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

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

/*
  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.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Set;
import org.itsnat.impl.core.browser.Browser;
import org.itsnat.impl.core.browser.BrowserBlackBerryOld;
import org.itsnat.impl.core.browser.BrowserGecko;
import org.itsnat.impl.core.browser.BrowserW3C;
import org.itsnat.impl.core.browser.opera.BrowserOpera;
import org.itsnat.impl.core.browser.webkit.BrowserWebKit;
import org.itsnat.impl.core.clientdoc.ClientDocumentStfulImpl;
import org.itsnat.impl.core.jsren.dom.node.otherns.JSRenderOtherNSAttributeW3CImpl;
import org.itsnat.impl.core.jsren.dom.node.otherns.JSRenderOtherNSElementW3CImpl;
import org.itsnat.impl.core.resp.ResponseLoadStfulDocumentValid;
import org.itsnat.impl.res.core.js.LoadScriptImpl;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;

/**
*
* @author jmarranz
*/
public abstract class ResponseDelegateHTMLLoadDocW3CImpl extends ResponseDelegateHTMLLoadDocImpl
{
    private final static String NSROOTATTRNAME = "itsnatnsroot";
    private final static String NSATTRPREFIX = "itsnatns_";


    public ResponseDelegateHTMLLoadDocW3CImpl(ResponseLoadStfulDocumentValid response)
    {
        super(response);
    }

    public static ResponseDelegateHTMLLoadDocW3CImpl createResponseDelegateHTMLLoadDocW3C(BrowserW3C browser,ResponseLoadStfulDocumentValid responseParent)
    {
        if (browser instanceof BrowserGecko)
            return ResponseDelegateHTMLLoadDocGeckoImpl.createResponseDelegateHTMLLoadDocGecko((BrowserGecko)browser,responseParent);
        else if (browser instanceof BrowserWebKit)
            return ResponseDelegateHTMLLoadDocWebKitImpl.createResponseDelegateLoadHTMLDocWebKit(responseParent);
        else if (browser instanceof BrowserOpera)
            return ResponseDelegateHTMLLoadDocOperaImpl.createResponseDelegateHTMLLoadDocOpera((BrowserOpera)browser, responseParent);
        else if (browser instanceof BrowserBlackBerryOld)
            return new ResponseDelegateHTMLLoadDocBlackBerryOld2Impl(responseParent);
        else
            return new ResponseDelegateHTMLLoadDocW3CDefaultImpl(responseParent);
    }

    protected LinkedList<Element> fixOtherNSElementsInHTMLFindRootElems()
    {
        // En tiempo de carga con MIME "text/html" los elementos inline no-X/HTML presentes
        // en el markup de carga son incorrectamente cargados en el DOM cliente en navegadores
        // con soporte de SVG nativo tal y como FireFox, Opera y algunos navegadores WebKit (Safari, Chrome y iPhone 2.1+ este �ltimo no probado)
        // Concretamente el namespaceURI no es el esperado por lo que son considerados elementos HTML desconocidos.
        // Esto no ocurre con MIME XHTML ("application/xhtml+xml")
        // La soluci�n es reinsertar los elementos de nuevo via DOM correctamente,
        // esta soluci�n no es obvia porque los elementos en el DOM no tienen el namespaceURI
        // definido por lo que hay que obtenerlo de los atributos de declaraci�n de namespaces,
        // tambi�n existe el problema de los tagNames est�n err�neamente en may�sculas
        // (creo que excepto Opera) y los atributos en min�sculas.
        // Por ello, como en el servidor sabemos exactamente como deben ser, creamos
        // atributos auxiliares para poder recrear el DOM correctamente
        // Existe la alternativa de tener un listado de todos los nombres de elementos y atributos de SVG
        // y MathML por ejemplo, tal y como se hace en:
        // http://intertwingly.net/blog/2006/12/05/HOWTO-Embed-MathML-and-SVG-into-HTML4
        // http://raphaeljs.com/
        // pero mi soluci�n es mucho mejor pues no requiere �sto y admite namespaces
        // a priori desconocidos, es la ventaja de trabajar desde el servidor.

        // Obtenemos los elementos antes de serializar y de ejecutar los listeners de usuario
        // Antes de serializar porque en el caso de fastLoad = false, es lo primero que se hace
        // en el caso de fastLoad = true se ejecutan primero los listeners del usuario, dichos
        // listeners

        ClientDocumentStfulImpl clientDoc = getClientDocumentStful();
        if (!clientDoc.isSendCodeEnabled())
            return null; // Hay que generar c�digo, aunque no ahora, por lo que no vale la pena esto si no se puede enviar c�digo

        Browser browser = clientDoc.getBrowser();
        if (!browser.canNativelyRenderOtherNSInXHTMLDoc())
            return null; // Si no puede renderizar por ejemplo SVG no vale la pena esto

        if (!getItsNatHTMLDocument().isMIME_HTML())
            return null; // En MIME XHTML no hace falta esto

        Element rootElem = getItsNatHTMLDocument().getDocument().getDocumentElement();
        return getOtherNSRootElementsInline(rootElem);
        // Si es null es que no hay.
    }

