Browse Source

mocha TypeScript unittests are configured.

Ievgen Naida 5 years ago
parent
commit
0d0037c9a5

+ 15 - 6
.babelrc

@@ -1,7 +1,16 @@
 {
-  "presets": ["@babel/env", "@babel/typescript"],
-  "plugins": [
-    "@babel/proposal-class-properties",
-    "@babel/proposal-object-rest-spread"
-  ]
-}
+  "presets": [
+    [
+      "@babel/env",
+      {
+        "targets": {
+          "browsers": [">0.25%"]
+        },
+        "useBuiltIns": "entry",
+        "corejs": { "version": 3, "proposals": true }
+      }
+    ],
+    "@babel/typescript"
+  ],
+  "plugins": ["@babel/proposal-class-properties", "@babel/proposal-object-rest-spread"]
+}

+ 9 - 1
.eslintignore

@@ -1 +1,9 @@
-*.js
+lib/*.js
+tests/js/*.js
+tests/js/src
+tests/src
+./tests/js/*.js
+./tests/js/src
+./tests/src
+./tests/tests/
+tests/tests/

+ 3 - 1
.gitignore

@@ -1,2 +1,4 @@
 /node_modules/*
-.bak
+.bak
+tests/js/src
+tests/src

+ 24 - 13
README.md

@@ -58,19 +58,6 @@ import {
 timeline.initialize({ id: 'timeline' });
 ```
 
-### Build 
-
-run once to install development references:
-```bash
-  npm install
-```
-
-to pack JavaScript as a bundle:
-
-```bash
-  npm run build
-```
-
 ### Draw the outline tree
 
 Scroll events can be synchronized with the outline at the left side of the control.
@@ -110,6 +97,30 @@ Default options:
 
 Vanilla js implementation. 
 
+## Development 
+### Build 
+
+run once to install development references:
+```bash
+  npm install
+```
+
+to pack JavaScript as a bundle:
+
+```bash
+  npm run build
+```
+
+### Build tests:
+
+To build TypeScript unittests command should be executed: 
+```bash
+  npm run build-tests
+```
+
+Tests execution can be started by opening tests/unittests.html. 
+External mocha libs are used so internet is required.
+
 ## License
 
 MIT

+ 105 - 81
lib/animation-timeline.js

@@ -743,7 +743,7 @@ var TimelineClickEvent = /*#__PURE__*/function () {
 
     timelineClickEvent_defineProperty(this, "args", void 0);
 
-    timelineClickEvent_defineProperty(this, "pos", new DOMPoint());
+    timelineClickEvent_defineProperty(this, "pos", void 0);
 
     timelineClickEvent_defineProperty(this, "val", void 0);
 
@@ -893,18 +893,19 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
    */
 
   /**
-   * Initialize Timeline
+   * Create Timeline instance
    * @param options Timeline settings.
    * @param model Timeline model.
    */
-  function Timeline(options) {
+  function Timeline() {
     var _thisSuper, _thisSuper2, _thisSuper3, _this;
 
+    var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
     var model = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
 
     timeline_classCallCheck(this, Timeline);
 
-    _this = _super.call(this);
+    _this = _super.call(this); // Allow to create instance without an error to perform tests.
 
     timeline_defineProperty(timeline_assertThisInitialized(_this), "_container", null);
 
@@ -1164,7 +1165,7 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
         return;
       }
 
-      var isTouch = args instanceof TouchEvent && args.changedTouches && args.changedTouches.length > 0;
+      var isTouch = args.changedTouches && args.changedTouches.length > 0;
       _this._currentPos = _this._trackMousePos(_this._canvas, args);
 
       if (!_this._isPanStarted && _this._selectionRect && _this._clickTimeoutIsOver()) {
@@ -1318,76 +1319,88 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
       _this._renderTimeline();
     });
 
-    _this._model = model;
-
-    if (!options || !options.id) {
-      throw new Error("Element cannot be empty. Should be string or DOM element.");
+    if (options || model) {
+      _this.initialize(options, model);
     }
 
-    var id = options.id;
-    _this._options = _this._mergeOptions(options);
-    _this._currentZoom = _this._options.zoom;
+    return _this;
+  }
+  /**
+   * Initialize Timeline
+   * @param options Timeline settings.
+   * @param model Timeline model.
+   */
 
-    if (id instanceof HTMLElement) {
-      _this._container = id;
-    } else {
-      _this._container = document.getElementById(id);
-    }
 
-    if (!_this._container) {
-      throw new Error("Element cannot be empty. Should be string or DOM element.");
-    }
+  timeline_createClass(Timeline, [{
+    key: "initialize",
+    value: function initialize(options, model) {
+      this._model = model;
 
-    _this._scrollContainer = document.createElement('div');
-    _this._scrollContent = document.createElement('div');
-    _this._canvas = document.createElement('canvas');
+      if (!options || !options.id) {
+        throw new Error("Element cannot be empty. Should be string or DOM element.");
+      }
 
-    if (!_this._canvas || !_this._canvas.getContext) {
-      console.log('Cannot initialize canvas context.');
-      return timeline_possibleConstructorReturn(_this, null);
-    }
+      var id = options.id;
+      this._options = this._mergeOptions(options);
+      this._currentZoom = this._options.zoom;
 
-    _this._container.style.position = 'relative'; // Generate size container:
+      if (id instanceof HTMLElement) {
+        this._container = id;
+      } else {
+        this._container = document.getElementById(id);
+      }
 
-    _this._canvas.style.cssText = 'image-rendering: -moz-crisp-edges;' + 'image-rendering: -webkit-crisp-edges;' + 'image-rendering: pixelated;' + 'image-rendering: crisp-edges;' + 'user-select: none;' + '-webkit-user-select: none;' + '-khtml-user-select: none;' + '-moz-user-select: none;' + '-o-user-select: none;' + 'user-select: none;' + 'touch-action: none;' + 'position: relative;' + '-webkit-user-drag: none;' + '-khtml-user-drag: none;' + '-moz-user-drag: none;' + '-o-user-drag: none;' + 'user-drag: none;' + 'padding: inherit';
+      if (!this._container) {
+        throw new Error("Element cannot be empty. Should be string or DOM element.");
+      }
 
-    _this._scrollContainer.classList.add(_this._options.scrollContainerClass);
+      this._scrollContainer = document.createElement('div');
+      this._scrollContent = document.createElement('div');
+      this._canvas = document.createElement('canvas');
 
-    _this._scrollContainer.style.cssText = 'overflow: scroll;' + 'position: absolute;' + 'width:  100%;' + 'height:  100%;';
-    _this._scrollContent.style.width = _this._scrollContent.style.height = '100%'; // add the text node to the created div
+      if (!this._canvas || !this._canvas.getContext) {
+        console.log('Cannot initialize canvas context.');
+        return null;
+      }
 
-    _this._scrollContainer.appendChild(_this._scrollContent);
+      this._container.style.position = 'relative'; // Generate size container:
 
-    _this._container.appendChild(_this._scrollContainer);
+      this._canvas.style.cssText = 'image-rendering: -moz-crisp-edges;' + 'image-rendering: -webkit-crisp-edges;' + 'image-rendering: pixelated;' + 'image-rendering: crisp-edges;' + 'user-select: none;' + '-webkit-user-select: none;' + '-khtml-user-select: none;' + '-moz-user-select: none;' + '-o-user-select: none;' + 'user-select: none;' + 'touch-action: none;' + 'position: relative;' + '-webkit-user-drag: none;' + '-khtml-user-drag: none;' + '-moz-user-drag: none;' + '-o-user-drag: none;' + 'user-drag: none;' + 'padding: inherit';
 
-    var scrollBarWidth = _this._scrollContainer.offsetWidth - _this._scrollContent.clientWidth; // Calculate current browser scroll bar size and add offset for the canvas
+      this._scrollContainer.classList.add(this._options.scrollContainerClass);
 
-    _this._canvas.style.width = _this._canvas.style.height = 'calc(100% -' + (scrollBarWidth || 17) + 'px)';
+      this._scrollContainer.style.cssText = 'overflow: scroll;' + 'position: absolute;' + 'width:  100%;' + 'height:  100%;';
+      this._scrollContent.style.width = this._scrollContent.style.height = '100%'; // add the text node to the created div
 
-    _this._container.appendChild(_this._canvas);
+      this._scrollContainer.appendChild(this._scrollContent);
 
-    if (_this._options.fillColor) {
-      _this._scrollContainer.style.background = _this._options.fillColor;
-    } // Normalize and validate span per seconds
+      this._container.appendChild(this._scrollContainer);
 
+      var scrollBarWidth = this._scrollContainer.offsetWidth - this._scrollContent.clientWidth; // Calculate current browser scroll bar size and add offset for the canvas
 
-    _this._options.snapsPerSeconds = Math.max(0, Math.min(60, _this._options.snapsPerSeconds || 0));
-    _this._ctx = _this._canvas.getContext('2d');
+      this._canvas.style.width = this._canvas.style.height = 'calc(100% -' + (scrollBarWidth || 17) + 'px)';
 
-    _this._subscribeOnEvents();
+      this._container.appendChild(this._canvas);
 
-    _this.rescale();
+      if (this._options.fillColor) {
+        this._scrollContainer.style.background = this._options.fillColor;
+      } // Normalize and validate span per seconds
 
-    _this.redraw();
 
-    return _this;
-  }
-  /**
-   * Subscribe current component on the related events.
-   */
+      this._options.snapsPerSeconds = Math.max(0, Math.min(60, this._options.snapsPerSeconds || 0));
+      this._ctx = this._canvas.getContext('2d');
 
+      this._subscribeOnEvents();
 
-  timeline_createClass(Timeline, [{
+      this.rescale();
+      this.redraw();
+    }
+    /**
+     * Subscribe current component on the related events.
+     */
+
+  }, {
     key: "_subscribeOnEvents",
     value: function _subscribeOnEvents() {
       this._container.addEventListener('wheel', this._handleWheelEvent);
@@ -1558,7 +1571,7 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
           selected.push(_this2._convertToElement(rowModel.row, keyframe));
         }
 
-        return false;
+        return;
       });
 
       return selected;
@@ -1614,7 +1627,7 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
           }
         }
 
-        return false;
+        return;
       });
 
       if (isChanged) {
@@ -1656,13 +1669,9 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
         var nextRow = true;
         row.keyframes.filter(function (p) {
           return p && !p.hidden;
-        }).find(function (keyframe, keyframeIndex) {
+        }).forEach(function (keyframe, keyframeIndex) {
           if (callback && keyframe) {
-            var isBreak = callback(keyframe, keyframeIndex, rowSize, index, nextRow);
-
-            if (isBreak) {
-              return true;
-            }
+            callback(keyframe, keyframeIndex, rowSize, index, nextRow);
           }
 
           nextRow = false;
@@ -2320,7 +2329,7 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
       } // get center of the lane:
 
 
-      var y = rowSize.y + rowSize.height / 2 - this._scrollContainer.scrollTop; // TODO: keyframe size:
+      var y = rowSize.y + rowSize.height / 2; // TODO: keyframe size:
 
       var size = 1; //this._options.keyframeSizePx || keyframe.size;
       //if (size == "auto") {
@@ -2450,7 +2459,7 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
           _this7._ctx.restore();
         }
 
-        return false;
+        return;
       });
     }
   }, {
@@ -2598,9 +2607,13 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
       var model = this._calculateRowsBounds();
 
       if (model && model.rows) {
-        return model.rows.find(function (rowData) {
-          return rowData.y >= posY && posY <= rowData.y + rowData.height;
-        });
+        for (var i = 0; i < model.rows.length; i++) {
+          var _row = model.rows[i];
+
+          if (_row && _row.y >= posY && posY <= _row.y + _row.height) {
+            return _row;
+          }
+        }
       }
 
       return null;
@@ -2727,7 +2740,8 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
       this._model = data;
       this.rescale();
       this.redraw();
-    }
+    } // eslint-disable-next-line @typescript-eslint/no-explicit-any
+
   }, {
     key: "_getMousePos",
     value: function _getMousePos(canvas, e) {
@@ -2735,16 +2749,12 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
       var clientX = 0;
       var clientY = 0;
 
-      if (e instanceof TouchEvent) {
-        var wheelEvent = e;
-
-        if (wheelEvent.changedTouches && wheelEvent.changedTouches.length > 0) {
-          // TODO: implement better touch support
-          var touch = e.changedTouches[0];
-          clientX = touch.clientX;
-          clientY = touch.clientY;
-          radius = Math.max(radius, touch.radiusX, touch.radiusY);
-        }
+      if (e.changedTouches && e.changedTouches.length > 0) {
+        // TODO: implement better touch support
+        var touch = e.changedTouches[0];
+        clientX = touch.clientX;
+        clientY = touch.clientY;
+        radius = Math.max(radius, touch.radiusX, touch.radiusY);
       } else {
         clientX = e.clientX;
         clientY = e.clientY;
@@ -2854,9 +2864,11 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
 
   }, {
     key: "_findDraggable",
-    value: function _findDraggable(elements, val) {
+    value: function _findDraggable(elements) {
       var _this8 = this;
 
+      var val = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
+
       // filter and sort: Timeline, individual keyframes, stripes (distance).
       var getPriority = function getPriority(type) {
         if (type === TimelineElementType.Timeline) {
@@ -2872,13 +2884,21 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
 
       var filteredElements = elements.filter(function (element) {
         if (element.type === TimelineElementType.Keyframe) {
-          var draggable = (_this8._options.keyframesDraggable === undefined ? true : !!_this8._options.keyframesDraggable) && (element.keyframe.draggable === undefined ? true : !!element.keyframe.draggable);
+          var draggable = true;
+
+          if (_this8._options) {
+            draggable = (_this8._options.keyframesDraggable === undefined ? true : !!_this8._options.keyframesDraggable) && (element.keyframe.draggable === undefined ? true : !!element.keyframe.draggable);
+          }
 
           if (!draggable) {
             return false;
           }
         } else if (element.type === TimelineElementType.Stripe) {
-          var _draggable = (_this8._options.stripesDraggable === undefined ? true : !!_this8._options.stripesDraggable) && (element.row.stripeDraggable === undefined ? true : !!element.row.stripeDraggable);
+          var _draggable = true;
+
+          if (_this8._options) {
+            _draggable = (_this8._options.stripesDraggable === undefined ? true : !!_this8._options.stripesDraggable) && (element.row.stripeDraggable === undefined ? true : !!element.row.stripeDraggable);
+          }
 
           if (!_draggable) {
             return false;
@@ -2894,6 +2914,10 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
         var prioB = getPriority(b.type);
 
         if (prioA == prioB) {
+          if (val === null) {
+            return 0;
+          }
+
           return TimelineUtils.getDistance(a.val, val) > TimelineUtils.getDistance(b.val, val) ? 1 : 0;
         }
 
@@ -2941,12 +2965,12 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
             var rowOverlapped = TimelineUtils.isOverlap(pos.x, pos.y, rowModel);
 
             if (rowOverlapped) {
-              var _row = {
+              var _row2 = {
                 val: _this9._mousePosToVal(pos.x, true),
                 type: TimelineElementType.Row,
                 row: rowModel.row
               };
-              toReturn.push(_row);
+              toReturn.push(_row2);
             }
 
             var keyframesStripeOverlapped = TimelineUtils.isOverlap(pos.x, pos.y, rowModel.stripeRect);
@@ -2981,7 +3005,7 @@ var timeline_Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
             }
           }
 
-          return false;
+          return;
         }, true);
       }
 

File diff suppressed because it is too large
+ 0 - 0
lib/animation-timeline.min.js


+ 7 - 1
package-lock.json

@@ -1,6 +1,6 @@
 {
   "name": "animation-timeline-js",
-  "version": "1.2.4",
+  "version": "2.0.5",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
@@ -1038,6 +1038,12 @@
       "integrity": "sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA==",
       "dev": true
     },
+    "@types/mocha": {
+      "version": "7.0.2",
+      "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-7.0.2.tgz",
+      "integrity": "sha512-ZvO2tAcjmMi8V/5Z3JsyofMe3hasRcaw88cto5etSVMwVQfeivGAlEYmaQgceUSVYFofVjT+ioHsATjdWcFt1w==",
+      "dev": true
+    },
     "@typescript-eslint/eslint-plugin": {
       "version": "2.31.0",
       "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.31.0.tgz",

+ 5 - 3
package.json

@@ -1,6 +1,6 @@
 {
   "name": "animation-timeline-js",
-  "version": "2.0.4",
+  "version": "2.0.5",
   "description": "animation timeline control based on the canvas.",
   "main": "lib/animation-timeline.min.js",
   "types": "src/index.ts",
@@ -11,6 +11,7 @@
     "@babel/plugin-proposal-class-properties": "^7.8.3",
     "@babel/preset-env": "^7.8.3",
     "@babel/preset-typescript": "^7.8.3",
+    "@types/mocha": "^7.0.2",
     "@typescript-eslint/eslint-plugin": "^2.31.0",
     "@typescript-eslint/parser": "^2.31.0",
     "babel-loader": "^8.1.0",
@@ -25,9 +26,10 @@
     "webpack-cli": "^3.3.11"
   },
   "scripts": {
-    "test": "echo \"Error: no test specified\" && exit 1",
+    "test": "echo \"Run tests/unittest.html explicitly to execute tests\" && exit 1",
     "build": "webpack",
-    "webpack": "webpack"
+    "webpack": "webpack",
+    "build-tests": "tsc -p tsconfig.tests.json"
   },
   "repository": {
     "type": "git",

+ 1 - 1
src/utils/rowsCalculationsResults.ts

@@ -1,4 +1,4 @@
-import { TimelineRow } from '..';
+import { TimelineRow } from '../timelineRow';
 
 export interface RowsCalculationsResults {
   /**

+ 1 - 1
src/utils/timelineDraggableData.ts

@@ -1,5 +1,5 @@
 import { TimelineClickableElement } from './timelineClickableElement';
-import { TimelineElementType } from '..';
+import { TimelineElementType } from '../enums/timelineElementType';
 
 export interface TimelineDraggableData {
   changed: boolean;

+ 27 - 0
tests/tests/timelineTests.js

@@ -0,0 +1,27 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var animation_timeline_js_1 = require("../lib/animation-timeline.js");
+describe('Timeline ', function () {
+    it('closest keyframe should be returned', function () {
+        var timeline = new animation_timeline_js_1.Timeline();
+        var elements = [
+            {
+                type: animation_timeline_js_1.TimelineElementType.Keyframe,
+                val: 0,
+            },
+            {
+                type: animation_timeline_js_1.TimelineElementType.Keyframe,
+                val: 4,
+            },
+            {
+                type: animation_timeline_js_1.TimelineElementType.Keyframe,
+                val: 9,
+            },
+        ];
+        var element = timeline._findDraggable(elements, 5);
+        if (element.val !== elements[2].val) {
+            throw new Error('Wrong keyframe selected');
+        }
+    });
+});
+//# sourceMappingURL=timelineTests.js.map

+ 1 - 0
tests/tests/timelineTests.js.map

@@ -0,0 +1 @@
+{"version":3,"file":"timelineTests.js","sourceRoot":"","sources":["../timelineTests.ts"],"names":[],"mappings":";;AAAA,sEAAuG;AAEvG,QAAQ,CAAC,WAAW,EAAE;IACpB,EAAE,CAAC,qCAAqC,EAAE;QACxC,IAAM,QAAQ,GAAG,IAAI,gCAAQ,EAAE,CAAC;QAChC,IAAM,QAAQ,GAAG;YACf;gBACE,IAAI,EAAE,2CAAmB,CAAC,QAAQ;gBAClC,GAAG,EAAE,CAAC;aACqB;YAC7B;gBACE,IAAI,EAAE,2CAAmB,CAAC,QAAQ;gBAClC,GAAG,EAAE,CAAC;aACqB;YAC7B;gBACE,IAAI,EAAE,2CAAmB,CAAC,QAAQ;gBAClC,GAAG,EAAE,CAAC;aACqB;SAC9B,CAAC;QACF,IAAM,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QACrD,IAAI,OAAO,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE;YACnC,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;SAC5C;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}

+ 27 - 0
tests/timelineTests.js

@@ -0,0 +1,27 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+var animation_timeline_js_1 = require("../lib/animation-timeline.js");
+describe('Timeline ', function () {
+    it('closest keyframe should be returned', function () {
+        var timeline = new animation_timeline_js_1.Timeline();
+        var elements = [
+            {
+                type: animation_timeline_js_1.TimelineElementType.Keyframe,
+                val: 0,
+            },
+            {
+                type: animation_timeline_js_1.TimelineElementType.Keyframe,
+                val: 4,
+            },
+            {
+                type: animation_timeline_js_1.TimelineElementType.Keyframe,
+                val: 9,
+            },
+        ];
+        var element = timeline._findDraggable(elements, 5);
+        if (element.val !== elements[2].val) {
+            throw new Error('Wrong keyframe selected');
+        }
+    });
+});
+//# sourceMappingURL=timelineTests.js.map

+ 1 - 0
tests/timelineTests.js.map

@@ -0,0 +1 @@
+{"version":3,"file":"timelineTests.js","sourceRoot":"","sources":["timelineTests.ts"],"names":[],"mappings":";;AAAA,sEAAuG;AAEvG,QAAQ,CAAC,WAAW,EAAE;IACpB,EAAE,CAAC,qCAAqC,EAAE;QACxC,IAAM,QAAQ,GAAG,IAAI,gCAAQ,EAAE,CAAC;QAChC,IAAM,QAAQ,GAAG;YACf;gBACE,IAAI,EAAE,2CAAmB,CAAC,QAAQ;gBAClC,GAAG,EAAE,CAAC;aACqB;YAC7B;gBACE,IAAI,EAAE,2CAAmB,CAAC,QAAQ;gBAClC,GAAG,EAAE,CAAC;aACqB;YAC7B;gBACE,IAAI,EAAE,2CAAmB,CAAC,QAAQ;gBAClC,GAAG,EAAE,CAAC;aACqB;SAC9B,CAAC;QACF,IAAM,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QACrD,IAAI,OAAO,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE;YACnC,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;SAC5C;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}

+ 25 - 0
tests/timelineTests.ts

@@ -0,0 +1,25 @@
+import { Timeline, TimelineElementType, TimelineClickableElement } from '../lib/animation-timeline.js';
+
+describe('Timeline ', function () {
+  it('closest keyframe should be returned', function () {
+    const timeline = new Timeline();
+    const elements = [
+      {
+        type: TimelineElementType.Keyframe,
+        val: 0,
+      } as TimelineClickableElement,
+      {
+        type: TimelineElementType.Keyframe,
+        val: 4,
+      } as TimelineClickableElement,
+      {
+        type: TimelineElementType.Keyframe,
+        val: 9,
+      } as TimelineClickableElement,
+    ];
+    const element = timeline._findDraggable(elements, 5);
+    if (element.val !== elements[2].val) {
+      throw new Error('Wrong keyframe selected');
+    }
+  });
+});

+ 31 - 0
tests/unittests.html

@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+    <meta charset="utf-8" />
+    <title>Mocha Tests</title>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <link rel="stylesheet" href="https://unpkg.com/mocha/mocha.css" />
+</head>
+
+<body>
+    <div id="mocha"></div>
+
+    <script src="https://unpkg.com/chai/chai.js"></script>
+    <script src="https://unpkg.com/mocha/mocha.js"></script>
+    <script src="../lib/animation-timeline.js"></script>
+    <script>var exports = {}; var require = function () {
+            return timelineModule;
+        };
+    </script>
+    <script class="mocha-init">
+        mocha.setup('bdd');
+        mocha.checkLeaks();
+    </script>
+    <script src="./tests/timelineTests.js"></script>
+    <script class="mocha-exec">
+        mocha.run();
+    </script>
+</body>
+
+</html>

+ 1 - 1
tsconfig.json

@@ -10,5 +10,5 @@
     "strict": false,
     "declaration": true
   },
-  "exclude": ["node_modules", "dist"]
+  "exclude": ["node_modules", "lib", "dist", "tests", "*.json"]
 }

+ 16 - 0
tsconfig.tests.json

@@ -0,0 +1,16 @@
+{
+  "compilerOptions": {
+    "module": "CommonJS",
+    "outDir": "./tests",
+    "lib": ["es2015", "dom"],
+    "target": "es5",
+    "allowJs": false,
+    "sourceMap": true,
+    "strict": false,
+    "declaration": false
+  },
+  "include": [
+    "./tests/*"
+],
+  "exclude": ["node_modules", "lib", "tests/js", "src", "src/*", "dist", "*.json", "*.js"]
+}

+ 5 - 3
webpack.config.js

@@ -1,10 +1,12 @@
 /* eslint-disable @typescript-eslint/no-var-requires */
 const path = require('path');
-let UnminifiedWebpackPlugin = require('unminified-webpack-plugin');
+const UnminifiedWebpackPlugin = require('unminified-webpack-plugin');
 
 //  devtool: 'inline-source-map',
 module.exports = {
-  entry: './src/index.ts',
+  entry: {
+    'animation-timeline': './lib/animation-timeline.ts',
+  },
   module: {
     rules: [
       {
@@ -18,7 +20,7 @@ module.exports = {
     extensions: ['.tsx', '.ts'],
   },
   output: {
-    filename: 'animation-timeline.min.js',
+    filename: '[name].min.js',
     libraryTarget: 'umd',
     library: 'timelineModule',
     // eslint-disable-next-line no-undef

Some files were not shown because too many files changed in this diff