All Downloads are FREE. Search and download functionalities are using the official Maven repository.

goog.tweak.tweakui.js Maven / Gradle / Ivy

// Copyright 2009 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 A UI for editing tweak settings / clicking tweak actions.
 *
 * @author [email protected] (Andrew Grieve)
 */

goog.provide('goog.tweak.EntriesPanel');
goog.provide('goog.tweak.TweakUi');

goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.dom.safe');
goog.require('goog.html.SafeHtml');
goog.require('goog.object');
goog.require('goog.string.Const');
goog.require('goog.style');
goog.require('goog.tweak');
goog.require('goog.tweak.BaseEntry');
goog.require('goog.tweak.BooleanGroup');
goog.require('goog.tweak.BooleanInGroupSetting');
goog.require('goog.tweak.BooleanSetting');
goog.require('goog.tweak.ButtonAction');
goog.require('goog.tweak.NumericSetting');
goog.require('goog.tweak.StringSetting');
goog.require('goog.ui.Zippy');
goog.require('goog.userAgent');



/**
 * A UI for editing tweak settings / clicking tweak actions.
 * @param {!goog.tweak.Registry} registry The registry to render.
 * @param {goog.dom.DomHelper=} opt_domHelper The DomHelper to render with.
 * @constructor
 * @final
 */
goog.tweak.TweakUi = function(registry, opt_domHelper) {
  /**
   * The registry to create a UI from.
   * @type {!goog.tweak.Registry}
   * @private
   */
  this.registry_ = registry;

  /**
   * The element to display when the UI is visible.
   * @type {goog.tweak.EntriesPanel|undefined}
   * @private
   */
  this.entriesPanel_;

  /**
   * The DomHelper to render with.
   * @type {!goog.dom.DomHelper}
   * @private
   */
  this.domHelper_ = opt_domHelper || goog.dom.getDomHelper();

  // Listen for newly registered entries (happens with lazy-loaded modules).
  registry.addOnRegisterListener(goog.bind(this.onNewRegisteredEntry_, this));
};


/**
 * The CSS class name unique to the root tweak panel div.
 * @type {string}
 * @private
 */
goog.tweak.TweakUi.ROOT_PANEL_CLASS_ = goog.getCssName('goog-tweak-root');


/**
 * The CSS class name unique to the tweak entry div.
 * @type {string}
 * @private
 */
goog.tweak.TweakUi.ENTRY_CSS_CLASS_ = goog.getCssName('goog-tweak-entry');


/**
 * The CSS classes for each tweak entry div.
 * @type {string}
 * @private
 */
goog.tweak.TweakUi.ENTRY_CSS_CLASSES_ = goog.tweak.TweakUi.ENTRY_CSS_CLASS_ +
    ' ' + goog.getCssName('goog-inline-block');


/**
 * The CSS classes for each namespace tweak entry div.
 * @type {string}
 * @private
 */
goog.tweak.TweakUi.ENTRY_GROUP_CSS_CLASSES_ =
    goog.tweak.TweakUi.ENTRY_CSS_CLASS_;


/**
 * Marker that the style sheet has already been installed.
 * @type {string}
 * @private
 */
goog.tweak.TweakUi.STYLE_SHEET_INSTALLED_MARKER_ = '__closure_tweak_installed_';


/**
 * CSS used by TweakUI.
 * @type {string}
 * @private
 */
goog.tweak.TweakUi.CSS_STYLES_ = (function() {
  var MOBILE = goog.userAgent.MOBILE;
  var IE = goog.userAgent.IE;
  var ENTRY_CLASS = '.' + goog.tweak.TweakUi.ENTRY_CSS_CLASS_;
  var ROOT_PANEL_CLASS = '.' + goog.tweak.TweakUi.ROOT_PANEL_CLASS_;
  var GOOG_INLINE_BLOCK_CLASS = '.' + goog.getCssName('goog-inline-block');
  var ret = ROOT_PANEL_CLASS + '{background:#ffc; padding:0 4px}';
  // Make this work even if the user hasn't included common.css.
  if (!IE) {
    ret += GOOG_INLINE_BLOCK_CLASS + '{display:inline-block}';
  }
  // Space things out vertically for touch UIs.
  if (MOBILE) {
    ret += ROOT_PANEL_CLASS + ',' + ROOT_PANEL_CLASS + ' fieldset{' +
        'line-height:2em;' +
        '}';
  }
  return ret;
})();


