~jstys-z/helioviewer.org/client5

« back to all changes in this revision

Viewing changes to lib/helioviewer/LEGACY/LayerManagerMenuEntry.js

  • Committer: V. Keith Hughitt
  • Date: 2009-04-01 21:08:05 UTC
  • Revision ID: hughitt1@kore-20090401210805-372f7dgih07vxk42
nightly build 04-01-2009

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*global Class, $, Option, document, $A, Event, Ajax, Element, Builder, Debug, UIElement */
 
2
var LayerManagerMenuEntry = Class.create(UIElement, {
 
3
    /**
 
4
     * @constructor
 
5
     */
 
6
    initialize: function (layermanager, layer) {
 
7
        this.className = "layerManagerMenuEntry";
 
8
        this.layermanager = layermanager;
 
9
        this.layer = layer;
 
10
        this.domNode = Builder.node('li', {className: 'accordionItem'});
 
11
        
 
12
        // If layer is not set, create an empty "template" layer
 
13
        if (layer.type === "NewLayer") {
 
14
            this.displayNewLayerOptions();
 
15
        }
 
16
        else if (layer.type === "TileLayer") {
 
17
            this.displayTileLayerOptions();
 
18
        }
 
19
 
 
20
        this.layermanager.accordionList.appendChild(this.domNode); //Cannot use prototype's insert() method to insert on top. Does not work in IE.
 
21
        
 
22
        //Add tooltips (has to occur after dom-node has been appended)
 
23
        if (layer.type === "TileLayer") {
 
24
            this.layermanager.fire('newToolTip', {id: "#" + this.removeBtn.id, params: {position: 'topleft'}});
 
25
            this.layermanager.fire('newToolTip', {id: "#" + this.visibilityBtn.id, params: {position: 'topleft'}});
 
26
        }
 
27
 
 
28
    },
 
29
    
 
30
    /**
 
31
     * @method displayTileLayerOptions
 
32
     */
 
33
    displayTileLayerOptions: function () {
 
34
        if (!this.header) {
 
35
            this.header =  this.domNode.appendChild(this.createMenuRowHeader(this.layer));
 
36
            this.content = this.domNode.appendChild(this.createMenuRowContent(this.layer));
 
37
        }
 
38
        else {
 
39
            this.header.replace(this.createMenuRowHeader(this.layer));
 
40
                this.content.replace(this.createMenuRowContent(this.layer));
 
41
        }
 
42
        this.setupEventHandlers();
 
43
 
 
44
        // Check to see if observation time matches the desired time
 
45
        this.updateTimeStamp(this.layer);
 
46
    },
 
47
    
 
48
   /**
 
49
    * @method displayNewLayerOptions
 
50
    */
 
51
    displayNewLayerOptions: function () {
 
52
        this.header =  Builder.node('div', {className: 'layer-Head'}, "New Layer");
 
53
        this.content = Builder.node('div');
 
54
        this.domNode.appendChild(this.header);
 
55
        this.domNode.appendChild(this.content); 
 
56
        
 
57
        var xhr  = null;
 
58
        var self = this;
 
59
        var dn = self.layermanager.controller.dataNavigator;
 
60
        
 
61
        // query list of available instruments if it is not already available
 
62
        if (!dn.data.get('Instruments')) {
 
63
            dn.query('Instruments');
 
64
        }
 
65
        
 
66
        
 
67
        // create select form-field for instrument choices
 
68
        xhr = new Ajax.Updater(this.content, 'getInstruments.php', {
 
69
            parameters: {
 
70
                type: 'html'
 
71
            },
 
72
            method: 'get',
 
73
            insertion: 'bottom',
 
74
            onComplete: function () {
 
75
                var selectField = self.content.select('.instrument-select').first();
 
76
                
 
77
                var onInstChange = function (e) {
 
78
                    //Debug.output(e.target.value + " chosen!");
 
79
                    // Get info for chosen instrument
 
80
                    var chosenInstrument = null;
 
81
                    for (var i = 0; i < dn.data.get('Instruments').length; i++) {
 
82
                        if (dn.data.get('Instruments')[i].instrument === e.target.value) {
 
83
                            chosenInstrument = dn.data.get('Instruments')[i];
 
84
                        }
 
85
                    }
 
86
                    self.layermanager.fire('newLayer', {menuEntry: self, instrument: chosenInstrument});
 
87
                };
 
88
                Event.observe(selectField, 'change', onInstChange.bind(self));
 
89
            }
 
90
        });
 
91
    },
 
92
    
 
93
    setupEventHandlers: function () {
 
94
        // Function for toggling layer visibility
 
95
        var toggleVisibility = function (e) {
 
96
            var visible = this.layer.toggleVisible();
 
97
            var icon = (visible ? 'LayerManagerButton_Visibility_Visible.png' : 'LayerManagerButton_Visibility_Hidden.png');
 
98
            this.visibilityBtn.setStyle({ background: 'url(images/blackGlass/' + icon + ')' });
 
99
            Event.stop(e);
 
100
        };
 
101
              
 
102
        // Function for handling layer remove button
 
103
        var removeLayer = function (e) {
 
104
            this.layermanager.remove(this, this.layer);
 
105
            Element.remove(this.domNode);
 
106
            Event.stop(e);
 
107
            this.layermanager.render();
 
108
        };
 
109
  
 
110
        // Event-handlers
 
111
        Event.observe(this.visibilityBtn, 'click', toggleVisibility.bindAsEventListener(this));          
 
112
        Event.observe(this.removeBtn, 'click', removeLayer.bindAsEventListener(this));          
 
113
        
 
114
        //NOTE 08-26-2008: Adding new event listener for updating timestamp
 
115
        this.layer.addObserver('obs_time_change', this.onLayerChange.bind(this));
 
116
        //this.layer.addObserver('change', this.onLayerChange.bind(this));        
 
117
    },
 
118
    
 
119
   /**
 
120
    * @method createMenuRowHeader Creates the header for a header/content pair to be used
 
121
    * within a jQuery accordion. The header describes the layer's associated instrument, the
 
122
    * timestamp of the current image displayed, and icons for removing the layer and toggling
 
123
    * it's visibility.
 
124
    * 
 
125
    * @param  {Layer}  layer  The tile layer
 
126
    * @return {Dom-node} Returns a <div> element with all of the necessary components.
 
127
    */
 
128
    createMenuRowHeader: function (layer) {
 
129
        var header =     Builder.node('div',  {className: 'layer-Head'});
 
130
        var instrument = Builder.node('span', {id: 'layer-header-' + layer.id, style: 'float: left; width: 33%;'}, layer.instrument + (layer.instrument === layer.detector ? "" : "/" + layer.detector.trimLeft('0')) + " " + layer.measurement.trimLeft('0'));
 
131
      
 
132
        //header.appendChild(instrument);
 
133
 
 
134
        // Timestampdev/ie_floats/
 
135
        var timestamp = Builder.node('span', {className: 'timestamp'});
 
136
 
 
137
        // Visibility Toggle
 
138
        this.visibilityBtn = Builder.node('button', {
 
139
            id: 'visibility-button-' + layer.id,
 
140
            className: 'layerManagerBtn visible',
 
141
            value: true,
 
142
            type: 'button',
 
143
            title: ' - Toggle ' + layer.instrument + ' layer visibility.'
 
144
        });
 
145
 
 
146
        // Layer Removal Button
 
147
        this.removeBtn = Builder.node('button', {
 
148
            id: 'remove-button-' + layer.id,
 
149
            className: 'layerManagerBtn remove', 
 
150
            value: true, 
 
151
            type: 'button',
 
152
            title: ' - Remove layer.'
 
153
        });
 
154
 
 
155
        // Container for right-aligned elements
 
156
        var rightSide = Builder.node('div', {style: 'text-align: right; float: left; width:67%;'}, [timestamp, " |", this.visibilityBtn, this.removeBtn]);
 
157
      
 
158
            // combine left and right containers
 
159
            var both = Builder.node('div', {style: 'overflow: hidden;' }, [instrument, rightSide]);
 
160
            header.appendChild(both);
 
161
            
 
162
        // header.appendChild(rightSide);
 
163
        return header;   
 
164
    },
 
165
     
 
166
    /*
 
167
     * @method createMenuRowContent
 
168
     * @param {Layer} layer The tile layer.
 
169
     * @return {Dom-node} The layer row content
 
170
     */
 
171
    createMenuRowContent: function (layer) {
 
172
        //Wrapper
 
173
        var body = Builder.node('div', {style: 'color: white;'});
 
174
        
 
175
        //Instrument
 
176
        var instLeft =  Builder.node('div', {style: 'float: left;  width: 40%;'}, 'Instrument: ');
 
177
        var instRight = Builder.node('div', {style: 'float: right; width: 60%;'},  this.createInstrumentControl(layer));
 
178
        body.appendChild(Builder.node('div', {style: 'height: 24px; padding: 4px;', id: 'instrument-row-' + layer.id}, [instLeft, instRight]));
 
179
        
 
180
        //Measurement
 
181
        /*
 
182
        if (layer.measurements.length > 1) {
 
183
                        var left =  Builder.node('div', {style: 'float: left;  width: 40%;'}, 'Measurement: ');
 
184
                //var right = Builder.node('div', {style: 'float: right; width: 60%;'},  this.createWavelengthControl(layer));
 
185
                //body.appendChild(Builder.node('div', {style: 'height: 24px; padding: 4px;', id: 'measurement-row-' + layer.id}, [left, right]));
 
186
        }*/
 
187
        
 
188
        //get available measurements for chosen instrument
 
189
        
 
190
        //var callBack = this.listMeasurements.bind(this);
 
191
        //var xhr = new Ajax.Request('getMeasurements.php', {
 
192
        //    onSuccess: callBack,
 
193
        //    parameters: {
 
194
        //        detector: layer.detector
 
195
        //    }
 
196
        //});
 
197
        /*this.measurementSelect = body.appendChild(Builder.node('div', {style: 'float: left;  width: 100%;'}, " "));*/
 
198
        
 
199
        //Opacity
 
200
        //var opacityLeft = Builder.node('div', {style: 'float: left;  width: 40%;'}, 'Opacity: ');
 
201
        //var opacityRight = Builder.node('div', {style: 'float: right; width: 60%;'},  [this.createOpacityControl(layer.id), "%"]);
 
202
        //body.appendChild(Builder.node('div', {style: 'height: 24px; padding: 4px;', id: 'opacity-row-' + layer.id}, [opacityLeft, opacityRight]));
 
203
        
 
204
        return body;
 
205
    },
 
206
    
 
207
    listMeasurements: function (transport) {
 
208
        var response = transport.responseJSON;
 
209
        this.layer.measurementType = response[0].type;
 
210
        
 
211
        this.layer.measurements = $A(response).collect(function (row) {
 
212
            return parseInt(row.measurement, 10);
 
213
        });
 
214
        
 
215
        /*this.measurementSelect.update(this.layer.measurementType + ":");*/
 
216
        
 
217
    },
 
218
    
 
219
    /**
 
220
     * @method createInstrumentControl
 
221
     */
 
222
    createInstrumentControl: function (layer) {
 
223
        var inst = new Element('select', {id: 'instrument-select-' + layer.id, style: 'display: none'});
 
224
        inst.length = 0;
 
225
 
 
226
        //Available Instruments
 
227
        //ToDo: Read availables from maps table, joined on instruments table for names
 
228
        var instruments = $A(["EIT", "LASCO"]);
 
229
                
 
230
        // Populate list of available instruments
 
231
        for (var i = 0; i < instruments.length; i++) {
 
232
            var opt = new Option(instruments[i]);
 
233
            opt.value = instruments[i];
 
234
            inst.options[inst.options.length] = opt;
 
235
        }
 
236
        
 
237
        // Set-up event handler to deal with an instrument change
 
238
        Event.observe(inst, 'change', this.onInstrumentChange.curry(layer.id));
 
239
        
 
240
        // Show only text until user clicks on the form item
 
241
        //var instText = Builder.node('span', {id: 'instrument-text-' + layer.id}, inst.value);
 
242
        var instText = Builder.node('span', {id: 'instrument-text-' + layer.id}, layer.instrument);
 
243
        
 
244
        /*
 
245
        Event.observe(instText, 'click', function (e) {
 
246
                $(e.target).hide();
 
247
                inst.show();
 
248
        });
 
249
        
 
250
        Event.observe(inst, 'blur', function (e) {
 
251
                $(e.target).hide();
 
252
                instText.show();
 
253
        }); */
 
254
        
 
255
        //return [inst, instText];
 
256
        return instText;
 
257
    },
 
258
    
 
259
    /**
 
260
     * @method onInstrumentChange
 
261
     * @param {Int} id
 
262
     */
 
263
    onInstrumentChange: function (id) {
 
264
        //Dom-nodes for layer components
 
265
        var header =         $('layer-header-' + id);
 
266
        var measurement =    $('wavelength-select-' + id);
 
267
        var measurementRow = $('measurement-row-' + id);
 
268
        var instText =       $('instrument-text-' + id);
 
269
        
 
270
        //Non-pretty solution... TODO: Create a function to handle parameter changes..
 
271
        if (this.value === "LASCO") {
 
272
            measurementRow.hide();
 
273
            header.update("LASCO");
 
274
        }
 
275
        else {
 
276
                header.update(this.value + " " + measurement.value);
 
277
                measurementRow.show();  
 
278
        }
 
279
 
 
280
        //Update text to be displayed while not active
 
281
        instText.update(this.value);
 
282
        
 
283
        document.instrumentChange.fire(id, this.value);
 
284
    },
 
285
    
 
286
    onLayerChange: function (layer) {
 
287
        // ToDo: update the other fields
 
288
        this.updateTimeStamp(layer);
 
289
    },
 
290
    
 
291
    /**
 
292
     * @method createWavelengthControl
 
293
     * @param  {Int} The layer's id.
 
294
     * @return {[Dom-node, Dom-node]} Returns a set of two dom-nodes to be inserted into the layer manager.
 
295
     */
 
296
    createWavelengthControl: function (layer) {
 
297
        var id = layer.id;
 
298
        var wl = new Element('select', {id: 'wavelength-select-' + id, style: 'display: none'});
 
299
        wl.length = 0;
 
300
 
 
301
                //Available wavelength choices for EIT
 
302
        var wavelengths = $A([171, 195, 284]);
 
303
                
 
304
        // Populate list of available wavelengths
 
305
        for (var i = 0; i < wavelengths.length; i++) {
 
306
            var opt = new Option(wavelengths[i]);
 
307
            opt.value = wavelengths[i];
 
308
            wl.options[wl.options.length] = opt;
 
309
        }
 
310
        
 
311
        // Set-up event handler to deal with an wavelength change
 
312
        Event.observe(wl, 'change', this.onWavelengthChange.curry(id));
 
313
        
 
314
        // Show only text until user clicks on the form item
 
315
        //var wlText = Builder.node('span', {id: 'wavelength-text-' + id}, wl.value);
 
316
        var wlText = Builder.node('span', {id: 'wavelength-text-' + id}, layer.measurement);
 
317
        Event.observe(wlText, 'click', function (e) {
 
318
                $(e.target).hide();
 
319
                wl.show();
 
320
        });
 
321
        
 
322
        // Revert to text display after form field loses focus
 
323
        Event.observe(wl, 'blur', function (e) {
 
324
                $(e.target).hide();
 
325
                wlText.show();
 
326
        });
 
327
        
 
328
        return [wl, wlText];
 
329
    },
 
330
    
 
331
    /**
 
332
     * Event handler: wavelength change
 
333
     */ 
 
334
    onWavelengthChange: function (id) {
 
335
        //Update header text
 
336
        var inst =   $('instrument-select-' + id);
 
337
        var header = $('layer-header-' + id);
 
338
        header.update(inst.value + " " + this.value);
 
339
        
 
340
        //Update text to be displayed while not active
 
341
        $('wavelength-text-' + id).update(this.value);
 
342
        
 
343
        document.wavelengthChange.fire(id, this.value);
 
344
    },
 
345
    
 
346
    /**
 
347
     * @method createOpacityControl Creates the opacity control cell.
 
348
     * @param  {layer}      The layer provider associated with the opacity control.
 
349
     * @return {HTML Element}       The opacity control cell.
 
350
     */
 
351
    createOpacityControl: function (id) {
 
352
        var opacity = 100;
 
353
        var opacityInput = new Element('input', {size: '3', value: opacity});
 
354
 
 
355
        Event.observe(opacityInput, 'change', function () {
 
356
            document.opacityChange.fire(id, parseInt(this.value, 10) / 100);
 
357
        });
 
358
                
 
359
        return opacityInput;
 
360
    },
 
361
    
 
362
    /**
 
363
     * @method createEnabledBox Creates the enabled/disabled cell.
 
364
     * @return {HTML Element}   The enabled/disabled cell.
 
365
     * @param  {Integer}        The layer's id
 
366
     */
 
367
    createEnabledBox: function (id) {
 
368
        var enabledTd = new Element('td', {style: "padding-left:15px;"});
 
369
        var enabled =   new Element('input', {type: 'checkbox', checked: 'true', name: 'enabled'});
 
370
        enabledTd.appendChild(enabled);
 
371
        
 
372
        Event.observe(enabled, 'click', this.onEnabledBoxClick.bind(this, id));
 
373
        return enabledTd;
 
374
    },
 
375
    
 
376
    /**
 
377
     * @method updateTimeStamp
 
378
     * @param {SunImage}
 
379
     * @param {Int}
 
380
     */
 
381
    updateTimeStamp: function () {
 
382
        //var id = this.layer.id; 
 
383
        if (this.layer.timestamp === undefined) {
 
384
                return;
 
385
        }
 
386
        
 
387
        //remove any pre-existing styling
 
388
        $(this.domNode).select(".timestamp").first().removeClassName("timeBehind");
 
389
        $(this.domNode).select(".timestamp").first().removeClassName("timeAhead");
 
390
        $(this.domNode).select(".timestamp").first().removeClassName("timeSignificantlyOff");
 
391
                
 
392
        // Update the timestamp
 
393
        var date = new Date(this.layer.timestamp * 1000);
 
394
        var dateString = date.toYmdUTCString() + ' ' + date.toHmUTCString();
 
395
 
 
396
        // Calc the time difference
 
397
        var timeDiff = this.layer.timestamp - this.layermanager.controller.date.getTime() / 1000;
 
398
        //var timeDiffAbs = Math.abs(timeDiff);
 
399
        //var tdHours = Math.floor(timeDiffAbs / 3600);
 
400
        //var tdMins = Math.floor((timeDiffAbs - tdHours * 3600) / 60);
 
401
        //var tdSecs = (timeDiffAbs - tdHours * 3600) - tdMins * 60;
 
402
        //var sign = (timeDiff === 0 ? '&plusmn;' : (timeDiff > 0 ? '+' : '&minus;'));
 
403
        //var timeDiffStr = sign + String(tdHours) + ':' + String(tdMins).padLeft(0, 2) + ':' + String(tdSecs).padLeft(0, 2);
 
404
 
 
405
        //this.domNode.select(".timestamp").first().update(dateString + ' ' + timeDiffStr);
 
406
        $(this.domNode).select(".timestamp").first().update(dateString);
 
407
        
 
408
        //get timestep (TODO: create a better accessor)
 
409
        var ts = this.layermanager.controller.timeStepSlider.timestep.numSecs;
 
410
        
 
411
        // Check to see if observation times match the actual time
 
412
        if (timeDiff < 0) {
 
413
                if (Math.abs(timeDiff) > (4 * ts)) {
 
414
                        $(this.domNode).select(".timestamp").first().addClassName("timeSignificantlyOff");
 
415
                }
 
416
                else {
 
417
                        $(this.domNode).select(".timestamp").first().addClassName("timeBehind");
 
418
                }
 
419
        }
 
420
        else if (timeDiff > 0) {
 
421
                if (timeDiff > (4 * ts)) {
 
422
                        $(this.domNode).select(".timestamp").first().addClassName("timeSignificantlyOff");
 
423
                }
 
424
                else {
 
425
                        $(this.domNode).select(".timestamp").first().addClassName("timeAhead");
 
426
                }
 
427
        }
 
428
    }
 
429
});
 
 
b'\\ No newline at end of file'