Path: blob/trunk/third_party/closure/goog/ui/editor/toolbarfactory.js
4067 views
/**1* @license2* Copyright The Closure Library Authors.3* SPDX-License-Identifier: Apache-2.04*/56/**7* @fileoverview Generic factory functions for creating the building blocks for8* an editor toolbar.9*/1011goog.provide('goog.ui.editor.ToolbarFactory');1213goog.require('goog.dom');14goog.require('goog.dom.TagName');15goog.require('goog.string');16goog.require('goog.style');17goog.require('goog.ui.Component');18goog.require('goog.ui.Container');19goog.require('goog.ui.Option');20goog.require('goog.ui.Toolbar');21goog.require('goog.ui.ToolbarButton');22goog.require('goog.ui.ToolbarColorMenuButton');23goog.require('goog.ui.ToolbarMenuButton');24goog.require('goog.ui.ToolbarRenderer');25goog.require('goog.ui.ToolbarSelect');26goog.requireType('goog.ui.Button');27goog.requireType('goog.ui.ButtonRenderer');28goog.requireType('goog.ui.ColorMenuButton');29goog.requireType('goog.ui.ColorMenuButtonRenderer');30goog.requireType('goog.ui.Control');31goog.requireType('goog.ui.ControlContent');32goog.requireType('goog.ui.MenuButton');33goog.requireType('goog.ui.MenuButtonRenderer');34goog.requireType('goog.ui.Select');353637/**38* Takes a font spec (e.g. "Arial, Helvetica, sans-serif") and returns the39* primary font name, normalized to lowercase (e.g. "arial").40* @param {string} fontSpec Font specification.41* @return {string} The primary font name, in lowercase.42*/43goog.ui.editor.ToolbarFactory.getPrimaryFont = function(fontSpec) {44'use strict';45const i = fontSpec.indexOf(',');46const fontName =47(i != -1 ? fontSpec.substring(0, i) : fontSpec).toLowerCase();48// Strip leading/trailing quotes from the font name (bug 1050118).49return goog.string.stripQuotes(fontName, '"\'');50};515253/**54* Bulk-adds fonts to the given font menu button. The argument must be an55* array of font descriptor objects, each of which must have the following56* attributes:57* <ul>58* <li>`caption` - Caption to show in the font menu (e.g. 'Tahoma')59* <li>`value` - Value for the corresponding 'font-family' CSS style60* (e.g. 'Tahoma, Arial, sans-serif')61* </ul>62* @param {!goog.ui.Select} button Font menu button.63* @param {!Array<{caption: string, value: string}>} fonts Array of64* font descriptors.65*/66goog.ui.editor.ToolbarFactory.addFonts = function(button, fonts) {67'use strict';68fonts.forEach(function(font) {69'use strict';70goog.ui.editor.ToolbarFactory.addFont(button, font.caption, font.value);71});72};737475/**76* Adds a menu item to the given font menu button. The first font listed in77* the `value` argument is considered the font ID, so adding two items78* whose CSS style starts with the same font may lead to unpredictable results.79* @param {!goog.ui.Select} button Font menu button.80* @param {string} caption Caption to show for the font menu.81* @param {string} value Value for the corresponding 'font-family' CSS style.82*/83goog.ui.editor.ToolbarFactory.addFont = function(button, caption, value) {84'use strict';85// The font ID is the first font listed in the CSS style, normalized to86// lowercase.87const id = goog.ui.editor.ToolbarFactory.getPrimaryFont(value);8889// Construct the option, and add it to the button.90const option = new goog.ui.Option(caption, value, button.getDomHelper());91option.setId(id);92button.addItem(option);9394// Captions are shown in their own font.95option.getContentElement().style.fontFamily = value;96};979899/**100* Bulk-adds font sizes to the given font size menu button. The argument must101* be an array of font size descriptor objects, each of which must have the102* following attributes:103* <ul>104* <li>`caption` - Caption to show in the font size menu (e.g. 'Huge')105* <li>`value` - Value for the corresponding HTML font size (e.g. 6)106* </ul>107* @param {!goog.ui.Select} button Font size menu button.108* @param {!Array<{caption: string, value:number}>} sizes Array of font109* size descriptors.110*/111goog.ui.editor.ToolbarFactory.addFontSizes = function(button, sizes) {112'use strict';113sizes.forEach(function(size) {114'use strict';115goog.ui.editor.ToolbarFactory.addFontSize(button, size.caption, size.value);116});117};118119120/**121* Adds a menu item to the given font size menu button. The `value`122* argument must be a legacy HTML font size in the 0-7 range.123* @param {!goog.ui.Select} button Font size menu button.124* @param {string} caption Caption to show in the font size menu.125* @param {number} value Value for the corresponding HTML font size.126* @suppress {strictMissingProperties} Part of the go/strict_warnings_migration127*/128goog.ui.editor.ToolbarFactory.addFontSize = function(button, caption, value) {129'use strict';130// Construct the option, and add it to the button.131const option = new goog.ui.Option(caption, value, button.getDomHelper());132button.addItem(option);133134// Adjust the font size of the menu item and the height of the checkbox135// element after they've been rendered by addItem(). Captions are shown in136// the corresponding font size, and lining up the checkbox is tricky.137const content = option.getContentElement();138content.style.fontSize =139goog.ui.editor.ToolbarFactory.getPxFromLegacySize(value) + 'px';140content.firstChild.style.height = '1.1em';141};142143144/**145* Converts a legacy font size specification into an equivalent pixel size.146* For example, {@code <font size="6">} is {@code font-size: 32px;}, etc.147* @param {number} fontSize Legacy font size spec in the 0-7 range.148* @return {number} Equivalent pixel size.149*/150goog.ui.editor.ToolbarFactory.getPxFromLegacySize = function(fontSize) {151'use strict';152return goog.ui.editor.ToolbarFactory.LEGACY_SIZE_TO_PX_MAP_[fontSize] || 10;153};154155156/**157* Converts a pixel font size specification into an equivalent legacy size.158* For example, {@code font-size: 32px;} is {@code <font size="6">}, etc.159* If the given pixel size doesn't exactly match one of the legacy sizes, -1 is160* returned.161* @param {number} px Pixel font size.162* @return {number} Equivalent legacy size spec in the 0-7 range, or -1 if none163* exists.164*/165goog.ui.editor.ToolbarFactory.getLegacySizeFromPx = function(px) {166'use strict';167// Use lastIndexOf to get the largest legacy size matching the pixel size168// (most notably returning 1 instead of 0 for 10px).169return goog.ui.editor.ToolbarFactory.LEGACY_SIZE_TO_PX_MAP_.lastIndexOf(px);170};171172173/**174* Map of legacy font sizes (0-7) to equivalent pixel sizes.175* @type {!Array<number>}176* @private177*/178goog.ui.editor.ToolbarFactory.LEGACY_SIZE_TO_PX_MAP_ =179[10, 10, 13, 16, 18, 24, 32, 48];180181182/**183* Bulk-adds format options to the given "Format block" menu button. The184* argument must be an array of format option descriptor objects, each of185* which must have the following attributes:186* <ul>187* <li>`caption` - Caption to show in the menu (e.g. 'Minor heading')188* <li>`command` - Corresponding {@link goog.dom.TagName} (e.g.189* 'H4')190* </ul>191* @param {!goog.ui.Select} button "Format block" menu button.192* @param {!Array<{caption: string, command: !goog.dom.TagName}>} formats Array193* of format option descriptors.194*/195goog.ui.editor.ToolbarFactory.addFormatOptions = function(button, formats) {196'use strict';197formats.forEach(function(format) {198'use strict';199goog.ui.editor.ToolbarFactory.addFormatOption(200button, format.caption, format.command);201});202};203204205/**206* Adds a menu item to the given "Format block" menu button.207* @param {!goog.ui.Select} button "Format block" menu button.208* @param {string} caption Caption to show in the menu.209* @param {!goog.dom.TagName} tag Corresponding block format tag.210*/211goog.ui.editor.ToolbarFactory.addFormatOption = function(button, caption, tag) {212'use strict';213// Construct the option, and add it to the button.214// TODO(attila): Create boring but functional menu item for now...215const buttonDom = button.getDomHelper();216const option = new goog.ui.Option(217buttonDom.createDom(goog.dom.TagName.DIV, null, caption), tag, buttonDom);218option.setId(String(tag));219button.addItem(option);220};221222223/**224* Creates a {@link goog.ui.Toolbar} containing the specified set of225* toolbar buttons, and renders it into the given parent element. Each226* item in the `items` array must a {@link goog.ui.Control}.227* @param {!Array<goog.ui.Control>} items Toolbar items; each must228* be a {@link goog.ui.Control}.229* @param {!Element} elem Toolbar parent element.230* @param {boolean=} opt_isRightToLeft Whether the editor chrome is231* right-to-left; defaults to the directionality of the toolbar parent232* element.233* @return {!goog.ui.Toolbar} Editor toolbar, rendered into the given parent234* element.235*/236goog.ui.editor.ToolbarFactory.makeToolbar = function(237items, elem, opt_isRightToLeft) {238'use strict';239const domHelper = goog.dom.getDomHelper(elem);240241// Create an empty horizontal toolbar using the default renderer.242const toolbar = new goog.ui.Toolbar(243goog.ui.ToolbarRenderer.getInstance(),244goog.ui.Container.Orientation.HORIZONTAL, domHelper);245246// Optimization: Explicitly test for the directionality of the parent247// element here, so we can set it for both the toolbar and its children,248// saving a lot of expensive calls to goog.style.isRightToLeft() during249// rendering.250const isRightToLeft = opt_isRightToLeft || goog.style.isRightToLeft(elem);251toolbar.setRightToLeft(isRightToLeft);252253// Optimization: Set the toolbar to non-focusable before it is rendered,254// to avoid creating unnecessary keyboard event handler objects.255toolbar.setFocusable(false);256257for (let i = 0, button; button = items[i]; i++) {258// Optimization: Set the button to non-focusable before it is rendered,259// to avoid creating unnecessary keyboard event handler objects. Also set260// the directionality of the button explicitly, to avoid expensive calls261// to goog.style.isRightToLeft() during rendering.262button.setSupportedState(goog.ui.Component.State.FOCUSED, false);263button.setRightToLeft(isRightToLeft);264toolbar.addChild(button, true);265}266267toolbar.render(elem);268return toolbar;269};270271272/**273* Creates a toolbar button with the given ID, tooltip, and caption. Applies274* any custom CSS class names to the button's caption element.275* @param {string} id Button ID; must equal a {@link goog.editor.Command} for276* built-in buttons, anything else for custom buttons.277* @param {string} tooltip Tooltip to be shown on hover.278* @param {goog.ui.ControlContent} caption Button caption.279* @param {string=} opt_classNames CSS class name(s) to apply to the caption280* element.281* @param {goog.ui.ButtonRenderer=} opt_renderer Button renderer; defaults to282* {@link goog.ui.ToolbarButtonRenderer} if unspecified.283* @param {goog.dom.DomHelper=} opt_domHelper DOM helper, used for DOM284* creation; defaults to the current document if unspecified.285* @return {!goog.ui.Button} A toolbar button.286*/287goog.ui.editor.ToolbarFactory.makeButton = function(288id, tooltip, caption, opt_classNames, opt_renderer, opt_domHelper) {289'use strict';290const button = new goog.ui.ToolbarButton(291goog.ui.editor.ToolbarFactory.createContent_(292caption, opt_classNames, opt_domHelper),293opt_renderer, opt_domHelper);294button.setId(id);295button.setTooltip(tooltip);296return button;297};298299300/**301* Creates a toggle button with the given ID, tooltip, and caption. Applies302* any custom CSS class names to the button's caption element. The button303* returned has checkbox-like toggle semantics.304* @param {string} id Button ID; must equal a {@link goog.editor.Command} for305* built-in buttons, anything else for custom buttons.306* @param {string} tooltip Tooltip to be shown on hover.307* @param {goog.ui.ControlContent} caption Button caption.308* @param {string=} opt_classNames CSS class name(s) to apply to the caption309* element.310* @param {goog.ui.ButtonRenderer=} opt_renderer Button renderer; defaults to311* {@link goog.ui.ToolbarButtonRenderer} if unspecified.312* @param {goog.dom.DomHelper=} opt_domHelper DOM helper, used for DOM313* creation; defaults to the current document if unspecified.314* @return {!goog.ui.Button} A toggle button.315*/316goog.ui.editor.ToolbarFactory.makeToggleButton = function(317id, tooltip, caption, opt_classNames, opt_renderer, opt_domHelper) {318'use strict';319const button = goog.ui.editor.ToolbarFactory.makeButton(320id, tooltip, caption, opt_classNames, opt_renderer, opt_domHelper);321button.setSupportedState(goog.ui.Component.State.CHECKED, true);322return button;323};324325326/**327* Creates a menu button with the given ID, tooltip, and caption. Applies328* any custom CSS class names to the button's caption element. The button329* returned doesn't have an actual menu attached; use {@link330* goog.ui.MenuButton#setMenu} to attach a {@link goog.ui.Menu} to the331* button.332* @param {string} id Button ID; must equal a {@link goog.editor.Command} for333* built-in buttons, anything else for custom buttons.334* @param {string} tooltip Tooltip to be shown on hover.335* @param {goog.ui.ControlContent} caption Button caption.336* @param {string=} opt_classNames CSS class name(s) to apply to the caption337* element.338* @param {goog.ui.ButtonRenderer=} opt_renderer Button renderer; defaults to339* {@link goog.ui.ToolbarMenuButtonRenderer} if unspecified.340* @param {goog.dom.DomHelper=} opt_domHelper DOM helper, used for DOM341* creation; defaults to the current document if unspecified.342* @return {!goog.ui.MenuButton} A menu button.343*/344goog.ui.editor.ToolbarFactory.makeMenuButton = function(345id, tooltip, caption, opt_classNames, opt_renderer, opt_domHelper) {346'use strict';347const button = new goog.ui.ToolbarMenuButton(348goog.ui.editor.ToolbarFactory.createContent_(349caption, opt_classNames, opt_domHelper),350null, opt_renderer, opt_domHelper);351button.setId(id);352button.setTooltip(tooltip);353return button;354};355356357/**358* Creates a select button with the given ID, tooltip, and caption. Applies359* any custom CSS class names to the button's root element. The button360* returned doesn't have an actual menu attached; use {@link361* goog.ui.Select#setMenu} to attach a {@link goog.ui.Menu} containing362* {@link goog.ui.Option}s to the select button.363* @param {string} id Button ID; must equal a {@link goog.editor.Command} for364* built-in buttons, anything else for custom buttons.365* @param {string} tooltip Tooltip to be shown on hover.366* @param {goog.ui.ControlContent} caption Button caption; used as the367* default caption when nothing is selected.368* @param {string=} opt_classNames CSS class name(s) to apply to the button's369* root element.370* @param {goog.ui.MenuButtonRenderer=} opt_renderer Button renderer;371* defaults to {@link goog.ui.ToolbarMenuButtonRenderer} if unspecified.372* @param {goog.dom.DomHelper=} opt_domHelper DOM helper, used for DOM373* creation; defaults to the current document if unspecified.374* @return {!goog.ui.Select} A select button.375*/376goog.ui.editor.ToolbarFactory.makeSelectButton = function(377id, tooltip, caption, opt_classNames, opt_renderer, opt_domHelper) {378'use strict';379const button =380new goog.ui.ToolbarSelect(null, null, opt_renderer, opt_domHelper);381if (opt_classNames) {382// Unlike the other button types, for goog.ui.Select buttons we apply the383// extra class names to the root element, because for select buttons the384// caption isn't stable (as it changes each time the selection changes).385opt_classNames.split(/\s+/).forEach(button.addClassName, button);386}387button.addClassName(goog.getCssName('goog-toolbar-select'));388button.setDefaultCaption(caption);389button.setId(id);390button.setTooltip(tooltip);391return button;392};393394395/**396* Creates a color menu button with the given ID, tooltip, and caption.397* Applies any custom CSS class names to the button's caption element. The398* button is created with a default color menu containing standard color399* palettes.400* @param {string} id Button ID; must equal a {@link goog.editor.Command} for401* built-in toolbar buttons, but can be anything else for custom buttons.402* @param {string} tooltip Tooltip to be shown on hover.403* @param {goog.ui.ControlContent} caption Button caption.404* @param {string=} opt_classNames CSS class name(s) to apply to the caption405* element.406* @param {goog.ui.ColorMenuButtonRenderer=} opt_renderer Button renderer;407* defaults to {@link goog.ui.ToolbarColorMenuButtonRenderer}408* if unspecified.409* @param {goog.dom.DomHelper=} opt_domHelper DOM helper, used for DOM410* creation; defaults to the current document if unspecified.411* @return {!goog.ui.ColorMenuButton} A color menu button.412*/413goog.ui.editor.ToolbarFactory.makeColorMenuButton = function(414id, tooltip, caption, opt_classNames, opt_renderer, opt_domHelper) {415'use strict';416const button = new goog.ui.ToolbarColorMenuButton(417goog.ui.editor.ToolbarFactory.createContent_(418caption, opt_classNames, opt_domHelper),419null, opt_renderer, opt_domHelper);420button.setId(id);421button.setTooltip(tooltip);422return button;423};424425426/**427* Creates a new DIV that wraps a button caption, optionally applying CSS428* class names to it. Used as a helper function in button factory methods.429* @param {goog.ui.ControlContent} caption Button caption.430* @param {string=} opt_classNames CSS class name(s) to apply to the DIV that431* wraps the caption (if any).432* @param {goog.dom.DomHelper=} opt_domHelper DOM helper, used for DOM433* creation; defaults to the current document if unspecified.434* @return {!Element} DIV that wraps the caption.435* @private436*/437goog.ui.editor.ToolbarFactory.createContent_ = function(438caption, opt_classNames, opt_domHelper) {439'use strict';440return (opt_domHelper || goog.dom.getDomHelper())441.createDom(goog.dom.TagName.DIV, opt_classNames, caption);442};443444445