UNPKG

@quantlab/handsontable

Version:

Spreadsheet-like data grid editor that provides copy/paste functionality compatible with Excel/Google Docs

1,766 lines (1,531 loc) 1.5 MB
/*! * (The MIT License) * * Copyright (c) 2012-2014 Marcin Warpechowski * Copyright (c) 2015 Handsoncode sp. z o.o. <hello@handsoncode.net> * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * 'Software'), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * Version: 0.33.0 * Date: Mon Jul 10 2017 10:08:33 GMT+0200 (CEST) */ (function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(require("moment"), require("numbro"), require("pikaday")); else if(typeof define === 'function' && define.amd) define("Handsontable", ["moment", "numbro", "pikaday"], factory); else if(typeof exports === 'object') exports["Handsontable"] = factory(require("moment"), require("numbro"), require("pikaday")); else root["Handsontable"] = factory(root["moment"], root["numbro"], root["Pikaday"]); })(this, function(__WEBPACK_EXTERNAL_MODULE_61__, __WEBPACK_EXTERNAL_MODULE_87__, __WEBPACK_EXTERNAL_MODULE_302__) { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // identity function for calling harmony imports with the correct context /******/ __webpack_require__.i = function(value) { return value; }; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { /******/ configurable: false, /******/ enumerable: true, /******/ get: getter /******/ }); /******/ } /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = 208); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; exports.__esModule = true; exports.HTML_CHARACTERS = undefined; exports.getParent = getParent; exports.closest = closest; exports.closestDown = closestDown; exports.isChildOf = isChildOf; exports.isChildOfWebComponentTable = isChildOfWebComponentTable; exports.polymerWrap = polymerWrap; exports.polymerUnwrap = polymerUnwrap; exports.index = index; exports.overlayContainsElement = overlayContainsElement; exports.hasClass = hasClass; exports.addClass = addClass; exports.removeClass = removeClass; exports.removeTextNodes = removeTextNodes; exports.empty = empty; exports.fastInnerHTML = fastInnerHTML; exports.fastInnerText = fastInnerText; exports.isVisible = isVisible; exports.offset = offset; exports.getWindowScrollTop = getWindowScrollTop; exports.getWindowScrollLeft = getWindowScrollLeft; exports.getScrollTop = getScrollTop; exports.getScrollLeft = getScrollLeft; exports.getScrollableElement = getScrollableElement; exports.getTrimmingContainer = getTrimmingContainer; exports.getStyle = getStyle; exports.getComputedStyle = getComputedStyle; exports.outerWidth = outerWidth; exports.outerHeight = outerHeight; exports.innerHeight = innerHeight; exports.innerWidth = innerWidth; exports.addEvent = addEvent; exports.removeEvent = removeEvent; exports.getCaretPosition = getCaretPosition; exports.getSelectionEndPosition = getSelectionEndPosition; exports.getSelectionText = getSelectionText; exports.setCaretPosition = setCaretPosition; exports.getScrollbarWidth = getScrollbarWidth; exports.hasVerticalScrollbar = hasVerticalScrollbar; exports.hasHorizontalScrollbar = hasHorizontalScrollbar; exports.setOverlayPosition = setOverlayPosition; exports.getCssTransform = getCssTransform; exports.resetCssTransform = resetCssTransform; exports.isInput = isInput; exports.isOutsideInput = isOutsideInput; var _browser = __webpack_require__(25); var _feature = __webpack_require__(34); /** * Get the parent of the specified node in the DOM tree. * * @param {HTMLElement} element Element from which traversing is started. * @param {Number} [level=0] Traversing deep level. * @return {HTMLElement|null} */ function getParent(element) { var level = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; var iteration = -1; var parent = null; while (element != null) { if (iteration === level) { parent = element; break; } if (element.host && element.nodeType === Node.DOCUMENT_FRAGMENT_NODE) { element = element.host; } else { iteration++; element = element.parentNode; } } return parent; } /** * Goes up the DOM tree (including given element) until it finds an element that matches the nodes or nodes name. * This method goes up through web components. * * @param {HTMLElement} element Element from which traversing is started * @param {Array} nodes Array of elements or Array of elements name * @param {HTMLElement} [until] * @returns {HTMLElement|null} */ function closest(element, nodes, until) { while (element != null && element !== until) { if (element.nodeType === Node.ELEMENT_NODE && (nodes.indexOf(element.nodeName) > -1 || nodes.indexOf(element) > -1)) { return element; } if (element.host && element.nodeType === Node.DOCUMENT_FRAGMENT_NODE) { element = element.host; } else { element = element.parentNode; } } return null; } /** * Goes "down" the DOM tree (including given element) until it finds an element that matches the nodes or nodes name. * * @param {HTMLElement} element Element from which traversing is started * @param {Array} nodes Array of elements or Array of elements name * @param {HTMLElement} [until] * @returns {HTMLElement|null} */ function closestDown(element, nodes, until) { var matched = []; while (element) { element = closest(element, nodes, until); if (!element || until && !until.contains(element)) { break; } matched.push(element); if (element.host && element.nodeType === Node.DOCUMENT_FRAGMENT_NODE) { element = element.host; } else { element = element.parentNode; } } var length = matched.length; return length ? matched[length - 1] : null; } /** * Goes up the DOM tree and checks if element is child of another element. * * @param child Child element * @param {Object|String} parent Parent element OR selector of the parent element. * If string provided, function returns `true` for the first occurrence of element with that class. * @returns {Boolean} */ function isChildOf(child, parent) { var node = child.parentNode; var queriedParents = []; if (typeof parent === 'string') { queriedParents = Array.prototype.slice.call(document.querySelectorAll(parent), 0); } else { queriedParents.push(parent); } while (node != null) { if (queriedParents.indexOf(node) > -1) { return true; } node = node.parentNode; } return false; } /** * Check if an element is part of `hot-table` web component. * * @param {Element} element * @returns {Boolean} */ function isChildOfWebComponentTable(element) { var hotTableName = 'hot-table', result = false, parentNode; parentNode = polymerWrap(element); function isHotTable(element) { return element.nodeType === Node.ELEMENT_NODE && element.nodeName === hotTableName.toUpperCase(); } while (parentNode != null) { if (isHotTable(parentNode)) { result = true; break; } else if (parentNode.host && parentNode.nodeType === Node.DOCUMENT_FRAGMENT_NODE) { result = isHotTable(parentNode.host); if (result) { break; } parentNode = parentNode.host; } parentNode = parentNode.parentNode; } return result; } /** * Wrap element into polymer/webcomponent container if exists * * @param element * @returns {*} */ function polymerWrap(element) { /* global Polymer */ return typeof Polymer !== 'undefined' && typeof wrap === 'function' ? wrap(element) : element; } /** * Unwrap element from polymer/webcomponent container if exists * * @param element * @returns {*} */ function polymerUnwrap(element) { /* global Polymer */ return typeof Polymer !== 'undefined' && typeof unwrap === 'function' ? unwrap(element) : element; } /** * Counts index of element within its parent * WARNING: for performance reasons, assumes there are only element nodes (no text nodes). This is true for Walkotnable * Otherwise would need to check for nodeType or use previousElementSibling * * @see http://jsperf.com/sibling-index/10 * @param {Element} element * @return {Number} */ function index(element) { var i = 0; if (element.previousSibling) { /* eslint-disable no-cond-assign */ while (element = element.previousSibling) { ++i; } } return i; } /** * Check if the provided overlay contains the provided element * * @param {String} overlay * @param {HTMLElement} element * @returns {boolean} */ function overlayContainsElement(overlayType, element) { var overlayElement = document.querySelector('.ht_clone_' + overlayType); return overlayElement ? overlayElement.contains(element) : null; } var classListSupport = !!document.documentElement.classList; var _hasClass, _addClass, _removeClass; function filterEmptyClassNames(classNames) { var len = 0, result = []; if (!classNames || !classNames.length) { return result; } while (classNames[len]) { result.push(classNames[len]); len++; } return result; } if (classListSupport) { var isSupportMultipleClassesArg = function () { var element = document.createElement('div'); element.classList.add('test', 'test2'); return element.classList.contains('test2'); }(); _hasClass = function _hasClass(element, className) { if (className === '') { return false; } return element.classList.contains(className); }; _addClass = function _addClass(element, className) { var len = 0; if (typeof className === 'string') { className = className.split(' '); } className = filterEmptyClassNames(className); if (isSupportMultipleClassesArg) { element.classList.add.apply(element.classList, className); } else { while (className && className[len]) { element.classList.add(className[len]); len++; } } }; _removeClass = function _removeClass(element, className) { var len = 0; if (typeof className === 'string') { className = className.split(' '); } className = filterEmptyClassNames(className); if (isSupportMultipleClassesArg) { element.classList.remove.apply(element.classList, className); } else { while (className && className[len]) { element.classList.remove(className[len]); len++; } } }; } else { var createClassNameRegExp = function createClassNameRegExp(className) { return new RegExp('(\\s|^)' + className + '(\\s|$)'); }; _hasClass = function _hasClass(element, className) { // http://snipplr.com/view/3561/addclass-removeclass-hasclass/ return !!element.className.match(createClassNameRegExp(className)); }; _addClass = function _addClass(element, className) { var len = 0, _className = element.className; if (typeof className === 'string') { className = className.split(' '); } if (_className === '') { _className = className.join(' '); } else { while (className && className[len]) { if (!createClassNameRegExp(className[len]).test(_className)) { _className += ' ' + className[len]; } len++; } } element.className = _className; }; _removeClass = function _removeClass(element, className) { var len = 0, _className = element.className; if (typeof className === 'string') { className = className.split(' '); } while (className && className[len]) { // String.prototype.trim is defined in polyfill.js _className = _className.replace(createClassNameRegExp(className[len]), ' ').trim(); len++; } if (element.className !== _className) { element.className = _className; } }; } /** * Checks if element has class name * * @param {HTMLElement} element * @param {String} className Class name to check * @returns {Boolean} */ function hasClass(element, className) { return _hasClass(element, className); } /** * Add class name to an element * * @param {HTMLElement} element * @param {String|Array} className Class name as string or array of strings */ function addClass(element, className) { return _addClass(element, className); } /** * Remove class name from an element * * @param {HTMLElement} element * @param {String|Array} className Class name as string or array of strings */ function removeClass(element, className) { return _removeClass(element, className); } function removeTextNodes(element, parent) { if (element.nodeType === 3) { parent.removeChild(element); // bye text nodes! } else if (['TABLE', 'THEAD', 'TBODY', 'TFOOT', 'TR'].indexOf(element.nodeName) > -1) { var childs = element.childNodes; for (var i = childs.length - 1; i >= 0; i--) { removeTextNodes(childs[i], element); } } } /** * Remove childs function * WARNING - this doesn't unload events and data attached by jQuery * http://jsperf.com/jquery-html-vs-empty-vs-innerhtml/9 * http://jsperf.com/jquery-html-vs-empty-vs-innerhtml/11 - no siginificant improvement with Chrome remove() method * * @param element * @returns {void} */ // function empty(element) { var child; /* eslint-disable no-cond-assign */ while (child = element.lastChild) { element.removeChild(child); } } var HTML_CHARACTERS = exports.HTML_CHARACTERS = /(<(.*)>|&(.*);)/; /** * Insert content into element trying avoid innerHTML method. * @return {void} */ function fastInnerHTML(element, content) { if (HTML_CHARACTERS.test(content)) { element.innerHTML = content; } else { fastInnerText(element, content); } } /** * Insert text content into element * @return {void} */ var textContextSupport = !!document.createTextNode('test').textContent; function fastInnerText(element, content) { var child = element.firstChild; if (child && child.nodeType === 3 && child.nextSibling === null) { // fast lane - replace existing text node if (textContextSupport) { // http://jsperf.com/replace-text-vs-reuse child.textContent = content; } else { // http://jsperf.com/replace-text-vs-reuse child.data = content; } } else { // slow lane - empty element and insert a text node empty(element); element.appendChild(document.createTextNode(content)); } } /** * Returns true if element is attached to the DOM and visible, false otherwise * @param elem * @returns {boolean} */ function isVisible(elem) { var next = elem; while (polymerUnwrap(next) !== document.documentElement) { // until <html> reached if (next === null) { // parent detached from DOM return false; } else if (next.nodeType === Node.DOCUMENT_FRAGMENT_NODE) { if (next.host) { // this is Web Components Shadow DOM // see: http://w3c.github.io/webcomponents/spec/shadow/#encapsulation // according to spec, should be if (next.ownerDocument !== window.document), but that doesn't work yet if (next.host.impl) { // Chrome 33.0.1723.0 canary (2013-11-29) Web Platform features disabled return isVisible(next.host.impl); } else if (next.host) { // Chrome 33.0.1723.0 canary (2013-11-29) Web Platform features enabled return isVisible(next.host); } throw new Error('Lost in Web Components world'); } else { return false; // this is a node detached from document in IE8 } } else if (next.style.display === 'none') { return false; } next = next.parentNode; } return true; } /** * Returns elements top and left offset relative to the document. Function is not compatible with jQuery offset. * * @param {HTMLElement} elem * @return {Object} Returns object with `top` and `left` props */ function offset(elem) { var offsetLeft, offsetTop, lastElem, docElem, box; docElem = document.documentElement; if ((0, _feature.hasCaptionProblem)() && elem.firstChild && elem.firstChild.nodeName === 'CAPTION') { // fixes problem with Firefox ignoring <caption> in TABLE offset (see also export outerHeight) // http://jsperf.com/offset-vs-getboundingclientrect/8 box = elem.getBoundingClientRect(); return { top: box.top + (window.pageYOffset || docElem.scrollTop) - (docElem.clientTop || 0), left: box.left + (window.pageXOffset || docElem.scrollLeft) - (docElem.clientLeft || 0) }; } offsetLeft = elem.offsetLeft; offsetTop = elem.offsetTop; lastElem = elem; /* eslint-disable no-cond-assign */ while (elem = elem.offsetParent) { // from my observation, document.body always has scrollLeft/scrollTop == 0 if (elem === document.body) { break; } offsetLeft += elem.offsetLeft; offsetTop += elem.offsetTop; lastElem = elem; } // slow - http://jsperf.com/offset-vs-getboundingclientrect/6 if (lastElem && lastElem.style.position === 'fixed') { // if(lastElem !== document.body) { //faster but does gives false positive in Firefox offsetLeft += window.pageXOffset || docElem.scrollLeft; offsetTop += window.pageYOffset || docElem.scrollTop; } return { left: offsetLeft, top: offsetTop }; } /** * Returns the document's scrollTop property. * * @returns {Number} */ function getWindowScrollTop() { var res = window.scrollY; if (res === void 0) { // IE8-11 res = document.documentElement.scrollTop; } return res; } /** * Returns the document's scrollLeft property. * * @returns {Number} */ function getWindowScrollLeft() { var res = window.scrollX; if (res === void 0) { // IE8-11 res = document.documentElement.scrollLeft; } return res; } /** * Returns the provided element's scrollTop property. * * @param element * @returns {Number} */ function getScrollTop(element) { if (element === window) { return getWindowScrollTop(); } return element.scrollTop; } /** * Returns the provided element's scrollLeft property. * * @param element * @returns {Number} */ function getScrollLeft(element) { if (element === window) { return getWindowScrollLeft(); } return element.scrollLeft; } /** * Returns a DOM element responsible for scrolling of the provided element. * * @param {HTMLElement} element * @returns {HTMLElement} Element's scrollable parent */ function getScrollableElement(element) { var el = element.parentNode, props = ['auto', 'scroll'], overflow, overflowX, overflowY, computedStyle = '', computedOverflow = '', computedOverflowY = '', computedOverflowX = ''; while (el && el.style && document.body !== el) { overflow = el.style.overflow; overflowX = el.style.overflowX; overflowY = el.style.overflowY; if (overflow == 'scroll' || overflowX == 'scroll' || overflowY == 'scroll') { return el; } else if (window.getComputedStyle) { computedStyle = window.getComputedStyle(el); computedOverflow = computedStyle.getPropertyValue('overflow'); computedOverflowY = computedStyle.getPropertyValue('overflow-y'); computedOverflowX = computedStyle.getPropertyValue('overflow-x'); if (computedOverflow === 'scroll' || computedOverflowX === 'scroll' || computedOverflowY === 'scroll') { return el; } } if (el.clientHeight <= el.scrollHeight && (props.indexOf(overflowY) !== -1 || props.indexOf(overflow) !== -1 || props.indexOf(computedOverflow) !== -1 || props.indexOf(computedOverflowY) !== -1)) { return el; } if (el.clientWidth <= el.scrollWidth && (props.indexOf(overflowX) !== -1 || props.indexOf(overflow) !== -1 || props.indexOf(computedOverflow) !== -1 || props.indexOf(computedOverflowX) !== -1)) { return el; } el = el.parentNode; } return window; } /** * Returns a DOM element responsible for trimming the provided element. * * @param {HTMLElement} base Base element * @returns {HTMLElement} Base element's trimming parent */ function getTrimmingContainer(base) { var el = base.parentNode; while (el && el.style && document.body !== el) { if (el.style.overflow !== 'visible' && el.style.overflow !== '') { return el; } else if (window.getComputedStyle) { var computedStyle = window.getComputedStyle(el); if (computedStyle.getPropertyValue('overflow') !== 'visible' && computedStyle.getPropertyValue('overflow') !== '') { return el; } } el = el.parentNode; } return window; } /** * Returns a style property for the provided element. (Be it an inline or external style). * * @param {HTMLElement} element * @param {String} prop Wanted property * @returns {String|undefined} Element's style property */ function getStyle(element, prop) { /* eslint-disable */ if (!element) { return; } else if (element === window) { if (prop === 'width') { return window.innerWidth + 'px'; } else if (prop === 'height') { return window.innerHeight + 'px'; } return; } var styleProp = element.style[prop], computedStyle; if (styleProp !== '' && styleProp !== void 0) { return styleProp; } else { computedStyle = getComputedStyle(element); if (computedStyle[prop] !== '' && computedStyle[prop] !== void 0) { return computedStyle[prop]; } } } /** * Returns a computed style object for the provided element. (Needed if style is declared in external stylesheet). * * @param element * @returns {IEElementStyle|CssStyle} Elements computed style object */ function getComputedStyle(element) { return element.currentStyle || document.defaultView.getComputedStyle(element); } /** * Returns the element's outer width. * * @param element * @returns {number} Element's outer width */ function outerWidth(element) { return element.offsetWidth; } /** * Returns the element's outer height * * @param elem * @returns {number} Element's outer height */ function outerHeight(elem) { if ((0, _feature.hasCaptionProblem)() && elem.firstChild && elem.firstChild.nodeName === 'CAPTION') { // fixes problem with Firefox ignoring <caption> in TABLE.offsetHeight // jQuery (1.10.1) still has this unsolved // may be better to just switch to getBoundingClientRect // http://bililite.com/blog/2009/03/27/finding-the-size-of-a-table/ // http://lists.w3.org/Archives/Public/www-style/2009Oct/0089.html // http://bugs.jquery.com/ticket/2196 // http://lists.w3.org/Archives/Public/www-style/2009Oct/0140.html#start140 return elem.offsetHeight + elem.firstChild.offsetHeight; } return elem.offsetHeight; } /** * Returns the element's inner height. * * @param element * @returns {number} Element's inner height */ function innerHeight(element) { return element.clientHeight || element.innerHeight; } /** * Returns the element's inner width. * * @param element * @returns {number} Element's inner width */ function innerWidth(element) { return element.clientWidth || element.innerWidth; } function addEvent(element, event, callback) { if (window.addEventListener) { element.addEventListener(event, callback, false); } else { element.attachEvent('on' + event, callback); } } function removeEvent(element, event, callback) { if (window.removeEventListener) { element.removeEventListener(event, callback, false); } else { element.detachEvent('on' + event, callback); } } /** * Returns caret position in text input * * @author http://stackoverflow.com/questions/263743/how-to-get-caret-position-in-textarea * @return {Number} */ function getCaretPosition(el) { if (el.selectionStart) { return el.selectionStart; } else if (document.selection) { // IE8 el.focus(); var r = document.selection.createRange(); if (r == null) { return 0; } var re = el.createTextRange(); var rc = re.duplicate(); re.moveToBookmark(r.getBookmark()); rc.setEndPoint('EndToStart', re); return rc.text.length; } return 0; } /** * Returns end of the selection in text input * * @return {Number} */ function getSelectionEndPosition(el) { if (el.selectionEnd) { return el.selectionEnd; } else if (document.selection) { // IE8 var r = document.selection.createRange(); if (r == null) { return 0; } var re = el.createTextRange(); return re.text.indexOf(r.text) + r.text.length; } return 0; } /** * Returns text under selection. * * @returns {String} */ function getSelectionText() { var text = ''; if (window.getSelection) { text = window.getSelection().toString(); } else if (document.selection && document.selection.type !== 'Control') { text = document.selection.createRange().text; } return text; } /** * Sets caret position in text input. * * @author http://blog.vishalon.net/index.php/javascript-getting-and-setting-caret-position-in-textarea/ * @param {Element} element * @param {Number} pos * @param {Number} endPos */ function setCaretPosition(element, pos, endPos) { if (endPos === void 0) { endPos = pos; } if (element.setSelectionRange) { element.focus(); try { element.setSelectionRange(pos, endPos); } catch (err) { var elementParent = element.parentNode; var parentDisplayValue = elementParent.style.display; elementParent.style.display = 'block'; element.setSelectionRange(pos, endPos); elementParent.style.display = parentDisplayValue; } } else if (element.createTextRange) { // IE8 var range = element.createTextRange(); range.collapse(true); range.moveEnd('character', endPos); range.moveStart('character', pos); range.select(); } } var cachedScrollbarWidth; // http://stackoverflow.com/questions/986937/how-can-i-get-the-browsers-scrollbar-sizes function walkontableCalculateScrollbarWidth() { var inner = document.createElement('div'); inner.style.height = '200px'; inner.style.width = '100%'; var outer = document.createElement('div'); outer.style.boxSizing = 'content-box'; outer.style.height = '150px'; outer.style.left = '0px'; outer.style.overflow = 'hidden'; outer.style.position = 'absolute'; outer.style.top = '0px'; outer.style.width = '200px'; outer.style.visibility = 'hidden'; outer.appendChild(inner); (document.body || document.documentElement).appendChild(outer); var w1 = inner.offsetWidth; outer.style.overflow = 'scroll'; var w2 = inner.offsetWidth; if (w1 == w2) { w2 = outer.clientWidth; } (document.body || document.documentElement).removeChild(outer); return w1 - w2; } /** * Returns the computed width of the native browser scroll bar. * * @return {Number} width */ function getScrollbarWidth() { if (cachedScrollbarWidth === void 0) { cachedScrollbarWidth = walkontableCalculateScrollbarWidth(); } return cachedScrollbarWidth; } /** * Checks if the provided element has a vertical scrollbar. * * @param {HTMLElement} element * @returns {Boolean} */ function hasVerticalScrollbar(element) { return element.offsetWidth !== element.clientWidth; } /** * Checks if the provided element has a vertical scrollbar. * * @param {HTMLElement} element * @returns {Boolean} */ function hasHorizontalScrollbar(element) { return element.offsetHeight !== element.clientHeight; } /** * Sets overlay position depending on it's type and used browser */ function setOverlayPosition(overlayElem, left, top) { if ((0, _browser.isIE8)() || (0, _browser.isIE9)()) { overlayElem.style.top = top; overlayElem.style.left = left; } else if ((0, _browser.isSafari)()) { overlayElem.style['-webkit-transform'] = 'translate3d(' + left + ',' + top + ',0)'; } else { overlayElem.style.transform = 'translate3d(' + left + ',' + top + ',0)'; } } function getCssTransform(element) { var transform; if (element.style.transform && (transform = element.style.transform) !== '') { return ['transform', transform]; } else if (element.style['-webkit-transform'] && (transform = element.style['-webkit-transform']) !== '') { return ['-webkit-transform', transform]; } return -1; } function resetCssTransform(element) { if (element.style.transform && element.style.transform !== '') { element.style.transform = ''; } else if (element.style['-webkit-transform'] && element.style['-webkit-transform'] !== '') { element.style['-webkit-transform'] = ''; } } /** * Determines if the given DOM element is an input field. * Notice: By 'input' we mean input, textarea and select nodes * * @param {HTMLElement} element - DOM element * @returns {Boolean} */ function isInput(element) { var inputs = ['INPUT', 'SELECT', 'TEXTAREA']; return element && (inputs.indexOf(element.nodeName) > -1 || element.contentEditable === 'true'); } /** * Determines if the given DOM element is an input field placed OUTSIDE of HOT. * Notice: By 'input' we mean input, textarea and select nodes * * @param {HTMLElement} element - DOM element * @returns {Boolean} */ function isOutsideInput(element) { return isInput(element) && element.className.indexOf('handsontableInput') == -1 && element.className.indexOf('copyPaste') == -1; } /***/ }), /* 1 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; exports.__esModule = true; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; exports.duckSchema = duckSchema; exports.inherit = inherit; exports.extend = extend; exports.deepExtend = deepExtend; exports.deepClone = deepClone; exports.clone = clone; exports.mixin = mixin; exports.isObjectEquals = isObjectEquals; exports.isObject = isObject; exports.defineGetter = defineGetter; exports.objectEach = objectEach; exports.getProperty = getProperty; exports.deepObjectSize = deepObjectSize; exports.createObjectPropListener = createObjectPropListener; exports.hasOwnProperty = hasOwnProperty; var _array = __webpack_require__(2); function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } /** * Generate schema for passed object. * * @param {Array|Object} object * @returns {Array|Object} */ function duckSchema(object) { var schema; if (Array.isArray(object)) { schema = []; } else { schema = {}; objectEach(object, function (value, key) { if (key === '__children') { return; } if (value && (typeof value === 'undefined' ? 'undefined' : _typeof(value)) === 'object' && !Array.isArray(value)) { schema[key] = duckSchema(value); } else if (Array.isArray(value)) { if (value.length && _typeof(value[0]) === 'object' && !Array.isArray(value[0])) { schema[key] = [duckSchema(value[0])]; } else { schema[key] = []; } } else { schema[key] = null; } }); } return schema; } /** * Inherit without without calling parent constructor, and setting `Child.prototype.constructor` to `Child` instead of `Parent`. * Creates temporary dummy function to call it as constructor. * Described in ticket: https://github.com/handsontable/handsontable/pull/516 * * @param {Object} Child child class * @param {Object} Parent parent class * @return {Object} extended Child */ function inherit(Child, Parent) { Parent.prototype.constructor = Parent; Child.prototype = new Parent(); Child.prototype.constructor = Child; return Child; } /** * Perform shallow extend of a target object with extension's own properties. * * @param {Object} target An object that will receive the new properties. * @param {Object} extension An object containing additional properties to merge into the target. */ function extend(target, extension) { objectEach(extension, function (value, key) { target[key] = value; }); return target; } /** * Perform deep extend of a target object with extension's own properties. * * @param {Object} target An object that will receive the new properties. * @param {Object} extension An object containing additional properties to merge into the target. */ function deepExtend(target, extension) { objectEach(extension, function (value, key) { if (extension[key] && _typeof(extension[key]) === 'object') { if (!target[key]) { if (Array.isArray(extension[key])) { target[key] = []; } else if (Object.prototype.toString.call(extension[key]) === '[object Date]') { target[key] = extension[key]; } else { target[key] = {}; } } deepExtend(target[key], extension[key]); } else { target[key] = extension[key]; } }); } /** * Perform deep clone of an object. * WARNING! Only clones JSON properties. Will cause error when `obj` contains a function, Date, etc. * * @param {Object} obj An object that will be cloned * @return {Object} */ function deepClone(obj) { if ((typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) === 'object') { return JSON.parse(JSON.stringify(obj)); } return obj; } /** * Shallow clone object. * * @param {Object} object * @returns {Object} */ function clone(object) { var result = {}; objectEach(object, function (value, key) { result[key] = value; }); return result; } /** * Extend the Base object (usually prototype) of the functionality the `mixins` objects. * * @param {Object} Base Base object which will be extended. * @param {Object} mixins The object of the functionality will be "copied". * @returns {Object} */ function mixin(Base) { if (!Base.MIXINS) { Base.MIXINS = []; } for (var _len = arguments.length, mixins = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { mixins[_key - 1] = arguments[_key]; } (0, _array.arrayEach)(mixins, function (mixin) { Base.MIXINS.push(mixin.MIXIN_NAME); objectEach(mixin, function (value, key) { if (Base.prototype[key] !== void 0) { throw new Error('Mixin conflict. Property \'' + key + '\' already exist and cannot be overwritten.'); } if (typeof value === 'function') { Base.prototype[key] = value; } else { var getter = function _getter(propertyName, initialValue) { propertyName = '_' + propertyName; var initValue = function initValue(value) { if (Array.isArray(value) || isObject(value)) { value = deepClone(value); } return value; }; return function () { if (this[propertyName] === void 0) { this[propertyName] = initValue(initialValue); } return this[propertyName]; }; }; var setter = function _setter(propertyName) { propertyName = '_' + propertyName; return function (value) { this[propertyName] = value; }; }; Object.defineProperty(Base.prototype, key, { get: getter(key, value), set: setter(key), configurable: true }); } }); }); return Base; } /** * Checks if two objects or arrays are (deep) equal * * @param {Object|Array} object1 * @param {Object|Array} object2 * @returns {Boolean} */ function isObjectEquals(object1, object2) { return JSON.stringify(object1) === JSON.stringify(object2); } /** * Determines whether given object is a plain Object. * Note: String and Array are not plain Objects * @param {*} obj * @returns {boolean} */ function isObject(obj) { return Object.prototype.toString.call(obj) == '[object Object]'; } function defineGetter(object, property, value, options) { options.value = value; options.writable = options.writable !== false; options.enumerable = options.enumerable !== false; options.configurable = options.configurable !== false; Object.defineProperty(object, property, options); } /** * A specialized version of `.forEach` for objects. * * @param {Object} object The object to iterate over. * @param {Function} iteratee The function invoked per iteration. * @returns {Object} Returns `object`. */ function objectEach(object, iteratee) { for (var key in object) { if (!object.hasOwnProperty || object.hasOwnProperty && Object.prototype.hasOwnProperty.call(object, key)) { if (iteratee(object[key], key, object) === false) { break; } } } return object; } /** * Get object property by its name. Access to sub properties can be achieved by dot notation (e.q. `'foo.bar.baz'`). * * @param {Object} object Object which value will be exported. * @param {String} name Object property name. * @returns {*} */ function getProperty(object, name) { var names = name.split('.'); var result = object; objectEach(names, function (name) { result = result[name]; if (result === void 0) { result = void 0; return false; } }); return result; } /** * Return object length (recursively). * * @param {*} object Object for which we want get length. * @returns {Number} */ function deepObjectSize(object) { if (!isObject(object)) { return 0; } var recursObjLen = function recursObjLen(obj) { var result = 0; if (isObject(obj)) { objectEach(obj, function (key) { result += recursObjLen(key); }); } else { result++; } return result; }; return recursObjLen(object); } /** * Create object with property where its value change will be observed. * * @param {*} [defaultValue=undefined] Default value. * @param {String} [propertyToListen='value'] Property to listen. * @returns {Object} */ function createObjectPropListener(defaultValue) { var _holder; var propertyToListen = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'value'; var privateProperty = '_' + propertyToListen; var holder = (_holder = { _touched: false }, _defineProperty(_holder, privateProperty, defaultValue), _defineProperty(_holder, 'isTouched', function isTouched() { return this._touched; }), _holder); Object.defineProperty(holder, propertyToListen, { get: function get() { return this[privateProperty]; }, set: function set(value) { this._touched = true; this[privateProperty] = value; }, enumerable: true, configurable: true }); return holder; } /** * Check if at specified `key` there is any value for `object`. * * @param {Object} object Object to search value at specyfic key. * @param {String} key String key to check. */ function hasOwnProperty(object, key) { return Object.prototype.hasOwnProperty.call(object, key); } /***/ }), /* 2 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; exports.__esModule = true; exports.to2dArray = to2dArray; exports.extendArray = extendArray; exports.pivot = pivot; exports.arrayReduce = arrayReduce; exports.arrayFilter = arrayFilter; exports.arrayMap = arrayMap; exports.arrayEach = arrayEach; exports.arraySum = arraySum; exports.arrayMax = arrayMax; exports.arrayMin = arrayMin; exports.arrayAvg = arrayAvg; exports.arrayFlatten = arrayFlatten; exports.arrayUnique = arrayUnique; function to2dArray(arr) { var i = 0, ilen = arr.length; while (i < ilen) { arr[i] = [arr[i]]; i++; } } function extendArray(arr, extension) { var i = 0, ilen = extension.length; while (i < ilen) { arr.push(extension[i]); i++; } } function pivot(arr) { var pivotedArr = []; if (!arr || arr.length === 0 || !arr[0] || arr[0].length === 0) { return pivotedArr; } var rowCount = arr.length; var colCount = arr[0].length; for (var i = 0; i < rowCount; i++) { for (var j = 0; j < colCount; j++) { if (!pivotedArr[j]) { pivotedArr[j] = []; } pivotedArr[j][i] = arr[i][j]; } } return pivotedArr; } /** * A specialized version of `.reduce` for arrays without support for callback * shorthands and `this` binding. * * {@link https://github.com/lodash/lodash/blob/master/lodash.js} * * @param {Array} array The array to iterate over. * @param {Function} iteratee The function invoked per iteration. * @param {*} [accumulator] The initial value. * @param {Boolean} [initFromArray] Specify using the first element of `array` as the initial value. * @returns {*} Returns the accumulated value. */ function arrayReduce(array, iteratee, accumulator, initFromArray) { var index = -1, length = array.length; if (initFromArray && length) { accumulator = array[++index]; } while (++index < length) { accumulator = iteratee(accumulator, array[index], index, array); } return accumulator; } /** * A specialized version of `.filter` for arrays without support for callback * shorthands and `this` binding. * * {@link https://github.com/lodash/lodash/blob/master/lodash.js} * * @param {Array} array The array to iterate over. * @param {Function} predicate The function invoked per iteration. * @returns {Array} Returns the new filtered array. */ function arrayFilter(array, predicate) { var index = -1, length = array.length, resIndex = -1, result = []; while (++index < length) { var value = array[index]; if (predicate(value, index, array)) { result[++resIndex] = value; } } return result; } /** * A specialized version of `.map` for arrays without support for callback * shorthands and `this` binding. * * @param {Array} array The array to iterate over. * @param {Function} iteratee The function invoked per iteration. * @returns {Array} Returns the new filtered array. */ function arrayMap(array, iteratee) { var index = -1, length = array.length, resIndex = -1, result = []; while (++index < length) { var value = array[index]; result[++resIndex] = iteratee(value, index, array); } return result; } /** * A specialized version of `.forEach` for arrays without support for callback * shorthands and `this` binding. * * {@link https://github.com/lodash/lodash/blob/master/lodash.js} * * @param {Array} array The array to iterate over. * @param {Function} iteratee The function invoked per iteration. * @returns {Array} Returns `array`. */ function arrayEach(array, iteratee) { var index = -1, length = array.length; while (++index < length) { if (iteratee(array[index], index, array) === false) { break; } } return array; } /** * Calculate sum value for each item of the array. * * @param {Array} array The array to process. * @returns {Number} Returns calculated sum value. */ function arraySum(array) { return arrayReduce(array, function (a, b) { return a + b; }, 0); } /** * Returns the highest value from an array. Can be array of numbers or array of strings. * NOTICE: Mixed values is not supported. * * @param {Array} array The array to process. * @returns {Number} Returns the highest value from an array. */ function arrayMax(array) { return arrayReduce(array, function (a, b) { return a > b ? a : b; }, Array.isArray(array) ? array[0] : void 0); } /** * Returns the lowest value from an array. Can be array of numbers or array of strings. * NOTICE: Mixed values is not supported. * * @param {Array} array The array to process. * @returns {Number} Returns the lowest value from an array. */ function arrayMin(array) { return arrayReduce(array, function (a, b) { return a < b ? a : b; }, Array.isArray(array) ? array[0] : void 0); } /** * Calculate average value for each item of the array. * * @param {Array} array The array to process. * @returns {Number} Returns calculated average value. */ function arrayAvg(array) { if (!array.length) { return 0; } return arraySum(array) / array.length; } /** * Flatten multidimensional array. * * @param {Array} array Array of Arrays * @returns {Array} */ function arrayFlatten(array) { return arrayReduce(array, function (initial, value) { return initial.concat(Array.isArray(value) ? arrayFlatten(value) : value); }, []); } /** * Unique values in the array. * * @param {Array} array The array to process. * @returns {Array} */ function arrayUnique(array) { var unique = []; arrayEach(array, function (value) { if (unique.indexOf(value) === -1) { unique.push(value); } }); return unique; } /***/ }), /* 3 */ /***/ (function(module, exports, __webpack_require__) { var global = __webpack_require__(13) , core = __webpack_require__(44) , hide = __webpack_require__(32) , redefine = __webpack_require__(33) , ctx = __webpack_require__(29) , PROTOTYPE = 'prototype'; var $export = function(type, name, source){ var IS_FORCED = type & $export.F ,