Panel.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
  2. * full list of contributors). Published under the 2-clause BSD license.
  3. * See license.txt in the OpenLayers distribution or repository for the
  4. * full text of the license. */
  5. /**
  6. * @requires OpenLayers/Control.js
  7. * @requires OpenLayers/Events/buttonclick.js
  8. */
  9. /**
  10. * Class: OpenLayers.Control.Panel
  11. * The Panel control is a container for other controls. With it toolbars
  12. * may be composed.
  13. *
  14. * Inherits from:
  15. * - <OpenLayers.Control>
  16. */
  17. OpenLayers.Control.Panel = OpenLayers.Class(OpenLayers.Control, {
  18. /**
  19. * Property: controls
  20. * {Array(<OpenLayers.Control>)}
  21. */
  22. controls: null,
  23. /**
  24. * APIProperty: autoActivate
  25. * {Boolean} Activate the control when it is added to a map. Default is
  26. * true.
  27. */
  28. autoActivate: true,
  29. /**
  30. * APIProperty: defaultControl
  31. * {<OpenLayers.Control>} The control which is activated when the control is
  32. * activated (turned on), which also happens at instantiation.
  33. * If <saveState> is true, <defaultControl> will be nullified after the
  34. * first activation of the panel.
  35. */
  36. defaultControl: null,
  37. /**
  38. * APIProperty: saveState
  39. * {Boolean} If set to true, the active state of this panel's controls will
  40. * be stored on panel deactivation, and restored on reactivation. Default
  41. * is false.
  42. */
  43. saveState: false,
  44. /**
  45. * APIProperty: allowDepress
  46. * {Boolean} If is true the <OpenLayers.Control.TYPE_TOOL> controls can
  47. * be deactivated by clicking the icon that represents them. Default
  48. * is false.
  49. */
  50. allowDepress: false,
  51. /**
  52. * Property: activeState
  53. * {Object} stores the active state of this panel's controls.
  54. */
  55. activeState: null,
  56. /**
  57. * Constructor: OpenLayers.Control.Panel
  58. * Create a new control panel.
  59. *
  60. * Each control in the panel is represented by an icon. When clicking
  61. * on an icon, the <activateControl> method is called.
  62. *
  63. * Specific properties for controls on a panel:
  64. * type - {Number} One of <OpenLayers.Control.TYPE_TOOL>,
  65. * <OpenLayers.Control.TYPE_TOGGLE>, <OpenLayers.Control.TYPE_BUTTON>.
  66. * If not provided, <OpenLayers.Control.TYPE_TOOL> is assumed.
  67. * title - {string} Text displayed when mouse is over the icon that
  68. * represents the control.
  69. *
  70. * The <OpenLayers.Control.type> of a control determines the behavior when
  71. * clicking its icon:
  72. * <OpenLayers.Control.TYPE_TOOL> - The control is activated and other
  73. * controls of this type in the same panel are deactivated. This is
  74. * the default type.
  75. * <OpenLayers.Control.TYPE_TOGGLE> - The active state of the control is
  76. * toggled.
  77. * <OpenLayers.Control.TYPE_BUTTON> - The
  78. * <OpenLayers.Control.Button.trigger> method of the control is called,
  79. * but its active state is not changed.
  80. *
  81. * If a control is <OpenLayers.Control.active>, it will be drawn with the
  82. * olControl[Name]ItemActive class, otherwise with the
  83. * olControl[Name]ItemInactive class.
  84. *
  85. * Parameters:
  86. * options - {Object} An optional object whose properties will be used
  87. * to extend the control.
  88. */
  89. initialize: function(options) {
  90. OpenLayers.Control.prototype.initialize.apply(this, [options]);
  91. this.controls = [];
  92. this.activeState = {};
  93. },
  94. /**
  95. * APIMethod: destroy
  96. */
  97. destroy: function() {
  98. if (this.map) {
  99. this.map.events.unregister("buttonclick", this, this.onButtonClick);
  100. }
  101. OpenLayers.Control.prototype.destroy.apply(this, arguments);
  102. for (var ctl, i = this.controls.length - 1; i >= 0; i--) {
  103. ctl = this.controls[i];
  104. if (ctl.events) {
  105. ctl.events.un({
  106. activate: this.iconOn,
  107. deactivate: this.iconOff
  108. });
  109. }
  110. ctl.panel_div = null;
  111. }
  112. this.activeState = null;
  113. },
  114. /**
  115. * APIMethod: activate
  116. */
  117. activate: function() {
  118. if (OpenLayers.Control.prototype.activate.apply(this, arguments)) {
  119. var control;
  120. for (var i=0, len=this.controls.length; i<len; i++) {
  121. control = this.controls[i];
  122. if (control === this.defaultControl ||
  123. (this.saveState && this.activeState[control.id])) {
  124. control.activate();
  125. }
  126. }
  127. if (this.saveState === true) {
  128. this.defaultControl = null;
  129. }
  130. this.redraw();
  131. return true;
  132. } else {
  133. return false;
  134. }
  135. },
  136. /**
  137. * APIMethod: deactivate
  138. */
  139. deactivate: function() {
  140. if (OpenLayers.Control.prototype.deactivate.apply(this, arguments)) {
  141. var control;
  142. for (var i=0, len=this.controls.length; i<len; i++) {
  143. control = this.controls[i];
  144. this.activeState[control.id] = control.deactivate();
  145. }
  146. this.redraw();
  147. return true;
  148. } else {
  149. return false;
  150. }
  151. },
  152. /**
  153. * Method: draw
  154. *
  155. * Returns:
  156. * {DOMElement}
  157. */
  158. draw: function() {
  159. OpenLayers.Control.prototype.draw.apply(this, arguments);
  160. if (this.outsideViewport) {
  161. this.events.attachToElement(this.div);
  162. this.events.register("buttonclick", this, this.onButtonClick);
  163. } else {
  164. this.map.events.register("buttonclick", this, this.onButtonClick);
  165. }
  166. this.addControlsToMap(this.controls);
  167. return this.div;
  168. },
  169. /**
  170. * Method: redraw
  171. */
  172. redraw: function() {
  173. for (var l=this.div.childNodes.length, i=l-1; i>=0; i--) {
  174. this.div.removeChild(this.div.childNodes[i]);
  175. }
  176. this.div.innerHTML = "";
  177. if (this.active) {
  178. for (var i=0, len=this.controls.length; i<len; i++) {
  179. this.div.appendChild(this.controls[i].panel_div);
  180. }
  181. }
  182. },
  183. /**
  184. * APIMethod: activateControl
  185. * This method is called when the user click on the icon representing a
  186. * control in the panel.
  187. *
  188. * Parameters:
  189. * control - {<OpenLayers.Control>}
  190. */
  191. activateControl: function (control) {
  192. if (!this.active) { return false; }
  193. if (control.type == OpenLayers.Control.TYPE_BUTTON) {
  194. control.trigger();
  195. return;
  196. }
  197. if (control.type == OpenLayers.Control.TYPE_TOGGLE) {
  198. if (control.active) {
  199. control.deactivate();
  200. } else {
  201. control.activate();
  202. }
  203. return;
  204. }
  205. if (this.allowDepress && control.active) {
  206. control.deactivate();
  207. } else {
  208. var c;
  209. for (var i=0, len=this.controls.length; i<len; i++) {
  210. c = this.controls[i];
  211. if (c != control &&
  212. (c.type === OpenLayers.Control.TYPE_TOOL || c.type == null)) {
  213. c.deactivate();
  214. }
  215. }
  216. control.activate();
  217. }
  218. },
  219. /**
  220. * APIMethod: addControls
  221. * To build a toolbar, you add a set of controls to it. addControls
  222. * lets you add a single control or a list of controls to the
  223. * Control Panel.
  224. *
  225. * Parameters:
  226. * controls - {<OpenLayers.Control>} Controls to add in the panel.
  227. */
  228. addControls: function(controls) {
  229. if (!(OpenLayers.Util.isArray(controls))) {
  230. controls = [controls];
  231. }
  232. this.controls = this.controls.concat(controls);
  233. for (var i=0, len=controls.length; i<len; i++) {
  234. var control = controls[i],
  235. element = this.createControlMarkup(control);
  236. OpenLayers.Element.addClass(element,
  237. control.displayClass + "ItemInactive");
  238. OpenLayers.Element.addClass(element, "olButton");
  239. if (control.title != "" && !element.title) {
  240. element.title = control.title;
  241. }
  242. control.panel_div = element;
  243. }
  244. if (this.map) { // map.addControl() has already been called on the panel
  245. this.addControlsToMap(controls);
  246. this.redraw();
  247. }
  248. },
  249. /**
  250. * APIMethod: createControlMarkup
  251. * This function just creates a div for the control. If specific HTML
  252. * markup is needed this function can be overridden in specific classes,
  253. * or at panel instantiation time:
  254. *
  255. * Example:
  256. * (code)
  257. * var panel = new OpenLayers.Control.Panel({
  258. * defaultControl: control,
  259. * // ovverride createControlMarkup to create actual buttons
  260. * // including texts wrapped into span elements.
  261. * createControlMarkup: function(control) {
  262. * var button = document.createElement('button'),
  263. * span = document.createElement('span');
  264. * if (control.text) {
  265. * span.innerHTML = control.text;
  266. * }
  267. * return button;
  268. * }
  269. * });
  270. * (end)
  271. *
  272. * Parameters:
  273. * control - {<OpenLayers.Control>} The control to create the HTML
  274. * markup for.
  275. *
  276. * Returns:
  277. * {DOMElement} The markup.
  278. */
  279. createControlMarkup: function(control) {
  280. return document.createElement("div");
  281. },
  282. /**
  283. * Method: addControlsToMap
  284. * Only for internal use in draw() and addControls() methods.
  285. *
  286. * Parameters:
  287. * controls - {Array(<OpenLayers.Control>)} Controls to add into map.
  288. */
  289. addControlsToMap: function (controls) {
  290. var control;
  291. for (var i=0, len=controls.length; i<len; i++) {
  292. control = controls[i];
  293. if (control.autoActivate === true) {
  294. control.autoActivate = false;
  295. this.map.addControl(control);
  296. control.autoActivate = true;
  297. } else {
  298. this.map.addControl(control);
  299. control.deactivate();
  300. }
  301. control.events.on({
  302. activate: this.iconOn,
  303. deactivate: this.iconOff
  304. });
  305. }
  306. },
  307. /**
  308. * Method: iconOn
  309. * Internal use, for use only with "controls[i].events.on/un".
  310. */
  311. iconOn: function() {
  312. var d = this.panel_div; // "this" refers to a control on panel!
  313. var re = new RegExp("\\b(" + this.displayClass + "Item)Inactive\\b");
  314. d.className = d.className.replace(re, "$1Active");
  315. },
  316. /**
  317. * Method: iconOff
  318. * Internal use, for use only with "controls[i].events.on/un".
  319. */
  320. iconOff: function() {
  321. var d = this.panel_div; // "this" refers to a control on panel!
  322. var re = new RegExp("\\b(" + this.displayClass + "Item)Active\\b");
  323. d.className = d.className.replace(re, "$1Inactive");
  324. },
  325. /**
  326. * Method: onButtonClick
  327. *
  328. * Parameters:
  329. * evt - {Event}
  330. */
  331. onButtonClick: function (evt) {
  332. var controls = this.controls,
  333. button = evt.buttonElement;
  334. for (var i=controls.length-1; i>=0; --i) {
  335. if (controls[i].panel_div === button) {
  336. this.activateControl(controls[i]);
  337. break;
  338. }
  339. }
  340. },
  341. /**
  342. * APIMethod: getControlsBy
  343. * Get a list of controls with properties matching the given criteria.
  344. *
  345. * Parameters:
  346. * property - {String} A control property to be matched.
  347. * match - {String | Object} A string to match. Can also be a regular
  348. * expression literal or object. In addition, it can be any object
  349. * with a method named test. For reqular expressions or other, if
  350. * match.test(control[property]) evaluates to true, the control will be
  351. * included in the array returned. If no controls are found, an empty
  352. * array is returned.
  353. *
  354. * Returns:
  355. * {Array(<OpenLayers.Control>)} A list of controls matching the given criteria.
  356. * An empty array is returned if no matches are found.
  357. */
  358. getControlsBy: function(property, match) {
  359. var test = (typeof match.test == "function");
  360. var found = OpenLayers.Array.filter(this.controls, function(item) {
  361. return item[property] == match || (test && match.test(item[property]));
  362. });
  363. return found;
  364. },
  365. /**
  366. * APIMethod: getControlsByName
  367. * Get a list of contorls with names matching the given name.
  368. *
  369. * Parameters:
  370. * match - {String | Object} A control name. The name can also be a regular
  371. * expression literal or object. In addition, it can be any object
  372. * with a method named test. For reqular expressions or other, if
  373. * name.test(control.name) evaluates to true, the control will be included
  374. * in the list of controls returned. If no controls are found, an empty
  375. * array is returned.
  376. *
  377. * Returns:
  378. * {Array(<OpenLayers.Control>)} A list of controls matching the given name.
  379. * An empty array is returned if no matches are found.
  380. */
  381. getControlsByName: function(match) {
  382. return this.getControlsBy("name", match);
  383. },
  384. /**
  385. * APIMethod: getControlsByClass
  386. * Get a list of controls of a given type (CLASS_NAME).
  387. *
  388. * Parameters:
  389. * match - {String | Object} A control class name. The type can also be a
  390. * regular expression literal or object. In addition, it can be any
  391. * object with a method named test. For reqular expressions or other,
  392. * if type.test(control.CLASS_NAME) evaluates to true, the control will
  393. * be included in the list of controls returned. If no controls are
  394. * found, an empty array is returned.
  395. *
  396. * Returns:
  397. * {Array(<OpenLayers.Control>)} A list of controls matching the given type.
  398. * An empty array is returned if no matches are found.
  399. */
  400. getControlsByClass: function(match) {
  401. return this.getControlsBy("CLASS_NAME", match);
  402. },
  403. CLASS_NAME: "OpenLayers.Control.Panel"
  404. });