Package org.itsnat.impl.core.resp.shared.html

Source Code of org.itsnat.impl.core.resp.shared.html.ResponseDelegateHTMLLoadDocImpl

/*
  ItsNat Java Web Application Framework
  Copyright (C) 2007-2011 Jose Maria Arranz Santamaria, Spanish citizen

  This software is free software; you can redistribute it and/or modify it
  under the terms of the GNU Lesser General Public License as
  published by the Free Software Foundation; either version 3 of
  the License, or (at your option) any later version.
  This software is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  Lesser General Public License for more details. You should have received
  a copy of the GNU Lesser General Public License along with this program.
  If not, see <http://www.gnu.org/licenses/>.
*/

package org.itsnat.impl.core.resp.shared.html;

import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import org.itsnat.impl.core.browser.Browser;
import org.itsnat.impl.core.browser.BrowserMSIEOld;
import org.itsnat.impl.core.browser.BrowserW3C;
import org.itsnat.impl.core.clientdoc.ClientDocumentStfulImpl;
import org.itsnat.impl.core.clientdoc.SVGWebInfoImpl;
import org.itsnat.impl.core.doc.ItsNatHTMLDocumentImpl;
import org.itsnat.impl.core.domimpl.html.HTMLTextAreaElementImpl;
import org.itsnat.impl.core.domutil.DOMUtilHTML;
import org.itsnat.impl.core.domutil.DOMUtilInternal;
import org.itsnat.impl.core.domutil.NamespaceUtil;
import org.itsnat.impl.core.jsren.JSRenderImpl;
import org.itsnat.impl.core.jsren.dom.node.JSRenderPropertyImpl;
import org.itsnat.impl.core.jsren.dom.node.PropertyImpl;
import org.itsnat.impl.core.resp.ResponseLoadStfulDocumentValid;
import org.itsnat.impl.core.resp.shared.*;
import org.itsnat.impl.core.template.html.HTMLTemplateVersionDelegateImpl;
import org.itsnat.impl.res.core.js.LoadScriptImpl;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.html.HTMLBodyElement;
import org.w3c.dom.html.HTMLDocument;
import org.w3c.dom.html.HTMLHeadElement;
import org.w3c.dom.html.HTMLMetaElement;
import org.w3c.dom.html.HTMLTextAreaElement;

/**
*
* @author jmarranz
*/
public abstract class ResponseDelegateHTMLLoadDocImpl extends ResponseDelegateStfulLoadDocImpl
{

    /**
     * Creates a new instance of ResponseDelegateHTMLLoadDocImpl
     */
    public ResponseDelegateHTMLLoadDocImpl(ResponseLoadStfulDocumentValid responseParent)
    {
        super(responseParent);
    }

    public static ResponseDelegateHTMLLoadDocImpl createResponseDelegateHTMLLoadDoc(ResponseLoadStfulDocumentValid responseParent)
    {
        Browser browser = responseParent.getClientDocument().getBrowser();
        if (browser instanceof BrowserMSIEOld)
            return ResponseDelegateHTMLLoadDocMSIEOldImpl.createResponseDelegateHTMLLoadDocMSIEOld((BrowserMSIEOld)browser,responseParent);
        else
            return ResponseDelegateHTMLLoadDocW3CImpl.createResponseDelegateHTMLLoadDocW3C((BrowserW3C)browser,responseParent);
    }

    public ItsNatHTMLDocumentImpl getItsNatHTMLDocument()
    {
        ClientDocumentStfulImpl clientDoc = getClientDocumentStful();
        return (ItsNatHTMLDocumentImpl)clientDoc.getItsNatDocument();
    }

    public String getJavaScriptMIME()
    {
        return "text/javascript";
    }

    public void setScriptURLAttribute(Element scriptElem,String url)
    {
        DOMUtilInternal.setAttribute(scriptElem,"src",url);
    }

