From 56efed8b1ed9974aade615fce2d96bc214d21540 Mon Sep 17 00:00:00 2001 From: Jose Antonio Marquez Date: Mon, 5 Mar 2012 15:55:30 -0800 Subject: Resolved URL path issues in document and CSS Added logic to allow for files opened and assets linked in any order all under the cloud server root. --- js/document/html-document.js | 121 ++++++++++++++++++++++++++++++++++++++++--- js/mediators/io-mediator.js | 63 +++++++++++----------- 2 files changed, 143 insertions(+), 41 deletions(-) diff --git a/js/document/html-document.js b/js/document/html-document.js index 1e41a797..ace1390f 100755 --- a/js/document/html-document.js +++ b/js/document/html-document.js @@ -409,16 +409,57 @@ exports.HTMLDocument = Montage.create(TextDocument, { if(!this.documentRoot.Ninja) this.documentRoot.Ninja = {}; //Inserting user's document into template - //TODO: Add logic to parse URLs from head/body + + + + + + + + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + //TODO: Clean up and make public method to prepend properties with Ninja URL this._templateDocument.head.innerHTML = (this._userDocument.content.head.replace(/\b(href|src)\s*=\s*"([^"]*)"/g, ninjaUrlRedirect.bind(this))).replace(/url\(([^"]*)(.+?)\1\)/g, ninjaUrlRedirect.bind(this)); this._templateDocument.body.innerHTML = (this._userDocument.content.body.replace(/\b(href|src)\s*=\s*"([^"]*)"/g, ninjaUrlRedirect.bind(this))).replace(/url\(([^"]*)(.+?)\1\)/g, ninjaUrlRedirect.bind(this)); // + //var docRootUrl = this.application.ninja.coreIoApi.rootUrl+escape((this.application.ninja.documentController.documentHackReference.root.split(this.application.ninja.coreIoApi.cloudData.root)[1]).replace(/\/\//gi, '/')); + // function ninjaUrlRedirect (prop) { - console.log(prop); + //Checking for property value to not contain a full direct URL + if (!prop.match(/(\b(?:(?:https?|ftp|file|[A-Za-z]+):\/\/|www\.|ftp\.)(?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[-A-Z0-9+&@#\/%=~_|$?!:,.])*(?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[A-Z0-9+&@#\/%=~_|$]))/gi)) { + //Checking for attributes and type of source + if (prop.indexOf('href') !== -1 || prop.indexOf('src') !== -1) { //From HTML attribute + // + prop = prop.replace(/"([^"]*)"/gi, ninjaUrlPrepend.bind(this)); + } else if (prop.indexOf('url') !== -1) { //From CSS property + //TODO: Add functionality + console.log('CSS: '+prop); + } + } return prop; } // - + function ninjaUrlPrepend (url) { + var docRootUrl = this.application.ninja.coreIoApi.rootUrl+escape((this.application.ninja.documentController.documentHackReference.root.split(this.application.ninja.coreIoApi.cloudData.root)[1]).replace(/\/\//gi, '/')); + return '"'+docRootUrl+url.replace(/\"/gi, '')+'"'; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + + + + + + + + + var scripttags = this._templateDocument.html.getElementsByTagName('script'), webgldata; //TODO: Use querySelectorAll // for (var w in scripttags) { @@ -493,10 +534,55 @@ exports.HTMLDocument = Montage.create(TextDocument, { //If rules are null, assuming cross-origin issue if(this._document.styleSheets[i].rules === null) { //TODO: Revisit URLs and URI creation logic, very hack right now - var fileUri, cssUrl, cssData, query, prefixUrl, fileCouldDirUrl; + var fileUri, cssUrl, cssData, query, prefixUrl, fileCouldDirUrl, docRootUrl; + // + docRootUrl = this.application.ninja.coreIoApi.rootUrl+escape((this.application.ninja.documentController.documentHackReference.root.split(this.application.ninja.coreIoApi.cloudData.root)[1]).replace(/\/\//gi, '/')); //TODO: Parse out relative URLs and map them to absolute - if (this._document.styleSheets[i].href.indexOf(chrome.extension.getURL('')) !== -1) { - //Getting the url of the CSS file + if (this._document.styleSheets[i].href.indexOf(this.application.ninja.coreIoApi.rootUrl) !== -1) { + + cssUrl = this._document.styleSheets[i].href.split(this.application.ninja.coreIoApi.rootUrl)[1]; + fileUri = this.application.ninja.coreIoApi.cloudData.root+cssUrl; + //TODO: Add error handling for reading file + cssData = this.application.ninja.coreIoApi.readFile({uri: fileUri}); + + + var tag = this.iframe.contentWindow.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 this._document.styleSheets[i].ownerNode.attributes) { + if (this._document.styleSheets[i].ownerNode.attributes[n].value && this._document.styleSheets[i].ownerNode.attributes[n].name !== 'disabled' && this._document.styleSheets[i].ownerNode.attributes[n].name !== 'disabled') { + if (this._document.styleSheets[i].ownerNode.attributes[n].value.indexOf(docRootUrl) !== -1) { + tag.setAttribute(this._document.styleSheets[i].ownerNode.attributes[n].name, this._document.styleSheets[i].ownerNode.attributes[n].value.split(docRootUrl)[1]); + } else { + tag.setAttribute(this._document.styleSheets[i].ownerNode.attributes[n].name, this._document.styleSheets[i].ownerNode.attributes[n].value); + } + } + } + + fileCouldDirUrl = this._document.styleSheets[i].href.split(this._document.styleSheets[i].href.split('/')[this._document.styleSheets[i].href.split('/').length-1])[0]; + prefixUrl = 'url('+fileCouldDirUrl; //This should be re-written with better RegEx + tag.innerHTML = cssData.content.replace(/url\(/gi, prefixUrl); + + + + //Looping through DOM to insert style tag at location of link element + query = this._templateDocument.html.querySelectorAll(['link']); + for (var j in query) { + if (query[j].href === this._document.styleSheets[i].href) { + //Disabling style sheet to reload via inserting in style tag + query[j].setAttribute('disabled', 'true'); + //Inserting tag + this._templateDocument.head.insertBefore(tag, query[j]); + } + } + + + /* +//Getting the url of the CSS file cssUrl = this._document.styleSheets[i].href.split('js/document/templates/montage-html')[1];//TODO: Parse out relative URLs and map them to absolute //Creating the URI of the file (this is wrong should not be splitting cssUrl) fileUri = (this.application.ninja.coreIoApi.cloudData.root+this.application.ninja.documentController.documentHackReference.root.split(this.application.ninja.coreIoApi.cloudData.root)[1]+cssUrl).replace(/\/\//gi, '/'); @@ -517,8 +603,8 @@ exports.HTMLDocument = Montage.create(TextDocument, { } // - fileCouldDirUrl = this.application.ninja.coreIoApi.rootUrl+escape((this.application.ninja.documentController.documentHackReference.root.split(this.application.ninja.coreIoApi.cloudData.root)[1]+cssUrl.split(cssUrl.split('/')[cssUrl.split('/').length-1])[0]).replace(/\/\//gi, '/')); - + //fileCouldDirUrl = this.application.ninja.coreIoApi.rootUrl+escape((this.application.ninja.documentController.documentHackReference.root.split(this.application.ninja.coreIoApi.cloudData.root)[1]+cssUrl.split(cssUrl.split('/')[cssUrl.split('/').length-1])[0]).replace(/\/\//gi, '/')); + fileCouldDirUrl = this.application.ninja.coreIoApi.rootUrl+escape((this.application.ninja.documentController.documentHackReference.root.split(this.application.ninja.coreIoApi.cloudData.root)[1]).replace(/\/\//gi, '/')); //TODO: Fix regEx to have logic for all possible URLs strings (currently prefixing all url()) prefixUrl = 'url('+fileCouldDirUrl; //This should be re-written with better RegEx @@ -534,6 +620,25 @@ exports.HTMLDocument = Montage.create(TextDocument, { this._templateDocument.head.insertBefore(tag, query[j]); } } +*/ + + + + + + + + + + + + + + + + + + } else { console.log('ERROR: Cross-Domain-Stylesheet detected, unable to load in Ninja'); //None local stylesheet, probably on a CDN (locked) diff --git a/js/mediators/io-mediator.js b/js/mediators/io-mediator.js index 5917edba..c02710c2 100644 --- a/js/mediators/io-mediator.js +++ b/js/mediators/io-mediator.js @@ -213,9 +213,11 @@ exports.IoMediator = Montage.create(Component, { parseNinjaTemplateToHtml: { enumerable: false, value: function (template) { + var regexRootUrl, rootUrl = this.application.ninja.coreIoApi.rootUrl+escape((this.application.ninja.documentController.documentHackReference.root.split(this.application.ninja.coreIoApi.cloudData.root)[1])); + regexRootUrl = new RegExp(rootUrl.replace(/\//gi, '\\\/'), 'gi'); //Injecting head and body into old document - template.document.content.document.head.innerHTML = template.head; - template.document.content.document.body.innerHTML = template.body; + template.document.content.document.head.innerHTML = template.head.replace(regexRootUrl, ''); + template.document.content.document.body.innerHTML = template.body.replace(regexRootUrl, ''); //Getting all CSS (style or link) tags var styletags = template.document.content.document.getElementsByTagName('style'), linktags = template.document.content.document.getElementsByTagName('link'), @@ -248,7 +250,7 @@ exports.IoMediator = Montage.create(Component, { for (var l in linktags) { if (linktags[l].getAttribute && linktags[l].getAttribute('disabled')) {//TODO: Use querySelectorAll for (var p=0; toremovetags[p]; p++) { - if (toremovetags[p].getAttribute('data-ninja-file-url') === ('/'+linktags[l].getAttribute('href'))) { + if (toremovetags[p].getAttribute('href') === linktags[l].getAttribute('href')) { if (!toremovetags[p].getAttribute('data-ninja-disabled')) { linktags[l].removeAttribute('disabled'); } @@ -335,55 +337,50 @@ exports.IoMediator = Montage.create(Component, { /////////////////////////////////////////////////////////////////////////////////////////// - var cleanedCss, fileCouldDirUrl, pathDepth, pathToDocRoot = '../'; + var cleanedCss, dirtyCss = this.getCssFromRules(template.css[i].cssRules), fileUrl = template.css[i].ownerNode.getAttribute('data-ninja-file-url'), - fileRootUrl = this.application.ninja.coreIoApi.rootUrl+escape((this.application.ninja.documentController.documentHackReference.root.split(this.application.ninja.coreIoApi.cloudData.root)[1]+fileUrl.split(fileUrl.split('/')[fileUrl.split('/').length-1])[0]).replace(/\/\//gi, '/')), - localPath = fileUrl.split(fileUrl.split('/')[fileUrl.split('/').length-2])[0] || fileUrl.split(fileUrl.split('/')[fileUrl.split('/').length-1])[0] || fileUrl.split(fileUrl.split('/')[0])[0], - documentRootURL = this.application.ninja.coreIoApi.rootUrl+escape((this.application.ninja.documentController.documentHackReference.root.split(this.application.ninja.coreIoApi.cloudData.root)[1])); - - pathDepth = Math.floor(localPath.split('/').length/2); - - for (var p=0; p < pathDepth; p++) { - pathToDocRoot += '../'; - } - - fileCouldDirUrl = this.application.ninja.coreIoApi.rootUrl+escape((this.application.ninja.documentController.documentHackReference.root.split(this.application.ninja.coreIoApi.cloudData.root)[1]+localPath).replace(/\/\//gi, '/')); - - cleanedCss = dirtyCss.replace(/(\b(?:(?:https?|ftp|file|[A-Za-z]+):\/\/|www\.|ftp\.)(?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[-A-Z0-9+&@#\/%=~_|$?!:,.])*(?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[A-Z0-9+&@#\/%=~_|$]))/gi, parseNinjaUrl.bind(this)); + fileRootUrl = this.application.ninja.coreIoApi.rootUrl+fileUrl.split(fileUrl.split('/')[fileUrl.split('/').length-1])[0], + cleanedCss = dirtyCss.replace(/(\b(?:(?:https?|ftp|file|[A-Za-z]+):\/\/|www\.|ftp\.)(?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[-A-Z0-9+&@#\/%=~_|$?!:,.])*(?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[A-Z0-9+&@#\/%=~_|$]))/gi, parseNinjaUrl.bind(this)); + function parseNinjaUrl (url) { + //console.log("Getting: " + url); // - if (url.indexOf(fileCouldDirUrl) !== -1 || url.indexOf(fileRootUrl) !== -1) { + if (url.indexOf(fileRootUrl) !== -1) { + url = url.replace(new RegExp(fileRootUrl.replace(/\//gi, '\\\/'), 'gi'), ''); + } else { + var assetsDirs = (url.replace(new RegExp((this.application.ninja.coreIoApi.rootUrl).replace(/\//gi, '\\\/'), 'gi'), '')).split('/'); + var fileDirs = (fileUrl.split(fileUrl.split('/')[fileUrl.split('/').length-1])[0]).split('/'); + var counter = 0; + var path = ''; + var newURL = ''; + // + for (var p=0; p < fileDirs.length-1; p++) { + if (fileDirs[p] === assetsDirs[p]) { + counter++; + } + } // - if (pathDepth < 1 || url.indexOf(fileRootUrl) > -1) { - // - url = url.replace(new RegExp(fileRootUrl.replace(/\//gi, '\\\/'), 'gi'), ''); - } else { - // - url = url.replace(new RegExp(fileCouldDirUrl.replace(/\//gi, '\\\/'), 'gi'), '../'); + for (var p=0; p < (fileDirs.length-counter)-1; p++) { + path += '../'; } - } else { // - if (url.indexOf(documentRootURL) !== 1) { - url = url.replace(new RegExp(documentRootURL.replace(/\//gi, '\\\/'), 'gi'), pathToDocRoot); - } else if (url.indexOf(this.application.ninja.coreIoApi.rootUrl) !== 1) { - //TODO: Add logic for files above root document folder + for (var p=counter; p < assetsDirs.length; p++) { + newURL += '/'+assetsDirs[p]; } + // + url = (path+newURL).replace(/\/\//gi, '/'); } //console.log("Returning: " + url); //console.log("-----"); return url; } - //console.log(cleanedCss); - /////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////// - //return; - //Saving data from rules array converted to string into file -- cgit v1.2.3