From 6356edefaea3fe78969c53fec2d371cb8f42d820 Mon Sep 17 00:00:00 2001 From: Jose Antonio Marquez Date: Thu, 3 May 2012 15:28:38 -0700 Subject: Full CSS support on open Add full CSS for files on open (including loading cross-domain). This is only for files that are opened. --- js/document/views/design.js | 87 +++++++++++++++++++++++++++++++-------------- js/io/system/coreioapi.js | 64 +++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+), 26 deletions(-) (limited to 'js') diff --git a/js/document/views/design.js b/js/document/views/design.js index e5213761..4f598305 100755 --- a/js/document/views/design.js +++ b/js/document/views/design.js @@ -127,21 +127,12 @@ exports.DesignDocumentView = Montage.create(BaseDocumentView, { this._observer.body = null; //Removing loading container this.document.body.removeChild(this.document.getElementsByTagName('ninjaloadinghack')[0]); - - - - - - // + //Getting style and link tags in document var stags = this.document.getElementsByTagName('style'), ltags = this.document.getElementsByTagName('link'); //Temporarily checking for disabled special case (we must enabled for Ninja to access styles) this.ninjaDisableAttribute(stags); this.ninjaDisableAttribute(ltags); - - - - //Looping through all link tags to reload into style tags if(ltags.length > 0) { for (var i = 0; i < ltags.length; i++) { @@ -152,14 +143,15 @@ exports.DesignDocumentView = Montage.create(BaseDocumentView, { //Disabling tag once it has been reloaded ltags[i].setAttribute('disabled', 'true'); } else { - //Error: broken? + //Error: TBD + //TODO: Determine what link tags would not have href data and error } } } + //TODO: Load webGL (blocking) - - + //TODO: Load Montage Components (blocking) //Makign callback if specified if (this._callback) this._callback(); @@ -186,6 +178,9 @@ exports.DesignDocumentView = Montage.create(BaseDocumentView, { value: function (linktag) { // var tag, cssUrl, fileUri, cssData, docRootUrl; + //Creating style tag to load CSS content into + tag = this.document.createElement('style'); + tag.setAttribute('type', 'text/css'); //TODO: Remove usage of hack reference of URL docRootUrl = this.application.ninja.coreIoApi.rootUrl+escape((this.application.ninja.documentController.documentHackReference.root.split(this.application.ninja.coreIoApi.cloudData.root)[1]).replace(/\/\//gi, '/')); //Checking for location of href to load (special case for cross-domain) @@ -195,19 +190,19 @@ exports.DesignDocumentView = Montage.create(BaseDocumentView, { fileUri = this.application.ninja.coreIoApi.cloudData.root+cssUrl; //Loading data from CSS file cssData = this.application.ninja.coreIoApi.readFile({uri: fileUri}); - // + //Setting properties of locally loaded styles + tag.setAttribute('data-ninja-uri', fileUri); + tag.setAttribute('data-ninja-file-url', cssUrl); + tag.setAttribute('data-ninja-file-read-only', JSON.parse(this.application.ninja.coreIoApi.isFileWritable({uri: fileUri}).content).readOnly); + tag.setAttribute('data-ninja-file-name', cssUrl.split('/')[cssUrl.split('/').length-1]); } else { - //Cross-domain resource + //Cross-domain content + cssData = this.application.ninja.coreIoApi.readExternalFile({url: linktag.href, binary: false}); + //Setting properties of externally loaded styles + tag.setAttribute('data-ninja-external-url', linktag.href); + tag.setAttribute('data-ninja-file-read-only', "true"); + tag.setAttribute('data-ninja-file-name', linktag.href.split('/')[linktag.href.split('/').length-1]); } - //TODO: Improve into single method - fileCouldDirUrl = linktag.href.split(linktag.href.split('/')[linktag.href.split('/').length-1])[0]; - //Creating style tag to load CSS content into - tag = this.document.createElement('style'); - tag.setAttribute('type', 'text/css'); - tag.setAttribute('data-ninja-uri', fileUri); - tag.setAttribute('data-ninja-file-url', cssUrl); - tag.setAttribute('data-ninja-file-read-only', JSON.parse(this.application.ninja.coreIoApi.isFileWritable({uri: fileUri}).content).readOnly); - tag.setAttribute('data-ninja-file-name', cssUrl.split('/')[cssUrl.split('/').length-1]); //Copying attributes to maintain same properties as the for (var n in linktag.attributes) { if (linktag.attributes[n].value && linktag.attributes[n].name !== 'disabled') { @@ -218,9 +213,49 @@ exports.DesignDocumentView = Montage.create(BaseDocumentView, { } } } + + + + + + + + + + + + //////////////////////////////////////////////////////// + //////////////////////////////////////////////////////// + //TODO: Clean up and make proper method + fileCouldDirUrl = linktag.href.split(linktag.href.split('/')[linktag.href.split('/').length-1])[0]; + // + if (cssData && cssData.content) { + tag.innerHTML = cssData.content.replace(/url\(()(.+?)\1\)/g, parseToNinjaUrl.bind(this)); + } else { + //Error: no data was loaded + } + // + function parseToNinjaUrl (prop) { + // + return prop.replace(/[^()\\""\\'']+/g, prefixWithNinjaUrl.bind(this)); + } // - //tag.innerHTML = cssData.content.replace(/url\(()(.+?)\1\)/g, detectUrl); - tag.innerHTML = cssData.content; + function prefixWithNinjaUrl (url) { + // + if (url !== 'url' && !url.match(/(\b(?:(?:https?|ftp|file|[A-Za-z]+):\/\/|www\.|ftp\.)(?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[-A-Z0-9+&@#\/%=~_|$?!:,.])*(?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[A-Z0-9+&@#\/%=~_|$]))/gi)) { + url = fileCouldDirUrl+url; + } + // + return url; + } + //////////////////////////////////////////////////////// + //////////////////////////////////////////////////////// + + + + + + // return tag; } diff --git a/js/io/system/coreioapi.js b/js/io/system/coreioapi.js index a06f45c6..1e6518fe 100755 --- a/js/io/system/coreioapi.js +++ b/js/io/system/coreioapi.js @@ -192,6 +192,23 @@ exports.CoreIoApi = Montage.create(Component, { set: function(value) { this._fileServiceURL = value; } + }, + //////////////////////////////////////////////////////////////////// + //File service API URL + _webServiceURL: { + enumerable: false, + value: '/web' + }, + //////////////////////////////////////////////////////////////////// + // + webServiceURL: { + enumerable: false, + get: function() { + return String(this.rootUrl+this._webServiceURL); + }, + set: function(value) { + this._webServiceURL = value; + } }, //////////////////////////////////////////////////////////////////// //Directory service API URL @@ -647,6 +664,53 @@ exports.CoreIoApi = Montage.create(Component, { } }, //////////////////////////////////////////////////////////////////// + // Reads an external file (cross-domain) + // Parameters: + // the file parameter must contain the following properties + // url: string value containing the full file path/URL i.e. "http://google.com/motorola.html" + // binary parameter is optional if the content is to be binary + // Return values: + // returns an object with two properties + // success: boolean indicating if the call succeeded or failed + // content: string containing the file contents + // status: int indicating the request HTTP status code + // 200 - the file was read and its contents were returned + // 404 - the file does not exist + // 500 - unknown server error occurred + readExternalFile: { + enumerable: false, + value: function(file) { + // + var retValue = {success:null, content:null, status:null}; + // + if(file && file.url && file.url.length) { + try { + var serviceURL = this._prepareServiceURL(this.webServiceURL, ''), + xhr = new XMLHttpRequest(); + // + xhr.open("GET", serviceURL+"?url="+file.url, false); + if (file.binary) xhr.setRequestHeader("return-type", "binary"); + xhr.setRequestHeader("Content-Type", "text/plain"); + xhr.send(); + // + if (xhr.readyState === 4) { + retValue.status = xhr.status; + if(xhr.status == 200) { + retValue.content = xhr.response; + } + retValue.success = true; + } + } + catch(error) { + xhr = null; + retValue.success = false; + } + } + // + return retValue; + } + }, + //////////////////////////////////////////////////////////////////// // Create a new directory/folder // Parameters: // the dir parameter must contain the following properties -- cgit v1.2.3