15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)cr.define('cr.ui', function() { 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Decorates elements as an instance of a class. 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {string|!Element} source The way to find the element(s) to decorate. 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * If this is a string then {@code querySeletorAll} is used to find the 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * elements to decorate. 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {!Function} constr The constructor to decorate with. The constr 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * needs to have a {@code decorate} function. 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function decorate(source, constr) { 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var elements; 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (typeof source == 'string') 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elements = cr.doc.querySelectorAll(source); 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elements = [source]; 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (var i = 0, el; el = elements[i]; i++) { 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!(el instanceof constr)) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) constr.decorate(el); 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Helper function for creating new element for define. 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function createElementHelper(tagName, opt_bag) { 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Allow passing in ownerDocument to create in a different document. 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var doc; 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (opt_bag && opt_bag.ownerDocument) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) doc = opt_bag.ownerDocument; 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) doc = cr.doc; 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return doc.createElement(tagName); 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Creates the constructor for a UI element class. 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Usage: 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * <pre> 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * var List = cr.ui.define('list'); 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * List.prototype = { 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * __proto__: HTMLUListElement.prototype, 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * decorate: function() { 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * ... 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * }, 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * ... 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * }; 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * </pre> 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {string|Function} tagNameOrFunction The tagName or 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * function to use for newly created elements. If this is a function it 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * needs to return a new element when called. 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {function(Object=):Element} The constructor function which takes 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * an optional property bag. The function also has a static 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * {@code decorate} method added to it. 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function define(tagNameOrFunction) { 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var createFunction, tagName; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (typeof tagNameOrFunction == 'function') { 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) createFunction = tagNameOrFunction; 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tagName = ''; 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) createFunction = createElementHelper; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tagName = tagNameOrFunction; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Creates a new UI element constructor. 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Object=} opt_propertyBag Optional bag of properties to set on the 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * object after created. The property {@code ownerDocument} is special 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * cased and it allows you to create the element in a different 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * document than the default. 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @constructor 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function f(opt_propertyBag) { 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var el = createFunction(tagName, opt_propertyBag); 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) f.decorate(el); 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (var propertyName in opt_propertyBag) { 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) el[propertyName] = opt_propertyBag[propertyName]; 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return el; 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Decorates an element as a UI element class. 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {!Element} el The element to decorate. 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) f.decorate = function(el) { 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) el.__proto__ = f.prototype; 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) el.decorate(); 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return f; 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Input elements do not grow and shrink with their content. This is a simple 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * (and not very efficient) way of handling shrinking to content with support 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * for min width and limited by the width of the parent element. 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {HTMLElement} el The element to limit the width for. 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} parentEl The parent element that should limit the size. 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} min The minimum width. 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} opt_scale Optional scale factor to apply to the width. 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function limitInputWidth(el, parentEl, min, opt_scale) { 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Needs a size larger than borders 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) el.style.width = '10px'; 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var doc = el.ownerDocument; 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var win = doc.defaultView; 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var computedStyle = win.getComputedStyle(el); 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var parentComputedStyle = win.getComputedStyle(parentEl); 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var rtl = computedStyle.direction == 'rtl'; 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // To get the max width we get the width of the treeItem minus the position 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // of the input. 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var inputRect = el.getBoundingClientRect(); // box-sizing 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var parentRect = parentEl.getBoundingClientRect(); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var startPos = rtl ? parentRect.right - inputRect.right : 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inputRect.left - parentRect.left; 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Add up border and padding of the input. 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var inner = parseInt(computedStyle.borderLeftWidth, 10) + 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parseInt(computedStyle.paddingLeft, 10) + 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parseInt(computedStyle.paddingRight, 10) + 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parseInt(computedStyle.borderRightWidth, 10); 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We also need to subtract the padding of parent to prevent it to overflow. 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var parentPadding = rtl ? parseInt(parentComputedStyle.paddingLeft, 10) : 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parseInt(parentComputedStyle.paddingRight, 10); 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var max = parentEl.clientWidth - startPos - inner - parentPadding; 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (opt_scale) 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) max *= opt_scale; 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function limit() { 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (el.scrollWidth > max) { 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) el.style.width = max + 'px'; 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) el.style.width = 0; 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var sw = el.scrollWidth; 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (sw < min) { 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) el.style.width = min + 'px'; 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) el.style.width = sw + 'px'; 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) el.addEventListener('input', limit); 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) limit(); 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Takes a number and spits out a value CSS will be happy with. To avoid 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * subpixel layout issues, the value is rounded to the nearest integral value. 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {number} pixels The number of pixels. 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {string} e.g. '16px'. 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) function toCssPx(pixels) { 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!window.isFinite(pixels)) 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) console.error('Pixel value is not a number: ' + pixels); 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Math.round(pixels) + 'px'; 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return { 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) decorate: decorate, 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) define: define, 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) limitInputWidth: limitInputWidth, 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) toCssPx: toCssPx, 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}); 178