/*
This file contains proprietary software owned by Motorola Mobility, Inc.
No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved.
*/
////////////////////////////////////////////////////////////////////////
//
var Montage = require("montage/core/core").Montage,
BaseDocumentView = require("js/document/views/base").BaseDocumentView;
////////////////////////////////////////////////////////////////////////
//
exports.DesignDocumentView = Montage.create(BaseDocumentView, {
////////////////////////////////////////////////////////////////////
//
hasTemplate: {
value: false
},
////////////////////////////////////////////////////////////////////
//
_callback: {
value: null
},
////////////////////////////////////////////////////////////////////
//
_template: {
value: null
},
////////////////////////////////////////////////////////////////////
//
_document: {
value: null
},
////////////////////////////////////////////////////////////////////
//
_bodyFragment: {
value: null
},
////////////////////////////////////////////////////////////////////
//
_headFragment: {
value: null
},
////////////////////////////////////////////////////////////////////
//
_observer: {
value: {head: null, body: null}
},
////////////////////////////////////////////////////////////////////
//
content: {
value: null
},
////////////////////////////////////////////////////////////////////
//TODO: Remove usage
model: {
value: null
},
////////////////////////////////////////////////////////////////////
//
document: {
get: function() {return this._document;},
set: function(value) {this._document = value;}
},
////////////////////////////////////////////////////////////////////
//
propertiesPanel: {
value: null
},
////////////////////////////////////////////////////////////////////
//
_liveNodeList: {
value: null
},
getLiveNodeList: {
value: function(useFilter) {
if(useFilter) {
var filteredNodes = [],
childNodes = Array.prototype.slice.call(this._liveNodeList, 0);
childNodes.forEach(function(item) {
if( (item.nodeType === 1) && (item.nodeName !== "STYLE") && (item.nodeName !== "SCRIPT")) {
filteredNodes.push(item);
}
});
return filteredNodes;
} else {
return Array.prototype.slice.call(this._liveNodeList, 0);
}
}
},
////////////////////////////////////////////////////////////////////
//
//
initialize: {
value: function (parent) {
//Creating iFrame for view
this.iframe = document.createElement("iframe");
//Setting default styles
this.iframe.style.border = "none";
this.iframe.style.background = "#FFF";
this.iframe.style.height = "100%";
this.iframe.style.width = "100%";
//Returning reference to iFrame created
return parent.appendChild(this.iframe);
}
},
////////////////////////////////////////////////////////////////////
//
render: {
value: function (callback, template) {
//TODO: Remove, this is a temp patch for webRequest API gate
this.application.ninja.documentController._hackRootFlag = false;
//Storing callback for dispatch ready
this._callback = callback;
this._template = template;
//Adding listener to know when template is loaded to then load user content
this.iframe.addEventListener("load", this.onTemplateLoad.bind(this), false);
//TODO: Add source parameter and root (optional)
if (template && template.type === 'banner' && template.size) {
this.iframe.src = "js/document/templates/banner/index.html";
} else {
this.iframe.src = "js/document/templates/html/index.html";
}
}
},
////////////////////////////////////////////////////////////////////
//
onTemplateLoad: {
value: function (e) {
this.application.ninja.documentController._hackRootFlag = true;
//TODO: Add support to constructing URL with a base HREF
var basetag = this.content.document.getElementsByTagName('base');
//Removing event
this.iframe.removeEventListener("load", this.onTemplateLoad.bind(this), false);
//TODO: Improve usage of this reference
this.document = this.iframe.contentWindow.document;
//Looping through template styles and marking them with ninja data attribute for I/O clean up
for (var k in this.document.styleSheets) {
if (this.document.styleSheets[k].ownerNode && this.document.styleSheets[k].ownerNode.setAttribute) {
this.document.styleSheets[k].ownerNode.setAttribute('data-ninja-template', 'true');
}
}
//Checking for a base URL
if (basetag.length) {
if (basetag[basetag.length-1].getAttribute && basetag[basetag.length-1].getAttribute('href')) {
//Setting base HREF in model
this.model.baseHref = basetag[basetag.length-1].getAttribute('href');
}
}
//Checking to content to be template
if (this._template) {
if (this._template.type === 'banner') {
//Loading contents into a fragment
this._bodyFragment = this.document.createElement('body');
//Listening for content to be ready
this._observer.body = new WebKitMutationObserver(this.insertBannerContent.bind(this));
this._observer.body.observe(this._bodyFragment, {childList: true});
//Inserting
HTML and parsing URLs via mediator method
this._bodyFragment.innerHTML = ''+(this.content.body.replace(/\b(href|src)\s*=\s*"([^"]*)"/g, this.application.ninja.ioMediator.getNinjaPropUrlRedirect.bind(this.application.ninja.ioMediator))).replace(/url\(([^"]*)(.+?)\1\)/g, this.application.ninja.ioMediator.getNinjaPropUrlRedirect.bind(this.application.ninja.ioMediator));
}
} else {
//Creating temp code fragement to load head
this._headFragment = this.document.createElement('head');
//Adding event listener to know when head is ready, event only dispatched once when using innerHTML
this._observer.head = new WebKitMutationObserver(this.insertHeadContent.bind(this));
this._observer.head.observe(this._headFragment, {childList: true});
//Inserting HTML and parsing URLs via mediator method
this._headFragment.innerHTML = (this.content.head.replace(/\b(href|src)\s*=\s*"([^"]*)"/g, this.application.ninja.ioMediator.getNinjaPropUrlRedirect.bind(this.application.ninja.ioMediator))).replace(/url\(([^"]*)(.+?)\1\)/g, this.application.ninja.ioMediator.getNinjaPropUrlRedirect.bind(this.application.ninja.ioMediator));
//Adding event listener to know when the body is ready and make callback (using HTML5 new DOM Mutation Events)
this._observer.body = new WebKitMutationObserver(this.bodyContentLoaded.bind(this));
this._observer.body.observe(this.document.body, {childList: true});
//Inserting HTML and parsing URLs via mediator method
this.document.body.innerHTML += ''+(this.content.body.replace(/\b(href|src)\s*=\s*"([^"]*)"/g, this.application.ninja.ioMediator.getNinjaPropUrlRedirect.bind(this.application.ninja.ioMediator))).replace(/url\(([^"]*)(.+?)\1\)/g, this.application.ninja.ioMediator.getNinjaPropUrlRedirect.bind(this.application.ninja.ioMediator));
//Copying attributes to maintain same properties as the
for (var n in this.content.document.body.attributes) {
if (this.content.document.body.attributes[n].value) {
this.document.body.setAttribute(this.content.document.body.attributes[n].name, this.content.document.body.attributes[n].value);
}
}
//TODO: Add attribute copying for and
}
}
},
////////////////////////////////////////////////////////////////////
//
insertBannerContent: {
value: function (e) {
//Getting first element in DOM (assumes it's root)
//TODO: Ensure wrapper logic is proper
var wrapper = this._bodyFragment.getElementsByTagName('*')[1],
banner = this._bodyFragment.getElementsByTagName('*')[2],
ninjaBanner = this.document.body.getElementsByTagName('ninja-content')[0],
ninjaWrapper = this.document.body.getElementsByTagName('ninja-viewport')[0];
//Copying attributes to maintain same properties as the banner wrapper
for (var n in wrapper.attributes) {
if (wrapper.attributes[n].value) {
ninjaWrapper.setAttribute(wrapper.attributes[n].name, wrapper.attributes[n].value);
}
}
//Copying attributes to maintain same properties as the banner content
for (var n in banner.attributes) {
if (banner.attributes[n].value) {
ninjaBanner.setAttribute(banner.attributes[n].name, banner.attributes[n].value);
}
}
//Adjusting margin per size of document
this.document.head.getElementsByTagName('style')[0].innerHTML += '\n ninja-viewport {overflow: visible !important;} ninja-content, ninja-viewport {width: ' + this._template.size.width + 'px; height: ' + this._template.size.height + 'px;}';
//Setting content in template
ninjaBanner.innerHTML = banner.innerHTML;
//Garbage collection
this._bodyFragment = null;
//Calling standard method to finish opening document
this.bodyContentLoaded(null);
}
},
////////////////////////////////////////////////////////////////////
//
insertHeadContent: {
value: function (e) {
//Removing event
this._observer.head.disconnect();
this._observer.head = null;
//Adding the loaded nodes from code fragment into actual document head
for(var i in this._headFragment.childNodes) {
//Minor hack to know node is actual HTML node
if(this._headFragment.childNodes[i].outerHTML) {
this.document.head.appendChild(this._headFragment.childNodes[i]);
}
}
//Garbage collection
this._headFragment = null;
}
},
////////////////////////////////////////////////////////////////////
//
bodyContentLoaded: {
value: function (e) {
//Removing event, only needed on initial load
this._observer.body.disconnect();
this._observer.body = null;
//Removing loading container (should be removed)
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'), i,
scripttags = this.document.getElementsByTagName('script');
//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 (i = 0; i < ltags.length; i++) {
//
if (ltags[i].href) {
//Inseting