// FIXME handle date line wrap goog.provide('ol.control.Attribution'); goog.require('goog.dom'); goog.require('goog.dom.TagName'); goog.require('goog.dom.classes'); goog.require('goog.events'); goog.require('goog.events.EventType'); goog.require('goog.object'); goog.require('goog.style'); goog.require('ol.Attribution'); goog.require('ol.control.Control'); goog.require('ol.css'); goog.require('ol.pointer.PointerEventHandler'); /** * @classdesc * Control to show all the attributions associated with the layer sources * in the map. This control is one of the default controls included in maps. * By default it will show in the bottom right portion of the map, but this can * be changed by using a css selector for `.ol-attribution`. * * @constructor * @extends {ol.control.Control} * @param {olx.control.AttributionOptions=} opt_options Attribution options. * @api */ ol.control.Attribution = function(opt_options) { var options = goog.isDef(opt_options) ? opt_options : {}; /** * @private * @type {Element} */ this.ulElement_ = goog.dom.createElement(goog.dom.TagName.UL); /** * @private * @type {boolean} */ this.collapsed_ = goog.isDef(options.collapsed) ? options.collapsed : true; var collapsible = goog.isDef(options.collapsible) ? options.collapsible : true; var className = goog.isDef(options.className) ? options.className : 'ol-attribution'; var tipLabel = goog.isDef(options.tipLabel) ? options.tipLabel : 'Attributions'; var tip = goog.dom.createDom(goog.dom.TagName.SPAN, { 'role' : 'tooltip' }, tipLabel); /** * @private * @type {string} */ this.label_ = goog.isDef(options.label) ? options.label : 'i'; var label = goog.dom.createDom(goog.dom.TagName.SPAN, {}, this.label_); /** * @private * @type {Element} */ this.labelSpan_ = label; var button = goog.dom.createDom(goog.dom.TagName.BUTTON, { 'class': 'ol-has-tooltip' }, this.labelSpan_); goog.dom.appendChild(button, tip); var buttonHandler = new ol.pointer.PointerEventHandler(button); this.registerDisposable(buttonHandler); goog.events.listen(buttonHandler, ol.pointer.EventType.POINTERUP, this.handleToggle_, false, this); goog.events.listen(button, [ goog.events.EventType.MOUSEOUT, goog.events.EventType.FOCUSOUT ], function() { this.blur(); }, false); var element = goog.dom.createDom(goog.dom.TagName.DIV, { 'class': className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' + ol.css.CLASS_CONTROL + (this.collapsed_ && collapsible ? ' ol-collapsed' : '') + (collapsible ? '' : ' ol-uncollapsible') }, this.ulElement_, button); goog.base(this, { element: element, target: options.target }); /** * @private * @type {boolean} */ this.renderedVisible_ = true; /** * @private * @type {Object.} */ this.attributionElements_ = {}; /** * @private * @type {Object.} */ this.attributionElementRenderedVisible_ = {}; }; goog.inherits(ol.control.Attribution, ol.control.Control); /** * @param {?olx.FrameState} frameState Frame state. * @return {Array.>} Attributions. */ ol.control.Attribution.prototype.getSourceAttributions = function(frameState) { var i, ii, j, jj, tileRanges, source, sourceAttribution, sourceAttributionKey, sourceAttributions, sourceKey; var layerStatesArray = frameState.layerStatesArray; /** @type {Object.} */ var attributions = goog.object.clone(frameState.attributions); /** @type {Object.} */ var hiddenAttributions = {}; for (i = 0, ii = layerStatesArray.length; i < ii; i++) { source = layerStatesArray[i].layer.getSource(); sourceKey = goog.getUid(source).toString(); sourceAttributions = source.getAttributions(); if (goog.isNull(sourceAttributions)) { continue; } for (j = 0, jj = sourceAttributions.length; j < jj; j++) { sourceAttribution = sourceAttributions[j]; sourceAttributionKey = goog.getUid(sourceAttribution).toString(); if (sourceAttributionKey in attributions) { continue; } tileRanges = frameState.usedTiles[sourceKey]; if (goog.isDef(tileRanges) && sourceAttribution.intersectsAnyTileRange(tileRanges)) { if (sourceAttributionKey in hiddenAttributions) { delete hiddenAttributions[sourceAttributionKey]; } attributions[sourceAttributionKey] = sourceAttribution; } else { hiddenAttributions[sourceAttributionKey] = sourceAttribution; } } } return [attributions, hiddenAttributions]; }; /** * @inheritDoc */ ol.control.Attribution.prototype.handleMapPostrender = function(mapEvent) { this.updateElement_(mapEvent.frameState); }; /** * @private * @param {?olx.FrameState} frameState Frame state. */ ol.control.Attribution.prototype.updateElement_ = function(frameState) { if (goog.isNull(frameState)) { if (this.renderedVisible_) { goog.style.setElementShown(this.element, false); this.renderedVisible_ = false; } return; } var attributions = this.getSourceAttributions(frameState); /** @type {Object.} */ var visibleAttributions = attributions[0]; /** @type {Object.} */ var hiddenAttributions = attributions[1]; var attributionElement, attributionKey; for (attributionKey in this.attributionElements_) { if (attributionKey in visibleAttributions) { if (!this.attributionElementRenderedVisible_[attributionKey]) { goog.style.setElementShown( this.attributionElements_[attributionKey], true); this.attributionElementRenderedVisible_[attributionKey] = true; } delete visibleAttributions[attributionKey]; } else if (attributionKey in hiddenAttributions) { if (this.attributionElementRenderedVisible_[attributionKey]) { goog.style.setElementShown( this.attributionElements_[attributionKey], false); delete this.attributionElementRenderedVisible_[attributionKey]; } delete hiddenAttributions[attributionKey]; } else { goog.dom.removeNode(this.attributionElements_[attributionKey]); delete this.attributionElements_[attributionKey]; delete this.attributionElementRenderedVisible_[attributionKey]; } } for (attributionKey in visibleAttributions) { attributionElement = goog.dom.createElement(goog.dom.TagName.LI); attributionElement.innerHTML = visibleAttributions[attributionKey].getHTML(); goog.dom.appendChild(this.ulElement_, attributionElement); this.attributionElements_[attributionKey] = attributionElement; this.attributionElementRenderedVisible_[attributionKey] = true; } for (attributionKey in hiddenAttributions) { attributionElement = goog.dom.createElement(goog.dom.TagName.LI); attributionElement.innerHTML = hiddenAttributions[attributionKey].getHTML(); goog.style.setElementShown(attributionElement, false); goog.dom.appendChild(this.ulElement_, attributionElement); this.attributionElements_[attributionKey] = attributionElement; } var renderVisible = !goog.object.isEmpty(this.attributionElementRenderedVisible_); if (this.renderedVisible_ != renderVisible) { goog.style.setElementShown(this.element, renderVisible); this.renderedVisible_ = renderVisible; } }; /** * @param {ol.pointer.PointerEvent} pointerEvent Pointer event. * @private */ ol.control.Attribution.prototype.handleToggle_ = function(pointerEvent) { pointerEvent.browserEvent.preventDefault(); goog.dom.classes.toggle(this.element, 'ol-collapsed'); goog.dom.setTextContent(this.labelSpan_, (this.collapsed_) ? '\u00D7' : this.label_); this.collapsed_ = !this.collapsed_; };