aboutsummaryrefslogtreecommitdiff
path: root/js/document/views/design.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/document/views/design.js')
-rwxr-xr-xjs/document/views/design.js259
1 files changed, 255 insertions, 4 deletions
diff --git a/js/document/views/design.js b/js/document/views/design.js
index 84871257..b23ebe78 100755
--- a/js/document/views/design.js
+++ b/js/document/views/design.js
@@ -7,16 +7,267 @@ No rights, expressed or implied, whatsoever to this software are provided by Mot
7//////////////////////////////////////////////////////////////////////// 7////////////////////////////////////////////////////////////////////////
8// 8//
9var Montage = require("montage/core/core").Montage, 9var 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//
14exports.DesignDocumentView = Montage.create(CodeDocumentView, { 13exports.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 _document: {
27 value: null
28 },
29 ////////////////////////////////////////////////////////////////////
30 //
31 _headFragment: {
32 value: null
33 },
34 ////////////////////////////////////////////////////////////////////
35 //
36 _observer: {
37 value: {head: null, body: null}
38 },
39 ////////////////////////////////////////////////////////////////////
40 //
41 content: {
42 value: null
43 },
44 ////////////////////////////////////////////////////////////////////
45 //
46 document: {
47 get: function() {return this._document;},
48 set: function(value) {this._document = value;}
49 },
50 ////////////////////////////////////////////////////////////////////
51 //
52 initialize: {
53 value: function (parent) {
54 //Creating iFrame for view
55 this.iframe = document.createElement("iframe");
56 //Setting default styles
57 this.iframe.style.border = "none";
58 this.iframe.style.background = "#FFF";
59 this.iframe.style.height = "100%";
60 this.iframe.style.width = "100%";
61 //Returning reference to iFrame created
62 return parent.appendChild(this.iframe);
63 }
64 },
65 ////////////////////////////////////////////////////////////////////
66 //
67 render: {
68 value: function (callback, template) {//TODO: Add support for templates
69 //Storing callback for dispatch ready
70 this._callback = callback;
71 //Adding listener to know when template is loaded to then load user content
72 this.iframe.addEventListener("load", this.onTemplateLoad.bind(this), false);
73 //TODO: Add source parameter and root (optional)
74 this.iframe.src = "js/document/templates/montage-web/index.html";
75 }
76 },
77 ////////////////////////////////////////////////////////////////////
78 //
79 onTemplateLoad: {
80 value: function (e) {
81 //Removing event
82 this.iframe.removeEventListener("load", this.onTemplateLoad.bind(this), false);
83 //TODO: Improve usage of this reference
84 this.document = this.iframe.contentWindow.document;
85 //Looping through template styles and marking them with ninja data attribute for I/O clean up
86 for (var k in this.document.styleSheets) {
87 if (this.document.styleSheets[k].ownerNode && this.document.styleSheets[k].ownerNode.setAttribute) {
88 this.document.styleSheets[k].ownerNode.setAttribute('data-ninja-template', 'true');
89 }
90 }
91 //Creating temp code fragement to load head
92 this._headFragment = this.document.createElement('head');
93 //Adding event listener to know when head is ready, event only dispatched once when using innerHTML
94 this._observer.head = new WebKitMutationObserver(this.insertHeadContent.bind(this));
95 this._observer.head.observe(this._headFragment, {childList: true});
96 //Inserting <head> HTML and parsing URLs via mediator method
97 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));
98 //Adding event listener to know when the body is ready and make callback (using HTML5 new DOM Mutation Events)
99 this._observer.body = new WebKitMutationObserver(this.bodyContentLoaded.bind(this));
100 this._observer.body.observe(this.document.body, {childList: true});
101 //Inserting <body> HTML and parsing URLs via mediator method
102 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));
103 }
104 },
105 ////////////////////////////////////////////////////////////////////
106 //
107 insertHeadContent: {
108 value: function (e) {
109 //Removing event
110 this._observer.head.disconnect();
111 this._observer.head = null;
112 //Adding the loaded nodes from code fragment into actual document head
113 for(var i in this._headFragment.childNodes) {
114 //Minor hack to know node is actual HTML node
115 if(this._headFragment.childNodes[i].outerHTML) {
116 this.document.head.appendChild(this._headFragment.childNodes[i]);
117 }
118 }
119 //Garbage collection
120 this._headFragment = null;
121 }
122 },
123 ////////////////////////////////////////////////////////////////////
124 //
125 bodyContentLoaded: {
126 value: function (e) {
127 //Removing event, only needed on initial load
128 this._observer.body.disconnect();
129 this._observer.body = null;
130 //Removing loading container
131 this.document.body.removeChild(this.document.getElementsByTagName('ninjaloadinghack')[0]);
132 //Getting style and link tags in document
133 var stags = this.document.getElementsByTagName('style'),
134 ltags = this.document.getElementsByTagName('link'), i,
135 scripttags = this.document.getElementsByTagName('script');
136 //Temporarily checking for disabled special case (we must enabled for Ninja to access styles)
137 this.ninjaDisableAttribute(stags);
138 this.ninjaDisableAttribute(ltags);
139 //Looping through all link tags to reload into style tags
140 if(ltags.length > 0) {
141 for (i = 0; i < ltags.length; i++) {
142 //
143 if (ltags[i].href) {
144 //TODO: Verify this works for tags in body as well (working in head)
145 this.document.head.insertBefore(this.getStyleTagFromCssFile(ltags[i]), ltags[i]) || this.document.body.insertBefore(this.getStyleTagFromCssFile(ltags[i]), ltags[i]);
146 //Disabling tag once it has been reloaded
147 ltags[i].setAttribute('disabled', 'true');
148 } else {
149 //Error: TBD
150 //TODO: Determine what link tags would not have href data and error
151 }
152 }
153 }
154 //Checking and initializing webGL
155 if (scripttags.length > 0) {
156 this.initWebGl(scripttags);
157 } //Else there is not data to parse
158
159
160
161 //TODO: Load Montage Components (blocking)
162 //this.initMontage();
163
164
165 //Makign callback if specified
166 if (this._callback) this._callback();
167 }
168 },
169 ////////////////////////////////////////////////////////////////////
170 //
171 ninjaDisableAttribute: {
172 value: function (tags) {
173 //Looping through tags
174 for (var i = 0; i < tags.length; i++) {
175 if (tags[i].getAttribute('data-ninja-template') === null) {
176 if (tags[i].getAttribute('disabled')) {
177 tags[i].removeAttribute('disabled');
178 tags[i].setAttribute('data-ninja-disabled', 'true');
179 }
180 }
181 }
182 }
183 },
184 ////////////////////////////////////////////////////////////////////
185 //TODO: Move to url-parser helper class
186 getStyleTagFromCssFile: {
187 value: function (linktag) {
188 //
189 var tag, cssData,
190 //TODO: Remove usage of hack reference of URL
191 docRootUrl = this.application.ninja.coreIoApi.rootUrl+escape((this.application.ninja.documentController.documentHackReference.root.split(this.application.ninja.coreIoApi.cloudData.root)[1]).replace(/\/\//gi, '/'));
192 //Creating style tag to load CSS content into
193 tag = this.document.createElement('style');
194 tag.setAttribute('type', 'text/css');
195 //Checking for location of href to load (special case for cross-domain)
196 if (linktag.href.indexOf(this.application.ninja.coreIoApi.rootUrl) !== -1) {
197 //Loading data from file
198 cssData = this.urlParser.loadLocalStyleSheet(linktag.href);
199 //Setting properties of locally loaded styles
200 tag.setAttribute('data-ninja-uri', cssData.fileUri);
201 tag.setAttribute('data-ninja-file-url', cssData.cssUrl);
202 tag.setAttribute('data-ninja-file-read-only', cssData.writable);
203 tag.setAttribute('data-ninja-file-name', cssData.cssUrl.split('/')[cssData.cssUrl.split('/').length-1]);
204 } else {
205 //Cross-domain content
206 cssData = this.urlParser.loadExternalStyleSheet(linktag.href);
207 //Setting properties of externally loaded styles
208 tag.setAttribute('data-ninja-external-url', linktag.href);
209 tag.setAttribute('data-ninja-file-read-only', "true");
210 tag.setAttribute('data-ninja-file-name', linktag.href.split('/')[linktag.href.split('/').length-1]);
211 }
212 //Copying attributes to maintain same properties as the <link>
213 for (var n in linktag.attributes) {
214 if (linktag.attributes[n].value && linktag.attributes[n].name !== 'disabled') {
215 if (linktag.attributes[n].value.indexOf(docRootUrl) !== -1) {
216 tag.setAttribute(linktag.attributes[n].name, linktag.attributes[n].value.split(docRootUrl)[1]);
217 } else {
218 tag.setAttribute(linktag.attributes[n].name, linktag.attributes[n].value);
219 }
220 }
221 }
222 //Setting content from loaded data