/**
 * Creates a TweakUi if tweaks are enabled.
 * @param {goog.dom.DomHelper=} opt_domHelper The DomHelper to render with.
 * @return {!Element|undefined} The root UI element or undefined if tweaks are
 *     not enabled.
 */
goog.tweak.TweakUi.create = function(opt_domHelper) {
  var registry = goog.tweak.getRegistry();
  if (registry) {
    var ui = new goog.tweak.TweakUi(registry, opt_domHelper);
    ui.render();
    return ui.getRootElement();
  }
};


/**
 * Creates a TweakUi inside of a show/hide link.
 * @param {goog.dom.DomHelper=} opt_domHelper The DomHelper to render with.
 * @return {!Element|undefined} The root UI element or undefined if tweaks are
 *     not enabled.
 */
goog.tweak.TweakUi.createCollapsible = function(opt_domHelper) {
  var registry = goog.tweak.getRegistry();
  if (registry) {
    var dh = opt_domHelper || goog.dom.getDomHelper();

    // The following strings are for internal debugging only.  No translation
    // necessary.  Do NOT wrap goog.getMsg() around these strings.
    var showLink =
        dh.createDom(goog.dom.TagName.A, {href: 'javascript:;'}, 'Show Tweaks');
    var hideLink =
        dh.createDom(goog.dom.TagName.A, {href: 'javascript:;'}, 'Hide Tweaks');
    var ret = dh.createDom(goog.dom.TagName.DIV, null, showLink);

    var lazyCreate = function() {
      // Lazily render the UI.
      var ui = new goog.tweak.TweakUi(
          /** @type {!goog.tweak.Registry} */ (registry), dh);
      ui.render();
      // Put the hide link on the same line as the "Show Descriptions" link.
      // Set the style lazily because we can.
      hideLink.style.marginRight = '10px';
      var tweakElem = ui.getRootElement();
      tweakElem.insertBefore(hideLink, tweakElem.firstChild);
      ret.appendChild(tweakElem);
      return tweakElem;
    };
    new goog.ui.Zippy(showLink, lazyCreate, false /* expanded */, hideLink);
    return ret;
  }
};


/**
 * Compares the given entries. Orders alphabetically and groups buttons and
 * expandable groups.
 * @param {!goog.tweak.BaseEntry} a The first entry to compare.
 * @param {!goog.tweak.BaseEntry} b The second entry to compare.
 * @return {number} Refer to goog.array.defaultCompare.
 * @private
 */
goog.tweak.TweakUi.entryCompare_ = function(a, b) {
  return (
      goog.array.defaultCompare(
          a instanceof goog.tweak.NamespaceEntry_,
          b instanceof goog.tweak.NamespaceEntry_) ||
      goog.array.defaultCompare(
          a instanceof goog.tweak.BooleanGroup,
          b instanceof goog.tweak.BooleanGroup) ||
      goog.array.defaultCompare(
          a instanceof goog.tweak.ButtonAction,
          b instanceof goog.tweak.ButtonAction) ||
      goog.array.defaultCompare(a.label, b.label) ||
      goog.array.defaultCompare(a.getId(), b.getId()));
};


/**
 * @param {!goog.tweak.BaseEntry} entry The entry.
 * @return {boolean} Returns whether the given entry contains sub-entries.
 * @private
 */
goog.tweak.TweakUi.isGroupEntry_ = function(entry) {
  return entry instanceof goog.tweak.NamespaceEntry_ ||
      entry instanceof goog.tweak.BooleanGroup;
};


/**
 * Returns the list of entries from the given boolean group.
 * @param {!goog.tweak.BooleanGroup} group The group to get the entries from.
 * @return {!Array} The sorted entries.
 * @private
 */
