Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6267)

Unified Diff: chrome/browser/resources/md_downloads/crisper.js

Issue 2252963002: MD WebUI: Strip comments from vulcanized JS files (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@history_vulcanize
Patch Set: Fix comments ending in **/ Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/resources/md_downloads/crisper.js
diff --git a/chrome/browser/resources/md_downloads/crisper.js b/chrome/browser/resources/md_downloads/crisper.js
index af749f7d2cee0307838c479506c8866e1ee7500d..9beae376ead6b15a4bbacff696d9854315bb69ef 100644
--- a/chrome/browser/resources/md_downloads/crisper.js
+++ b/chrome/browser/resources/md_downloads/crisper.js
@@ -2,19 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-/**
- * @fileoverview Assertion support.
- */
-
-/**
- * Verify |condition| is truthy and return |condition| if so.
- * @template T
- * @param {T} condition A condition to check for truthiness. Note that this
- * may be used to test whether a value is defined or not, and we don't want
- * to force a cast to Boolean.
- * @param {string=} opt_message A message to show on failure.
- * @return {T} A non-null |condition|.
- */
+
function assert(condition, opt_message) {
if (!condition) {
var message = 'Assertion failed';
@@ -29,41 +17,11 @@ function assert(condition, opt_message) {
return condition;
}
-/**
- * Call this from places in the code that should never be reached.
- *
- * For example, handling all the values of enum with a switch() like this:
- *
- * function getValueFromEnum(enum) {
- * switch (enum) {
- * case ENUM_FIRST_OF_TWO:
- * return first
- * case ENUM_LAST_OF_TWO:
- * return last;
- * }
- * assertNotReached();
- * return document;
- * }
- *
- * This code should only be hit in the case of serious programmer error or
- * unexpected input.
- *
- * @param {string=} opt_message A message to show when this is hit.
- */
function assertNotReached(opt_message) {
assert(false, opt_message || 'Unreachable code hit');
}
-/**
- * @param {*} value The value to check.
- * @param {function(new: T, ...)} type A user-defined constructor.
- * @param {string=} opt_message A message to show when this is hit.
- * @return {T}
- * @template T
- */
function assertInstanceof(value, type, opt_message) {
- // We don't use assert immediately here so that we avoid constructing an error
- // message if we don't have to.
if (!(value instanceof type)) {
assertNotReached(opt_message || 'Value ' + value +
' is not a[n] ' + (type.name || typeof type));
@@ -74,24 +32,7 @@ function assertInstanceof(value, type, opt_message) {
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-/**
- * @fileoverview PromiseResolver is a helper class that allows creating a
- * Promise that will be fulfilled (resolved or rejected) some time later.
- *
- * Example:
- * var resolver = new PromiseResolver();
- * resolver.promise.then(function(result) {
- * console.log('resolved with', result);
- * });
- * ...
- * ...
- * resolver.resolve({hello: 'world'});
- */
-
-/**
- * @constructor @struct
- * @template T
- */
+
function PromiseResolver() {
/** @private {function(T=): void} */
this.resolve_;
@@ -123,11 +64,6 @@ PromiseResolver.prototype = {
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-/**
- * The global object.
- * @type {!Object}
- * @const
- */
var global = this;
/** @typedef {{eventName: string, uid: number}} */
@@ -137,26 +73,12 @@ var WebUIListener;
var cr = cr || function() {
'use strict';
- /**
- * Builds an object structure for the provided namespace path,
- * ensuring that names that already exist are not overwritten. For
- * example:
- * "a.b.c" -> a = {};a.b={};a.b.c={};
- * @param {string} name Name of the object that this file defines.
- * @param {*=} opt_object The object to expose at the end of the path.
- * @param {Object=} opt_objectToExportTo The object to add the path to;
- * default is {@code global}.
- * @return {!Object} The last object exported (i.e. exportPath('cr.ui')
- * returns a reference to the ui property of window.cr).
- * @private
- */
function exportPath(name, opt_object, opt_objectToExportTo) {
var parts = name.split('.');
var cur = opt_objectToExportTo || global;
for (var part; parts.length && (part = parts.shift());) {
if (!parts.length && opt_object !== undefined) {
- // last part and we have an object; use it
cur[part] = opt_object;
} else if (part in cur) {
cur = cur[part];
@@ -167,13 +89,6 @@ var cr = cr || function() {
return cur;
}
- /**
- * Fires a property change event on the target.
- * @param {EventTarget} target The target to dispatch the event on.
- * @param {string} propertyName The name of the property that changed.
- * @param {*} newValue The new value for the property.
- * @param {*} oldValue The old value for the property.
- */
function dispatchPropertyChange(target, propertyName, newValue, oldValue) {
var e = new Event(propertyName + 'Change');
e.propertyName = propertyName;
@@ -182,50 +97,18 @@ var cr = cr || function() {
target.dispatchEvent(e);
}
- /**
- * Converts a camelCase javascript property name to a hyphenated-lower-case
- * attribute name.
- * @param {string} jsName The javascript camelCase property name.
- * @return {string} The equivalent hyphenated-lower-case attribute name.
- */
function getAttributeName(jsName) {
return jsName.replace(/([A-Z])/g, '-$1').toLowerCase();
}
- /**
- * The kind of property to define in {@code defineProperty}.
- * @enum {string}
- * @const
- */
var PropertyKind = {
- /**
- * Plain old JS property where the backing data is stored as a "private"
- * field on the object.
- * Use for properties of any type. Type will not be checked.
- */
JS: 'js',
- /**
- * The property backing data is stored as an attribute on an element.
- * Use only for properties of type {string}.
- */
ATTR: 'attr',
- /**
- * The property backing data is stored as an attribute on an element. If the
- * element has the attribute then the value is true.
- * Use only for properties of type {boolean}.
- */
BOOL_ATTR: 'boolAttr'
};
- /**
- * Helper function for defineProperty that returns the getter to use for the
- * property.
- * @param {string} name The name of the property.
- * @param {PropertyKind} kind The kind of the property.
- * @return {function():*} The getter for the property.
- */
function getGetter(name, kind) {
switch (kind) {
case PropertyKind.JS:
@@ -245,22 +128,9 @@ var cr = cr || function() {
};
}
- // TODO(dbeam): replace with assertNotReached() in assert.js when I can coax
- // the browser/unit tests to preprocess this file through grit.
throw 'not reached';
}
- /**
- * Helper function for defineProperty that returns the setter of the right
- * kind.
- * @param {string} name The name of the property we are defining the setter
- * for.
- * @param {PropertyKind} kind The kind of property we are getting the
- * setter for.
- * @param {function(*, *):void=} opt_setHook A function to run after the
- * property is set, but before the propertyChange event is fired.
- * @return {function(*):void} The function to use as a setter.
- */
function getSetter(name, kind, opt_setHook) {
switch (kind) {
case PropertyKind.JS:
@@ -306,20 +176,9 @@ var cr = cr || function() {
};
}
- // TODO(dbeam): replace with assertNotReached() in assert.js when I can coax
- // the browser/unit tests to preprocess this file through grit.
throw 'not reached';
}
- /**
- * Defines a property on an object. When the setter changes the value a
- * property change event with the type {@code name + 'Change'} is fired.
- * @param {!Object} obj The object to define the property for.
- * @param {string} name The name of the property.
- * @param {PropertyKind=} opt_kind What kind of underlying storage to use.
- * @param {function(*, *):void=} opt_setHook A function to run after the
- * property is set, but before the propertyChange event is fired.
- */
function defineProperty(obj, name, opt_kind, opt_setHook) {
if (typeof obj == 'function')
obj = obj.prototype;
@@ -333,40 +192,18 @@ var cr = cr || function() {
obj.__defineSetter__(name, getSetter(name, kind, opt_setHook));
}
- /**
- * Counter for use with createUid
- */
var uidCounter = 1;
- /**
- * @return {number} A new unique ID.
- */
function createUid() {
return uidCounter++;
}
- /**
- * Returns a unique ID for the item. This mutates the item so it needs to be
- * an object
- * @param {!Object} item The item to get the unique ID for.
- * @return {number} The unique ID for the item.
- */
function getUid(item) {
if (item.hasOwnProperty('uid'))
return item.uid;
return item.uid = createUid();
}
- /**
- * Dispatches a simple event on an event target.
- * @param {!EventTarget} target The event target to dispatch the event on.
- * @param {string} type The type of the event.
- * @param {boolean=} opt_bubbles Whether the event bubbles or not.
- * @param {boolean=} opt_cancelable Whether the default action of the event
- * can be prevented. Default is true.
- * @return {boolean} If any of the listeners called {@code preventDefault}
- * during the dispatch this will return false.
- */
function dispatchSimpleEvent(target, type, opt_bubbles, opt_cancelable) {
var e = new Event(type, {
bubbles: opt_bubbles,
@@ -375,32 +212,10 @@ var cr = cr || function() {
return target.dispatchEvent(e);
}
- /**
- * Calls |fun| and adds all the fields of the returned object to the object
- * named by |name|. For example, cr.define('cr.ui', function() {
- * function List() {
- * ...
- * }
- * function ListItem() {
- * ...
- * }
- * return {
- * List: List,
- * ListItem: ListItem,
- * };
- * });
- * defines the functions cr.ui.List and cr.ui.ListItem.
- * @param {string} name The name of the object that we are adding fields to.
- * @param {!Function} fun The function that will return an object containing
- * the names and values of the new fields.
- */
function define(name, fun) {
var obj = exportPath(name);
var exports = fun();
for (var propertyName in exports) {
- // Maybe we should check the prototype chain here? The current usage
- // pattern is always using an object literal so we only care about own
- // properties.
var propertyDescriptor = Object.getOwnPropertyDescriptor(exports,
propertyName);
if (propertyDescriptor)
@@ -408,26 +223,12 @@ var cr = cr || function() {
}
}
- /**
- * Adds a {@code getInstance} static method that always return the same
- * instance object.
- * @param {!Function} ctor The constructor for the class to add the static
- * method to.
- */
function addSingletonGetter(ctor) {
ctor.getInstance = function() {
return ctor.instance_ || (ctor.instance_ = new ctor());
};
}
- /**
- * Forwards public APIs to private implementations.
- * @param {Function} ctor Constructor that have private implementations in its
- * prototype.
- * @param {Array<string>} methods List of public method names that have their
- * underscored counterparts in constructor's prototype.
- * @param {string=} opt_target Selector for target node.
- */
function makePublic(ctor, methods, opt_target) {
methods.forEach(function(method) {
ctor[method] = function() {
@@ -438,28 +239,8 @@ var cr = cr || function() {
});
}
- /**
- * The mapping used by the sendWithPromise mechanism to tie the Promise
- * returned to callers with the corresponding WebUI response. The mapping is
- * from ID to the PromiseResolver helper; the ID is generated by
- * sendWithPromise and is unique across all invocations of said method.
- * @type {!Object<!PromiseResolver>}
- */
var chromeSendResolverMap = {};
- /**
- * The named method the WebUI handler calls directly in response to a
- * chrome.send call that expects a response. The handler requires no knowledge
- * of the specific name of this method, as the name is passed to the handler
- * as the first argument in the arguments list of chrome.send. The handler
- * must pass the ID, also sent via the chrome.send arguments list, as the
- * first argument of the JS invocation; additionally, the handler may
- * supply any number of other arguments that will be included in the response.
- * @param {string} id The unique ID identifying the Promise this response is
- * tied to.
- * @param {boolean} isSuccess Whether the request was successful.
- * @param {*} response The response as sent from C++.
- */
function webUIResponse(id, isSuccess, response) {
var resolver = chromeSendResolverMap[id];
delete chromeSendResolverMap[id];
@@ -470,14 +251,6 @@ var cr = cr || function() {
resolver.reject(response);
}
- /**
- * A variation of chrome.send, suitable for messages that expect a single
- * response from C++.
- * @param {string} methodName The name of the WebUI handler API.
- * @param {...*} var_args Varibale number of arguments to be forwarded to the
- * C++ call.
- * @return {!Promise}
- */
function sendWithPromise(methodName, var_args) {
var args = Array.prototype.slice.call(arguments, 1);
var promiseResolver = new PromiseResolver();
@@ -487,28 +260,11 @@ var cr = cr || function() {
return promiseResolver.promise;
}
- /**
- * A map of maps associating event names with listeners. The 2nd level map
- * associates a listener ID with the callback function, such that individual
- * listeners can be removed from an event without affecting other listeners of
- * the same event.
- * @type {!Object<!Object<!Function>>}
- */
var webUIListenerMap = {};
- /**
- * The named method the WebUI handler calls directly when an event occurs.
- * The WebUI handler must supply the name of the event as the first argument
- * of the JS invocation; additionally, the handler may supply any number of
- * other arguments that will be forwarded to the listener callbacks.
- * @param {string} event The name of the event that has occurred.
- * @param {...*} var_args Additional arguments passed from C++.
- */
function webUIListenerCallback(event, var_args) {
var eventListenersMap = webUIListenerMap[event];
if (!eventListenersMap) {
- // C++ event sent for an event that has no listeners.
- // TODO(dpapad): Should a warning be displayed here?
return;
}
@@ -518,14 +274,6 @@ var cr = cr || function() {
}
}
- /**
- * Registers a listener for an event fired from WebUI handlers. Any number of
- * listeners may register for a single event.
- * @param {string} eventName The event to listen to.
- * @param {!Function} callback The callback run when the event is fired.
- * @return {!WebUIListener} An object to be used for removing a listener via
- * cr.removeWebUIListener. Should be treated as read-only.
- */
function addWebUIListener(eventName, callback) {
webUIListenerMap[eventName] = webUIListenerMap[eventName] || {};
var uid = createUid();
@@ -533,13 +281,6 @@ var cr = cr || function() {
return {eventName: eventName, uid: uid};
}
- /**
- * Removes a listener. Does nothing if the specified listener is not found.
- * @param {!WebUIListener} listener The listener to be removed (as returned by
- * addWebUIListener).
- * @return {boolean} Whether the given listener was found and actually
- * removed.
- */
function removeWebUIListener(listener) {
var listenerExists = webUIListenerMap[listener.eventName] &&
webUIListenerMap[listener.eventName][listener.uid];
@@ -562,7 +303,6 @@ var cr = cr || function() {
makePublic: makePublic,
PropertyKind: PropertyKind,
- // C++ <-> JS communication related methods.
addWebUIListener: addWebUIListener,
removeWebUIListener: removeWebUIListener,
sendWithPromise: sendWithPromise,
@@ -610,14 +350,6 @@ var cr = cr || function() {
cr.define('cr.ui', function() {
- /**
- * Decorates elements as an instance of a class.
- * @param {string|!Element} source The way to find the element(s) to decorate.
- * If this is a string then {@code querySeletorAll} is used to find the
- * elements to decorate.
- * @param {!Function} constr The constructor to decorate with. The constr
- * needs to have a {@code decorate} function.
- */
function decorate(source, constr) {
var elements;
if (typeof source == 'string')
@@ -631,11 +363,7 @@ cr.define('cr.ui', function() {
}
}
- /**
- * Helper function for creating new element for define.
- */
function createElementHelper(tagName, opt_bag) {
- // Allow passing in ownerDocument to create in a different document.
var doc;
if (opt_bag && opt_bag.ownerDocument)
doc = opt_bag.ownerDocument;
@@ -644,28 +372,6 @@ cr.define('cr.ui', function() {
return doc.createElement(tagName);
}
- /**
- * Creates the constructor for a UI element class.
- *
- * Usage:
- * <pre>
- * var List = cr.ui.define('list');
- * List.prototype = {
- * __proto__: HTMLUListElement.prototype,
- * decorate: function() {
- * ...
- * },
- * ...
- * };
- * </pre>
- *
- * @param {string|Function} tagNameOrFunction The tagName or
- * function to use for newly created elements. If this is a function it
- * needs to return a new element when called.
- * @return {function(Object=):Element} The constructor function which takes
- * an optional property bag. The function also has a static
- * {@code decorate} method added to it.
- */
function define(tagNameOrFunction) {
var createFunction, tagName;
if (typeof tagNameOrFunction == 'function') {
@@ -676,14 +382,6 @@ cr.define('cr.ui', function() {
tagName = tagNameOrFunction;
}
- /**
- * Creates a new UI element constructor.
- * @param {Object=} opt_propertyBag Optional bag of properties to set on the
- * object after created. The property {@code ownerDocument} is special
- * cased and it allows you to create the element in a different
- * document than the default.
- * @constructor
- */
function f(opt_propertyBag) {
var el = createFunction(tagName, opt_propertyBag);
f.decorate(el);
@@ -693,10 +391,6 @@ cr.define('cr.ui', function() {
return el;
}
- /**
- * Decorates an element as a UI element class.
- * @param {!Element} el The element to decorate.
- */
f.decorate = function(el) {
el.__proto__ = f.prototype;
el.decorate();
@@ -705,18 +399,7 @@ cr.define('cr.ui', function() {
return f;
}
- /**
- * Input elements do not grow and shrink with their content. This is a simple
- * (and not very efficient) way of handling shrinking to content with support
- * for min width and limited by the width of the parent element.
- * @param {!HTMLElement} el The element to limit the width for.
- * @param {!HTMLElement} parentEl The parent element that should limit the
- * size.
- * @param {number} min The minimum width.
- * @param {number=} opt_scale Optional scale factor to apply to the width.
- */
function limitInputWidth(el, parentEl, min, opt_scale) {
- // Needs a size larger than borders
el.style.width = '10px';
var doc = el.ownerDocument;
var win = doc.defaultView;
@@ -724,20 +407,16 @@ cr.define('cr.ui', function() {
var parentComputedStyle = win.getComputedStyle(parentEl);
var rtl = computedStyle.direction == 'rtl';
- // To get the max width we get the width of the treeItem minus the position
- // of the input.
var inputRect = el.getBoundingClientRect(); // box-sizing
var parentRect = parentEl.getBoundingClientRect();
var startPos = rtl ? parentRect.right - inputRect.right :
inputRect.left - parentRect.left;
- // Add up border and padding of the input.
var inner = parseInt(computedStyle.borderLeftWidth, 10) +
parseInt(computedStyle.paddingLeft, 10) +
parseInt(computedStyle.paddingRight, 10) +
parseInt(computedStyle.borderRightWidth, 10);
- // We also need to subtract the padding of parent to prevent it to overflow.
var parentPadding = rtl ? parseInt(parentComputedStyle.paddingLeft, 10) :
parseInt(parentComputedStyle.paddingRight, 10);
@@ -763,24 +442,12 @@ cr.define('cr.ui', function() {
limit();
}
- /**
- * Takes a number and spits out a value CSS will be happy with. To avoid
- * subpixel layout issues, the value is rounded to the nearest integral value.
- * @param {number} pixels The number of pixels.
- * @return {string} e.g. '16px'.
- */
function toCssPx(pixels) {
if (!window.isFinite(pixels))
console.error('Pixel value is not a number: ' + pixels);
return Math.round(pixels) + 'px';
}
- /**
- * Users complain they occasionaly use doubleclicks instead of clicks
- * (http://crbug.com/140364). To fix it we freeze click handling for
- * the doubleclick time interval.
- * @param {MouseEvent} e Initial click event.
- */
function swallowDoubleClick(e) {
var doc = e.target.ownerDocument;
var counter = Math.min(1, e.detail);
@@ -791,17 +458,12 @@ cr.define('cr.ui', function() {
function onclick(e) {
if (e.detail > counter) {
counter = e.detail;
- // Swallow the click since it's a click inside the doubleclick timeout.
swallow(e);
} else {
- // Stop tracking clicks and let regular handling.
doc.removeEventListener('dblclick', swallow, true);
doc.removeEventListener('click', onclick, true);
}
}
- // The following 'click' event (if e.type == 'mouseup') mustn't be taken
- // into account (it mustn't stop tracking clicks). Start event listening
- // after zero timeout.
setTimeout(function() {
doc.addEventListener('click', onclick, true);
doc.addEventListener('dblclick', swallow, true);
@@ -820,27 +482,9 @@ cr.define('cr.ui', function() {
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-/**
- * @fileoverview A command is an abstraction of an action a user can do in the
- * UI.
- *
- * When the focus changes in the document for each command a canExecute event
- * is dispatched on the active element. By listening to this event you can
- * enable and disable the command by setting the event.canExecute property.
- *
- * When a command is executed a command event is dispatched on the active
- * element. Note that you should stop the propagation after you have handled the
- * command if there might be other command listeners higher up in the DOM tree.
- */
cr.define('cr.ui', function() {
- /**
- * This is used to identify keyboard shortcuts.
- * @param {string} shortcut The text used to describe the keys for this
- * keyboard shortcut.
- * @constructor
- */
function KeyboardShortcut(shortcut) {
var mods = {};
var ident = '';
@@ -865,14 +509,8 @@ cr.define('cr.ui', function() {
}
KeyboardShortcut.prototype = {
- /**
- * Whether the keyboard shortcut object matches a keyboard event.
- * @param {!Event} e The keyboard event object.
- * @return {boolean} Whether we found a match or not.
- */
matchesEvent: function(e) {
if (e.key == this.ident_) {
- // All keyboard modifiers needs to match.
var mods = this.mods_;
return ['altKey', 'ctrlKey', 'metaKey', 'shiftKey'].every(function(k) {
return e[k] == !!mods[k];
@@ -882,19 +520,11 @@ cr.define('cr.ui', function() {
}
};
- /**
- * Creates a new command element.
- * @constructor
- * @extends {HTMLElement}
- */
var Command = cr.ui.define('command');
Command.prototype = {
__proto__: HTMLElement.prototype,
- /**
- * Initializes the command.
- */
decorate: function() {
CommandManager.init(assert(this.ownerDocument));
@@ -902,12 +532,6 @@ cr.define('cr.ui', function() {
this.shortcut = this.getAttribute('shortcut');
},
- /**
- * Executes the command by dispatching a command event on the given element.
- * If |element| isn't given, the active element is used instead.
- * If the command is {@code disabled} this does nothing.
- * @param {HTMLElement=} opt_element Optional element to dispatch event on.
- */
execute: function(opt_element) {
if (this.disabled)
return;
@@ -920,32 +544,11 @@ cr.define('cr.ui', function() {
}
},
- /**
- * Call this when there have been changes that might change whether the
- * command can be executed or not.
- * @param {Node=} opt_node Node for which to actuate command state.
- */
canExecuteChange: function(opt_node) {
dispatchCanExecuteEvent(this,
opt_node || this.ownerDocument.activeElement);
},
- /**
- * The keyboard shortcut that triggers the command. This is a string
- * consisting of a key (as reported by WebKit in keydown) as
- * well as optional key modifiers joinded with a '|'.
- *
- * Multiple keyboard shortcuts can be provided by separating them by
- * whitespace.
- *
- * For example:
- * "F1"
- * "Backspace|Meta" for Apple command backspace.
- * "a|Ctrl" for Control A
- * "Delete Backspace|Meta" for Delete and Command Backspace
- *
- * @type {string}
- */
shortcut_: '',
get shortcut() {
return this.shortcut_;
@@ -957,18 +560,12 @@ cr.define('cr.ui', function() {
return new KeyboardShortcut(shortcut);
});
- // Set this after the keyboardShortcuts_ since that might throw.
this.shortcut_ = shortcut;
cr.dispatchPropertyChange(this, 'shortcut', this.shortcut_,
oldShortcut);
}
},
- /**
- * Whether the event object matches the shortcut for this command.
- * @param {!Event} e The key event object.
- * @return {boolean} Whether it matched or not.
- */
matchesEvent: function(e) {
if (!this.keyboardShortcuts_)
return false;
@@ -979,68 +576,29 @@ cr.define('cr.ui', function() {
},
};
- /**
- * The label of the command.
- */
cr.defineProperty(Command, 'label', cr.PropertyKind.ATTR);
- /**
- * Whether the command is disabled or not.
- */
cr.defineProperty(Command, 'disabled', cr.PropertyKind.BOOL_ATTR);
- /**
- * Whether the command is hidden or not.
- */
cr.defineProperty(Command, 'hidden', cr.PropertyKind.BOOL_ATTR);
- /**
- * Whether the command is checked or not.
- */
cr.defineProperty(Command, 'checked', cr.PropertyKind.BOOL_ATTR);
- /**
- * The flag that prevents the shortcut text from being displayed on menu.
- *
- * If false, the keyboard shortcut text (eg. "Ctrl+X" for the cut command)
- * is displayed in menu when the command is assosiated with a menu item.
- * Otherwise, no text is displayed.
- */
cr.defineProperty(Command, 'hideShortcutText', cr.PropertyKind.BOOL_ATTR);
- /**
- * Dispatches a canExecute event on the target.
- * @param {!cr.ui.Command} command The command that we are testing for.
- * @param {EventTarget} target The target element to dispatch the event on.
- */
function dispatchCanExecuteEvent(command, target) {
var e = new CanExecuteEvent(command);
target.dispatchEvent(e);
command.disabled = !e.canExecute;
}
- /**
- * The command managers for different documents.
- */
var commandManagers = {};
- /**
- * Keeps track of the focused element and updates the commands when the focus
- * changes.
- * @param {!Document} doc The document that we are managing the commands for.
- * @constructor
- */
function CommandManager(doc) {
doc.addEventListener('focus', this.handleFocus_.bind(this), true);
- // Make sure we add the listener to the bubbling phase so that elements can
- // prevent the command.
doc.addEventListener('keydown', this.handleKeyDown_.bind(this), false);
}
- /**
- * Initializes a command manager for the document as needed.
- * @param {!Document} doc The document to manage the commands for.
- */
CommandManager.init = function(doc) {
var uid = cr.getUid(doc);
if (!(uid in commandManagers)) {
@@ -1050,17 +608,9 @@ cr.define('cr.ui', function() {
CommandManager.prototype = {
- /**
- * Handles focus changes on the document.
- * @param {Event} e The focus event object.
- * @private
- * @suppress {checkTypes}
- * TODO(vitalyp): remove the suppression.
- */
handleFocus_: function(e) {
var target = e.target;
- // Ignore focus on a menu button or command item.
if (target.menu || target.command)
return;
@@ -1072,10 +622,6 @@ cr.define('cr.ui', function() {
});
},
- /**
- * Handles the keydown event and routes it to the right command.
- * @param {!Event} e The keydown event.
- */
handleKeyDown_: function(e) {
var target = e.target;
var commands = Array.prototype.slice.call(
@@ -1083,14 +629,10 @@ cr.define('cr.ui', function() {
for (var i = 0, command; command = commands[i]; i++) {
if (command.matchesEvent(e)) {
- // When invoking a command via a shortcut, we have to manually check
- // if it can be executed, since focus might not have been changed
- // what would have updated the command's state.
command.canExecuteChange();
if (!command.disabled) {
e.preventDefault();
- // We do not want any other element to handle this.
e.stopPropagation();
command.execute();
return;
@@ -1100,13 +642,6 @@ cr.define('cr.ui', function() {
}
};
- /**
- * The event type used for canExecute events.
- * @param {!cr.ui.Command} command The command that we are evaluating.
- * @extends {Event}
- * @constructor
- * @class
- */
function CanExecuteEvent(command) {
var e = new Event('canExecute', {bubbles: true, cancelable: true});
e.__proto__ = CanExecuteEvent.prototype;
@@ -1117,18 +652,8 @@ cr.define('cr.ui', function() {
CanExecuteEvent.prototype = {
__proto__: Event.prototype,
- /**
- * The current command
- * @type {cr.ui.Command}
- */
command: null,
- /**
- * Whether the target can execute the command. Setting this also stops the
- * propagation and prevents the default. Callers can tell if an event has
- * been handled via |this.defaultPrevented|.
- * @type {boolean}
- */
canExecute_: false,
get canExecute() {
return this.canExecute_;
@@ -1140,7 +665,6 @@ cr.define('cr.ui', function() {
}
};
- // Export
return {
Command: Command,
CanExecuteEvent: CanExecuteEvent
@@ -1150,36 +674,17 @@ cr.define('cr.ui', function() {
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// <include src-disabled="assert.js">
-/**
- * Alias for document.getElementById. Found elements must be HTMLElements.
- * @param {string} id The ID of the element to find.
- * @return {HTMLElement} The found element or null if not found.
- */
function $(id) {
var el = document.getElementById(id);
return el ? assertInstanceof(el, HTMLElement) : null;
}
-// TODO(devlin): This should return SVGElement, but closure compiler is missing
-// those externs.
-/**
- * Alias for document.getElementById. Found elements must be SVGElements.
- * @param {string} id The ID of the element to find.
- * @return {Element} The found element or null if not found.
- */
function getSVGElement(id) {
var el = document.getElementById(id);
return el ? assertInstanceof(el, Element) : null;
}
-/**
- * Add an accessible message to the page that will be announced to
- * users who have spoken feedback on, but will be invisible to all
- * other users. It's removed right away so it doesn't clutter the DOM.
- * @param {string} msg The text to be pronounced.
- */
function announceAccessibleMessage(msg) {
var element = document.createElement('div');
element.setAttribute('aria-live', 'polite');
@@ -1193,30 +698,14 @@ function announceAccessibleMessage(msg) {
}, 0);
}
-/**
- * Generates a CSS url string.
- * @param {string} s The URL to generate the CSS url for.
- * @return {string} The CSS url string.
- */
function url(s) {
- // http://www.w3.org/TR/css3-values/#uris
- // Parentheses, commas, whitespace characters, single quotes (') and double
- // quotes (") appearing in a URI must be escaped with a backslash
var s2 = s.replace(/(\(|\)|\,|\s|\'|\"|\\)/g, '\\$1');
- // WebKit has a bug when it comes to URLs that end with \
- // https://bugs.webkit.org/show_bug.cgi?id=28885
if (/\\\\$/.test(s2)) {
- // Add a space to work around the WebKit bug.
s2 += ' ';
}
return 'url("' + s2 + '")';
}
-/**
- * Parses query parameters from Location.
- * @param {Location} location The URL to generate the CSS url for.
- * @return {Object} Dictionary containing name value pairs for URL
- */
function parseQueryParams(location) {
var params = {};
var query = unescape(location.search.substring(1));
@@ -1228,14 +717,6 @@ function parseQueryParams(location) {
return params;
}
-/**
- * Creates a new URL by appending or replacing the given query key and value.
- * Not supporting URL with username and password.
- * @param {Location} location The original URL.
- * @param {string} key The query parameter name.
- * @param {string} value The query parameter value.
- * @return {string} The constructed new URL.
- */
function setQueryParam(location, key, value) {
var query = parseQueryParams(location);
query[encodeURIComponent(key)] = encodeURIComponent(value);
@@ -1248,24 +729,12 @@ function setQueryParam(location, key, value) {
return location.origin + location.pathname + newQuery + location.hash;
}
-/**
- * @param {Node} el A node to search for ancestors with |className|.
- * @param {string} className A class to search for.
- * @return {Element} A node with class of |className| or null if none is found.
- */
function findAncestorByClass(el, className) {
return /** @type {Element} */(findAncestor(el, function(el) {
return el.classList && el.classList.contains(className);
}));
}
-/**
- * Return the first ancestor for which the {@code predicate} returns true.
- * @param {Node} node The node to check.
- * @param {function(Node):boolean} predicate The function that tests the
- * nodes.
- * @return {Node} The found ancestor or null if not found.
- */
function findAncestor(node, predicate) {
var last = false;
while (node != null && !(last = predicate(node))) {
@@ -1285,81 +754,43 @@ function swapDomNodes(a, b) {
aParent.insertBefore(b, afterA);
}
-/**
- * Disables text selection and dragging, with optional whitelist callbacks.
- * @param {function(Event):boolean=} opt_allowSelectStart Unless this function
- * is defined and returns true, the onselectionstart event will be
- * surpressed.
- * @param {function(Event):boolean=} opt_allowDragStart Unless this function
- * is defined and returns true, the ondragstart event will be surpressed.
- */
function disableTextSelectAndDrag(opt_allowSelectStart, opt_allowDragStart) {
- // Disable text selection.
document.onselectstart = function(e) {
if (!(opt_allowSelectStart && opt_allowSelectStart.call(this, e)))
e.preventDefault();
};
- // Disable dragging.
document.ondragstart = function(e) {
if (!(opt_allowDragStart && opt_allowDragStart.call(this, e)))
e.preventDefault();
};
}
-/**
- * TODO(dbeam): DO NOT USE. THIS IS DEPRECATED. Use an action-link instead.
- * Call this to stop clicks on <a href="#"> links from scrolling to the top of
- * the page (and possibly showing a # in the link).
- */
function preventDefaultOnPoundLinkClicks() {
document.addEventListener('click', function(e) {
var anchor = findAncestor(/** @type {Node} */(e.target), function(el) {
return el.tagName == 'A';
});
- // Use getAttribute() to prevent URL normalization.
if (anchor && anchor.getAttribute('href') == '#')
e.preventDefault();
});
}
-/**
- * Check the directionality of the page.
- * @return {boolean} True if Chrome is running an RTL UI.
- */
function isRTL() {
return document.documentElement.dir == 'rtl';
}
-/**
- * Get an element that's known to exist by its ID. We use this instead of just
- * calling getElementById and not checking the result because this lets us
- * satisfy the JSCompiler type system.
- * @param {string} id The identifier name.
- * @return {!HTMLElement} the Element.
- */
function getRequiredElement(id) {
return assertInstanceof($(id), HTMLElement,
'Missing required element: ' + id);
}
-/**
- * Query an element that's known to exist by a selector. We use this instead of
- * just calling querySelector and not checking the result because this lets us
- * satisfy the JSCompiler type system.
- * @param {string} selectors CSS selectors to query the element.
- * @param {(!Document|!DocumentFragment|!Element)=} opt_context An optional
- * context object for querySelector.
- * @return {!HTMLElement} the Element.
- */
function queryRequiredElement(selectors, opt_context) {
var element = (opt_context || document).querySelector(selectors);
return assertInstanceof(element, HTMLElement,
'Missing required element: ' + selectors);
}
-// Handle click on a link. If the link points to a chrome: or file: url, then
-// call into the browser to do the navigation.
['click', 'auxclick'].forEach(function(eventName) {
document.addEventListener(eventName, function(e) {
if (e.defaultPrevented)
@@ -1377,7 +808,6 @@ function queryRequiredElement(selectors, opt_context) {
}
}
- // Fallback if Event.path is not available.
var el = e.target;
if (!anchor && el.nodeType == Node.ELEMENT_NODE &&
el.webkitMatchesSelector('A, A *')) {
@@ -1407,14 +837,6 @@ function queryRequiredElement(selectors, opt_context) {
});
});
-/**
- * Creates a new URL which is the old URL with a GET param of key=value.
- * @param {string} url The base URL. There is not sanity checking on the URL so
- * it must be passed in a proper format.
- * @param {string} key The key of the param.
- * @param {string} value The value of the param.
- * @return {string} The new URL.
- */
function appendParam(url, key, value) {
var param = encodeURIComponent(key) + '=' + encodeURIComponent(value);
@@ -1423,33 +845,17 @@ function appendParam(url, key, value) {
return url + '&' + param;
}
-/**
- * Creates an element of a specified type with a specified class name.
- * @param {string} type The node type.
- * @param {string} className The class name to use.
- * @return {Element} The created element.
- */
function createElementWithClassName(type, className) {
var elm = document.createElement(type);
elm.className = className;
return elm;
}
-/**
- * webkitTransitionEnd does not always fire (e.g. when animation is aborted
- * or when no paint happens during the animation). This function sets up
- * a timer and emulate the event if it is not fired when the timer expires.
- * @param {!HTMLElement} el The element to watch for webkitTransitionEnd.
- * @param {number=} opt_timeOut The maximum wait time in milliseconds for the
- * webkitTransitionEnd to happen. If not specified, it is fetched from |el|
- * using the transitionDuration style value.
- */
function ensureTransitionEndEvent(el, opt_timeOut) {
if (opt_timeOut === undefined) {
var style = getComputedStyle(el);
opt_timeOut = parseFloat(style.transitionDuration) * 1000;
- // Give an additional 50ms buffer for the animation to complete.
opt_timeOut += 50;
}
@@ -1464,51 +870,22 @@ function ensureTransitionEndEvent(el, opt_timeOut) {
}, opt_timeOut);
}
-/**
- * Alias for document.scrollTop getter.
- * @param {!HTMLDocument} doc The document node where information will be
- * queried from.
- * @return {number} The Y document scroll offset.
- */
function scrollTopForDocument(doc) {
return doc.documentElement.scrollTop || doc.body.scrollTop;
}
-/**
- * Alias for document.scrollTop setter.
- * @param {!HTMLDocument} doc The document node where information will be
- * queried from.
- * @param {number} value The target Y scroll offset.
- */
function setScrollTopForDocument(doc, value) {
doc.documentElement.scrollTop = doc.body.scrollTop = value;
}
-/**
- * Alias for document.scrollLeft getter.
- * @param {!HTMLDocument} doc The document node where information will be
- * queried from.
- * @return {number} The X document scroll offset.
- */
function scrollLeftForDocument(doc) {
return doc.documentElement.scrollLeft || doc.body.scrollLeft;
}
-/**
- * Alias for document.scrollLeft setter.
- * @param {!HTMLDocument} doc The document node where information will be
- * queried from.
- * @param {number} value The target X scroll offset.
- */
function setScrollLeftForDocument(doc, value) {
doc.documentElement.scrollLeft = doc.body.scrollLeft = value;
}
-/**
- * Replaces '&', '<', '>', '"', and ''' characters with their HTML encoding.
- * @param {string} original The original string.
- * @return {string} The string with all the characters mentioned above replaced.
- */
function HTMLEscape(original) {
return original.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
@@ -1517,44 +894,24 @@ function HTMLEscape(original) {
.replace(/'/g, '&#39;');
}
-/**
- * Shortens the provided string (if necessary) to a string of length at most
- * |maxLength|.
- * @param {string} original The original string.
- * @param {number} maxLength The maximum length allowed for the string.
- * @return {string} The original string if its length does not exceed
- * |maxLength|. Otherwise the first |maxLength| - 1 characters with '...'
- * appended.
- */
function elide(original, maxLength) {
if (original.length <= maxLength)
return original;
return original.substring(0, maxLength - 1) + '\u2026';
}
-/**
- * Quote a string so it can be used in a regular expression.
- * @param {string} str The source string.
- * @return {string} The escaped string.
- */
function quoteString(str) {
return str.replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, '\\$1');
}
// <if expr="is_ios">
-// Polyfill 'key' in KeyboardEvent for iOS.
-// This function is not intended to be complete but should
-// be sufficient enough to have iOS work correctly while
-// it does not support key yet.
if (!('key' in KeyboardEvent.prototype)) {
Object.defineProperty(KeyboardEvent.prototype, 'key', {
/** @this {KeyboardEvent} */
get: function () {
- // 0-9
if (this.keyCode >= 0x30 && this.keyCode <= 0x39)
return String.fromCharCode(this.keyCode);
- // A-Z
if (this.keyCode >= 0x41 && this.keyCode <= 0x5a) {
var result = String.fromCharCode(this.keyCode).toLowerCase();
if (this.shiftKey)
@@ -1562,7 +919,6 @@ if (!('key' in KeyboardEvent.prototype)) {
return result;
}
- // Special characters
switch(this.keyCode) {
case 0x08: return 'Backspace';
case 0x09: return 'Tab';
@@ -1607,38 +963,13 @@ if (!('key' in KeyboardEvent.prototype)) {
window.console.log("KeyboardEvent.Key polyfill not required");
}
// </if> /* is_ios */
-/**
- * `IronResizableBehavior` is a behavior that can be used in Polymer elements to
- * coordinate the flow of resize events between "resizers" (elements that control the
- * size or hidden state of their children) and "resizables" (elements that need to be
- * notified when they are resized or un-hidden by their parents in order to take
- * action on their new measurements).
- *
- * Elements that perform measurement should add the `IronResizableBehavior` behavior to
- * their element definition and listen for the `iron-resize` event on themselves.
- * This event will be fired when they become showing after having been hidden,
- * when they are resized explicitly by another resizable, or when the window has been
- * resized.
- *
- * Note, the `iron-resize` event is non-bubbling.
- *
- * @polymerBehavior Polymer.IronResizableBehavior
- * @demo demo/index.html
- **/
Polymer.IronResizableBehavior = {
properties: {
- /**
- * The closest ancestor element that implements `IronResizableBehavior`.
- */
_parentResizable: {
type: Object,
observer: '_parentResizableChanged'
},
- /**
- * True if this element is currently notifying its descedant elements of
- * resize.
- */
_notifyingDescendant: {
type: Boolean,
value: false
@@ -1650,8 +981,6 @@ if (!('key' in KeyboardEvent.prototype)) {
},
created: function() {
- // We don't really need property effects on these, and also we want them
- // to be created before the `_parentResizable` observer fires:
this._interestedResizables = [];
this._boundNotifyResize = this.notifyResize.bind(this);
},
@@ -1679,10 +1008,6 @@ if (!('key' in KeyboardEvent.prototype)) {
this._parentResizable = null;
},
- /**
- * Can be called to manually notify a resizable and its descendant
- * resizables of a resize change.
- */
notifyResize: function() {
if (!this.isAttached) {
return;
@@ -1697,18 +1022,10 @@ if (!('key' in KeyboardEvent.prototype)) {
this._fireResize();
},
- /**
- * Used to assign the closest resizable ancestor to this resizable
- * if the ancestor detects a request for notifications.
- */
assignParentResizable: function(parentResizable) {
this._parentResizable = parentResizable;
},
- /**
- * Used to remove a resizable descendant from the list of descendants
- * that should be notified of a resize change.
- */
stopResizeNotificationsFor: function(target) {
var index = this._interestedResizables.indexOf(target);
@@ -1718,15 +1035,6 @@ if (!('key' in KeyboardEvent.prototype)) {
}
},
- /**
- * This method can be overridden to filter nested elements that should or
- * should not be notified by the current element. Return true if an element
- * should be notified, or false if it should not be notified.
- *
- * @param {HTMLElement} element A candidate descendant element that
- * implements `IronResizableBehavior`.
- * @return {boolean} True if the `element` should be notified of resize.
- */
resizerShouldNotify: function(element) { return true; },
_onDescendantIronResize: function(event) {
@@ -1735,9 +1043,6 @@ if (!('key' in KeyboardEvent.prototype)) {
return;
}
- // NOTE(cdata): In ShadowDOM, event retargetting makes echoing of the
- // otherwise non-bubbling event "just work." We do it manually here for
- // the case where Polymer is not using shadow roots for whatever reason:
if (!Polymer.Settings.useShadow) {
this._fireResize();
}
@@ -1775,9 +1080,6 @@ if (!('key' in KeyboardEvent.prototype)) {
},
_notifyDescendant: function(descendant) {
- // NOTE(cdata): In IE10, attached is fired on children first, so it's
- // important not to notify them if the parent is not attached yet (or
- // else they will get redundantly notified when the parent attaches).
if (!this.isAttached) {
return;
}
@@ -1790,12 +1092,6 @@ if (!('key' in KeyboardEvent.prototype)) {
(function() {
'use strict';
- /**
- * Chrome uses an older version of DOM Level 3 Keyboard Events
- *
- * Most keys are labeled as text, but some are Unicode codepoints.
- * Values taken from: http://www.w3.org/TR/2007/WD-DOM-Level-3-Events-20071221/keyset.html#KeySet-Set
- */
var KEY_IDENTIFIER = {
'U+0008': 'backspace',
'U+0009': 'tab',
@@ -1804,13 +1100,6 @@ if (!('key' in KeyboardEvent.prototype)) {
'U+007F': 'del'
};
- /**
- * Special table for KeyboardEvent.keyCode.
- * KeyboardEvent.keyIdentifier is better, and KeyBoardEvent.key is even better
- * than that.
- *
- * Values from: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.keyCode#Value_of_keyCode
- */
var KEY_CODE = {
8: 'backspace',
9: 'tab',
@@ -1829,11 +1118,6 @@ if (!('key' in KeyboardEvent.prototype)) {
106: '*'
};
- /**
- * MODIFIER_KEYS maps the short name for modifier keys used in a key
- * combo string to the property name that references those same keys
- * in a KeyboardEvent instance.
- */
var MODIFIER_KEYS = {
'shift': 'shiftKey',
'ctrl': 'ctrlKey',
@@ -1841,44 +1125,16 @@ if (!('key' in KeyboardEvent.prototype)) {
'meta': 'metaKey'
};
- /**
- * KeyboardEvent.key is mostly represented by printable character made by
- * the keyboard, with unprintable keys labeled nicely.
- *
- * However, on OS X, Alt+char can make a Unicode character that follows an
- * Apple-specific mapping. In this case, we fall back to .keyCode.
- */
var KEY_CHAR = /[a-z0-9*]/;
- /**
- * Matches a keyIdentifier string.
- */
var IDENT_CHAR = /U\+/;
- /**
- * Matches arrow keys in Gecko 27.0+
- */
var ARROW_KEY = /^arrow/;
- /**
- * Matches space keys everywhere (notably including IE10's exceptional name
- * `spacebar`).
- */
var SPACE_KEY = /^space(bar)?/;
- /**
- * Matches ESC key.
- *
- * Value from: http://w3c.github.io/uievents-key/#key-Escape
- */
var ESC_KEY = /^escape$/;
- /**
- * Transforms the key.
- * @param {string} key The KeyBoardEvent.key
- * @param {Boolean} [noSpecialChars] Limits the transformation to
- * alpha-numeric characters.
- */
function transformKey(key, noSpecialChars) {
var validKey = '';
if (key) {
@@ -1894,7 +1150,6 @@ if (!('key' in KeyboardEvent.prototype)) {
} else if (ARROW_KEY.test(lKey)) {
validKey = lKey.replace('arrow', '');
} else if (lKey == 'multiply') {
- // numpad '*' can map to Multiply on IE/Windows
validKey = '*';
} else {
validKey = lKey;
@@ -1922,17 +1177,12 @@ if (!('key' in KeyboardEvent.prototype)) {
var validKey = '';
if (Number(keyCode)) {
if (keyCode >= 65 && keyCode <= 90) {
- // ascii a-z
- // lowercase is 32 offset from uppercase
validKey = String.fromCharCode(32 + keyCode);
} else if (keyCode >= 112 && keyCode <= 123) {
- // function keys f1-f12
validKey = 'f' + (keyCode - 112);
} else if (keyCode >= 48 && keyCode <= 57) {
- // top 0-9 keys
validKey = String(keyCode - 48);
} else if (keyCode >= 96 && keyCode <= 105) {
- // num pad 0-9
validKey = String(keyCode - 96);
} else {
validKey = KEY_CODE[keyCode];
@@ -1941,19 +1191,7 @@ if (!('key' in KeyboardEvent.prototype)) {
return validKey;
}
- /**
- * Calculates the normalized key for a KeyboardEvent.
- * @param {KeyboardEvent} keyEvent
- * @param {Boolean} [noSpecialChars] Set to true to limit keyEvent.key
- * transformation to alpha-numeric chars. This is useful with key
- * combinations like shift + 2, which on FF for MacOS produces
- * keyEvent.key = @
- * To get 2 returned, set noSpecialChars = true
- * To get @ returned, set noSpecialChars = false
- */
function normalizedKeyForEvent(keyEvent, noSpecialChars) {
- // Fall back from .key, to .keyIdentifier, to .keyCode, and then to
- // .detail.key to support artificial keyboard events.
return transformKey(keyEvent.key, noSpecialChars) ||
transformKeyIdentifier(keyEvent.keyIdentifier) ||
transformKeyCode(keyEvent.keyCode) ||
@@ -1961,7 +1199,6 @@ if (!('key' in KeyboardEvent.prototype)) {
}
function keyComboMatchesEvent(keyCombo, event) {
- // For combos with modifiers we support only alpha-numeric keys
var keyEvent = normalizedKeyForEvent(event, keyCombo.hasModifiers);
return keyEvent === keyCombo.key &&
(!keyCombo.hasModifiers || (
@@ -2005,49 +1242,8 @@ if (!('key' in KeyboardEvent.prototype)) {
});
}
- /**
- * `Polymer.IronA11yKeysBehavior` provides a normalized interface for processing
- * keyboard commands that pertain to [WAI-ARIA best practices](http://www.w3.org/TR/wai-aria-practices/#kbd_general_binding).
- * The element takes care of browser differences with respect to Keyboard events
- * and uses an expressive syntax to filter key presses.
- *
- * Use the `keyBindings` prototype property to express what combination of keys
- * will trigger the callback. A key binding has the format
- * `"KEY+MODIFIER:EVENT": "callback"` (`"KEY": "callback"` or
- * `"KEY:EVENT": "callback"` are valid as well). Some examples:
- *
- * keyBindings: {
- * 'space': '_onKeydown', // same as 'space:keydown'
- * 'shift+tab': '_onKeydown',
- * 'enter:keypress': '_onKeypress',
- * 'esc:keyup': '_onKeyup'
- * }
- *
- * The callback will receive with an event containing the following information in `event.detail`:
- *
- * _onKeydown: function(event) {
- * console.log(event.detail.combo); // KEY+MODIFIER, e.g. "shift+tab"
- * console.log(event.detail.key); // KEY only, e.g. "tab"
- * console.log(event.detail.event); // EVENT, e.g. "keydown"
- * console.log(event.detail.keyboardEvent); // the original KeyboardEvent
- * }
- *
- * Use the `keyEventTarget` attribute to set up event handlers on a specific
- * node.
- *
- * See the [demo source code](https://github.com/PolymerElements/iron-a11y-keys-behavior/blob/master/demo/x-key-aware.html)
- * for an example.
- *
- * @demo demo/index.html
- * @polymerBehavior
- */
Polymer.IronA11yKeysBehavior = {
properties: {
- /**
- * The EventTarget that will be firing relevant KeyboardEvents. Set it to
- * `null` to disable the listeners.
- * @type {?EventTarget}
- */
keyEventTarget: {
type: Object,
value: function() {
@@ -2055,10 +1251,6 @@ if (!('key' in KeyboardEvent.prototype)) {
}
},
- /**
- * If true, this property will cause the implementing element to
- * automatically stop propagation on any handled KeyboardEvents.
- */
stopKeyboardEventPropagation: {
type: Boolean,
value: false
@@ -2071,8 +1263,6 @@ if (!('key' in KeyboardEvent.prototype)) {
}
},
- // We use this due to a limitation in IE10 where instances will have
- // own properties of everything on the "prototype".
_imperativeKeyBindings: {
type: Object,
value: function() {
@@ -2086,11 +1276,6 @@ if (!('key' in KeyboardEvent.prototype)) {
],
- /**
- * To be used to express what combination of keys will trigger the relative
- * callback. e.g. `keyBindings: { 'esc': '_onEscPressed'}`
- * @type {Object}
- */
keyBindings: {},
registered: function() {
@@ -2105,33 +1290,18 @@ if (!('key' in KeyboardEvent.prototype)) {
this._unlistenKeyEventListeners();
},
- /**
- * Can be used to imperatively add a key binding to the implementing
- * element. This is the imperative equivalent of declaring a keybinding
- * in the `keyBindings` prototype property.
- */
addOwnKeyBinding: function(eventString, handlerName) {
this._imperativeKeyBindings[eventString] = handlerName;
this._prepKeyBindings();
this._resetKeyEventListeners();
},
- /**
- * When called, will remove all imperatively-added key bindings.
- */
removeOwnKeyBindings: function() {
this._imperativeKeyBindings = {};
this._prepKeyBindings();
this._resetKeyEventListeners();
},
- /**
- * Returns true if a keyboard event matches `eventString`.
- *
- * @param {KeyboardEvent} event
- * @param {string} eventString
- * @return {boolean}
- */
keyboardEventMatchesKeys: function(event, eventString) {
var keyCombos = parseEventString(eventString);
for (var i = 0; i < keyCombos.length; ++i) {
@@ -2167,7 +1337,6 @@ if (!('key' in KeyboardEvent.prototype)) {
this._addKeyBinding(eventString, this._imperativeKeyBindings[eventString]);
}
- // Give precedence to combos with modifiers to be checked first.
for (var eventName in this._keyBindings) {
this._keyBindings[eventName].sort(function (kb1, kb2) {
var b1 = kb1[0].hasModifiers;
@@ -2218,7 +1387,6 @@ if (!('key' in KeyboardEvent.prototype)) {
var boundKeyHandler;
while (this._boundKeyHandlers.length) {
- // My kingdom for block-scope binding and destructuring assignment..
keyHandlerTuple = this._boundKeyHandlers.pop();
keyEventTarget = keyHandlerTuple[0];
eventName = keyHandlerTuple[1];
@@ -2233,7 +1401,6 @@ if (!('key' in KeyboardEvent.prototype)) {
event.stopPropagation();
}
- // if event has been already prevented, don't do anything
if (event.defaultPrevented) {
return;
}
@@ -2243,7 +1410,6 @@ if (!('key' in KeyboardEvent.prototype)) {
var handlerName = keyBindings[i][1];
if (keyComboMatchesEvent(keyCombo, event)) {
this._triggerKeyHandler(keyCombo, handlerName, event);
- // exit the loop if eventDefault was prevented
if (event.defaultPrevented) {
return;
}
@@ -2265,55 +1431,10 @@ if (!('key' in KeyboardEvent.prototype)) {
}
};
})();
-/**
- * `Polymer.IronScrollTargetBehavior` allows an element to respond to scroll events from a
- * designated scroll target.
- *
- * Elements that consume this behavior can override the `_scrollHandler`
- * method to add logic on the scroll event.
- *
- * @demo demo/scrolling-region.html Scrolling Region
- * @demo demo/document.html Document Element
- * @polymerBehavior
- */
Polymer.IronScrollTargetBehavior = {
properties: {
- /**
- * Specifies the element that will handle the scroll event
- * on the behalf of the current element. This is typically a reference to an element,
- * but there are a few more posibilities:
- *
- * ### Elements id
- *
- *```html
- * <div id="scrollable-element" style="overflow: auto;">
- * <x-element scroll-target="scrollable-element">
- * \x3c!-- Content--\x3e
- * </x-element>
- * </div>
- *```
- * In this case, the `scrollTarget` will point to the outer div element.
- *
- * ### Document scrolling
- *
- * For document scrolling, you can use the reserved word `document`:
- *
- *```html
- * <x-element scroll-target="document">
- * \x3c!-- Content --\x3e
- * </x-element>
- *```
- *
- * ### Elements reference
- *
- *```js
- * appHeader.scrollTarget = document.querySelector('#scrollable-element');
- *```
- *
- * @type {HTMLElement}
- */
scrollTarget: {
type: HTMLElement,
value: function() {
@@ -2338,7 +1459,6 @@ if (!('key' in KeyboardEvent.prototype)) {
if (!isAttached) {
return;
}
- // Support element id references
if (scrollTarget === 'document') {
this.scrollTarget = this._doc;
@@ -2358,37 +1478,16 @@ if (!('key' in KeyboardEvent.prototype)) {
}
},
- /**
- * Runs on every scroll event. Consumer of this behavior may override this method.
- *
- * @protected
- */
_scrollHandler: function scrollHandler() {},
- /**
- * The default scroll target. Consumers of this behavior may want to customize
- * the default scroll target.
- *
- * @type {Element}
- */
get _defaultScrollTarget() {
return this._doc;
},
- /**
- * Shortcut for the document element
- *
- * @type {Element}
- */
get _doc() {
return this.ownerDocument.documentElement;
},
- /**
- * Gets the number of pixels that the content of an element is scrolled upward.
- *
- * @type {number}
- */
get _scrollTop() {
if (this._isValidScrollTarget()) {
return this.scrollTarget === this._doc ? window.pageYOffset : this.scrollTarget.scrollTop;
@@ -2396,11 +1495,6 @@ if (!('key' in KeyboardEvent.prototype)) {
return 0;
},
- /**
- * Gets the number of pixels that the content of an element is scrolled to the left.
- *
- * @type {number}
- */
get _scrollLeft() {
if (this._isValidScrollTarget()) {
return this.scrollTarget === this._doc ? window.pageXOffset : this.scrollTarget.scrollLeft;
@@ -2408,11 +1502,6 @@ if (!('key' in KeyboardEvent.prototype)) {
return 0;
},
- /**
- * Sets the number of pixels that the content of an element is scrolled upward.
- *
- * @type {number}
- */
set _scrollTop(top) {
if (this.scrollTarget === this._doc) {
window.scrollTo(window.pageXOffset, top);
@@ -2421,11 +1510,6 @@ if (!('key' in KeyboardEvent.prototype)) {
}
},
- /**
- * Sets the number of pixels that the content of an element is scrolled to the left.
- *
- * @type {number}
- */
set _scrollLeft(left) {
if (this.scrollTarget === this._doc) {
window.scrollTo(left, window.pageYOffset);
@@ -2434,13 +1518,6 @@ if (!('key' in KeyboardEvent.prototype)) {
}
},
- /**
- * Scrolls the content to a particular place.
- *
- * @method scroll
- * @param {number} left The left position
- * @param {number} top The top position
- */
scroll: function(left, top) {
if (this.scrollTarget === this._doc) {
window.scrollTo(left, top);
@@ -2450,11 +1527,6 @@ if (!('key' in KeyboardEvent.prototype)) {
}
},
- /**
- * Gets the width of the scroll target.
- *
- * @type {number}
- */
get _scrollTargetWidth() {
if (this._isValidScrollTarget()) {
return this.scrollTarget === this._doc ? window.innerWidth : this.scrollTarget.offsetWidth;
@@ -2462,11 +1534,6 @@ if (!('key' in KeyboardEvent.prototype)) {
return 0;
},
- /**
- * Gets the height of the scroll target.
- *
- * @type {number}
- */
get _scrollTargetHeight() {
if (this._isValidScrollTarget()) {
return this.scrollTarget === this._doc ? window.innerHeight : this.scrollTarget.offsetHeight;
@@ -2474,11 +1541,6 @@ if (!('key' in KeyboardEvent.prototype)) {
return 0;
},
- /**
- * Returns true if the scroll target is a valid HTMLElement.
- *
- * @return {boolean}
- */
_isValidScrollTarget: function() {
return this.scrollTarget instanceof HTMLElement;
}
@@ -2498,101 +1560,51 @@ if (!('key' in KeyboardEvent.prototype)) {
properties: {
- /**
- * An array containing items determining how many instances of the template
- * to stamp and that that each template instance should bind to.
- */
items: {
type: Array
},
- /**
- * The max count of physical items the pool can extend to.
- */
maxPhysicalCount: {
type: Number,
value: 500
},
- /**
- * The name of the variable to add to the binding scope for the array
- * element associated with a given template instance.
- */
as: {
type: String,
value: 'item'
},
- /**
- * The name of the variable to add to the binding scope with the index
- * for the row.
- */
indexAs: {
type: String,
value: 'index'
},
- /**
- * The name of the variable to add to the binding scope to indicate
- * if the row is selected.
- */
selectedAs: {
type: String,
value: 'selected'
},
- /**
- * When true, the list is rendered as a grid. Grid items must have
- * fixed width and height set via CSS. e.g.
- *
- * ```html
- * <iron-list grid>
- * <template>
- * <div style="width: 100px; height: 100px;"> 100x100 </div>
- * </template>
- * </iron-list>
- * ```
- */
grid: {
type: Boolean,
value: false,
reflectToAttribute: true
},
- /**
- * When true, tapping a row will select the item, placing its data model
- * in the set of selected items retrievable via the selection property.
- *
- * Note that tapping focusable elements within the list item will not
- * result in selection, since they are presumed to have their * own action.
- */
selectionEnabled: {
type: Boolean,
value: false
},
- /**
- * When `multiSelection` is false, this is the currently selected item, or `null`
- * if no item is selected.
- */
selectedItem: {
type: Object,
notify: true
},
- /**
- * When `multiSelection` is true, this is an array that contains the selected items.
- */
selectedItems: {
type: Object,
notify: true
},
- /**
- * When `true`, multiple items may be selected at once (in this case,
- * `selected` is an array of currently selected items). When `false`,
- * only one item may be selected at a time.
- */
multiSelection: {
type: Boolean,
value: false
@@ -2619,209 +1631,89 @@ if (!('key' in KeyboardEvent.prototype)) {
'enter': '_didEnter'
},
- /**
- * The ratio of hidden tiles that should remain in the scroll direction.
- * Recommended value ~0.5, so it will distribute tiles evely in both directions.
- */
_ratio: 0.5,
- /**
- * The padding-top value for the list.
- */
_scrollerPaddingTop: 0,
- /**
- * This value is the same as `scrollTop`.
- */
_scrollPosition: 0,
- /**
- * The sum of the heights of all the tiles in the DOM.
- */
_physicalSize: 0,
- /**
- * The average `offsetHeight` of the tiles observed till now.
- */
_physicalAverage: 0,
- /**
- * The number of tiles which `offsetHeight` > 0 observed until now.
- */
_physicalAverageCount: 0,
- /**
- * The Y position of the item rendered in the `_physicalStart`
- * tile relative to the scrolling list.
- */
_physicalTop: 0,
- /**
- * The number of items in the list.
- */
_virtualCount: 0,
- /**
- * A map between an item key and its physical item index
- */
_physicalIndexForKey: null,
- /**
- * The estimated scroll height based on `_physicalAverage`
- */
_estScrollHeight: 0,
- /**
- * The scroll height of the dom node
- */
_scrollHeight: 0,
- /**
- * The height of the list. This is referred as the viewport in the context of list.
- */
_viewportHeight: 0,
- /**
- * The width of the list. This is referred as the viewport in the context of list.
- */
_viewportWidth: 0,
- /**
- * An array of DOM nodes that are currently in the tree
- * @type {?Array<!TemplatizerNode>}
- */
_physicalItems: null,
- /**
- * An array of heights for each item in `_physicalItems`
- * @type {?Array<number>}
- */
_physicalSizes: null,
- /**
- * A cached value for the first visible index.
- * See `firstVisibleIndex`
- * @type {?number}
- */
_firstVisibleIndexVal: null,
- /**
- * A cached value for the last visible index.
- * See `lastVisibleIndex`
- * @type {?number}
- */
_lastVisibleIndexVal: null,
- /**
- * A Polymer collection for the items.
- * @type {?Polymer.Collection}
- */
_collection: null,
- /**
- * True if the current item list was rendered for the first time
- * after attached.
- */
_itemsRendered: false,
- /**
- * The page that is currently rendered.
- */
_lastPage: null,
- /**
- * The max number of pages to render. One page is equivalent to the height of the list.
- */
_maxPages: 3,
- /**
- * The currently focused physical item.
- */
_focusedItem: null,
- /**
- * The index of the `_focusedItem`.
- */
_focusedIndex: -1,
- /**
- * The the item that is focused if it is moved offscreen.
- * @private {?TemplatizerNode}
- */
_offscreenFocusedItem: null,
- /**
- * The item that backfills the `_offscreenFocusedItem` in the physical items
- * list when that item is moved offscreen.
- */
_focusBackfillItem: null,
- /**
- * The maximum items per row
- */
_itemsPerRow: 1,
- /**
- * The width of each grid item
- */
_itemWidth: 0,
- /**
- * The height of the row in grid layout.
- */
_rowHeight: 0,
- /**
- * The bottom of the physical content.
- */
get _physicalBottom() {
return this._physicalTop + this._physicalSize;
},
- /**
- * The bottom of the scroll.
- */
get _scrollBottom() {
return this._scrollPosition + this._viewportHeight;
},
- /**
- * The n-th item rendered in the last physical item.
- */
get _virtualEnd() {
return this._virtualStart + this._physicalCount - 1;
},
- /**
- * The height of the physical content that isn't on the screen.
- */
get _hiddenContentSize() {
var size = this.grid ? this._physicalRows * this._rowHeight : this._physicalSize;
return size - this._viewportHeight;
},
- /**
- * The maximum scroll top value.
- */
get _maxScrollTop() {
return this._estScrollHeight - this._viewportHeight + this._scrollerPaddingTop;
},
- /**
- * The lowest n-th value for an item such that it can be rendered in `_physicalStart`.
- */
_minVirtualStart: 0,
- /**
- * The largest n-th value for an item such that it can be rendered in `_physicalStart`.
- */
get _maxVirtualStart() {
return Math.max(0, this._virtualCount - this._physicalCount);
},
- /**
- * The n-th item rendered in the `_physicalStart` tile.
- */
_virtualStartVal: 0,
set _virtualStart(val) {
@@ -2832,9 +1724,6 @@ if (!('key' in KeyboardEvent.prototype)) {
return this._virtualStartVal || 0;
},
- /**
- * The k-th tile that is at the top of the scrolling list.
- */
_physicalStartVal: 0,
set _physicalStart(val) {
@@ -2849,9 +1738,6 @@ if (!('key' in KeyboardEvent.prototype)) {
return this._physicalStartVal || 0;
},
- /**
- * The number of tiles in the DOM.
- */
_physicalCountVal: 0,
set _physicalCount(val) {
@@ -2863,18 +1749,8 @@ if (!('key' in KeyboardEvent.prototype)) {
return this._physicalCountVal;
},
- /**
- * The k-th tile that is at the bottom of the scrolling list.
- */
_physicalEnd: 0,
- /**
- * An optimal physical size such that we will have enough physical items
- * to fill up the viewport and recycle when the user scrolls.
- *
- * This default value assumes that we will at least have the equivalent
- * to a viewport of physical items above and below the user's viewport.
- */
get _optPhysicalSize() {
if (this.grid) {
return this._estRowsInView * this._rowHeight * this._maxPages;
@@ -2886,18 +1762,10 @@ if (!('key' in KeyboardEvent.prototype)) {
return this._estRowsInView * this._itemsPerRow * this._maxPages;
},
- /**
- * True if the current list is visible.
- */
get _isVisible() {
return this.scrollTarget && Boolean(this.scrollTarget.offsetWidth || this.scrollTarget.offsetHeight);
},
- /**
- * Gets the index of the first visible item in the viewport.
- *
- * @type {number}
- */
get firstVisibleIndex() {
if (this._firstVisibleIndexVal === null) {
var physicalOffset = Math.floor(this._physicalTop + this._scrollerPaddingTop);
@@ -2909,7 +1777,6 @@ if (!('key' in KeyboardEvent.prototype)) {
if (physicalOffset > this._scrollPosition) {
return this.grid ? vidx - (vidx % this._itemsPerRow) : vidx;
}
- // Handle a partially rendered final row in grid mode
if (this.grid && this._virtualCount - 1 === vidx) {
return vidx - (vidx % this._itemsPerRow);
}
@@ -2918,11 +1785,6 @@ if (!('key' in KeyboardEvent.prototype)) {
return this._firstVisibleIndexVal;
},
- /**
- * Gets the index of the last visible item in the viewport.
- *
- * @type {number}
- */
get lastVisibleIndex() {
if (this._lastVisibleIndexVal === null) {
if (this.grid) {
@@ -2934,7 +1796,6 @@ if (!('key' in KeyboardEvent.prototype)) {
if (physicalOffset < this._scrollBottom) {
this._lastVisibleIndexVal = vidx;
} else {
- // Break _iterateItems
return true;
}
physicalOffset += this._getPhysicalSizeIncrement(pidx);
@@ -2966,8 +1827,6 @@ if (!('key' in KeyboardEvent.prototype)) {
attached: function() {
this.updateViewportBoundaries();
this._render();
- // `iron-resize` is fired when the list is attached if the event is added
- // before attached causing unnecessary work.
this.listen(this, 'iron-resize', '_resizeHandler');
},
@@ -2976,20 +1835,11 @@ if (!('key' in KeyboardEvent.prototype)) {
this.unlisten(this, 'iron-resize', '_resizeHandler');
},
- /**
- * Set the overflow property if this element has its own scrolling region
- */
_setOverflow: function(scrollTarget) {
this.style.webkitOverflowScrolling = scrollTarget === this ? 'touch' : '';
this.style.overflow = scrollTarget === this ? 'auto' : '';
},
- /**
- * Invoke this method if you dynamically update the viewport's
- * size or CSS padding.
- *
- * @method updateViewportBoundaries
- */
updateViewportBoundaries: function() {
this._scrollerPaddingTop = this.scrollTarget === this ? 0 :
parseInt(window.getComputedStyle(this)['padding-top'], 10);
@@ -3000,12 +1850,7 @@ if (!('key' in KeyboardEvent.prototype)) {
}
},
- /**
- * Update the models, the position of the
- * items in the viewport and recycle tiles as needed.
- */
_scrollHandler: function() {
- // clamp the `scrollTop` value
var scrollTop = Math.max(0, Math.min(this._maxScrollTop, this._scrollTop));
var delta = scrollTop - this._scrollPosition;
var tileHeight, tileTop, kth, recycledTileSet, scrollBottom, physicalBottom;
@@ -3015,22 +1860,18 @@ if (!('key' in KeyboardEvent.prototype)) {
var currentRatio = ratio;
var movingUp = [];
- // track the last `scrollTop`
this._scrollPosition = scrollTop;
- // clear cached visible indexes
this._firstVisibleIndexVal = null;
this._lastVisibleIndexVal = null;
scrollBottom = this._scrollBottom;
physicalBottom = this._physicalBottom;
- // random access
if (Math.abs(delta) > this._physicalSize) {
this._physicalTop += delta;
recycledTiles = Math.round(delta / this._physicalAverage);
}
- // scroll up
else if (delta < 0) {
var topSpace = scrollTop - this._physicalTop;
var virtualStart = this._virtualStart;
@@ -3040,15 +1881,10 @@ if (!('key' in KeyboardEvent.prototype)) {
kth = this._physicalEnd;
currentRatio = topSpace / hiddenContentSize;
- // move tiles from bottom to top
while (
- // approximate `currentRatio` to `ratio`
currentRatio < ratio &&
- // recycle less physical items than the total
recycledTiles < this._physicalCount &&
- // ensure that these recycled tiles are needed
virtualStart - recycledTiles > 0 &&
- // ensure that the tile is not visible
physicalBottom - this._getPhysicalSizeIncrement(kth) > scrollBottom
) {
@@ -3063,7 +1899,6 @@ if (!('key' in KeyboardEvent.prototype)) {
movingUp = recycledTileSet;
recycledTiles = -recycledTiles;
}
- // scroll down
else if (delta > 0) {
var bottomSpace = physicalBottom - scrollBottom;
var virtualEnd = this._virtualEnd;
@@ -3074,15 +1909,10 @@ if (!('key' in KeyboardEvent.prototype)) {
kth = this._physicalStart;
currentRatio = bottomSpace / hiddenContentSize;
- // move tiles from top to bottom
while (
- // approximate `currentRatio` to `ratio`
currentRatio < ratio &&
- // recycle less physical items than the total
recycledTiles < this._physicalCount &&
- // ensure that these recycled tiles are needed
virtualEnd + recycledTiles < lastVirtualItemIndex &&
- // ensure that the tile is not visible
this._physicalTop + this._getPhysicalSizeIncrement(kth) < scrollTop
) {
@@ -3097,7 +1927,6 @@ if (!('key' in KeyboardEvent.prototype)) {
}
if (recycledTiles === 0) {
- // Try to increase the pool if the list's client height isn't filled up with physical items
if (physicalBottom < scrollBottom || this._physicalTop > scrollTop) {
this._increasePoolIfNeeded();
}
@@ -3108,36 +1937,21 @@ if (!('key' in KeyboardEvent.prototype)) {
}
},
- /**
- * Update the list of items, starting from the `_virtualStart` item.
- * @param {!Array<number>=} itemSet
- * @param {!Array<number>=} movingUp
- */
_update: function(itemSet, movingUp) {
- // manage focus
this._manageFocus();
- // update models
this._assignModels(itemSet);
- // measure heights
this._updateMetrics(itemSet);
- // adjust offset after measuring
if (movingUp) {
while (movingUp.length) {
var idx = movingUp.pop();
this._physicalTop -= this._getPhysicalSizeIncrement(idx);
}
}
- // update the position of the items
this._positionItems();
- // set the scroller size
this._updateScrollerSize();
- // increase the pool of physical items
this._increasePoolIfNeeded();
},
- /**
- * Creates a pool of DOM elements and attaches them to the local dom.
- */
_createPool: function(size) {
var physicalItems = new Array(size);
@@ -3145,42 +1959,27 @@ if (!('key' in KeyboardEvent.prototype)) {
for (var i = 0; i < size; i++) {
var inst = this.stamp(null);
- // First element child is item; Safari doesn't support children[0]
- // on a doc fragment
physicalItems[i] = inst.root.querySelector('*');
Polymer.dom(this).appendChild(inst.root);
}
return physicalItems;
},
- /**
- * Increases the pool of physical items only if needed.
- *
- * @return {boolean} True if the pool was increased.
- */
_increasePoolIfNeeded: function() {
- // Base case 1: the list has no height.
if (this._viewportHeight === 0) {
return false;
}
- // Base case 2: If the physical size is optimal and the list's client height is full
- // with physical items, don't increase the pool.
var isClientHeightFull = this._physicalBottom >= this._scrollBottom && this._physicalTop <= this._scrollPosition;
if (this._physicalSize >= this._optPhysicalSize && isClientHeightFull) {
return false;
}
- // this value should range between [0 <= `currentPage` <= `_maxPages`]
var currentPage = Math.floor(this._physicalSize / this._viewportHeight);
if (currentPage === 0) {
- // fill the first page
this._debounceTemplate(this._increasePool.bind(this, Math.round(this._physicalCount * 0.5)));
} else if (this._lastPage !== currentPage && isClientHeightFull) {
- // paint the page and defer the next increase
- // wait 16ms which is rough enough to get paint cycle.
Polymer.dom.addDebouncer(this.debounce('_debounceTemplate', this._increasePool.bind(this, this._itemsPerRow), 16));
} else {
- // fill the rest of the pages
this._debounceTemplate(this._increasePool.bind(this, this._itemsPerRow));
}
@@ -3189,9 +1988,6 @@ if (!('key' in KeyboardEvent.prototype)) {
return true;
},
- /**
- * Increases the pool size.
- */
_increasePool: function(missingItems) {
var nextPhysicalCount = Math.min(
this._physicalCount + missingItems,
@@ -3210,9 +2006,6 @@ if (!('key' in KeyboardEvent.prototype)) {
this._physicalCount = prevPhysicalCount + delta;
- // update the physical start if we need to preserve the model of the focused item.
- // In this situation, the focused item is currently rendered and its model would
- // have changed after increasing the pool if the physical start remained unchanged.
if (this._physicalStart > this._physicalEnd &&
this._isIndexRendered(this._focusedIndex) &&
this._getPhysicalIndex(this._focusedIndex) < this._physicalEnd) {
@@ -3221,10 +2014,6 @@ if (!('key' in KeyboardEvent.prototype)) {
this._update();
},
- /**
- * Render a new list of items. This method does exactly the same as `update`,
- * but it also ensures that only one `update` cycle is created.
- */
_render: function() {
var requiresUpdate = this._virtualCount > 0 || this._physicalCount > 0;
@@ -3235,12 +2024,8 @@ if (!('key' in KeyboardEvent.prototype)) {
}
},
- /**
- * Templetizes the user template.
- */
_ensureTemplatized: function() {
if (!this.ctor) {
- // Template instance props that should be excluded from forwarding
var props = {};
props.__key__ = true;
props[this.as] = true;
@@ -3259,18 +2044,10 @@ if (!('key' in KeyboardEvent.prototype)) {
}
},
- /**
- * Implements extension point from Templatizer mixin.
- */
_getStampedChildren: function() {
return this._physicalItems;
},
- /**
- * Implements extension point from Templatizer
- * Called as a side effect of a template instance path change, responsible
- * for notifying items.<key-for-instance>.<path> change up to host.
- */
_forwardInstancePath: function(inst, path, value) {
if (path.indexOf(this.as + '.') === 0) {
this.notifyPath('items.' + inst.__key__ + '.' +
@@ -3278,11 +2055,6 @@ if (!('key' in KeyboardEvent.prototype)) {
}
},
- /**
- * Implements extension point from Templatizer mixin
- * Called as side-effect of a host property change, responsible for
- * notifying parent path change on each row.
- */
_forwardParentProp: function(prop, value) {
if (this._physicalItems) {
this._physicalItems.forEach(function(item) {
@@ -3291,11 +2063,6 @@ if (!('key' in KeyboardEvent.prototype)) {
}
},
- /**
- * Implements extension point from Templatizer
- * Called as side-effect of a host path change, responsible for
- * notifying parent.<path> path change on each row.
- */
_forwardParentPath: function(path, value) {
if (this._physicalItems) {
this._physicalItems.forEach(function(item) {
@@ -3304,10 +2071,6 @@ if (!('key' in KeyboardEvent.prototype)) {
}
},
- /**
- * Called as a side effect of a host items.<key>.<path> path change,
- * responsible for notifying item.<path> changes.
- */
_forwardItemPath: function(path, value) {
if (!this._physicalIndexForKey) {
return;
@@ -3326,7 +2089,6 @@ if (!('key' in KeyboardEvent.prototype)) {
path = this.as + '.' + path.substring(dot+1);
el._templateInstance.notifyPath(path, value, true);
} else {
- // Update selection if needed
var currentItem = el._templateInstance[this.as];
if (Array.isArray(this.selectedItems)) {
for (var i = 0; i < this.selectedItems.length; i++) {
@@ -3342,13 +2104,8 @@ if (!('key' in KeyboardEvent.prototype)) {
}
},
- /**
- * Called when the items have changed. That is, ressignments
- * to `items`, splices or updates to a single item.
- */
_itemsChanged: function(change) {
if (change.path === 'items') {
- // reset items
this._virtualStart = 0;
this._physicalTop = 0;
this._virtualCount = this.items ? this.items.length : 0;
@@ -3359,7 +2116,6 @@ if (!('key' in KeyboardEvent.prototype)) {
this._resetScrollPosition(0);
this._removeFocusedItem();
- // create the initial physical items
if (!this._physicalItems) {
this._physicalCount = Math.max(1, Math.min(DEFAULT_PHYSICAL_COUNT, this._virtualCount));
this._physicalItems = this._createPool(this._physicalCount);
@@ -3374,7 +2130,6 @@ if (!('key' in KeyboardEvent.prototype)) {
this._virtualCount = this.items ? this.items.length : 0;
} else {
- // update a single item
this._forwardItemPath(change.path.split('.').slice(1).join('.'), change.value);
return;
}
@@ -3383,14 +2138,9 @@ if (!('key' in KeyboardEvent.prototype)) {
this._debounceTemplate(this._render);
},
- /**
- * @param {!Array<!PolymerSplice>} splices
- */
_adjustVirtualIndex: function(splices) {
splices.forEach(function(splice) {
- // deselect removed items
splice.removed.forEach(this._removeItem, this);
- // We only need to care about changes happening above the current position
if (splice.index < this._virtualStart) {
var delta = Math.max(
splice.addedCount - splice.removed.length,
@@ -3407,19 +2157,11 @@ if (!('key' in KeyboardEvent.prototype)) {
_removeItem: function(item) {
this.$.selector.deselect(item);
- // remove the current focused item
if (this._focusedItem && this._focusedItem._templateInstance[this.as] === item) {
this._removeFocusedItem();
}
},
- /**
- * Executes a provided function per every physical index in `itemSet`
- * `itemSet` default value is equivalent to the entire set of physical indexes.
- *
- * @param {!function(number, number)} fn
- * @param {!Array<number>=} itemSet
- */
_iterateItems: function(fn, itemSet) {
var pidx, vidx, rtn, i;
@@ -3448,12 +2190,6 @@ if (!('key' in KeyboardEvent.prototype)) {
}
},
- /**
- * Returns the virtual index for a given physical index
- *
- * @param {number} pidx Physical index
- * @return {number}
- */
_computeVidx: function(pidx) {
if (pidx >= this._physicalStart) {
return this._virtualStart + (pidx - this._physicalStart);
@@ -3461,10 +2197,6 @@ if (!('key' in KeyboardEvent.prototype)) {
return this._virtualStart + (this._physicalCount - this._physicalStart) + pidx;
},
- /**
- * Assigns the data models to a given set of items.
- * @param {!Array<number>=} itemSet
- */
_assignModels: function(itemSet) {
this._iterateItems(function(pidx, vidx) {
var el = this._physicalItems[pidx];
@@ -3486,14 +2218,7 @@ if (!('key' in KeyboardEvent.prototype)) {
}, itemSet);
},
- /**
- * Updates the height for a given set of items.
- *
- * @param {!Array<number>=} itemSet
- */
_updateMetrics: function(itemSet) {
- // Make sure we distributed all the physical items
- // so we can measure them
Polymer.dom.flush();
var newPhysicalSize = 0;
@@ -3518,7 +2243,6 @@ if (!('key' in KeyboardEvent.prototype)) {
this._physicalSize = this._physicalSize + newPhysicalSize - oldPhysicalSize;
}
- // update the average if we measured something
if (this._physicalAverageCount !== prevAvgCount) {
this._physicalAverage = Math.round(
((prevPhysicalAvg * prevAvgCount) + newPhysicalSize) /
@@ -3528,17 +2252,11 @@ if (!('key' in KeyboardEvent.prototype)) {
_updateGridMetrics: function() {
this._viewportWidth = this.$.items.offsetWidth;
- // Set item width to the value of the _physicalItems offsetWidth
this._itemWidth = this._physicalCount > 0 ? this._physicalItems[0].getBoundingClientRect().width : DEFAULT_GRID_SIZE;
- // Set row height to the value of the _physicalItems offsetHeight
this._rowHeight = this._physicalCount > 0 ? this._physicalItems[0].offsetHeight : DEFAULT_GRID_SIZE;
- // If in grid mode compute how many items with exist in each row
this._itemsPerRow = this._itemWidth ? Math.floor(this._viewportWidth / this._itemWidth) : this._itemsPerRow;
},
- /**
- * Updates the position of the physical items.
- */
_positionItems: function() {
this._adjustScrollPosition();
@@ -3580,37 +2298,22 @@ if (!('key' in KeyboardEvent.prototype)) {
return this._rowHeight;
},
- /**
- * Returns, based on the current index,
- * whether or not the next index will need
- * to be rendered on a new row.
- *
- * @param {number} vidx Virtual index
- * @return {boolean}
- */
_shouldRenderNextRow: function(vidx) {
return vidx % this._itemsPerRow === this._itemsPerRow - 1;
},
- /**
- * Adjusts the scroll position when it was overestimated.
- */
_adjustScrollPosition: function() {
var deltaHeight = this._virtualStart === 0 ? this._physicalTop :
Math.min(this._scrollPosition + this._physicalTop, 0);
if (deltaHeight) {
this._physicalTop = this._physicalTop - deltaHeight;
- // juking scroll position during interial scrolling on iOS is no bueno
if (!IOS_TOUCH_SCROLLING && this._physicalTop !== 0) {
this._resetScrollPosition(this._scrollTop - deltaHeight);
}
}
},
- /**
- * Sets the position of the scroll.
- */
_resetScrollPosition: function(pos) {
if (this.scrollTarget) {
this._scrollTop = pos;
@@ -3618,11 +2321,6 @@ if (!('key' in KeyboardEvent.prototype)) {
}
},
- /**
- * Sets the scroll height, that's the height of the content,
- *
- * @param {boolean=} forceUpdate If true, updates the height no matter what.
- */
_updateScrollerSize: function(forceUpdate) {
if (this.grid) {
this._estScrollHeight = this._virtualRowCount * this._rowHeight;
@@ -3635,31 +2333,16 @@ if (!('key' in KeyboardEvent.prototype)) {
forceUpdate = forceUpdate || this._scrollPosition >= this._estScrollHeight - this._physicalSize;
forceUpdate = forceUpdate || this.grid && this.$.items.style.height < this._estScrollHeight;
- // amortize height adjustment, so it won't trigger repaints very often
if (forceUpdate || Math.abs(this._estScrollHeight - this._scrollHeight) >= this._optPhysicalSize) {
this.$.items.style.height = this._estScrollHeight + 'px';
this._scrollHeight = this._estScrollHeight;
}
},
- /**
- * Scroll to a specific item in the virtual list regardless
- * of the physical items in the DOM tree.
- *
- * @method scrollToItem
- * @param {(Object)} item The item to be scrolled to
- */
scrollToItem: function(item){
return this.scrollToIndex(this.items.indexOf(item));
},
- /**
- * Scroll to a specific index in the virtual list regardless
- * of the physical items in the DOM tree.
- *
- * @method scrollToIndex
- * @param {number} idx The index of the item
- */
scrollToIndex: function(idx) {
if (typeof idx !== 'number' || idx < 0 || idx > this.items.length - 1) {
return;
@@ -3668,18 +2351,13 @@ if (!('key' in KeyboardEvent.prototype)) {
Polymer.dom.flush();
idx = Math.min(Math.max(idx, 0), this._virtualCount-1);
- // update the virtual start only when needed
if (!this._isIndexRendered(idx) || idx >= this._maxVirtualStart) {
this._virtualStart = this.grid ? (idx - this._itemsPerRow * 2) : (idx - 1);
}
- // manage focus
this._manageFocus();
- // assign new models
this._assignModels();
- // measure the new sizes
this._updateMetrics();
- // estimate new physical offset
var estPhysicalTop = Math.floor(this._virtualStart / this._itemsPerRow) * this._physicalAverage;
this._physicalTop = estPhysicalTop;
@@ -3688,45 +2366,28 @@ if (!('key' in KeyboardEvent.prototype)) {
var targetOffsetTop = 0;
var hiddenContentSize = this._hiddenContentSize;
- // scroll to the item as much as we can
while (currentVirtualItem < idx && targetOffsetTop <= hiddenContentSize) {
targetOffsetTop = targetOffsetTop + this._getPhysicalSizeIncrement(currentTopItem);
currentTopItem = (currentTopItem + 1) % this._physicalCount;
currentVirtualItem++;
}
- // update the scroller size
this._updateScrollerSize(true);
- // update the position of the items
this._positionItems();
- // set the new scroll position
this._resetScrollPosition(this._physicalTop + this._scrollerPaddingTop + targetOffsetTop);
- // increase the pool of physical items if needed
this._increasePoolIfNeeded();
- // clear cached visible index
this._firstVisibleIndexVal = null;
this._lastVisibleIndexVal = null;
},
- /**
- * Reset the physical average and the average count.
- */
_resetAverage: function() {
this._physicalAverage = 0;
this._physicalAverageCount = 0;
},
- /**
- * A handler for the `iron-resize` event triggered by `IronResizableBehavior`
- * when the element is resized.
- */
_resizeHandler: function() {
- // iOS fires the resize event when the address bar slides up
if (IOS && Math.abs(this._viewportHeight - this._scrollTargetHeight) < 100) {
return;
}
- // In Desktop Safari 9.0.3, if the scroll bars are always shown,
- // changing the scroll position from a resize handler would result in
- // the scroll position being reset. Waiting 1ms fixes the issue.
Polymer.dom.addDebouncer(this.debounce('_debounceTemplate', function() {
this.updateViewportBoundaries();
this._render();
@@ -3748,11 +2409,6 @@ if (!('key' in KeyboardEvent.prototype)) {
return null;
},
- /**
- * Gets a valid item instance from its index or the object value.
- *
- * @param {(Object|number)} item The item object or its index
- */
_getNormalizedItem: function(item) {
if (this._collection.getKey(item) === undefined) {
if (typeof item === 'number') {
@@ -3767,12 +2423,6 @@ if (!('key' in KeyboardEvent.prototype)) {
return item;
},
- /**
- * Select the list item at the given index.
- *
- * @method selectItem
- * @param {(Object|number)} item The item object or its index
- */
selectItem: function(item) {
item = this._getNormalizedItem(item);
var model = this._getModelFromItem(item);
@@ -3787,13 +2437,6 @@ if (!('key' in KeyboardEvent.prototype)) {
this.updateSizeForItem(item);
},
- /**
- * Deselects the given item list if it is already selected.
- *
-
- * @method deselect
- * @param {(Object|number)} item The item object or its index
- */
deselectItem: function(item) {
item = this._getNormalizedItem(item);
var model = this._getModelFromItem(item);
@@ -3805,13 +2448,6 @@ if (!('key' in KeyboardEvent.prototype)) {
this.updateSizeForItem(item);
},
- /**
- * Select or deselect a given item depending on whether the item
- * has already been selected.
- *
- * @method toggleSelectionForItem
- * @param {(Object|number)} item The item object or its index
- */
toggleSelectionForItem: function(item) {
item = this._getNormalizedItem(item);
if (/** @type {!ArraySelectorElement} */ (this.$.selector).isSelected(item)) {
@@ -3821,11 +2457,6 @@ if (!('key' in KeyboardEvent.prototype)) {
}
},
- /**
- * Clears the current selection state of the list.
- *
- * @method clearSelection
- */
clearSelection: function() {
function unselect(item) {
var model = this._getModelFromItem(item);
@@ -3843,18 +2474,11 @@ if (!('key' in KeyboardEvent.prototype)) {
/** @type {!ArraySelectorElement} */ (this.$.selector).clearSelection();
},
- /**
- * Add an event listener to `tap` if `selectionEnabled` is true,
- * it will remove the listener otherwise.
- */
_selectionEnabledChanged: function(selectionEnabled) {
var handler = selectionEnabled ? this.listen : this.unlisten;
handler.call(this, this, 'tap', '_selectionHandler');
},
- /**
- * Select an item from an event object.
- */
_selectionHandler: function(e) {
var model = this.modelForElement(e.target);
if (!model) {
@@ -3864,20 +2488,15 @@ if (!('key' in KeyboardEvent.prototype)) {
var target = Polymer.dom(e).path[0];
var activeEl = Polymer.dom(this.domHost ? this.domHost.root : document).activeElement;
var physicalItem = this._physicalItems[this._getPhysicalIndex(model[this.indexAs])];
- // Safari does not focus certain form controls via mouse
- // https://bugs.webkit.org/show_bug.cgi?id=118043
if (target.localName === 'input' ||
target.localName === 'button' ||
target.localName === 'select') {
return;
}
- // Set a temporary tabindex
modelTabIndex = model.tabIndex;
model.tabIndex = SECRET_TABINDEX;
activeElTabIndex = activeEl ? activeEl.tabIndex : -1;
model.tabIndex = modelTabIndex;
- // Only select the item if the tap wasn't on a focusable child
- // or the element bound to `tabIndex`
if (activeEl && physicalItem.contains(activeEl) && activeElTabIndex !== SECRET_TABINDEX) {
return;
}
@@ -3889,12 +2508,6 @@ if (!('key' in KeyboardEvent.prototype)) {
this.$.selector.multi = multiSelection;
},
- /**
- * Updates the size of an item.
- *
- * @method updateSizeForItem
- * @param {(Object|number)} item The item object or its index
- */
updateSizeForItem: function(item) {
item = this._getNormalizedItem(item);
var key = this._collection.getKey(item);
@@ -3906,26 +2519,16 @@ if (!('key' in KeyboardEvent.prototype)) {
}
},
- /**
- * Creates a temporary backfill item in the rendered pool of physical items
- * to replace the main focused item. The focused item has tabIndex = 0
- * and might be currently focused by the user.
- *
- * This dynamic replacement helps to preserve the focus state.
- */
_manageFocus: function() {
var fidx = this._focusedIndex;
if (fidx >= 0 && fidx < this._virtualCount) {
- // if it's a valid index, check if that index is rendered
- // in a physical item.
if (this._isIndexRendered(fidx)) {
this._restoreFocusedItem();
} else {
this._createFocusBackfillItem();
}
} else if (this._virtualCount > 0 && this._physicalCount > 0) {
- // otherwise, assign the initial focused index.
this._focusedIndex = this._virtualStart;
this._focusedItem = this._physicalItems[this._physicalStart];
}
@@ -3948,7 +2551,6 @@ if (!('key' in KeyboardEvent.prototype)) {
return;
}
this._restoreFocusedItem();
- // scroll to index to make sure it's rendered
if (!this._isIndexRendered(idx)) {
this.scrollToIndex(idx);
}
@@ -3957,19 +2559,14 @@ if (!('key' in KeyboardEvent.prototype)) {
var model = physicalItem._templateInstance;
var focusable;
- // set a secret tab index
model.tabIndex = SECRET_TABINDEX;
- // check if focusable element is the physical item
if (physicalItem.tabIndex === SECRET_TABINDEX) {
focusable = physicalItem;
}
- // search for the element which tabindex is bound to the secret tab index
if (!focusable) {
focusable = Polymer.dom(physicalItem).querySelector('[tabindex="' + SECRET_TABINDEX + '"]');
}
- // restore the tab index
model.tabIndex = 0;
- // focus the focusable element
this._focusedIndex = idx;
focusable && focusable.focus();
},
@@ -3990,20 +2587,15 @@ if (!('key' in KeyboardEvent.prototype)) {
return;
}
if (!this._focusBackfillItem) {
- // create a physical item, so that it backfills the focused item.
var stampedTemplate = this.stamp(null);
this._focusBackfillItem = stampedTemplate.root.querySelector('*');
Polymer.dom(this).appendChild(stampedTemplate.root);
}
- // get the physical index for the focused index
pidx = this._getPhysicalIndex(fidx);
if (pidx != null) {
- // set the offcreen focused physical item
this._offscreenFocusedItem = this._physicalItems[pidx];
- // backfill the focused physical item
this._physicalItems[pidx] = this._focusBackfillItem;
- // hide the focused physical
this.translate3d(0, HIDDEN_Y, 0, this._offscreenFocusedItem);
}
},
@@ -4014,19 +2606,13 @@ if (!('key' in KeyboardEvent.prototype)) {
if (!this._offscreenFocusedItem || this._focusedIndex < 0) {
return;
}
- // assign models to the focused index
this._assignModels();
- // get the new physical index for the focused index
pidx = this._getPhysicalIndex(fidx);
if (pidx != null) {
- // flip the focus backfill
this._focusBackfillItem = this._physicalItems[pidx];
- // restore the focused physical item
this._physicalItems[pidx] = this._offscreenFocusedItem;
- // reset the offscreen focused item
this._offscreenFocusedItem = null;
- // hide the physical item that backfills
this.translate3d(0, HIDDEN_Y, 0, this._focusBackfillItem);
}
},
@@ -4041,15 +2627,12 @@ if (!('key' in KeyboardEvent.prototype)) {
return;
}
if (focusedModel === targetModel) {
- // if the user focused the same item, then bring it into view if it's not visible
if (!this._isIndexVisible(fidx)) {
this.scrollToIndex(fidx);
}
} else {
this._restoreFocusedItem();
- // restore tabIndex for the currently focused item
focusedModel.tabIndex = -1;
- // set the tabIndex for the next focused item
targetModel.tabIndex = 0;
fidx = targetModel[this.indexAs];
this._focusedIndex = fidx;
@@ -4066,7 +2649,6 @@ if (!('key' in KeyboardEvent.prototype)) {
},
_didMoveDown: function(e) {
- // disable scroll when pressing the down key
e.detail.keyboardEvent.preventDefault();
this._focusPhysicalItem(this._focusedIndex + 1);
},
@@ -4083,10 +2665,6 @@ if (!('key' in KeyboardEvent.prototype)) {
// found in the LICENSE file.
cr.define('downloads', function() {
- /**
- * @param {string} chromeSendName
- * @return {function(string):void} A chrome.send() callback with curried name.
- */
function chromeSendWithId(chromeSendName) {
return function(id) { chrome.send(chromeSendName, [id]); };
}
@@ -4097,24 +2675,11 @@ cr.define('downloads', function() {
this.searchTerms_ = [];
}
- /**
- * @param {string} s
- * @return {string} |s| without whitespace at the beginning or end.
- */
function trim(s) { return s.trim(); }
- /**
- * @param {string|undefined} value
- * @return {boolean} Whether |value| is truthy.
- */
function truthy(value) { return !!value; }
- /**
- * @param {string} searchText Input typed by the user into a search box.
- * @return {Array<string>} A list of terms extracted from |searchText|.
- */
ActionService.splitTerms = function(searchText) {
- // Split quoted terms (e.g., 'The "lazy" dog' => ['The', 'lazy', 'dog']).
return searchText.split(/"([^"]*)"/).map(trim).filter(truthy);
};
@@ -4149,10 +2714,6 @@ cr.define('downloads', function() {
chrome.send('getDownloads', this.searchTerms_);
},
- /**
- * @return {boolean} Whether the user is currently searching for downloads
- * (i.e. has a non-empty search term).
- */
isSearching: function() {
return this.searchTerms_.length > 0;
},
@@ -4160,9 +2721,6 @@ cr.define('downloads', function() {
/** Opens the current local destination for downloads. */
openDownloadsFolder: chrome.send.bind(chrome, 'openDownloadsFolder'),
- /**
- * @param {string} id ID of the download to run locally on the user's box.
- */
openFile: chromeSendWithId('openFile'),
/** @param {string} id ID the of the progressing download to pause. */
@@ -4174,10 +2732,6 @@ cr.define('downloads', function() {
/** @param {string} id ID of the paused download to resume. */
resume: chromeSendWithId('resume'),
- /**
- * @param {string} id ID of the dangerous download to save despite
- * warnings.
- */
saveDangerous: chromeSendWithId('saveDangerous'),
/** @param {string} searchText What to search for. */
@@ -4197,10 +2751,6 @@ cr.define('downloads', function() {
this.loadMore();
},
- /**
- * Shows the local folder a finished download resides in.
- * @param {string} id ID of the download to show.
- */
show: chromeSendWithId('show'),
/** Undo download removal. */
@@ -4216,10 +2766,6 @@ cr.define('downloads', function() {
// found in the LICENSE file.
cr.define('downloads', function() {
- /**
- * Explains why a download is in DANGEROUS state.
- * @enum {string}
- */
var DangerType = {
NOT_DANGEROUS: 'NOT_DANGEROUS',
DANGEROUS_FILE: 'DANGEROUS_FILE',
@@ -4230,11 +2776,6 @@ cr.define('downloads', function() {
POTENTIALLY_UNWANTED: 'POTENTIALLY_UNWANTED',
};
- /**
- * The states a download can be in. These correspond to states defined in
- * DownloadsDOMHandler::CreateDownloadItemValue
- * @enum {string}
- */
var States = {
IN_PROGRESS: 'IN_PROGRESS',
CANCELLED: 'CANCELLED',
@@ -4253,42 +2794,13 @@ cr.define('downloads', function() {
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Action links are elements that are used to perform an in-page navigation or
-// action (e.g. showing a dialog).
-//
-// They look like normal anchor (<a>) tags as their text color is blue. However,
-// they're subtly different as they're not initially underlined (giving users a
-// clue that underlined links navigate while action links don't).
-//
-// Action links look very similar to normal links when hovered (hand cursor,
-// underlined). This gives the user an idea that clicking this link will do
-// something similar to navigation but in the same page.
-//
-// They can be created in JavaScript like this:
-//
-// var link = document.createElement('a', 'action-link'); // Note second arg.
-//
-// or with a constructor like this:
-//
-// var link = new ActionLink();
-//
-// They can be used easily from HTML as well, like so:
-//
-// <a is="action-link">Click me!</a>
-//
-// NOTE: <action-link> and document.createElement('action-link') don't work.
-
-/**
- * @constructor
- * @extends {HTMLAnchorElement}
- */
+
var ActionLink = document.registerElement('action-link', {
prototype: {
__proto__: HTMLAnchorElement.prototype,
/** @this {ActionLink} */
createdCallback: function() {
- // Action links can start disabled (e.g. <a is="action-link" disabled>).
this.tabIndex = this.disabled ? -1 : 0;
if (!this.hasAttribute('role'))
@@ -4296,11 +2808,6 @@ var ActionLink = document.registerElement('action-link', {
this.addEventListener('keydown', function(e) {
if (!this.disabled && e.key == 'Enter' && !this.href) {
- // Schedule a click asynchronously because other 'keydown' handlers
- // may still run later (e.g. document.addEventListener('keydown')).
- // Specifically options dialogs break when this timeout isn't here.
- // NOTE: this affects the "trusted" state of the ensuing click. I
- // haven't found anything that breaks because of this (yet).
window.setTimeout(this.click.bind(this), 0);
}
});
@@ -4315,13 +2822,10 @@ var ActionLink = document.registerElement('action-link', {
}
this.addEventListener('mousedown', function() {
- // This handlers strives to match the behavior of <a href="...">.
- // While the mouse is down, prevent text selection from dragging.
document.addEventListener('selectstart', preventDefault);
document.addEventListener('mouseup', removePreventDefault);
- // If focus started via mouse press, don't show an outline.
if (document.activeElement != this)
this.classList.add('no-outline');
});
@@ -4364,7 +2868,6 @@ var ActionLink = document.registerElement('action-link', {
});
(function() {
- // monostate data
var metaDatas = {};
var metaArrays = {};
var singleton = null;
@@ -4375,44 +2878,28 @@ var ActionLink = document.registerElement('action-link', {
properties: {
- /**
- * The type of meta-data. All meta-data of the same type is stored
- * together.
- */
type: {
type: String,
value: 'default',
observer: '_typeChanged'
},
- /**
- * The key used to store `value` under the `type` namespace.
- */
key: {
type: String,
observer: '_keyChanged'
},
- /**
- * The meta-data to store or retrieve.
- */
value: {
type: Object,
notify: true,
observer: '_valueChanged'
},
- /**
- * If true, `value` is set to the iron-meta instance itself.
- */
self: {
type: Boolean,
observer: '_selfChanged'
},
- /**
- * Array of all meta-data values for the given type.
- */
list: {
type: Array,
notify: true
@@ -4424,12 +2911,6 @@ var ActionLink = document.registerElement('action-link', {
hidden: true
},
- /**
- * Only runs if someone invokes the factory/constructor directly
- * e.g. `new Polymer.IronMeta()`
- *
- * @param {{type: (string|undefined), key: (string|undefined), value}=} config
- */
factoryImpl: function(config) {
if (config) {
for (var n in config) {
@@ -4445,7 +2926,6 @@ var ActionLink = document.registerElement('action-link', {
},
created: function() {
- // TODO(sjmiles): good for debugging?
this._metaDatas = metaDatas;
this._metaArrays = metaArrays;
},
@@ -4477,13 +2957,6 @@ var ActionLink = document.registerElement('action-link', {
this._registerKeyValue(this.key, this.value);
},
- /**
- * Retrieves meta data value by key.
- *
- * @method byKey
- * @param {string} key The key of the meta-data to be returned.
- * @return {*}
- */
byKey: function(key) {
return this._metaData && this._metaData[key];
},
@@ -4527,62 +3000,29 @@ var ActionLink = document.registerElement('action-link', {
return singleton;
};
- /**
- `iron-meta-query` can be used to access infomation stored in `iron-meta`.
-
- Examples:
-
- If I create an instance like this:
-
- <iron-meta key="info" value="foo/bar"></iron-meta>
-
- Note that value="foo/bar" is the metadata I've defined. I could define more
- attributes or use child nodes to define additional metadata.
-
- Now I can access that element (and it's metadata) from any `iron-meta-query` instance:
-
- var value = new Polymer.IronMetaQuery({key: 'info'}).value;
-
- @group Polymer Iron Elements
- @element iron-meta-query
- */
Polymer.IronMetaQuery = Polymer({
is: 'iron-meta-query',
properties: {
- /**
- * The type of meta-data. All meta-data of the same type is stored
- * together.
- */
type: {
type: String,
value: 'default',
observer: '_typeChanged'
},
- /**
- * Specifies a key to use for retrieving `value` from the `type`
- * namespace.
- */
key: {
type: String,
observer: '_keyChanged'
},
- /**
- * The meta-data to store or retrieve.
- */
value: {
type: Object,
notify: true,
readOnly: true
},
- /**
- * Array of all meta-data values for the given type.
- */
list: {
type: Array,
notify: true
@@ -4590,12 +3030,6 @@ var ActionLink = document.registerElement('action-link', {
},
- /**
- * Actually a factory method, not a true constructor. Only runs if
- * someone invokes it directly (via `new Polymer.IronMeta()`);
- *
- * @param {{type: (string|undefined), key: (string|undefined)}=} config
- */
factoryImpl: function(config) {
if (config) {
for (var n in config) {
@@ -4610,7 +3044,6 @@ var ActionLink = document.registerElement('action-link', {
},
created: function() {
- // TODO(sjmiles): good for debugging?
this._metaDatas = metaDatas;
this._metaArrays = metaArrays;
},
@@ -4627,11 +3060,6 @@ var ActionLink = document.registerElement('action-link', {
}
},
- /**
- * Retrieves meta data value by key.
- * @param {string} key The key of the meta-data to be returned.
- * @return {*}
- */
byKey: function(key) {
return this._metaData && this._metaData[key];
}
@@ -4645,37 +3073,21 @@ Polymer({
properties: {
- /**
- * The name of the icon to use. The name should be of the form:
- * `iconset_name:icon_name`.
- */
icon: {
type: String,
observer: '_iconChanged'
},
- /**
- * The name of the theme to used, if one is specified by the
- * iconset.
- */
theme: {
type: String,
observer: '_updateIcon'
},
- /**
- * If using iron-icon without an iconset, you can set the src to be
- * the URL of an individual icon image file. Note that this will take
- * precedence over a given icon attribute.
- */
src: {
type: String,
observer: '_srcChanged'
},
- /**
- * @type {!Polymer.IronMeta}
- */
_meta: {
value: Polymer.Base.create('iron-meta', {type: 'iconset'}),
observer: '_updateIcon'
@@ -4736,17 +3148,10 @@ Polymer({
}
});
-/**
- * @demo demo/index.html
- * @polymerBehavior
- */
Polymer.IronControlState = {
properties: {
- /**
- * If true, the element currently has focus.
- */
focused: {
type: Boolean,
value: false,
@@ -4755,9 +3160,6 @@ Polymer({
reflectToAttribute: true
},
- /**
- * If true, the user cannot interact with this element.
- */
disabled: {
type: Boolean,
value: false,
@@ -4789,11 +3191,6 @@ Polymer({
},
_focusBlurHandler: function(event) {
- // NOTE(cdata): if we are in ShadowDOM land, `event.target` will
- // eventually become `this` due to retargeting; if we are not in
- // ShadowDOM land, `event.target` will eventually become `this` due
- // to the second conditional which fires a synthetic event (that is also
- // handled). In either case, we can disregard `event.path`.
if (event.target === this) {
this._setFocused(event.type === 'focus');
@@ -4823,24 +3220,16 @@ Polymer({
},
_changedControlState: function() {
- // _controlStateChanged is abstract, follow-on behaviors may implement it
if (this._controlStateChanged) {
this._controlStateChanged();
}
}
};
-/**
- * @demo demo/index.html
- * @polymerBehavior Polymer.IronButtonState
- */
Polymer.IronButtonStateImpl = {
properties: {
- /**
- * If true, the user is currently holding down the button.
- */
pressed: {
type: Boolean,
readOnly: true,
@@ -4849,19 +3238,12 @@ Polymer({
observer: '_pressedChanged'
},
- /**
- * If true, the button toggles the active state with each tap or press
- * of the spacebar.
- */
toggles: {
type: Boolean,
value: false,
reflectToAttribute: true
},
- /**
- * If true, the button is a toggle and is currently in the active state.
- */
active: {
type: Boolean,
value: false,
@@ -4869,30 +3251,17 @@ Polymer({
reflectToAttribute: true
},
- /**
- * True if the element is currently being pressed by a "pointer," which
- * is loosely defined as mouse or touch input (but specifically excluding
- * keyboard input).
- */
pointerDown: {
type: Boolean,
readOnly: true,
value: false
},
- /**
- * True if the input device that caused the element to receive focus
- * was a keyboard.
- */
receivedFocusFromKeyboard: {
type: Boolean,
readOnly: true
},
- /**
- * The aria attribute to be set if the button is a toggle and in the
- * active state.
- */
ariaActiveAttribute: {
type: String,
value: 'aria-pressed',
@@ -4921,7 +3290,6 @@ Polymer({
_tapHandler: function() {
if (this.toggles) {
- // a tap is needed to toggle the active state
this._userActivate(!this.active);
} else {
this.active = false;
@@ -4932,8 +3300,6 @@ Polymer({
this._setReceivedFocusFromKeyboard(!this.pointerDown && focused);
},
- // to emulate native checkbox, (de-)activations from a user interaction fire
- // 'change' events
_userActivate: function(active) {
if (this.active !== active) {
this.active = active;
@@ -4952,15 +3318,10 @@ Polymer({
this._setPressed(false);
},
- /**
- * @param {!KeyboardEvent} event .
- */
_spaceKeyDownHandler: function(event) {
var keyboardEvent = event.detail.keyboardEvent;
var target = Polymer.dom(keyboardEvent).localTarget;
- // Ignore the event if this is coming from a focused light child, since that
- // element will deal with it.
if (this.isLightDescendant(/** @type {Node} */(target)))
return;
@@ -4969,15 +3330,10 @@ Polymer({
this._setPressed(true);
},
- /**
- * @param {!KeyboardEvent} event .
- */
_spaceKeyUpHandler: function(event) {
var keyboardEvent = event.detail.keyboardEvent;
var target = Polymer.dom(keyboardEvent).localTarget;
- // Ignore the event if this is coming from a focused light child, since that
- // element will deal with it.
if (this.isLightDescendant(/** @type {Node} */(target)))
return;
@@ -4987,15 +3343,12 @@ Polymer({
this._setPressed(false);
},
- // trigger click asynchronously, the asynchrony is useful to allow one
- // event handler to unwind before triggering another event
_asyncClick: function() {
this.async(function() {
this.click();
}, 1);
},
- // any of these changes are considered a change to button state
_pressedChanged: function(pressed) {
this._changedButtonState();
@@ -5025,7 +3378,6 @@ Polymer({
}
},
- // provide hook for follow-on behaviors to react to button-state
_changedButtonState: function() {
if (this._buttonStateChanged) {
@@ -5053,10 +3405,6 @@ Polymer({
window.performance.now.bind(window.performance) : Date.now
};
- /**
- * @param {HTMLElement} element
- * @constructor
- */
function ElementMetrics(element) {
this.element = element;
this.width = this.boundingRect.width;
@@ -5080,10 +3428,6 @@ Polymer({
}
};
- /**
- * @param {HTMLElement} element
- * @constructor
- */
function Ripple(element) {
this.element = element;
this.color = window.getComputedStyle(element).color;
@@ -5177,8 +3521,6 @@ Polymer({
},
get outerOpacity() {
- // Linear increase in background opacity, capped at the opacity
- // of the wavefront (waveOpacity).
var outerOpacity = this.mouseUpElapsedSeconds * 0.3;
var waveOpacity = this.opacity;
@@ -5257,8 +3599,6 @@ Polymer({
dy = this.yNow - (this.containerMetrics.height / 2);
- // 2d transform for safari because of border-radius and overflow:hidden clipping bug.
- // https://bugs.webkit.org/show_bug.cgi?id=98538
this.waveContainer.style.webkitTransform = 'translate(' + dx + 'px, ' + dy + 'px)';
this.waveContainer.style.transform = 'translate3d(' + dx + 'px, ' + dy + 'px, 0)';
this.wave.style.webkitTransform = 'scale(' + scale + ',' + scale + ')';
@@ -5334,62 +3674,26 @@ Polymer({
],
properties: {
- /**
- * The initial opacity set on the wave.
- *
- * @attribute initialOpacity
- * @type number
- * @default 0.25
- */
initialOpacity: {
type: Number,
value: 0.25
},
- /**
- * How fast (opacity per second) the wave fades out.
- *
- * @attribute opacityDecayVelocity
- * @type number
- * @default 0.8
- */
opacityDecayVelocity: {
type: Number,
value: 0.8
},
- /**
- * If true, ripples will exhibit a gravitational pull towards
- * the center of their container as they fade away.
- *
- * @attribute recenters
- * @type boolean
- * @default false
- */
recenters: {
type: Boolean,
value: false
},
- /**
- * If true, ripples will center inside its container
- *
- * @attribute recenters
- * @type boolean
- * @default false
- */
center: {
type: Boolean,
value: false
},
- /**
- * A list of the visual ripples.
- *
- * @attribute ripples
- * @type Array
- * @default []
- */
ripples: {
type: Array,
value: function() {
@@ -5397,10 +3701,6 @@ Polymer({
}
},
- /**
- * True when there are visible ripples animating within the
- * element.
- */
animating: {
type: Boolean,
readOnly: true,
@@ -5408,22 +3708,12 @@ Polymer({
value: false
},
- /**
- * If true, the ripple will remain in the "down" state until `holdDown`
- * is set to false again.
- */
holdDown: {
type: Boolean,
value: false,
observer: '_holdDownChanged'
},
- /**
- * If true, the ripple will not generate a ripple effect
- * via pointer interaction.
- * Calling ripple's imperative api like `simulatedRipple` will
- * still generate the ripple effect.
- */
noink: {
type: Boolean,
value: false
@@ -5452,9 +3742,6 @@ Polymer({
},
attached: function() {
- // Set up a11yKeysBehavior to listen to key events on the target,
- // so that space and enter activate the ripple even if the target doesn't
- // handle key events. The key handlers deal with `noink` themselves.
if (this.parentNode.nodeType == 11) { // DOCUMENT_FRAGMENT_NODE
this.keyEventTarget = Polymer.dom(this).getOwnerRoot().host;
} else {
@@ -5484,28 +3771,17 @@ Polymer({
simulatedRipple: function() {
this.downAction(null);
- // Please see polymer/polymer#1305
this.async(function() {
this.upAction();
}, 1);
},
- /**
- * Provokes a ripple down effect via a UI event,
- * respecting the `noink` property.
- * @param {Event=} event
- */
uiDownAction: function(event) {
if (!this.noink) {
this.downAction(event);
}
},
- /**
- * Provokes a ripple down effect via a UI event,
- * *not* respecting the `noink` property.
- * @param {Event=} event
- */
downAction: function(event) {
if (this.holdDown && this.ripples.length > 0) {
return;
@@ -5521,22 +3797,12 @@ Polymer({
}
},
- /**
- * Provokes a ripple up effect via a UI event,
- * respecting the `noink` property.
- * @param {Event=} event
- */
uiUpAction: function(event) {
if (!this.noink) {
this.upAction(event);
}
},
- /**
- * Provokes a ripple up effect via a UI event,
- * *not* respecting the `noink` property.
- * @param {Event=} event
- */
upAction: function(event) {
if (this.holdDown) {
return;
@@ -5623,8 +3889,6 @@ Polymer({
this.uiUpAction();
},
- // note: holdDown does not respect noink since it can be a focus based
- // effect.
_holdDownChanged: function(newVal, oldVal) {
if (oldVal === undefined) {
return;
@@ -5636,58 +3900,26 @@ Polymer({
}
}
- /**
- Fired when the animation finishes.
- This is useful if you want to wait until
- the ripple animation finishes to perform some action.
-
- @event transitionend
- @param {{node: Object}} detail Contains the animated node.
- */
});
})();
-/**
- * `Polymer.PaperRippleBehavior` dynamically implements a ripple
- * when the element has focus via pointer or keyboard.
- *
- * NOTE: This behavior is intended to be used in conjunction with and after
- * `Polymer.IronButtonState` and `Polymer.IronControlState`.
- *
- * @polymerBehavior Polymer.PaperRippleBehavior
- */
Polymer.PaperRippleBehavior = {
properties: {
- /**
- * If true, the element will not produce a ripple effect when interacted
- * with via the pointer.
- */
noink: {
type: Boolean,
observer: '_noinkChanged'
},
- /**
- * @type {Element|undefined}
- */
_rippleContainer: {
type: Object,
}
},
- /**
- * Ensures a `<paper-ripple>` element is available when the element is
- * focused.
- */
_buttonStateChanged: function() {
if (this.focused) {
this.ensureRipple();
}
},
- /**
- * In addition to the functionality provided in `IronButtonState`, ensures
- * a ripple effect is created when the element is in a `pressed` state.
- */
_downHandler: function(event) {
Polymer.IronButtonStateImpl._downHandler.call(this, event);
if (this.pressed) {
@@ -5695,12 +3927,6 @@ Polymer({
}
},
- /**
- * Ensures this element contains a ripple effect. For startup efficiency
- * the ripple effect is dynamically on demand when needed.
- * @param {!Event=} optTriggeringEvent (optional) event that triggered the
- * ripple.
- */
ensureRipple: function(optTriggeringEvent) {
if (!this.hasRipple()) {
this._ripple = this._createRipple();
@@ -5710,9 +3936,6 @@ Polymer({
Polymer.dom(rippleContainer).appendChild(this._ripple);
}
if (optTriggeringEvent) {
- // Check if the event happened inside of the ripple container
- // Fall back to host instead of the root because distributed text
- // nodes are not valid event targets
var domContainer = Polymer.dom(this._rippleContainer || this);
var target = Polymer.dom(optTriggeringEvent).rootTarget;
if (domContainer.deepContains( /** @type {Node} */(target))) {
@@ -5722,30 +3945,15 @@ Polymer({
}
},
- /**
- * Returns the `<paper-ripple>` element used by this element to create
- * ripple effects. The element's ripple is created on demand, when
- * necessary, and calling this method will force the
- * ripple to be created.
- */
getRipple: function() {
this.ensureRipple();
return this._ripple;
},
- /**
- * Returns true if this element currently contains a ripple effect.
- * @return {boolean}
- */
hasRipple: function() {
return Boolean(this._ripple);
},
- /**
- * Create the element's ripple effect via creating a `<paper-ripple>`.
- * Override this method to customize the ripple element.
- * @return {!PaperRippleElement} Returns a `<paper-ripple>` element.
- */
_createRipple: function() {
return /** @type {!PaperRippleElement} */ (
document.createElement('paper-ripple'));
@@ -5760,15 +3968,6 @@ Polymer({
/** @polymerBehavior Polymer.PaperButtonBehavior */
Polymer.PaperButtonBehaviorImpl = {
properties: {
- /**
- * The z-depth of this element, from 0-5. Setting to 0 will remove the
- * shadow, and each increasing number greater than 0 will be "deeper"
- * than the last.
- *
- * @attribute elevation
- * @type number
- * @default 1
- */
elevation: {
type: Number,
reflectToAttribute: true,
@@ -5803,26 +4002,13 @@ Polymer({
this.toggleClass('keyboard-focus', receivedFocusFromKeyboard);
},
- /**
- * In addition to `IronButtonState` behavior, when space key goes down,
- * create a ripple down effect.
- *
- * @param {!KeyboardEvent} event .
- */
_spaceKeyDownHandler: function(event) {
Polymer.IronButtonStateImpl._spaceKeyDownHandler.call(this, event);
- // Ensure that there is at most one ripple when the space key is held down.
if (this.hasRipple() && this.getRipple().ripples.length < 1) {
this._ripple.uiDownAction();
}
},
- /**
- * In addition to `IronButtonState` behavior, when space key goes up,
- * create a ripple up effect.
- *
- * @param {!KeyboardEvent} event .
- */
_spaceKeyUpHandler: function(event) {
Polymer.IronButtonStateImpl._spaceKeyUpHandler.call(this, event);
if (this.hasRipple()) {
@@ -5846,9 +4032,6 @@ Polymer({
],
properties: {
- /**
- * If true, the button should be styled with a shadow.
- */
raised: {
type: Boolean,
reflectToAttribute: true,
@@ -5865,14 +4048,6 @@ Polymer({
}
}
- /**
- Fired when the animation finishes.
- This is useful if you want to wait until
- the ripple animation finishes to perform some action.
-
- @event transitionend
- Event param: {{node: Object}} detail Contains the animated node.
- */
});
Polymer({
is: 'paper-icon-button-light',
@@ -5897,9 +4072,6 @@ Polymer({
this.getRipple().upAction();
},
- /**
- * @param {...*} var_args
- */
ensureRipple: function(var_args) {
var lastRipple = this._ripple;
Polymer.PaperRippleBehavior.ensureRipple.apply(this, arguments);
@@ -5909,19 +4081,10 @@ Polymer({
}
}
});
-/**
- * `iron-range-behavior` provides the behavior for something with a minimum to maximum range.
- *
- * @demo demo/index.html
- * @polymerBehavior
- */
Polymer.IronRangeBehavior = {
properties: {
- /**
- * The number that represents the current value.
- */
value: {
type: Number,
value: 0,
@@ -5929,36 +4092,24 @@ Polymer({
reflectToAttribute: true
},
- /**
- * The number that indicates the minimum value of the range.
- */
min: {
type: Number,
value: 0,
notify: true
},
- /**
- * The number that indicates the maximum value of the range.
- */
max: {
type: Number,
value: 100,
notify: true
},
- /**
- * Specifies the value granularity of the range's value.
- */
step: {
type: Number,
value: 1,
notify: true
},
- /**
- * Returns the ratio of the value.
- */
ratio: {
type: Number,
value: 0,
@@ -5980,7 +4131,6 @@ Polymer({
},
_calcStep: function(value) {
- // polymer/issues/2493
value = parseFloat(value);
if (!this.step) {
@@ -5989,14 +4139,6 @@ Polymer({
var numSteps = Math.round((value - this.min) / this.step);
if (this.step < 1) {
- /**
- * For small values of this.step, if we calculate the step using
- * `Math.round(value / step) * step` we may hit a precision point issue
- * eg. 0.1 * 0.2 = 0.020000000000000004
- * http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
- *
- * as a work around we can divide by the reciprocal of `step`
- */
return numSteps / (1 / this.step) + this.min;
} else {
return numSteps * this.step + this.min;
@@ -6023,35 +4165,23 @@ Polymer({
],
properties: {
- /**
- * The number that represents the current secondary progress.
- */
secondaryProgress: {
type: Number,
value: 0
},
- /**
- * The secondary ratio
- */
secondaryRatio: {
type: Number,
value: 0,
readOnly: true
},
- /**
- * Use an indeterminate progress indicator.
- */
indeterminate: {
type: Boolean,
value: false,
observer: '_toggleIndeterminate'
},
- /**
- * True if the progress is disabled.
- */
disabled: {
type: Boolean,
value: false,
@@ -6069,8 +4199,6 @@ Polymer({
},
_toggleIndeterminate: function(indeterminate) {
- // If we use attribute/class binding, the animation sometimes doesn't translate properly
- // on Safari 7.1. So instead, we toggle the class here in the update method.
this.toggleClass('indeterminate', indeterminate, this.$.primaryProgress);
},
@@ -6109,57 +4237,16 @@ Polymer({
return secondaryRatio === 0;
}
});
-/**
- * The `iron-iconset-svg` element allows users to define their own icon sets
- * that contain svg icons. The svg icon elements should be children of the
- * `iron-iconset-svg` element. Multiple icons should be given distinct id's.
- *
- * Using svg elements to create icons has a few advantages over traditional
- * bitmap graphics like jpg or png. Icons that use svg are vector based so
- * they are resolution independent and should look good on any device. They
- * are stylable via css. Icons can be themed, colorized, and even animated.
- *
- * Example:
- *
- * <iron-iconset-svg name="my-svg-icons" size="24">
- * <svg>
- * <defs>
- * <g id="shape">
- * <rect x="12" y="0" width="12" height="24" />
- * <circle cx="12" cy="12" r="12" />
- * </g>
- * </defs>
- * </svg>
- * </iron-iconset-svg>
- *
- * This will automatically register the icon set "my-svg-icons" to the iconset
- * database. To use these icons from within another element, make a
- * `iron-iconset` element and call the `byId` method
- * to retrieve a given iconset. To apply a particular icon inside an
- * element use the `applyIcon` method. For example:
- *
- * iconset.applyIcon(iconNode, 'car');
- *
- * @element iron-iconset-svg
- * @demo demo/index.html
- * @implements {Polymer.Iconset}
- */
Polymer({
is: 'iron-iconset-svg',
properties: {
- /**
- * The name of the iconset.
- */
name: {
type: String,
observer: '_nameChanged'
},
- /**
- * The size of an individual icon. Note that icons must be square.
- */
size: {
type: Number,
value: 24
@@ -6171,11 +4258,6 @@ Polymer({
this.style.display = 'none';
},
- /**
- * Construct an array of all icon names in this iconset.
- *
- * @return {!Array} Array of icon names.
- */
getIconNames: function() {
this._icons = this._createIconMap();
return Object.keys(this._icons).map(function(n) {
@@ -6183,23 +4265,9 @@ Polymer({
}, this);
},
- /**
- * Applies an icon to the given element.
- *
- * An svg icon is prepended to the element's shadowRoot if it exists,
- * otherwise to the element itself.
- *
- * @method applyIcon
- * @param {Element} element Element to which the icon is applied.
- * @param {string} iconName Name of the icon to apply.
- * @return {?Element} The svg element which renders the icon.
- */
applyIcon: function(element, iconName) {
- // insert svg element into shadow root, if it exists
element = element.root || element;
- // Remove old svg element
this.removeIcon(element);
- // install new svg element
var svg = this._cloneIcon(iconName);
if (svg) {
var pde = Polymer.dom(element);
@@ -6209,25 +4277,13 @@ Polymer({
return null;
},
- /**
- * Remove an icon from the given element by undoing the changes effected
- * by `applyIcon`.
- *
- * @param {Element} element The element from which the icon is removed.
- */
removeIcon: function(element) {
- // Remove old svg element
if (element._svgIcon) {
Polymer.dom(element).removeChild(element._svgIcon);
element._svgIcon = null;
}
},
- /**
- *
- * When name is changed, register iconset metadata
- *
- */
_nameChanged: function() {
new Polymer.IronMeta({type: 'iconset', key: this.name, value: this});
this.async(function() {
@@ -6235,15 +4291,7 @@ Polymer({
});
},
- /**
- * Create a map of child SVG elements by id.
- *
- * @return {!Object} Map of id's to SVG elements.
- */
_createIconMap: function() {
- // Objects chained to Object.prototype (`{}`) have members. Specifically,
- // on FF there is a `watch` method that confuses the icon map, so we
- // need to use a null-based object here.
var icons = Object.create(null);
Polymer.dom(this).querySelectorAll('[id]')
.forEach(function(icon) {
@@ -6252,25 +4300,11 @@ Polymer({
return icons;
},
- /**
- * Produce installable clone of the SVG element matching `id` in this
- * iconset, or `undefined` if there is no matching element.
- *
- * @return {Element} Returns an installable clone of the SVG element
- * matching `id`.
- */
_cloneIcon: function(id) {
- // create the icon map on-demand, since the iconset itself has no discrete
- // signal to know when it's children are fully parsed
this._icons = this._icons || this._createIconMap();
return this._prepareSvgClone(this._icons[id], this.size);
},
- /**
- * @param {Element} sourceSvg
- * @param {number} size
- * @return {Element}
- */
_prepareSvgClone: function(sourceSvg, size) {
if (sourceSvg) {
var content = sourceSvg.cloneNode(true),
@@ -6278,8 +4312,6 @@ Polymer({
viewBox = content.getAttribute('viewBox') || '0 0 ' + size + ' ' + size;
svg.setAttribute('viewBox', viewBox);
svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
- // TODO(dfreedm): `pointer-events: none` works around https://crbug.com/370136
- // TODO(sjmiles): inline style may not be ideal, but avoids requiring a shadow-root
svg.style.cssText = 'pointer-events: none; display: block; width: 100%; height: 100%;';
svg.appendChild(content).removeAttribute('id');
return svg;
@@ -6358,8 +4390,6 @@ cr.define('downloads', function() {
},
observers: [
- // TODO(dbeam): this gets called way more when I observe data.by_ext_id
- // and data.by_ext_name directly. Why?
'observeControlledBy_(controlledBy_)',
'observeIsDangerous_(isDangerous_, data)',
],
@@ -6560,19 +4590,11 @@ cr.define('downloads', function() {
downloads.ActionService.getInstance().discardDangerous(this.data.id);
},
- /**
- * @private
- * @param {Event} e
- */
onDragStart_: function(e) {
e.preventDefault();
downloads.ActionService.getInstance().drag(this.data.id);
},
- /**
- * @param {Event} e
- * @private
- */
onFileLinkTap_: function(e) {
e.preventDefault();
downloads.ActionService.getInstance().openFile(this.data.id);
@@ -6630,10 +4652,6 @@ Polymer({
Polymer.PaperItemBehavior
]
});
-/**
- * @param {!Function} selectCallback
- * @constructor
- */
Polymer.IronSelection = function(selectCallback) {
this.selection = [];
this.selectCallback = selectCallback;
@@ -6641,24 +4659,10 @@ Polymer({
Polymer.IronSelection.prototype = {
- /**
- * Retrieves the selected item(s).
- *
- * @method get
- * @returns Returns the selected item(s). If the multi property is true,
- * `get` will return an array, otherwise it will return
- * the selected item or undefined if there is no selection.
- */
get: function() {
return this.multi ? this.selection.slice() : this.selection[0];
},
- /**
- * Clears all the selection except the ones indicated.
- *
- * @method clear
- * @param {Array} excludes items to be excluded.
- */
clear: function(excludes) {
this.selection.slice().forEach(function(item) {
if (!excludes || excludes.indexOf(item) < 0) {
@@ -6667,28 +4671,13 @@ Polymer({
}, this);
},
- /**
- * Indicates if a given item is selected.
- *
- * @method isSelected
- * @param {*} item The item whose selection state should be checked.
- * @returns Returns true if `item` is selected.
- */
isSelected: function(item) {
return this.selection.indexOf(item) >= 0;
},
- /**
- * Sets the selection state for a given item to either selected or deselected.
- *
- * @method setItemSelected
- * @param {*} item The item to select.
- * @param {boolean} isSelected True for selected, false for deselected.
- */
setItemSelected: function(item, isSelected) {
if (item != null) {
if (isSelected !== this.isSelected(item)) {
- // proceed to update selection only if requested state differs from current
if (isSelected) {
this.selection.push(item);
} else {
@@ -6704,14 +4693,6 @@ Polymer({
}
},
- /**
- * Sets the selection state for a given item. If the `multi` property
- * is true, then the selected state of `item` will be toggled; otherwise
- * the `item` will be selected.
- *
- * @method select
- * @param {*} item The item to select.
- */
select: function(item) {
if (this.multi) {
this.toggle(item);
@@ -6721,12 +4702,6 @@ Polymer({
}
},
- /**
- * Toggles the selection state for `item`.
- *
- * @method toggle
- * @param {*} item The item to toggle.
- */
toggle: function(item) {
this.setItemSelected(item, !this.isSelected(item));
}
@@ -6735,116 +4710,51 @@ Polymer({
/** @polymerBehavior */
Polymer.IronSelectableBehavior = {
- /**
- * Fired when iron-selector is activated (selected or deselected).
- * It is fired before the selected items are changed.
- * Cancel the event to abort selection.
- *
- * @event iron-activate
- */
-
- /**
- * Fired when an item is selected
- *
- * @event iron-select
- */
-
- /**
- * Fired when an item is deselected
- *
- * @event iron-deselect
- */
-
- /**
- * Fired when the list of selectable items changes (e.g., items are
- * added or removed). The detail of the event is a mutation record that
- * describes what changed.
- *
- * @event iron-items-changed
- */
+
+
+
properties: {
- /**
- * If you want to use an attribute value or property of an element for
- * `selected` instead of the index, set this to the name of the attribute
- * or property. Hyphenated values are converted to camel case when used to
- * look up the property of a selectable element. Camel cased values are
- * *not* converted to hyphenated values for attribute lookup. It's
- * recommended that you provide the hyphenated form of the name so that
- * selection works in both cases. (Use `attr-or-property-name` instead of
- * `attrOrPropertyName`.)
- */
attrForSelected: {
type: String,
value: null
},
- /**
- * Gets or sets the selected element. The default is to use the index of the item.
- * @type {string|number}
- */
selected: {
type: String,
notify: true
},
- /**
- * Returns the currently selected item.
- *
- * @type {?Object}
- */
selectedItem: {
type: Object,
readOnly: true,
notify: true
},
- /**
- * The event that fires from items when they are selected. Selectable
- * will listen for this event from items and update the selection state.
- * Set to empty string to listen to no events.
- */
activateEvent: {
type: String,
value: 'tap',
observer: '_activateEventChanged'
},
- /**
- * This is a CSS selector string. If this is set, only items that match the CSS selector
- * are selectable.
- */
selectable: String,
- /**
- * The class to set on elements when selected.
- */
selectedClass: {
type: String,
value: 'iron-selected'
},
- /**
- * The attribute to set on elements when selected.
- */
selectedAttribute: {
type: String,
value: null
},
- /**
- * Default fallback if the selection based on selected with `attrForSelected`
- * is not found.
- */
fallbackSelection: {
type: String,
value: null
},
- /**
- * The list of items from which a selection can be made.
- */
items: {
type: Array,
readOnly: true,
@@ -6854,12 +4764,6 @@ Polymer({
}
},
- /**
- * The set of excluded elements where the key is the `localName`
- * of the element that will be ignored from the item list.
- *
- * @default {template: 1}
- */
_excludedLocalNames: {
type: Object,
value: function() {
@@ -6897,69 +4801,29 @@ Polymer({
this._removeListener(this.activateEvent);
},
- /**
- * Returns the index of the given item.
- *
- * @method indexOf
- * @param {Object} item
- * @returns Returns the index of the item
- */
indexOf: function(item) {
return this.items.indexOf(item);
},
- /**
- * Selects the given value.
- *
- * @method select
- * @param {string|number} value the value to select.
- */
select: function(value) {
this.selected = value;
},
- /**
- * Selects the previous item.
- *
- * @method selectPrevious
- */
selectPrevious: function() {
var length = this.items.length;
var index = (Number(this._valueToIndex(this.selected)) - 1 + length) % length;
this.selected = this._indexToValue(index);
},
- /**
- * Selects the next item.
- *
- * @method selectNext
- */
selectNext: function() {
var index = (Number(this._valueToIndex(this.selected)) + 1) % this.items.length;
this.selected = this._indexToValue(index);
},
- /**
- * Selects the item at the given index.
- *
- * @method selectIndex
- */
selectIndex: function(index) {
this.select(this._indexToValue(index));
},
- /**
- * Force a synchronous update of the `items` property.
- *
- * NOTE: Consider listening for the `iron-items-changed` event to respond to
- * updates to the set of selectable items after updates to the DOM list and
- * selection state have been made.
- *
- * WARNING: If you are using this method, you should probably consider an
- * alternate approach. Synchronously querying for items is potentially
- * slow for many use cases. The `items` property will update asynchronously
- * on its own to reflect selectable items in the DOM.
- */
forceSynchronousItemUpdate: function() {
this._updateItems();
},
@@ -7005,8 +4869,6 @@ Polymer({
_selectSelected: function(selected) {
this._selection.select(this._valueToItem(this.selected));
- // Check for items, since this array is populated only when attached
- // Since Number(0) is falsy, explicitly check for undefined
if (this.fallbackSelection && this.items.length && (this._selection.get() === undefined)) {
this.selected = this.fallbackSelection;
}
@@ -7063,7 +4925,6 @@ Polymer({
this._setSelectedItem(this._selection.get());
},
- // observe items change under the given node.
_observeItems: function(node) {
return Polymer.dom(node).observeNodes(function(mutation) {
this._updateItems();
@@ -7072,8 +4933,6 @@ Polymer({
this._updateSelected();
}
- // Let other interested parties know about the change so that
- // we don't have to recreate mutation observers everywhere.
this.fire('iron-items-changed', mutation, {
bubbles: false,
cancelable: false
@@ -7107,27 +4966,17 @@ Polymer({
Polymer.IronMultiSelectableBehaviorImpl = {
properties: {
- /**
- * If true, multiple selections are allowed.
- */
multi: {
type: Boolean,
value: false,
observer: 'multiChanged'
},
- /**
- * Gets or sets the selected elements. This is used instead of `selected` when `multi`
- * is true.
- */
selectedValues: {
type: Array,
notify: true
},
- /**
- * Returns an array of currently selected items.
- */
selectedItems: {
type: Array,
readOnly: true,
@@ -7140,13 +4989,6 @@ Polymer({
'_updateSelected(selectedValues.splices)'
],
- /**
- * Selects the given value. If the `multi` property is true, then the selected state of the
- * `value` will be toggled; otherwise the `value` will be selected.
- *
- * @method select
- * @param {string|number} value the value to select.
- */
select: function(value) {
if (this.multi) {
if (this.selectedValues) {
@@ -7191,13 +5033,10 @@ Polymer({
_selectMulti: function(values) {
if (values) {
var selectedItems = this._valuesToItems(values);
- // clear all but the current selected items
this._selection.clear(selectedItems);
- // select only those not selected yet
for (var i = 0; i < selectedItems.length; i++) {
this._selection.setItemSelected(selectedItems[i], true);
}
- // Check for items, since this array is populated only when attached
if (this.fallbackSelection && this.items.length && !this._selection.get().length) {
var fallback = this._valueToItem(this.fallbackSelection);
if (fallback) {
@@ -7241,31 +5080,16 @@ Polymer({
Polymer.IronSelectableBehavior,
Polymer.IronMultiSelectableBehaviorImpl
];
-/**
- * `Polymer.IronMenuBehavior` implements accessible menu behavior.
- *
- * @demo demo/index.html
- * @polymerBehavior Polymer.IronMenuBehavior
- */
Polymer.IronMenuBehaviorImpl = {
properties: {
- /**
- * Returns the currently focused item.
- * @type {?Object}
- */
focusedItem: {
observer: '_focusedItemChanged',
readOnly: true,
type: Object
},
- /**
- * The attribute to use on menu items to look up the item title. Typing the first
- * letter of an item when the menu is open focuses that item. If unset, `textContent`
- * will be used.
- */
attrForItemTitle: {
type: String
}
@@ -7297,15 +5121,7 @@ Polymer({
this._resetTabindices();
},
- /**
- * Selects the given value. If the `multi` property is true, then the selected state of the
- * `value` will be toggled; otherwise the `value` will be selected.
- *
- * @param {string|number} value the value to select.
- */
select: function(value) {
- // Cancel automatically focusing a default item if the menu received focus
- // through a user action selecting a particular item.
if (this._defaultFocusAsync) {
this.cancelAsync(this._defaultFocusAsync);
this._defaultFocusAsync = null;
@@ -7316,12 +5132,6 @@ Polymer({
Polymer.IronMultiSelectableBehaviorImpl.select.apply(this, arguments);
},
- /**
- * Resets all tabindex attributes to the appropriate value based on the
- * current selection state. The appropriate value is `0` (focusable) for
- * the default selected item, and `-1` (not keyboard focusable) for all
- * other items.
- */
_resetTabindices: function() {
var selectedItem = this.multi ? (this.selectedItems && this.selectedItems[0]) : this.selectedItem;
@@ -7330,12 +5140,6 @@ Polymer({
}, this);
},
- /**
- * Sets appropriate ARIA based on whether or not the menu is meant to be
- * multi-selectable.
- *
- * @param {boolean} multi True if the menu should be multi-selectable.
- */
_updateMultiselectable: function(multi) {
if (multi) {
this.setAttribute('aria-multiselectable', 'true');
@@ -7344,12 +5148,6 @@ Polymer({
}
},
- /**
- * Given a KeyboardEvent, this method will focus the appropriate item in the
- * menu (if there is a relevant item, and it is possible to focus it).
- *
- * @param {KeyboardEvent} event A KeyboardEvent.
- */
_focusWithKeyboardEvent: function(event) {
for (var i = 0, item; item = this.items[i]; i++) {
var attr = this.attrForItemTitle || 'textContent';
@@ -7363,11 +5161,6 @@ Polymer({
}
},
- /**
- * Focuses the previous item (relative to the currently focused item) in the
- * menu, disabled items will be skipped.
- * Loop until length + 1 to handle case of single item in menu.
- */
_focusPrevious: function() {
var length = this.items.length;
var curFocusIndex = Number(this.indexOf(this.focusedItem));
@@ -7380,11 +5173,6 @@ Polymer({
}
},
- /**
- * Focuses the next item (relative to the currently focused item) in the
- * menu, disabled items will be skipped.
- * Loop until length + 1 to handle case of single item in menu.
- */
_focusNext: function() {
var length = this.items.length;
var curFocusIndex = Number(this.indexOf(this.focusedItem));
@@ -7397,14 +5185,6 @@ Polymer({
}
},
- /**
- * Mutates items in the menu based on provided selection details, so that
- * all items correctly reflect selection state.
- *
- * @param {Element} item An item in the menu.
- * @param {boolean} isSelected True if the item should be shown in a
- * selected state, otherwise false.
- */
_applySelection: function(item, isSelected) {
if (isSelected) {
item.setAttribute('aria-selected', 'true');
@@ -7414,14 +5194,6 @@ Polymer({
Polymer.IronSelectableBehavior._applySelection.apply(this, arguments);
},
- /**
- * Discretely updates tabindex values among menu items as the focused item
- * changes.
- *
- * @param {Element} focusedItem The element that is currently focused.
- * @param {?Element} old The last element that was considered focused, if
- * applicable.
- */
_focusedItemChanged: function(focusedItem, old) {
old && old.setAttribute('tabindex', '-1');
if (focusedItem) {
@@ -7430,24 +5202,12 @@ Polymer({
}
},
- /**
- * A handler that responds to mutation changes related to the list of items
- * in the menu.
- *
- * @param {CustomEvent} event An event containing mutation records as its
- * detail.
- */
_onIronItemsChanged: function(event) {
if (event.detail.addedNodes.length) {
this._resetTabindices();
}
},
- /**
- * Handler that is called when a shift+tab keypress is detected by the menu.
- *
- * @param {CustomEvent} event A key combination event.
- */
_onShiftTabDown: function(event) {
var oldTabIndex = this.getAttribute('tabindex');
@@ -7460,33 +5220,21 @@ Polymer({
this.async(function() {
this.setAttribute('tabindex', oldTabIndex);
Polymer.IronMenuBehaviorImpl._shiftTabPressed = false;
- // NOTE(cdata): polymer/polymer#1305
}, 1);
},
- /**
- * Handler that is called when the menu receives focus.
- *
- * @param {FocusEvent} event A focus event.
- */
_onFocus: function(event) {
if (Polymer.IronMenuBehaviorImpl._shiftTabPressed) {
- // do not focus the menu itself
return;
}
- // Do not focus the selected tab if the deepest target is part of the
- // menu element's local DOM and is focusable.
var rootTarget = /** @type {?HTMLElement} */(
Polymer.dom(event).rootTarget);
if (rootTarget !== this && typeof rootTarget.tabIndex !== "undefined" && !this.isLightDescendant(rootTarget)) {
return;
}
- // clear the cached focus item
this._defaultFocusAsync = this.async(function() {
- // focus the selected item when the menu receives focus, or the first item
- // if no item is selected
var selectedItem = this.multi ? (this.selectedItems && this.selectedItems[0]) : this.selectedItem;
this._setFocusedItem(null);
@@ -7494,57 +5242,32 @@ Polymer({
if (selectedItem) {
this._setFocusedItem(selectedItem);
} else if (this.items[0]) {
- // We find the first none-disabled item (if one exists)
this._focusNext();
}
});
},
- /**
- * Handler that is called when the up key is pressed.
- *
- * @param {CustomEvent} event A key combination event.
- */
_onUpKey: function(event) {
- // up and down arrows moves the focus
this._focusPrevious();
event.detail.keyboardEvent.preventDefault();
},
- /**
- * Handler that is called when the down key is pressed.
- *
- * @param {CustomEvent} event A key combination event.
- */
_onDownKey: function(event) {
this._focusNext();
event.detail.keyboardEvent.preventDefault();
},
- /**
- * Handler that is called when the esc key is pressed.
- *
- * @param {CustomEvent} event A key combination event.
- */
_onEscKey: function(event) {
- // esc blurs the control
this.focusedItem.blur();
},
- /**
- * Handler that is called when a keydown event is detected.
- *
- * @param {KeyboardEvent} event A keyboard event.
- */
_onKeydown: function(event) {
if (!this.keyboardEventMatchesKeys(event, 'up down esc')) {
- // all other keys focus the menu item starting with that character
this._focusWithKeyboardEvent(event);
}
event.stopPropagation();
},
- // override _activateHandler
_activateHandler: function(event) {
Polymer.IronSelectableBehavior._activateHandler.call(this, event);
event.stopPropagation();
@@ -7568,52 +5291,11 @@ Polymer({
]
});
})();
-/**
-`Polymer.IronFitBehavior` fits an element in another element using `max-height` and `max-width`, and
-optionally centers it in the window or another element.
-
-The element will only be sized and/or positioned if it has not already been sized and/or positioned
-by CSS.
-
-CSS properties | Action
------------------------------|-------------------------------------------
-`position` set | Element is not centered horizontally or vertically
-`top` or `bottom` set | Element is not vertically centered
-`left` or `right` set | Element is not horizontally centered
-`max-height` set | Element respects `max-height`
-`max-width` set | Element respects `max-width`
-
-`Polymer.IronFitBehavior` can position an element into another element using
-`verticalAlign` and `horizontalAlign`. This will override the element's css position.
-
- <div class="container">
- <iron-fit-impl vertical-align="top" horizontal-align="auto">
- Positioned into the container
- </iron-fit-impl>
- </div>
-
-Use `noOverlap` to position the element around another element without overlapping it.
-
- <div class="container">
- <iron-fit-impl no-overlap vertical-align="auto" horizontal-align="auto">
- Positioned around the container
- </iron-fit-impl>
- </div>
-
-@demo demo/index.html
-@polymerBehavior
-*/
Polymer.IronFitBehavior = {
properties: {
- /**
- * The element that will receive a `max-height`/`width`. By default it is the same as `this`,
- * but it can be set to a child element. This is useful, for example, for implementing a
- * scrolling region inside the element.
- * @type {!Element}
- */
sizingTarget: {
type: Object,
value: function() {
@@ -7621,77 +5303,43 @@ Use `noOverlap` to position the element around another element without overlappi
}
},
- /**
- * The element to fit `this` into.
- */
fitInto: {
type: Object,
value: window
},
- /**
- * Will position the element around the positionTarget without overlapping it.
- */
noOverlap: {
type: Boolean
},
- /**
- * The element that should be used to position the element. If not set, it will
- * default to the parent node.
- * @type {!Element}
- */
positionTarget: {
type: Element
},
- /**
- * The orientation against which to align the element horizontally
- * relative to the `positionTarget`. Possible values are "left", "right", "auto".
- */
horizontalAlign: {
type: String
},
- /**
- * The orientation against which to align the element vertically
- * relative to the `positionTarget`. Possible values are "top", "bottom", "auto".
- */
verticalAlign: {
type: String
},
- /**
- * If true, it will use `horizontalAlign` and `verticalAlign` values as preferred alignment
- * and if there's not enough space, it will pick the values which minimize the cropping.
- */
dynamicAlign: {
type: Boolean
},
- /**
- * The same as setting margin-left and margin-right css properties.
- * @deprecated
- */
horizontalOffset: {
type: Number,
value: 0,
notify: true
},
- /**
- * The same as setting margin-top and margin-bottom css properties.
- * @deprecated
- */
verticalOffset: {
type: Number,
value: 0,
notify: true
},
- /**
- * Set to true to auto-fit on attach.
- */
autoFitOnAttach: {
type: Boolean,
value: false
@@ -7743,10 +5391,6 @@ Use `noOverlap` to position the element around another element without overlappi
return fitTop;
},
- /**
- * The element that should be used to position the element,
- * if no position target is configured.
- */
get _defaultPositionTarget() {
var parent = Polymer.dom(this).parentNode;
@@ -7757,12 +5401,8 @@ Use `noOverlap` to position the element around another element without overlappi
return parent;
},
- /**
- * The horizontal align value, accounting for the RTL/LTR text direction.
- */
get _localeHorizontalAlign() {
if (this._isRTL) {
- // In RTL, "left" becomes "right".
if (this.horizontalAlign === 'right') {
return 'left';
}
@@ -7774,7 +5414,6 @@ Use `noOverlap` to position the element around another element without overlappi
},
attached: function() {
- // Memoize this to avoid expensive calculations & relayouts.
this._isRTL = window.getComputedStyle(this).direction == 'rtl';
this.positionTarget = this.positionTarget || this._defaultPositionTarget;
if (this.autoFitOnAttach) {
@@ -7788,19 +5427,12 @@ Use `noOverlap` to position the element around another element without overlappi
}
},
- /**
- * Positions and fits the element into the `fitInto` element.
- */
fit: function() {
this.position();
this.constrain();
this.center();
},
- /**
- * Memoize information needed to position and size the target element.
- * @suppress {deprecated}
- */
_discoverInfo: function() {
if (this._fitInfo) {
return;
@@ -7839,7 +5471,6 @@ Use `noOverlap` to position the element around another element without overlappi
}
};
- // Support these properties until they are removed.
if (this.verticalOffset) {
this._fitInfo.margin.top = this._fitInfo.margin.bottom = this.verticalOffset;
this._fitInfo.inlineStyle.marginTop = this.style.marginTop || '';
@@ -7854,10 +5485,6 @@ Use `noOverlap` to position the element around another element without overlappi
}
},
- /**
- * Resets the target element's position and size constraints, and clear
- * the memoized data.
- */
resetFit: function() {
var info = this._fitInfo || {};
for (var property in info.sizerInlineStyle) {
@@ -7870,12 +5497,6 @@ Use `noOverlap` to position the element around another element without overlappi
this._fitInfo = null;
},
- /**
- * Equivalent to calling `resetFit()` and `fit()`. Useful to call this after
- * the element or the `fitInto` element has been resized, or if any of the
- * positioning properties (e.g. `horizontalAlign, verticalAlign`) is updated.
- * It preserves the scroll position of the sizingTarget.
- */
refit: function() {
var scrollLeft = this.sizingTarget.scrollLeft;
var scrollTop = this.sizingTarget.scrollTop;
@@ -7885,20 +5506,14 @@ Use `noOverlap` to position the element around another element without overlappi
this.sizingTarget.scrollTop = scrollTop;
},
- /**
- * Positions the element according to `horizontalAlign, verticalAlign`.
- */
position: function() {
if (!this.horizontalAlign && !this.verticalAlign) {
- // needs to be centered, and it is done after constrain.
return;
}
this._discoverInfo();
this.style.position = 'fixed';
- // Need border-box for margin/padding.
this.sizingTarget.style.boxSizing = 'border-box';
- // Set to 0, 0 in order to discover any offset caused by parent stacking contexts.
this.style.left = '0px';
this.style.top = '0px';
@@ -7908,7 +5523,6 @@ Use `noOverlap` to position the element around another element without overlappi
var margin = this._fitInfo.margin;
- // Consider the margin as part of the size for position calculations.
var size = {
width: rect.width + margin.left + margin.right,
height: rect.height + margin.top + margin.bottom
@@ -7919,7 +5533,6 @@ Use `noOverlap` to position the element around another element without overlappi
var left = position.left + margin.left;
var top = position.top + margin.top;
- // Use original size (without margin).
var right = Math.min(fitRect.right - margin.right, left + rect.width);
var bottom = Math.min(fitRect.bottom - margin.bottom, top + rect.height);
@@ -7941,15 +5554,10 @@ Use `noOverlap` to position the element around another element without overlappi
this.sizingTarget.style.maxWidth = (right - left) + 'px';
this.sizingTarget.style.maxHeight = (bottom - top) + 'px';
- // Remove the offset caused by any stacking context.
this.style.left = (left - rect.left) + 'px';
this.style.top = (top - rect.top) + 'px';
},
- /**
- * Constrains the size of the element to `fitInto` by setting `max-height`
- * and/or `max-width`.
- */
constrain: function() {
if (this.horizontalAlign || this.verticalAlign) {
return;
@@ -7957,7 +5565,6 @@ Use `noOverlap` to position the element around another element without overlappi
this._discoverInfo();
var info = this._fitInfo;
- // position at (0px, 0px) if not already positioned, so we can measure the natural size.
if (!info.positionedBy.vertically) {
this.style.position = 'fixed';
this.style.top = '0px';
@@ -7967,9 +5574,7 @@ Use `noOverlap` to position the element around another element without overlappi
this.style.left = '0px';
}
- // need border-box for margin/padding
this.sizingTarget.style.boxSizing = 'border-box';
- // constrain the width and height if not already set
var rect = this.getBoundingClientRect();
if (!info.sizedBy.height) {
this.__sizeDimension(rect, info.positionedBy.vertically, 'top', 'bottom', 'Height');
@@ -7979,17 +5584,10 @@ Use `noOverlap` to position the element around another element without overlappi
}
},
- /**
- * @protected
- * @deprecated
- */
_sizeDimension: function(rect, positionedBy, start, end, extent) {
this.__sizeDimension(rect, positionedBy, start, end, extent);
},
- /**
- * @private
- */
__sizeDimension: function(rect, positionedBy, start, end, extent) {
var info = this._fitInfo;
var fitRect = this.__getNormalizedRect(this.fitInto);
@@ -8002,10 +5600,6 @@ Use `noOverlap` to position the element around another element without overlappi
this.sizingTarget.style['max' + extent] = (max - margin - offset - sizingOffset) + 'px';
},
- /**
- * Centers horizontally and vertically if not already positioned. This also sets
- * `position:fixed`.
- */
center: function() {
if (this.horizontalAlign || this.verticalAlign) {
return;
@@ -8014,21 +5608,15 @@ Use `noOverlap` to position the element around another element without overlappi
var positionedBy = this._fitInfo.positionedBy;
if (positionedBy.vertically && positionedBy.horizontally) {
- // Already positioned.
return;
}
- // Need position:fixed to center
this.style.position = 'fixed';
- // Take into account the offset caused by parents that create stacking
- // contexts (e.g. with transform: translate3d). Translate to 0,0 and
- // measure the bounding rect.
if (!positionedBy.vertically) {
this.style.top = '0px';
}
if (!positionedBy.horizontally) {
this.style.left = '0px';
}
- // It will take in consideration margins and transforms
var rect = this.getBoundingClientRect();
var fitRect = this.__getNormalizedRect(this.fitInto);
if (!positionedBy.vertically) {
@@ -8063,8 +5651,6 @@ Use `noOverlap` to position the element around another element without overlappi
__getPosition: function(hAlign, vAlign, size, positionRect, fitRect) {
- // All the possible configurations.
- // Ordered as top-left, top-right, bottom-left, bottom-right.
var positions = [{
verticalAlign: 'top',
horizontalAlign: 'left',
@@ -8088,7 +5674,6 @@ Use `noOverlap` to position the element around another element without overlappi
}];
if (this.noOverlap) {
- // Duplicate.
for (var i = 0, l = positions.length; i < l; i++) {
var copy = {};
for (var key in positions[i]) {
@@ -8096,15 +5681,12 @@ Use `noOverlap` to position the element around another element without overlappi
}
positions.push(copy);
}
- // Horizontal overlap only.
positions[0].top = positions[1].top += positionRect.height;
positions[2].top = positions[3].top -= positionRect.height;
- // Vertical overlap only.
positions[4].left = positions[6].left += positionRect.width;
positions[5].left = positions[7].left -= positionRect.width;
}
- // Consider auto as null for coding convenience.
vAlign = vAlign === 'auto' ? null : vAlign;
hAlign = hAlign === 'auto' ? null : hAlign;
@@ -8112,23 +5694,15 @@ Use `noOverlap` to position the element around another element without overlappi
for (var i = 0; i < positions.length; i++) {
var pos = positions[i];
- // If both vAlign and hAlign are defined, return exact match.
- // For dynamicAlign and noOverlap we'll have more than one candidate, so
- // we'll have to check the croppedArea to make the best choice.
if (!this.dynamicAlign && !this.noOverlap &&
pos.verticalAlign === vAlign && pos.horizontalAlign === hAlign) {
position = pos;
break;
}
- // Align is ok if alignment preferences are respected. If no preferences,
- // it is considered ok.
var alignOk = (!vAlign || pos.verticalAlign === vAlign) &&
(!hAlign || pos.horizontalAlign === hAlign);
- // Filter out elements that don't match the alignment (if defined).
- // With dynamicAlign, we need to consider all the positions to find the
- // one that minimizes the cropped area.
if (!this.dynamicAlign && !alignOk) {
continue;
}
@@ -8136,13 +5710,9 @@ Use `noOverlap` to position the element around another element without overlappi
position = position || pos;
pos.croppedArea = this.__getCroppedArea(pos, size, fitRect);
var diff = pos.croppedArea - position.croppedArea;
- // Check which crops less. If it crops equally, check if align is ok.
if (diff < 0 || (diff === 0 && alignOk)) {
position = pos;
}
- // If not cropped and respects the align requirements, keep it.
- // This allows to prefer positions overlapping horizontally over the
- // ones overlapping vertically.
if (position.croppedArea === 0 && alignOk) {
break;
}
@@ -8161,9 +5731,6 @@ Use `noOverlap` to position the element around another element without overlappi
properties: {
- /**
- * Returns true if the backdrop is opened.
- */
opened: {
reflectToAttribute: true,
type: Boolean,
@@ -8178,7 +5745,6 @@ Use `noOverlap` to position the element around another element without overlappi
},
created: function() {
- // Used to cancel previous requestAnimationFrame calls when opened changes.
this.__openedRaf = null;
},
@@ -8186,32 +5752,20 @@ Use `noOverlap` to position the element around another element without overlappi
this.opened && this._openedChanged(this.opened);
},
- /**
- * Appends the backdrop to document body if needed.
- */
prepare: function() {
if (this.opened && !this.parentNode) {
Polymer.dom(document.body).appendChild(this);
}
},
- /**
- * Shows the backdrop.
- */
open: function() {
this.opened = true;
},
- /**
- * Hides the backdrop.
- */
close: function() {
this.opened = false;
},
- /**
- * Removes the backdrop from document body if needed.
- */
complete: function() {
if (!this.opened && this.parentNode === document.body) {
Polymer.dom(this.parentNode).removeChild(this);
@@ -8224,17 +5778,10 @@ Use `noOverlap` to position the element around another element without overlappi
}
},
- /**
- * @param {boolean} opened
- * @private
- */
_openedChanged: function(opened) {
if (opened) {
- // Auto-attach.
this.prepare();
} else {
- // Animation might be disabled via the mixin or opacity custom property.
- // If it is disabled in other ways, it's up to the user to call complete.
var cs = window.getComputedStyle(this);
if (cs.transitionDuration === '0s' || cs.opacity == 0) {
this.complete();
@@ -8245,12 +5792,10 @@ Use `noOverlap` to position the element around another element without overlappi
return;
}
- // Always cancel previous requestAnimationFrame.
if (this.__openedRaf) {
window.cancelAnimationFrame(this.__openedRaf);
this.__openedRaf = null;
}
- // Force relayout to ensure proper transitions.
this.scrollTop = this.scrollTop;
this.__openedRaf = window.requestAnimationFrame(function() {
this.__openedRaf = null;
@@ -8260,32 +5805,13 @@ Use `noOverlap` to position the element around another element without overlappi
});
})();
-/**
- * @struct
- * @constructor
- * @private
- */
Polymer.IronOverlayManagerClass = function() {
- /**
- * Used to keep track of the opened overlays.
- * @private {Array<Element>}
- */
this._overlays = [];
- /**
- * iframes have a default z-index of 100,
- * so this default should be at least that.
- * @private {number}
- */
this._minimumZ = 101;
- /**
- * Memoized backdrop element.
- * @private {Element|null}
- */
this._backdropElement = null;
- // Enable document-wide tap recognizer.
Polymer.Gestures.add(document, 'tap', this._onCaptureClick.bind(this));
document.addEventListener('focus', this._onCaptureFocus.bind(this), true);
@@ -8296,10 +5822,6 @@ Use `noOverlap` to position the element around another element without overlappi
constructor: Polymer.IronOverlayManagerClass,
- /**
- * The shared backdrop element.
- * @type {!Element} backdropElement
- */
get backdropElement() {
if (!this._backdropElement) {
this._backdropElement = document.createElement('iron-overlay-backdrop');
@@ -8307,14 +5829,7 @@ Use `noOverlap` to position the element around another element without overlappi
return this._backdropElement;
},
- /**
- * The deepest active element.
- * @type {!Element} activeElement the active element
- */
get deepActiveElement() {
- // document.activeElement can be null
- // https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement
- // In case of null, default it to document.body.
var active = document.activeElement || document.body;
while (active.root && Polymer.dom(active.root).activeElement) {
active = Polymer.dom(active.root).activeElement;
@@ -8322,11 +5837,6 @@ Use `noOverlap` to position the element around another element without overlappi
return active;
},
- /**
- * Brings the overlay at the specified index to the front.
- * @param {number} i
- * @private
- */
_bringOverlayAtIndexToFront: function(i) {
var overlay = this._overlays[i];
if (!overlay) {
@@ -8334,21 +5844,17 @@ Use `noOverlap` to position the element around another element without overlappi
}
var lastI = this._overlays.length - 1;
var currentOverlay = this._overlays[lastI];
- // Ensure always-on-top overlay stays on top.
if (currentOverlay && this._shouldBeBehindOverlay(overlay, currentOverlay)) {
lastI--;
}
- // If already the top element, return.
if (i >= lastI) {
return;
}
- // Update z-index to be on top.
var minimumZ = Math.max(this.currentOverlayZ(), this._minimumZ);
if (this._getZ(overlay) <= minimumZ) {
this._applyOverlayZ(overlay, minimumZ);
}
- // Shift other overlays behind the new on top.
while (i < lastI) {
this._overlays[i] = this._overlays[i + 1];
i++;
@@ -8356,11 +5862,6 @@ Use `noOverlap` to position the element around another element without overlappi
this._overlays[lastI] = overlay;
},
- /**
- * Adds the overlay and updates its z-index if it's opened, or removes it if it's closed.
- * Also updates the backdrop z-index.
- * @param {!Element} overlay
- */
addOrRemoveOverlay: function(overlay) {
if (overlay.opened) {
this.addOverlay(overlay);
@@ -8369,11 +5870,6 @@ Use `noOverlap` to position the element around another element without overlappi
}
},
- /**
- * Tracks overlays for z-index and focus management.
- * Ensures the last added overlay with always-on-top remains on top.
- * @param {!Element} overlay
- */
addOverlay: function(overlay) {
var i = this._overlays.indexOf(overlay);
if (i >= 0) {
@@ -8386,17 +5882,13 @@ Use `noOverlap` to position the element around another element without overlappi
var minimumZ = Math.max(this._getZ(currentOverlay), this._minimumZ);
var newZ = this._getZ(overlay);
- // Ensure always-on-top overlay stays on top.
if (currentOverlay && this._shouldBeBehindOverlay(overlay, currentOverlay)) {
- // This bumps the z-index of +2.
this._applyOverlayZ(currentOverlay, minimumZ);
insertionIndex--;
- // Update minimumZ to match previous overlay's z-index.
var previousOverlay = this._overlays[insertionIndex - 1];
minimumZ = Math.max(this._getZ(previousOverlay), this._minimumZ);
}
- // Update z-index and insert overlay.
if (newZ <= minimumZ) {
this._applyOverlayZ(overlay, minimumZ);
}
@@ -8405,9 +5897,6 @@ Use `noOverlap` to position the element around another element without overlappi
this.trackBackdrop();
},
- /**
- * @param {!Element} overlay
- */
removeOverlay: function(overlay) {
var i = this._overlays.indexOf(overlay);
if (i === -1) {
@@ -8418,28 +5907,15 @@ Use `noOverlap` to position the element around another element without overlappi
this.trackBackdrop();
},
- /**
- * Returns the current overlay.
- * @return {Element|undefined}
- */
currentOverlay: function() {
var i = this._overlays.length - 1;
return this._overlays[i];
},
- /**
- * Returns the current overlay z-index.
- * @return {number}
- */
currentOverlayZ: function() {
return this._getZ(this.currentOverlay());
},
- /**
- * Ensures that the minimum z-index of new overlays is at least `minimumZ`.
- * This does not effect the z-index of any existing overlays.
- * @param {number} minimumZ
- */
ensureMinimumZ: function(minimumZ) {
this._minimumZ = Math.max(this._minimumZ, minimumZ);
},
@@ -8451,12 +5927,8 @@ Use `noOverlap` to position the element around another element without overlappi
}
},
- /**
- * Updates the backdrop z-index.
- */
trackBackdrop: function() {
var overlay = this._overlayWithBackdrop();
- // Avoid creating the backdrop if there is no overlay with backdrop.
if (!overlay && !this._backdropElement) {
return;
}
@@ -8464,9 +5936,6 @@ Use `noOverlap` to position the element around another element without overlappi
this.backdropElement.opened = !!overlay;
},
- /**
- * @return {Array<Element>}
- */
getBackdrops: function() {
var backdrops = [];
for (var i = 0; i < this._overlays.length; i++) {
@@ -8477,19 +5946,10 @@ Use `noOverlap` to position the element around another element without overlappi
return backdrops;
},
- /**
- * Returns the z-index for the backdrop.
- * @return {number}
- */
backdropZ: function() {
return this._getZ(this._overlayWithBackdrop()) - 1;
},
- /**
- * Returns the first opened overlay that has a backdrop.
- * @return {Element|undefined}
- * @private
- */
_overlayWithBackdrop: function() {
for (var i = 0; i < this._overlays.length; i++) {
if (this._overlays[i].withBackdrop) {
@@ -8498,17 +5958,10 @@ Use `noOverlap` to position the element around another element without overlappi
}
},
- /**
- * Calculates the minimum z-index for the overlay.
- * @param {Element=} overlay
- * @private
- */
_getZ: function(overlay) {
var z = this._minimumZ;
if (overlay) {
var z1 = Number(overlay.style.zIndex || window.getComputedStyle(overlay).zIndex);
- // Check if is a number
- // Number.isNaN not supported in IE 10+
if (z1 === z1) {
z = z1;
}
@@ -8516,31 +5969,14 @@ Use `noOverlap` to position the element around another element without overlappi
return z;
},
- /**
- * @param {!Element} element
- * @param {number|string} z
- * @private
- */
_setZ: function(element, z) {
element.style.zIndex = z;
},
- /**
- * @param {!Element} overlay
- * @param {number} aboveZ
- * @private
- */
_applyOverlayZ: function(overlay, aboveZ) {
this._setZ(overlay, aboveZ + 2);
},
- /**
- * Returns the deepest overlay in the path.
- * @param {Array<Element>=} path
- * @return {Element|undefined}
- * @suppress {missingProperties}
- * @private
- */
_overlayInPath: function(path) {
path = path || [];
for (var i = 0; i < path.length; i++) {
@@ -8550,24 +5986,13 @@ Use `noOverlap` to position the element around another element without overlappi
}
},
- /**
- * Ensures the click event is delegated to the right overlay.
- * @param {!Event} event
- * @private
- */
_onCaptureClick: function(event) {
var overlay = /** @type {?} */ (this.currentOverlay());
- // Check if clicked outside of top overlay.
if (overlay && this._overlayInPath(Polymer.dom(event).path) !== overlay) {
overlay._onCaptureClick(event);
}
},
- /**
- * Ensures the focus event is delegated to the right overlay.
- * @param {!Event} event
- * @private
- */
_onCaptureFocus: function(event) {
var overlay = /** @type {?} */ (this.currentOverlay());
if (overlay) {
@@ -8575,11 +6000,6 @@ Use `noOverlap` to position the element around another element without overlappi
}
},
- /**
- * Ensures TAB and ESC keyboard events are delegated to the right overlay.
- * @param {!Event} event
- * @private
- */
_onCaptureKeyDown: function(event) {
var overlay = /** @type {?} */ (this.currentOverlay());
if (overlay) {
@@ -8591,14 +6011,6 @@ Use `noOverlap` to position the element around another element without overlappi
}
},
- /**
- * Returns if the overlay1 should be behind overlay2.
- * @param {!Element} overlay1
- * @param {!Element} overlay2
- * @return {boolean}
- * @suppress {missingProperties}
- * @private
- */
_shouldBeBehindOverlay: function(overlay1, overlay2) {
return !overlay1.alwaysOnTop && overlay2.alwaysOnTop;
}
@@ -8608,56 +6020,11 @@ Use `noOverlap` to position the element around another element without overlappi
(function() {
'use strict';
-/**
-Use `Polymer.IronOverlayBehavior` to implement an element that can be hidden or shown, and displays
-on top of other content. It includes an optional backdrop, and can be used to implement a variety
-of UI controls including dialogs and drop downs. Multiple overlays may be displayed at once.
-
-See the [demo source code](https://github.com/PolymerElements/iron-overlay-behavior/blob/master/demo/simple-overlay.html)
-for an example.
-
-### Closing and canceling
-
-An overlay may be hidden by closing or canceling. The difference between close and cancel is user
-intent. Closing generally implies that the user acknowledged the content on the overlay. By default,
-it will cancel whenever the user taps outside it or presses the escape key. This behavior is
-configurable with the `no-cancel-on-esc-key` and the `no-cancel-on-outside-click` properties.
-`close()` should be called explicitly by the implementer when the user interacts with a control
-in the overlay element. When the dialog is canceled, the overlay fires an 'iron-overlay-canceled'
-event. Call `preventDefault` on this event to prevent the overlay from closing.
-
-### Positioning
-
-By default the element is sized and positioned to fit and centered inside the window. You can
-position and size it manually using CSS. See `Polymer.IronFitBehavior`.
-
-### Backdrop
-
-Set the `with-backdrop` attribute to display a backdrop behind the overlay. The backdrop is
-appended to `<body>` and is of type `<iron-overlay-backdrop>`. See its doc page for styling
-options.
-
-In addition, `with-backdrop` will wrap the focus within the content in the light DOM.
-Override the [`_focusableNodes` getter](#Polymer.IronOverlayBehavior:property-_focusableNodes)
-to achieve a different behavior.
-
-### Limitations
-
-The element is styled to appear on top of other content by setting its `z-index` property. You
-must ensure no element has a stacking context with a higher `z-index` than its parent stacking
-context. You should place this element as a child of `<body>` whenever possible.
-
-@demo demo/index.html
-@polymerBehavior Polymer.IronOverlayBehavior
-*/
Polymer.IronOverlayBehaviorImpl = {
properties: {
- /**
- * True if the overlay is currently displayed.
- */
opened: {
observer: '_openedChanged',
type: Boolean,
@@ -8665,9 +6032,6 @@ context. You should place this element as a child of `<body>` whenever possible.
notify: true
},
- /**
- * True if the overlay was canceled when it was last closed.
- */
canceled: {
observer: '_canceledChanged',
readOnly: true,
@@ -8675,80 +6039,44 @@ context. You should place this element as a child of `<body>` whenever possible.
value: false
},
- /**
- * Set to true to display a backdrop behind the overlay. It traps the focus
- * within the light DOM of the overlay.
- */
withBackdrop: {
observer: '_withBackdropChanged',
type: Boolean
},
- /**
- * Set to true to disable auto-focusing the overlay or child nodes with
- * the `autofocus` attribute` when the overlay is opened.
- */
noAutoFocus: {
type: Boolean,
value: false
},
- /**
- * Set to true to disable canceling the overlay with the ESC key.
- */
noCancelOnEscKey: {
type: Boolean,
value: false
},
- /**
- * Set to true to disable canceling the overlay by clicking outside it.
- */
noCancelOnOutsideClick: {
type: Boolean,
value: false
},
- /**
- * Contains the reason(s) this overlay was last closed (see `iron-overlay-closed`).
- * `IronOverlayBehavior` provides the `canceled` reason; implementers of the
- * behavior can provide other reasons in addition to `canceled`.
- */
closingReason: {
- // was a getter before, but needs to be a property so other
- // behaviors can override this.
type: Object
},
- /**
- * Set to true to enable restoring of focus when overlay is closed.
- */
restoreFocusOnClose: {
type: Boolean,
value: false
},
- /**
- * Set to true to keep overlay always on top.
- */
alwaysOnTop: {
type: Boolean
},
- /**
- * Shortcut to access to the overlay manager.
- * @private
- * @type {Polymer.IronOverlayManagerClass}
- */
_manager: {
type: Object,
value: Polymer.IronOverlayManager
},
- /**
- * The node being focused.
- * @type {?Node}
- */
_focusedChild: {
type: Object
}
@@ -8759,34 +6087,15 @@ context. You should place this element as a child of `<body>` whenever possible.
'iron-resize': '_onIronResize'
},
- /**
- * The backdrop element.
- * @type {Element}
- */
get backdropElement() {
return this._manager.backdropElement;
},
- /**
- * Returns the node to give focus to.
- * @type {Node}
- */
get _focusNode() {
return this._focusedChild || Polymer.dom(this).querySelector('[autofocus]') || this;
},
- /**
- * Array of nodes that can receive focus (overlay included), ordered by `tabindex`.
- * This is used to retrieve which is the first and last focusable nodes in order
- * to wrap the focus for overlays `with-backdrop`.
- *
- * If you know what is your content (specifically the first and last focusable children),
- * you can override this method to return only `[firstFocusable, lastFocusable];`
- * @type {Array<Node>}
- * @protected
- */
get _focusableNodes() {
- // Elements that can be focused even if they have [disabled] attribute.
var FOCUSABLE_WITH_DISABLED = [
'a[href]',
'area[href]',
@@ -8795,7 +6104,6 @@ context. You should place this element as a child of `<body>` whenever possible.
'[contentEditable=true]'
];
- // Elements that cannot be focused if they have [disabled] attribute.
var FOCUSABLE_WITHOUT_DISABLED = [
'input',
'select',
@@ -8803,7 +6111,6 @@ context. You should place this element as a child of `<body>` whenever possible.
'button'
];
- // Discard elements with tabindex=-1 (makes them not focusable).
var selector = FOCUSABLE_WITH_DISABLED.join(':not([tabindex="-1"]),') +
':not([tabindex="-1"]),' +
FOCUSABLE_WITHOUT_DISABLED.join(':not([disabled]):not([tabindex="-1"]),') +
@@ -8811,11 +6118,8 @@ context. You should place this element as a child of `<body>` whenever possible.
var focusables = Polymer.dom(this).querySelectorAll(selector);
if (this.tabIndex >= 0) {
- // Insert at the beginning because we might have all elements with tabIndex = 0,
- // and the overlay should be the first of the list.
focusables.splice(0, 0, this);
}
- // Sort by tabindex.
return focusables.sort(function (a, b) {
if (a.tabIndex === b.tabIndex) {
return 0;
@@ -8828,22 +6132,15 @@ context. You should place this element as a child of `<body>` whenever possible.
},
ready: function() {
- // Used to skip calls to notifyResize and refit while the overlay is animating.
this.__isAnimating = false;
- // with-backdrop needs tabindex to be set in order to trap the focus.
- // If it is not set, IronOverlayBehavior will set it, and remove it if with-backdrop = false.
this.__shouldRemoveTabIndex = false;
- // Used for wrapping the focus on TAB / Shift+TAB.
this.__firstFocusableNode = this.__lastFocusableNode = null;
- // Used by __onNextAnimationFrame to cancel any previous callback.
this.__raf = null;
- // Focused node before overlay gets opened. Can be restored on close.
this.__restoreFocusNode = null;
this._ensureSetup();
},
attached: function() {
- // Call _openedChanged here so that position can be computed correctly.
if (this.opened) {
this._openedChanged(this.opened);
}
@@ -8860,34 +6157,21 @@ context. You should place this element as a child of `<body>` whenever possible.
this._manager.removeOverlay(this);
},
- /**
- * Toggle the opened state of the overlay.
- */
toggle: function() {
this._setCanceled(false);
this.opened = !this.opened;
},
- /**
- * Open the overlay.
- */
open: function() {
this._setCanceled(false);
this.opened = true;
},
- /**
- * Close the overlay.
- */
close: function() {
this._setCanceled(false);
this.opened = false;
},
- /**
- * Cancels the overlay.
- * @param {Event=} event The original event
- */
cancel: function(event) {
var cancelEvent = this.fire('iron-overlay-canceled', event, {cancelable: true});
if (cancelEvent.defaultPrevented) {
@@ -8907,11 +6191,6 @@ context. You should place this element as a child of `<body>` whenever possible.
this.style.display = 'none';
},
- /**
- * Called when `opened` changes.
- * @param {boolean=} opened
- * @protected
- */
_openedChanged: function(opened) {
if (opened) {
this.removeAttribute('aria-hidden');
@@ -8919,15 +6198,12 @@ context. You should place this element as a child of `<body>` whenever possible.
this.setAttribute('aria-hidden', 'true');
}
- // Defer any animation-related code on attached
- // (_openedChanged gets called again on attached).
if (!this.isAttached) {
return;
}
this.__isAnimating = true;
- // Use requestAnimationFrame for non-blocking rendering.
this.__onNextAnimationFrame(this.__openedChanged);
},
@@ -8937,7 +6213,6 @@ context. You should place this element as a child of `<body>` whenever possible.
},
_withBackdropChanged: function() {
- // If tabindex is already set, no need to override it.
if (this.withBackdrop && !this.hasAttribute('tabindex')) {
this.setAttribute('tabindex', '-1');
this.__shouldRemoveTabIndex = true;
@@ -8950,53 +6225,31 @@ context. You should place this element as a child of `<body>` whenever possible.
}
},
- /**
- * tasks which must occur before opening; e.g. making the element visible.
- * @protected
- */
_prepareRenderOpened: function() {
- // Store focused node.
this.__restoreFocusNode = this._manager.deepActiveElement;
- // Needed to calculate the size of the overlay so that transitions on its size
- // will have the correct starting points.
this._preparePositioning();
this.refit();
this._finishPositioning();
- // Safari will apply the focus to the autofocus element when displayed
- // for the first time, so we make sure to return the focus where it was.
if (this.noAutoFocus && document.activeElement === this._focusNode) {
this._focusNode.blur();
this.__restoreFocusNode.focus();
}
},
- /**
- * Tasks which cause the overlay to actually open; typically play an animation.
- * @protected
- */
_renderOpened: function() {
this._finishRenderOpened();
},
- /**
- * Tasks which cause the overlay to actually close; typically play an animation.
- * @protected
- */
_renderClosed: function() {
this._finishRenderClosed();
},
- /**
- * Tasks to be performed at the end of open action. Will fire `iron-overlay-opened`.
- * @protected
- */
_finishRenderOpened: function() {
this.notifyResize();
this.__isAnimating = false;
- // Store it so we don't query too much.
var focusableNodes = this._focusableNodes;
this.__firstFocusableNode = focusableNodes[0];
this.__lastFocusableNode = focusableNodes[focusableNodes.length - 1];
@@ -9004,14 +6257,8 @@ context. You should place this element as a child of `<body>` whenever possible.
this.fire('iron-overlay-opened');
},
- /**
- * Tasks to be performed at the end of close action. Will fire `iron-overlay-closed`.
- * @protected
- */
_finishRenderClosed: function() {
- // Hide the overlay.
this.style.display = 'none';
- // Reset z-index only at the end of the animation.
this.style.zIndex = '';
this.notifyResize();
this.__isAnimating = false;
@@ -9025,24 +6272,14 @@ context. You should place this element as a child of `<body>` whenever possible.
},
_finishPositioning: function() {
- // First, make it invisible & reactivate animations.
this.style.display = 'none';
- // Force reflow before re-enabling animations so that they don't start.
- // Set scrollTop to itself so that Closure Compiler doesn't remove this.
this.scrollTop = this.scrollTop;
this.style.transition = this.style.webkitTransition = '';
this.style.transform = this.style.webkitTransform = '';
- // Now that animations are enabled, make it visible again
this.style.display = '';
- // Force reflow, so that following animations are properly started.
- // Set scrollTop to itself so that Closure Compiler doesn't remove this.
this.scrollTop = this.scrollTop;
},
- /**
- * Applies focus according to the opened state.
- * @protected
- */
_applyFocus: function() {
if (this.opened) {
if (!this.noAutoFocus) {
@@ -9052,14 +6289,10 @@ context. You should place this element as a child of `<body>` whenever possible.
else {
this._focusNode.blur();
this._focusedChild = null;
- // Restore focus.
if (this.restoreFocusOnClose && this.__restoreFocusNode) {
this.__restoreFocusNode.focus();
}
this.__restoreFocusNode = null;
- // If many overlays get closed at the same time, one of them would still
- // be the currentOverlay even if already closed, and would call _applyFocus
- // infinitely, so we check for this not to be the current overlay.
var currentOverlay = this._manager.currentOverlay();
if (currentOverlay && this !== currentOverlay) {
currentOverlay._applyFocus();
@@ -9067,22 +6300,12 @@ context. You should place this element as a child of `<body>` whenever possible.
}
},
- /**
- * Cancels (closes) the overlay. Call when click happens outside the overlay.
- * @param {!Event} event
- * @protected
- */
_onCaptureClick: function(event) {
if (!this.noCancelOnOutsideClick) {
this.cancel(event);
}
},
- /**
- * Keeps track of the focused child. If withBackdrop, traps focus within overlay.
- * @param {!Event} event
- * @protected
- */
_onCaptureFocus: function (event) {
if (!this.withBackdrop) {
return;
@@ -9096,103 +6319,54 @@ context. You should place this element as a child of `<body>` whenever possible.
}
},
- /**
- * Handles the ESC key event and cancels (closes) the overlay.
- * @param {!Event} event
- * @protected
- */
_onCaptureEsc: function(event) {
if (!this.noCancelOnEscKey) {
this.cancel(event);
}
},
- /**
- * Handles TAB key events to track focus changes.
- * Will wrap focus for overlays withBackdrop.
- * @param {!Event} event
- * @protected
- */
_onCaptureTab: function(event) {
if (!this.withBackdrop) {
return;
}
- // TAB wraps from last to first focusable.
- // Shift + TAB wraps from first to last focusable.
var shift = event.shiftKey;
var nodeToCheck = shift ? this.__firstFocusableNode : this.__lastFocusableNode;
var nodeToSet = shift ? this.__lastFocusableNode : this.__firstFocusableNode;
var shouldWrap = false;
if (nodeToCheck === nodeToSet) {
- // If nodeToCheck is the same as nodeToSet, it means we have an overlay
- // with 0 or 1 focusables; in either case we still need to trap the
- // focus within the overlay.
shouldWrap = true;
} else {
- // In dom=shadow, the manager will receive focus changes on the main
- // root but not the ones within other shadow roots, so we can't rely on
- // _focusedChild, but we should check the deepest active element.
var focusedNode = this._manager.deepActiveElement;
- // If the active element is not the nodeToCheck but the overlay itself,
- // it means the focus is about to go outside the overlay, hence we
- // should prevent that (e.g. user opens the overlay and hit Shift+TAB).
shouldWrap = (focusedNode === nodeToCheck || focusedNode === this);
}
if (shouldWrap) {
- // When the overlay contains the last focusable element of the document
- // and it's already focused, pressing TAB would move the focus outside
- // the document (e.g. to the browser search bar). Similarly, when the
- // overlay contains the first focusable element of the document and it's
- // already focused, pressing Shift+TAB would move the focus outside the
- // document (e.g. to the browser search bar).
- // In both cases, we would not receive a focus event, but only a blur.
- // In order to achieve focus wrapping, we prevent this TAB event and
- // force the focus. This will also prevent the focus to temporarily move
- // outside the overlay, which might cause scrolling.
event.preventDefault();
this._focusedChild = nodeToSet;
this._applyFocus();
}
},
- /**
- * Refits if the overlay is opened and not animating.
- * @protected
- */
_onIronResize: function() {
if (this.opened && !this.__isAnimating) {
this.__onNextAnimationFrame(this.refit);
}
},
- /**
- * Will call notifyResize if overlay is opened.
- * Can be overridden in order to avoid multiple observers on the same node.
- * @protected
- */
_onNodesChange: function() {
if (this.opened && !this.__isAnimating) {
this.notifyResize();
}
},
- /**
- * Tasks executed when opened changes: prepare for the opening, move the
- * focus, update the manager, render opened/closed.
- * @private
- */
__openedChanged: function() {
if (this.opened) {
- // Make overlay visible, then add it to the manager.
this._prepareRenderOpened();
this._manager.addOverlay(this);
- // Move the focus to the child node with [autofocus].
this._applyFocus();
this._renderOpened();
} else {
- // Remove overlay, then restore the focus before actually closing.
this._manager.removeOverlay(this);
this._applyFocus();
@@ -9200,14 +6374,6 @@ context. You should place this element as a child of `<body>` whenever possible.
}
},
- /**
- * Executes a callback on the next animation frame, overriding any previous
- * callback awaiting for the next animation frame. e.g.
- * `__onNextAnimationFrame(callback1) && __onNextAnimationFrame(callback2)`;
- * `callback1` will never be invoked.
- * @param {!Function} callback Its `this` parameter is the overlay itself.
- * @private
- */
__onNextAnimationFrame: function(callback) {
if (this.__raf) {
window.cancelAnimationFrame(this.__raf);
@@ -9224,56 +6390,23 @@ context. You should place this element as a child of `<body>` whenever possible.
/** @polymerBehavior */
Polymer.IronOverlayBehavior = [Polymer.IronFitBehavior, Polymer.IronResizableBehavior, Polymer.IronOverlayBehaviorImpl];
- /**
- * Fired after the overlay opens.
- * @event iron-overlay-opened
- */
-
- /**
- * Fired when the overlay is canceled, but before it is closed.
- * @event iron-overlay-canceled
- * @param {Event} event The closing of the overlay can be prevented
- * by calling `event.preventDefault()`. The `event.detail` is the original event that
- * originated the canceling (e.g. ESC keyboard event or click event outside the overlay).
- */
-
- /**
- * Fired after the overlay closes.
- * @event iron-overlay-closed
- * @param {Event} event The `event.detail` is the `closingReason` property
- * (contains `canceled`, whether the overlay was canceled).
- */
+
+
})();
-/**
- * `Polymer.NeonAnimatableBehavior` is implemented by elements containing animations for use with
- * elements implementing `Polymer.NeonAnimationRunnerBehavior`.
- * @polymerBehavior
- */
Polymer.NeonAnimatableBehavior = {
properties: {
- /**
- * Animation configuration. See README for more info.
- */
animationConfig: {
type: Object
},
- /**
- * Convenience property for setting an 'entry' animation. Do not set `animationConfig.entry`
- * manually if using this. The animated node is set to `this` if using this property.
- */
entryAnimation: {
observer: '_entryAnimationChanged',
type: String
},
- /**
- * Convenience property for setting an 'exit' animation. Do not set `animationConfig.exit`
- * manually if using this. The animated node is set to `this` if using this property.
- */
exitAnimation: {
observer: '_exitAnimationChanged',
type: String
@@ -9298,7 +6431,6 @@ context. You should place this element as a child of `<body>` whenever possible.
},
_copyProperties: function(config1, config2) {
- // shallowly copy properties from config2 to config1
for (var property in config2) {
config1[property] = config2[property];
}
@@ -9322,7 +6454,6 @@ context. You should place this element as a child of `<body>` whenever possible.
return;
}
- // type is optional
var thisConfig;
if (type) {
thisConfig = this.animationConfig[type];
@@ -9334,7 +6465,6 @@ context. You should place this element as a child of `<body>` whenever possible.
thisConfig = [thisConfig];
}
- // iterate animations and recurse to process configurations from child nodes
if (thisConfig) {
for (var config, index = 0; config = thisConfig[index]; index++) {
if (config.animatable) {
@@ -9343,14 +6473,12 @@ context. You should place this element as a child of `<body>` whenever possible.
if (config.id) {
var cachedConfig = map[config.id];
if (cachedConfig) {
- // merge configurations with the same id, making a clone lazily
if (!cachedConfig.isClone) {
map[config.id] = this._cloneConfig(cachedConfig)
cachedConfig = map[config.id];
}
this._copyProperties(cachedConfig, config);
} else {
- // put any configs with an id into a map
map[config.id] = config;
}
} else {
@@ -9361,17 +6489,10 @@ context. You should place this element as a child of `<body>` whenever possible.
}
},
- /**
- * An element implementing `Polymer.NeonAnimationRunnerBehavior` calls this method to configure
- * an animation with an optional type. Elements implementing `Polymer.NeonAnimatableBehavior`
- * should define the property `animationConfig`, which is either a configuration object
- * or a map of animation type to array of configuration objects.
- */
getAnimationConfig: function(type) {
var map = {};
var allConfigs = [];
this._getAnimationConfigRecursive(type, map, allConfigs);
- // append the configurations saved in the map to the array
for (var key in map) {
allConfigs.push(map[key]);
}
@@ -9379,11 +6500,6 @@ context. You should place this element as a child of `<body>` whenever possible.
}
};
-/**
- * `Polymer.NeonAnimationRunnerBehavior` adds a method to run animations.
- *
- * @polymerBehavior Polymer.NeonAnimationRunnerBehavior
- */
Polymer.NeonAnimationRunnerBehaviorImpl = {
_configureAnimations: function(configs) {
@@ -9391,13 +6507,10 @@ context. You should place this element as a child of `<body>` whenever possible.
if (configs.length > 0) {
for (var config, index = 0; config = configs[index]; index++) {
var neonAnimation = document.createElement(config.name);
- // is this element actually a neon animation?
if (neonAnimation.isNeonAnimation) {
var result = null;
- // configuration or play could fail if polyfills aren't loaded
try {
result = neonAnimation.configure(config);
- // Check if we have an Effect rather than an Animation
if (typeof result.cancel != 'function') {
result = document.timeline.play(result);
}
@@ -9440,11 +6553,6 @@ context. You should place this element as a child of `<body>` whenever possible.
}
},
- /**
- * Plays an animation with an optional `type`.
- * @param {string=} type
- * @param {!Object=} cookie
- */
playAnimation: function(type, cookie) {
var configs = this.getAnimationConfig(type);
if (!configs) {
@@ -9476,9 +6584,6 @@ context. You should place this element as a child of `<body>` whenever possible.
}
},
- /**
- * Cancels the currently running animations.
- */
cancelAnimation: function() {
for (var k in this._animations) {
this._animations[k].cancel();
@@ -9492,17 +6597,10 @@ context. You should place this element as a child of `<body>` whenever possible.
Polymer.NeonAnimatableBehavior,
Polymer.NeonAnimationRunnerBehaviorImpl
];
-/**
- * Use `Polymer.NeonAnimationBehavior` to implement an animation.
- * @polymerBehavior
- */
Polymer.NeonAnimationBehavior = {
properties: {
- /**
- * Defines the animation timing.
- */
animationTiming: {
type: Object,
value: function() {
@@ -9516,21 +6614,9 @@ context. You should place this element as a child of `<body>` whenever possible.
},
- /**
- * Can be used to determine that elements implement this behavior.
- */
isNeonAnimation: true,
- /**
- * Do any animation configuration here.
- */
- // configure: function(config) {
- // },
- /**
- * Returns the animation timing by mixing in properties from `config` to the defaults defined
- * by the animation.
- */
timingFromConfig: function(config) {
if (config.timing) {
for (var property in config.timing) {
@@ -9540,9 +6626,6 @@ context. You should place this element as a child of `<body>` whenever possible.
return this.animationTiming;
},
- /**
- * Sets `transform` and `transformOrigin` properties along with the prefixed versions.
- */
setPrefixedProperty: function(node, property, value) {
var map = {
'transform': ['webkitTransform'],
@@ -9555,9 +6638,6 @@ context. You should place this element as a child of `<body>` whenever possible.
node.style[property] = value;
},
- /**
- * Called when the animation finishes.
- */
complete: function() {}
};
@@ -9586,38 +6666,20 @@ Polymer({
});
(function() {
'use strict';
- // Used to calculate the scroll direction during touch events.
var LAST_TOUCH_POSITION = {
pageX: 0,
pageY: 0
};
- // Used to avoid computing event.path and filter scrollable nodes (better perf).
var ROOT_TARGET = null;
var SCROLLABLE_NODES = [];
- /**
- * The IronDropdownScrollManager is intended to provide a central source
- * of authority and control over which elements in a document are currently
- * allowed to scroll.
- */
Polymer.IronDropdownScrollManager = {
- /**
- * The current element that defines the DOM boundaries of the
- * scroll lock. This is always the most recently locking element.
- */
get currentLockingElement() {
return this._lockingElements[this._lockingElements.length - 1];
},
- /**
- * Returns true if the provided element is "scroll locked", which is to
- * say that it cannot be scrolled via pointer or keyboard interactions.
- *
- * @param {HTMLElement} element An HTML element instance which may or may
- * not be scroll locked.
- */
elementIsScrollLocked: function(element) {
var currentLockingElement = this.currentLockingElement;
@@ -9647,18 +6709,7 @@ Polymer({
return scrollLocked;
},
- /**
- * Push an element onto the current scroll lock stack. The most recently
- * pushed element and its children will be considered scrollable. All
- * other elements will not be scrollable.
- *
- * Scroll locking is implemented as a stack so that cases such as
- * dropdowns within dropdowns are handled well.
- *
- * @param {HTMLElement} element The element that should lock scroll.
- */
pushScrollLock: function(element) {
- // Prevent pushing the same element twice
if (this._lockingElements.indexOf(element) >= 0) {
return;
}
@@ -9673,15 +6724,6 @@ Polymer({
this._unlockedElementCache = [];
},
- /**
- * Remove an element from the scroll lock stack. The element being
- * removed does not need to be the most recently pushed element. However,
- * the scroll lock constraints only change when the most recently pushed
- * element is removed.
- *
- * @param {HTMLElement} element The element to remove from the scroll
- * lock stack.
- */
removeScrollLock: function(element) {
var index = this._lockingElements.indexOf(element);
@@ -9714,12 +6756,6 @@ Polymer({
},
_composedTreeContains: function(element, child) {
- // NOTE(cdata): This method iterates over content elements and their
- // corresponding distributed nodes to implement a contains-like method
- // that pierces through the composed tree of the ShadowDOM. Results of
- // this operation are cached (elsewhere) on a per-scroll-lock basis, to
- // guard against potentially expensive lookups happening repeatedly as
- // a user scrolls / touchmoves.
var contentElements;
var distributedNodes;
var contentIndex;
@@ -9747,12 +6783,9 @@ Polymer({
},
_scrollInteractionHandler: function(event) {
- // Avoid canceling an event with cancelable=false, e.g. scrolling is in
- // progress and cannot be interrupted.
if (event.cancelable && this._shouldPreventScrolling(event)) {
event.preventDefault();
}
- // If event has targetTouches (touch event), update last touch position.
if (event.targetTouches) {
var touch = event.targetTouches[0];
LAST_TOUCH_POSITION.pageX = touch.pageX;
@@ -9763,15 +6796,10 @@ Polymer({
_lockScrollInteractions: function() {
this._boundScrollHandler = this._boundScrollHandler ||
this._scrollInteractionHandler.bind(this);
- // Modern `wheel` event for mouse wheel scrolling:
document.addEventListener('wheel', this._boundScrollHandler, true);
- // Older, non-standard `mousewheel` event for some FF:
document.addEventListener('mousewheel', this._boundScrollHandler, true);
- // IE:
document.addEventListener('DOMMouseScroll', this._boundScrollHandler, true);
- // Save the SCROLLABLE_NODES on touchstart, to be used on touchmove.
document.addEventListener('touchstart', this._boundScrollHandler, true);
- // Mobile devices can scroll on touch move:
document.addEventListener('touchmove', this._boundScrollHandler, true);
},
@@ -9783,57 +6811,32 @@ Polymer({
document.removeEventListener('touchmove', this._boundScrollHandler, true);
},
- /**
- * Returns true if the event causes scroll outside the current locking
- * element, e.g. pointer/keyboard interactions, or scroll "leaking"
- * outside the locking element when it is already at its scroll boundaries.
- * @param {!Event} event
- * @return {boolean}
- * @private
- */
_shouldPreventScrolling: function(event) {
- // Update if root target changed. For touch events, ensure we don't
- // update during touchmove.
var target = Polymer.dom(event).rootTarget;
if (event.type !== 'touchmove' && ROOT_TARGET !== target) {
ROOT_TARGET = target;
SCROLLABLE_NODES = this._getScrollableNodes(Polymer.dom(event).path);
}
- // Prevent event if no scrollable nodes.
if (!SCROLLABLE_NODES.length) {
return true;
}
- // Don't prevent touchstart event inside the locking element when it has
- // scrollable nodes.
if (event.type === 'touchstart') {
return false;
}
- // Get deltaX/Y.
var info = this._getScrollInfo(event);
- // Prevent if there is no child that can scroll.
return !this._getScrollingNode(SCROLLABLE_NODES, info.deltaX, info.deltaY);
},
- /**
- * Returns an array of scrollable nodes up to the current locking element,
- * which is included too if scrollable.
- * @param {!Array<Node>} nodes
- * @return {Array<Node>} scrollables
- * @private
- */
_getScrollableNodes: function(nodes) {
var scrollables = [];
var lockingIndex = nodes.indexOf(this.currentLockingElement);
- // Loop from root target to locking element (included).
for (var i = 0; i <= lockingIndex; i++) {
var node = nodes[i];
- // Skip document fragments.
if (node.nodeType === 11) {
continue;
}
- // Check inline style before checking computed style.
var style = node.style;
if (style.overflow !== 'scroll' && style.overflow !== 'auto') {
style = window.getComputedStyle(node);
@@ -9845,32 +6848,18 @@ Polymer({
return scrollables;
},
- /**
- * Returns the node that is scrolling. If there is no scrolling,
- * returns undefined.
- * @param {!Array<Node>} nodes
- * @param {number} deltaX Scroll delta on the x-axis
- * @param {number} deltaY Scroll delta on the y-axis
- * @return {Node|undefined}
- * @private
- */
_getScrollingNode: function(nodes, deltaX, deltaY) {
- // No scroll.
if (!deltaX && !deltaY) {
return;
}
- // Check only one axis according to where there is more scroll.
- // Prefer vertical to horizontal.
var verticalScroll = Math.abs(deltaY) >= Math.abs(deltaX);
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
var canScroll = false;
if (verticalScroll) {
- // delta < 0 is scroll up, delta > 0 is scroll down.
canScroll = deltaY < 0 ? node.scrollTop > 0 :
node.scrollTop < node.scrollHeight - node.clientHeight;
} else {
- // delta < 0 is scroll left, delta > 0 is scroll right.
canScroll = deltaX < 0 ? node.scrollLeft > 0 :
node.scrollLeft < node.scrollWidth - node.clientWidth;
}
@@ -9880,42 +6869,24 @@ Polymer({
}
},
- /**
- * Returns scroll `deltaX` and `deltaY`.
- * @param {!Event} event The scroll event
- * @return {{
- * deltaX: number The x-axis scroll delta (positive: scroll right,
- * negative: scroll left, 0: no scroll),
- * deltaY: number The y-axis scroll delta (positive: scroll down,
- * negative: scroll up, 0: no scroll)
- * }} info
- * @private
- */
_getScrollInfo: function(event) {
var info = {
deltaX: event.deltaX,
deltaY: event.deltaY
};
- // Already available.
if ('deltaX' in event) {
- // do nothing, values are already good.
}
- // Safari has scroll info in `wheelDeltaX/Y`.
else if ('wheelDeltaX' in event) {
info.deltaX = -event.wheelDeltaX;
info.deltaY = -event.wheelDeltaY;
}
- // Firefox has scroll info in `detail` and `axis`.
else if ('axis' in event) {
info.deltaX = event.axis === 1 ? event.detail : 0;
info.deltaY = event.axis === 2 ? event.detail : 0;
}
- // On mobile devices, calculate scroll direction.
else if (event.targetTouches) {
var touch = event.targetTouches[0];
- // Touch moves from right to left => scrolling goes right.
info.deltaX = LAST_TOUCH_POSITION.pageX - touch.pageX;
- // Touch moves from down to up => scrolling goes down.
info.deltaY = LAST_TOUCH_POSITION.pageY - touch.pageY;
}
return info;
@@ -9936,77 +6907,40 @@ Polymer({
],
properties: {
- /**
- * The orientation against which to align the dropdown content
- * horizontally relative to the dropdown trigger.
- * Overridden from `Polymer.IronFitBehavior`.
- */
horizontalAlign: {
type: String,
value: 'left',
reflectToAttribute: true
},
- /**
- * The orientation against which to align the dropdown content
- * vertically relative to the dropdown trigger.
- * Overridden from `Polymer.IronFitBehavior`.
- */
verticalAlign: {
type: String,
value: 'top',
reflectToAttribute: true
},
- /**
- * An animation config. If provided, this will be used to animate the
- * opening of the dropdown.
- */
openAnimationConfig: {
type: Object
},
- /**
- * An animation config. If provided, this will be used to animate the
- * closing of the dropdown.
- */
closeAnimationConfig: {
type: Object
},
- /**
- * If provided, this will be the element that will be focused when
- * the dropdown opens.
- */
focusTarget: {
type: Object
},
- /**
- * Set to true to disable animations when opening and closing the
- * dropdown.
- */
noAnimations: {
type: Boolean,
value: false
},
- /**
- * By default, the dropdown will constrain scrolling on the page
- * to itself when opened.
- * Set to true in order to prevent scroll from being constrained
- * to the dropdown when it opens.
- */
allowOutsideScroll: {
type: Boolean,
value: false
},
- /**
- * Callback for scroll events.
- * @type {Function}
- * @private
- */
_boundOnCaptureScroll: {
type: Function,
value: function() {
@@ -10023,26 +6957,17 @@ Polymer({
'_updateOverlayPosition(positionTarget, verticalAlign, horizontalAlign, verticalOffset, horizontalOffset)'
],
- /**
- * The element that is contained by the dropdown, if any.
- */
get containedElement() {
return Polymer.dom(this.$.content).getDistributedNodes()[0];
},
- /**
- * The element that should be focused when the dropdown opens.
- * @deprecated
- */
get _focusTarget() {
return this.focusTarget || this.containedElement;
},
ready: function() {
- // Memoized scrolling position, used to block scrolling outside.
this._scrollTop = 0;
this._scrollLeft = 0;
- // Used to perform a non-blocking refit on scroll.
this._refitOnScrollRAF = null;
},
@@ -10051,10 +6976,6 @@ Polymer({
Polymer.IronDropdownScrollManager.removeScrollLock(this);
},
- /**
- * Called when the value of `opened` changes.
- * Overridden from `IronOverlayBehavior`
- */
_openedChanged: function() {
if (this.opened && this.disabled) {
this.cancel();
@@ -10074,9 +6995,6 @@ Polymer({
}
},
- /**
- * Overridden from `IronOverlayBehavior`.
- */
_renderOpened: function() {
if (!this.noAnimations && this.animationConfig.open) {
this.$.contentWrapper.classList.add('animating');
@@ -10086,9 +7004,6 @@ Polymer({
}
},
- /**
- * Overridden from `IronOverlayBehavior`.
- */
_renderClosed: function() {
if (!this.noAnimations && this.animationConfig.close) {
@@ -10099,12 +7014,6 @@ Polymer({
}
},
- /**
- * Called when animation finishes on the dropdown (when opening or
- * closing). Responsible for "completing" the process of opening or
- * closing the dropdown by positioning it or setting its display to
- * none.
- */
_onNeonAnimationFinish: function() {
this.$.contentWrapper.classList.remove('animating');
if (this.opened) {
@@ -10123,31 +7032,21 @@ Polymer({
}
},
- /**
- * Memoizes the scroll position of the outside scrolling element.
- * @private
- */
_saveScrollPosition: function() {
if (document.scrollingElement) {
this._scrollTop = document.scrollingElement.scrollTop;
this._scrollLeft = document.scrollingElement.scrollLeft;
} else {
- // Since we don't know if is the body or html, get max.
this._scrollTop = Math.max(document.documentElement.scrollTop, document.body.scrollTop);
this._scrollLeft = Math.max(document.documentElement.scrollLeft, document.body.scrollLeft);
}
},
- /**
- * Resets the scroll position of the outside scrolling element.
- * @private
- */
_restoreScrollPosition: function() {
if (document.scrollingElement) {
document.scrollingElement.scrollTop = this._scrollTop;
document.scrollingElement.scrollLeft = this._scrollLeft;
} else {
- // Since we don't know if is the body or html, set both.
document.documentElement.scrollTop = this._scrollTop;
document.documentElement.scrollLeft = this._scrollLeft;
document.body.scrollTop = this._scrollTop;
@@ -10155,10 +7054,6 @@ Polymer({
}
},
- /**
- * Constructs the final animation config from different properties used
- * to configure specific parts of the opening and closing animations.
- */
_updateAnimationConfig: function() {
var animations = (this.openAnimationConfig || []).concat(this.closeAnimationConfig || []);
for (var i = 0; i < animations.length; i++) {
@@ -10170,20 +7065,12 @@ Polymer({
};
},
- /**
- * Updates the overlay position based on configured horizontal
- * and vertical alignment.
- */
_updateOverlayPosition: function() {
if (this.isAttached) {
- // This triggers iron-resize, and iron-overlay-behavior will call refit if needed.
this.notifyResize();
}
},
- /**
- * Apply focus to focusTarget or containedElement
- */
_applyFocus: function () {
var focusTarget = this.focusTarget || this.containedElement;
if (focusTarget && this.opened && !this.noAutoFocus) {
@@ -10333,17 +7220,7 @@ Polymer({
var PaperMenuButton = Polymer({
is: 'paper-menu-button',
- /**
- * Fired when the dropdown opens.
- *
- * @event paper-dropdown-open
- */
- /**
- * Fired when the dropdown closes.
- *
- * @event paper-dropdown-close
- */
behaviors: [
Polymer.IronA11yKeysBehavior,
@@ -10351,9 +7228,6 @@ Polymer({
],
properties: {
- /**
- * True if the content is currently displayed.
- */
opened: {
type: Boolean,
value: false,
@@ -10361,97 +7235,53 @@ Polymer({
observer: '_openedChanged'
},
- /**
- * The orientation against which to align the menu dropdown
- * horizontally relative to the dropdown trigger.
- */
horizontalAlign: {
type: String,
value: 'left',
reflectToAttribute: true
},
- /**
- * The orientation against which to align the menu dropdown
- * vertically relative to the dropdown trigger.
- */
verticalAlign: {
type: String,
value: 'top',
reflectToAttribute: true
},
- /**
- * If true, the `horizontalAlign` and `verticalAlign` properties will
- * be considered preferences instead of strict requirements when
- * positioning the dropdown and may be changed if doing so reduces
- * the area of the dropdown falling outside of `fitInto`.
- */
dynamicAlign: {
type: Boolean
},
- /**
- * A pixel value that will be added to the position calculated for the
- * given `horizontalAlign`. Use a negative value to offset to the
- * left, or a positive value to offset to the right.
- */
horizontalOffset: {
type: Number,
value: 0,
notify: true
},
- /**
- * A pixel value that will be added to the position calculated for the
- * given `verticalAlign`. Use a negative value to offset towards the
- * top, or a positive value to offset towards the bottom.
- */
verticalOffset: {
type: Number,
value: 0,
notify: true
},
- /**
- * If true, the dropdown will be positioned so that it doesn't overlap
- * the button.
- */
noOverlap: {
type: Boolean
},
- /**
- * Set to true to disable animations when opening and closing the
- * dropdown.
- */
noAnimations: {
type: Boolean,
value: false
},
- /**
- * Set to true to disable automatically closing the dropdown after
- * a selection has been made.
- */
ignoreSelect: {
type: Boolean,
value: false
},
- /**
- * Set to true to enable automatically closing the dropdown after an
- * item has been activated, even if the selection did not change.
- */
closeOnActivate: {
type: Boolean,
value: false
},
- /**
- * An animation config. If provided, this will be used to animate the
- * opening of the dropdown.
- */
openAnimationConfig: {
type: Object,
value: function() {
@@ -10479,10 +7309,6 @@ Polymer({
}
},
- /**
- * An animation config. If provided, this will be used to animate the
- * closing of the dropdown.
- */
closeAnimationConfig: {
type: Object,
value: function() {
@@ -10508,29 +7334,16 @@ Polymer({
}
},
- /**
- * By default, the dropdown will constrain scrolling on the page
- * to itself when opened.
- * Set to true in order to prevent scroll from being constrained
- * to the dropdown when it opens.
- */
allowOutsideScroll: {
type: Boolean,
value: false
},
- /**
- * Whether focus should be restored to the button when the menu closes.
- */
restoreFocusOnClose: {
type: Boolean,
value: true
},
- /**
- * This is the element intended to be bound as the focus target
- * for the `iron-dropdown` contained by `paper-menu-button`.
- */
_dropdownContent: {
type: Object
}
@@ -10546,16 +7359,10 @@ Polymer({
'iron-select': '_onIronSelect'
},
- /**
- * The content element that is contained by the menu button, if any.
- */
get contentElement() {
return Polymer.dom(this.$.content).getDistributedNodes()[0];
},
- /**
- * Toggles the drowpdown content between opened and closed.
- */
toggle: function() {
if (this.opened) {
this.close();
@@ -10564,10 +7371,6 @@ Polymer({
}
},
- /**
- * Make the dropdown content appear as an overlay positioned relative
- * to the dropdown trigger.
- */
open: function() {
if (this.disabled) {
return;
@@ -10576,52 +7379,24 @@ Polymer({
this.$.dropdown.open();
},
- /**
- * Hide the dropdown content.
- */
close: function() {
this.$.dropdown.close();
},
- /**
- * When an `iron-select` event is received, the dropdown should
- * automatically close on the assumption that a value has been chosen.
- *
- * @param {CustomEvent} event A CustomEvent instance with type
- * set to `"iron-select"`.
- */
_onIronSelect: function(event) {
if (!this.ignoreSelect) {
this.close();
}
},
- /**
- * Closes the dropdown when an `iron-activate` event is received if
- * `closeOnActivate` is true.
- *
- * @param {CustomEvent} event A CustomEvent of type 'iron-activate'.
- */
_onIronActivate: function(event) {
if (this.closeOnActivate) {
this.close();
}
},
- /**
- * When the dropdown opens, the `paper-menu-button` fires `paper-open`.
- * When the dropdown closes, the `paper-menu-button` fires `paper-close`.
- *
- * @param {boolean} opened True if the dropdown is opened, otherwise false.
- * @param {boolean} oldOpened The previous value of `opened`.
- */
_openedChanged: function(opened, oldOpened) {
if (opened) {
- // TODO(cdata): Update this when we can measure changes in distributed
- // children in an idiomatic way.
- // We poke this property in case the element has changed. This will
- // cause the focus target for the `iron-dropdown` to be updated as
- // necessary:
this._dropdownContent = this.contentElement;
this.fire('paper-dropdown-open');
} else if (oldOpened != null) {
@@ -10629,12 +7404,6 @@ Polymer({
}
},
- /**
- * If the dropdown is open when disabled becomes true, close the
- * dropdown.
- *
- * @param {boolean} disabled True if disabled, otherwise false.
- */
_disabledChanged: function(disabled) {
Polymer.IronControlState._disabledChanged.apply(this, arguments);
if (disabled && this.opened) {
@@ -10660,11 +7429,6 @@ Polymer({
Polymer.PaperMenuButton = PaperMenuButton;
})();
-/**
- * `Polymer.PaperInkyFocusBehavior` implements a ripple when the element has keyboard focus.
- *
- * @polymerBehavior Polymer.PaperInkyFocusBehavior
- */
Polymer.PaperInkyFocusBehaviorImpl = {
observers: [
'_focusedChanged(receivedFocusFromKeyboard)'
@@ -10708,26 +7472,14 @@ Polymer({
],
properties: {
- /**
- * The URL of an image for the icon. If the src property is specified,
- * the icon property should not be.
- */
src: {
type: String
},
- /**
- * Specifies the icon name or index in the set of icons available in
- * the icon's icon set. If the icon property is specified,
- * the src property should not be.
- */
icon: {
type: String
},
- /**
- * Specifies the alternate text for the button, for accessibility.
- */
alt: {
type: String,
observer: "_altChanged"
@@ -10737,7 +7489,6 @@ Polymer({
_altChanged: function(newValue, oldValue) {
var label = this.getAttribute('aria-label');
- // Don't stomp over a user-set aria-label.
if (!label || oldValue == label) {
this.setAttribute('aria-label', newValue);
}
@@ -10747,11 +7498,6 @@ Polymer({
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-/**
- * Implements an incremental search field which can be shown and hidden.
- * Canonical implementation is <cr-search-field>.
- * @polymerBehavior
- */
var CrSearchFieldBehavior = {
properties: {
label: {
@@ -10779,27 +7525,13 @@ var CrSearchFieldBehavior = {
},
},
- /**
- * @abstract
- * @return {!HTMLInputElement} The input field element the behavior should
- * use.
- */
getSearchInput: function() {},
- /**
- * @return {string} The value of the search field.
- */
getValue: function() {
return this.getSearchInput().value;
},
- /**
- * Sets the value of the search field.
- * @param {string} value
- */
setValue: function(value) {
- // Use bindValue when setting the input value so that changes propagate
- // correctly.
this.getSearchInput().bindValue = value;
this.onValueChanged_(value);
},
@@ -10818,12 +7550,6 @@ var CrSearchFieldBehavior = {
this.onValueChanged_(this.getValue());
},
- /**
- * Updates the internal state of the search field based on a change that has
- * already happened.
- * @param {string} newValue
- * @private
- */
onValueChanged_: function(newValue) {
if (newValue == this.lastValue_)
return;
@@ -10856,11 +7582,6 @@ var CrSearchFieldBehavior = {
properties: {
- /**
- * The value of mode is used to set the `aria-live` attribute
- * for the element that will be announced. Valid values are: `off`,
- * `polite` and `assertive`.
- */
mode: {
type: String,
value: 'polite'
@@ -10880,11 +7601,6 @@ var CrSearchFieldBehavior = {
document.body.addEventListener('iron-announce', this._onIronAnnounce.bind(this));
},
- /**
- * Cause a text string to be announced by screen readers.
- *
- * @param {string} text The text that should be announced.
- */
announce: function(text) {
this._text = '';
this.async(function() {
@@ -10909,49 +7625,16 @@ var CrSearchFieldBehavior = {
document.body.appendChild(Polymer.IronA11yAnnouncer.instance);
};
})();
-/**
- * Singleton IronMeta instance.
- */
Polymer.IronValidatableBehaviorMeta = null;
- /**
- * `Use Polymer.IronValidatableBehavior` to implement an element that validates user input.
- * Use the related `Polymer.IronValidatorBehavior` to add custom validation logic to an iron-input.
- *
- * By default, an `<iron-form>` element validates its fields when the user presses the submit button.
- * To validate a form imperatively, call the form's `validate()` method, which in turn will
- * call `validate()` on all its children. By using `Polymer.IronValidatableBehavior`, your
- * custom element will get a public `validate()`, which
- * will return the validity of the element, and a corresponding `invalid` attribute,
- * which can be used for styling.
- *
- * To implement the custom validation logic of your element, you must override
- * the protected `_getValidity()` method of this behaviour, rather than `validate()`.
- * See [this](https://github.com/PolymerElements/iron-form/blob/master/demo/simple-element.html)
- * for an example.
- *
- * ### Accessibility
- *
- * Changing the `invalid` property, either manually or by calling `validate()` will update the
- * `aria-invalid` attribute.
- *
- * @demo demo/index.html
- * @polymerBehavior
- */
Polymer.IronValidatableBehavior = {
properties: {
- /**
- * Name of the validator to use.
- */
validator: {
type: String
},
- /**
- * True if the last call to `validate` is invalid.
- */
invalid: {
notify: true,
reflectToAttribute: true,
@@ -10959,19 +7642,10 @@ var CrSearchFieldBehavior = {
value: false
},
- /**
- * This property is deprecated and should not be used. Use the global
- * validator meta singleton, `Polymer.IronValidatableBehaviorMeta` instead.
- */
_validatorMeta: {
type: Object
},
- /**
- * Namespace for this validator. This property is deprecated and should
- * not be used. For all intents and purposes, please consider it a
- * read-only, config-time property.
- */
validatorType: {
type: String,
value: 'validator'
@@ -10999,36 +7673,15 @@ var CrSearchFieldBehavior = {
}
},
- /**
- * @return {boolean} True if the validator `validator` exists.
- */
hasValidator: function() {
return this._validator != null;
},
- /**
- * Returns true if the `value` is valid, and updates `invalid`. If you want
- * your element to have custom validation logic, do not override this method;
- * override `_getValidity(value)` instead.
-
- * @param {Object} value The value to be validated. By default, it is passed
- * to the validator's `validate()` function, if a validator is set.
- * @return {boolean} True if `value` is valid.
- */
validate: function(value) {
this.invalid = !this._getValidity(value);
return !this.invalid;
},
- /**
- * Returns true if `value` is valid. By default, it is passed
- * to the validator's `validate()` function, if a validator is set. You
- * should override this method if you want to implement custom validity
- * logic for your element.
- *
- * @param {Object} value The value to be validated.
- * @return {boolean} True if `value` is valid.
- */
_getValidity: function(value) {
if (this.hasValidator()) {
@@ -11042,39 +7695,6 @@ var CrSearchFieldBehavior = {
Polymer.IronValidatableBehaviorMeta.byKey(this.validator);
}
};
-/*
-`<iron-input>` adds two-way binding and custom validators using `Polymer.IronValidatorBehavior`
-to `<input>`.
-
-### Two-way binding
-
-By default you can only get notified of changes to an `input`'s `value` due to user input:
-
- <input value="{{myValue::input}}">
-
-`iron-input` adds the `bind-value` property that mirrors the `value` property, and can be used
-for two-way data binding. `bind-value` will notify if it is changed either by user input or by script.
-
- <input is="iron-input" bind-value="{{myValue}}">
-
-### Custom validators
-
-You can use custom validators that implement `Polymer.IronValidatorBehavior` with `<iron-input>`.
-
- <input is="iron-input" validator="my-custom-validator">
-
-### Stopping invalid input
-
-It may be desirable to only allow users to enter certain characters. You can use the
-`prevent-invalid-input` and `allowed-pattern` attributes together to accomplish this. This feature
-is separate from validation, and `allowed-pattern` does not affect how the input is validated.
-
- \x3c!-- only allow characters that match [0-9] --\x3e
- <input is="iron-input" prevent-invalid-input allowed-pattern="[0-9]">
-
-@hero hero.svg
-@demo demo/index.html
-*/
Polymer({
@@ -11088,32 +7708,15 @@ is separate from validation, and `allowed-pattern` does not affect how the input
properties: {
- /**
- * Use this property instead of `value` for two-way data binding.
- */
bindValue: {
observer: '_bindValueChanged',
type: String
},
- /**
- * Set to true to prevent the user from entering invalid input. If `allowedPattern` is set,
- * any character typed by the user will be matched against that pattern, and rejected if it's not a match.
- * Pasted input will have each character checked individually; if any character
- * doesn't match `allowedPattern`, the entire pasted string will be rejected.
- * If `allowedPattern` is not set, it will use the `type` attribute (only supported for `type=number`).
- */
preventInvalidInput: {
type: Boolean
},
- /**
- * Regular expression that list the characters allowed as input.
- * This pattern represents the allowed characters for the field; as the user inputs text,
- * each individual character will be checked against the pattern (rather than checking
- * the entire value as a whole). The recommended format should be a list of allowed characters;
- * for example, `[a-zA-Z0-9.+-!;:]`
- */
allowedPattern: {
type: String,
observer: "_allowedPatternChanged"
@@ -11138,7 +7741,6 @@ is separate from validation, and `allowed-pattern` does not affect how the input
/** @suppress {checkTypes} */
registered: function() {
- // Feature detect whether we need to patch dispatchEvent (i.e. on FF and IE).
if (!this._canDispatchEventOnDisabled()) {
this._origDispatchEvent = this.dispatchEvent;
this.dispatchEvent = this._dispatchEventFirefoxIE;
@@ -11166,11 +7768,6 @@ is separate from validation, and `allowed-pattern` does not affect how the input
},
_dispatchEventFirefoxIE: function() {
- // Due to Firefox bug, events fired on disabled form controls can throw
- // errors; furthermore, neither IE nor Firefox will actually dispatch
- // events from disabled form controls; as such, we toggle disable around
- // the dispatch to allow notifying properties to notify
- // See issue #47 for details
var disabled = this.disabled;
this.disabled = false;
this._origDispatchEvent.apply(this, arguments);
@@ -11195,25 +7792,18 @@ is separate from validation, and `allowed-pattern` does not affect how the input
this.bindValue = this.value;
},
- /**
- * @suppress {checkTypes}
- */
_bindValueChanged: function() {
if (this.value !== this.bindValue) {
this.value = !(this.bindValue || this.bindValue === 0 || this.bindValue === false) ? '' : this.bindValue;
}
- // manually notify because we don't want to notify until after setting value
this.fire('bind-value-changed', {value: this.bindValue});
},
_allowedPatternChanged: function() {
- // Force to prevent invalid input when an `allowed-pattern` is set
this.preventInvalidInput = this.allowedPattern ? true : false;
},
_onInput: function() {
- // Need to validate each of the characters pasted if they haven't
- // been validated inside `_onKeypress` already.
if (this.preventInvalidInput && !this._patternAlreadyChecked) {
var valid = this._checkPatternValidity();
if (!valid) {
@@ -11228,24 +7818,13 @@ is separate from validation, and `allowed-pattern` does not affect how the input
},
_isPrintable: function(event) {
- // What a control/printable character is varies wildly based on the browser.
- // - most control characters (arrows, backspace) do not send a `keypress` event
- // in Chrome, but the *do* on Firefox
- // - in Firefox, when they do send a `keypress` event, control chars have
- // a charCode = 0, keyCode = xx (for ex. 40 for down arrow)
- // - printable characters always send a keypress event.
- // - in Firefox, printable chars always have a keyCode = 0. In Chrome, the keyCode
- // always matches the charCode.
- // None of this makes any sense.
-
- // For these keys, ASCII code == browser keycode.
+
var anyNonPrintable =
(event.keyCode == 8) || // backspace
(event.keyCode == 9) || // tab
(event.keyCode == 13) || // enter
(event.keyCode == 27); // escape
- // For these keys, make sure it's a browser keycode and not an ASCII code.
var mozNonPrintable =
(event.keyCode == 19) || // pause
(event.keyCode == 20) || // caps lock
@@ -11268,11 +7847,9 @@ is separate from validation, and `allowed-pattern` does not affect how the input
return;
}
- // Handle special keys and backspace
if (event.metaKey || event.ctrlKey || event.altKey)
return;
- // Check the pattern either here or in `_onInput`, but not in both.
this._patternAlreadyChecked = true;
var thisChar = String.fromCharCode(event.charCode);
@@ -11295,20 +7872,10 @@ is separate from validation, and `allowed-pattern` does not affect how the input
return true;
},
- /**
- * Returns true if `value` is valid. The validator provided in `validator` will be used first,
- * then any constraints.
- * @return {boolean} True if the value is valid.
- */
validate: function() {
- // First, check what the browser thinks. Some inputs (like type=number)
- // behave weirdly and will set the value to "" if something invalid is
- // entered, but will set the validity correctly.
var valid = this.checkValidity();
- // Only do extra checking if the browser thought this was valid.
if (valid) {
- // Empty, required input is invalid
if (this.required && this.value === '') {
valid = false;
} else if (this.hasValidator()) {
@@ -11326,60 +7893,36 @@ is separate from validation, and `allowed-pattern` does not affect how the input
}
});
- /*
- The `iron-input-validate` event is fired whenever `validate()` is called.
- @event iron-input-validate
- */
Polymer({
is: 'paper-input-container',
properties: {
- /**
- * Set to true to disable the floating label. The label disappears when the input value is
- * not null.
- */
noLabelFloat: {
type: Boolean,
value: false
},
- /**
- * Set to true to always float the floating label.
- */
alwaysFloatLabel: {
type: Boolean,
value: false
},
- /**
- * The attribute to listen for value changes on.
- */
attrForValue: {
type: String,
value: 'bind-value'
},
- /**
- * Set to true to auto-validate the input value when it changes.
- */
autoValidate: {
type: Boolean,
value: false
},
- /**
- * True if the input is invalid. This property is set automatically when the input value
- * changes if auto-validating, or when the `iron-input-validate` event is heard from a child.
- */
invalid: {
observer: '_invalidChanged',
type: Boolean,
value: false
},
- /**
- * True if the input has focus.
- */
focused: {
readOnly: true,
type: Boolean,
@@ -11389,9 +7932,6 @@ Polymer({
_addons: {
type: Array
- // do not set a default value here intentionally - it will be initialized lazily when a
- // distributed child is attached, which may occur before configuration for this element
- // in polyfill.
},
_inputHasContent: {
@@ -11469,7 +8009,6 @@ Polymer({
this.addEventListener('input', this._onInput);
}
- // Only validate when attached if the input already has a value.
if (this._inputElementValue != '') {
this._handleValueAndAutoValidate(this._inputElement);
} else {
@@ -11510,7 +8049,6 @@ Polymer({
_handleValue: function(inputElement) {
var value = this._inputElementValue;
- // type="number" hack needed because this.value is empty until it's valid
if (value || value === 0 || (inputElement.type === 'number' && !inputElement.checkValidity())) {
this._inputHasContent = true;
} else {
@@ -11535,7 +8073,6 @@ Polymer({
this.invalid = !valid;
}
- // Call this last to notify the add-ons.
this._handleValue(inputElement);
},
@@ -11549,10 +8086,6 @@ Polymer({
}
},
- /**
- * Call this to update the state of add-ons.
- * @param {Object} state Add-on state.
- */
updateAddons: function(state) {
for (var addon, index = 0; addon = this._addons[index]; index++) {
addon.update(state);
@@ -11566,8 +8099,6 @@ Polymer({
if (alwaysFloatLabel || _inputHasContent) {
cls += ' label-is-floating';
- // If the label is floating, ignore any offsets that may have been
- // applied from a prefix element.
this.$.labelAndInputContainer.style.position = 'static';
if (invalid) {
@@ -11576,7 +8107,6 @@ Polymer({
cls += " label-is-highlighted";
}
} else {
- // When the label is not floating, it should overlap the input element.
if (label) {
this.$.labelAndInputContainer.style.position = 'relative';
}
@@ -11647,7 +8177,6 @@ cr.define('downloads', function() {
is: 'downloads-toolbar',
attached: function() {
- // isRTL() only works after i18n_template.js runs to set <html dir>.
this.overflowAlign_ = isRTL() ? 'left' : 'right';
},
@@ -11705,10 +8234,6 @@ cr.define('downloads', function() {
window.removeEventListener('resize', assert(this.boundClose_));
},
- /**
- * @param {!Event} e
- * @private
- */
onItemBlur_: function(e) {
var menu = /** @type {PaperMenuElement} */(this.$$('paper-menu'));
if (menu.items.indexOf(e.relatedTarget) >= 0)
@@ -11725,10 +8250,6 @@ cr.define('downloads', function() {
window.addEventListener('resize', this.boundClose_);
},
- /**
- * @param {!CustomEvent} event
- * @private
- */
onSearchChanged_: function(event) {
downloads.ActionService.getInstance().search(
/** @type {string} */ (event.detail));
@@ -11801,11 +8322,6 @@ cr.define('downloads', function() {
}
},
- /**
- * @param {number} index
- * @param {!Array<!downloads.Data>} list
- * @private
- */
insertItems_: function(index, list) {
this.splice.apply(this, ['items_', index, 0].concat(list));
this.updateHideDates_(index, index + list.length);
@@ -11817,10 +8333,6 @@ cr.define('downloads', function() {
this.hasDownloads_ = this.items_.length > 0;
},
- /**
- * @param {Event} e
- * @private
- */
onCanExecute_: function(e) {
e = /** @type {cr.ui.CanExecuteEvent} */(e);
switch (e.command.id) {
@@ -11836,10 +8348,6 @@ cr.define('downloads', function() {
}
},
- /**
- * @param {Event} e
- * @private
- */
onCommand_: function(e) {
if (e.command.id == 'clear-all-command')
downloads.ActionService.getInstance().clearAll();
@@ -11853,7 +8361,6 @@ cr.define('downloads', function() {
onListScroll_: function() {
var list = this.$['downloads-list'];
if (list.scrollHeight - list.scrollTop - list.offsetHeight <= 100) {
- // Approaching the end of the scrollback. Attempt to load more items.
downloads.ActionService.getInstance().loadMore();
}
},
@@ -11867,21 +8374,12 @@ cr.define('downloads', function() {
downloads.ActionService.getInstance().loadMore();
},
- /**
- * @param {number} index
- * @private
- */
removeItem_: function(index) {
this.splice('items_', index, 1);
this.updateHideDates_(index, index);
this.onListScroll_();
},
- /**
- * @param {number} start
- * @param {number} end
- * @private
- */
updateHideDates_: function(start, end) {
for (var i = start; i <= end; ++i) {
var current = this.items_[i];
@@ -11892,11 +8390,6 @@ cr.define('downloads', function() {
}
},
- /**
- * @param {number} index
- * @param {!downloads.Data} data
- * @private
- */
updateItem_: function(index, data) {
this.set('items_.' + index, data);
this.updateHideDates_(index, index);
« no previous file with comments | « no previous file | chrome/browser/resources/md_history/app.crisper.js » ('j') | chrome/browser/resources/vulcanize.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698