PageSourceSearch

https://www.coopculture.it/system/modules/it.coopculture.ecommerce/resources/js/KmlMapParser.js

js coopculture.it collected 2026-10-02 03:28:24 UTC 67,795 bytes, 1,943 lines download raw bytes

1/*****************************************************************************
2 *  KmlMapParser.js
3 *  KmlMapParser  - A Google Maps API Extension
4 *  Project: http://code.google.com/p/kmlmapparser/
5 *  Author:  R. Raponi
6 *  Version: 1.0
7 *
8 *
9 *  Licensed under the Apache License, Version 2.0 (the "License");
10 *  you may not use this file except in compliance with the License.
11 *  You may obtain a copy of the License at
12 *
13 *      http://www.apache.org/licenses/LICENSE-2.0
14 *
15 *  Unless required by applicable law or agreed to in writing, software
16 *  distributed under the License is distributed on an "AS IS" BASIS,
17 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 *  See the License for the specific language governing permissions and
19 *  limitations under the License.
20 * -----------------------------------------------------------------------------------
21 *
22 * @param {Object} config Configuration options
23 *
24 * var grid = new KmlMapParser({ map: map,
25 *                               showSidebar: true,
26 *                               sidebarId: 'sideBar'
27 *                              }
28 *
29 *  @param {Object} config Configuration options
30 *  --------------------------
31 *    allFoldersOpen: true
32 *    zoomLevel: 15
33 *    zoomOnClick: true
34 *    imageDirectory: 'http://localhost:8090/envistaExamples/resources/images'
35 *    imageSize: {width: 32, height:32}
36 *    imageHotspot: {x: 0, y:32}
37 *    showImageShadow: true
38 *    showSidebar: true
39 *    sidebarId: 'sideBar'
40 *    showSidebarDescriptions: true
41 *    showOverlaysInSidebar: true
42 *    showRootName: true
43 *    showBubble: false
44 *    showSidebarBubble: true
45 *    highlightColor: 'ff0000'
46 *    showFolders: false
47 *    showMultiPointsAsMarkers: true
48 *    useMapCenter: true
49 *    afterParseFn: myCallbackFunction
50 *    kml: ['../kmlFiles/sidebarMap.kml', '../kmlFiles/state_capitals.kml']
51 *    kmlFile: '../kmlFiles/sidebarMap.kml'  < deprecated >
52 *
53 *
54 * sidebar CSS can be found in KmlMapParser.css
55 ******************************************************************************/
56
57// Extend the global String object with a method to remove leading and trailing whitespace
58if (!String.prototype.trim) {
59    String.prototype.trim = function () {
60        return this.replace(/^\s+|\s+$/g, '');
61    };
62}
63
64
65KmlMapParser  = function(config){
66
67    //check and set config variables
68    if (config === undefined){
69        throw 'KmlMapParser internal error: needs Configuration options especially the map!';
70    }
71
72    this.origConfig = config;
73    this.config = config;
74
75    this.kmlFile = config.kml ? config.kml : config.kmlFile;
76
77    //TODO make map if not defined
78    this.map = config.map;
79
80    if (config.imageDirectory !== undefined){
81        this.imageDirectory = config.imageDirectory;
82    }
83
84    this.sidebarId = config.sidebarId ? this.config.sidebarId : 'the_side_bar';
85    this.showMarkers = (config.showMarkers!==undefined) ? this.config.showMarkers : true;
86    this.showSidebar = (config.showSidebar!==undefined) ? this.config.showSidebar : true;
87    this.showSidebarDescriptions = (config.showSidebarDescriptions!==undefined) ? this.config.showSidebarDescriptions : true;
88
89    this.showBubble = (config.showBubble!==undefined) ? this.config.showBubble : true;
90    if (this.showBubble){
91        this.showSidebarBubble = (config.showSidebarBubble!==undefined) ? this.config.showSidebarBubble : false;
92    }else{
93        this.showSidebarBubble = false;
94    }
95
96    this.showFolders = (config.showFolders!==undefined) ? this.config.showFolders : true;
97    if (this.showFolders){
98        this.allFoldersOpen = (config.allFoldersOpen!==undefined) ? this.config.allFoldersOpen : undefined;
99    }
100    this.defaultImageSize = (config.imageSize!== undefined) ? this.config.imageSize : {width: 32, height:32};
101    this.defaultHotspot = (config.imageHotspot!== undefined) ? this.config.imageHotspot : {x: 16, y:32};
102    this.showImageShadow = (config.showImageShadow !== undefined) ? this.config.showImageShadow : true;
103
104    this.showMultiPointsAsMarkers = (config.showMultiPointsAsMarkers!==undefined) ? this.config.showMultiPointsAsMarkers : false;
105    this.showRootName = (config.showRootName!==undefined) ? this.config.showRootName : true;
106
107    this.useMapCenter = (config.useMapCenter!==undefined) ? this.config.useMapCenter : false;
108    if (this.useMapCenter){
109        this.mapCenter = this.map.getCenter();
110    }
111
112    this.defaultZoomLevel = (config.zoomLevel!==undefined) ? this.config.zoomLevel : 15;
113    this.shouldZoom = (config.zoomOnClick!==undefined) ? this.config.zoomOnClick : true;
114
115    if (config.highlightColor === undefined){
116        this.highlightColor = '#aaffff';
117    } else {
118        this.highlightColor = config.highlightColor;
119    }
120
121    if (config.markerIcon === undefined){
122        this.markerIcon = '';
123    } else {
124        this.markerIcon = config.markerIcon;
125    }
126
127    this.showOverlaysInSidebar = (config.showOverlaysInSidebar!==undefined) ? this.config.showOverlaysInSidebar : true;
128
129    if (config.afterParseFn === undefined){
130        this.hasAfterParse = false;
131    } else {
132        this.hasAfterParse = true;
133        this.afterParseFn = config.afterParseFn;
134    }
135
136    //create the info window
137    this.infoWindow = new google.maps.InfoWindow();
138    this.mapshapes  = [];
139    this.folderIndex  = 0;
140    this.placemarkIndex  = 0;
141    this.overlayIndex = 0;
142    this.zindex=100;
143
144    if (this.kmlFile !== undefined){
145        this.parse(this.kmlFile);
146    }
147};
148
149KmlMapParser.prototype = {
150
151    /*
152    * Process one or more KML documents
153    */
154    parse :  function (urls) {
155        if (typeof urls === 'string') {
156            urls = [urls];
157        }
158        this.docSet = { docs: [], remaining: urls.length};
159
160        for (var i = 0; i < urls.length; i++) {
161            this.parseUrl(urls[i], i);
162        }
163    },
164
165
166    /*
167     *  parse and process one KML document
168     */
169    parseUrl : function (url, num){
170        var baseUrl = url.split('?')[0],
171            doc = { baseUrl: baseUrl, url: url, id: num };
172
173        this.docSet.docs.push(doc);
174
175        var that = this,
176            render = this.render,
177            callback = function (responseXML) {render(responseXML, doc, that);};
178
179        this.fetchXMLdoc(url, callback);
180    },
181
182
183    /*
184     * Get the document associated with the id
185     * @param {Number or String} docId the document id is the index number of the KML url
186     * @return {Object} document
187     */
188    getDocumentById : function (docId) {
189        var iDocId = (typeof docId === 'string') ? parseInt(docId, 10) : docId;
190        return this.docSet.docs[docId];
191    },
192
193
194
195    /*
196     *  Show the map objects associated with a document
197     *  by the documents id
198     * @param {String} docId
199     */
200    hideDocumentById : function (docId) {
201        var doc = this.getDocumentById(docId);
202        if (doc && doc.isVisible){
203            this.setVisibilityByDoc(doc, false);
204        }
205    },
206
207
208    /*
209    *  Show the map objects associated with a document
210    *  by the documents id
211    * @param {String} docId
212    */
213    showDocumentById : function (docId){
214        var doc = this.getDocumentById(docId);
215        if (doc && !doc.isVisible ){
216            this.setVisibilityByDoc(doc, true);
217        }
218    },
219
220
221    /*
222    *  Sets visibility on all map objects and the sidebar
223    * @param {Boolean} isVisible
224    */
225    setVisibility : function (isVisible){
226        this.setVisibilityOnMarkers(isVisible);
227        this.setOverlayVisibility(isVisible);
228
229        if (this.showSidebar && !!this.sidebarId){
230            var side = document.getElementById(this.sidebarId);
231            if (side !== null){
232                this.setVisibilitybyNode(side, isVisible);
233            }
234        }
235    },
236
237
238    /*
239    *  Sets visibility on all map markers and shapes
240    * @param {Boolean} isVisible
241    * @param {Number}  docId  (optional)
242    */
243    setVisibilityOnMarkers : function (isVisible, docId){
244        var ms = this.mapshapes,
245            mss, shapeId;
246
247        for ( shapeId in ms){
248            if (ms.hasOwnProperty(shapeId)) {
249                mss = ms[shapeId];
250                if ((docId !== undefined && mss.docId === docId ) || (docId === undefined)){
251                    this.setMapObjectVisibility(mss, isVisible);
252                }
253            }
254        }
255    },
256
257
258    /*
259    *  sets the visiblility on map objects
260    *  by the documents id
261    * @param {Number} docId
262    * @param {boolean} isVisible
263    */
264    setVisibilityByDoc : function (doc, isVisible) {
265        var docRoot = document.getElementById('doc-'+ doc.id),
266            i, overlayId, overlay;
267
268        if (doc !== undefined && doc.isVisible !== isVisible){
269            //markers and shapes
270            this.setVisibilityOnMarkers(isVisible, doc.id);
271
272            //overlays
273            if (doc.hasOverlays){
274                for (i = 0; i < doc.overlays.length; i++){
275                    this.setOverlayVisibility(doc.overlays[i].overlay, isVisible);
276                }
277            }
278
279            //folders
280            if (this.showSidebar && docRoot !== null){
281                this.setVisibilitybyNode(docRoot, isVisible);
282            }
283            doc.isVisible = isVisible;
284        }
285    },
286
287
288    /*
289    * set Overlay visibility on a marker or shape
290    * actually removes it form the map
291    * @param {Object} Overly
292    * @param {Boolean} isVisible
293    */
294    setMapObjectVisibility: function (shape, isVisible) {
295        if ( typeof shape === 'object'){
296            //shapes
297            if (isVisible){
298                shape.setMap(this.map);
299            }else{
300                shape.setMap(null);
301            }
302        }
303    },
304
305
306    /*
307     *  sets the overlay visibility by the documents id
308     * @param {Number} docId
309     * @param {Boolean} visibility
310     */
311    setOverlayVisibilityByDocId : function (docId, isVisible){
312        var doc = this.getDocumentById[docId];
313
314        if (doc !== undefined && doc.hasOverlays){
315            for (i = 0; i < doc.overlays.length; i++){
316                this.setVisibilitybyOverlay(doc.overlays[i].overlay, isVisible);
317            }
318        }
319    },
320
321
322    /*
323     *  sets the overlay visibility by the overlays id
324     * @param {Number} overlayId
325     * @param {Boolean} visibility
326     */
327    setOverlayVisibilityById:  function (id, isVisible){
328        var docs = this.docSet.docs,
329            doc, overlay, i, j;
330
331        if (docs.length > 0){
332            for (i = 0; i < docs.length; i++){
333                doc = docs[i];
334                if (doc !== undefined && doc.hasOverlays){
335                    for (j = 0; j < doc.overlays.length; j++){
336                        overlay = doc.overlays[j].overlay;
337                        if (id && id === overlay.id_){
338                            this.setVisibilitybyOverlay(overlay, isVisible);
339                        }
340                    }
341                }
342            }
343        }
344    },
345
346
347    /*
348    * set Overlay visibility
349    * @param {Object} Overly
350    * @param {Boolean} isVisible
351    */
352    setVisibilitybyOverlay: function (overlay, isVisible) {
353        if (overlay !== undefined && overlay !== null){
354            overlay.setVisibility(isVisible);
355        }
356    },
357
358
359    /*
360    *  sets all the visibility on all overlays
361    * @param {Boolean} isVisible
362    */
363    setOverlayVisibility : function (isVisible) {
364        var docs = this.docSet.docs,
365            doc, overlay, i, j;
366
367        if (docs.length > 0){
368            for (i = 0; i < docs.length; i++){
369                doc = docs[i];
370                if (doc !== undefined && doc.hasOverlays){
371                    for (j = 0; j < doc.overlays.length; j++){
372                        overlay = doc.overlays[j].overlay;
373                        this.setVisibilitybyOverlay(overlay, isVisible);
374                    }
375                }
376            }
377        }
378    },
379
380
381    /*
382    *  set Overlay opacity
383    * @param {Number} opacity 0.0 - 1.0.
384    */
385    setOverlayOpacity: function (opacity) {
386        var docs = this.docSet.docs,
387            doc, overlay, i, j;
388
389        if (docs.length > 0){
390            for (i = 0; i < docs.length; i++){
391                doc = docs[i];
392                if (doc !== undefined && doc.hasOverlays){
393                    for (j = 0; j < doc.overlays.length; j++){
394                        overlay = doc.overlays[j].overlay;
395                        this.setOpacityByOverlay(overlay, opacity);
396                    }
397                }
398            }
399        }
400    },
401
402
403    /*
404    *  sets the overlay opacity by the documents id
405    * @param {Number} docId
406    * @param {Number} opacity 0.0 - 1.0
407    */
408    setOverlayOpacityByDocId : function (docId, opacity) {
409        var doc = this.getDocumentById[docId];
410
411        if (doc !== undefined && doc.hasOverlays){
412            for (i = 0; i < doc.overlays.length; i++){
413                this.setOverlayOpacity(doc.overlays[i], opacity);
414            }
415        }
416    },
417
418
419    /*
420    *  set Overlay opacity
421    * @param {Object} Overly.
422    * @param {Number} opacity 0.0 - 1.0
423    */
424    setOpacityByOverlay: function (overlay, opacity) {
425        this.setVisibilitybyOverlay(overlay, true);
426        overlay.setOpacity(opacity);
427    },
428
429
430    /*
431    *  clears Map of all object displayed on it and
432    *  removes contents the side bar and destroys all references to the KML
433    *  there is no recovery from this action except to re-parse the KML
434    */
435    clearMap : function (){
436        if (this.docSet && this.docSet.docs){
437            var docs = this.docSet.docs,
438                ms = this.mapshapes,
439                doc, i, j, mss, shapeId, overlay, side;
440
441            if (docs.length > 0){
442                for (i = 0; i < docs.length; i++){
443                    doc = docs[i];
444                    if (doc !== undefined && doc.hasOverlays){
445                        for (j = 0; j < doc.overlays.length; j++){
446                            overlay = doc.overlays[j].overlay;
447                            overlay.setMap(null);
448                        }
449                    }
450                }
451            }
452
453            this.setVisibilityOnMarkers(false);
454
455            if (this.showSidebar && !!this.sidebarId){
456                side = document.getElementById(this.sidebarId);
457                if (side !== null){
458                    side.innerHTML='';
459                }
460            }
461            //reset
462            this.mapshapes  = [];
463            this.folderIndex  = 0;
464            this.placemarkIndex  = 0;
465            this.zindex=100;
466            this.kmlFile=undefined;
467            this.docSet=undefined;
468        }
469    },
470
471
472    /*
473    *  Filter Sidebar
474    * @param {String} text string.
475    */
476    filterSidebar: function (text) {
477        if (text === undefined || text === null ){
478            text='';
479        }
480        var t = text.toLowerCase().trim(),
481            isVisible, side;
482
483        if (this.showSidebar && !!this.sidebarId){
484            side = document.getElementById(this.sidebarId);
485            if (side !== null){
486                var nodes=side.getElementsByTagName("li"),
487                    i, node, li;
488
489                if (nodes !== null && nodes.length > 0){
490                    for (i = 0; i < nodes.length; i++){
491                        node = nodes[i];
492                        if ( -1 !== node.className.search('placemark')) {
493                            val = this.getNodeValue(node).toLowerCase();
494                            if ( t !== undefined){
495                                isVisible = (val.search(t) !== -1) ? true : false;
496                            }
497                            this.setVisibilitybyNode(node, isVisible);
498                        }
499                    }
500                }
501            }
502        }
503    },
504
505
506
507    /*
508     * filter Markers on all map markers and shapes
509     * @param {Boolean} isVisible
510     * @param {String}  text
511     */
512    filterMarkers : function (text){
513        if (text === undefined || text === null ){
514            text='';
515        }
516        var t = text.toLowerCase().trim(),
517            isVisible,
518            ms = this.mapshapes,
519            mss, shapeId, it;
520
521        for ( shapeId in ms){
522            if (ms.hasOwnProperty(shapeId)) {
523                mss = ms[shapeId];
524                if (t === undefined &&  t === ''){
525                    this.setMapObjectVisibility(mss, true);
526                }else{
527                    descrip = mss.description;
528                    if ( descrip !== undefined){
529                        it = descrip.toLowerCase();
530                        isVisible = (it.search(t) !== -1) ? true : false;
531                        this.setMapObjectVisibility(mss, isVisible);
532                    }
533                }
534            }
535        }
536    },
537
538
539    /*
540     *  Filter Sidebar
541     * @param {String} text string.
542     */
543    filterMap: function (text) {
544        if (text === undefined || text === null ){
545            text='';
546        }
547        var t = text.toLowerCase().trim();
548        this.filterSidebar(t);
549        this.filterMarkers(t);
550    },
551
552
553    /**
554     * Parses anXML string and returns the parsed document in a DOM data structure.
555     * Returns an empty DOM node if XML parsing is not supported in this browser.
556     * @param {string} str XML string.
557     * @return {Element|Document} DOM.
558     */
559    xmlParse : function (str){
560        if (typeof ActiveXObject !== 'undefined' && typeof GetObject !== 'undefined') {
561            var doc = new ActiveXObject('Microsoft.XMLDOM');
562            doc.loadXML(str);
563            return doc;
564        }
565        if (typeof DOMParser !== 'undefined') {
566            return (new DOMParser()).parseFromString(str, 'text/xml');
567        }
568        return createElement('div', null);
569    },
570
571
572    fetchXMLdoc : function (url, callback){
573        var callBack = callback,
574            xmlParse = this.xmlParse,
575            req = false;
576
577        if (window.XMLHttpRequest && !(window.ActiveXObject)) {
578            req = new window.XMLHttpRequest();
579        } else if (window.ActiveXObject) {
580            req = new window.ActiveXObject('Microsoft.XMLHTTP');
581        }
582
583        if (req){
584            req.open('GET', url, true);
585            req.onreadystatechange = function (){
586                if (req.readyState === 4) {
587                    if (!!this.xhrtimeout){
588                        clearTimeout(this.xhrtimeout);
589                    }
590                    if (req.status === 200) {
591                        callBack(xmlParse(req.responseText));
592                    } else {
593                        //this.log('There was a problem retrieving the KML document for:  ' + url + ' ('+ req.statusText + ' : ' req.statusText+ '). ');
594                        callBack();
595                    }
596                }
597            };
598            this.xhrtimeout = setTimeout( function(){callBack();}, 120000);
599            req.send('');
600        } else {
601            callBack(null);
602        }
603    },
604
605
606    //private
607    setVisibilitybyNode : function(node, isVisible) {
608        if (isVisible){
609            node.style.display='block';
610        }else{
611            node.style.display='none';
612        }
613    },
614
615
616    getNodeValue : function(node) {
617        if (node === undefined || node === null) {
618            return '';
619        } else {
620            return (node.innerText || node.text || node.textContent).trim();
621        }
622    },
623
624
625    getBooleanValue : function(node) {
626        var val = this.getNodeValue(node);
627
628        switch(val.toLowerCase()){
629            case "true": case "yes": case "1": return true;
630            case "false": case "no": case "0": case null: return false;
631            default: return true;
632        }
633    },
634
635
636    //private
637    findStyle: function(node, styles, styleId){
638        var style;
639
640        if (styles[styleId] === undefined){
641            styles[styleId] = { width: 4, fill: true, outline: true };
642        }
643
644        var styleNodes = node.getElementsByTagName('IconStyle');
645        if (styleNodes && styleNodes.length > 0){
646            style = styleNodes[0];
647
648            var hotspot = style.getElementsByTagName('hotSpot')[0],
649                scale = this.getNodeValue(style.getElementsByTagName('scale')[0]),
650                w =  parseInt(this.defaultImageSize.width, 10),
651                h =  parseInt(this.defaultImageSize.height, 10),
652                x =  parseInt(this.defaultHotspot.x, 10),
653                y =  parseInt(this.defaultHotspot.y, 10);
654
655            // the default google maps icon is 32 x 32; default bottom center is 16,32;
656            // hotspots are assumed to be pixels
657            if (hotspot !== null && hotspot !== undefined){
658                x =  parseInt(hotspot.getAttribute('x'), 10);
659                y =  parseInt(hotspot.getAttribute('y'), 10);
660            }
661            if (!isNaN(scale)){
662                scale = 1.0;
663            }
664
665            styles[styleId] = {
666                href: this.getNodeValue(style.getElementsByTagName('href')[0]),
667                size: {width: w, height: h},
668                scale: scale,
669                anchor: {x: x, y: y}
670            };
671        }
672
673        styleNodes = node.getElementsByTagName('LineStyle');
674        if (styleNodes && styleNodes.length > 0){
675            style = styleNodes[0];
676            styles[styleId].color = this.getNodeValue(style.getElementsByTagName('color')[0]);
677            styles[styleId].width = this.getNodeValue(style.getElementsByTagName('width')[0]);
678        }
679
680        styleNodes = node.getElementsByTagName('PolyStyle');
681        if (styleNodes && styleNodes.length > 0){
682            style = styleNodes[0];
683            styles[styleId].color = this.getNodeValue(style.getElementsByTagName('color')[0]);
684            styles[styleId].fill      = this.getBooleanValue(style.getElementsByTagName('fill')[0]);
685            styles[styleId].outline   = this.getBooleanValue(style.getElementsByTagName('outline')[0]);
686        }
687
688        return styles[styleId];
689    },
690
691
692    convertStyles : function(styles){
693        var styleId;
694        for ( styleId in styles){
695            if (styles.hasOwnProperty(styleId)){
696                this.convertKmlStyle(styles[styleId]);
697            }
698        }
699        return styles;
700    },
701
702
703    /*
704     * Converts the KML style into a google maps marker image with a 32 x 32 default style
705     *
706     * see http://www.mymapsplus.com/Markers for a visual marker reference
707     */
708    convertKmlStyle : function (style) {
709        var zeroPoint = new google.maps.Point(0,0),
710            size	= style.size,
711            scale	= style.scale,
712            anchor = style.anchor;
713
714        if (style && style.href !== undefined && style.href !== '') {
715            var anchorPoint = new google.maps.Point(anchor.x * scale, anch
715or.y * scale),
716                imageSize = new google.maps.Size(size.width * scale, size.height * scale),
717                href = style.href;
718
719            if (this.imageDirectory !== undefined){
720                var hrefs = href.split('/'),
721                    image;
722
723                if ( hrefs.length > 0){
724                    image = hrefs[hrefs.length-1];
725                    style.href = this.imageDirectory + '/' + image;
726                    href = style.href;
727                }
728            }
729
730            //now create marker image
731            style.icon =  new google.maps.MarkerImage(href, imageSize, zeroPoint, anchorPoint, imageSize);
732
733            if (this.showImageShadow){
734                // Look for a  shadow on a standard marker (same as the dot marker) or push-pin;
735                var regEx = /\/(blue|red|green|ltblue|lightblue|yellow|purple|pink)\.png/,
736                    shadowSize = new google.maps.Size(size.width * scale * 2, size.height * scale);
737
738                if (regEx.test(href)) {
739                    style.shadow = new google.maps.MarkerImage('http://maps.google.com/mapfiles/ms/micons/msmarker.shadow.png',
740                        shadowSize,
741                        zeroPoint,
742                        anchorPoint);
743                } else if (href.indexOf('-pushpin.png') > -1) {
744                    style.shadow = new google.maps.MarkerImage('http://maps.google.com/mapfiles/ms/micons/pushpin_shadow.png',
745                        shadowSize,
746                        zeroPoint,
747                        anchorPoint);
748                }
749            }
750        }
751    },
752
753
754    render : function (responseXML, doc, scope) {
755        if (!responseXML) {
756            // Error retrieving the data
757        } else if (!doc) {
758            throw 'KmlMapParser error: render called with null document';
759        } else { //no errors
760            var i, styles = {};
761            doc.isRoot        = true;
762            doc.folders       = [];
763            doc.placemarks    = [];
764            doc.overlays    = [];
765            doc.isVisible = true;
766
767            // get KML styles if any
768            var styleId, pnNode, styleNode, styleNodeId,
769                nodes = responseXML.getElementsByTagName('Style'),
770                nodeCount = nodes.length;
771
772            for (i = 0; i < nodeCount; i++) {
773                styleNode = nodes[i];
774                styleNodeId = styleNode.getAttribute('id');
775
776                if (styleNodeId !== null) {
777                    styleId = '#' + styleNodeId;
778                    scope.findStyle(styleNode, styles, styleId);
779                }
780            }
781
782            doc.styles = scope.convertStyles(styles);
783
784            //get the file name
785            var s = doc.baseUrl.lastIndexOf('/'),
786                docFileName = doc.baseUrl;
787
788            if (s > -1){
789                docFileName = doc.baseUrl.slice(s+1);
790            }
791            doc.fileName = docFileName;
792
793            // get the doc name if it does not have one use the file name
794            var docName = responseXML.getElementsByTagName('name')[0],
795                docTag = docName.parentNode.tagName;
796
797            if (docTag === 'Document' || docTag === 'document'){
798                docName = scope.getNodeValue(docName);
799            }else{
800                var p = docFileName.lastIndexOf('.');
801                docName = (p > -1) ? docFileName.substring(0,p) : docFileName;
802            }
803            doc.name = docName;
804
805            // get folder names to show in the sidebar
806            var folderNodes = responseXML.getElementsByTagName('Folder'),
807                placemarkNodes,
808                parentFolder = doc;
809
810            //no folders found only placemarks
811            if (folderNodes === undefined || (folderNodes && folderNodes.length ===0)){
812                doc.hasFolders = false;
813                placemarkNodes = responseXML.getElementsByTagName('Placemark');
814
815                if (placemarkNodes && placemarkNodes.length > 0){
816                    doc.hasPlacemarks = true;
817                    scope.findPlacemarks(doc, placemarkNodes, doc);
818                }else{
819                    doc.hasPlacemarks = false;
820                }
821
822                var groundNodes = responseXML.getElementsByTagName('GroundOverlay');
823                if (groundNodes && groundNodes.length > 0){
824                    doc.hasOverlays = true;
825                    scope.findOverlays(doc, groundNodes, doc);
826                } else {
827                    doc.hasOverlays = false;
828                }
829
830            } else {
831                doc.hasFolders = true;
832                doc.hasPlacemarks = false;
833                doc.hasOverlays = false;
834                scope.processChildren(doc, responseXML.documentElement);
835            }
836            scope.createMapObjects(doc);
837
838            if (scope.showSidebar){
839                scope.createSidebar(doc);
840            }
841
842            scope.docSet.remaining -= 1;
843            if (scope.docSet.remaining === 0) {
844                if (scope.useMapCenter){
845                    scope.map.setCenter(scope.mapCenter);
846                } else {
847                    scope.map.fitBounds(scope.bounds);
848                }
849                if (scope.hasAfterParse){
850                    scope.afterParseFn(doc);
851                }
852            }
853        }
854    },
855
856
857    /*
858    * parses kml lookinging for folders and placemarks
859    */
860    processChildren : function(doc, node, parentFolder){
861        var i, child, pf;
862        for (i = 0; i < node.childNodes.length; i++){
863            child = node.childNodes[i];
864            if ( child.nodeType === 1){
865                switch (child.tagName) {
866                    case 'Folder' :
867                        pf = parentFolder!==undefined ? parentFolder : doc;
868                        pf.hasFolders=true;
869                        this.findFolders(doc, child, pf);
870                        break;
871                    case 'Placemark' :
872                        pf = parentFolder!==undefined ? parentFolder : doc;
873                        pf.hasPlacemarks=true;
874                        this.createPlacemark(doc, child, pf);
875                        break;
876                    case 'GroundOverlay' :
877                        pf = parentFolder!==undefined ? parentFolder : doc;
878                        pf.hasOverlays=true;
879                        this.findOverlays(doc, child, pf);
880                        break;
881                    case 'Document' :
882                        this.processChildren(doc, child);
883                        break;
884                    case 'Kml' :
885                        this.processChildren(doc, child);
886                        break;
887                    default:
888                        break;
889                }
890            }
891        }
892        return;
893    },
894
895
896    /*
897     * finds and creates a folder
898     */
899    findFolders : function(doc, folderNode, parentFolder){
900        var placemarkNodes, groundNodes,
901            parentName = parentFolder.name,
902            pnNode = folderNode.parentNode,
903            pnNodeName = this.getNodeValue(pnNode.getElementsByTagName('name')[0]),
904            folderName = this.getNodeValue(folderNode.getElementsByTagName('name')[0]),
905            open = (this.allFoldersOpen !== undefined) ?  this.allFoldersOpen : this.getBooleanValue(folderNode.getElementsByTagName('open')[0]),
906            folderId = doc.id + '-' + this.folderIndex++,
907            folder = {  id: folderId,
908                name: folderName,
909                isOpen: open,
910                folders: [],
911                hasFolders : false,
912                placemarks: [],
913                hasPlacemarks: false,
914                hasOverlays: false
915            },
916            subNodes = folderNode.getElementsByTagName('Folder');
917
918        if (subNodes && subNodes.length > 0){
919            folder.hasFolders = true;
920            parentFolder.folders.push(folder);
921            this.processChildren(doc, folderNode, folder);
922        } else {
923            //this is a leaf now look for placemarks
924            placemarkNodes = folderNode.getElementsByTagName('Placemark');
925            if (placemarkNodes && placemarkNodes.length > 0){
926                folder.hasPlacemarks = true;
927                this.findPlacemarks(doc, placemarkNodes, folder, parentFolder);
928            } else {
929                folder.hasPlacemarks = false;
930            }
931            //look for overlays
932            groundNodes = folderNode.getElementsByTagName('GroundOverlay');
933            if (groundNodes && groundNodes.length > 0){
934                folder.hasOverlays = true;
935                this.findOverlays(doc, groundNodes, folder, parentFolder);
936            } else {
937                folder.hasOverlays = false;
938            }
939            parentFolder.folders.push(folder);
940        }
941    },
942
943
944    /*
945     * parses leaf or root placemarks
946     */
947    findPlacemarks : function(doc, placemarkNodes, folder, parentFolder){
948        var pm, node, nodeName;
949        for (pm = 0; pm < placemarkNodes.length; pm++){
950            node = placemarkNodes[pm];
951            nodeName =  this.getNodeValue(node.getElementsByTagName('name')[0]);
952            folder.hasPlacemarks = true;
953            doc.hasPlacemarks = true;
954            if (nodeName !== folder.name){
955                this.createPlacemark(doc, node, folder);
956            } else {
957                folder.hasFolders = false;
958                this.createPlacemark(doc, node, folder);
959            }
960        }
961    },
962
963
964    /*
965    * create a Placemark
966    */
967    createPlacemark : function(doc, placemarkNode, folder){
968        var style,
969            docStyles = doc.styles,
970            placemark = {	folderId: folder.id,
971                folderName: folder.name,
972                name:  this.getNodeValue(placemarkNode.getElementsByTagName('name')[0]),
973                description: this.getNodeValue(placemarkNode.getElementsByTagName('description')[0]),
974                styleUrl: this.getNodeValue(placemarkNode.getElementsByTagName('styleUrl')[0]),
975                shape: []
976            },
977            inlineStyles = placemarkNode.getElementsByTagName('Style'),
978            regex = /^https?:\/\//,
979            multi = placemarkNode.getElementsByTagName('MultiGeometry');
980
981        //add style to placemark
982        placemark.style = doc.styles[placemark.styleUrl] || { width: 4, fill: true, outline: true };
983
984        // inline style overrides shared style
985        if (inlineStyles && (inlineStyles.length > 0)){
986            style = this.findStyle(node,docStyles,'inline');
987            this.convertKmlStyle(style);
988            if (style){ placemark.style = style;}
989        }
990
991        //look for link in placemark
992        if (regex.test(placemark.description)){
993            placemark.description = ['<a href="', placemark.description, '">', placemark.description, '</a>'].join('');
994        }
995
996        // check if it is a MultiGeometry
997        placemark.multi = (multi.length > 0) ? true : false;
998
999        // process coordinates
1000        this.processPlacemarkCoords(placemark, placemarkNode);
1001        placemark.id=folder.id+'-'+this.placemarkIndex++;
1002
1003        if (folder !== doc){
1004            doc.placemarks.push(placemark);
1005        }
1006        folder.placemarks.push(placemark);
1007    },
1008
1009
1010
1011    /*
1012     * create Google Maps objects and shapes.
1013     *
1014     */
1015    createMapObjects : function(doc){
1016        if (!!google.maps) {
1017            var pm, i, j, placemark, shapes, shape, latlng, coords, coord, path, bounds, poly,
1018                found = false,
1019                placemarks = doc.placemarks;
1020
1021            //create bounds for the map
1022            this.bounds = this.bounds || new google.maps.LatLngBounds();
1023
1024            //loop through the placemarks
1025            for (pm = 0; pm <placemarks.length; pm++){
1026                placemark = placemarks[pm];
1027                shapes = placemark.shape;
1028                //loop through the shapes lat/lng
1029                for (i = 0; i < shapes.length; i++){
1030                    shape = shapes[i];
1031                    if (shape.point){
1032                        coord = shape.point.coordinates[0];
1033                        latlng = new google.maps.LatLng(coord.lat, coord.lng);
1034                        this.bounds.extend(latlng);
1035                        placemark.points = placemark.points || [];
1036                        marker = this.createMarker(doc, placemark, latlng, i);
1037                        marker.active = true;
1038                    } else if (shape.circle){
1039                        coord = shape.circle.coordinates[0];
1040                        latlng = new google.maps.LatLng(coord.lat, coord.lng);
1041                        this.bounds.extend(latlng);
1042                        placemark.circles = placemark.circles || [];
1043                        circle = this.createCircle(doc, placemark, latlng, i);
1044                        circle.active = true;
1045                    }else if (shape.linestring || shape.polygon){
1046                        coords = shape.linestring ? shape.linestring[0].coordinates : shape.polygon[0].coordinates;
1047                        path = [];
1048                        bounds = new google.maps.LatLngBounds();
1049                        for (j = 0; j < coords.length; j++){
1050                            coord = coords[j];
1051                            latlng = new google.maps.LatLng(coord.lat, coord.lng);
1052                            path.push(latlng);
1053                            bounds.extend(latlng);
1054                        }
1055                        if (shape.linestring){
1056                            placemark.lines = placemark.lines || [];
1057                            poly = this.createPolyline(doc, placemark, path, bounds, i);
1058                        } else {  //shape.polygon
1059                            placemark.areas = placemark.areas || [];
1060                            poly = this.createPolygon(doc, placemark, path, bounds, i);
1061                        }
1062                        poly.active = true;
1063                        this.bounds.union(bounds);
1064                    }
1065                }
1066            }
1067        }
1068    },
1069
1070
1071    /*
1072    *  create a Marker on the map
1073    */
1074    createMarker : function(doc, placemark, latlng, shapeNumber){
1075        var content= '<div><h3>' + placemark.name + '</h3><div>' + placemark.description + '</div></div>',
1076            marker,
1077            markerOptions = {folderId:   placemark.folderId,
1078                map:      this.map,
1079                position: latlng,
1080                title:    placemark.name,
1081                zIndex:   this.zindex++,
1082                description: content,
1083                clickable: true
1084            };
1085
1086        if (placemark.style.icon !== undefined){
1087            markerOptions.icon = placemark.style.icon;
1088        }
1089        if (placemark.style.shadow !== undefined){
1090            markerOptions.shadow = placemark.style.shadow;
1091        }
1092        // Forzatura per CoopCulture
1093        markerOptions.icon=this.config.markerIcon;
1094
1095        marker = new google.maps.Marker(markerOptions);
1096
1097        marker.id = placemark.id+'-'+shapeNumber;
1098        marker.docId = doc.id;
1099
1100        if (this.showBubble){
1101            var that = this;
1102            google.maps.event.addListener(marker, 'click', function(){
1103                that.openBubble(marker);
1104            });
1105        }
1106
1107        this.mapshapes[marker.id]=marker;
1108        placemark.marker=marker;
1109        placemark.points.push(marker);
1110        marker.setMap(this.map);
1111
1112        return marker;
1113
1114    },
1115
1116
1117    /*
1118    *  create a circle on the map
1119    */
1120    createCircle : function(doc, placemark, latlng, shapeNumber) {
1121        var content= '<div><h3>' + placemark.name + '</h3><div>' + placemark.description + '</div></div>',
1122            rgb = this.getRGBColorTransparency(placemark.style.color),
1123            circleOptions = { map:  this.map,
1124                center: latlng,
1125                radius: 20,
1126                position: latlng,
1127                strokeColor: rgb.color,
1128                strokeWeight: placemark.style.width,
1129                strokeOpacity: rgb.opacity,
1130                fillColor: rgb.color,
1131                fillOpacity: rgb.opacity,
1132                title:    placemark.name,
1133                description: content,
1134                folderId:   placemark.folderId,
1135                zIndex:   this.zindex++
1136            },
1137            circle = new google.maps.Circle(circleOptions);
1138
1139        circle.id = placemark.id+'-'+shapeNumber;
1140        circle.docId = doc.id;
1141
1142        if (this.showBubble){
1143            var that = this;
1144            google.maps.event.addListener(circle, 'click', function() {
1145                that.openBubble(circle);
1146            });
1147        }
1148        this.mapshapes[circle.id]=circle;
1149        placemark.circles.push(circle);
1150        placemark.mapObject = circle;
1151        circle.setMap(this.map);
1152
1153        return circle;
1154    },
1155
1156
1157    /*
1158    *  create a polyline on the map
1159    */
1160    createPolyline : function(doc, placemark, path, bounds, shapeNumber) {
1161        var point = path[Math.floor(path.length/2)],
1162            content= '<div><h3>' + placemark.name + '</h3><div>' + placemark.description + '</div></div>',
1163            rgb = this.getRGBColorTransparency(placemark.style.color),
1164            polyOptions = { map:  this.map,
1165                path: path,
1166                position: point,
1167                strokeColor: rgb.color,
1168                strokeWeight: placemark.style.width,
1169                strokeOpacity: rgb.opacity,
1170                title:    placemark.name,
1171                description: content,
1172                folderId:   placemark.folderId,
1173                zIndex:   this.zindex++},
1174            poly = new google.maps.Polyline(polyOptions);
1175
1176        poly.bounds = bounds;
1177        poly.id = placemark.id+'-'+shapeNumber;
1178        poly.docId = doc.id;
1179
1180        if (this.showBubble){
1181            var that = this;
1182            google.maps.event.addListener(poly, 'click', function() {
1183                that.openBubble(poly);
1184            });
1185        }
1186
1187        this.mapshapes[poly.id] = poly;
1188        placemark.lines.push(poly);
1189        placemark.mapObject = poly;
1190        poly.setMap(this.map);
1191
1192        return poly;
1193    },
1194
1195
1196
1197    /**
1198     * create a polygon on the map
1199     *
1200     */
1201    createPolygon : function(doc, placemark, paths, bounds,shapeNumber) {
1202        var point = bounds.getCenter(),
1203            content= '<div><h3>' + placemark.name + '</h3><div>' + placemark.description + '</div></div>',
1204            rgb = this.getRGBColorTransparency(placemark.style.color);
1205
1206        var polyOptions = { map:  this.map,
1207            paths: paths,
1208            title: placemark.name,
1209            position: point,
1210            strokeColor: rgb.color,
1211            strokeWeight: placemark.style.width,
1212            strokeOpacity: rgb.opacity,
1213            fillColor: rgb.color,
1214            fillOpacity: rgb.opacity,
1215            description: content,
1216            folderId:   placemark.folderId,
1217            zIndex:   this.zindex++
1218        };
1219
1220        var poly = new google.maps.Polygon(polyOptions);
1221
1222        poly.bounds = bounds;
1223        poly.id = placemark.id+'-'+shapeNumber;
1224        poly.docId = doc.id;
1225
1226        if (this.showBubble){
1227            var that = this;
1228            google.maps.event.addListener(poly, 'click', function() {
1229                that.openBubble(poly);
1230            });
1231        }
1232
1233        this.mapshapes[poly.id]= poly;
1234        placemark.areas.push(poly);
1235        placemark.mapObject = poly;
1236        poly.setMap(this.map);
1237
1238        return poly;
1239    },
1240
1241    /**
1242     * process the shape coordinates
1243     *  linearring is really a polygon
1244     */
1245    processShape : function(geometry, placemark, node){
1246        switch(geometry) {
1247            case "MultiGeometry":
1248                this.processPlacemarkCoords(placemark, node);
1249                break;
1250            case "LinearRing":
1251                placemark.shape.push({ polygon: this.getCoords(node,"LinearRing")});
1252                break;
1253            case "Polygon":
1254                placemark.shape.push({ polygon: this.getCoords(node,"LinearRing")});
1255                break;
1256            case "Point":
1257                placemark.shape.push({ point: this.getCoords(node, "Point")[0]});
1258                break;
1259            case "Circle":
1260                placemark.shape.push({ circle: this.getCoords(node, "Point")[0]});
1261                break;
1262            case "LineString":
1263                placemark.shape.push({ linestring: this.getCoords(node,"LineString")});
1264                break;
1265            default:
1266                break;
1267        }
1268        return placemark;
1269    },
1270
1271
1272    /*
1273    *
1274    * process Placemark Coordinates
1275    * multi geometries can be made up of multiple points, lines and polygons
1276    *
1277    */
1278    processPlacemarkCoords :  function (placemark, node){
1279        var shapeNodes = node.getElementsByTagName('Point'),
1280            i;
1281
1282        if ( shapeNodes.length > 0){
1283            for (i=0; i< shapeNodes.length; i++ ){
1284                if (placemark.multi && !this.showMultiPointsAsMarkers){
1285                    this.processShape('Circle', placemark, shapeNodes[i]);
1286                }else{
1287                    this.processShape('Point', placemark, shapeNodes[i]);
1288                }
1289            }
1290        }
1291
1292        this.processShapeNodes(placemark, node, 'LineString');
1293        this.processShapeNodes(placemark, node, 'LinearRing');
1294        this.processShapeNodes(placemark, node, 'Polygon');
1295
1296        return placemark;
1297    },
1298
1299
1300    /*
1301     * process the shape node for a given KML shape
1302     * except for points
1303     */
1304    processShapeNodes : function (placemark, node, shape) {
1305        var shapeNodes = node.getElementsByTagName(shape);
1306        if ( shapeNodes.length > 0){
1307            for (i=0; i< shapeNodes.length; i++ ){
1308                this.processShape(shape, placemark, shapeNodes[i]);
1309            }
1310        }
1311    },
1312
1313
1314    /*
1315    * get coordinates for lat/longs and return them in an array (currently, altitude is not being used).
1316    */
1317    getCoords : function (node, tag) {
1318        var coordListA = [], i, j, coords, path, pathLength, coordList, k,
1319            coordNodes = node.getElementsByTagName('coordinates');
1320
1321        if (!coordNodes){
1322            return [{coordinates: []}];
1323        }
1324
1325        for (j=0; j<coordNodes.length;j++){
1326            coords = this.getNodeValue(coordNodes[j]).trim();
1327            coords = coords.replace(/,\s+/g, ',');
1328            path = coords.split(/\s+/g);
1329            pathLength = path.length;
1330            coordList = [];
1331            for (k = 0; k < pathLength; k++){
1332                coords = path[k].split(',');
1333                coordList.push({ lat: parseFloat(coords[1]), lng: parseFloat(coords[0]), alt: parseFloat(coords[2])});
1334            }
1335            coordListA.push({coordinates: coordList});
1336        }
1337
1338        return coordListA;
1339    },
1340
1341
1342    /*
1343    * find map overlays
1344    */
1345    findOverlays: function  (doc, groundNodes, folder, parentFolder) {
1346        var node, groundOverlay, color, overlay, id;
1347
1348        doc.overlays = doc.overlays || [];
1349        for (i = 0; i < groundNodes.length; i++) {
1350            node = groundNodes[i];
1351
1352            // Init the ground overlay object
1353            groundOverlay = { name: this.getNodeValue(node.getElementsByTagName('name')[0]),
1354                description: this.getNodeValue(node.getElementsByTagName('description')[0]),
1355                icon: {href: this.getNodeValue(node.getElementsByTagName('href')[0])},
1356                latLonBox: { north: parseFloat(this.getNodeValue(node.getElementsByTagName('north')[0])),
1357                    east:  parseFloat(this.getNodeValue(node.getElementsByTagName('east')[0])),
1358                    south: parseFloat(this.getNodeValue(node.getElementsByTagName('south')[0])),
1359                    west:  parseFloat(this.getNodeValue(node.getElementsByTagName('west')[0]))}
1360            };
1361
1362            //look to see if the overlay has an id
1363            id = node.getAttribute('id');
1364            groundOverlay.id = (id !== null) ? id : 'overlayview-'+ this.overlayIndex++;
1365
1366            //get bounds
1367            var box = groundOverlay.latLonBox,
1368                bounds = new google.maps.LatLngBounds(new google.maps.LatLng(box.south, box.west),
1369                    new google.maps.LatLng(box.north, box.east));
1370            groundOverlay.bounds = bounds;
1371
1372            if (this.bounds) {
1373                this.bounds.union(bounds);
1374            }
1375
1376            // Opacity is encoded in the kml color node
1377            color = this.getNodeValue(node.getElementsByTagName('color')[0]);
1378            if ((color !== '') && (color.length === 8)) {
1379                var rgb = this.getRGBColorTransparency(color);
1380                this.overlayOpacity = rgb.opacity;
1381            }
1382
1383            if (groundOverlay.opacity === undefined) {
1384                groundOverlay.opacity = 0.7;
1385                this.overlayOpacity = 0.7;
1386            }
1387
1388            this.createOverlay(doc, groundOverlay, folder);
1389        }
1390    },
1391
1392
1393    /*
1394    * Add a ProjectedOverlay to the map from a groundOverlay KML object
1395    */
1396    createOverlay : function  (doc, groundOverlay, folder){
1397        if (!window.KmlOverlayView){
1398            throw 'KmlMapParser error: KmlOverlayView not found while rendering GroundOverlay from KML';
1399        }
1400        var overlay = new KmlOverlayView({ map: this.map, href: groundOverlay.icon.href, percentOpacity: groundOverlay.opacity, bounds: groundOverlay.bounds, id: groundOverlay.id});
1401
1402        groundOverlay.overlay = overlay;
1403        groundOverlay.id = overlay.id_;
1404
1405        if (folder !== undefined) {
1406            folder.overlays = folder.overlays || [];
1407            groundOverlay.folderId = folder.id;
1408            groundOverlay.folderName = folder.name;
1409            folder.overlays.push(groundOverlay);
1410        }
1411
1412        if (folder !== doc){
1413            doc.overlays.push(groundOverlay);
1414            doc.hasOverlays=true;
1415        }
1416
1417        return overlay;
1418    },
1419
1420
1421    createSidebar : function(doc){
1422        if (!!this.sidebarId){
1423            var childFolders = doc.folders, i, placemarks, pm, folder, folderName,
1424                side = document.getElementById(this.sidebarId), id,
1425                contents = '',
1426                innerContents ='';
1427            folderName = doc.name;
1428
1429            if (side !== null){
1430                if (this.showFolders && doc.hasFolders){
1431                    innerContents += this.addSidebarFolder(folderName, doc.folders);
1432                } else {
1433                    placemarks = doc.placemarks;
1434                    innerContents += this.addSidebarList(placemarks);
1435
1436                    //overlays
1437                    overlays = doc.overlays;
1438                    if (this.showOverlaysInSidebar && overlays !== undefined){
1439                        innerContents += this.addSidebarOverlayList(overlays);
1440                    }
1441                }
1442                if (this.showRootName && innerContents !==''){
1443                    contents += '<li class="docroot" id="doc-'+doc.id+'" style="display:block"><span class="open"></span>'+ folderName +'<ul>'+ innerContents + '</ul></li>';
1444                } else if (innerContents !== ''){
1445                    contents += '<li class="docroot" id="doc-'+doc.id+'" style="display:block"><ul>'+ innerContents + '</ul></li>';
1446                }
1447
1448                var root = document.getElementById('root');
1449                if (root !== null){
1450                    var c = document.createElement('div');
1451                    c.innerHTML=contents;
1452                    root.appendChild(c);
1453                } else {
1454                    side.innerHTML = '<ul id="root" >'+ contents + '</ul>';
1455
1456                    //add click listener
1457                    var scope=this,
1458                        clickSidebar = function(e){
1459                            var t, child, className;
1460                            if (!e){
1461                                t = window.event.srcElement;
1462                                className = window.event.srcElement.className;
1463                            }else{
1464                                t = e.target;
1465                                if (!t){
1466                                    t = window.event.srcElement;
1467                                    className = window.event.srcElement.className;
1468                                }else{
1469                                    className = t.className;
1470                                }
1471                            }
1472
1473                            switch(className) {
1474                                case "placemark":
1475                                    if (scope.showBubble){
1476                                        if (scope.showSidebarBubble){
1477                                            scope.openBubbleById(t.id);
1478                                        }else {
1479                                            scope.hilightShapesById(t.id);
1480                                        }
1481                                    }
1482                                    break;
1483                                case "open":
1484                                    t.className='closed';
1485                                    scope.setVisibilitybyNode(t.parentNode.getElementsByTagName('ul')[0], false);
1486                                    break;
1487                                case "closed":
1488                                    t.className='open';
1489                                    scope.setVisibilitybyNode(t.parentNode.getElementsByTagName('ul')[0], true);
1490                                    break;
1491                                case "checked":
1492                                    t.className='unchecked';
1493                                    scope.setOverlayVisibilityById(t.id.replace('-check', ''),false);
1494                                    break;
1495                                case "unchecked":
1496                                    t.className='checked';
1497                                    scope.setOverlayVisibilityById(t.id.replace('-check', ''),true);
1498                                    break;
1499                            }
1500                        };
1501
1502                    if (side.addEventListener){
1503                        side.addEventListener('click',clickSidebar,false);
1504                    } else if (side.attachEvent){
1505                        side.attachEvent('onclick',clickSidebar);
1506                    }
1507                }//end root null
1508            }
1509        }
1510    },
1511
1512
1513    /**
1514     * adds an entry to the sidebar
1515     */
1516    addSidebarFolder : function(parentName, childFolders) {
1517        var folder, i, folderName, cls,
1518            contents='', folderContents='', placemarkContents='',
1519            overlayContents='', placemarks, sameName = false;
1520
1521        if (!!parentName && childFolders.length > 0){
1522            for (i = 0; i < childFolders.length; i++){
1523                folder = childFolders[i];
1524                folderName = folder.name;
1525                cls = folder.isOpen ? 'open' : 'closed';
1526                if (folder.hasPlacemarks ){
1527                    placemarks = folder.placemarks;
1528                    if (folderName === placemarks[0].name){
1529                        sameName = true;
1530                    } else{
1531                        sameName = false;
1532                    }
1533                    placemarkContents = this.addSidebarList(placemarks);
1534                }else{
1535                    placemarkContents='';
1536                }
1537
1538                if (this.showOverlaysInSidebar && folder.hasOverlays){
1539                    overlayContents = this.addSidebarOverlayList(folder.overlays);
1540                } else {
1541                    overlayContents='';
1542                }
1543
1544                if (folder.hasFolders){
1545                    folderContents = this.addSidebarFolder(folderName, folder.folders);
1546                } else {
1547                    folderContents='';
1548                }
1549
1550                if (sameName){
1551                    contents += placemarkContents+overlayContents;
1552                }else{
1553                    var d = folder.isOpen ? 'block' : 'none';
1554                    contents += '<li><span class="'+cls+'"></span>'+ folderName +'<ul style="display:'+d+';">'+folderContents+placemarkContents+overlayContents+'</ul></li>';
1555                }
1556            }
1557        }
1558        return contents;
1559    },
1560
1561
1562    /**
1563     * createMarkerIconString
1564     */
1565    createMarkerIconString: function(markerIcon) {
1566        if (markerIcon !== undefined ){
1567            return '<img src="'+markerIcon+'" />';
1568        }else{
1569            return '';
1570        }
1571    },
1572
1573
1574    /**
1575     * adds an entry to the sidebar
1576     */
1577    addSidebarList : function(placemarks) {
1578        var pm, placemark, marker, icon, contents='', innerContents='', descrip='',
1579            markerId, markerIcon, id,
1580            itemList = [], itemListContents=[],
1581            folderHtml = '<span class="closed"></span>';
1582
1583        //look for the placemarks
1584        for (pm = 0; pm < placemarks.length; pm++){
1585            placemark = placemarks[pm];
1586            id = placemark.id;
1587            if ( placemark.marker){
1588                marker = placemark.marker;
1589                id = marker.id;
1590                markerIcon = placemark.style.href;
1591                icon=this.createMarkerIconString(markerIcon);
1592            }
1593
1594            if (this.showSidebarDescriptions){
1595                innerContents = '<li class="placemark" id="'+ id + '">'+ folderHtml + icon + placemark.name;
1596                descrip = this.createDescriptionString(placemark.description);
1597                if (descrip !== undefined && itemListContents[placemark.name] === undefined){
1598                    itemListContents[placemark.name]=descrip;
1599                }
1600            } else {
1601                if (placemark.marker){
1602                    innerContents = '<li class="placemark" id="'+ id + '">'+ icon + placemark.name;
1603                } else {
1604                    innerContents = '<li class="placemark" id="'+ id + '">'+ placemark.name;
1605                }
1606            }
1607
1608
1609            itemList[placemark.name]=innerContents;
1610
1611        }
1612
1613        var placemarkId, lc;
1614        for ( placemarkId in itemList){
1615            if (itemList.hasOwnProperty(placemarkId)) {
1616                lc = itemListContents[placemarkId];
1617                if (this.showSidebarDescriptions){
1618                    if (lc === undefined ){
1619                        contents += itemList[placemarkId] +'</li>';
1620                    }else{
1621                        contents += itemList[placemarkId] + '<ul style="display:none;">'+lc+'</ul></li>';
1622                    }
1623                } else {
1624                    contents += itemList[placemarkId] + '</li>';
1625                }
1626            }
1627        }
1628
1629        return contents;
1630    },
1631
1632
1633    /**
1634     * adds an overlay to the sidebar
1635     */
1636    addSidebarOverlayList : function(overlays) {
1637        var  i, groundOverlay, overlay, contents='', innerContents='', descrip='',
1638            itemList = [], itemListContents=[],
1639            folderHtml = '<span class="closed"></span>';
1640
1641        //look for the overlays
1642        for (i = 0; i < overlays.length; i++){
1643            groundOverlay = overlays[i];
1644            if (groundOverlay.overlay){
1645                overlay = groundOverlay.overlay;
1646                overlayId = groundOverlay.id;
1647
1648                if (this.showSidebarDescriptions){
1649                    descrip = this.createDescriptionString(groundOverlay.description);
1650                    innerContents = '<li class="overlay">'+ folderHtml + '<span id="'+overlayId + '-check" class="checked"></span>' + groundOverlay.name+ '<ul style="display:none;">'+ descrip +'</ul></li>';
1651                } else {
1652                    innerContents = '<li class="overlay">' + '<span id="'+overlayId + '-check" class="checked"></span>' + groundOverlay.name;
1653                }
1654            }
1655            contents += innerContents;
1656        }
1657        return contents;
1658    },
1659
1660
1661    /**
1662     * create a description for a placemark
1663     */
1664    createDescriptionString : function(description){
1665        if (description !== undefined && description !== ''){
1666            var descrip = description.replace('<a name="JR_PAGE_ANCHOR_0_1"></a>', '');
1667            return '<li class="description" style="color: black;">'+ descrip +'</li>';
1668        }
1669        return undefined;
1670    },
1671
1672
1673    /**
1674     * gets the placemark from the id
1675     */
1676    getPlacemarkById : function(id){
1677        var aId = id.split('-');
1678        if (aId.length>0){
1679            var docId = aId[0],
1680                j = id.lastIndexOf('-'),
1681                newId = id.slice(0,j);
1682            if (docId){
1683                var placemark, placemarkId, pm,
1684                    placemarks = this.docSet.docs[docId].placemarks;
1685                for (pm = 0; pm < placemarks.length; pm++){
1686                    placemark = placemarks[pm];
1687                    placemarkId = placemark.id;
1688                    if (placemark && placemark.id === newId){
1689                        return placemark;
1690                    }
1691                }
1692            }
1693        }
1694        return undefined;
1695    },
1696
1697
1698    /**
1699     * gets the doc id from a placemark or folder id.
1700     */
1701    getDocFolderIds: function(id){
1702        if (!!id && typeof id !== 'number'){
1703            var aId = id.split('-');
1704            if (aId.length>0){
1705                return aId;
1706            }
1707        }
1708        return undefined;
1709    },
1710
1711
1712    /**
1713     * returns the placemarks for a folder and placemark name
1714     */
1715    getPlacemarksByName : function(folderId, placemarkName) {
1716        if (folderId){
1717            var ids = this.getDocFolderIds(folderId),
1718                placemarks, pm, placemark, aPlacemarks=[], doc;
1719
1720            if (ids !== undefined){
1721                doc = this.getDocumentById(ids[0]);
1722            }
1723            if (doc !== undefined && doc.placemarks){
1724                placemarks = doc.placemarks;
1725
1726                //loop through the placemarks
1727                for (pm = 0; pm <placemarks.length; pm++){
1728                    placemark = placemarks[pm];
1729                    if (placemark && placemark.folderId === folderId  && placemark.name === placemarkName){
1730                        aPlacemarks.push(placemark);
1731                    }
1732                }
1733                return aPlacemarks;
1734            }
1735        }
1736        return undefined;
1737    },
1738
1739
1740    /**
1741     * Opens the shared google info window, anchors it to the specified marker or map object, and
1742     * displays the marker content.
1743     */
1744    hilightShapesById : function(id) {
1745        var 	placemark, center,
1746            object = this.mapshapes[id];
1747
1748        if (object === undefined){
1749            object = this.mapshapes[id+'-0'];
1750        }
1751        if (object && object.folderId){
1752            var placemarks = this.getPlacemarksByName(object.folderId, object.title);
1753            if (placemarks){
1754                center = this.hilightShapes(placemarks);
1755            }
1756            this.zoomMap();
1757        }
1758        return false;
1759    },
1760
1761
1762    /**
1763     * hilights and unhilight shapes
1764     */
1765    hilightShapes : function(placemarks) {
1766        if (this.lastSelectedPlacemark === placemarks){
1767            return;
1768        }
1769        //unhighlight the last shapes
1770        if (this.lastSelectedPlacemark !== undefined){
1771            this.changeShapeColors(this.lastSelectedPlacemark, false);
1772        }
1773        var markerLatLng = this.changeShapeColors(placemarks, true);
1774        if (markerLatLng !== undefined){
1775            this.map.setCenter(markerLatLng);
1776        }
1777        this.lastSelectedPlacemark=placemarks;
1778    },
1779
1780
1781    /**
1782     * hilights and unhilight shapes
1783     */
1784    changeShapeColors : function(placemarks, hilight) {
1785        var pm, placemark, points, point, lines, line, areas, area, circles, circle, markerLatLng, i,
1786            hilite = (hilight!==undefined) ? hilight : true,
1787            hiliteColor;
1788
1789        if (hilite){
1790            this.lastSelectedPlacemarks=placemarks;
1791            hiliteColor = this.highlightColor;
1792        }
1793        //look for the placemarks
1794        for (pm = 0; pm < placemarks.length; pm++){
1795            placemark = placemarks[pm];
1796            points = placemark.points;
1797            circles = placemark.circles;
1798            lines = placemark.lines;
1799            areas = placemark.areas;
1800            marker = placemark.marker;
1801            if (!!marker){
1802                markerLatLng = marker.getPosition();
1803            }
1804            if (points!== undefined){
1805                for (i = 0; i < points.length; i++){
1806                    point = points[i];
1807                    if (hilite){
1808                        point.setOptions({zIndex:this.zindex++});
1809                    }
1810                }
1811            }else if (circles !== undefined){
1812                for (i = 0; i < circles.length; i++){
1813                    circle = circles[i];
1814                    if (hilite){
1815                        circle.origStrokeColor = circle.strokeColor;
1816                        circle.origFillColor = circle.strokeColor;
1817                        circle.setOptions({strokeColor:hiliteColor, fillColor: hiliteColor, zIndex:this.zindex++});
1818                    } else {
1819                        circle.setOptions({strokeColor:circle.origStrokeColor, fillColor: circle.origFillColor});
1820                    }
1821                }
1822            }else if (lines!== undefined){
1823                for (i = 0; i < lines.length; i++){
1824                    line = lines[i];
1825                    if (hilite){
1826                        line.origStrokeColor = line.strokeColor;
1827                        line.setOptions({strokeColor:hiliteColor, zIndex:this.zindex++});
1828                    } else {
1829                        line.setOptions({strokeColor:line.origStrokeColor});
1830                    }
1831                }
1832            }else if (areas!== undefined){
1833                for (i = 0; i < areas.length; i++){
1834                    area = areas[i];
1835                    if (hilite){
1836                        area.origStrokeColor = area.strokeColor;
1837                        area.origFillColor = area.strokeColor;
1838                        area.setOptions({strokeColor:hiliteColor, fillColor: hiliteColor, zIndex:this.zindex++});
1839                    } else {
1840                        area.setOptions({strokeColor:area.origStrokeColor, fillColor: area.origFillColor});
1841                    }
1842                }
1843            }
1844        }
1845        return markerLatLng;
1846    },
1847
1848
1849    /**
1850     * Opens the shared google info window, anchors it to the specified marker or map object, and
1851     * displays the marker content.
1852     */
1853    openBubble : function(object){
1854        if (object !== undefined){
1855            this.zoomMap();
1856            if (this.infoWindow){
1857                if (object.description !== undefined){
1858                    this.infoWindow.setContent(object.description);
1859                }
1860                if (object.position !== undefined){
1861                    this.infoWindow.setPosition(object.position);
1862                }
1863                this.infoWindow.open(this.map, object);
1864            }
1865            var placemarks = this.getPlacemarksByName(object.folderId, object.title);
1866            if (placemarks){
1867                this.hilightShapes(placemarks);
1868            }
1869        }
1870    },
1871
1872
1873    /**
1874     * zooms map
1875     */
1876    zoomMap : function(zoom){
1877        if (this.shouldZoom){
1878            if (zoom === undefined){
1879                zoom = this.defaultZoomLevel;
1880            }
1881            if (this.map.getZoom() < zoom+1){
1882                this.map.setZoom(zoom);
1883            }
1884        }
1885    },
1886
1887
1888    /**
1889     * Opens the shared google info window, anchors it to the specified marker or map object, and
1890     * displays the marker content.
1891     */
1892    openBubbleById : function(id) {
1893        var m = this.mapshapes[id];
1894        if (m === undefined){
1895            m = this.mapshapes[id+'-0'];
1896        }
1897        this.openBubble(m);
1898    },
1899
1900
1901    /**
1902     * Called when clicking anywhere on the map and closes the info window.
1903     */
1904    closeBubble : function() {
1905        if (this.infoWindow){
1906            this.infoWindow.close();
1907        }
1908    },
1909
1910
1911    /*
1912     *  KML color and opacity (alpha) values are expressed in hexadecimal notation. The range of values for any one color is 0 to 255 (00 to ff).
1913     *  For alpha, 00 is fully transparent and ff is fully opaque.
1914     *  The order of expression is aabbggrr, where aa=alpha (00 to ff); bb=blue (00 to ff); gg=green (00 to ff); rr=red (00 to ff).
1915     *
1916     *  For example, if you want to apply a blue color with 50 percent opacity to an overlay,
1917     *  you would specify the following: <color>7fff0000</color>, where alpha=0x7f, blue=0xff, green=0x00, and red=0x00.
1918     */
1919    getRGBColorTransparency: function (kmlColor) {
1920        var color = {};
1921        if (kmlColor) {
1922            aa = kmlColor.substr(0,2);
1923            bb = kmlColor.substr(2,2);
1924            gg = kmlColor.substr(4,2);
1925            rr = kmlColor.substr(6,2);
1926            color.color = "#" + rr + gg + bb;
1927            color.opacity = parseFloat(parseInt(aa,16)/256).toFixed(1);
1928        }
1929        if (isNaN(color.opacity)){
1930            color.color = this.getStrokeColor();
1931            color.opacity = 1.0;
1932        }
1933        return color;
1934    },
1935    /*
1936     * getStrokeColor
1937     */
1938    getStrokeColor : function(){
1939        // Forzatura per CoopCulture
1940        return '#'+this.highlightColor;
1941        //return  '#' + Math.round(0xffffff * Math.random()).toString(16);
1942    }
1943};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.