objj-runtime
Version:
JavaScript (ECMAScript) and Objective-J runtime
367 lines (286 loc) • 10.4 kB
JavaScript
var rootResources = { };
function StaticResource(/*CFURL*/ aURL, /*StaticResource*/ aParent, /*BOOL*/ isDirectory, /*BOOL*/ isResolved, /*Dictionary*/ aFilenameTranslateDictionary)
{
this._parent = aParent;
this._eventDispatcher = new EventDispatcher(this);
var name = aURL.absoluteURL().lastPathComponent() || aURL.schemeAndAuthority();
this._name = name;
this._URL = aURL; //new CFURL(aName, aParent && aParent.URL().asDirectoryPathURL());
this._isResolved = !!isResolved;
this._filenameTranslateDictionary = aFilenameTranslateDictionary;
if (isDirectory)
this._URL = this._URL.asDirectoryPathURL();
if (!aParent)
rootResources[name] = this;
this._isDirectory = !!isDirectory;
this._isNotFound = NO;
if (aParent)
aParent._children[name] = this;
if (isDirectory)
this._children = { };
else
this._contents = "";
}
StaticResource.rootResources = function()
{
return rootResources;
};
function countProp(x) {
var count = 0;
for (var k in x) {
if (x.hasOwnProperty(k)) {
++count;
}
}
return count;
}
StaticResource.resetRootResources = function()
{
rootResources = {};
};
StaticResource.prototype.filenameTranslateDictionary = function()
{
return this._filenameTranslateDictionary || {};
};
exports.StaticResource = StaticResource;
function resolveStaticResource(/*StaticResource*/ aResource)
{
aResource._isResolved = YES;
aResource._eventDispatcher.dispatchEvent(
{
type:"resolve",
staticResource:aResource
});
}
StaticResource.prototype.resolve = function()
{
if (this.isDirectory())
{
var bundle = new CFBundle(this.URL());
// Eat any errors.
bundle.onerror = function() { };
// The bundle will actually resolve this node.
bundle.load(NO);
}
else
{
var self = this;
function onsuccess(/*anEvent*/ anEvent)
{
self._contents = anEvent.request.responseText();
resolveStaticResource(self);
}
function onfailure()
{
self._isNotFound = YES;
resolveStaticResource(self);
}
var url = this.URL(),
aFilenameTranslateDictionary = this.filenameTranslateDictionary();
if (aFilenameTranslateDictionary)
{
var urlString = url.toString(),
lastPathComponent = url.lastPathComponent(),
basePath = urlString.substring(0, urlString.length - lastPathComponent.length),
translatedName = aFilenameTranslateDictionary[lastPathComponent];
if (translatedName && urlString.slice(-translatedName.length) !== translatedName)
url = new CFURL(basePath + translatedName); // FIXME: do an add component to url or something better....
}
new FileRequest(url, onsuccess, onfailure);
}
};
StaticResource.prototype.name = function()
{
return this._name;
};
StaticResource.prototype.URL = function()
{
return this._URL;
};
StaticResource.prototype.contents = function()
{
return this._contents;
};
StaticResource.prototype.children = function()
{
return this._children;
};
StaticResource.prototype.parent = function()
{
return this._parent;
};
StaticResource.prototype.isResolved = function()
{
return this._isResolved;
};
StaticResource.prototype.write = function(/*String*/ aString)
{
this._contents += aString;
};
function rootResourceForAbsoluteURL(/*CFURL*/ anAbsoluteURL)
{
var schemeAndAuthority = anAbsoluteURL.schemeAndAuthority(),
resource = rootResources[schemeAndAuthority];
if (!resource)
resource = new StaticResource(new CFURL(schemeAndAuthority), NULL, YES, YES);
return resource;
}
StaticResource.resourceAtURL = function(/*CFURL|String*/ aURL, /*BOOL*/ resolveAsDirectoriesIfNecessary)
{
aURL = makeAbsoluteURL(aURL).absoluteURL();
var resource = rootResourceForAbsoluteURL(aURL),
components = aURL.pathComponents(),
index = 0,
count = components.length;
for (; index < count; ++index)
{
var name = components[index];
if (hasOwnProperty.call(resource._children, name))
resource = resource._children[name];
else if (resolveAsDirectoriesIfNecessary)
{
// We do this because on Windows the path may start with C: and be
// misinterpreted as a scheme.
if (name !== "/")
name = "./" + name;
resource = new StaticResource(new CFURL(name, resource.URL()), resource, YES, YES);
}
else
throw new Error("Static Resource at " + aURL + " is not resolved (\"" + name + "\")");
}
return resource;
};
StaticResource.prototype.resourceAtURL = function(/*CFURL|String*/ aURL, /*BOOL*/ resolveAsDirectoriesIfNecessary)
{
return StaticResource.resourceAtURL(new CFURL(aURL, this.URL()), resolveAsDirectoriesIfNecessary);
};
/*!
* Returns an object with all the resources. Can not be directories.
*/
StaticResource.resolveResourcesAtURLs = function(/*Array of CFURL|String*/ URLs, /*Function*/ aCallback)
{
var count = URLs.length,
allResources = {};
for (var i = 0, size = count; i < size; i++)
{
var url = URLs[i];
StaticResource.resolveResourceAtURL(url, NO, function(aResource) {
allResources[url] = aResource;
if (--count === 0)
aCallback(allResources);
});
}
}
StaticResource.resolveResourceAtURL = function(/*CFURL|String*/ aURL, /*BOOL*/ isDirectory, /*Function*/ aCallback, /*Dictionary*/ aFilenameTranslateDictionary)
{
aURL = makeAbsoluteURL(aURL).absoluteURL();
resolveResourceComponents(rootResourceForAbsoluteURL(aURL), isDirectory, aURL.pathComponents(), 0, aCallback, aFilenameTranslateDictionary);
};
StaticResource.prototype.resolveResourceAtURL = function(/*CFURL|String*/ aURL, /*BOOL*/ isDirectory, /*Function*/ aCallback)
{
StaticResource.resolveResourceAtURL(new CFURL(aURL, this.URL()).absoluteURL(), isDirectory, aCallback);
};
function resolveResourceComponents(/*StaticResource*/ aResource, /*BOOL*/ isDirectory, /*Array*/ components, /*Integer*/ index, /*Function*/ aCallback, /*Dictionry*/ aFilenameTranslateDictionary)
{
var count = components.length;
for (; index < count; ++index)
{
var name = components[index],
child = hasOwnProperty.call(aResource._children, name) && aResource._children[name];
// If the child doesn't exist, create and resolve it.
if (!child)
{
child = new StaticResource(new CFURL(name, aResource.URL()), aResource, index + 1 < count || isDirectory , NO, aFilenameTranslateDictionary);
child.resolve();
}
// If this resource is still being resolved, just wait and rerun this same method when it's ready.
if (!child.isResolved())
return child.addEventListener("resolve", function()
{
// Continue resolving once this is done.
resolveResourceComponents(aResource, isDirectory, components, index, aCallback, aFilenameTranslateDictionary);
});
// If we've already determined that this file doesn't exist...
if (child.isNotFound())
return aCallback(null, new Error("File not found: " + components.join("/")));
// If we have more path components and this is not a directory...
if ((index + 1 < count) && child.isFile())
return aCallback(null, new Error("File is not a directory: " + components.join("/")));
aResource = child;
}
aCallback(aResource);
}
function resolveResourceAtURLSearchingIncludeURLs(/*CFURL*/ aURL, /*Number*/ anIndex, /*Function*/ aCallback)
{
var includeURLs = StaticResource.includeURLs(),
searchURL = new CFURL(aURL, includeURLs[anIndex]).absoluteURL();
StaticResource.resolveResourceAtURL(searchURL, NO, function(/*StaticResource*/ aStaticResource)
{
if (!aStaticResource)
{
if (anIndex + 1 < includeURLs.length)
resolveResourceAtURLSearchingIncludeURLs(aURL, anIndex + 1, aCallback);
else
aCallback(NULL);
return;
}
aCallback(aStaticResource);
});
}
StaticResource.resolveResourceAtURLSearchingIncludeURLs = function(/*CFURL*/ aURL, /*Function*/ aCallback)
{
resolveResourceAtURLSearchingIncludeURLs(aURL, 0, aCallback);
};
StaticResource.prototype.addEventListener = function(/*String*/ anEventName, /*Function*/ anEventListener)
{
this._eventDispatcher.addEventListener(anEventName, anEventListener);
};
StaticResource.prototype.removeEventListener = function(/*String*/ anEventName, /*Function*/ anEventListener)
{
this._eventDispatcher.removeEventListener(anEventName, anEventListener);
};
StaticResource.prototype.isNotFound = function()
{
return this._isNotFound;
};
StaticResource.prototype.isFile = function()
{
return !this._isDirectory;
};
StaticResource.prototype.isDirectory = function()
{
return this._isDirectory;
};
StaticResource.prototype.toString = function(/*BOOL*/ includeNotFounds)
{
if (this.isNotFound())
return "<file not found: " + this.name() + ">";
var string = this.name();
if (this.isDirectory())
{
var children = this._children;
for (var name in children)
if (children.hasOwnProperty(name))
{
var child = children[name];
if (includeNotFounds || !child.isNotFound())
string += "\n\t" + children[name].toString(includeNotFounds).split('\n').join("\n\t");
}
}
return string;
};
var includeURLs = NULL;
StaticResource.includeURLs = function()
{
if (includeURLs !== NULL)
return includeURLs;
includeURLs = [];
if (!global.OBJJ_INCLUDE_PATHS && !global.OBJJ_INCLUDE_URLS)
includeURLs = ["Frameworks", "Frameworks/Debug"];
else
includeURLs = (global.OBJJ_INCLUDE_PATHS || []).concat(global.OBJJ_INCLUDE_URLS || []);
var count = includeURLs.length;
while (count--)
includeURLs[count] = new CFURL(includeURLs[count]).asDirectoryPathURL();
return includeURLs;
};