1 /* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
2 * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
3 * full text of the license. */
6 * @requires OpenLayers/Control.js
7 * @requires OpenLayers/Control/Button.js
11 * Class: OpenLayers.Control.NavigationHistory
12 * A navigation history control. This is a meta-control, that creates two
13 * dependent controls: <previous> and <next>. Call the trigger method
14 * on the <previous> and <next> controls to restore previous and next
15 * history states. The previous and next controls will become active
16 * when there are available states to restore and will become deactive
17 * when there are no states to restore.
20 * - <OpenLayers.Control>
22 OpenLayers.Control.NavigationHistory = OpenLayers.Class(OpenLayers.Control, {
26 * {String} Note that this control is not intended to be added directly
27 * to a control panel. Instead, add the sub-controls previous and
28 * next. These sub-controls are button type controls that activate
29 * and deactivate themselves. If this parent control is added to
30 * a panel, it will act as a toggle.
32 type: OpenLayers.Control.TYPE_TOGGLE,
35 * APIProperty: previous
36 * {<OpenLayers.Control>} A button type control whose trigger method restores
37 * the previous state managed by this control.
42 * APIProperty: previousOptions
43 * {Object} Set this property on the options argument of the constructor
44 * to set optional properties on the <previous> control.
46 previousOptions: null,
50 * {<OpenLayers.Control>} A button type control whose trigger method restores
51 * the next state managed by this control.
56 * APIProperty: nextOptions
57 * {Object} Set this property on the options argument of the constructor
58 * to set optional properties on the <next> control.
64 * {Integer} Optional limit on the number of history items to retain. If
65 * null, there is no limit. Default is 50.
70 * Property: activateOnDraw
71 * {Boolean} Activate the control when it is first added to the map.
77 * Property: clearOnDeactivate
78 * {Boolean} Clear the history when the control is deactivated. Default
81 clearOnDeactivate: false,
85 * {Object} An object with keys corresponding to event types. Values
86 * are functions that return an object representing the current state.
92 * {Array} Array of items in the history.
97 * Property: previousStack
98 * {Array} List of items in the history. First item represents the current
104 * Property: listeners
105 * {Object} An object containing properties corresponding to event types.
106 * This object is used to configure the control and is modified on
112 * Property: restoring
113 * {Boolean} Currently restoring a history state. This is set to true
114 * before calling restore and set to false after restore returns.
119 * Constructor: OpenLayers.Control.NavigationHistory
122 * options - {Object} An optional object whose properties will be used
123 * to extend the control.
125 initialize: function(options) {
126 OpenLayers.Control.prototype.initialize.apply(this, [options]);
128 this.registry = OpenLayers.Util.extend({
129 "moveend": function() {
131 center: this.map.getCenter(),
132 resolution: this.map.getResolution()
139 var previousOptions = {
140 trigger: OpenLayers.Function.bind(this.previousTrigger, this),
141 displayClass: this.displayClass + " " + this.displayClass + "Previous"
143 OpenLayers.Util.extend(previousOptions, this.previousOptions);
144 this.previous = new OpenLayers.Control.Button(previousOptions);
147 trigger: OpenLayers.Function.bind(this.nextTrigger, this),
148 displayClass: this.displayClass + " " + this.displayClass + "Next"
150 OpenLayers.Util.extend(nextOptions, this.nextOptions);
151 this.next = new OpenLayers.Control.Button(nextOptions);
156 * Method: onPreviousChange
157 * Called when the previous history stack changes.
160 * state - {Object} An object representing the state to be restored
161 * if previous is triggered again or null if no previous states remain.
162 * length - {Integer} The number of remaining previous states that can
165 onPreviousChange: function(state, length) {
166 if(state && !this.previous.active) {
167 this.previous.activate();
168 } else if(!state && this.previous.active) {
169 this.previous.deactivate();
174 * Method: onNextChange
175 * Called when the next history stack changes.
178 * state - {Object} An object representing the state to be restored
179 * if next is triggered again or null if no next states remain.
180 * length - {Integer} The number of remaining next states that can
183 onNextChange: function(state, length) {
184 if(state && !this.next.active) {
185 this.next.activate();
186 } else if(!state && this.next.active) {
187 this.next.deactivate();
193 * Destroy the control.
195 destroy: function() {
196 OpenLayers.Control.prototype.destroy.apply(this);
197 this.previous.destroy();
200 for(var prop in this) {
207 * Set the map property for the control and <previous> and <next> child
211 * map - {<OpenLayers.Map>}
213 setMap: function(map) {
215 this.next.setMap(map);
216 this.previous.setMap(map);
221 * Called when the control is added to the map.
224 OpenLayers.Control.prototype.draw.apply(this, arguments);
226 this.previous.draw();
227 if(this.activateOnDraw) {
233 * Method: previousTrigger
234 * Restore the previous state. If no items are in the previous history
235 * stack, this has no effect.
238 * {Object} Item representing state that was restored. Undefined if no
239 * items are in the previous history stack.
241 previousTrigger: function() {
242 var current = this.previousStack.shift();
243 var state = this.previousStack.shift();
244 if(state != undefined) {
245 this.nextStack.unshift(current);
246 this.previousStack.unshift(state);
247 this.restoring = true;
249 this.restoring = false;
250 this.onNextChange(this.nextStack[0], this.nextStack.length);
251 this.onPreviousChange(
252 this.previousStack[1], this.previousStack.length - 1
255 this.previousStack.unshift(current);
261 * APIMethod: nextTrigger
262 * Restore the next state. If no items are in the next history
263 * stack, this has no effect. The next history stack is populated
264 * as states are restored from the previous history stack.
267 * {Object} Item representing state that was restored. Undefined if no
268 * items are in the next history stack.
270 nextTrigger: function() {
271 var state = this.nextStack.shift();
272 if(state != undefined) {
273 this.previousStack.unshift(state);
274 this.restoring = true;
276 this.restoring = false;
277 this.onNextChange(this.nextStack[0], this.nextStack.length);
278 this.onPreviousChange(
279 this.previousStack[1], this.previousStack.length - 1
290 this.previousStack = [];
296 * Update the state with the given object.
299 * state - {Object} An object representing the state to restore.
301 restore: function(state) {
302 var zoom = this.map.getZoomForResolution(state.resolution);
303 this.map.setCenter(state.center, zoom);
307 * Method: setListeners
308 * Sets functions to be registered in the listeners object.
310 setListeners: function() {
312 for(var type in this.registry) {
313 this.listeners[type] = OpenLayers.Function.bind(function() {
314 if(!this.restoring) {
315 var state = this.registry[type].apply(this, arguments);
316 this.previousStack.unshift(state);
317 if(this.previousStack.length > 1) {
318 this.onPreviousChange(
319 this.previousStack[1], this.previousStack.length - 1
322 if(this.previousStack.length > (this.limit + 1)) {
323 this.previousStack.pop();
325 if(this.nextStack.length > 0) {
327 this.onNextChange(null, 0);
336 * APIMethod: activate
337 * Activate the control. This registers any listeners.
340 * {Boolean} Control successfully activated.
342 activate: function() {
343 var activated = false;
345 if(OpenLayers.Control.prototype.activate.apply(this)) {
346 if(this.listeners == null) {
349 for(var type in this.listeners) {
350 this.map.events.register(type, this, this.listeners[type]);
353 if(this.previousStack.length == 0) {
363 * Called after the control is activated if the previous history stack is
366 initStack: function() {
367 if(this.map.getCenter()) {
368 this.listeners.moveend();
373 * APIMethod: deactivate
374 * Deactivate the control. This unregisters any listeners.
377 * {Boolean} Control successfully deactivated.
379 deactivate: function() {
380 var deactivated = false;
382 if(OpenLayers.Control.prototype.deactivate.apply(this)) {
383 for(var type in this.listeners) {
384 this.map.events.unregister(
385 type, this, this.listeners[type]
388 if(this.clearOnDeactivate) {
397 CLASS_NAME: "OpenLayers.Control.NavigationHistory"