goog.tweak.TweakUi.extractBooleanGroupEntries_ = function(group) {
  var ret = goog.object.getValues(group.getChildEntries());
  ret.sort(goog.tweak.TweakUi.entryCompare_);
  return ret;
};


/**
 * @param {!goog.tweak.BaseEntry} entry The entry.
 * @return {string} Returns the namespace for the entry, or '' if it is not
 *     namespaced.
 * @private
 */
goog.tweak.TweakUi.extractNamespace_ = function(entry) {
  var namespaceMatch = /.+(?=\.)/.exec(entry.getId());
  return namespaceMatch ? namespaceMatch[0] : '';
};


/**
 * @param {!goog.tweak.BaseEntry} entry The entry.
 * @return {string} Returns the part of the label after the last period, unless
 *     the label has been explicly set (it is different from the ID).
 * @private
 */
goog.tweak.TweakUi.getNamespacedLabel_ = function(entry) {
  var label = entry.label;
  if (label == entry.getId()) {
    label = label.substr(label.lastIndexOf('.') + 1);
  }
  return label;
};


/**
 * @return {!Element} The root element. Must not be called before render().
 */
goog.tweak.TweakUi.prototype.getRootElement = function() {
  goog.asserts.assert(
      this.entriesPanel_, 'TweakUi.getRootElement called before render().');
  return this.entriesPanel_.getRootElement();
};


/**
 * Reloads the page with query parameters set by the UI.
 * @private
 */
goog.tweak.TweakUi.prototype.restartWithAppliedTweaks_ = function() {
  var queryString = this.registry_.makeUrlQuery();
  var wnd = this.domHelper_.getWindow();
  if (queryString != wnd.location.search) {
    wnd.location.search = queryString;
  } else {
    wnd.location.reload();
  }
};


/**
 * Installs the required CSS styles.
 * @private
 */
goog.tweak.TweakUi.prototype.installStyles_ = function() {
  // Use an marker to install the styles only once per document.
  // Styles are injected via JS instead of in a separate style sheet so that
  // they are automatically excluded when tweaks are stripped out.
  var doc = this.domHelper_.getDocument();
  if (!(goog.tweak.TweakUi.STYLE_SHEET_INSTALLED_MARKER_ in doc)) {
    goog.style.installStyles(goog.tweak.TweakUi.CSS_STYLES_, doc);
    doc[goog.tweak.TweakUi.STYLE_SHEET_INSTALLED_MARKER_] = true;
  }
};


/**
 * Creates the element to display when the UI is visible.
 * @return {!Element} The root element.
 */
goog.tweak.TweakUi.prototype.render = function() {
  this.installStyles_();
  var dh = this.domHelper_;
  // The submit button
  var submitButton = dh.createDom(
      goog.dom.TagName.BUTTON, {style: 'font-weight:bold'}, 'Apply Tweaks');
  submitButton.onclick = goog.bind(this.restartWithAppliedTweaks_, this);

  var rootPanel = new goog.tweak.EntriesPanel([], dh);
  var rootPanelDiv = rootPanel.render(submitButton);
  rootPanelDiv.className += ' ' + goog.tweak.TweakUi.ROOT_PANEL_CLASS_;
  this.entriesPanel_ = rootPanel;

  var entries = this.registry_.extractEntries(
      true /* excludeChildEntries */, false /* excludeNonSettings */);
  for (var i = 0, entry; entry = entries[i]; i++) {
    this.insertEntry_(entry);
  }

  return rootPanelDiv;
};


/**
 * Updates the UI with the given entry.
 * @param {!goog.tweak.BaseEntry} entry The newly registered entry.
 * @private
 */
goog.tweak.TweakUi.prototype.onNewRegisteredEntry_ = function(entry) {
  if (this.entriesPanel_) {
    this.insertEntry_(entry);
  }
};


/**
 * Updates the UI with the given entry.
 * @param {!goog.tweak.BaseEntry} entry The newly registered entry.
 * @private
 */
