diff options
Diffstat (limited to 'js/document/views/design.js')
-rwxr-xr-x | js/document/views/design.js | 431 |
1 files changed, 427 insertions, 4 deletions
diff --git a/js/document/views/design.js b/js/document/views/design.js index 84871257..c7313708 100755 --- a/js/document/views/design.js +++ b/js/document/views/design.js | |||
@@ -7,16 +7,439 @@ No rights, expressed or implied, whatsoever to this software are provided by Mot | |||
7 | //////////////////////////////////////////////////////////////////////// | 7 | //////////////////////////////////////////////////////////////////////// |
8 | // | 8 | // |
9 | var Montage = require("montage/core/core").Montage, | 9 | var Montage = require("montage/core/core").Montage, |
10 | Component = require("montage/ui/component").Component, | 10 | BaseDocumentView = require("js/document/views/base").BaseDocumentView; |
11 | CodeDocumentView = require("js/document/views/code").CodeDocumentView; | ||
12 | //////////////////////////////////////////////////////////////////////// | 11 | //////////////////////////////////////////////////////////////////////// |
13 | // | 12 | // |
14 | exports.DesignDocumentView = Montage.create(CodeDocumentView, { | 13 | exports.DesignDocumentView = Montage.create(BaseDocumentView, { |
15 | //////////////////////////////////////////////////////////////////// | 14 | //////////////////////////////////////////////////////////////////// |
16 | // | 15 | // |
17 | hasTemplate: { | 16 | hasTemplate: { |
18 | enumerable: false, | ||
19 | value: false | 17 | value: false |
18 | }, | ||
19 | //////////////////////////////////////////////////////////////////// | ||
20 | // | ||
21 | _callback: { | ||
22 | value: null | ||
23 | }, | ||
24 | //////////////////////////////////////////////////////////////////// | ||
25 | // | ||
26 | _template: { | ||
27 | value: null | ||
28 | }, | ||
29 | //////////////////////////////////////////////////////////////////// | ||
30 | // | ||
31 | _document: { | ||
32 | value: null | ||
33 | }, | ||
34 | //////////////////////////////////////////////////////////////////// | ||
35 | // | ||
36 | _bodyFragment: { | ||
37 | value: null | ||
38 | }, | ||
39 | //////////////////////////////////////////////////////////////////// | ||
40 | // | ||
41 | _headFragment: { | ||
42 | value: null | ||
43 | }, | ||
44 | //////////////////////////////////////////////////////////////////// | ||
45 | // | ||
46 | _observer: { | ||
47 | value: {head: null, body: null} | ||
48 | }, | ||
49 | //////////////////////////////////////////////////////////////////// | ||
50 | // | ||
51 | content: { | ||
52 | value: null | ||
53 | }, | ||
54 | //////////////////////////////////////////////////////////////////// | ||
55 | //TODO: Remove usage | ||
56 | model: { | ||
57 | value: null | ||
58 | }, | ||
59 | //////////////////////////////////////////////////////////////////// | ||
60 | // | ||
61 | document: { | ||
62 | get: function() {return this._document;}, | ||
63 | set: function(value) {this._document = value;} | ||
64 | }, | ||
65 | //////////////////////////////////////////////////////////////////// | ||
66 | // | ||
67 | propertiesPanel: { | ||
68 | value: null | ||
69 | }, | ||
70 | //////////////////////////////////////////////////////////////////// | ||
71 | // | ||
72 | _liveNodeList: { | ||
73 | value: null | ||
74 | }, | ||
75 | //////////////////////////////////////////////////////////////////// | ||
76 | // | ||
77 | getLiveNodeList: { | ||
78 | value: function(useFilter) { | ||
79 | if(useFilter) { | ||
80 | var filteredNodes = [], | ||
81 | childNodes = Array.prototype.slice.call(this._liveNodeList, 0); | ||
82 | |||
83 | childNodes.forEach(function(item) { | ||
84 | if( (item.nodeType === 1) && (item.nodeName !== "STYLE") && (item.nodeName !== "SCRIPT")) { | ||
85 | filteredNodes.push(item); | ||
86 | } | ||
87 | }); | ||
88 | return filteredNodes; | ||
89 | } else { | ||
90 | return Array.prototype.slice.call(this._liveNodeList, 0); | ||
91 | } | ||
92 | } | ||
93 | }, | ||
94 | //////////////////////////////////////////////////////////////////// | ||
95 | // | ||
96 | initialize: { | ||
97 | value: function (parent) { | ||
98 | //Creating iFrame for view | ||
99 | this.iframe = document.createElement("iframe"); | ||
100 | //Setting default styles | ||
101 | this.iframe.style.border = "none"; | ||
102 | this.iframe.style.background = "#FFF"; | ||
103 | this.iframe.style.height = "100%"; | ||
104 | this.iframe.style.width = "100%"; | ||
105 | //Returning reference to iFrame created | ||
106 | return parent.appendChild(this.iframe); | ||
107 | } | ||
108 | }, | ||
109 | //////////////////////////////////////////////////////////////////// | ||
110 | // | ||
111 | render: { | ||
112 | value: function (callback, template) { | ||
113 | //TODO: Remove, this is a temp patch for webRequest API gate | ||
114 | this.application.ninja.documentController.redirectRequests = false; | ||
115 | //Storing callback for dispatch ready | ||
116 | this._callback = callback; | ||
117 | this._template = template; | ||
118 | //Adding listener to know when template is loaded to then load user content | ||
119 | this.iframe.addEventListener("load", this.onTemplateLoad.bind(this), false); | ||
120 | //TODO: Add source parameter and root (optional) | ||
121 | if (template && template.type === 'banner' && template.size) { | ||
122 | this.iframe.src = "js/document/templates/banner/index.html"; | ||
123 | } else { | ||
124 | this.iframe.src = "js/document/templates/html/index.html"; | ||
125 | } | ||
126 | } | ||
127 | }, | ||
128 | //////////////////////////////////////////////////////////////////// | ||
129 | // | ||
130 | onTemplateLoad: { | ||
131 | value: function (e) { | ||
132 | //console.log(this.iframe.contentWindow); | ||
133 | this.application.ninja.documentController.redirectRequests = true; | ||
134 | //TODO: Add support to constructing URL with a base HREF | ||
135 | var basetag = this.content.document.getElementsByTagName('base'); | ||
136 | //Removing event | ||
137 | this.iframe.removeEventListener("load", this.onTemplateLoad.bind(this), false); | ||
138 | //TODO: Improve usage of this reference | ||
139 | this.document = this.iframe.contentWindow.document; | ||
140 | //Looping through template styles and marking them with ninja data attribute for I/O clean up | ||
141 | for (var k in this.document.styleSheets) { | ||
142 | if (this.document.styleSheets[k].ownerNode && this.document.styleSheets[k].ownerNode.setAttribute) { | ||
143 | this.document.styleSheets[k].ownerNode.setAttribute('data-ninja-template', 'true'); | ||
144 | } | ||
145 | } | ||
146 | //Checking for a base URL | ||
147 | if (basetag.length) { | ||
148 | if (basetag[basetag.length-1].getAttribute && basetag[basetag.length-1].getAttribute('href')) { | ||
149 | //Setting base HREF in model | ||
150 | this.model.baseHref = basetag[basetag.length-1].getAttribute('href'); | ||
151 | } | ||
152 | } | ||
153 | //Checking to content to be template | ||
154 | if (this._template) { | ||
155 | if (this._template.type === 'banner') { | ||
156 | //Loading contents into a fragment | ||
157 | this._bodyFragment = this.document.createElement('body'); | ||
158 | //Listening for content to be ready | ||
159 | this._observer.body = new WebKitMutationObserver(this.insertBannerContent.bind(this)); | ||
160 | this._observer.body.observe(this._bodyFragment, {childList: true}); | ||
161 | //Inserting <body> HTML and parsing URLs via mediator method | ||
162 | this._bodyFragment.innerHTML = '<ninjaloadinghack></ninjaloadinghack>'+(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)); | ||
163 | } | ||
164 | } else { | ||
165 | //Creating temp code fragement to load head | ||
166 | this._headFragment = this.document.createElement('head'); | ||
167 | //Adding event listener to know when head is ready, event only dispatched once when using innerHTML | ||
168 | this._observer.head = new WebKitMutationObserver(this.insertHeadContent.bind(this)); | ||
169 | this._observer.head.observe(this._headFragment, {childList: true}); | ||
170 | //Inserting <head> HTML and parsing URLs via mediator method | ||
171 | 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)); | ||
172 | //Adding event listener to know when the body is ready and make callback (using HTML5 new DOM Mutation Events) | ||
173 | this._observer.body = new WebKitMutationObserver(this.bodyContentLoaded.bind(this)); | ||
174 | this._observer.body.observe(this.document.body, {childList: true}); | ||
175 | //Inserting <body> HTML and parsing URLs via mediator method | ||
176 | this.document.body.innerHTML += '<ninjaloadinghack></ninjaloadinghack>'+(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)); | ||
177 | //Copying attributes to maintain same properties as the <body> | ||
178 | for (var n in this.content.document.body.attributes) { | ||
179 | if (this.content.document.body.attributes[n].value) { | ||
180 | this.document.body.setAttribute(this.content.document.body.attributes[n].name, this.content.document.body.attributes[n].value); | ||
181 | } | ||
182 | } | ||
183 | //TODO: Add attribute copying for <HEAD> and <HTML> | ||
184 | } | ||
185 | } | ||
186 | }, | ||
187 | //////////////////////////////////////////////////////////////////// | ||
188 | // | ||
189 | insertBannerContent: { | ||
190 | value: function (e) { | ||
191 | //Getting first element in DOM (assumes it's root) | ||
192 | //TODO: Ensure wrapper logic is proper | ||
193 | var wrapper = this._bodyFragment.getElementsByTagName('*')[1], | ||
194 | banner = this._bodyFragment.getElementsByTagName('*')[2], | ||
195 | ninjaBanner = this.document.body.getElementsByTagName('ninja-content')[0], | ||
196 | ninjaWrapper = this.document.body.getElementsByTagName('ninja-viewport')[0]; | ||
197 | //Copying attributes to maintain same properties as the banner wrapper | ||
198 | for (var n in wrapper.attributes) { | ||
199 | if (wrapper.attributes[n].value) { | ||
200 | ninjaWrapper.setAttribute(wrapper.attributes[n].name, wrapper.attributes[n].value); | ||
201 | } | ||
202 | } | ||
203 | //Copying attributes to maintain same properties as the banner content | ||
204 | for (var n in banner.attributes) { | ||
205 | if (banner.attributes[n].value) { | ||
206 | ninjaBanner.setAttribute(banner.attributes[n].name, banner.attributes[n].value); | ||
207 | } | ||
208 | } | ||
209 | //Adjusting margin per size of document | ||
210 | 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;}'; | ||
211 | //Setting content in template | ||
212 | ninjaBanner.innerHTML = banner.innerHTML; | ||
213 | //Garbage collection | ||
214 | this._bodyFragment = null; | ||
215 | //Calling standard method to finish opening document | ||
216 | this.bodyContentLoaded(null); | ||
217 | } | ||
218 | }, | ||
219 | //////////////////////////////////////////////////////////////////// | ||
220 | // | ||
221 | insertHeadContent: { | ||
222 | value: function (e) { | ||
223 | //Removing event | ||
224 | this._observer.head.disconnect(); | ||