    public void setScriptContent(Element scriptElem,String code)
    {
        ItsNatHTMLDocumentImpl itsNatDoc = getItsNatHTMLDocument();
        Document doc = scriptElem.getOwnerDocument();
        if (itsNatDoc.isMIME_HTML())
            scriptElem.appendChild(doc.createTextNode(code))// No usamos CDATA porque hay problemas en MSIE y te�ricamente no est� soportado en HTML
        else // XHTML MIME
            scriptElem.appendChild(doc.createCDATASection(code));
    }

    public String addScriptMarkupToDocMarkup(String docMarkup,String scriptsMarkup)
    {
        StringBuilder finalMarkup = new StringBuilder();

        int posHTMLEnd = docMarkup.lastIndexOf('<');
        int posBODYEnd = docMarkup.lastIndexOf('<',posHTMLEnd - 1);
        String preScript = docMarkup.substring(0,posBODYEnd);
        String posScript = docMarkup.substring(posBODYEnd);

        finalMarkup.append(preScript);
        finalMarkup.append(scriptsMarkup);
        finalMarkup.append(posScript);

        return finalMarkup.toString();
    }

    public String getDocumentNamespace()
    {
        return NamespaceUtil.XHTML_NAMESPACE;
    }

    protected void rewriteClientUIControlProperties(Element elem,boolean revertJSChanges,StringBuilder code)
    {
        // Obviamente los documentos XHTML contienen elementos XHTML :)
        rewriteClientHTMLUIControlProperties(elem,revertJSChanges,code);
    }

    @Override
    protected String serializeDocument()
    {
        // En este punto SVGWeb debe de estar ya detectado o no
        boolean useSVGWeb = SVGWebInfoImpl.isSVGWebEnabled(getClientDocumentStful());

        // Primero los que no son procesados por SVGWeb (aunque da igual)
        LinkedList<Attr> otherNSElemsAttribs = null;
        LinkedList<Element> otherNSRootElemsInHTML = fixOtherNSElementsInHTMLFindRootElems();
        if (otherNSRootElemsInHTML != null)
            otherNSElemsAttribs = fixOtherNSElementsInHTMLSaveValidNames(otherNSRootElemsInHTML);

        Map<Element,Element> svgRootElems = null;
        if (useSVGWeb)
        {
            HTMLDocument doc = getItsNatHTMLDocument().getHTMLDocument();
            svgRootElems = processTreeSVGWebElements(doc);
        }

        String docMarkup = super.serializeDocument();

        if (useSVGWeb)
        {
            if ((svgRootElems != null) && !svgRootElems.isEmpty())
                restoreSVGWebElements(svgRootElems);
        }

        if (otherNSRootElemsInHTML  != null)
        {
            fixOtherNSElementsInHTMLCleanAuxAttribs(otherNSElemsAttribs);
            fixOtherNSElementsInHTMLGenCode(otherNSRootElemsInHTML);
        }

        return docMarkup;
    }

