diff --git a/karma.conf.js b/karma.conf.js index 3a917a709..73149f50f 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -1,4 +1,7 @@ -module.exports = function (config) { +var webpackConfig = require('./webpack.config'); + + +module.exports = function(config) { config.set({ basePath: '', frameworks: ['jasmine'], @@ -26,6 +29,7 @@ module.exports = function (config) { // Application resources 'static/js/**/*.js', + 'static/js/**/*.ts', // Tests 'static/test/**/*.js', @@ -36,8 +40,11 @@ module.exports = function (config) { preprocessors: { 'static/lib/ngReact/react.ngReact.min.js': ['webpack'], 'static/lib/angular-moment.min.js': ['webpack'], + 'static/js/**/*.ts': ['webpack'], + }, + webpack: { + module: webpackConfig.module, }, - webpack: {}, webpackMiddleware: { stats: 'errors-only' }, diff --git a/package.json b/package.json index 36de3d949..4d87b1c97 100644 --- a/package.json +++ b/package.json @@ -14,9 +14,6 @@ }, "homepage": "https://github.com/coreos-inc/quay#readme", "dependencies": { - "@types/angular": "1.5.16", - "@types/react": "0.14.39", - "@types/react-dom": "0.14.17", "angular": "1.5.3", "angular-animate": "^1.5.3", "angular-cookies": "^1.5.3", @@ -36,7 +33,13 @@ "underscore": "^1.5.2" }, "devDependencies": { + "@types/angular": "1.5.16", + "@types/angular-mocks": "^1.5.8", + "@types/jasmine": "^2.5.41", + "@types/react": "0.14.39", + "@types/react-dom": "0.14.17", "angular-mocks": "^1.5.3", + "css-loader": "0.25.0", "jasmine-core": "^2.5.2", "karma": "^0.13.22", "karma-chrome-launcher": "^2.0.0", @@ -45,12 +48,11 @@ "karma-jasmine": "^0.3.8", "karma-phantomjs-launcher": "^1.0.0", "karma-webpack": "^1.8.1", - "css-loader": "0.25.0", "node-sass": "3.10.1", + "phantomjs-prebuilt": "^2.1.7", "sass-loader": "4.0.2", "source-map-loader": "0.1.5", "style-loader": "0.13.1", - "phantomjs-prebuilt": "^2.1.7", "ts-loader": "0.9.5", "typescript": "2.0.3", "typings": "1.4.0", diff --git a/static/js/services/angular-view-array/angular-view-array.js b/static/js/services/angular-view-array/angular-view-array.js deleted file mode 100644 index d23ae3949..000000000 --- a/static/js/services/angular-view-array/angular-view-array.js +++ /dev/null @@ -1,104 +0,0 @@ -(function() { - 'use strict'; - - /** - * Specialized wrapper around array which provides a toggle() method for viewing the contents of the - * array in a manner that is asynchronously filled in over a short time period. This prevents long - * pauses in the UI for ngRepeat's when the array is significant in size. - */ - angular - .module('quay') - .factory('AngularViewArray', factory); - - factory.$inject = [ - '$interval' - ]; - - function factory($interval) { - var ADDTIONAL_COUNT = 20; - - function _ViewArray() { - this.isVisible = false; - this.visibleEntries = null; - this.hasEntries = false; - this.entries = []; - this.hasHiddenEntries = false; - - this.timerRef_ = null; - this.currentIndex_ = 0; - } - - _ViewArray.prototype.length = function() { - return this.entries.length; - }; - - _ViewArray.prototype.get = function(index) { - return this.entries[index]; - }; - - _ViewArray.prototype.push = function(elem) { - this.entries.push(elem); - this.hasEntries = true; - - if (this.isVisible) { - this.startTimer_(); - } - }; - - _ViewArray.prototype.toggle = function() { - this.setVisible(!this.isVisible); - }; - - _ViewArray.prototype.setVisible = function(newState) { - this.isVisible = newState; - - this.visibleEntries = []; - this.currentIndex_ = 0; - - if (newState) { - this.showAdditionalEntries_(); - this.startTimer_(); - } else { - this.stopTimer_(); - } - }; - - _ViewArray.prototype.showAdditionalEntries_ = function() { - var i = 0; - for (i = this.currentIndex_; i < (this.currentIndex_ + ADDTIONAL_COUNT) && i < this.entries.length; ++i) { - this.visibleEntries.push(this.entries[i]); - } - - this.currentIndex_ = i; - this.hasHiddenEntries = this.currentIndex_ < this.entries.length; - if (this.currentIndex_ >= this.entries.length) { - this.stopTimer_(); - } - }; - - _ViewArray.prototype.startTimer_ = function() { - if (this.timerRef_) { return; } - - var that = this; - this.timerRef_ = $interval(function() { - that.showAdditionalEntries_(); - }, 10); - }; - - _ViewArray.prototype.stopTimer_ = function() { - if (this.timerRef_) { - $interval.cancel(this.timerRef_); - this.timerRef_ = null; - } - }; - - var service = { - 'create': function() { - return new _ViewArray(); - } - }; - - return service; - } - -})(); \ No newline at end of file diff --git a/static/js/services/angular-view-array/angular-view-array.spec.js b/static/js/services/angular-view-array/angular-view-array.spec.ts similarity index 55% rename from static/js/services/angular-view-array/angular-view-array.spec.js rename to static/js/services/angular-view-array/angular-view-array.spec.ts index 314a3b5a1..ce30f9268 100644 --- a/static/js/services/angular-view-array/angular-view-array.spec.js +++ b/static/js/services/angular-view-array/angular-view-array.spec.ts @@ -1,44 +1,47 @@ -describe("Service: AngularViewArray", function() { - var angularViewArray; +import IInjectorService = angular.auto.IInjectorService; - beforeEach(module('quay')); - beforeEach(inject(function($injector) { +describe("Service: AngularViewArray", () => { + var angularViewArray: any; + + beforeEach(angular.mock.module('quay')); + + beforeEach(inject(($injector: IInjectorService) => { angularViewArray = $injector.get('AngularViewArray'); })); - describe("create", function() { + describe("create", () => { - it("returns a ViewArray object", function() { - var viewArray = angularViewArray.create(); + it("returns a ViewArray object", () => { + var viewArray: any = angularViewArray.create(); expect(viewArray).toBeDefined(); }); - describe("returned ViewArray object", function() { - var viewArray; + describe("returned ViewArray object", () => { + var viewArray: any; - beforeEach(function() { + beforeEach(() => { viewArray = angularViewArray.create(); }); - describe("constructor", function() { + describe("constructor", () => { // TODO }); - describe("length", function() { + describe("length", () => { - it("returns the number of entries", function() { + it("returns the number of entries", () => { viewArray.entries = [{}, {}, {}]; expect(viewArray.length()).toEqual(viewArray.entries.length); }); }); - describe("get", function() { + describe("get", () => { - it("returns the entry at a given index", function() { - var index = 8; + it("returns the entry at a given index", () => { + var index: number = 8; viewArray.entries = new Array(10); viewArray.entries[index] = 3; @@ -46,33 +49,33 @@ describe("Service: AngularViewArray", function() { }); }); - describe("push", function() { + describe("push", () => { - it("adds given element to the end of entries", function() { - var element = 3; - var originalLength = viewArray.length(); + it("adds given element to the end of entries", () => { + var element: number = 3; + var originalLength: number = viewArray.length(); viewArray.push(element); expect(viewArray.entries.length).toEqual(originalLength + 1); expect(viewArray.get(originalLength)).toEqual(element); }); - it("sets 'hasEntries' to true", function() { + it("sets 'hasEntries' to true", () => { viewArray.push(2); expect(viewArray.hasEntries).toBe(true); }); - it("starts timer if 'isVisible' is true", function() { - spyOn(viewArray, "startTimer_").and.returnValue(); + it("starts timer if 'isVisible' is true", () => { + spyOn(viewArray, "startTimer_").and.returnValue(null); viewArray.isVisible = true; viewArray.push(2); expect(viewArray.startTimer_).toHaveBeenCalled(); }); - it("does not start timer if 'isVisible' is false", function() { - spyOn(viewArray, "startTimer_").and.returnValue(); + it("does not start timer if 'isVisible' is false", () => { + spyOn(viewArray, "startTimer_").and.returnValue(null); viewArray.isVisible = false; viewArray.push(2); @@ -80,16 +83,16 @@ describe("Service: AngularViewArray", function() { }); }); - describe("toggle", function() { + describe("toggle", () => { - it("sets 'isVisible' to false if currently true", function() { + it("sets 'isVisible' to false if currently true", () => { viewArray.isVisible = true; viewArray.toggle(); expect(viewArray.isVisible).toBe(false); }); - it("sets 'isVisible' to true if currently false", function() { + it("sets 'isVisible' to true if currently false", () => { viewArray.isVisible = false; viewArray.toggle(); @@ -97,43 +100,43 @@ describe("Service: AngularViewArray", function() { }); }); - describe("setVisible", function() { + describe("setVisible", () => { - it("sets 'isVisible' to false if given false", function() { + it("sets 'isVisible' to false if given false", () => { viewArray.setVisible(false); expect(viewArray.isVisible).toBe(false); }); - it("sets 'visibleEntries' to empty array if given false", function() { + it("sets 'visibleEntries' to empty array if given false", () => { viewArray.setVisible(false); expect(viewArray.visibleEntries.length).toEqual(0); }); - it("shows additional entries if given true", function() { - spyOn(viewArray, "showAdditionalEntries_").and.returnValue(); + it("shows additional entries if given true", () => { + spyOn(viewArray, "showAdditionalEntries_").and.returnValue(null); viewArray.setVisible(true); expect(viewArray.showAdditionalEntries_).toHaveBeenCalled(); }); - it("does not show additional entries if given false", function() { - spyOn(viewArray, "showAdditionalEntries_").and.returnValue(); + it("does not show additional entries if given false", () => { + spyOn(viewArray, "showAdditionalEntries_").and.returnValue(null); viewArray.setVisible(false); expect(viewArray.showAdditionalEntries_).not.toHaveBeenCalled(); }); - it("starts timer if given true", function() { - spyOn(viewArray, "startTimer_").and.returnValue(); + it("starts timer if given true", () => { + spyOn(viewArray, "startTimer_").and.returnValue(null); viewArray.setVisible(true); expect(viewArray.startTimer_).toHaveBeenCalled(); }); - it("stops timer if given false", function() { - spyOn(viewArray, "stopTimer_").and.returnValue(); + it("stops timer if given false", () => { + spyOn(viewArray, "stopTimer_").and.returnValue(null); viewArray.setVisible(true); expect(viewArray.stopTimer_).toHaveBeenCalled(); diff --git a/static/js/services/angular-view-array/angular-view-array.ts b/static/js/services/angular-view-array/angular-view-array.ts new file mode 100644 index 000000000..1a8fe7a73 --- /dev/null +++ b/static/js/services/angular-view-array/angular-view-array.ts @@ -0,0 +1,108 @@ +import * as angular from 'angular'; +import { ViewArray } from './view-array'; +import { ViewArrayImpl } from './view-array.impl'; + + +/** + * Specialized wrapper around array which provides a toggle() method for viewing the contents of the + * array in a manner that is asynchronously filled in over a short time period. This prevents long + * pauses in the UI for ngRepeat's when the array is significant in size. + */ +angular + .module('quay') + .factory('AngularViewArray', AngularViewArrayFactory); + +AngularViewArrayFactory.$inject = [ + '$interval' +]; + +export default function AngularViewArrayFactory($interval) { + var ADDTIONAL_COUNT = 20; + + function _ViewArray() { + this.isVisible = false; + this.visibleEntries = null; + this.hasEntries = false; + this.entries = []; + this.hasHiddenEntries = false; + + this.timerRef_ = null; + this.currentIndex_ = 0; + } + + _ViewArray.prototype.length = function(): number { + return this.entries.length; + }; + + _ViewArray.prototype.get = function(index: number): any { + return this.entries[index]; + }; + + _ViewArray.prototype.push = function(elem: any): void { + this.entries.push(elem); + this.hasEntries = true; + + if (this.isVisible) { + this.startTimer_(); + } + }; + + _ViewArray.prototype.toggle = function(): void { + this.setVisible(!this.isVisible); + }; + + _ViewArray.prototype.setVisible = function(newState: boolean): void { + this.isVisible = newState; + + this.visibleEntries = []; + this.currentIndex_ = 0; + + if (newState) { + this.showAdditionalEntries_(); + this.startTimer_(); + } + else { + this.stopTimer_(); + } + }; + + _ViewArray.prototype.showAdditionalEntries_ = function(): void { + var i: number = 0; + for (i = this.currentIndex_; i < (this.currentIndex_ + ADDTIONAL_COUNT) && i < this.entries.length; ++i) { + this.visibleEntries.push(this.entries[i]); + } + + this.currentIndex_ = i; + this.hasHiddenEntries = this.currentIndex_ < this.entries.length; + if (this.currentIndex_ >= this.entries.length) { + this.stopTimer_(); + } + }; + + _ViewArray.prototype.startTimer_ = function(): void { + if (this.timerRef_) { + return; + } + + var that = this; + this.timerRef_ = $interval(function() { + that.showAdditionalEntries_(); + }, 10); + }; + + _ViewArray.prototype.stopTimer_ = function(): void { + if (this.timerRef_) { + $interval.cancel(this.timerRef_); + this.timerRef_ = null; + } + }; + + var service: any = { + create: function(): any { + return new _ViewArray(); + } + }; + + return service; +} + diff --git a/static/js/services/angular-view-array/view-array.impl.ts b/static/js/services/angular-view-array/view-array.impl.ts new file mode 100644 index 000000000..a0050bc6a --- /dev/null +++ b/static/js/services/angular-view-array/view-array.impl.ts @@ -0,0 +1,90 @@ +import { ViewArray } from './view-array'; + + +export class ViewArrayImpl implements ViewArray { + + isVisible: boolean; + visibleEntries: any[]; + hasEntries: boolean; + entries: any[]; + hasHiddenEntries: boolean; + timerRef_: any; + currentIndex_: number; + + constructor(private interval: any, private additionalCount: number) { + this.isVisible = false; + this.visibleEntries = null; + this.hasEntries = false; + this.entries = []; + this.hasHiddenEntries = false; + this.timerRef_ = null; + this.currentIndex_ = 0; + } + + public length(): number { + return this.entries.length; + } + + public get(index: number): any { + return this.entries[index]; + } + + public push(elem: any): void { + this.entries.push(elem); + this.hasEntries = true; + + if (this.isVisible) { + this.startTimer_(); + } + } + + public toggle(): void { + this.setVisible(!this.isVisible); + } + + public setVisible(newState: boolean): void { + this.isVisible = newState; + + this.visibleEntries = []; + this.currentIndex_ = 0; + + if (newState) { + this.showAdditionalEntries_(); + this.startTimer_(); + } + else { + this.stopTimer_(); + } + } + + private showAdditionalEntries_(): void { + var i: number = 0; + for (i = this.currentIndex_; i < (this.currentIndex_ + this.additionalCount) && i < this.entries.length; ++i) { + this.visibleEntries.push(this.entries[i]); + } + + this.currentIndex_ = i; + this.hasHiddenEntries = this.currentIndex_ < this.entries.length; + if (this.currentIndex_ >= this.entries.length) { + this.stopTimer_(); + } + } + + private startTimer_(): void { + if (this.timerRef_) { + return; + } + + var that = this; + this.timerRef_ = this.interval(function() { + that.showAdditionalEntries_(); + }, 10); + } + + private stopTimer_(): void { + if (this.timerRef_) { + this.interval.cancel(this.timerRef_); + this.timerRef_ = null; + } + } +} \ No newline at end of file diff --git a/static/js/services/angular-view-array/view-array.ts b/static/js/services/angular-view-array/view-array.ts new file mode 100644 index 000000000..343ca1efb --- /dev/null +++ b/static/js/services/angular-view-array/view-array.ts @@ -0,0 +1,12 @@ +export abstract class ViewArray { + + public abstract length(): number; + + public abstract get(index: number): any; + + public abstract push(elem: any): void; + + public abstract toggle(): void; + + public abstract setVisible(newState: boolean): void; +} \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js index b5029b6d5..42b13ae06 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -2,7 +2,7 @@ var webpack = require('webpack'); var path = require("path"); var config = { - entry: ["./static/js/app.tsx"], + entry: ["./static/js/app.tsx", "./static/js/services/angular-view-array/angular-view-array.ts"], output: { path: path.resolve(__dirname, "static/js/build"), filename: "bundle.js" @@ -20,13 +20,14 @@ var config = { loader: "ts-loader", exclude: /node_modules/ }, - { - test: /\.scss$/, + { + test: /\.scss$/, loaders: ['style', 'css', 'sass'], - exclude: /node_modules/ + exclude: /node_modules/ } ] - } + }, + devtool: "cheap-eval-source-map", }; module.exports = config;