-
Notifications
You must be signed in to change notification settings - Fork 821
/
LeftAndMain.Preview.js
306 lines (261 loc) · 9.28 KB
/
LeftAndMain.Preview.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
(function($) {
$.entwine('ss', function($){
/**
* Shows a previewable website state alongside its editable version in backend UI,
* typically a page. This allows CMS users to seamlessly switch between preview and
* edit mode in the same browser window. The preview panel is embedded in the layout
* of the backend UI, and loads its content via an iframe.
*
* The admin UI itself is collapsible, leaving most screen space to this panel.
*
* Relies on the server responses to indicate if a preview URL is available for the
* currently loaded admin interface. If no preview is available, the panel is "blocked"
* automatically.
*
* Internal links within the preview iframe trigger a refresh of the admin panel as well,
* while all external links are disabled (via JavaScript).
*/
$('.cms-preview').entwine({
// Minimum width to keep the CMS operational
SharedWidth: null,
onadd: function() {
var self = this, layoutContainer = this.parent();
// this.resizable({
// handles: 'w',
// stop: function(e, ui) {
// $('.cms-container').layout({resize: false});
// }
// });
// TODO Compute dynamically
this.setSharedWidth(500);
// Create layout and controls
this.find('iframe').addClass('center');
this.find('iframe').bind('load', function() {
self._fixIframeLinks();
// Load edit view for new page, but only if the preview is activated at the moment.
// This avoids e.g. force-redirections of the edit view on RedirectorPage instances.
if(!self.is('.is-collapsed')) self.loadCurrentPage();
});
if(this.hasClass('is-expanded')) this.expand();
else this.collapse();
this.data('cms-preview-initialized', true);
// Preview might not be available in all admin interfaces - block/disable when necessary
this.append('<div class="cms-preview-overlay ui-widget-overlay-light"></div>');
this.find('.cms-preview-overlay-light').hide();
$('.cms-preview-toggle-link')[this.canPreview() ? 'show' : 'hide']();
self._fixIframeLinks();
this._super();
},
loadUrl: function(url) {
this.find('iframe').attr('src', url);
},
updateAfterXhr: function(){
$('.cms-preview-toggle-link')[this.canPreview() ? 'show' : 'hide']();
// Only load when panel is visible (see details in iframe load event handler).
if(this.is('.is-collapsed')) return;
// var url = ui.xmlhttp.getResponseHeader('x-frontend-url');
var url = $('.cms-edit-form').find(':input[name=PreviewURL],:input[name=StageURLSegment]').val();
if(url) {
this.loadUrl(url);
this.unblock();
} else {
this.block();
}
},
'from .cms-container': {
onaftersubmitform: function(){
this.updateAfterXhr();
},
onafterstatechange: function(){
this.updateAfterXhr();
}
},
// Toggle preview when new menu entry is selected.
// Only do this when preview is actually shown,
// to avoid auto-expanding the menu in normal CMS mode
'from .cms-menu-list li': {
onselect: function(){
if(!this.hasClass('is-collapsed')) this.collapse();
}
},
/**
* Loads the matching edit form for a page viewed in the preview iframe,
* based on metadata sent along with this document.
*/
loadCurrentPage: function() {
var doc = this.find('iframe')[0].contentDocument, containerEl = this.getLayoutContainer();
if(!this.canPreview()) return;
// Load this page in the admin interface if appropriate
var id = $(doc).find('meta[name=x-page-id]').attr('content');
var editLink = $(doc).find('meta[name=x-cms-edit-link]').attr('content');
var contentPanel = $('.cms-content');
if(id && contentPanel.find(':input[name=ID]').val() != id) {
// Ignore behaviour without history support (as we need ajax loading
// for the new form to load in the background)
if(window.History.enabled)
$('.cms-container').loadPanel(editLink);
}
},
/**
* Determines if the current interface is capable of previewing its managed record.
*
* Returns: {boolean}
*/
canPreview: function() {
var contentEl = this.getLayoutContainer().find('.cms-content');
// Only load if we're in the "edit page" view
var blockedClasses = ['CMSPagesController', 'CMSSettingsController', 'CMSPageHistoryController'];
return !(contentEl.is('.' + blockedClasses.join(',.')));
},
_fixIframeLinks: function() {
var doc = this.find('iframe')[0].contentDocument;
if(!doc) return;
// Block outside links from going anywhere
var links = doc.getElementsByTagName('A');
for (var i = 0; i < links.length; i++) {
var href = links[i].getAttribute('href');
if(!href) continue;
// Open external links in new window to avoid "escaping" the
// internal page context in the preview iframe,
// which is important to stay in for the CMS logic.
if (href.match(/^http:\/\//)) links[i].setAttribute('target', '_blank');
}
// Hide duplicate navigator, as it replicates existing UI in the CMS
var navi = doc.getElementById('SilverStripeNavigator');
if(navi) navi.style.display = 'none';
var naviMsg = doc.getElementById('SilverStripeNavigatorMessage');
if(naviMsg) naviMsg.style.display = 'none';
},
expand: function(inclMenu) {
var self = this, containerEl = this.getLayoutContainer(), contentEl = containerEl.find('.cms-content');
this.show();
this.removeClass('east').addClass('center').removeClass('is-collapsed');
// this.css('overflow', 'auto');
contentEl.removeClass('center').hide();
this.find('iframe').show();
this.find('.cms-preview-toggle a').html('»');
this.find('.cms-preview-controls').show();
if(this.data('cms-preview-initialized')) {
containerEl.find('.cms-menu').collapsePanel();
}
containerEl.redraw();
},
collapse: function() {
var self = this, containerEl = this.getLayoutContainer(), contentEl = containerEl.find('.cms-content');
this.addClass('east').removeClass('center').addClass('is-collapsed').width(10);
// this.css('overflow', 'hidden');
contentEl.addClass('center').show().css('visibility', 'visible');
this.find('iframe').hide();
this.find('.cms-preview-toggle a').html('«');
this.find('.cms-preview-controls').hide();
if(this.data('cms-preview-initialized')) {
containerEl.find('.cms-menu').expandPanel();
}
containerEl.redraw();
},
block: function() {
this.addClass('blocked');
},
unblock: function() {
this.removeClass('blocked');
},
getLayoutContainer: function() {
return this.parents('.cms-container');
},
toggle: function(bool) {
this[this.hasClass('is-collapsed') ? 'expand' : 'collapse']();
},
redraw: function() {
if(window.debug) console.log('redraw', this.attr('class'), this.get(0));
this.layout({resize: false});
}
});
$('.cms-preview.collapsed').entwine({
onmatch: function() {
this.find('a').text('<');
this._super();
},
onunmatch: function() {
this._super();
}
});
$('.cms-preview.blocked').entwine({
onmatch: function() {
this.find('.cms-preview-overlay').show();
this._super();
},
onunmatch: function() {
this.find('.cms-preview-overlay').hide();
this._super();
}
});
$('.cms-preview.expanded').entwine({
onmatch: function() {
this.find('a').text('>');
this._super();
},
onunmatch: function() {
this._super();
}
});
$('.cms-preview .cms-preview-toggle').entwine({
onclick: function(e) {
e.preventDefault();
this.parents('.cms-preview').toggle();
}
});
$('.cms-switch-view a').entwine({
onclick: function(e) {
e.preventDefault();
var preview = $('.cms-preview');
preview.toggle(true);
preview.loadUrl($(e.target).attr('href'));
}
});
$('.cms-menu li').entwine({
onclick: function(e) {
// Prevent reloading of interface when opening the edit panel
if(this.hasClass('Menu-CMSMain')) {
var preview = $('.cms-preview');
preview.toggle(true);
e.preventDefault();
}
}
});
$('.cms-preview .cms-preview-states').entwine({
onmatch: function() {
this.find('a').addClass('disabled');
this.find('.active a').removeClass('disabled');
this.find('.cms-preview-watermark').show();
this.find('.active .cms-preview-watermark').hide();
this._super();
},
onunmatch: function() {
this._super();
}
});
$('.cms-preview .cms-preview-states a').entwine({
onclick: function(e) {
e.preventDefault();
this.parents('.cms-preview').loadUrl(this.attr('href'));
this.addClass('disabled');
this.parents('.cms-preview-states').find('a').not(this).removeClass('disabled');
//This hides all watermarks
this.parents('.cms-preview-states').find('.cms-preview-watermark').hide();
//Show the watermark for the current state
this.siblings('.cms-preview-watermark').show();
}
});
$('.cms-preview-toggle-link').entwine({
onclick: function(e) {
e.preventDefault();
var preview = $('.cms-preview'), url = $('.cms-edit-form').find(':input[name=PreviewURL],:input[name=StageURLSegment]').val();
if(url) {
preview.loadUrl(url);
preview.unblock();
preview.toggle();
}
}
});
});
}(jQuery));