    public void detectSVGWeb()
    {
        // Usamos m�s o menos el mismo tipo de chequeos que hace SVGWeb en el cliente
        // S�lo soportaremos SVGWeb si su presencia en la p�gina es clara,
        // debe de existir un <meta name="svg.render.forceflash"> o estar "svg.render.forceflash" en el URL
        // pues a trav�s del <script> que incluye el archivo "svg.js" no est� claro que
        // dicho archivo sea el SVGWeb
        // Da igual si estamos en fastLoad o no pues la inserci�n din�mica del <meta>
        // y del <script> del SVGWeb via JavaScript en carga no creo que funcionen bien,
        // por tanto suponemos que est�n ah� como markup desde el principio.
        // ES FUNDAMENTAL que el <meta> NO est� cacheado (usar itsnat:nocache="true" por ejemplo)
        // de otra manera el <meta> NO se refleja en el DOM.

        ItsNatHTMLDocumentImpl itsNatDoc = getItsNatHTMLDocument();
        HTMLDocument doc = itsNatDoc.getHTMLDocument();

        boolean svgWeb = false;
        boolean forceFlash = false; // El valor se impondr� (lo exigimos de otra manera no reconocemos SVGWeb)
        int metaDecPos = -1;

        // El valor de svg.render.forceflash en el URL manda sobre el valor del <meta>
        String queryString = getResponseLoadDoc().getRequest().getItsNatServletRequest().getQueryStringInternal();
        if (queryString == null) return; // No hay query string, caso por ejemplo de Pretty URLs
        if (queryString.indexOf("svg.render.forceflash=true") != -1)
        {
            svgWeb = true;
            forceFlash = true;
        }
        else if (queryString.indexOf("svg.render.forceflash=false") != -1)
        {
            svgWeb = true;
            forceFlash = false;
        }

        if (!svgWeb)
        {
            // No est� svg.render.forceflash en el URL vamos a ver si est� en el <meta>
            HTMLHeadElement head = DOMUtilHTML.getHTMLHead(doc);
            LinkedList<Node> metaList = DOMUtilInternal.getChildElementListWithTagName(head,"meta",true);
            if (metaList != null)
            {
                int i = 0;
                for(Iterator<Node> it = metaList.iterator(); it.hasNext(); )
                {
                    HTMLMetaElement elem = (HTMLMetaElement)it.next();
                    if (HTMLTemplateVersionDelegateImpl.isSVGWebMetaDeclarationStatic(elem))
                    {
                        svgWeb = true;
                        forceFlash = elem.getContent().toLowerCase().equals("true");
                        metaDecPos = i;
                        break;
                    }
                    i++;
                }
            }
        }

        if (svgWeb)
        {
            ClientDocumentStfulImpl clientDoc = getClientDocumentStful();
            clientDoc.setSVGWebInfo(forceFlash,metaDecPos);
            addScriptFileToLoad(LoadScriptImpl.ITSNAT_SVGWEB);
        }
    }

    protected boolean isSVGRootElementProcessedBySVGWeb(Element elem)
    {
        ClientDocumentStfulImpl clientDoc = getClientDocumentStful();
        return SVGWebInfoImpl.isSVGRootElementProcessedBySVGWebFlash(elem,clientDoc);
    }

    protected Map<Element,Element> processTreeSVGWebElements(HTMLDocument doc)
    {
        HTMLBodyElement body = (HTMLBodyElement)doc.getBody();
        Map<Element,Element> svgwebElems = new HashMap<Element,Element>();
        processTreeSVGWebElements(body,svgwebElems);
        if (svgwebElems.isEmpty())
            svgwebElems = null;
        return svgwebElems;
    }

    protected Node processTreeSVGWebElements(Node node,Map<Element,Element> svgwebElems)
    {
        if (node == null) return null;
        if (node.getNodeType() != Node.ELEMENT_NODE) return node;

        Element elem = (Element)node;
        if (isSVGRootElementProcessedBySVGWeb(elem))
        {
            // Hay el deseo expl�cito de que sea SVGWeb quien procese este <svg>
            Element script = processSVGRootElemForSVGWeb(elem);
            svgwebElems.put(script, elem);
            return script; // script ha reemplazado a elem
        }
        else if (elem.hasChildNodes())
        {
            Node child = elem.getFirstChild();
            while(child != null)
            {
                child = processTreeSVGWebElements(child,svgwebElems);

                child = child.getNextSibling();
            }
        }
        return elem;
    }

    protected Element processSVGRootElemForSVGWeb(Element elem)
    {
        // Envolvemos temporalmente el elemento root <svg> en un
        // <script type="image/svg+xml">
        // Esta es la �nica opci�n viable compatible con ItsNat porque el uso de <object>
        // con data/src="data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg">...</svg>"
        // da lugar a la generaci�n de un <iframe> al final de la p�gina por cada <object>
        // lo cual nos fastidia el DOM.
        // Usando <script type="image/svg+xml"> no se genera nada al final de la p�gina
        // en el caso de navegadores no MSIE, en el caso de MSIE se genera un UNICO <div>
        // este <div> es b�sicamente para generar el <?import namespace="svg" ..?>
        // y declaraciones necesarias de cada trozo de SVG inclu�do, este elemento
        // es tratado autom�ticamente de forma adecuada por ItsNat para que no estropee el DOM.
        // Otra cosa positiva de usar la t�cnica <script type="image/svg+xml"> es que
        // en el c�digo fuente se ve el c�digo SVG, con object y data/src inline se ve todo
        // en una l�nea y adem�s no se tolera cargar la p�gina con "localhost" (da error en MSIE y FireFox
        // de diferente naturaleza) ha de usarse 127.0.0.1

        Document doc = elem.getOwnerDocument();
        Element script = doc.createElement("script");
        script.setAttribute("type","image/svg+xml");
        elem.getParentNode().replaceChild(script,elem);
        script.appendChild(elem);
        return script; // Ha reemplazado a elem
    }

