(* Copyright (C) 2000-2002, HELM Team. * * This file is part of HELM, an Hypertextual, Electronic * Library of Mathematics, developed at the Computer Science * Department, University of Bologna, Italy. * * HELM is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * HELM 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HELM; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA. * * For details, see the HELM World-Wide-Web page, * http://cs.unibo.it/helm/. *) let mathmlns = "http://www.w3.org/1998/Math/MathML";; let xmldiffns = "http://helm.cs.unibo.it/XmlDiff";; let helmns = "http://www.cs.unibo.it/helm";; let ds_selection = Gdome.domString "selection";; let ds_2 = Gdome.domString "2";; let ds_mathmlns = Gdome.domString mathmlns;; let ds_m_style = Gdome.domString "m:mstyle";; let ds_mathbackground = Gdome.domString "mathbackground";; let ds_xmldiffns = Gdome.domString xmldiffns;; let ds_xmldiff_type = Gdome.domString "xmldiff:type";; let ds_fake = Gdome.domString "fake";; let ds_helmns = Gdome.domString helmns;; let ds_xref = Gdome.domString "xref";; let ds_type = Gdome.domString "type";; let ds_yellow = Gdome.domString "yellow";; let ds_green = Gdome.domString "#00ff00";; let ds_maction = Gdome.domString "maction";; let ds_mtr = Gdome.domString "mtr";; let ds_mtd = Gdome.domString "mtd";; type highlighted_nodes = Gdome.node list;; let rec make_visible (n: Gdome.node) = match n#get_parentNode with None -> () | Some p -> match p#get_namespaceURI, p#get_localName with Some nu, Some ln when nu#equals ds_mathmlns && ln#equals ds_maction -> (new Gdome.element_of_node p)#setAttribute ~name:ds_selection ~value:ds_2 ; make_visible p | _,_ -> make_visible p ;; let highlight_node_total_time = ref 0.0;; let highlight_node ?(color=ds_yellow) (doc: Gdome.document) (n: Gdome.node) = let highlight (n: Gdome.node) = let highlighter = doc#createElementNS ~namespaceURI:(Some ds_mathmlns) ~qualifiedName:ds_m_style in highlighter#setAttribute ~name:ds_mathbackground ~value:color ; highlighter#setAttributeNS ~namespaceURI:(Some ds_xmldiffns) ~qualifiedName:ds_xmldiff_type ~value:ds_fake ; let parent = match n#get_parentNode with None -> assert false | Some p -> p in ignore (parent#replaceChild ~oldChild:n ~newChild:(highlighter :> Gdome.node)) ; ignore (highlighter#appendChild n) ; (highlighter :> Gdome.node) in let rec find_mstylable_node n = match n#get_namespaceURI, n#get_localName with Some nu, Some ln when nu#equals ds_mathmlns && (not (ln#equals ds_mtr)) && (not (ln#equals ds_mtd)) -> n | Some nu, Some ln when nu#equals ds_mathmlns && ln#equals ds_mtr || ln#equals ds_mtd -> let true_child = match n#get_firstChild with None -> assert false | Some n -> n in find_mstylable_node true_child | _,_ -> match n#get_parentNode with None -> assert false | Some p -> find_mstylable_node p in let highlighter = highlight (find_mstylable_node n) in make_visible highlighter ; highlighter ;; let iter_children ~f (n:Gdome.node) = let rec aux = function None -> () | Some n -> let sibling = n#get_nextSibling in (f n) ; aux sibling in aux n#get_firstChild ;; let highlight_nodes ~xrefs (doc:Gdome.document) = let highlighted = ref [] in let rec aux (n:Gdome.element) = let attributeNS = (n#getAttributeNS ~namespaceURI:ds_helmns ~localName:ds_xref)#to_string in if List.mem attributeNS xrefs then highlighted := (highlight_node ~color:ds_green doc (n :> Gdome.node)):: !highlighted ; iter_children (n :> Gdome.node) ~f:(function n -> if n#get_nodeType = GdomeNodeTypeT.ELEMENT_NODE then aux (new Gdome.element_of_node n)) in aux doc#get_documentElement ; !highlighted ;; let dim_nodes = List.iter (function (n : Gdome.node) -> assert (n#get_nodeType = GdomeNodeTypeT.ELEMENT_NODE && ((new Gdome.element_of_node n)#getAttributeNS ~namespaceURI:ds_xmldiffns ~localName:ds_type)#equals ds_fake) ; let true_child = match n#get_firstChild with None -> assert false | Some n -> n in let p = match n#get_parentNode with None -> assert false | Some n -> n in ignore (p#replaceChild ~oldChild:n ~newChild:true_child) ) ;; let update_dom ~(from : Gdome.document) (d : Gdome.document) = let rec aux (p: Gdome.node) (f: Gdome.node) (t: Gdome.node) = let replace t1 = if t1 = GdomeNodeTypeT.ELEMENT_NODE && ((new Gdome.element_of_node f)#getAttributeNS ~namespaceURI:ds_xmldiffns ~localName:ds_type)#equals ds_fake then let true_child = match f#get_firstChild with None -> assert false | Some n -> n in begin ignore (p#replaceChild ~oldChild:f ~newChild:true_child) ; aux p true_child t end else let t' = from#importNode t true in ignore (p#replaceChild ~newChild:t' ~oldChild:f) ; (* ignore (highlight_node from t') *) in match f#get_nodeType,t#get_nodeType with GdomeNodeTypeT.TEXT_NODE,GdomeNodeTypeT.TEXT_NODE -> (match f#get_nodeValue, t#get_nodeValue with Some v, Some v' when v#equals v' -> () | Some _, (Some _ as v') -> f#set_nodeValue v' | _,_ -> assert false) | GdomeNodeTypeT.ELEMENT_NODE as t1,GdomeNodeTypeT.ELEMENT_NODE -> (match f#get_namespaceURI,t#get_namespaceURI,f#get_localName,t#get_localName with Some nu, Some nu', Some ln, Some ln' when ln#equals ln' && nu#equals nu' -> begin match f#get_attributes, t#get_attributes with Some fattrs, Some tattrs -> let flen = fattrs#get_length in let tlen = tattrs#get_length in let processed = ref [] in for i = 0 to flen -1 do match fattrs#item i with None -> () (* CSC: sigh, togliere un nodo rompe fa decrescere la lunghezza ==> passare a un while *) | Some attr -> match attr#get_namespaceURI with None -> (* Back to DOM Level 1 ;-( *) begin let name = attr#get_nodeName in match tattrs#getNamedItem ~name with None -> ignore (fattrs#removeNamedItem ~name) | Some attr' -> processed := (None,Some name)::!processed ; match attr#get_nodeValue, attr'#get_nodeValue with Some v1, Some v2 when v1#equals v2 || (name#equals ds_selection && nu#equals ds_mathmlns && ln#equals ds_maction) -> () | Some v1, Some v2 -> let attr'' = from#importNode attr' true in ignore (fattrs#setNamedItem attr'') | _,_ -> assert false end | Some namespaceURI -> let localName = match attr#get_localName with Some v -> v | None -> assert false in match tattrs#getNamedItemNS ~namespaceURI ~localName with None -> ignore (fattrs#removeNamedItemNS ~namespaceURI ~localName) | Some attr' -> processed := (Some namespaceURI,Some localName)::!processed ; match attr#get_nodeValue, attr'#get_nodeValue with Some v1, Some v2 when v1#equals v2 -> () | Some _, Some _ -> let attr'' = from#importNode attr' true in ignore (fattrs#setNamedItem attr'') | _,_ -> assert false done ; for i = 0 to tlen -1 do match tattrs#item i with None -> assert false | Some attr -> let namespaceURI,localName = match attr#get_namespaceURI with None -> None,attr#get_nodeName | Some namespaceURI as v -> v, match attr#get_localName with None -> assert false | Some v -> v in if not (List.exists (function None,Some localName' -> (match namespaceURI with None -> localName#equals localName' | Some _ -> false) | Some namespaceURI', Some localName' -> (match namespaceURI with None -> false | Some namespaceURI -> localName#equals localName' && namespaceURI#equals namespaceURI' ) | _,_ -> assert false ) !processed) then let attr' = from#importNode attr false in ignore (fattrs#setNamedItem attr') done | _,_ -> assert false end ; let rec dumb_diff = function [],[] -> () | he1::tl1,he2::tl2 -> aux f he1 he2 ; dumb_diff (tl1,tl2) | [],tl2 -> List.iter (function n -> let n' = from#importNode n true in ignore (f#appendChild n') ; (* ignore (highlight_node from n') *) () ) tl2 | tl1,[] -> List.iter (function n -> ignore (f#removeChild n)) tl1 in let node_list_of_nodeList n = let rec aux = function None -> [] | Some n when n#get_nodeType = GdomeNodeTypeT.ELEMENT_NODE or n#get_nodeType = GdomeNodeTypeT.TEXT_NODE -> n::(aux n#get_nextSibling) | Some n -> aux n#get_nextSibling in aux n#get_firstChild in dumb_diff (node_list_of_nodeList f, node_list_of_nodeList t) | _,_,_,_ -> replace t1 ) | t1,t2 when (t1 = GdomeNodeTypeT.ELEMENT_NODE || t1 = GdomeNodeTypeT.TEXT_NODE) && (t2 = GdomeNodeTypeT.ELEMENT_NODE || t2 = GdomeNodeTypeT.TEXT_NODE) -> replace t1 | _,_ -> assert false in try aux (d :> Gdome.node) (from#get_documentElement :> Gdome.node) (d#get_documentElement :> Gdome.node) with (GdomeInit.DOMException (e,msg) as ex) -> raise ex | e -> raise e ;;