goog.tweak.TweakUi.prototype.insertEntry_ = function(entry) {
  var panel = this.entriesPanel_;
  var namespace = goog.tweak.TweakUi.extractNamespace_(entry);

  if (namespace) {
    // Find the NamespaceEntry that the entry belongs to.
    var namespaceEntryId = goog.tweak.NamespaceEntry_.ID_PREFIX + namespace;
    var nsPanel = panel.childPanels[namespaceEntryId];
    if (nsPanel) {
      panel = nsPanel;
    } else {
      entry = new goog.tweak.NamespaceEntry_(namespace, [entry]);
    }
  }
  if (entry instanceof goog.tweak.BooleanInGroupSetting) {
    var group = entry.getGroup();
    // BooleanGroup entries are always registered before their
    // BooleanInGroupSettings.
    panel = panel.childPanels[group.getId()];
  }
  goog.asserts.assert(panel, 'Missing panel for entry %s', entry.getId());
  panel.insertEntry(entry);
};



/**
 * The body of the tweaks UI and also used for BooleanGroup.
 * @param {!Array} entries The entries to show in the
 *     panel.
 * @param {goog.dom.DomHelper=} opt_domHelper The DomHelper to render with.
 * @constructor
 * @final
 */
goog.tweak.EntriesPanel = function(entries, opt_domHelper) {
  /**
   * The entries to show in the panel.
   * @type {!Array} entries
   * @private
   */
  this.entries_ = entries;

  var self = this;
  /**
   * The bound onclick handler for the help question marks.
   * @this {Element}
   * @private
   */
  this.boundHelpOnClickHandler_ = function() {
    self.onHelpClick_(this.parentNode);
  };

  /**
   * The element that contains the UI.
   * @type {Element}
   * @private
   */
  this.rootElem_;

  /**
   * The element that contains all of the settings and the endElement.
   * @type {Element}
   * @private
   */
  this.mainPanel_;

  /**
   * Flips between true/false each time the "Toggle Descriptions" link is
   * clicked.
   * @type {boolean}
   * @private
   */
  this.showAllDescriptionsState_;

  /**
   * The DomHelper to render with.
   * @type {!goog.dom.DomHelper}
   * @private
   */
  this.domHelper_ = opt_domHelper || goog.dom.getDomHelper();

  /**
   * Map of tweak ID -> EntriesPanel for child panels (BooleanGroups).
   * @type {!Object}
   */
  this.childPanels = {};
};


/**
 * @return {!Element} Returns the expanded element. Must not be called before
 *     render().
 */
goog.tweak.EntriesPanel.prototype.getRootElement = function() {
  goog.asserts.assert(
      this.rootElem_, 'EntriesPanel.getRootElement called before render().');
  return /** @type {!Element} */ (this.rootElem_);
};


