1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.myfaces.tobago.renderkit.html.scarborough.standard.tag;
21
22 import org.apache.commons.lang.StringUtils;
23 import org.apache.myfaces.tobago.application.ProjectStage;
24 import org.apache.myfaces.tobago.component.Attributes;
25 import org.apache.myfaces.tobago.component.Facets;
26 import org.apache.myfaces.tobago.component.UIMenuBar;
27 import org.apache.myfaces.tobago.component.UIPage;
28 import org.apache.myfaces.tobago.component.UIPopup;
29 import org.apache.myfaces.tobago.config.Configurable;
30 import org.apache.myfaces.tobago.config.TobagoConfig;
31 import org.apache.myfaces.tobago.context.ClientProperties;
32 import org.apache.myfaces.tobago.context.Markup;
33 import org.apache.myfaces.tobago.context.ResourceManagerUtils;
34 import org.apache.myfaces.tobago.context.Theme;
35 import org.apache.myfaces.tobago.internal.ajax.AjaxInternalUtils;
36 import org.apache.myfaces.tobago.internal.component.AbstractUIPage;
37 import org.apache.myfaces.tobago.internal.layout.LayoutContext;
38 import org.apache.myfaces.tobago.internal.util.AccessKeyMap;
39 import org.apache.myfaces.tobago.internal.util.FacesContextUtils;
40 import org.apache.myfaces.tobago.internal.util.MimeTypeUtils;
41 import org.apache.myfaces.tobago.internal.util.ResponseUtils;
42 import org.apache.myfaces.tobago.layout.Measure;
43 import org.apache.myfaces.tobago.renderkit.PageRendererBase;
44 import org.apache.myfaces.tobago.renderkit.css.Classes;
45 import org.apache.myfaces.tobago.renderkit.css.Style;
46 import org.apache.myfaces.tobago.renderkit.html.HtmlAttributes;
47 import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
48 import org.apache.myfaces.tobago.renderkit.html.HtmlInputTypes;
49 import org.apache.myfaces.tobago.renderkit.html.util.HtmlRendererUtils;
50 import org.apache.myfaces.tobago.renderkit.util.RenderUtils;
51 import org.apache.myfaces.tobago.util.ComponentUtils;
52 import org.apache.myfaces.tobago.util.VariableResolverUtils;
53 import org.apache.myfaces.tobago.webapp.Secret;
54 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57
58 import javax.faces.application.Application;
59 import javax.faces.application.FacesMessage;
60 import javax.faces.application.ViewHandler;
61 import javax.faces.component.UIComponent;
62 import javax.faces.context.ExternalContext;
63 import javax.faces.context.FacesContext;
64 import javax.faces.context.ResponseWriter;
65 import java.io.IOException;
66 import java.util.ArrayList;
67 import java.util.Collection;
68 import java.util.Iterator;
69 import java.util.List;
70 import java.util.Map;
71 import java.util.Set;
72 import java.util.StringTokenizer;
73
74 public class PageRenderer extends PageRendererBase {
75
76 private static final Logger LOG = LoggerFactory.getLogger(PageRenderer.class);
77
78 private static final String CLIENT_DEBUG_SEVERITY = "clientDebugSeverity";
79 private static final String LAST_FOCUS_ID = "lastFocusId";
80
81 @Override
82 public void decode(FacesContext facesContext, UIComponent component) {
83 super.decode(facesContext, component);
84 String clientId = component.getClientId(facesContext);
85 ExternalContext externalContext = facesContext.getExternalContext();
86
87
88 String severity = (String)
89 externalContext.getRequestParameterMap().get(clientId + ComponentUtils.SUB_SEPARATOR + "clientSeverity");
90 if (severity != null) {
91 externalContext.getRequestMap().put(CLIENT_DEBUG_SEVERITY, severity);
92 }
93
94
95 String lastFocusId = (String)
96 externalContext.getRequestParameterMap().get(clientId + ComponentUtils.SUB_SEPARATOR + LAST_FOCUS_ID);
97 if (lastFocusId != null) {
98 FacesContextUtils.setFocusId(facesContext, lastFocusId);
99 }
100
101
102 String name = clientId + ComponentUtils.SUB_SEPARATOR + "scrollbarWeight";
103 String value = null;
104 try {
105 value = (String) facesContext.getExternalContext().getRequestParameterMap().get(name);
106 if (StringUtils.isNotBlank(value)) {
107 StringTokenizer tokenizer = new StringTokenizer(value, ";");
108 Measure vertical = Measure.valueOf(tokenizer.nextToken());
109 Measure horizontal = Measure.valueOf(tokenizer.nextToken());
110 if (vertical.greaterThan(Measure.valueOf(30)) || vertical.lessThan(Measure.valueOf(3))
111 || horizontal.greaterThan(Measure.valueOf(30)) || horizontal.lessThan(Measure.valueOf(3))) {
112 LOG.error("Ignoring strange values: vertical=" + vertical + " horizontal=" + horizontal);
113 } else {
114 ClientProperties client = VariableResolverUtils.resolveClientProperties(facesContext);
115 client.setVerticalScrollbarWeight(vertical);
116 client.setHorizontalScrollbarWeight(horizontal);
117 }
118 }
119 } catch (Exception e) {
120 LOG.error("Error in decoding '" + name + "': value='" + value + "'", e);
121 }
122 }
123
124 @Override
125 public void encodeBegin(FacesContext facesContext, UIComponent component) throws IOException {
126
127 final UIPage page = (UIPage) component;
128 final TobagoConfig tobagoConfig = TobagoConfig.getInstance(facesContext);
129
130
131 RenderUtils.prepareRendererAll(facesContext, page);
132
133 LayoutContext layoutContext = new LayoutContext(page);
134 layoutContext.layout();
135 if (FacesContextUtils.getFocusId(facesContext) == null && !StringUtils.isBlank(page.getFocusId())) {
136 FacesContextUtils.setFocusId(facesContext, page.getFocusId());
137 }
138 TobagoResponseWriter writer = HtmlRendererUtils.getTobagoResponseWriter(facesContext);
139
140
141 facesContext.setResponseWriter(writer);
142
143 ResponseUtils.ensureNoCacheHeader(facesContext);
144
145 ResponseUtils.ensureContentSecurityPolicyHeader(facesContext, tobagoConfig.getContentSecurityPolicy());
146
147 if (LOG.isDebugEnabled()) {
148 for (Object o : page.getAttributes().entrySet()) {
149 Map.Entry entry = (Map.Entry) o;
150 LOG.debug("*** '" + entry.getKey() + "' -> '" + entry.getValue() + "'");
151 }
152 }
153
154 Application application = facesContext.getApplication();
155 ViewHandler viewHandler = application.getViewHandler();
156 String viewId = facesContext.getViewRoot().getViewId();
157 String formAction = viewHandler.getActionURL(facesContext, viewId);
158 formAction = facesContext.getExternalContext().encodeActionURL(formAction);
159 String contentType = writer.getContentTypeWithCharSet();
160 ResponseUtils.ensureContentTypeHeader(facesContext, contentType);
161 String clientId = page.getClientId(facesContext);
162 final ClientProperties client = VariableResolverUtils.resolveClientProperties(facesContext);
163 final ProjectStage projectStage = tobagoConfig.getProjectStage();
164 final boolean developmentMode = projectStage == ProjectStage.Development;
165 final boolean debugMode = client.isDebugMode() || developmentMode;
166 final boolean productionMode = !debugMode && projectStage == ProjectStage.Production;
167 int clientLogSeverity = 2;
168 if (debugMode) {
169 String severity = (String) facesContext.getExternalContext().getRequestMap().get(CLIENT_DEBUG_SEVERITY);
170 if (LOG.isDebugEnabled()) {
171 LOG.debug("get " + CLIENT_DEBUG_SEVERITY + " = " + severity);
172 }
173 if (severity != null) {
174 try {
175 int index = severity.indexOf(';');
176 if (index == -1) {
177 index = severity.length();
178 }
179 clientLogSeverity = Integer.parseInt(severity.substring(0, index));
180 } catch (NumberFormatException e) {
181 }
182 }
183 boolean frameKiller = tobagoConfig.isPreventFrameAttacks();
184
185 if (!FacesContextUtils.isAjax(facesContext)) {
186 HtmlRendererUtils.renderDojoDndSource(facesContext, component);
187
188 String title = (String) page.getAttributes().get(Attributes.LABEL);
189
190 writer.startElement(HtmlElements.HEAD, null);
191
192
193
194
195 writer.startElement(HtmlElements.META, null);
196 writer.writeAttribute(HtmlAttributes.HTTP_EQUIV, "Content-Type", false);
197 writer.writeAttribute(HtmlAttributes.CONTENT, contentType, false);
198 writer.endElement(HtmlElements.META);
199
200
201 writer.startElement(HtmlElements.TITLE, null);
202 writer.writeText(title != null ? title : "");
203 writer.endElement(HtmlElements.TITLE);
204 final Theme theme = client.getTheme();
205
206 if (debugMode) {
207
208
209 writer.writeJavascript("var TbgHeadStart = new Date();");
210 }
211
212
213 for (String styleFile : theme.getStyleResources(productionMode)) {
214 writeStyle(facesContext, writer, styleFile);
215 }
216
217 for (String styleFile : FacesContextUtils.getStyleFiles(facesContext)) {
218 writeStyle(facesContext, writer, styleFile);
219 }
220
221 String icon = page.getApplicationIcon();
222 if (icon != null) {
223
224 if (ResourceManagerUtils.isAbsoluteResource(icon)) {
225
226 } else {
227 icon = ResourceManagerUtils.getImageWithPath(facesContext, icon);
228 }
229
230 writer.startElement(HtmlElements.LINK, null);
231 if (icon.endsWith(".ico")) {
232 writer.writeAttribute(HtmlAttributes.REL, "shortcut icon", false);
233 writer.writeAttribute(HtmlAttributes.HREF, icon, false);
234 } else {
235
236 writer.writeAttribute(HtmlAttributes.REL, "icon", false);
237 writer.writeAttribute(HtmlAttributes.TYPE, MimeTypeUtils.getMimeTypeForFile(icon), false);
238 writer.writeAttribute(HtmlAttributes.HREF, icon, false);
239 }
240 writer.endElement(HtmlElements.LINK);
241 }
242
243
244 Set<String> styleBlocks = FacesContextUtils.getStyleBlocks(facesContext);
245 if (styleBlocks.size() > 0) {
246 writer.startElement(HtmlElements.STYLE, null);
247 writer.flush();
248 for (String cssBlock : styleBlocks) {
249 writer.write(cssBlock);
250 }
251 writer.endElement(HtmlElements.STYLE);
252 }
253
254 if (debugMode) {
255 boolean hideClientLogging = true;
256 String severity = (String) facesContext.getExternalContext().getRequestMap().get(CLIENT_DEBUG_SEVERITY);
257 if (LOG.isDebugEnabled()) {
258 LOG.debug("get " + CLIENT_DEBUG_SEVERITY + " = " + severity);
259 }
260 if (severity != null) {
261 try {
262 int index = severity.indexOf(';');
263 if (index == -1) {
264 index = severity.length();
265 }
266 clientLogSeverity = Integer.parseInt(severity.substring(0, index));
267 } catch (NumberFormatException e) {
268 hideClientLogging = !severity.contains("show");
269 }
270
271
272 }
273
274
275 for (String scriptFile: theme.getScriptResources(productionMode)) {
276 encodeScript(facesContext, writer, scriptFile);
277 }
278
279 for (String scriptFile : FacesContextUtils.getScriptFiles(facesContext)) {
280 encodeScript(facesContext, writer, scriptFile);
281 }
282
283
284 writer.startJavascript();
285
286 writeEventFunction(writer, FacesContextUtils.getOnloadScripts(facesContext), "load", false);
287
288
289 writeEventFunction(writer, FacesContextUtils.getOnunloadScripts(facesContext), "unload", false);
290
291
292 writeEventFunction(writer, FacesContextUtils.getOnexitScripts(facesContext), "exit", false);
293
294 writeEventFunction(writer, FacesContextUtils.getOnsubmitScripts(facesContext), "submit", true);
295
296 int debugCounter = 0;
297 for (String scriptBlock : FacesContextUtils.getScriptBlocks(facesContext)) {
298
299 if (LOG.isDebugEnabled()) {
300 LOG.debug("write scriptblock " + ++debugCounter + " :\n" + scriptBlock);
301 }
302 writer.write(scriptBlock);
303 writer.write('\n');
304 }
305 writer.endJavascript();
306 writer.endElement(HtmlElements.HEAD);
307 }
308
309 writer.startElement(HtmlElements.BODY, page);
310 writer.writeIdAttribute(clientId);
311 writer.writeClassAttribute(Classes.create(page));
312 HtmlRendererUtils.writeDataAttributes(facesContext, writer, page);
313 HtmlRendererUtils.renderCommandFacet(page, facesContext, writer);
314
315 if (debugMode) {
316 writer.writeJavascript("TbgTimer.startBody = new Date();");
317 }
318
319 writer.startElement(HtmlElements.FORM, page);
320 if (frameKiller && !FacesContextUtils.isAjax(facesContext)) {
321 writer.writeAttribute(HtmlAttributes.STYLE, "display:none", false);
322 }
323 writer.writeAttribute(HtmlAttributes.ACTION, formAction, true);
324 writer.writeIdAttribute(page.getFormId(facesContext));
325 writer.writeAttribute(HtmlAttributes.METHOD, getMethod(page), false);
326 String enctype = FacesContextUtils.getEnctype(facesContext);
327 if (enctype != null) {
328 writer.writeAttribute(HtmlAttributes.ENCTYPE, enctype, false);
329 }
330
331 writer.writeAttribute(HtmlAttributes.ACCEPT_CHARSET, AbstractUIPage.FORM_ACCEPT_CHARSET, false);
332
333
334 writer.startElement(HtmlElements.INPUT, null);
335 writer.writeAttribute(HtmlAttributes.TYPE, HtmlInputTypes.HIDDEN, false);
336 writer.writeNameAttribute(clientId + ComponentUtils.SUB_SEPARATOR + "form-action");
337 writer.writeIdAttribute(clientId + ComponentUtils.SUB_SEPARATOR + "form-action");
338 writer.endElement(HtmlElements.INPUT);
339
340 writer.startElement(HtmlElements.INPUT, null);
341 writer.writeAttribute(HtmlAttributes.TYPE, HtmlInputTypes.HIDDEN, false);
342 writer.writeNameAttribute(clientId + ComponentUtils.SUB_SEPARATOR + "context-path");
343 writer.writeIdAttribute(clientId + ComponentUtils.SUB_SEPARATOR + "context-path");
344 writer.writeAttribute(HtmlAttributes.VALUE, facesContext.getExternalContext().getRequestContextPath(), true);
345 writer.endElement(HtmlElements.INPUT);
346
347 writer.startElement(HtmlElements.INPUT, null);
348 writer.writeAttribute(HtmlAttributes.TYPE, HtmlInputTypes.HIDDEN, false);
349 writer.writeNameAttribute(clientId + ComponentUtils.SUB_SEPARATOR + "action-position");
350 writer.writeIdAttribute(clientId + ComponentUtils.SUB_SEPARATOR + "action-position");
351 writer.endElement(HtmlElements.INPUT);
352
353 boolean calculateScrollbarWeight =
354 client.getVerticalScrollbarWeight() == null || client.getHorizontalScrollbarWeight() == null;
355
356 if (calculateScrollbarWeight) {
357 writer.startElement(HtmlElements.DIV, null);
358 writer.writeClassAttribute(Classes.create(page, "scrollbarWeight", Markup.NULL));
359 writer.startElement(HtmlElements.DIV, null);
360 writer.endElement(HtmlElements.DIV);
361 writer.endElement(HtmlElements.DIV);
362 }
363
364 writer.startElement(HtmlElements.INPUT, null);
365 writer.writeAttribute(HtmlAttributes.TYPE, HtmlInputTypes.HIDDEN, false);
366 writer.writeNameAttribute(clientId + ComponentUtils.SUB_SEPARATOR + "scrollbarWeight");
367 writer.writeIdAttribute(clientId + ComponentUtils.SUB_SEPARATOR + "scrollbarWeight");
368 if (client.getVerticalScrollbarWeight() != null && client.getHorizontalScrollbarWeight() != null) {
369 StringBuilder buf = new StringBuilder();
370 buf.append(client.getVerticalScrollbarWeight().getPixel());
371 buf.append(";");
372 buf.append(client.getHorizontalScrollbarWeight().getPixel());
373 writer.writeAttribute(HtmlAttributes.VALUE, buf.toString(), false);
374 }
375 writer.endElement(HtmlElements.INPUT);
376
377 if (TobagoConfig.getInstance(FacesContext.getCurrentInstance()).isCreateSessionSecret()) {
378 Secret.encode(facesContext, writer);
379 }
380
381 if (debugMode) {
382 writer.startElement(HtmlElements.INPUT, null);
383 writer.writeAttribute(HtmlAttributes.VALUE, clientLogSeverity);
384 writer.writeAttribute(HtmlAttributes.ID, clientId + ComponentUtils.SUB_SEPARATOR + "clientSeverity", false);
385 writer.writeAttribute(HtmlAttributes.NAME, clientId + ComponentUtils.SUB_SEPARATOR + "clientSeverity", false);
386 writer.writeAttribute(HtmlAttributes.TYPE, HtmlInputTypes.HIDDEN, false);
387 writer.endElement(HtmlElements.INPUT);
388 }
389
390 if (component.getFacet("backButtonDetector") != null) {
391 UIComponent hidden = component.getFacet("backButtonDetector");
392 RenderUtils.encode(facesContext, hidden);
393 }
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412 UIMenuBar menuBar = (UIMenuBar) page.getFacet(Facets.MENUBAR);
413 if (menuBar != null) {
414 menuBar.getAttributes().put(Attributes.PAGE_MENU, Boolean.TRUE);
415 RenderUtils.encode(facesContext, menuBar);
416 }
417
418
419
420
421
422 writer.startElement(HtmlElements.DIV, page);
423 writer.writeClassAttribute(Classes.create(page, "content"));
424 writer.writeIdAttribute(clientId + ComponentUtils.SUB_SEPARATOR + "content");
425 Style style = new Style(facesContext, page);
426
427
428
429 Measure border = getBorderBottom(facesContext, page);
430 style.setHeight(page.getCurrentHeight().subtract(border));
431 style.setTop(border);
432 writer.writeStyleAttribute(style);
433 }
434
435 private void writeStyle(FacesContext facesContext, TobagoResponseWriter writer, String styleFile)
436 throws IOException {
437 List<String> styles = ResourceManagerUtils.getStyles(facesContext, styleFile);
438 for (String styleString : styles) {
439 if (styleString.length() > 0) {
440 writer.startElement(HtmlElements.LINK, null);
441 writer.writeAttribute(HtmlAttributes.REL, "stylesheet", false);
442 writer.writeAttribute(HtmlAttributes.HREF, styleString, false);
443
444 writer.writeAttribute(HtmlAttributes.TYPE, "text/css", false);
445 writer.endElement(HtmlElements.LINK);
446 }
447 }
448 }
449
450
451
452
453
454
455
456 @Override
457 public void encodeEnd(FacesContext facesContext, UIComponent component) throws IOException {
458
459
460 UIPage page = (UIPage) component;
461 TobagoResponseWriter writer = HtmlRendererUtils.getTobagoResponseWriter(facesContext);
462
463 writer.endElement(HtmlElements.DIV);
464
465
466
467
468
469 UIPopup[] popupArray = FacesContextUtils.getPopups(facesContext).toArray(
470 new UIPopup[FacesContextUtils.getPopups(facesContext).size()]);
471 for (UIPopup popup : popupArray) {
472 RenderUtils.encode(facesContext, popup);
473 }
474
475 String clientId = page.getClientId(facesContext);
476 final boolean debugMode = VariableResolverUtils.resolveClientProperties(facesContext).isDebugMode();
477
478
479
480 if (VariableResolverUtils.resolveClientProperties(facesContext).getUserAgent().isMsie()) {
481 writer.startElement(HtmlElements.INPUT, null);
482 writer.writeAttribute(HtmlAttributes.TYPE, HtmlInputTypes.TEXT, false);
483 writer.writeAttribute(HtmlAttributes.NAME, "tobago.dummy", false);
484 writer.writeAttribute(HtmlAttributes.TABINDEX, "-1", false);
485 writer.writeAttribute(HtmlAttributes.STYLE, "visibility:hidden;display:none;", false);
486 writer.endElement(HtmlElements.INPUT);
487 }
488
489 List<String> messageClientIds = AjaxInternalUtils.getMessagesClientIds(facesContext);
490 if (messageClientIds != null) {
491 writer.startElement(HtmlElements.INPUT, null);
492 writer.writeAttribute(HtmlAttributes.VALUE, StringUtils.join(messageClientIds, ','), true);
493 writer.writeAttribute(HtmlAttributes.ID, clientId + ComponentUtils.SUB_SEPARATOR + "messagesClientIds", false);
494 writer.writeAttribute(HtmlAttributes.NAME, clientId + ComponentUtils.SUB_SEPARATOR + "messagesClientIds", false);
495 writer.writeAttribute(HtmlAttributes.TYPE, HtmlInputTypes.HIDDEN, false);
496 writer.endElement(HtmlElements.INPUT);
497 }
498
499
500 writer.startElement(HtmlElements.DIV, page);
501 writer.writeClassAttribute(Classes.create(page, "menuStore"));
502 writer.endElement(HtmlElements.DIV);
503
504 Application application = facesContext.getApplication();
505 ViewHandler viewHandler = application.getViewHandler();
506
507 writer.startElement(HtmlElements.SPAN, null);
508 writer.writeIdAttribute(clientId + ComponentUtils.SUB_SEPARATOR + "jsf-state-container");
509 writer.flush();
510 if (!FacesContextUtils.isAjax(facesContext)) {
511 viewHandler.writeState(facesContext);
512 }
513 writer.endElement(HtmlElements.SPAN);
514
515
516 writer.endElement(HtmlElements.FORM);
517
518
519
520
521 writer.startElement(HtmlElements.IMG, null);
522 writer.writeClassAttribute(Classes.create(page, "overlayWaitPreloadedImage"));
523 final String wait = ResourceManagerUtils.getImageWithPath(facesContext, "image/tobago-overlay-wait.gif");
524 writer.writeAttribute(HtmlAttributes.SRC, wait, false);
525 writer.endElement(HtmlElements.IMG);
526
527 writer.startElement(HtmlElements.IMG, null);
528 writer.writeClassAttribute(Classes.create(page, "overlayErrorPreloadedImage"));
529 final String error = ClientProperties.getInstance(facesContext).getUserAgent().isMsie6()
530 ? ResourceManagerUtils.getImageWithPath(facesContext, "image/remove.gif")
531 : ResourceManagerUtils.getImageWithPath(facesContext, "image/dialog-error.png");
532 writer.writeAttribute(HtmlAttributes.SRC, error, false);
533 writer.endElement(HtmlElements.IMG);
534
535 writer.startElement(HtmlElements.IMG, null);
536 writer.writeClassAttribute(Classes.create(page, "pngFixBlankImage"));
537 final String pngFixBlankImage = ResourceManagerUtils.getImageWithPath(facesContext, "image/blank.gif");
538 writer.writeAttribute(HtmlAttributes.SRC, pngFixBlankImage, false);
539 writer.endElement(HtmlElements.IMG);
540
541 writer.startElement(HtmlElements.IMG, null);
542 writer.writeClassAttribute(Classes.create(page, "overlayBackgroundImage"));
543 final String overlayBackgroundImage = ResourceManagerUtils.getImageWithPath(facesContext,
544 "image/tobago-overlay-background.png");
545 writer.writeAttribute(HtmlAttributes.SRC, overlayBackgroundImage, false);
546 writer.endElement(HtmlElements.IMG);
547
548
549 if (debugMode) {
550 List<String> logMessages = new ArrayList<String>();
551 for (Iterator ids = facesContext.getClientIdsWithMessages();
552 ids.hasNext();) {
553 String id = (String) ids.next();
554 for (Iterator messages = facesContext.getMessages(id);
555 messages.hasNext();) {
556 FacesMessage message = (FacesMessage) messages.next();
557 logMessages.add(errorMessageForDebugging(id, message));
558 }
559
560 }
561 if (!logMessages.isEmpty()) {
562 logMessages.add(0, "LOG.show();");
563 }
564
565 HtmlRendererUtils.writeScriptLoader(facesContext, null,
566 logMessages.toArray(new String[logMessages.size()]));
567 }
568
569 if (debugMode) {
570 writer.writeJavascript("TbgTimer.endBody = new Date();");
571 }
572
573
574
575 writer.startElement(HtmlElements.NOSCRIPT, null);
576 writer.startElement(HtmlElements.DIV, null);
577 writer.writeClassAttribute(Classes.create(page, "noscript"));
578 writer.writeText(ResourceManagerUtils.getPropertyNotNull(facesContext, "tobago", "pageNoscript"));
579 writer.endElement(HtmlElements.DIV);
580 writer.endElement(HtmlElements.NOSCRIPT);
581
582 writer.endElement(HtmlElements.BODY);
583
584 if (LOG.isDebugEnabled()) {
585 LOG.debug("unused AccessKeys : "
586 + AccessKeyMap.getUnusedKeys(facesContext));
587 LOG.debug("duplicated AccessKeys: "
588 + AccessKeyMap.getDublicatedKeys(facesContext));
589 }
590
591 if (facesContext.getExternalContext().getRequestParameterMap().get("X") != null) {
592 throw new RuntimeException("Debugging activated via X parameter");
593 }
594 }
595
596 private void writeEventFunction(TobagoResponseWriter writer, Collection<String> eventFunctions,
597 String event, boolean returnBoolean) throws IOException {
598 if (!eventFunctions.isEmpty()) {
599 writer.write("Tobago.applicationOn");
600 writer.write(event);
601 writer.write(" = function() {\n");
602 if (returnBoolean) {
603 writer.write(" var result;\n");
604 }
605 for (String function : eventFunctions) {
606 if (returnBoolean) {
607 writer.write(" result = ");
608 } else {
609 writer.write(" ");
610 }
611 writer.write(function);
612 if (!function.trim().endsWith(";")) {
613 writer.write(";\n");
614 } else {
615 writer.write("\n");
616 }
617 if (returnBoolean) {
618 writer.write(" if (typeof result == \"boolean\" && ! result) {\n");
619 writer.write(" return false;\n");
620 writer.write(" }\n");
621 }
622 }
623 writer.write("\n return true;\n}\n");
624 }
625 }
626
627 private void encodeScript(FacesContext facesContext, TobagoResponseWriter writer, String script) throws IOException {
628 List<String> list;
629 if (ResourceManagerUtils.isAbsoluteResource(script)) {
630 list = new ArrayList<String>();
631 list.add(script);
632 } else {
633 list = ResourceManagerUtils.getScripts(facesContext, script);
634 }
635 for (String src : list) {
636 if (StringUtils.isNotBlank(src)) {
637 writer.startElement(HtmlElements.SCRIPT, null);
638 writer.writeAttribute(HtmlAttributes.SRC, src, true);
639
640
641 writer.writeAttribute(HtmlAttributes.TYPE, "text/javascript", false);
642 writer.endElement(HtmlElements.SCRIPT);
643 }
644 }
645 }
646
647 private void errorMessageForDebugging(String id, FacesMessage message,
648 ResponseWriter writer) throws IOException {
649 writer.startElement(HtmlElements.DIV, null);
650 writer.writeAttribute(HtmlAttributes.STYLE, "color: red", null);
651 writer.flush();
652 writer.write("[");
653 writer.write(id != null ? id : "null");
654 writer.write("]");
655 writer.write("[");
656 writer.write(message.getSummary() == null ? "null" : message.getSummary());
657 writer.write("/");
658 writer.write(message.getDetail() == null ? "null" : message.getDetail());
659 writer.write("]");
660 writer.endElement(HtmlElements.DIV);
661 writer.startElement(HtmlElements.BR, null);
662 writer.endElement(HtmlElements.BR);
663 }
664
665 private String errorMessageForDebugging(String id, FacesMessage message) {
666 StringBuilder sb = new StringBuilder("LOG.info(\"FacesMessage: [");
667 sb.append(id != null ? id : "null");
668 sb.append("][");
669 sb.append(message.getSummary() == null ? "null" : escape(message.getSummary()));
670 sb.append("/");
671 sb.append(message.getDetail() == null ? "null" : escape(message.getDetail()));
672 sb.append("]\");");
673 return sb.toString();
674 }
675
676 private String escape(String s) {
677 return StringUtils.replace(StringUtils.replace(s, "\\", "\\\\"), "\"", "\\\"");
678 }
679
680 private String getMethod(UIPage page) {
681 String method = (String) page.getAttributes().get(Attributes.METHOD);
682 return method == null ? "post" : method;
683 }
684
685 @Override
686 public boolean getRendersChildren() {
687 return true;
688 }
689
690 @Override
691 public Measure getBorderBottom(FacesContext facesContext, Configurable component) {
692
693
694 UIPage page = (UIPage) component;
695 UIMenuBar menuBar = (UIMenuBar) page.getFacet(Facets.MENUBAR);
696 if (menuBar != null) {
697 return getResourceManager().getThemeMeasure(facesContext, page, "custom.menuBar-height");
698 } else {
699 return Measure.ZERO;
700 }
701 }
702
703 @Override
704 public Measure getWidth(FacesContext facesContext, Configurable component) {
705
706 Measure width = (Measure) FacesContext.getCurrentInstance().getExternalContext()
707 .getRequestMap().get("tobago-page-clientDimension-width");
708 if (width != null) {
709 return width;
710 } else {
711 return super.getWidth(facesContext, component);
712 }
713 }
714
715 @Override
716 public Measure getHeight(FacesContext facesContext, Configurable component) {
717
718 Measure height = (Measure) FacesContext.getCurrentInstance().getExternalContext()
719 .getRequestMap().get("tobago-page-clientDimension-height");
720 if (height != null) {
721 return height;
722 } else {
723 return super.getHeight(facesContext, component);
724 }
725 }
726 }