    protected static void restoreSVGWebElements(Map<Element,Element> svgRootElems)
    {
        if (svgRootElems != null)
        {
            for(Map.Entry<Element,Element> entry : svgRootElems.entrySet())
            {
                Element script = entry.getKey();
                Element elem = entry.getValue();
                script.getParentNode().replaceChild(elem, script);
            }
        }
    }

    protected void rewriteClientHTMLTextAreaProperties(HTMLTextAreaElement elem,StringBuilder code)
    {
        // Se redefine en el caso de Opera 9 Desktop
        ClientDocumentStfulImpl clientDoc = getClientDocumentStful();
        Browser browser = clientDoc.getBrowser();

        // Hay dos casos, fast load mode y no fast load, pero la acci�n es la misma
        // - Caso Fast Load
        //   El contenido que manda est� en el nodo de texto del <textarea>
        //   no en el atributo value, salvo que expl�citamente se sepa que se ha definido
        //   Para m�s detalles ver m�todos:
        //   ItsNatHTMLTextAreaImpl.afterRender(...) y
        //   DocMutationEventListenerHTMLImpl.beforeAfterRenderAndSendMutationCode(...)

        // - Caso NO fast load
        //  En modo no fast load el reseteo (esta llamada) se hace tras serializar
        //  pero ANTES de que se despachen los listeners. El valor del atributo value
        //  no ha podido ser cambiado respecto al inicial en el template
        //  (ya sea page template o fragmento incluido via <include> da igual)
        //  y sabemos que no pinta nada inicialmente (ignorado) en el valor del textarea
        //  por lo que s�lo cuenta el nodo de texto hijo. Sabemos que en este
        // caso el value no ha sido definido expl�citamente por c�digo del usuario.

        // En remote control tenemos que saber si el atributo fue definido expl�citamente
        // por c�digo o no.

        // Recuerda que en Opera 9 se pasa por aqu� dos veces (la segunda tras la carga)
        // para evitar el auto-fill

        String explicitValue = ((HTMLTextAreaElementImpl)elem).getValueProperty();
        if (explicitValue != null) // Ser� el mismo valor que el atributo value
        {
            processUIControlProperty(elem,"value",code,clientDoc);
        }
        else // Manda el nodo de texto (el atributo puede tener un valor inicial cualquiera pero este no pinta nada)
        {
            code.append( "var elem = " + clientDoc.getNodeReference(elem,true,true) + ";\n" );
            String content = DOMUtilInternal.getTextContent(elem,false); // No puede ser nulo
            String valueJS = JSRenderImpl.toTransportableStringLiteral(content,browser);
            JSRenderPropertyImpl render = JSRenderPropertyImpl.getJSRenderProperty(elem,clientDoc.getBrowser());
            PropertyImpl prop = render.getProperty(elem,"value");
            code.append( render.renderSetProperty(prop, elem, "elem", valueJS, content, clientDoc) );
        }
    }

    protected abstract LinkedList<Element> fixOtherNSElementsInHTMLFindRootElems();
    protected abstract LinkedList<Attr> fixOtherNSElementsInHTMLSaveValidNames(LinkedList<Element> otherNSRootElemsInHTML);
    protected abstract void fixOtherNSElementsInHTMLCleanAuxAttribs(LinkedList<Attr> attribs);
    protected abstract void fixOtherNSElementsInHTMLGenCode(LinkedList<Element> otherNSElemsInHTML);
}
TOP

Related Classes of org.itsnat.impl.core.resp.shared.html.ResponseDelegateHTMLLoadDocImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.