    protected static boolean hasSomeCharUpcase(String value)
    {
        if (value == null) return false;
        for(int i = 0; i < value.length(); i++)
            if (Character.isUpperCase(value.charAt(i))) return true;
        return false;
    }

    protected LinkedList<Attr> fixOtherNSElementsInHTMLSaveValidNames(LinkedList<Element> otherNSRootElemsInHTML)
    {
        LinkedList<Attr> auxAttribs = new LinkedList<Attr>();
        for(Element elem : otherNSRootElemsInHTML)
        {
            // Marcamos el elemento root como elemento que ha de procesarse con el script
            // que enviaremos al cliente, para distinguir de los casos en los que por ejemplo
            // embebamos MathML dentro de SVG etc (raro pero posible).
            Attr attr = elem.getOwnerDocument().createAttribute(NSROOTATTRNAME);
            attr.setValue("true");
            elem.setAttributeNode(attr);
            auxAttribs.add(attr);

            fixOtherNSElementsInHTMLSaveValidNames(elem,auxAttribs);
        }
        return auxAttribs;
    }

    protected void fixOtherNSElementsInHTMLSaveValidNames(Element elem,LinkedList<Attr> auxAttribs)
    {
        // Primero tomamos una foto de los atributos originales pues sobre la marcha vamos a a�adir
        // atributos auxiliares seguramente.

        if (JSRenderOtherNSAttributeW3CImpl.hasIgnoreNSAttrInMIMEHTML(elem)) return;

        Attr[] originalAttribs = null;
        if (elem.hasAttributes())
        {
            NamedNodeMap attribs = elem.getAttributes();
            int len = attribs.getLength();
            originalAttribs = new Attr[len];
            for(int i = 0; i < len; i++)
            {
                Attr attr = (Attr)attribs.item(i);
                originalAttribs[i] = attr;
            }
        }

        boolean elemWithOtherNS = JSRenderOtherNSElementW3CImpl.isElementWithOtherNSTagNameInMIMEHTML(elem);
        if (elemWithOtherNS)
            fixOtherNSElementsInHTMLSaveValidName(elem,elem.getPrefix(),elem.getLocalName(),auxAttribs);

        if (originalAttribs != null)
        {
            for(int i = 0; i < originalAttribs.length; i++)
            {
                Attr attr = originalAttribs[i];
                if (elemWithOtherNS || JSRenderOtherNSAttributeW3CImpl.isAttrWithOtherNSInMIMEHTML(attr))
                {
                    // Aunque el atributo no tenga namespace propio, si est� dentro de un elemento con namespace (no XHTML) la distinci�n entre may�sculas y min�sculas es importante (por ejemplo en SVG)
                    // hay que generar el atributo backup
                    String prefix = attr.getPrefix();
                    String localName;
                    if (prefix != null) localName = attr.getName().substring(prefix.length() + 1);
                    else localName = attr.getName();
                    fixOtherNSElementsInHTMLSaveValidName(elem,prefix,localName,auxAttribs);
                }
            }
        }


        if (elem.hasChildNodes())
        {
            Node node = elem.getFirstChild();
            while(node != null)
            {
                if (node instanceof Element) // Los dem�s casos: nodos de texto, comentarios etc
                    fixOtherNSElementsInHTMLSaveValidNames((Element)node,auxAttribs);

                node = node.getNextSibling();
            }
        }
    }

