Where am I? Relative paths
Happy new year all! The first post in this new year is something I see a lot of beginners run into. They create a flash movie which has to load some resources and they simply go like:
obj.loadSomething("mycontent.swf");
Running the sample locally works fine ofcourse since everything is where you expect it to be.
However, after deployment your swf might be loaded into another swf, or loaded from a html page at another location and your content suddenly breaks. Why? Since “mycontent.swf” was a relative location.
So how do you fix it? Well there are several solutions:
- use a complete path
- use a resource file to define a content path
- use _url to determine where your swf actually is and thus where your content is
Option 1 isn’t very good, if your content is moved to another folder on the webserver, it breaks again. Option 2 does not actually solve the problem, since now you have to find the resource file :). Let’s go with option 3.
Using _url you can determine where your calling swf is being loaded from. Based on where it is loaded from you can find your relative content again. Image the following function (wrap it in a class or not):
function getPath (parent:MovieClip, path:String):String {
//if its a full path, do not alter it
if (path.indexOf(":") != -1) return path;
//take the parent url and normalize it
//(some player versions return \\ for local paths)
var parUrl:String = parent._url;
parUrl = parUrl.split("\\\").join("/");
//take our full path, and cut off filename
//eg (http://url/main.swf, becomes http://url/
var parArr:Array = parUrl.split("/");
parArr.pop();
parUrl = parArr.join("/")+"/";
//normalize the path we are looking for too
var pathUrl:String = path.split("\\\").join("/");
//combine full path and relative url
return parUrl+pathUrl;
}
Note that this is not a complete working version, but it works fine except for the following:
Of course the code can easily be extended to incorporate these features. We’ll leave this as an exercise for the reader:).
Using this function, we can now change our previous code to:
obj.loadSomething(getPath(this,"mycontent.swf"));
“this” should refer to a movieclip, for example _root. Using this indirection is a good thing in itself, since our path management is now localized, so if any problems occur, we only have to edit the getPath function instead of going through our code finding every loadSomething call. In a real project you might put the getPath function as a static method into a Utility class, add logging to it etc.