/* 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, ElementModel = require("js/models/element-model"); //////////////////////////////////////////////////////////////////////// // exports.DesignDocumentView = Montage.create(BaseDocumentView, { //////////////////////////////////////////////////////////////////// // hasTemplate: { value: false }, //////////////////////////////////////////////////////////////////// // _callback: { value: null }, //////////////////////////////////////////////////////////////////// // _viewCallback: { value: null }, //////////////////////////////////////////////////////////////////// // _template: { value: null }, //////////////////////////////////////////////////////////////////// // _bodyFragment: { value: null }, //////////////////////////////////////////////////////////////////// // _headFragment: { value: null }, //////////////////////////////////////////////////////////////////// // _observer: { value: {head: null, body: null} }, //////////////////////////////////////////////////////////////////// // content: { value: null }, //////////////////////////////////////////////////////////////////// // _liveNodeList: { value: null }, //////////////////////////////////////////////////////////////////// // _webGlHelper: { value: null }, //////////////////////////////////////////////////////////////////// // _baseHref: { value: null }, //////////////////////////////////////////////////////////////////// // baseHref: { get: function() {return this._baseHref;}, set: function(value) {this._baseHref = value;} }, //////////////////////////////////////////////////////////////////// // _document: { value: null }, //////////////////////////////////////////////////////////////////// // document: { get: function() {return this._document;}, set: function(value) {this._document = value;} }, //////////////////////////////////////////////////////////////////// // _documentRoot: { value: null }, //////////////////////////////////////////////////////////////////// // documentRoot: { get: function() {return this._documentRoot;}, set: function(value) {this._documentRoot = value;} }, //////////////////////////////////////////////////////////////////// // 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, viewCallback) { //TODO: Remove, this is a temp patch for webRequest API gate this.application.ninja.documentController.redirectRequests = false; //Storing callback for dispatch ready this._callback = callback; this._template = template; this._viewCallback = viewCallback; //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) { //TODO: Remove, this is a temp patch for webRequest API gate this.application.ninja.documentController.redirectRequests = 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.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.tmplt.getNinjaPropUrlRedirect.bind(this.application.ninja.ioMediator.tmplt))).replace(/url\(([^"]*)(.+?)\1\)/g, this.application.ninja.ioMediator.tmplt.getNinjaPropUrlRedirect.bind(this.application.ninja.ioMediator.tmplt)); } } 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.tmplt.getNinjaPropUrlRedirect.bind(this.application.ninja.ioMediator.tmplt))).replace(/url\(([^"]*)(.+?)\1\)/g, this.application.ninja.ioMediator.tmplt.getNinjaPropUrlRedirect.bind(this.application.ninja.ioMediator.tmplt)); //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.tmplt.getNinjaPropUrlRedirect.bind(this.application.ninja.ioMediator.tmplt))).replace(/url\(([^"]*)(.+?)\1\)/g, this.application.ninja.ioMediator.tmplt.getNinjaPropUrlRedirect.bind(this.application.ninja.ioMediator.tmplt)); //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); } } //Copying attributes to maintain same properties as the for (var m in this.content.document.head.attributes) { if (this.content.document.head.attributes[m].value) { this.document.head.setAttribute(this.content.document.head.attributes[m].name, this.content.document.head.attributes[m].value); } } //Copying attributes to maintain same properties as the var htmlTagMem = this.content.document.getElementsByTagName('html')[0], htmlTagDoc = this.document.getElementsByTagName('html')[0]; for (var m in htmlTagMem.attributes) { if (htmlTagMem.attributes[m].value) { htmlTagDoc.setAttribute(htmlTagMem.attributes[m].name, htmlTagMem.attributes[m].value); } } } } }, //////////////////////////////////////////////////////////////////// // 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 htags = this.document.getElementsByTagName('html'), bannerWrapper, userStyles, stags = this.document.getElementsByTagName('style'), ltags = this.document.getElementsByTagName('link'), i, orgNodes, 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