1/*
2@license
3
4dhtmlxGantt v.6.3.5 Standard
5
6This version of dhtmlxGantt is distributed under GPL 2.0 license and can be legally used in GPL projects.
7
8To use dhtmlxGantt in non-GPL projects (and get Pro version of the product), please obtain Commercial/Enterprise or Ultimate license on our site https://dhtmlx.com/docs/products/dhtmlxGantt/#licensing or contact us at sales@dhtmlx.com
9
10(c) XB Software Ltd.
11
12*/
13(function webpackUniversalModuleDefinition(root, factory) {
14	if(typeof exports === 'object' && typeof module === 'object')
15		module.exports = factory();
16	else if(typeof define === 'function' && define.amd)
17		define("ext/dhtmlxgantt_click_drag", [], factory);
18	else if(typeof exports === 'object')
19		exports["ext/dhtmlxgantt_click_drag"] = factory();
20	else
21		root["ext/dhtmlxgantt_click_drag"] = factory();
22})(window, function() {
23return /******/ (function(modules) { // webpackBootstrap
24/******/ 	// The module cache
25/******/ 	var installedModules = {};
26/******/
27/******/ 	// The require function
28/******/ 	function __webpack_require__(moduleId) {
29/******/
30/******/ 		// Check if module is in cache
31/******/ 		if(installedModules[moduleId]) {
32/******/ 			return installedModules[moduleId].exports;
33/******/ 		}
34/******/ 		// Create a new module (and put it into the cache)
35/******/ 		var module = installedModules[moduleId] = {
36/******/ 			i: moduleId,
37/******/ 			l: false,
38/******/ 			exports: {}
39/******/ 		};
40/******/
41/******/ 		// Execute the module function
42/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
43/******/
44/******/ 		// Flag the module as loaded
45/******/ 		module.l = true;
46/******/
47/******/ 		// Return the exports of the module
48/******/ 		return module.exports;
49/******/ 	}
50/******/
51/******/
52/******/ 	// expose the modules object (__webpack_modules__)
53/******/ 	__webpack_require__.m = modules;
54/******/
55/******/ 	// expose the module cache
56/******/ 	__webpack_require__.c = installedModules;
57/******/
58/******/ 	// define getter function for harmony exports
59/******/ 	__webpack_require__.d = function(exports, name, getter) {
60/******/ 		if(!__webpack_require__.o(exports, name)) {
61/******/ 			Object.defineProperty(exports, name, { enumerable: true, get: getter });
62/******/ 		}
63/******/ 	};
64/******/
65/******/ 	// define __esModule on exports
66/******/ 	__webpack_require__.r = function(exports) {
67/******/ 		if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
68/******/ 			Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
69/******/ 		}
70/******/ 		Object.defineProperty(exports, '__esModule', { value: true });
71/******/ 	};
72/******/
73/******/ 	// create a fake namespace object
74/******/ 	// mode & 1: value is a module id, require it
75/******/ 	// mode & 2: merge all properties of value into the ns
76/******/ 	// mode & 4: return value when already ns object
77/******/ 	// mode & 8|1: behave like require
78/******/ 	__webpack_require__.t = function(value, mode) {
79/******/ 		if(mode & 1) value = __webpack_require__(value);
80/******/ 		if(mode & 8) return value;
81/******/ 		if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
82/******/ 		var ns = Object.create(null);
83/******/ 		__webpack_require__.r(ns);
84/******/ 		Object.defineProperty(ns, 'default', { enumerable: true, value: value });
85/******/ 		if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
86/******/ 		return ns;
87/******/ 	};
88/******/
89/******/ 	// getDefaultExport function for compatibility with non-harmony modules
90/******/ 	__webpack_require__.n = function(module) {
91/******/ 		var getter = module && module.__esModule ?
92/******/ 			function getDefault() { return module['default']; } :
93/******/ 			function getModuleExports() { return module; };
94/******/ 		__webpack_require__.d(getter, 'a', getter);
95/******/ 		return getter;
96/******/ 	};
97/******/
98/******/ 	// Object.prototype.hasOwnProperty.call
99/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
100/******/
101/******/ 	// __webpack_public_path__
102/******/ 	__webpack_require__.p = "/codebase/sources/";
103/******/
104/******/
105/******/ 	// Load entry module and return exports
106/******/ 	return __webpack_require__(__webpack_require__.s = "./sources/ext/click_drag/index.ts");
107/******/ })
108/************************************************************************/
109/******/ ({
110
111/***/ "./sources/ext/click_drag/eventsManager.ts":
112/*!*************************************************!*\
113  !*** ./sources/ext/click_drag/eventsManager.ts ***!
114  \*************************************************/
115/*! no static exports found */
116/***/ (function(module, exports, __webpack_require__) {
117
118"use strict";
119
120Object.defineProperty(exports, "__esModule", { value: true });
121var EventsManager = /** @class */ (function () {
122    function EventsManager() {
123        this._mouseDown = false;
124        this._domEvents = gantt._createDomEventScope();
125    }
126    EventsManager.prototype.attach = function (selectedRegion, useKey) {
127        var _this = this;
128        var _target = selectedRegion.getViewPort();
129        this._originPosition = window.getComputedStyle(_target).display;
130        this._restoreOriginPosition = function () {
131            _target.style.position = _this._originPosition;
132        };
133        if (this._originPosition === "static") {
134            _target.style.position = "relative";
135        }
136        var state = gantt.$services.getService("state");
137        state.registerProvider("clickDrag", function () {
138            var result = { autoscroll: false };
139            return result;
140        });
141        var scheduledDndCoordinates = null;
142        var startDragAndDrop = function () {
143            if (!scheduledDndCoordinates) {
144                return;
145            }
146            _this._mouseDown = true;
147            selectedRegion.setStart(scheduledDndCoordinates);
148            selectedRegion.setPosition(scheduledDndCoordinates);
149            selectedRegion.setEnd(scheduledDndCoordinates);
150            scheduledDndCoordinates = null;
151        };
152        this._domEvents.attach(_target, "mousedown", function (event) {
153            scheduledDndCoordinates = null;
154            if (gantt.utils.dom.closest(event.target, ".gantt_task_line, .gantt_task_link")) {
155                return;
156            }
157            state.registerProvider("clickDrag", function () {
158                var result = { autoscroll: _this._mouseDown };
159                return result;
160            });
161            if (useKey && event[useKey] !== true) {
162                return;
163            }
164            scheduledDndCoordinates = _this._getCoordinates(event, selectedRegion);
165        });
166        this._domEvents.attach(document.body, "mouseup", function (event) {
167            scheduledDndCoordinates = null;
168            if (useKey && event[useKey] !== true) {
169                return;
170            }
171            if (_this._mouseDown === true) {
172                _this._mouseDown = false;
173                var coordinates = _this._getCoordinates(event, selectedRegion);
174                selectedRegion.dragEnd(coordinates);
175            }
176        });
177        this._domEvents.attach(_target, "mousemove", function (event) {
178            if (useKey && event[useKey] !== true) {
179                return;
180            }
181            var coordinates = null;
182            if (!_this._mouseDown && scheduledDndCoordinates) {
183                coordinates = _this._getCoordinates(event, selectedRegion);
184                if (Math.abs(scheduledDndCoordinates.relative.left - coordinates.relative.left) > 5) {
185                    // add small threshold not to start dnd on simple click
186                    startDragAndDrop();
187                }
188                return;
189            }
190            if (_this._mouseDown === true) {
191                coordinates = _this._getCoordinates(event, selectedRegion);
192                selectedRegion.setEnd(coordinates);
193                selectedRegion.render();
194            }
195        });
196    };
197    EventsManager.prototype.detach = function () {
198        this._domEvents.detachAll();
199        if (this._restoreOriginPosition) {
200            this._restoreOriginPosition();
201        }
202        var state = gantt.$services.getService("state");
203        state.unregisterProvider("clickDrag");
204    };
205    EventsManager.prototype.destructor = function () {
206        this.detach();
207    };
208    EventsManager.prototype._getCoordinates = function (event, selectedRegion) {
209        var viewPort = selectedRegion.getViewPort();
210        var viewPortBounds = viewPort.getBoundingClientRect();
211        var clientX = event.clientX, clientY = event.clientY;
212        var result = {
213            absolute: {
214                left: clientX,
215                top: clientY,
216            },
217            relative: {
218                left: clientX - viewPortBounds.left + viewPort.scrollLeft,
219                top: clientY - viewPortBounds.top + viewPort.scrollTop
220            }
221        };
222        return result;
223    };
224    return EventsManager;
225}());
226exports.EventsManager = EventsManager;
227
228
229/***/ }),
230
231/***/ "./sources/ext/click_drag/index.ts":
232/*!*****************************************!*\
233  !*** ./sources/ext/click_drag/index.ts ***!
234  \*****************************************/
235/*! no static exports found */
236/***/ (function(module, exports, __webpack_require__) {
237
238"use strict";
239
240var __assign = (this && this.__assign) || function () {
241    __assign = Object.assign || function(t) {
242        for (var s, i = 1, n = arguments.length; i < n; i++) {
243            s = arguments[i];
244            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
245                t[p] = s[p];
246        }
247        return t;
248    };
249    return __assign.apply(this, arguments);
250};
251Object.defineProperty(exports, "__esModule", { value: true });
252var eventsManager_1 = __webpack_require__(/*! ./eventsManager */ "./sources/ext/click_drag/eventsManager.ts");
253var selectedRegion_1 = __webpack_require__(/*! ./selectedRegion */ "./sources/ext/click_drag/selectedRegion.ts");
254if (!gantt.ext) {
255    gantt.ext = {};
256}
257var defaultConfig = {
258    className: "gantt_click_drag_rect",
259    useRequestAnimationFrame: true,
260    callback: undefined,
261    singleRow: false
262};
263var eventsManager = new eventsManager_1.EventsManager();
264gantt.ext.clickDrag = eventsManager;
265gantt.attachEvent("onGanttReady", function () {
266    var config = __assign({ viewPort: gantt.$task_data }, defaultConfig);
267    if (gantt.config.click_drag) {
268        var clickDrag = gantt.config.click_drag;
269        config.render = clickDrag.render || defaultConfig.render;
270        config.className = clickDrag.className || defaultConfig.className;
271        config.callback = clickDrag.callback || defaultConfig.callback;
272        config.viewPort = clickDrag.viewPort || gantt.$task_data;
273        config.useRequestAnimationFrame = clickDrag.useRequestAnimationFrame === undefined ?
274            defaultConfig.useRequestAnimationFrame : clickDrag.useRequestAnimationFrame;
275        config.singleRow = clickDrag.singleRow === undefined ? defaultConfig.singleRow : clickDrag.singleRow;
276        var selectedRegion = new selectedRegion_1.SelectedRegion(config);
277        gantt.ext.clickDrag.attach(selectedRegion, clickDrag.useKey);
278    }
279});
280gantt.attachEvent("onDestroy", function () {
281    eventsManager.destructor();
282});
283
284
285/***/ }),
286
287/***/ "./sources/ext/click_drag/selectedRegion.ts":
288/*!**************************************************!*\
289  !*** ./sources/ext/click_drag/selectedRegion.ts ***!
290  \**************************************************/
291/*! no static exports found */
292/***/ (function(module, exports, __webpack_require__) {
293
294"use strict";
295
296Object.defineProperty(exports, "__esModule", { value: true });
297var eventable = __webpack_require__(/*! ../../utils/eventable */ "./sources/utils/eventable.js");
298var helpers_1 = __webpack_require__(/*! ../../utils/helpers */ "./sources/utils/helpers.js");
299function _countSize(start, end) {
300    var result = start - end;
301    if (result >= 0) {
302        return result;
303    }
304    return -result;
305}
306var SelectedRegion = /** @class */ (function () {
307    function SelectedRegion(config) {
308        var _this = this;
309        this._el = document.createElement("div");
310        this._viewPort = config.viewPort;
311        this._el.classList.add(config.className);
312        if (typeof config.callback === "function") {
313            this._callback = config.callback;
314        }
315        if (typeof config.render === "function") {
316            this.render = function () {
317                _this._el = config.render(_this._startPoint, _this._endPoint);
318                if (config.className !== "") {
319                    _this._el.classList.add(config.className);
320                }
321                _this.draw();
322            };
323        }
324        if (!helpers_1.isEventable(this._viewPort)) {
325            eventable(this._viewPort);
326        }
327        this._singleRow = config.singleRow;
328        this._useRequestAnimationFrame = config.useRequestAnimationFrame;
329    }
330    SelectedRegion.prototype.setStyles = function () {
331        if (this._singleRow) {
332            var height = gantt.config.row_height;
333            this._el.style.height = height + "px";
334            this._el.style.top = (Math.ceil(this._positionPoint.relative.top / height) - 1) * height + "px";
335        }
336        else {
337            this._el.style.height = _countSize(this._endPoint.relative.top, this._startPoint.relative.top) + "px";
338            this._el.style.top = this._positionPoint.relative.top + "px";
339        }
340        this._el.style.width = _countSize(this._endPoint.relative.left, this._startPoint.relative.left) + "px";
341        this._el.style.left = this._positionPoint.relative.left + "px";
342    };
343    SelectedRegion.prototype.render = function () {
344        this.setStyles();
345        this.draw();
346    };
347    SelectedRegion.prototype.draw = function () {
348        var _this = this;
349        if (this._useRequestAnimationFrame) {
350            return helpers_1.requestAnimationFrame(function () {
351                _this._viewPort.appendChild(_this.getElement());
352            });
353        }
354        else {
355            this._viewPort.appendChild(this.getElement());
356        }
357    };
358    SelectedRegion.prototype.clear = function () {
359        var _this = this;
360        if (this._useRequestAnimationFrame) {
361            return helpers_1.requestAnimationFrame(function () {
362                if (!_this._el.parentNode) {
363                    return;
364                }
365                _this._viewPort.removeChild(_this._el);
366            });
367        }
368        else {
369            if (!this._el.parentNode) {
370                return;
371            }
372            this._viewPort.removeChild(this._el);
373        }
374    };
375    SelectedRegion.prototype.getElement = function () {
376        return this._el;
377    };
378    SelectedRegion.prototype.getViewPort = function () {
379        return this._viewPort;
380    };
381    SelectedRegion.prototype.setStart = function (startPoint) {
382        this._startPoint = startPoint;
383        this._startDate = gantt.dateFromPos(this._startPoint.relative.left);
384        this._viewPort.callEvent("onBeforeDrag", [this._startPoint]);
385    };
386    SelectedRegion.prototype.setEnd = function (endPoint) {
387        this._endPoint = endPoint;
388        if (this._singleRow) {
389            var height = gantt.config.row_height;
390            this._endPoint.relative.top = (Math.ceil(this._startPoint.relative.top / height)) * height;
391        }
392        this._endDate = gantt.dateFromPos(this._endPoint.relative.left);
393        if (this._startPoint.relative.left > this._endPoint.relative.left) {
394            this._positionPoint = {
395                relative: { left: this._endPoint.relative.left, top: this._positionPoint.relative.top },
396                absolute: { left: this._endPoint.absolute.left, top: this._positionPoint.absolute.top }
397            };
398        }
399        if (this._startPoint.relative.top > this._endPoint.relative.top) {
400            this._positionPoint = {
401                relative: { left: this._positionPoint.relative.left, top: this._endPoint.relative.top },
402                absolute: { left: this._positionPoint.absolute.left, top: this._endPoint.absolute.top }
403            };
404        }
405        this._viewPort.callEvent("onDrag", [this._startPoint, this._endPoint]);
406    };
407    SelectedRegion.prototype.setPosition = function (positionPoint) {
408        this._positionPoint = positionPoint;
409    };
410    SelectedRegion.prototype.dragEnd = function (endPoint) {
411        var _a;
412        if (endPoint.relative.left < 0) {
413            endPoint.relative.left = 0;
414        }
415        this._viewPort.callEvent("onBeforeDragEnd", [this._startPoint, endPoint]);
416        this.setEnd(endPoint);
417        if (this._startDate.valueOf() > this._endDate.valueOf()) {
418            _a = [this._endDate, this._startDate], this._startDate = _a[0], this._endDate = _a[1];
419        }
420        this.clear();
421        var tasksByTime = gantt.getTaskByTime(this._startDate, this._endDate);
422        var tasksByIndex = this._getTasksByTop(this._startPoint.relative.top, this._endPoint.relative.top);
423        this._viewPort.callEvent("onDragEnd", [this._startPoint, this._endPoint]);
424        if (this._callback) {
425            this._callback(this._startPoint, this._endPoint, this._startDate, this._endDate, tasksByTime, tasksByIndex);
426        }
427    };
428    SelectedRegion.prototype.getInBounds = function () {
429        return this._singleRow;
430    };
431    SelectedRegion.prototype._getTasksByTop = function (start, end) {
432        var startValue = start;
433        var endValue = end;
434        if (start > end) {
435            startValue = end;
436            endValue = start;
437        }
438        var height = gantt.config.row_height;
439        var startIndex = Math.ceil(startValue / height) - 1;
440        var endIndex = Math.ceil(endValue / height) - 1;
441        var result = [];
442        for (var i = startIndex; i <= endIndex; i++) {
443            var task = gantt.getTaskByIndex(i);
444            if (task) {
445                result.push(gantt.getTaskByIndex(i));
446            }
447        }
448        return result;
449    };
450    return SelectedRegion;
451}());
452exports.SelectedRegion = SelectedRegion;
453
454
455/***/ }),
456
457/***/ "./sources/utils/eventable.js":
458/*!************************************!*\
459  !*** ./sources/utils/eventable.js ***!
460  \************************************/
461/*! no static exports found */
462/***/ (function(module, exports) {
463
464var EventHost = function(){
465	this._connected = [];
466	this._silent_mode = false;
467};
468
469EventHost.prototype = {
470	_silentStart: function() {
471		this._silent_mode = true;
472	},
473	_silentEnd: function() {
474		this._silent_mode = false;
475	}
476};
477
478var	createEventStorage = function(obj) {
479	var dhx_catch = [];
480	var z = function(){
481		var res = true;
482		for (var i = 0; i < dhx_catch.length; i++){
483			if (dhx_catch[i]){
484				var zr = dhx_catch[i].apply(obj, arguments);
485				res=res&&zr;
486			}
487		}
488		return res;
489	};
490	z.addEvent=function(ev){
491		if (typeof (ev) == "function")
492			return dhx_catch.push(ev)-1;
493		return false;
494	};
495	z.removeEvent=function(id){
496		dhx_catch[id]=null;
497	};
498	return z;
499};
500
501function makeEventable(obj){
502
503	var eventHost = new EventHost();
504	obj.attachEvent=function(name, catcher, callObj){
505		name='ev_'+name.toLowerCase();
506		if (!eventHost[name])
507			eventHost[name] = createEventStorage(callObj||this);
508
509		return(name+':'+eventHost[name].addEvent(catcher)); //return ID (event name & event ID)
510	};
511	obj.attachAll = function(callback, callObj){
512		this.attachEvent('listen_all', callback, callObj);
513	};
514
515	obj.callEvent=function(name, arg0, callObj){
516		if (eventHost._silent_mode) return true;
517
518		var handlerName = 'ev_'+name.toLowerCase();
519
520		if (eventHost['ev_listen_all']){
521			eventHost['ev_listen_all'].apply(callObj || this, [name].concat(arg0));
522		}
523
524		if (eventHost[handlerName])
525			return eventHost[handlerName].apply(callObj || this, arg0);
526		return true;
527	};
528	obj.checkEvent=function(name){
529		return (!!eventHost['ev_'+name.toLowerCase()]);
530	};
531	obj.detachEvent=function(id){
532		if (id){
533			var list = id.split(':');//get EventName and ID
534			var eventName = list[0];
535			var eventId = list[1];
536
537			if(eventHost[eventName]){
538				eventHost[eventName].removeEvent(eventId); //remove event
539			}
540		}
541	};
542	obj.detachAllEvents = function(){
543		for (var name in eventHost){
544			if (name.indexOf("ev_") === 0)
545				delete eventHost[name];
546		}
547	};
548
549}
550
551module.exports = makeEventable;
552
553/***/ }),
554
555/***/ "./sources/utils/helpers.js":
556/*!**********************************!*\
557  !*** ./sources/utils/helpers.js ***!
558  \**********************************/
559/*! no static exports found */
560/***/ (function(module, exports) {
561
562var units = {
563	"second": 1,
564	"minute": 60,
565	"hour": 60 * 60,
566	"day": 60 * 60 * 24,
567	"week": 60 * 60 * 24 * 7,
568	"month": 60 * 60 * 24 * 30,
569	"quarter": 60 * 60 * 24 * 30 * 3,
570	"year": 60 * 60 * 24 * 365
571};
572function getSecondsInUnit(unit){
573	return units[unit] || units.hour;
574}
575
576function forEach(arr, callback) {
577	if (arr.forEach) {
578		arr.forEach(callback);
579	} else {
580		var workArray = arr.slice();
581		for (var i = 0; i < workArray.length; i++) {
582			callback(workArray[i], i);
583		}
584	}
585}
586
587function arrayMap(arr, callback) {
588	if (arr.map) {
589		return arr.map(callback);
590	} else {
591		var workArray = arr.slice();
592		var resArray = [];
593
594		for (var i = 0; i < workArray.length; i++) {
595			resArray.push(callback(workArray[i], i));
596		}
597		return resArray;
598	}
599}
600
601
602function arrayFind(arr, callback) {
603	if (arr.find) {
604		return arr.find(callback);
605	} else {
606		for (var i = 0; i < arr.length; i++) {
607			if (callback(arr[i], i)) {
608				return arr[i];
609			}
610		}
611	}
612}
613
614// iframe-safe array type check instead of using instanceof
615function isArray(obj){
616	if(Array.isArray){
617		return Array.isArray(obj);
618	}else{
619		// close enough
620		return (obj && obj.length !== undefined && obj.pop && obj.push);
621	}
622}
623
624// non-primitive string object, e.g. new String("abc")
625function isStringObject(obj){
626	return obj && typeof obj === "object"
627		&& Function.prototype.toString.call(obj.constructor) === "function String() { [native code] }";
628}
629
630// non-primitive number object, e.g. new Number(5)
631function isNumberObject(obj){
632	return obj && typeof obj === "object"
633		&& Function.prototype.toString.call(obj.constructor) === "function Number() { [native code] }";
634}
635
636// non-primitive number object, e.g. new Boolean(true)
637function isBooleanObject(obj){
638	return obj && typeof obj === "object"
639		&& Function.prototype.toString.call(obj.constructor) === "function Boolean() { [native code] }";
640}
641
642function isDate(obj) {
643	if (obj && typeof obj === "object") {
644		return !!(obj.getFullYear && obj.getMonth && obj.getDate);
645	} else {
646		return false;
647	}
648}
649
650function isValidDate(obj){
651	return isDate(obj) && !isNaN(obj.getTime());
652}
653
654function arrayFilter(arr, callback) {
655	var result = [];
656
657	if (arr.filter) {
658		return arr.filter(callback);
659	} else {
660		for (var i = 0; i < arr.length; i++) {
661			if (callback(arr[i], i)) {
662				result[result.length] = arr[i];
663			}
664		}
665		return result;
666	}
667}
668
669function hashToArray(hash) {
670	var result = [];
671
672	for (var key in hash) {
673		if (hash.hasOwnProperty(key)) {
674			result.push(hash[key]);
675		}
676	}
677
678	return result;
679}
680
681function arraySome(arr, callback) {
682	if (arr.length === 0) return false;
683
684	for (var i = 0; i < arr.length; i++) {
685		if (callback(arr[i], i, arr)) {
686			return true;
687		}
688	}
689	return false;
690}
691
692function arrayDifference(arr, callback) {
693	return arrayFilter(arr, function(item, i) {
694		return !callback(item, i);
695	});
696}
697
698function throttle (callback, timeout) {
699	var wait = false;
700
701	return function () {
702		if (!wait) {
703			callback.apply(null, arguments);
704			wait = true;
705			setTimeout(function () {
706				wait = false;
707			}, timeout);
708		}
709	};
710}
711
712function delay (callback, timeout){
713	var timer;
714
715	var result = function() {
716		result.$cancelTimeout();
717		callback.$pending = true;
718		var args = Array.prototype.slice.call(arguments);
719		timer = setTimeout(function(){
720			callback.apply(this, args);
721			result.$pending = false;
722		}, timeout);
723	};
724
725	result.$pending = false;
726	result.$cancelTimeout = function(){
727		clearTimeout(timer);
728		callback.$pending = false;
729	};
730	result.$execute = function(){
731		callback();
732		callback.$cancelTimeout();
733	};
734
735	return result;
736}
737
738function sortArrayOfHash(arr, field, desc) {
739	var compare = function(a, b) {
740		return a < b;
741	};
742
743	arr.sort(function(a, b) {
744		if (a[field] === b[field]) return 0;
745
746		return desc ? compare(a[field], b[field]) : compare(b[field], a[field]);
747	});
748}
749
750function objectKeys(obj) {
751	if (Object.keys) {
752		return Object.keys(obj);
753	}
754	var result = [];
755	var key;
756	for (key in obj) {
757		if (Object.prototype.hasOwnProperty.call(obj, key)) {
758			result.push(key);
759		}
760	}
761	return result;
762}
763
764function requestAnimationFrame(callback) {
765	var w = window;
766	var foundRequestAnimationFrame = w.requestAnimationFrame
767		|| w.webkitRequestAnimationFrame
768		|| w.msRequestAnimationFrame
769		|| w.mozRequestAnimationFrame
770		|| w.oRequestAnimationFrame
771		|| function(cb) { setTimeout(cb, 1000/60); };
772	return foundRequestAnimationFrame(callback);
773}
774
775function isEventable(obj) {
776	return obj.attachEvent && obj.detachEvent;
777}
778
779module.exports = {
780	getSecondsInUnit: getSecondsInUnit,
781	forEach: forEach,
782	arrayMap: arrayMap,
783	arrayFind: arrayFind,
784	arrayFilter: arrayFilter,
785	arrayDifference: arrayDifference,
786	arraySome: arraySome,
787	hashToArray: hashToArray,
788	sortArrayOfHash: sortArrayOfHash,
789	throttle: throttle,
790	isArray: isArray,
791	isDate: isDate,
792	isValidDate: isValidDate,
793	isStringObject: isStringObject,
794	isNumberObject: isNumberObject,
795	isBooleanObject: isBooleanObject,
796	delay: delay,
797	objectKeys: objectKeys,
798	requestAnimationFrame: requestAnimationFrame,
799	isEventable: isEventable
800};
801
802/***/ })
803
804/******/ });
805});