Update wmts-hidpi, add nicer-api-docs
This commit is contained in:
525
nicer-api-docs/closure-library/closure/goog/ui/editor/bubble.js
Normal file
525
nicer-api-docs/closure-library/closure/goog/ui/editor/bubble.js
Normal file
@@ -0,0 +1,525 @@
|
||||
// Copyright 2005 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Bubble component - handles display, hiding, etc. of the
|
||||
* actual bubble UI.
|
||||
*
|
||||
* This is used exclusively by code within the editor package, and should not
|
||||
* be used directly.
|
||||
*
|
||||
* @author robbyw@google.com (Robby Walker)
|
||||
* @author tildahl@google.com (Michael Tildahl)
|
||||
*/
|
||||
|
||||
goog.provide('goog.ui.editor.Bubble');
|
||||
|
||||
goog.require('goog.dom');
|
||||
goog.require('goog.dom.TagName');
|
||||
goog.require('goog.dom.ViewportSizeMonitor');
|
||||
goog.require('goog.dom.classes');
|
||||
goog.require('goog.editor.style');
|
||||
goog.require('goog.events.EventHandler');
|
||||
goog.require('goog.events.EventTarget');
|
||||
goog.require('goog.events.EventType');
|
||||
goog.require('goog.log');
|
||||
goog.require('goog.math.Box');
|
||||
goog.require('goog.object');
|
||||
goog.require('goog.positioning');
|
||||
goog.require('goog.positioning.Corner');
|
||||
goog.require('goog.positioning.Overflow');
|
||||
goog.require('goog.positioning.OverflowStatus');
|
||||
goog.require('goog.string');
|
||||
goog.require('goog.style');
|
||||
goog.require('goog.ui.Component');
|
||||
goog.require('goog.ui.PopupBase');
|
||||
goog.require('goog.userAgent');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Property bubble UI element.
|
||||
* @param {Element} parent The parent element for this bubble.
|
||||
* @param {number} zIndex The z index to draw the bubble at.
|
||||
* @constructor
|
||||
* @extends {goog.events.EventTarget}
|
||||
*/
|
||||
goog.ui.editor.Bubble = function(parent, zIndex) {
|
||||
goog.base(this);
|
||||
|
||||
/**
|
||||
* Dom helper for the document the bubble should be shown in.
|
||||
* @type {!goog.dom.DomHelper}
|
||||
* @private
|
||||
*/
|
||||
this.dom_ = goog.dom.getDomHelper(parent);
|
||||
|
||||
/**
|
||||
* Event handler for this bubble.
|
||||
* @type {goog.events.EventHandler}
|
||||
* @private
|
||||
*/
|
||||
this.eventHandler_ = new goog.events.EventHandler(this);
|
||||
|
||||
/**
|
||||
* Object that monitors the application window for size changes.
|
||||
* @type {goog.dom.ViewportSizeMonitor}
|
||||
* @private
|
||||
*/
|
||||
this.viewPortSizeMonitor_ = new goog.dom.ViewportSizeMonitor(
|
||||
this.dom_.getWindow());
|
||||
|
||||
/**
|
||||
* Maps panel ids to panels.
|
||||
* @type {Object.<goog.ui.editor.Bubble.Panel_>}
|
||||
* @private
|
||||
*/
|
||||
this.panels_ = {};
|
||||
|
||||
/**
|
||||
* Container element for the entire bubble. This may contain elements related
|
||||
* to look and feel or styling of the bubble.
|
||||
* @type {Element}
|
||||
* @private
|
||||
*/
|
||||
this.bubbleContainer_ =
|
||||
this.dom_.createDom(goog.dom.TagName.DIV,
|
||||
{'className': goog.ui.editor.Bubble.BUBBLE_CLASSNAME});
|
||||
|
||||
goog.style.setElementShown(this.bubbleContainer_, false);
|
||||
goog.dom.appendChild(parent, this.bubbleContainer_);
|
||||
goog.style.setStyle(this.bubbleContainer_, 'zIndex', zIndex);
|
||||
|
||||
/**
|
||||
* Container element for the bubble panels - this should be some inner element
|
||||
* within (or equal to) bubbleContainer.
|
||||
* @type {Element}
|
||||
* @private
|
||||
*/
|
||||
this.bubbleContents_ = this.createBubbleDom(this.dom_, this.bubbleContainer_);
|
||||
|
||||
/**
|
||||
* Element showing the close box.
|
||||
* @type {!Element}
|
||||
* @private
|
||||
*/
|
||||
this.closeBox_ = this.dom_.createDom(goog.dom.TagName.DIV, {
|
||||
'className': goog.getCssName('tr_bubble_closebox'),
|
||||
'innerHTML': ' '
|
||||
});
|
||||
this.bubbleContents_.appendChild(this.closeBox_);
|
||||
|
||||
// We make bubbles unselectable so that clicking on them does not steal focus
|
||||
// or move the cursor away from the element the bubble is attached to.
|
||||
goog.editor.style.makeUnselectable(this.bubbleContainer_, this.eventHandler_);
|
||||
|
||||
/**
|
||||
* Popup that controls showing and hiding the bubble at the appropriate
|
||||
* position.
|
||||
* @type {goog.ui.PopupBase}
|
||||
* @private
|
||||
*/
|
||||
this.popup_ = new goog.ui.PopupBase(this.bubbleContainer_);
|
||||
};
|
||||
goog.inherits(goog.ui.editor.Bubble, goog.events.EventTarget);
|
||||
|
||||
|
||||
/**
|
||||
* The css class name of the bubble container element.
|
||||
* @type {string}
|
||||
*/
|
||||
goog.ui.editor.Bubble.BUBBLE_CLASSNAME = goog.getCssName('tr_bubble');
|
||||
|
||||
|
||||
/**
|
||||
* Creates and adds DOM for the bubble UI to the given container. This default
|
||||
* implementation just returns the container itself.
|
||||
* @param {!goog.dom.DomHelper} dom DOM helper to use.
|
||||
* @param {!Element} container Element to add the new elements to.
|
||||
* @return {!Element} The element where bubble content should be added.
|
||||
* @protected
|
||||
*/
|
||||
goog.ui.editor.Bubble.prototype.createBubbleDom = function(dom, container) {
|
||||
return container;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A logger for goog.ui.editor.Bubble.
|
||||
* @type {goog.log.Logger}
|
||||
* @protected
|
||||
*/
|
||||
goog.ui.editor.Bubble.prototype.logger =
|
||||
goog.log.getLogger('goog.ui.editor.Bubble');
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.ui.editor.Bubble.prototype.disposeInternal = function() {
|
||||
goog.base(this, 'disposeInternal');
|
||||
|
||||
goog.dom.removeNode(this.bubbleContainer_);
|
||||
this.bubbleContainer_ = null;
|
||||
|
||||
this.eventHandler_.dispose();
|
||||
this.eventHandler_ = null;
|
||||
|
||||
this.viewPortSizeMonitor_.dispose();
|
||||
this.viewPortSizeMonitor_ = null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Element} The element that where the bubble's contents go.
|
||||
*/
|
||||
goog.ui.editor.Bubble.prototype.getContentElement = function() {
|
||||
return this.bubbleContents_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Element} The element that contains the bubble.
|
||||
* @protected
|
||||
*/
|
||||
goog.ui.editor.Bubble.prototype.getContainerElement = function() {
|
||||
return this.bubbleContainer_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {goog.events.EventHandler} The event handler.
|
||||
* @protected
|
||||
*/
|
||||
goog.ui.editor.Bubble.prototype.getEventHandler = function() {
|
||||
return this.eventHandler_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handles user resizing of window.
|
||||
* @private
|
||||
*/
|
||||
goog.ui.editor.Bubble.prototype.handleWindowResize_ = function() {
|
||||
if (this.isVisible()) {
|
||||
this.reposition();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns whether there is already a panel of the given type.
|
||||
* @param {string} type Type of panel to check.
|
||||
* @return {boolean} Whether there is already a panel of the given type.
|
||||
*/
|
||||
goog.ui.editor.Bubble.prototype.hasPanelOfType = function(type) {
|
||||
return goog.object.some(this.panels_, function(panel) {
|
||||
return panel.type == type;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds a panel to the bubble.
|
||||
* @param {string} type The type of bubble panel this is. Should usually be
|
||||
* the same as the tagName of the targetElement. This ensures multiple
|
||||
* bubble panels don't appear for the same element.
|
||||
* @param {string} title The title of the panel.
|
||||
* @param {Element} targetElement The target element of the bubble.
|
||||
* @param {function(Element): void} contentFn Function that when called with
|
||||
* a container element, will add relevant panel content to it.
|
||||
* @param {boolean=} opt_preferTopPosition Whether to prefer placing the bubble
|
||||
* above the element instead of below it. Defaults to preferring below.
|
||||
* If any panel prefers the top position, the top position is used.
|
||||
* @return {string} The id of the panel.
|
||||
*/
|
||||
goog.ui.editor.Bubble.prototype.addPanel = function(type, title, targetElement,
|
||||
contentFn, opt_preferTopPosition) {
|
||||
var id = goog.string.createUniqueString();
|
||||
var panel = new goog.ui.editor.Bubble.Panel_(this.dom_, id, type, title,
|
||||
targetElement, !opt_preferTopPosition);
|
||||
this.panels_[id] = panel;
|
||||
|
||||
// Insert the panel in string order of type. Technically we could use binary
|
||||
// search here but n is really small (probably 0 - 2) so it's not worth it.
|
||||
// The last child of bubbleContents_ is the close box so we take care not
|
||||
// to treat it as a panel element, and we also ensure it stays as the last
|
||||
// element. The intention here is not to create any artificial order, but
|
||||
// just to ensure that it is always consistent.
|
||||
var nextElement;
|
||||
for (var i = 0, len = this.bubbleContents_.childNodes.length - 1; i < len;
|
||||
i++) {
|
||||
var otherChild = this.bubbleContents_.childNodes[i];
|
||||
var otherPanel = this.panels_[otherChild.id];
|
||||
if (otherPanel.type > type) {
|
||||
nextElement = otherChild;
|
||||
break;
|
||||
}
|
||||
}
|
||||
goog.dom.insertSiblingBefore(panel.element,
|
||||
nextElement || this.bubbleContents_.lastChild);
|
||||
|
||||
contentFn(panel.getContentElement());
|
||||
goog.editor.style.makeUnselectable(panel.element, this.eventHandler_);
|
||||
|
||||
var numPanels = goog.object.getCount(this.panels_);
|
||||
if (numPanels == 1) {
|
||||
this.openBubble_();
|
||||
} else if (numPanels == 2) {
|
||||
goog.dom.classes.add(this.bubbleContainer_,
|
||||
goog.getCssName('tr_multi_bubble'));
|
||||
}
|
||||
this.reposition();
|
||||
|
||||
return id;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes the panel with the given id.
|
||||
* @param {string} id The id of the panel.
|
||||
*/
|
||||
goog.ui.editor.Bubble.prototype.removePanel = function(id) {
|
||||
var panel = this.panels_[id];
|
||||
goog.dom.removeNode(panel.element);
|
||||
delete this.panels_[id];
|
||||
|
||||
var numPanels = goog.object.getCount(this.panels_);
|
||||
if (numPanels <= 1) {
|
||||
goog.dom.classes.remove(this.bubbleContainer_,
|
||||
goog.getCssName('tr_multi_bubble'));
|
||||
}
|
||||
|
||||
if (numPanels == 0) {
|
||||
this.closeBubble_();
|
||||
} else {
|
||||
this.reposition();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Opens the bubble.
|
||||
* @private
|
||||
*/
|
||||
goog.ui.editor.Bubble.prototype.openBubble_ = function() {
|
||||
this.eventHandler_.
|
||||
listen(this.closeBox_, goog.events.EventType.CLICK,
|
||||
this.closeBubble_).
|
||||
listen(this.viewPortSizeMonitor_,
|
||||
goog.events.EventType.RESIZE, this.handleWindowResize_).
|
||||
listen(this.popup_, goog.ui.PopupBase.EventType.HIDE,
|
||||
this.handlePopupHide);
|
||||
|
||||
this.popup_.setVisible(true);
|
||||
this.reposition();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Closes the bubble.
|
||||
* @private
|
||||
*/
|
||||
goog.ui.editor.Bubble.prototype.closeBubble_ = function() {
|
||||
this.popup_.setVisible(false);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handles the popup's hide event by removing all panels and dispatching a
|
||||
* HIDE event.
|
||||
* @protected
|
||||
*/
|
||||
goog.ui.editor.Bubble.prototype.handlePopupHide = function() {
|
||||
// Remove the panel elements.
|
||||
for (var panelId in this.panels_) {
|
||||
goog.dom.removeNode(this.panels_[panelId].element);
|
||||
}
|
||||
|
||||
// Update the state to reflect no panels.
|
||||
this.panels_ = {};
|
||||
goog.dom.classes.remove(this.bubbleContainer_,
|
||||
goog.getCssName('tr_multi_bubble'));
|
||||
|
||||
this.eventHandler_.removeAll();
|
||||
this.dispatchEvent(goog.ui.Component.EventType.HIDE);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the visibility of the bubble.
|
||||
* @return {boolean} True if visible false if not.
|
||||
*/
|
||||
goog.ui.editor.Bubble.prototype.isVisible = function() {
|
||||
return this.popup_.isVisible();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The vertical clearance in pixels between the bottom of the targetElement
|
||||
* and the edge of the bubble.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
goog.ui.editor.Bubble.VERTICAL_CLEARANCE_ = goog.userAgent.IE ? 4 : 2;
|
||||
|
||||
|
||||
/**
|
||||
* Bubble's margin box to be passed to goog.positioning.
|
||||
* @type {goog.math.Box}
|
||||
* @private
|
||||
*/
|
||||
goog.ui.editor.Bubble.MARGIN_BOX_ = new goog.math.Box(
|
||||
goog.ui.editor.Bubble.VERTICAL_CLEARANCE_, 0,
|
||||
goog.ui.editor.Bubble.VERTICAL_CLEARANCE_, 0);
|
||||
|
||||
|
||||
/**
|
||||
* Positions and displays this bubble below its targetElement. Assumes that
|
||||
* the bubbleContainer is already contained in the document object it applies
|
||||
* to.
|
||||
*/
|
||||
goog.ui.editor.Bubble.prototype.reposition = function() {
|
||||
var targetElement = null;
|
||||
var preferBottomPosition = true;
|
||||
for (var panelId in this.panels_) {
|
||||
var panel = this.panels_[panelId];
|
||||
// We don't care which targetElement we get, so we just take the last one.
|
||||
targetElement = panel.targetElement;
|
||||
preferBottomPosition = preferBottomPosition && panel.preferBottomPosition;
|
||||
}
|
||||
var status = goog.positioning.OverflowStatus.FAILED;
|
||||
|
||||
// Fix for bug when bubbleContainer and targetElement have
|
||||
// opposite directionality, the bubble should anchor to the END of
|
||||
// the targetElement instead of START.
|
||||
var reverseLayout = (goog.style.isRightToLeft(this.bubbleContainer_) !=
|
||||
goog.style.isRightToLeft(targetElement));
|
||||
|
||||
// Try to put the bubble at the bottom of the target unless the plugin has
|
||||
// requested otherwise.
|
||||
if (preferBottomPosition) {
|
||||
status = this.positionAtAnchor_(reverseLayout ?
|
||||
goog.positioning.Corner.BOTTOM_END :
|
||||
goog.positioning.Corner.BOTTOM_START,
|
||||
goog.positioning.Corner.TOP_START,
|
||||
goog.positioning.Overflow.ADJUST_X | goog.positioning.Overflow.FAIL_Y);
|
||||
}
|
||||
|
||||
if (status & goog.positioning.OverflowStatus.FAILED) {
|
||||
// Try to put it at the top of the target if there is not enough
|
||||
// space at the bottom.
|
||||
status = this.positionAtAnchor_(reverseLayout ?
|
||||
goog.positioning.Corner.TOP_END : goog.positioning.Corner.TOP_START,
|
||||
goog.positioning.Corner.BOTTOM_START,
|
||||
goog.positioning.Overflow.ADJUST_X | goog.positioning.Overflow.FAIL_Y);
|
||||
}
|
||||
|
||||
if (status & goog.positioning.OverflowStatus.FAILED) {
|
||||
// Put it at the bottom again with adjustment if there is no
|
||||
// enough space at the top.
|
||||
status = this.positionAtAnchor_(reverseLayout ?
|
||||
goog.positioning.Corner.BOTTOM_END :
|
||||
goog.positioning.Corner.BOTTOM_START,
|
||||
goog.positioning.Corner.TOP_START,
|
||||
goog.positioning.Overflow.ADJUST_X |
|
||||
goog.positioning.Overflow.ADJUST_Y);
|
||||
if (status & goog.positioning.OverflowStatus.FAILED) {
|
||||
goog.log.warning(this.logger,
|
||||
'reposition(): positionAtAnchor() failed with ' + status);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A helper for reposition() - positions the bubble in regards to the position
|
||||
* of the elements the bubble is attached to.
|
||||
* @param {goog.positioning.Corner} targetCorner The corner of
|
||||
* the target element.
|
||||
* @param {goog.positioning.Corner} bubbleCorner The corner of the bubble.
|
||||
* @param {number} overflow Overflow handling mode bitmap,
|
||||
* {@see goog.positioning.Overflow}.
|
||||
* @return {number} Status bitmap, {@see goog.positioning.OverflowStatus}.
|
||||
* @private
|
||||
*/
|
||||
goog.ui.editor.Bubble.prototype.positionAtAnchor_ = function(
|
||||
targetCorner, bubbleCorner, overflow) {
|
||||
var targetElement = null;
|
||||
for (var panelId in this.panels_) {
|
||||
// For now, we use the outermost element. This assumes the multiple
|
||||
// elements this panel is showing for contain each other - in the event
|
||||
// that is not generally the case this may need to be updated to pick
|
||||
// the lowest or highest element depending on targetCorner.
|
||||
var candidate = this.panels_[panelId].targetElement;
|
||||
if (!targetElement || goog.dom.contains(candidate, targetElement)) {
|
||||
targetElement = this.panels_[panelId].targetElement;
|
||||
}
|
||||
}
|
||||
return goog.positioning.positionAtAnchor(
|
||||
targetElement, targetCorner, this.bubbleContainer_,
|
||||
bubbleCorner, null, goog.ui.editor.Bubble.MARGIN_BOX_, overflow);
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Private class used to describe a bubble panel.
|
||||
* @param {goog.dom.DomHelper} dom DOM helper used to create the panel.
|
||||
* @param {string} id ID of the panel.
|
||||
* @param {string} type Type of the panel.
|
||||
* @param {string} title Title of the panel.
|
||||
* @param {Element} targetElement Element the panel is showing for.
|
||||
* @param {boolean} preferBottomPosition Whether this panel prefers to show
|
||||
* below the target element.
|
||||
* @constructor
|
||||
* @private
|
||||
*/
|
||||
goog.ui.editor.Bubble.Panel_ = function(dom, id, type, title, targetElement,
|
||||
preferBottomPosition) {
|
||||
/**
|
||||
* The type of bubble panel.
|
||||
* @type {string}
|
||||
*/
|
||||
this.type = type;
|
||||
|
||||
/**
|
||||
* The target element of this bubble panel.
|
||||
* @type {Element}
|
||||
*/
|
||||
this.targetElement = targetElement;
|
||||
|
||||
/**
|
||||
* Whether the panel prefers to be placed below the target element.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.preferBottomPosition = preferBottomPosition;
|
||||
|
||||
/**
|
||||
* The element containing this panel.
|
||||
*/
|
||||
this.element = dom.createDom(goog.dom.TagName.DIV,
|
||||
{className: goog.getCssName('tr_bubble_panel'), id: id},
|
||||
dom.createDom(goog.dom.TagName.DIV,
|
||||
{className: goog.getCssName('tr_bubble_panel_title')},
|
||||
title + ':'), // TODO(robbyw): Does this work properly in bidi?
|
||||
dom.createDom(goog.dom.TagName.DIV,
|
||||
{className: goog.getCssName('tr_bubble_panel_content')}));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Element} The element in the panel where content should go.
|
||||
*/
|
||||
goog.ui.editor.Bubble.Panel_.prototype.getContentElement = function() {
|
||||
return /** @type {Element} */ (this.element.lastChild);
|
||||
};
|
||||
Reference in New Issue
Block a user