    protected void fixOtherNSElementsInHTMLSaveValidName(Element elem,String prefix,String localName,LinkedList<Attr> auxAttribs)
    {
        if (!hasSomeCharUpcase(prefix) && !hasSomeCharUpcase(localName)) return;

        // Necesita un atributo auxiliar "backup" con el nombre original
        String attrName,attrValue;
        if (prefix != null)
        {
            attrName = NSATTRPREFIX + prefix.toLowerCase() + "_" + localName.toLowerCase();
            attrValue = prefix + ":" + localName;
        }
        else
        {
            attrName = NSATTRPREFIX + localName.toLowerCase();
            attrValue = localName;
        }
        Attr attr = elem.getOwnerDocument().createAttribute(attrName);
        attr.setValue(attrValue);
        elem.setAttributeNode(attr);
        auxAttribs.add(attr);
    }

    protected void fixOtherNSElementsInHTMLCleanAuxAttribs(LinkedList<Attr> attribs)
    {
        if (attribs == null) return;
        for(Attr attr : attribs)
        {
            attr.getOwnerElement().removeAttributeNode(attr);
        }
    }

    protected void fixOtherNSElementsInHTMLGenCode(LinkedList<Element> otherNSElemsInHTML)
    {
        addScriptFileToLoad(LoadScriptImpl.ITSNAT_FIX_OTHERNS_IN_HTML);

        StringBuilder code = new StringBuilder();

        Set<String> tagNames = new HashSet<String>();
        for(Element elem : otherNSElemsInHTML)
        {
            tagNames.add(elem.getTagName().toUpperCase());
        }

        code.append("new ItsNatFixOtherNSInHTML().fixTreeOtherNSInHTML([");
        for(Iterator<String> it = tagNames.iterator(); it.hasNext(); )
        {
            String tagName = (String)it.next();
            code.append("\"" + tagName + "\"");
            if (it.hasNext()) code.append(",");
        }
        code.append("]);\n");

        code.append("obj = null;\n"); // Para liberar el objeto utilidad pues ya no lo necesitamos

        addFixDOMCodeToSend(code.toString());
    }


    protected LinkedList<Element> getOtherNSRootElementsInline(Node node)
    {
        return getOtherNSRootElementsInline(node,null);
    }

    protected LinkedList<Element> getOtherNSRootElementsInline(Node node,LinkedList<Element> list)
    {
        if (node.getNodeType() != Node.ELEMENT_NODE) return list;

        Element elem = (Element)node;

        if (isSVGRootElementProcessedBySVGWeb(elem))
        {
            // En el caso de que sea un elemento a procesar por SVGWeb se envolver� en un <script type="image/svg+xml"> dentro del mismo el SVG ser� un nodo de texto por lo que no ser� "visible" por el JavaScript que corrige el DOM por lo que no tiene sentido este proceso
            // No procesamos ni el elemento ni sus hijos
            return list;
        }
        else if (JSRenderOtherNSElementW3CImpl.isElementWithSomethingOtherNSInMIMEHTML(elem))
        {
            if (list == null) list = new LinkedList<Element>();

            // A�adimos s�lo el elemento padre pues el tratamiento
            // tambi�n se har� a los hijos de este padre pero via JavaScript.
            list.add(elem);
        }
        else
        {
            Node child = elem.getFirstChild();
            while (child != null)
            {
                list = getOtherNSRootElementsInline(child,list);
                child = child.getNextSibling();
            }
        }

        return list;
    }

    public String getJavaScriptDocumentName()
    {
        return "W3CHTMLDocument";
    }
}
TOP

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

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.