/**
 * Creates and returns the expanded element.
 * The markup looks like:
 *
 *    
* Show Descriptions *
* ... * {endElement} *
*
* * @param {Element|DocumentFragment=} opt_endElement Element to insert after all * tweak entries. * @return {!Element} The root element for the panel. */ goog.tweak.EntriesPanel.prototype.render = function(opt_endElement) { var dh = this.domHelper_; var entries = this.entries_; var ret = dh.createDom(goog.dom.TagName.DIV); var showAllDescriptionsLink = dh.createDom( goog.dom.TagName.A, { href: 'javascript:;', onclick: goog.bind(this.toggleAllDescriptions, this) }, 'Toggle all Descriptions'); ret.appendChild(showAllDescriptionsLink); // Add all of the entries. var mainPanel = dh.createElement(goog.dom.TagName.DIV); this.mainPanel_ = mainPanel; for (var i = 0, entry; entry = entries[i]; i++) { mainPanel.appendChild(this.createEntryElem_(entry)); } if (opt_endElement) { mainPanel.appendChild(opt_endElement); } ret.appendChild(mainPanel); this.rootElem_ = ret; return /** @type {!Element} */ (ret); }; /** * Inserts the given entry into the panel. * @param {!goog.tweak.BaseEntry} entry The entry to insert. */ goog.tweak.EntriesPanel.prototype.insertEntry = function(entry) { var insertIndex = -goog.array.binarySearch( this.entries_, entry, goog.tweak.TweakUi.entryCompare_) - 1; goog.asserts.assert( insertIndex >= 0, 'insertEntry failed for %s', entry.getId()); goog.array.insertAt(this.entries_, entry, insertIndex); this.mainPanel_.insertBefore( this.createEntryElem_(entry), // IE doesn't like 'undefined' here. this.mainPanel_.childNodes[insertIndex] || null); }; /** * Creates and returns a form element for the given entry. * @param {!goog.tweak.BaseEntry} entry The entry. * @return {!Element} The root DOM element for the entry. * @private */ goog.tweak.EntriesPanel.prototype.createEntryElem_ = function(entry) { var dh = this.domHelper_; var isGroupEntry = goog.tweak.TweakUi.isGroupEntry_(entry); var classes = isGroupEntry ? goog.tweak.TweakUi.ENTRY_GROUP_CSS_CLASSES_ : goog.tweak.TweakUi.ENTRY_CSS_CLASSES_; // Containers should not use label tags or else all descendent inputs will be // connected on desktop browsers. var containerNodeName = isGroupEntry ? goog.dom.TagName.SPAN : goog.dom.TagName.LABEL; var ret = dh.createDom( goog.dom.TagName.DIV, classes, dh.createDom( containerNodeName, { // Make the hover text the description. title: entry.description, style: 'color:' + (entry.isRestartRequired() ? '' : 'blue') }, this.createTweakEntryDom_(entry)), // Add the expandable help question mark. this.createHelpElem_(entry)); return ret; }; /** * Click handler for the help link. * @param {Node} entryDiv The div that contains the tweak. * @private */ goog.tweak.EntriesPanel.prototype.onHelpClick_ = function(entryDiv) { this.showDescription_(entryDiv, !entryDiv.style.display); }; /** * Twiddle the DOM so that the entry within the given span is shown/hidden. * @param {Node} entryDiv The div that contains the tweak. * @param {boolean} show True to show, false to hide. * @private */ goog.tweak.EntriesPanel.prototype.showDescription_ = function(entryDiv, show) { var descriptionElem = entryDiv.lastChild.lastChild; goog.style.setElementShown(/** @type {Element} */ (descriptionElem), show); entryDiv.style.display = show ? 'block' : ''; }; /** * Creates and returns a help element for the given entry. * @param {goog.tweak.BaseEntry} entry The entry. * @return {!Element} The root element of the created DOM. * @private */ goog.tweak.EntriesPanel.prototype.createHelpElem_ = function(entry) { // The markup looks like: // ?{description} var ret = this.domHelper_.createElement(goog.dom.TagName.SPAN); goog.dom.safe.setInnerHtml( ret, goog.html.SafeHtml.concat( goog.html.SafeHtml.create( 'b', {'style': goog.string.Const.from('padding:0 1em 0 .5em')}, '?'), goog.html.SafeHtml.create( 'span', {'style': goog.string.Const.from('display:none;color:#666')}))); ret.onclick = this.boundHelpOnClickHandler_; // IE<9 doesn't support lastElementChild. var descriptionElem = /** @type {!Element} */ (ret.lastChild); if (entry.isRestartRequired()) { goog.dom.setTextContent(descriptionElem, entry.description); } else { goog.dom.safe.setInnerHtml( descriptionElem, goog.html.SafeHtml.concat( goog.html.SafeHtml.htmlEscape(entry.description), goog.html.SafeHtml.create( 'span', {'style': goog.string.Const.from('color: blue')}, '(no restart required)'))); } return ret; }; /** * Show all entry descriptions (has the same effect as clicking on all ?'s). */ goog.tweak.EntriesPanel.prototype.toggleAllDescriptions = function() { var show = !this.showAllDescriptionsState_; this.showAllDescriptionsState_ = show; var entryDivs = this.domHelper_.getElementsByTagNameAndClass( goog.dom.TagName.DIV, goog.tweak.TweakUi.ENTRY_CSS_CLASS_, this.rootElem_); for (var i = 0, div; div = entryDivs[i]; i++) { this.showDescription_(div, show); } }; /** * Creates the DOM element to control the given enum setting. * @param {!goog.tweak.StringSetting|!goog.tweak.NumericSetting} tweak The * setting. * @param {string} label The label for the entry. * @param {!Function} onchangeFunc onchange event handler. * @return {!DocumentFragment} The DOM element. * @private */ goog.tweak.EntriesPanel.prototype.createComboBoxDom_ = function( tweak, label, onchangeFunc) { // The markup looks like: // Label: var dh = this.domHelper_; var ret = dh.getDocument().createDocumentFragment(); ret.appendChild(dh.createTextNode(label + ': ')); var selectElem = dh.createElement(goog.dom.TagName.SELECT); var values = tweak.getValidValues(); for (var i = 0, il = values.length; i < il; ++i) { var optionElem = dh.createElement(goog.dom.TagName.OPTION); optionElem.text = String(values[i]); // Setting the option tag's value is required for selectElem.value to work // properly. optionElem.value = String(values[i]); selectElem.appendChild(optionElem); } ret.appendChild(selectElem); // Set the value and add a callback. selectElem.value = tweak.getNewValue(); selectElem.onchange = onchangeFunc; tweak.addCallback(function() { selectElem.value = tweak.getNewValue(); }); return ret; }; /** * Creates the DOM element to control the given boolean setting. * @param {!goog.tweak.BooleanSetting} tweak The setting. * @param {string} label The label for the entry. * @return {!DocumentFragment} The DOM elements. * @private */ goog.tweak.EntriesPanel.prototype.createBooleanSettingDom_ = function( tweak, label) { var dh = this.domHelper_; var ret = dh.getDocument().createDocumentFragment(); var checkbox = dh.createDom(goog.dom.TagName.INPUT, {type: 'checkbox'}); ret.appendChild(checkbox); ret.appendChild(dh.createTextNode(label)); // Needed on IE6 to ensure the textbox doesn't get cleared // when added to the DOM. checkbox.defaultChecked = tweak.getNewValue(); checkbox.checked = tweak.getNewValue(); checkbox.onchange = function() { tweak.setValue(checkbox.checked); }; tweak.addCallback(function() { checkbox.checked = tweak.getNewValue(); }); return ret; }; /** * Creates the DOM for a BooleanGroup or NamespaceEntry. * @param {!goog.tweak.BooleanGroup|!goog.tweak.NamespaceEntry_} entry The * entry. * @param {string} label The label for the entry. * @param {!Array} childEntries The child entries. * @return {!DocumentFragment} The DOM element. * @private */ goog.tweak.EntriesPanel.prototype.createSubPanelDom_ = function( entry, label, childEntries) { var dh = this.domHelper_; var toggleLink = dh.createDom(goog.dom.TagName.A, {href: 'javascript:;'}, label + ' \xBB'); var toggleLink2 = dh.createDom(goog.dom.TagName.A, {href: 'javascript:;'}, '\xAB ' + label); toggleLink2.style.marginRight = '10px'; var innerUi = new goog.tweak.EntriesPanel(childEntries, dh); this.childPanels[entry.getId()] = innerUi; var elem = innerUi.render(); // Move the toggle descriptions link into the legend. var descriptionsLink = elem.firstChild; var childrenElem = dh.createDom( goog.dom.TagName.FIELDSET, goog.getCssName('goog-inline-block'), dh.createDom( goog.dom.TagName.LEGEND, null, toggleLink2, descriptionsLink), elem); new goog.ui.Zippy( toggleLink, childrenElem, false /* expanded */, toggleLink2); var ret = dh.getDocument().createDocumentFragment(); ret.appendChild(toggleLink); ret.appendChild(childrenElem); return ret; }; /** * Creates the DOM element to control the given string setting. * @param {!goog.tweak.StringSetting|!goog.tweak.NumericSetting} tweak The * setting. * @param {string} label The label for the entry. * @param {!Function} onchangeFunc onchange event handler. * @return {!DocumentFragment} The DOM element. * @private */ goog.tweak.EntriesPanel.prototype.createTextBoxDom_ = function( tweak, label, onchangeFunc) { var dh = this.domHelper_; var ret = dh.getDocument().createDocumentFragment(); ret.appendChild(dh.createTextNode(label + ': ')); var textBox = dh.createDom(goog.dom.TagName.INPUT, { value: tweak.getNewValue(), // TODO(agrieve): Make size configurable or autogrow. size: 5, onblur: onchangeFunc }); ret.appendChild(textBox); tweak.addCallback(function() { textBox.value = tweak.getNewValue(); }); return ret; }; /** * Creates the DOM element to control the given button action. * @param {!goog.tweak.ButtonAction} tweak The action. * @param {string} label The label for the entry. * @return {!Element} The DOM element. * @private */ goog.tweak.EntriesPanel.prototype.createButtonActionDom_ = function( tweak, label) { return this.domHelper_.createDom( goog.dom.TagName.BUTTON, {onclick: goog.bind(tweak.fireCallbacks, tweak)}, label); }; /** * Creates the DOM element to control the given entry. * @param {!goog.tweak.BaseEntry} entry The entry. * @return {!Element|!DocumentFragment} The DOM element. * @private */ goog.tweak.EntriesPanel.prototype.createTweakEntryDom_ = function(entry) { var label = goog.tweak.TweakUi.getNamespacedLabel_(entry); if (entry instanceof goog.tweak.BooleanSetting) { return this.createBooleanSettingDom_(entry, label); } else if (entry instanceof goog.tweak.BooleanGroup) { var childEntries = goog.tweak.TweakUi.extractBooleanGroupEntries_(entry); return this.createSubPanelDom_(entry, label, childEntries); } else if (entry instanceof goog.tweak.StringSetting) { /** @this {Element} */ var setValueFunc = function() { entry.setValue(this.value); }; return entry.getValidValues() ? this.createComboBoxDom_(entry, label, setValueFunc) : this.createTextBoxDom_(entry, label, setValueFunc); } else if (entry instanceof goog.tweak.NumericSetting) { setValueFunc = function() { // Reset the value if it's not a number. if (isNaN(this.value)) { this.value = entry.getNewValue(); } else { entry.setValue(+this.value); } }; return entry.getValidValues() ? this.createComboBoxDom_(entry, label, setValueFunc) : this.createTextBoxDom_(entry, label, setValueFunc); } else if (entry instanceof goog.tweak.NamespaceEntry_) { return this.createSubPanelDom_(entry, entry.label, entry.entries); } goog.asserts.assertInstanceof( entry, goog.tweak.ButtonAction, 'invalid entry: %s', entry); return this.createButtonActionDom_( /** @type {!goog.tweak.ButtonAction} */ (entry), label); }; /** * Entries used to represent the collapsible namespace links. These entries are * never registered with the TweakRegistry, but are contained within the * collection of entries within TweakPanels. * @param {string} namespace The namespace for the entry. * @param {!Array} entries Entries within the namespace. * @constructor * @extends {goog.tweak.BaseEntry} * @private */ goog.tweak.NamespaceEntry_ = function(namespace, entries) { goog.tweak.BaseEntry.call( this, goog.tweak.NamespaceEntry_.ID_PREFIX + namespace, 'Tweaks within the ' + namespace + ' namespace.'); /** * Entries within this namespace. * @type {!Array} */ this.entries = entries; this.label = namespace; }; goog.inherits(goog.tweak.NamespaceEntry_, goog.tweak.BaseEntry); /** * Prefix for the IDs of namespace entries used to ensure that they do not * conflict with regular entries. * @type {string} */ goog.tweak.NamespaceEntry_.ID_PREFIX = '!';




© 2015 - 2025 Weber Informatics LLC | Privacy Policy