Changes between Initial Version and Version 1 of HowToCustomizeSelectionPanel


Ignore:
Timestamp:
Jun 11, 2008, 12:44:00 PM (16 years ago)
Author:
aboudreault
Comment:

to be continued...

Legend:

Unmodified
Added
Removed
Modified
  • HowToCustomizeSelectionPanel

    v1 v1  
     1[[PageOutline]]
     2= How To Customize !SelectionPanel widget =
     3
     4== Introduction ==
     5
     6This !HowTo describe how customize the !SelectionPanel widget for display the results the way you want. In this !HowTo,  we'll see what are the two possible methods to customize this widget and make a example for each. For customize the !SelectionPanel, you'll need to know the Selection API for get layers, features and values. (You can check [http://trac.osgeo.org/fusion/wiki/MapGuideTutorial#WorkingwithSelections here] to get more information on the current Selection API).
     7
     8== First method: customize by defining a function ==
     9
     10The simpliest one. This allow you to create a javascript function that will receive the '''Selection object''' in parameter. In this function, You'll use the ''Selection API'' for handle the features and do whatever you want with them.
     11
     12
     13'''Example'''
     14
     15 1. Create the javascript function implementation
     16{{{
     17function displaySelection(oSelection)
     18{
     19    //TODO: this just gets the first map, we need them all
     20    selection = null;
     21    for (var mapName in oSelection) {
     22        selection = oSelection[mapName];
     23        break;
     24    }
     25    if (selection && selection.getNumElements) {
     26        //obtain a reference to the HTML Element that the results
     27        //will be placed in
     28        var resultElm = $('divResults');
     29        resultElm.innerHTML = '';
     30        for (var i=0; i<selection.getNumLayers(); i++) {
     31            var selectionLayer = selection.getLayer(i);
     32            var propNames = selectionLayer.getPropertyNames();
     33            var span = document.createElement('span');
     34            span.className = 'selectionResultsTitle';
     35            span.innerHTML = 'Layer ' + selectionLayer.getName();
     36            resultElm.appendChild(span);
     37            var table = document.createElement('table');
     38            table.className = 'selectionResultsTable';
     39            resultElm.appendChild(table);
     40            //set up the table header to be the property names         
     41            var thead = document.createElement('thead');
     42            table.appendChild(thead);
     43            var tr = document.createElement('tr');
     44            thead.appendChild(tr);
     45            for (var j=0; j<propNames.length; j++) {
     46                var td = document.createElement('td');
     47                td.innerHTML = propNames[j];
     48                tr.appendChild(td);
     49            }
     50            //output the selection values
     51            var tbody = document.createElement('tbody');
     52            table.appendChild(tbody);
     53            for (var j=0; j<selectionLayer.getNumElements(); j++) {
     54                var tr = document.createElement('tr');
     55                tbody.appendChild(tr);
     56                for (var k=0; k<propNames.length; k++) {
     57                    var td = document.createElement('td');
     58                    td.innerHTML = selectionLayer.getElementValue(j, k);
     59                    tr.appendChild(td);
     60                }
     61            }
     62        }
     63    }
     64}
     65}}}
     66
     67
     68This function will produce a html table with one feature per row.
     69
     70 2. Configuration needs in the ApplicationDefinition.xml
     71 You'll need to modify the !SelectionPanel widget tag for enable the customization. By adding the ''!SelectionRenderer'' tag in the Extension section, you're telling to the !SelectionPanel to use your function instead of the default one. The widget tab should now look like:
     72{{{
     73<Widget xsi:type="WidgetType">
     74  <Name>divList</Name>
     75  <Type>SelectionPanel</Type>
     76  <StatusItem/>
     77  <Extension xsi:type="CustomContentType">
     78    <SelectionRenderer>displaySelection</SelectionRenderer>
     79  </Extension>
     80</Widget>
     81}}}
     82
     83== Second method: customize by creating a renderer class ==
     84
     85This method let you define a special behavior for the !SelectionPanel. It can be a little bit more complicated than the first one but it can be very useful for those who have to make a complex behavior. It also keep a structured application using the ''Object Oriented programming''. This method is also the best if you want to support '''pagination''' (displaying results by batches) in your results panel.
     86
     87Basicly, creating a renderer class is not very complicated. You'll have to create a class that inherit from the '''Fusion.Widget.!SelectionPanel.!SelectionRenderer''' and implement these three functions: ''initialize'', ''updateSelection'' and ''clearSelection''. The first function is for initialize the base class and initialize all specific properties of your renderer (creating div, button, image, adding CSS, etc.). The second will be binded to the Fusion.Event.MAP_SELECTION_ON event, and the third to Fusion.Event.MAP_SELECTION_OFF.
     88
     89'''Example 1: simple renderer'''
     90{{{
     91Fusion.Widget.SelectionPanel.SimpleRenderer = OpenLayers.Class(Fusion.Widget.SelectionPanel.SelectionRenderer,
     92{
     93    initialize : function(selectionPanel) {
     94        // This must always be called to initialize the base class.
     95        Fusion.Widget.SelectionPanel.SelectionRenderer.prototype.initialize.apply(this, [selectionPanel]);
     96    },
     97
     98    updateSelection: function() {
     99        this.getMap().getSelection(
     100            OpenLayers.Function.bind(this.renderSelection, this));
     101    },
     102
     103    clearSelection: function() {
     104        // do clear stuff...
     105        this.oSelection = null;
     106    },
     107   
     108    renderSelection: function(oSelection) {
     109        //TODO: this just gets the first map, we need them all
     110        selection = null;
     111        for (var mapName in oSelection) {
     112            selection = oSelection[mapName];
     113            break;
     114        }
     115        if (selection && selection.getNumElements) {
     116            //obtain a reference to the HTML Element that the results
     117            //will be placed in
     118            var resultElm = this.oSelectionPanel.domObj;
     119            resultElm.innerHTML = '';
     120            for (var i=0; i<selection.getNumLayers(); i++) {
     121                var selectionLayer = selection.getLayer(i);
     122                var propNames = selectionLayer.getPropertyNames();
     123                var span = document.createElement('span');
     124                span.className = 'selectionResultsTitle';
     125                span.innerHTML = 'Layer ' + selectionLayer.getName();
     126                resultElm.appendChild(span);
     127                var table = document.createElement('table');
     128                table.className = 'selectionResultsTable';
     129                resultElm.appendChild(table);
     130                //set up the table header to be the property names         
     131                var thead = document.createElement('thead');
     132                table.appendChild(thead);
     133                var tr = document.createElement('tr');
     134                thead.appendChild(tr);
     135                for (var j=0; j<propNames.length; j++) {
     136                    var td = document.createElement('td');
     137                    td.innerHTML = propNames[j];
     138                    tr.appendChild(td);
     139                }   
     140                //output the selection values
     141                var tbody = document.createElement('tbody');
     142                table.appendChild(tbody);
     143                for (var j=0; j<selectionLayer.getNumElements(); j++) {
     144                    var tr = document.createElement('tr');
     145                    tbody.appendChild(tr);
     146                    for (var k=0; k<propNames.length; k++) {
     147                        var td = document.createElement('td');
     148                                            td.innerHTML = selectionLayer.getElementValue(j, k);
     149                        tr.appendChild(td);
     150                    }
     151                }
     152            }
     153        }
     154    }   
     155});
     156}}}
     157
     158And the widget tag in the ApplicationDefinition.xml
     159{{{
     160<Widget xsi:type="WidgetType">
     161  <Name>divResults</Name>
     162  <Type>SelectionPanel</Type>
     163  <StatusItem/>
     164  <Extension xsi:type="CustomContentType">
     165     <SelectionRenderer>Fusion.Widget.SelectionPanel.SimpleRenderer</SelectionRenderer>
     166  </Extension>
     167</Widget>
     168}}}
     169
     170This is a very simple renderer created with the function we'd use in the first method.I just bind the renderSelection function to handle results and display them. It's exactly the same thing that use the first method. In this simple case, you should use the first method instead than create a class.
     171
     172'''Example 2: complex renderer'''
     173{{{
     174Fusion.Widget.SelectionPanel.SelectionRendererHorizontal = OpenLayers.Class(Fusion.Widget.SelectionPanel.SelectionRenderer,
     175{
     176    initialize : function(selectionPanel) {
     177        Fusion.Widget.SelectionPanel.SelectionRenderer.prototype.initialize.apply(this, [selectionPanel]);
     178   
     179        var d = document.createElement('div');
     180        this.featureDiv = document.createElement('div');
     181        this.featureDiv.innerHTML = 'No Selection';
     182        Element.addClassName(this.featureDiv, 'noSelection');
     183        d.appendChild(this.featureDiv);
     184
     185        if (this.iResultsPerPage != 0) {
     186            this.previousButton = document.createElement('img');
     187            this.previousButton.src = this.oSelectionPanel.previousIcon;
     188            this.previousButton.style.position = "absolute";
     189            this.previousButton.style.left = "0px";
     190            this.previousButton.style.padding = "3px";
     191            Event.observe(this.previousButton, 'click',
     192                          OpenLayers.Function.bind(this.renderLayers, this, 'prev'));
     193            this.nextButton = document.createElement('img');
     194            this.nextButton.src = this.oSelectionPanel.nextIcon;
     195            this.nextButton.style.position = "absolute";
     196            this.nextButton.style.right = "0px";
     197            this.nextButton.style.padding = "3px";
     198            Event.observe(this.nextButton, 'click',
     199                          OpenLayers.Function.bind(this.renderLayers, this, 'next'));
     200           
     201            d.appendChild(this.previousButton);
     202            d.appendChild(this.nextButton);
     203        }
     204
     205        Element.addClassName(this.featureDiv, 'selectionPanelContent');
     206        Fusion.addWidgetStyleSheet(this.oSelectionPanel.getLocation() + 'SelectionPanel/SelectionPanel.css');
     207        this.oSelectionPanel.domObj.appendChild(d);
     208    },
     209
     210    updateSelection: function() {
     211        this.getMap().getSelection(
     212            OpenLayers.Function.bind(this.renderSelection, this));
     213    },
     214
     215    clearSelection: function() {
     216        this.oSelection = null;
     217        Element.addClassName(this.featureDiv, 'noSelection');
     218        this.featureDiv.innerHTML = OpenLayers.i18n('noSelection');
     219    },
     220   
     221    renderSelection: function(oSelection) {
     222        //TODO: this just gets the first map, we need them all
     223        this.oSelection = null;
     224        for (var mapName in oSelection) {
     225            this.oSelection = oSelection[mapName];
     226            break;
     227        }
     228        this.resetPageIndexes();
     229        this.renderLayers("next");
     230    },
     231   
     232    renderLayers: function(renderingPage) {
     233        if (!this.oSelection) {
     234            return;
     235        }
     236       
     237        Element.removeClassName(this.featureDiv, 'noSelection');
     238        this.featureDiv.innerHTML = '';
     239       
     240        var nLayers = this.oSelection.getNumLayers();
     241        for (var i=0; i<nLayers; i++) {
     242            var table = document.createElement('table');
     243            table.style.borderLeft = "1px solid #CCCCCC";
     244            table.style.marginBottom = "10px";
     245            var layerObj = this.oSelection.getLayer(i);
     246            var aNames = layerObj.getPropertyNames();
     247            //find the legend label from the Map layer objects
     248            var mapLayers = this.getMap().aMaps[0].aLayers; //TODO: allow multiple maps
     249            var labelName = layerObj.getName();
     250            for (var j=0; j<mapLayers.length; ++j) {
     251                if (mapLayers[j].layerName == labelName) {
     252                    labelName = mapLayers[j].legendLabel;
     253                    break;
     254                }
     255            }
     256           
     257            var thead = document.createElement('thead');
     258            var tr = document.createElement('tr');
     259            var th = document.createElement('th');
     260            th.innerHTML = labelName;
     261            th.colSpan=aNames.length;
     262            th.style.textAlign = "center";
     263            tr.appendChild(th);
     264            thead.appendChild(tr);
     265            tr = document.createElement('tr');
     266            for (var j=0; j<aNames.length; j++) {
     267                th = document.createElement('th');
     268                th.innerHTML = aNames[j];
     269                th.style.textAlign = "center";
     270                tr.appendChild(th);
     271            }
     272            thead.appendChild(tr);
     273            table.appendChild(thead);
     274            var tbody = document.createElement('tbody');
     275            var page = (renderingPage == 'next') ? this.getNextPage(layerObj): this.getPreviousPage(layerObj);
     276            this.renderFeatures(page,tbody);
     277            table.appendChild(tbody);
     278            this.featureDiv.appendChild(table);
     279        }
     280
     281    },
     282
     283    renderFeatures: function(page, dom) {
     284        if (!page)
     285            return;
     286
     287        for (var i=0; i<page.length; i++) {
     288            var tr = document.createElement('tr');
     289            if (i%2) {
     290                Element.addClassName(tr, 'oddRow');
     291            }
     292            for (var j=0; j<page[i].length; j++) {
     293                var td = document.createElement('td');
     294                td.innerHTML = page[i][j];
     295                tr.appendChild(td);
     296            }
     297            dom.appendChild(tr);           
     298        }
     299    }
     300});
     301}}}
     302
     303And the widget tag in the ApplicationDefinition.xml
     304{{{
     305<Widget xsi:type="WidgetType">
     306  <Name>divResults</Name>
     307  <Type>SelectionPanel</Type>
     308  <StatusItem/>
     309  <Extension xsi:type="CustomContentType">
     310    <NextImageUrl>images/icon_next.png</NextImageUrl>
     311    <PreviousImageUrl>images/icon_previous.png</PreviousImageUrl>
     312    <ResultsPerPage>10</ResultsPerPage>
     313    <SelectionRenderer>Fusion.Widget.SelectionPanel.SelectionRendererHorizontal</SelectionRenderer>
     314  </Extension>
     315</Widget>
     316}}}
     317
     318As you can see, this example is more complex. I use the initialize method for initialize my html element, add some css style and bind some event to the appropriate function of this class. I also add a previous/next button for navigate page to page because this renderer support the ''pagination''. So, i've set the !ResultsPerPage to 10 in the ApplicationDefinition.xml and all my pages will not exceed this limit.
     319
     320== Pagination ==
     321
     322ah HA! i'll continue this later!