commit afe73b5baaaf5d7c24e659185bb0a8162beb624f Author: Martin Donnelly Date: Thu Dec 22 00:00:06 2016 +0000 upload diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9d9d6f8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,279 @@ +# Created by https://www.gitignore.io/api/bower,node,dotsettings,visualstudio + +### Bower ### +bower_components +.bower-cache +.bower-registry +.bower-tmp + + +### Node ### +# Logs +logs +*.log +npm-debug.log* + +# Runtime data +pids +*.pid +*.seed + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directory +# https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git +node_modules +jspm_Packages + + +### DotSettings ### +*.DotSettings + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Ionic +platforms +plugins +www + +# AODB Specific +tests/compiled +report +app/core/frame/frame.ts.orig +.vscode/ +hooks/after_platform_add/010_install_plugins.js +hooks/ +*.orig + + +.DS_Store +.idea/ +jspm_packages/ diff --git a/.io-config.json b/.io-config.json new file mode 100644 index 0000000..00ba0f3 --- /dev/null +++ b/.io-config.json @@ -0,0 +1 @@ +{"app_id":"e5b00de9","api_key":"f7be4e17290bb7e1b87b82db3c86936d948a3d1066502abc"} \ No newline at end of file diff --git a/.project b/.project new file mode 100644 index 0000000..370b12f --- /dev/null +++ b/.project @@ -0,0 +1,11 @@ + + + AODB + + + + + + + + diff --git a/AODB.Mobile.jsproj b/AODB.Mobile.jsproj new file mode 100644 index 0000000..ca07856 --- /dev/null +++ b/AODB.Mobile.jsproj @@ -0,0 +1,115 @@ + + + + + + Debug + Android + + + Debug + iOS + + + Debug + Windows-AnyCPU + + + Debug + Windows-x64 + + + Debug + Windows-x86 + + + Debug + Windows-ARM + + + Debug + Windows Phone 8 + + + Debug + Windows Phone (Universal) + + + Release + Android + + + Release + iOS + + + Release + Windows-AnyCPU + + + Release + Windows-x64 + + + Release + Windows-x86 + + + Release + Windows-ARM + + + Release + Windows Phone 8 + + + Release + Windows Phone (Universal) + + + + + + + f20dd032-ca1f-4eae-b4c3-af8a475fb1a7 + + + + 14.0 + + + 1.6.0 + true + + + false + true + + + + + Tools for Apache Cordova + + + MDD + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/AODB.Mobile.sln b/AODB.Mobile.sln new file mode 100644 index 0000000..a90c84f --- /dev/null +++ b/AODB.Mobile.sln @@ -0,0 +1,80 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.23107.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{262852C6-CD72-467D-83FE-5EEB1973A190}") = "AODB.Mobile", "AODB.Mobile.jsproj", "{F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Android = Debug|Android + Debug|iOS = Debug|iOS + Debug|Windows Phone (Universal) = Debug|Windows Phone (Universal) + Debug|Windows Phone 8 = Debug|Windows Phone 8 + Debug|Windows-AnyCPU = Debug|Windows-AnyCPU + Debug|Windows-ARM = Debug|Windows-ARM + Debug|Windows-x64 = Debug|Windows-x64 + Debug|Windows-x86 = Debug|Windows-x86 + Release|Android = Release|Android + Release|iOS = Release|iOS + Release|Windows Phone (Universal) = Release|Windows Phone (Universal) + Release|Windows Phone 8 = Release|Windows Phone 8 + Release|Windows-AnyCPU = Release|Windows-AnyCPU + Release|Windows-ARM = Release|Windows-ARM + Release|Windows-x64 = Release|Windows-x64 + Release|Windows-x86 = Release|Windows-x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Debug|Android.ActiveCfg = Debug|Android + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Debug|Android.Build.0 = Debug|Android + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Debug|Android.Deploy.0 = Debug|Android + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Debug|iOS.ActiveCfg = Debug|iOS + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Debug|iOS.Build.0 = Debug|iOS + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Debug|iOS.Deploy.0 = Debug|iOS + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Debug|Windows Phone (Universal).ActiveCfg = Debug|Windows Phone (Universal) + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Debug|Windows Phone (Universal).Build.0 = Debug|Windows Phone (Universal) + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Debug|Windows Phone (Universal).Deploy.0 = Debug|Windows Phone (Universal) + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Debug|Windows Phone 8.ActiveCfg = Debug|Windows Phone 8 + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Debug|Windows Phone 8.Build.0 = Debug|Windows Phone 8 + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Debug|Windows Phone 8.Deploy.0 = Debug|Windows Phone 8 + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Debug|Windows-AnyCPU.ActiveCfg = Debug|Windows-AnyCPU + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Debug|Windows-AnyCPU.Build.0 = Debug|Windows-AnyCPU + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Debug|Windows-AnyCPU.Deploy.0 = Debug|Windows-AnyCPU + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Debug|Windows-ARM.ActiveCfg = Debug|Windows-ARM + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Debug|Windows-ARM.Build.0 = Debug|Windows-ARM + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Debug|Windows-ARM.Deploy.0 = Debug|Windows-ARM + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Debug|Windows-x64.ActiveCfg = Debug|Windows-x64 + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Debug|Windows-x64.Build.0 = Debug|Windows-x64 + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Debug|Windows-x64.Deploy.0 = Debug|Windows-x64 + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Debug|Windows-x86.ActiveCfg = Debug|Windows-x86 + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Debug|Windows-x86.Build.0 = Debug|Windows-x86 + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Debug|Windows-x86.Deploy.0 = Debug|Windows-x86 + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Release|Android.ActiveCfg = Release|Android + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Release|Android.Build.0 = Release|Android + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Release|Android.Deploy.0 = Release|Android + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Release|iOS.ActiveCfg = Release|iOS + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Release|iOS.Build.0 = Release|iOS + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Release|iOS.Deploy.0 = Release|iOS + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Release|Windows Phone (Universal).ActiveCfg = Release|Windows Phone (Universal) + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Release|Windows Phone (Universal).Build.0 = Release|Windows Phone (Universal) + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Release|Windows Phone (Universal).Deploy.0 = Release|Windows Phone (Universal) + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Release|Windows Phone 8.ActiveCfg = Release|Windows Phone 8 + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Release|Windows Phone 8.Build.0 = Release|Windows Phone 8 + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Release|Windows Phone 8.Deploy.0 = Release|Windows Phone 8 + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Release|Windows-AnyCPU.ActiveCfg = Release|Windows-AnyCPU + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Release|Windows-AnyCPU.Build.0 = Release|Windows-AnyCPU + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Release|Windows-AnyCPU.Deploy.0 = Release|Windows-AnyCPU + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Release|Windows-ARM.ActiveCfg = Release|Windows-ARM + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Release|Windows-ARM.Build.0 = Release|Windows-ARM + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Release|Windows-ARM.Deploy.0 = Release|Windows-ARM + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Release|Windows-x64.ActiveCfg = Release|Windows-x64 + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Release|Windows-x64.Build.0 = Release|Windows-x64 + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Release|Windows-x64.Deploy.0 = Release|Windows-x64 + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Release|Windows-x86.ActiveCfg = Release|Windows-x86 + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Release|Windows-x86.Build.0 = Release|Windows-x86 + {F20DD032-CA1F-4EAE-B4C3-AF8A475FB1A7}.Release|Windows-x86.Deploy.0 = Release|Windows-x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/GitVersionConfig.yaml b/GitVersionConfig.yaml new file mode 100644 index 0000000..bf7d9ba --- /dev/null +++ b/GitVersionConfig.yaml @@ -0,0 +1,26 @@ +assembly-versioning-scheme: MajorMinorPatch +mode: ContinuousDeployment +branches: + master: + tag: + increment: Patch + prevent-increment-of-merged-branch-version: true + release[/-]: + tag: beta + feature[/-]: + tag: useBranchName + increment: Inherit + hotfix[/-]: + tag: beta + support[/-]: + tag: + increment: Patch + prevent-increment-of-merged-branch-version: true + develop: + tag: unstable + increment: Minor + track-merge-target: true + (pull|pull\-requests|pr)[/-]: + tag: PullRequest + increment: Inherit + tag-number-pattern: '[/-](?\d+)[-/]' diff --git a/README.md b/README.md new file mode 100644 index 0000000..7197a49 --- /dev/null +++ b/README.md @@ -0,0 +1,25 @@ +# AODB Mobile Readme + +## [Mac OS X Setup Guide](Readme/MacSetupGuide.md) + +## [Xubuntu Setup Guide](Readme/XubuntuSetupGuide.md) + +## [Development Guide](Readme/DevelopmentGuide.md) + +## [Release Guide](Readme/ReleaseGuide.md) + +## [Mobile Interface Endpoints](Readme/MobileInterfaceEndpoints.md) + +### TODO How do I get set up? + +* Summary of set up +* Configuration +* Dependencies +* Database configuration +* How to run tests +* Deployment instructions + +Contribution guidelines +* Writing tests +* Code review +* Other guidelines \ No newline at end of file diff --git a/Readme/DevelopmentGuide.md b/Readme/DevelopmentGuide.md new file mode 100644 index 0000000..f80bb04 --- /dev/null +++ b/Readme/DevelopmentGuide.md @@ -0,0 +1,206 @@ +# AODB Development + +## Background + +The AODB Mobile application built using Ionic, Angular and Typescript, it communicates with AODB over a well-defined, loosely coupled interface. + +--- +## Prerequisites + +Access to the team foundation server for the AODB Mobile project which contains the git repository and project documentation. +[Transport AODB Mobile Team Foundation Server](http://i-t-v-tf01:8080/tfs/Transport/Chroma%20Refresh/AODB%20Mobile) + +Access to the AODB Mobile project Thycotic Secret Server which contains all account information, usernames and passwords. +[Transport AODB Mobile Thycotic Secret Server](https://secrettransport.pdats.com) + +--- + +## Contents + +* [Overview](#overview) +* [Node Packages](#node-packages) +* [Setup and Run](#setup-and-run) +* [Development](#development) +* [Git Flow](#git-flow) + +--- +## Node Packages + +Install the following node packages with specified versions + +* gulp +* cordova +* ionic +* jspm +* bower +* npm-check +* npm-install-missing +* phantomjs-prebuilt +* sinopia +* pm2 + +**Install Node Packages with the following command in the terminal prompt:** +``` +$ npm i -g gulp cordova ionic jspm bower npm-check npm-install-missing phantomjs-prebuilt sinopia pm2 +``` + +**List installed Node Packages with the following command in the terminal prompt:** +``` +$ npm ls -g --depth=0 +``` + +--- +## Setup and Run + +The ionic info command prints out useful information about your system’s Ionic environment and dependencies +``` +$ ionic info +``` + +Clone the repo +``` +$ git clone http://i-t-v-tf01:8080/tfs/Transport/Chroma%20Refresh/_git/AODB +``` +Use gulp to install the projects dependencies +``` +$ gulp install +``` +Use gulp to build the project +``` +$ gulp build +``` +See the application running run the following command: +``` +$ ionic serve -l +``` + +--- +## Development + +### TFS + +[TFS Conventions Document](http://i-t-v-tf02:12345/ChromaDev/Chroma%20Processes/TFS%20Workflow/TFS%20Conventions.docx) + +### Pull requests +>Pull requests let you tell others about changes you've pushed to a repository. Once a pull request is sent, interested parties can review the set of changes, discuss potential modifications, and even push follow-up commits if necessary. + +--- +### Wallaby.js +>Wallaby.js is an intelligent and super fast test runner for JavaScript that continuously runs your tests. ... Wallaby.js is insanely fast, because it only executes tests affected by your code changes and runs your tests in parallel. + +--- +### Gulp +>Gulp is a task/build runner for development. + + +**Gulp watch task will watch all files in the application folder and rebuild the www folder when anything changes** +``` +$ gulp watch +``` + +**Compiles and run the tests** +``` +$ gulp test +``` + + +**List Gulp tasks** +``` +$ gulp --tasks +``` + + +--- +### Git Flow + +**Initialize** + +**Initialize gitflow** +``` +$ git flow init +``` + +**Features** + +**Start a new feature** +``` +$ git flow feature start MYFEATURE +``` +**Finish up a feature** +``` +$ git flow feature finish MYFEATURE +``` +**Publish a feature** +``` +$ git flow feature publish MYFEATURE +``` +**Get a feature published by another user.** +``` +$ git flow feature pull origin MYFEATURE +``` +**You can track a feature on origin by using** +``` +$ git flow feature track MYFEATURE +``` + +**Releases** + +**Start a release** + +**To start a release, use the git flow release command** +``` +$ git flow release start RELEASE [BASE] +``` +**Publish the release branch after creating it to allow release commits by other developers.** +``` +$ git flow release publish RELEASE +``` +**Track a remote release** +``` +$ git flow release track RELEASE +``` + +**Finish up a release** + +**Finishing a release performs several actions:** +* Merges the release branch back into 'master' +* Tags the release with its name +* Back-merges the release into 'develop' +* Removes the release branch + +**Finish release** +``` +$ git flow release finish RELEASE +``` + +**Push your tags with** +``` +$ git push --tags +``` +--- + + +**Start hotfix** + +``` +$ git flow hotfix start VERSION [BASENAME] +``` + +**Finish a hotfix** + +``` +$ git flow hotfix finish VERSION +``` +--- +**Commands** + +| | | | | +|:---------------|:--------------|:-------------|:-------| +| |**init** | | | +|**git flow =>** |**feature =>** |**start =>** |**NAME**| +| |**release** |**finish** | | +| |**hotfix** |**pubish** | | +| | |**pull** | | + +--- + diff --git a/Readme/MacSetupGuide.md b/Readme/MacSetupGuide.md new file mode 100644 index 0000000..3e356d4 --- /dev/null +++ b/Readme/MacSetupGuide.md @@ -0,0 +1,530 @@ +# AODB Mobile Mac + +## Background + +This guide is designed to set up and install all the components required for a development, automated build and continual integration environment on Mac OS X. + +## Prerequisites + +Access to the team foundation server for the AODB Mobile project which contains the git repository and project documentation. +[Transport AODB Mobile Team Foundation Server](http://i-t-v-tf01:8080/tfs/Transport/Chroma%20Refresh/AODB%20Mobile) + +Access to the AODB Mobile project Thycotic Secret Server which contains all account information, usernames and passwords. +[Transport AODB Mobile Thycotic Secret Server](https://secrettransport.pdats.com) + +Access to the Apple developer account which is used for setting up provisioning profiles, device management and certificates. +[Apple Developer Account](https://developer.apple.com) + +--- + +## Contents + +Install and configure the following components:l + +* [Rename Computer](#rename-computer) +* [Sophos](#sophos) +* [Java SDK](#java-sdk) +* [Xcode](#xcode) +* [Homebrew](#homebrew) +* [Git](#git) +* [OpenSSL](#openssl) +* [Visual Studio Team Services Agent](#visual-studio-team-services-agent) +* [Node Version Manager](#node-version-manager) +* [Node](#node) +* [Node Packages](#node-packages) +* [Sinopia](#sinopia) +* [PM2 Process Management](#pm2-process-management) +* [WebStorm](#webstorm) +* [SourceTree](#sourcetree) +* [Visual Studio Code](#visual-studio-code) +* [HockeyApp](#hockeyapp) + +--- + +## Rename Computer + +>Rename computer name using central technology asset id. + +**Asset ID: LM120477** +* Launch ‘System Preferences’ from the Apple menu in OS X +* Click the ‘Sharing’ icon +* Type in what you want your Mac’s new computer name to be +* Close ‘System Preferences’ for the setting to take effect + +--- + +## Sophos + +>Sophos Endpoint doesn’t rely on signatures to catch malware, which means it catches zero-day threats without adversely affecting the performance of your device. So you get protection before those exploits even arrive. + +Raise Assist with CT for adding Sophos Endpoint + + +## Java SDK +>The Java Development Kit (JDK) is a software development environment used for developing Java applications and applets. It includes the Java Runtime + +Download and install the Java Platform, Standard Edition +[Java SE Downloads](http://www.oracle.com/technetwork/java/javase/downloads/index.html) + +**Set $JAVA_HOME environment variable with the following command in the terminal prompt:** + +``` +$ emacs .profile +``` + +**Add this to the end of the .profile file:** + +``` +JAVA_HOME=/Library/Java/Home +export JAVA_HOME; +``` + +>Save and exit emacs (ctrl-x, ctrl-s; ctrl-x, ctrl-c) + +**Confirm Java verion with the following command in the terminal prompt:** +``` +$ java -version +``` +--- + +## Xcode + +>Xcode is an integrated development environment (IDE) containing the tools for developing iOS. + +**Install Xcode with the following command in the terminal prompt:** +``` +$ xcode-select --install +``` + +**Add MobileAppsTeam Developer Account to Xcode** + +* Open Xcode +* Xcode > Preferences > Accounts Tab +* Add MobileAppsTeam@leidos.com Account + + +**iOS developer certificates** + +[Apple Developer](https://developer.apple.com/) + +* Log into Apple Developer Account with MobileAppsTeam@leidos.com; +* Download iOS developer certificates; +* Open downloaded certificates in Keychain; +* Ensure Xcode has logged has the developer account logged in. + +--- + +## Homebrew + +>Homebrew is a open-source software package management. + +**Install Homebrew with the following command in the terminal prompt:** +``` +$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" +``` + +**Confirm the Homebrew installed with the following command in the terminal prompt:** +``` +$ brew doctor +``` + +[Homebrew documentation](https://git.io/brew-docs) + +--- + +## Git + +>Git is a version control system. Must be version >= 2.9.0 + +**Install Git with the following command in the terminal prompt:** +``` +$ brew install git +``` + +**Confirm the version of Git with the following command in the terminal prompt:** +``` +$ git --version +``` + +--- + +## OpenSSL + +>OpenSSL is an open source tool for using the Secure Socket Layer (SSL) and Transport Layer Security (TLS) protocols for Web authentication. + +**Install OpenSSL with the following command in the terminal prompt:** + +``` +$ brew install openssl +``` +**Ensure folder exists on machine with the following commands in the terminal prompt:** + +``` +$ mkdir -p /usr/local/lib/ +$ ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/ +$ ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/ +$ brew link --force openssl +$ brew info openssl +``` + +--- + +## Visual Studio Team Services Agent + +>The Visual Studio Team Services Agent OSX is cross platform build and release agent for Team Services and Team Foundation Server 2015 + +### Download the OSX agent + +[Download vsts-agent-osx.10.11-x64-2.105.7.tar.gz](https://github.com/Microsoft/vsts-agent/releases/download/v2.105.7/vsts-agent-osx.10.11-x64-2.105.7.tar.gz) + +**Create OSX agent folder in the `$HOME` with the following command in the terminal prompt:** +``` +$ cd $HOME +$ mkdir aodb-vsts-agent && cd aodb-vsts-agent +``` + +**Extract into agent folder from Downloads with the following command in the terminal prompt:** +``` +$ tar xzf ~/Downloads/vsts-agent-osx.10.11-x64-2.105.7.tar.gz +``` + +### Configure the agent + +**Configure the agent with the following command in the terminal prompt:** +``` +$ cd $HOME/aodb-vsts-agent +$ ./config.sh +``` + +**Enter the following details as below:** + +Enter Server URL > http://i-t-v-tf01:8080/tfs +Enter authentication type (press enter for Negotive) > +Enter user name > I-T-V-TF01/GITUSER +Enter Password > [Transport AODB Mobile Thycotic Secret Server](https://secrettransport.pdats.com) +Enter queue name > Chroma vNext +Enter agent name > Mac-LM120477 +Default any other settings + +**Run the agent with the following command in the terminal prompt:** +``` +$ ./run.sh +``` + +**Remove the agent to reconfigure with the following command in the terminal prompt:** +``` +$ ./config remove +``` +[Visual Studio Team Services Agent Documentation](https://github.com/Microsoft/vsts-agent) + +--- + +## Node Version Manager + +>Node Version Manager is bash script to manage multiple active node.js versions + +**Install NVM with the following command in the terminal prompt:** +``` +$ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.32.1/install.sh | bash +``` + +**Add NVM to the bash_profile with the following command in the terminal prompt:** +``` +$ nano ~/.bash_profile +``` + +**Add the following lines to the .bash_profile :** + +export PATH=$PATH:~/.android-sdk-macosx/platform-tools/ +export NVM_DIR="/Users/MobileAppsTeam/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" + + +**Verify installation with the following command in the terminal prompt:** +``` +$ nvm -v +``` + +[Node Version Manager Documentation](https://github.com/creationix/nvm#verify-installation) + +--- + +## Node + +>Node.js is an open-source, cross-platform JavaScript runtime environment. + +**Install Node and NPM with the following command in the terminal prompt:** +``` +$ nvm install 6.9.0 +$ npm i -g npm@3.10.7 +$ nvm use 6.9.0 +$ nvm alias default 6.9.0 + +``` + +**Verify Node version 6.9.0 and npm version 3.10.7 with the following command in the terminal prompt:** +``` +$ node -v && npm -v +``` +--- + +## Node Packages + +Install the following node packages with specified versions + +* gulp +* cordova +* ionic +* jspm +* bower +* npm-check +* npm-install-missing +* phantomjs-prebuilt +* sinopia +* pm2 + +**Install Node Packages with the following command in the terminal prompt:** +``` +$ npm i -g gulp cordova ionic jspm bower npm-check npm-install-missing phantomjs-prebuilt sinopia pm2 +``` + +**List installed Node Packages with the following command in the terminal prompt:** +``` +$ npm ls -g --depth=0 +``` + +--- + +## Sinopia + +>Sinopia is a private / caching npm repository server + +**Install Sinopia with the following command in the terminal prompt:** +``` +$ npm i sinopia -g +``` + +**Run Sinopia with the following command in the terminal prompt:** +``` +$ sinopia +``` + +**Set npm registry to Sinopia with the following command in the terminal prompt:** +``` +$ npm set registry http://localhost:4873/ +``` +**Set add user to Sinopia with the following command in the terminal prompt:** +``` +$ npm adduser --registry http://localhost:4873/ +``` + +Username: mobileappsteam +Password: [Transport AODB Mobile Thycotic Secret Server](https://secrettransport.pdats.com) +Email: MobileAppsTeam@leidos.com + +**Clone local-Chromaux git repository with the following commands in the terminal prompt:** +``` +$ cd $HOME/dev +$ git clone http://i-t-v-tf01:8080/tfs/Transport/Chroma%20Refresh/_git/UX +``` + +**Run the gulp command to export Chroma.UX with the following commands in the terminal prompt:** +``` +$ cd $HOME/dev/UX/Chroma.UX/ +$ npm install +$ gulp newexport +``` + +**Check the npm config file has the value registry=http://localhost:4873/ with the following command in the terminal prompt:** +``` +$cat ~/.npmrc +``` + +**Publish the Chroma.UX package to Sinopia with the following commands in the terminal prompt:** +``` +$ cd $HOME/dev/UX/local-chromaux/ +$ npm publish . +``` + + +[Sinopia Documentation](https://www.npmjs.com/package/sinopia) + +--- + +## PM2 Process Management + +>PM2 is a production process manager for Node.js applications with a built-in load balancer. It allows you to keep applications alive forever, to reload them without downtime and to facilitate common system admin tasks. + +**Install PM2 with the following command in the terminal prompt:** +``` +$ npm i pm2@latest -g +``` + +**Setup Auto-Completion with the following command in the terminal prompt:** +``` +$ pm2 completion >> ~/.bash_profile +``` + +**Create a process configuration JSON file as ~/process.json** + +```json +{ + "apps" : [ + { + "name" : "Sinopia", + "script" : "/Users/MobileAppsTeam/.nvm/versions/node/v4.4.7/bin/sinopia", + "cwd" : "/Users/MobileAppsTeam", + "watch" : false, + "instances" : 1, + "exec_mode" : "fork", + "combine_logs" : true, + "max_memory_restart" : "300M", + "restart_delay" : 5000 + }, + { + "name" : "BuildAgent", + "script" : "run.sh", + "cwd" : "/Users/MobileAppsTeam/aodb-vsts-agent", + "watch" : false, + "instances" : 1, + "exec_mode" : "fork", + "combine_logs" : true, + "max_memory_restart" : "300M", + "restart_delay" : 5000 + } + ] +} +``` + +**Start with the following command in the terminal prompt:** +``` +$ pm2 start ~/profile.json +``` + +**Additional Commands** +``` +$ pm2 kill +$ pm2 monit +$ pm2 list +$ pm2 log 0 +$ pm3 log 1 +``` + + +[PM2 documentation](http://pm2.keymetrics.io/docs/usage/quick-start/) + +--- + +## Android command line SDK Tools + +>SDK Tools is a downloadable component for the Android SDK. It includes the complete set of development and debugging tools for the Android SDK. + + +**Download the Mac SDK Tools** +[android-sdk_r24.4.1-macosx.zip](https://dl.google.com/android/android-sdk_r24.4.1-macosx.zip) + +**Unzip Android command line SDK Tools with the following commands in the terminal prompt:** +``` +$ cd ~/Downloads/ +$ unzip android-sdk*.zip +$ mv android-sdk-macosx/ ~/.android-sdk-macosx +``` + +**Run the SDK Manager with the following commands in the terminal prompt:** +``` +$ sh ~/.android-sdk-macosx/tools/android +``` + +**Select the following below:** + +Tools +* Android SDK Build-tools 23.03 +* Android SDK Build-tools 23.02 +* Android SDK Build-tools 23.01 +* Android SDK Build-tools 22.01 + +Android 6.0 (API 23) +* SDK Platform +* Google APIs Intel x86 Atom_64 System Image +* Sources for Android SDK + +**Click Install Packages** + +**Add platform-tools to your path with the following commands in the terminal prompt:** +``` +$ echo 'export PATH=$PATH:~/.android-sdk-macosx/platform-tools/' >> ~/.bash_profile +``` + +**Refresh your bash profile with the following commands in the terminal prompt:** +``` +$ source ~/.bash_profile +``` + +[Android Developer Website](https://developer.android.com/studio/index.html) + +--- + +## WebStorm + +>WebStorm is a JavaScript IDE for client-side development and server-side development with Node.js. + +[Download WebStorm for Mac OS](https://download.jetbrains.com/webstorm/WebStorm-2016.2.4.dmg) + +[WebStorm Website](https://www.jetbrains.com/webstorm/) + +--- + +## SourceTree + +>SourceTree is a Git and Hg client. SourceTree simplifies how you interact with your Git and Mercurial repositories. + +[Download SourceTree](https://downloads.atlassian.com/software/sourcetree/SourceTree_2.3.1.zip?_ga=1.107064514.1767012481.1477928157) + +--- + +## Visual Studio Code + +>Visual Studio Code is a source code editor developed by Microsoft for Windows, Linux and macOS. It includes support for debugging, embedded Git control, syntax highlighting, intelligent code completion, snippets, and code refactoring. + +[Download Visual Studio Code](http://code.visualstudio.com/docs/?dv=osx) + +--- + +## Tinker Tools + +>TinkerTool is an application that gives you access to additional preference settings Apple has built into macOS. This allows to activate hidden features in the operating system and in some of the applications delivered with the system + +[Download Tinker Tools]() +--- +## Brackets + +>Brackets is an open source code editor for web designers and front-end developers. + +[Download Brackets]() +--- + +## Chrome + +>Chrome is a fast, simple and secure web browser, built for the modern web. Download Chrome. + +[Download Chrome]() + +--- + +# TO ADD + +screen + +How To Use Linux Screen + +Control Command +Command: “Ctrl-a” + +Switching Between Windows + +Command: “Ctrl-a” “n” + +Detaching From Screen + +Command: “Ctrl-a” “d” + +--- \ No newline at end of file diff --git a/Readme/MobileInterfaceEndpoints.md b/Readme/MobileInterfaceEndpoints.md new file mode 100644 index 0000000..1f85279 --- /dev/null +++ b/Readme/MobileInterfaceEndpoints.md @@ -0,0 +1,522 @@ +# Mobile Interface Endpoints + +|Verb|Name|Url| +|---|---|---| +|POST|[Authentication](#authentication)|/api/auth| +|POST|[CancelTransaction](#canceltransaction)|/api/cancelTransaction| +|POST|[ConfirmTransaction](#confirmtransaction)|/api/confirmTransaction| +|POST|[CreateTransaction](#createtransaction)|/api/createTransaction| +|GET|[Detail](#detail)|/api/detail/| +|GET|[Flights](#flights)|/api/flights| +|GET|[GetOperatorImage](#getoperatorimage)|/api/GetOperatorImage| +|GET|[GetTransactionCodes](#gettransactioncodes)|/api/getTransactionCodes| +|GET|[GetTransactionConfig](#gettransactionconfig)|/api/getTransactionConfig| +|GET|[GetUserAccessRightsForTransaction](#getuseraccessrightsfortransaction)|/api/getUserAccessRightsForTransaction| +|GET|[GetWindows](#getwindows)|/api/getWindows| +|POST|[SetSite](#setsite)|/api/setSite| +|GET|[Transactions](#transactions)|/api/transactions| +|POST|[UpdateTransaction](#updatetransaction)|/api/updateTransaction| +|POST|[UpdateFlight](#Updatflight)|/api/updateFlight| + +--- + +## Authentication + +**/api/auth** + +**Example post** + +```json +{ + "Username": "username", + "Password": "password", + "ActiveDirectoryUsername": "" +} +``` + +**Example response** + +```json +{ + "ContentEncoding": null, + "ContentType": null, + "Data": { + "LoginSuccess": true, + "SiteSelectionRequired": true, + "Sites": { + "SelectedSiteId": 0, + "Sites": [ + { + "SiteId": 23, + "SiteName": "Oslo Airport", + "IATACode": "OSL" + }, + { + "SiteId": 68, + "SiteName": "Alesund Airport, Vigra", + "IATACode": "AES" + } + ], + "Warning": false + } + }, + "JsonRequestBehavior": 1, + "MaxJsonLength": null, + "RecursionLimit": null +} +``` + +--- +## CancelTransaction + +**Example request** +``` +http://localhost:89/api/cancelTransaction +``` + +**Example post** + +```json +{ + "Id": "296994", + "PhysflightId": "7126204", + "PublflightId": "7126204", + "Code": "TOW", + "Name": "ACFT TOW", + "Quantity": 1, + "Duration": "0", + "PONumber": "1", + "StartTime": "08/12/2016 12:18", + "EndTime": "08/12/2016 12:18", + "Confirmed": true, + "Cancelled": true, + "CodeType": 1, + "Timestamp": 1689685320 +} +``` + +--- +## ConfirmTransaction + +**Example request** +``` +http://localhost:89/api/confirmTransaction +``` + +**Example post** + +```json +{ + "Id": "296994", + "PhysflightId": "7126204", + "PublflightId": "7126204", + "Code": "TOW", + "Name": "ACFT TOW", + "Quantity": 1, + "Duration": "0", + "PONumber": "1", + "StartTime": "08/12/2016 12:18", + "EndTime": "08/12/2016 12:18", + "Confirmed": false, + "Cancelled": true, + "CodeType": 1, + "Timestamp": 1689685320 +} +``` + + +**Example response** +```json +{ + "Success":true +} +``` + +--- +## CreateTransaction + +**Example request** + +``` +http://localhost:89/api/createTransaction +``` + +**Example post** + +```json +{ + "Id": "296994", + "PhysflightId": "7126204", + "PublflightId": "7126204", + "Code": "TOW", + "Name": "ACFT TOW", + "Quantity": 1, + "Duration": "0", + "PONumber": "1", + "StartTime": "08/12/2016 12:18", + "EndTime": "08/12/2016 12:18", + "Confirmed": false, + "Cancelled": false, + "CodeType": 1, + "Timestamp": 1689685320 +} +``` + +**Example response** +```json +{ + "Success":true +} +``` + +--- + +## Detail + +**/api/detail/** + +**Example request** + +``` +http://localhost:89//api/detail/?flightId=7121274&requestId=c9bced9b-1e6e-44b3-a236-0dd3005ee967 +``` + +**Example response** + +```json +{ + "Editors": [ + { + "Name": "readonly", + "Type": "readonly", + "Url": "" + }, + { + "Name": "datetime", + "Type": "datetime", + "Url": "updateflightdate" + }, + { + "Name": "freetext", + "Type": "freetext", + "Url": "updateflight" + } + ], + "Groups": [ + { + "Name": "Detail", + "Display": "Details", + "Icon": "ion-plane" + } + ], + "Fields": [ + { + "Value": "WF", + "Name": "Operator", + "Editor": "readonly", + "Group": "detail", + "Mapping": "SCOPER", + "Restrict": "" + } + ], + "Flight": { + "Id": "7121274", + "PhysFlightId": "7121274", + "Type": "D", + "Number": "128", + "Operator": "WF", + "FlightConcat": "WF128", + "AircraftType": "DH1", + "Registration": "", + "Location": "FRO", + "Scheduled": "\/Date(1478635200000)\/", + "Estimated": "\/Date(-62135596800000)\/", + "Actual": "\/Date(-62135596800000)\/", + "Terminal": "T1", + "Stand": "" + }, + "IsOutsideOfWindow": false +} +``` + +--- + +## Flights + +**/api/flights** + +>Gets list of flights + +**Example request** + +``` +http://localhost:89/api/flights?window=Default +``` + +**Example json data** + +```json +{ + "Flights": [ + { + "Id": "6760005", + "PhysFlightId": "6760005", + "Type": "D", + "Number": "4055", + "Operator": "SK", + "FlightConcat": "SK4055", + "AircraftType": "73G", + "Registration": "", + "Location": "SVG", + "Scheduled": "\/Date(1478895600000)\/", + "Estimated": "\/Date(-62135596800000)\/", + "Actual": "\/Date(-62135596800000)\/", + "Terminal": "T1", + "Stand": "" + } + ], + "RequestId": "6be3dc32-847c-4d6f-b504-a5dac8444791", + "Filter": "Default" +} +``` + +--- +## GetOperatorImage + +**api/GetOperatorImage** + +**Example get request** + +``` +/api/GetOperatorImage?code=BA +``` + +>Content-Type:image/jpeg + +--- + +## GetTransactionCodes + +**/api/getTransactionCodes** + +**Example request** + +``` +http://localhost:89//api/getTransactionCodes +``` + +**Example response** + +```json +[ + { + "Code": "TOW", + "CodeType": 1, + "Name": "ACFT TOW" + }, + { + "Code": "ASU", + "CodeType": 1, + "Name": "AIR START UNIT" + } +] +``` + +--- + +## GetTransactionConfig +**/api/getTransactionConfig** + +**Example request** +``` +http://localhost:89//api/getTransactionConfig?flightId=7250332&physFlight=7250332 +``` + +**Example response** + +```json +[ + { + "Id": 0, + "ColumnName": "FLGTTRAN_TRANCATG_CODE", + "Visible": true, + "Editable": true, + "Width": 6, + "Index": 0, + "HeaderText": "Code", + "DateFormat": null, + "Highlight": false, + "Description": "Code", + "Frozen": false, + "Configuration": null, + "ListItems": null, + "Justify": "RIGHT", + "Length": 4, + "Precision": 0, + "ColumnDataType": 0, + "CodeSetType": null, + "LookupType": 0, + "Formatter": null, + "Fixed": false, + "LookupTypeName": null, + "InGrid": false + } +] +``` + +--- + +## GetUserAccessRightsForTransaction + +**/api/getUserAccessRightsForTransaction** + +**Example request** +``` +http://localhost:89//api/getUserAccessRightsForTransaction +``` + +**Example response** + +```json +{ + "ProfileCode": "FSWH SYSTEM CONTROLLER", + "FunctionDefinition": "FSW_TRANSACTIONS", + "Enabled": true, + "Update": true, + "Add": true, + "Delete": true, + "View": true, + "FuncEnabled": false, + "FuncPackage": false, + "FuncProcedure": false, + "FuncParamaters": 0 +} +``` + +--- + +## GetWindows +**/api/getWindows** + +**Example response** + +```json +[ + { + "Id": 0, + "Name": "ABB", + "Description": "ABB", + "Type": "STANDARD" + } +] +``` + +--- + +//TODO +## SetSite + +**/api/setSite** + +**Example request** +``` +http://localhost:89/api/setSite +``` +**Example response** + +```json +{ + "ContentEncoding": null, + "ContentType": null, + "Data": { + "Error": false + }, + "JsonRequestBehavior": 1, + "MaxJsonLength": null, + "RecursionLimit": null +} +``` + +--- + +## Transactions + +**/api/transactions** + +**Example request** +``` +http://localhost:89//api/transactions?flightId=7250332&physFlight=7250332 +``` + +**Example response** + +```json +[ + { + "Id": "296645", + "PhysflightId": "7250332", + "PublflightId": "7250332", + "Code": "TOW", + "Name": "ACFT TOW", + "Quantity": 1, + "Duration": "0", + "PONumber": "", + "StartTime": "10/11/2016 19:14", + "EndTime": "10/11/2016 19:14", + "Confirmed": false, + "Cancelled": false, + "CodeType": 1, + "Timestamp": 1683178617 + } +] +``` + +--- + +## UpdateTransaction + +**Example post** + +```json +{ + "Id": "296994", + "PhysflightId": "7126204", + "PublflightId": "7126204", + "Code": "TOW", + "Name": "ACFT TOW", + "Quantity": 1, + "Duration": "0", + "PONumber": "1", + "StartTime": "08/12/2016 12:18", + "EndTime": "08/12/2016 12:18", + "Confirmed": false, + "Cancelled": false, + "CodeType": 1, + "Timestamp": 1689685320 +} +``` + +--- + +## UpdateFlight + +**Example post** + +```json +{ + "ErrorCode": null, + "Error": null, + "Success": true, + "RequiresConfirmation": false, + "ErrorDescription": null, + "ErrorCaption": null, + "PublishedFlightId": "7126204", + "ColumnName": "S1_PHYSFLGT_CREW_NUMBER", + "Value": "100", + "UpdatedValue": "100", + "Operator": null, + "AircraftType": null +} +``` + +--- \ No newline at end of file diff --git a/Readme/ReleaseGuide.md b/Readme/ReleaseGuide.md new file mode 100644 index 0000000..7bac3d0 --- /dev/null +++ b/Readme/ReleaseGuide.md @@ -0,0 +1,97 @@ +# AODB Mobile Release Guide + +## Background + +## Prerequisites + +Access to the team foundation server for the AODB Mobile project which contains the git repository and project documentation. +[Transport AODB Mobile Team Foundation Server](http://i-t-v-tf01:8080/tfs/Transport/Chroma%20Refresh/AODB%20Mobile) + +Access to the AODB Mobile project Thycotic Secret Server which contains all account information, usernames and passwords. +[Transport AODB Mobile Thycotic Secret Server](https://secrettransport.pdats.com) + +Access to the Apple developer account which is used for setting up provisioning profiles, device management and certificates. +[Apple Developer Account](https://developer.apple.com) + +--- + +## Contents + +* [Apple Developer](#apple-developer) +* [HockeyApp](#hockeyapp) + +## Apple Developer + +>Apple Developer, formerly Apple Developer Connection or ADC, is Apple Inc.'s developer network. It is designed to make available resources to help software developers write software for the Mac OS X and iOS platforms. + +[Apple Developer Login](https://developer.apple.com/) + +--- + +## HockeyApp + +>HockeyApp is a service for app developers to support them in various aspects of their development process, including the management and recruitment of testers, the distribution of apps and the collection of crash reports. + +[HockeyApp Website](https://rink.hockeyapp.net) + +### Invite User + +* Sign in to HockeyApp +* Click on your app, then on "Invite User". +* Select Role [Roles](#roles) +* User will need to download + +**Roles** +* Developers can view and edit all data of the app. +* Members can view all data and answer to feedback messages, but not edit the app or upload builds. +* Testers can download and install the app. + +### Export Unprovisioned Devices + +* Sign in to HockeyApp +* Click on your app, then on "Users". +* Select "Export > Unprovisioned Devices", then a file will be downloaded. + +### Import into Apple Developer + +* Sign in to http://developer.apple.com. +* Click on "Certificates, Identifiers & Profiles" in the right sidebar. +* Click on "Devices", then on the + button. +* Select "Register Multiple Devices" and choose the downloaded device file. +* Click on "Continue". +* Confirm the list of imported devices with "Register". + +### Download Provisioning Profiles + +* iOS Provisioning Profiles (Development) +* Modify your profile contents and select the Generate button to save changes +* Devices +* Click Select all +* Click Generate +* On the Mac Download Provisioning Profiles +* Open Xcode +* Under preference > select account +* Sign in with developer account MobileAppsTeam@leidos.com +* Click "view Details" +* Click "Download" on the latest provisioning profile +* Run ```ls -apl ~/Library/MobileDevice/Provisioning\ Profiles/``` in the terminal +* Select last provisioning id +* Add to build.json provisioningProfile + + +```json +{ + "ios": { + "debug": { + "developmentTeam":"DA3XCEKC7Z", + "provisioningProfile" : "fa3567f0-e841-405a-b9e8-adc652a74f8c" + + }, + "release": { + "developmentTeam":"DA3XCEKC7Z", + "provisioningProfile" : "fa3567f0-e841-405a-b9e8-adc652a74f8c" + + } + } +} +``` \ No newline at end of file diff --git a/Readme/XubuntuSetupGuide.md b/Readme/XubuntuSetupGuide.md new file mode 100644 index 0000000..7359e28 --- /dev/null +++ b/Readme/XubuntuSetupGuide.md @@ -0,0 +1,418 @@ +# Build Guide Xubuntu + +## Background + +This guide is designed to set up and install all the components required for a development environment on Xubuntu. + +## Prerequisites + +Xubuntu operating system + +>Xubuntu is an elegant and easy-to-use Unix-like operating system. Xubuntu comes with Xfce, which is a stable, light and configurable desktop environment. + +[Download Yakkety Yak the 16.10 xubuntu-16.04-desktop-amd64.iso](http://cdimages.ubuntu.com/xubuntu/releases/16.04/release/xubuntu-16.04-desktop-amd64.iso) + +[Xubuntu website](https://xubuntu.org/) + +Access to the team foundation server for the AODB Mobile project which contains the git repository and project documentation. +[Transport AODB Mobile Team Foundation Server](http://i-t-v-tf01:8080/tfs/Transport/Chroma%20Refresh/AODB%20Mobile) + +Access to the AODB Mobile project Thycotic Secret Server which contains all account information, usernames and passwords. +[Transport AODB Mobile Thycotic Secret Server](https://secrettransport.pdats.com) + +--- + +## Contents + +Install and configure the following components: + +* [Update and Upgrade](#update-and-upgrade) +* [Sophos](#sophos) +* [Java SDK](#java-sdk) +* [Android command line SDK Tools](#android-command-line-sdk-tools) +* [Development Tools](#development-tools) +* [Node Version Manager](#node-version-manager) +* [Node](#node) +* [Node Packages](#node-packages) +* [Sinopia](#sinopia) +* [PM2 Process Management](#pm2-process-management) +* [WebStorm](#webstorm) +* [Visual Studio Code](#visual-studio-code) +* [Chromium](#chromium) +* [Brackets](#brackets) +--- + +## Update and Upgrade +>Resynchronize the package index files and Upgrade the Debian Linux system including security update. + +**Update and Upgrade with the following command in the terminal prompt:** +``` +$ sudo apt-get update +$ sudo apt-get upgrade +``` + +**Reboot with the following command in the terminal prompt:** +``` +$ sudo reboot -n +``` + +## Sophos +>Sophos Endpoint doesn’t rely on signatures to catch malware, which means it catches zero-day threats without adversely affecting the performance of your device. So you get protection before those exploits even arrive. + +Raise Assist with CT for adding Sophos Endpoint + +--- + +## Java SDK +>The Java Development Kit (JDK) is a software development environment used for developing Java applications and applets. It includes the Java Runtime + +**Use Webup8 Oracle Java8 Installer with the following commands in the terminal prompt:** +``` +$ sudo add-apt-repository ppa:webupd8team/java -y +$ sudo apt-get update +$ sudo apt-get install oracle-java8-installer +``` + +**Set Java environment variables with the following command in the terminal prompt:** +``` +$ sudo apt-get install oracle-java8-set-default +``` + +**Check the Java version with the following command in the terminal prompt:** +``` +$ java -version +``` + +**Set environment variables with the following command in the terminal prompt:** +``` +$ sudo nano /etc/environment +``` + +**Add the following to the environment file** +``` +JAVA_HOME="/usr/lib/vm/java-8-oracle" +``` + +**Refresh environment file with the following command in the terminal prompt:** +``` +$ source /etc/environment +``` + +**Set environment variables in .bashrc with the following command in the terminal prompt:** +``` +$ sudo nano ~/.bashrc +``` + +**Add the following to the .bashrc file:** +``` +export JAVA_HOME="/usr/lib/vm/java-8-oracle" +``` + +**Refresh the bash profile with the following commands in the terminal prompt:** +``` +$ source ~/.bashrc +``` + +--- + +## Android command line SDK Tools +>SDK Tools is a downloadable component for the Android SDK. It includes the complete set of development and debugging tools for the Android SDK. + +**Download the Mac SDK Tools** +[android-sdk_r24.4.1-linux.tgz](https://dl.google.com/android/android-sdk_r24.4.1-linux.tgz) + +**Unzip Android command line SDK Tools with the following commands in the terminal prompt:** +``` +$ mkdir ~/Apps +$ cd ~/Downloads/ +$ tar android-sdk*.zip +$ mv android-sdk-linux/ ~/Apps/android-sdk-linux +``` + +**Add the following to the .bashrc file:** +``` +export ANDROID_HOME="$HOME/Apps/android-sdk-linux" +export PATH=$PATH:$ANDROID_HOME/platform-tools/:$ANDROID_HOME/tools/ +``` + +**Refresh your bash profile with the following commands in the terminal prompt:** +``` +$ source ~/.bashrc +``` + +**Run the SDK Manager with the following commands in the terminal prompt:** +``` +$ sh ~/.android-sdk-linux/tools/android +``` + +**Select the following below:** + +__Under Tools__ +* Android SDK Platform-tools (Rev 25) +* Android SDK Build-tools (Rev 25) + +__Under Android 7.11 (API 25)__ +* SDK Platform (API 25) +* Google APIs Intel x86 Atom_64 System Image(API 25, Rev 2) + + +**Click Install Packages** + +[Android Developer Website](https://developer.android.com/studio/index.html) + +--- + +## Development Tools +>Build-essential is a package which contains references to numerous packages needed for building software in general + +>Git is a version control system that is used for software development and other version control tasks. + +>htop is an interactive system-monitor process-viewer. It is designed as an alternative to the Unix program top. + +>Linux Screen allows you to: Use multiple shell windows from a single SSH session. + +>curl is a command line tool for getting or sending files using URL syntax. + +**Install the following packages** +* build-essential +* git +* htop +* screen +* curl + +**Run the following command in the terminal prompt:** +``` +$ sudo apt-get install build-essential git htop screen curl +``` + +--- + +## Node Version Manager +>Node Version Manager is bash script to manage multiple active node.js versions + +**Install NVM with the following command in the terminal prompt:** +``` +$ wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.32.1/install.sh | bash +``` + +**Refresh your bash profile with the following commands in the terminal prompt:** +``` +$ source ~/.bashrc +``` + +**Verify installation with the following command in the terminal prompt:** +``` +$ nvm --version +``` + +[Node Version Manager Documentation](https://github.com/creationix/nvm#verify-installation) + +--- +## Node + +>Node.js is an open-source, cross-platform JavaScript runtime environment. + +**Install Node and NPM with the following command in the terminal prompt:** +``` +$ nvm install 6.9.0 +$ npm i -g npm@3.10.7 +$ nvm use 6.9.0 +$ nvm alias default 6.9.0 + +``` + +**Verify Node version 6.9.0 and npm version 3.10.7 with the following command in the terminal prompt:** +``` +$ node -v && npm -v +``` +--- + +## Node Packages +Install the following node packages with specified versions + +* gulp +* cordova +* ionic +* jspmw +* bower +* npm-check +* npm-install-missing +* phantomjs-prebuilt +* sinopia +* pm2 + +**Install Node Packages with the following command in the terminal prompt:** +``` +$ npm i -g gulp cordova ionic jspm bower npm-check npm-install-missing phantomjs-prebuilt sinopia pm2 +``` + +**List installed Node Packages with the following command in the terminal prompt:** +``` +$ npm ls -g --depth=0 +``` + +--- + +## Sinopia +>Sinopia is a private / caching npm repository server + +**Install Sinopia with the following command in the terminal prompt:** +``` +$ npm i sinopia -g +``` + +**Run Sinopia with the following command in the terminal prompt:** +``` +$ sinopia +``` + +**Set npm registry to Sinopia with the following command in the terminal prompt:** +``` +$ npm set registry http://localhost:4873/ +``` +**Set add user to Sinopia with the following command in the terminal prompt:** +``` +$ npm adduser --registry http://localhost:4873/ +``` + +Username: mobileappsteam +Password: [Transport AODB Mobile Thycotic Secret Server](https://secrettransport.pdats.com) +Email: MobileAppsTeam@leidos.com + +**Clone local-Chromaux git repository with the following commands in the terminal prompt:** +``` +$ cd $HOME/dev +$ git clone http://i-t-v-tf01:8080/tfs/Transport/Chroma%20Refresh/_git/UX +``` + +**Run the gulp command to export Chroma.UX with the following commands in the terminal prompt:** +``` +$ cd $HOME/dev/UX/Chroma.UX/ +$ npm install +$ gulp newexport +``` + +**Check the npm config file has the value registry=http://localhost:4873/ with the following command in the terminal prompt:** +``` +$cat ~/.npmrc +``` + +**Publish the Chroma.UX package to Sinopia with the following commands in the terminal prompt:** +``` +$ cd $HOME/dev/UX/local-chromaux/ +$ npm publish . +``` + +[Sinopia Documentation](https://www.npmjs.com/package/sinopia) + +--- + +## PM2 Process Management +>PM2 is a production process manager for Node.js applications with a built-in load balancer. It allows you to keep applications alive forever, to reload them without downtime and to facilitate common system admin tasks. + +**Install PM2 with the following command in the terminal prompt:** +``` +$ npm i pm2@latest -g +``` + +**Setup Auto-Completion with the following command in the terminal prompt:** +``` +$ pm2 completion >> ~/.bashrc +``` + +**Create a process configuration JSON file as ~/process.json** + +```json +{ + "apps" : [ + { + "name" : "Sinopia", + "script" : "/home/mobileappsteam/.nvm/versions/node/v4.4.7/bin/sinopia", + "cwd" : "/home/mobileappsteam", + "watch" : false, + "instances" : 1, + "combine_logs" : true, + "max_memory_restart" : "300M", + "restart_delay" : 5000 + } + + ] +} +``` + + +**Generate startup scripts with the following command in the terminal prompt:** +``` +$ pm2 startup ubuntu +``` + +**Following with be generated** +``` +PM2] You have to run this command as root. Execute the following command: +sudo su -c "env PATH=$PATH:/home/mobileappsteam/.nvm/versions/node/v6.9.0/bin pm2 startup ubuntu -u mobileappsteam --hp /home/mobileappsteam" +``` + +**Run the generated command in the terminal prompt:** +``` +$ sudo su -c "env PATH=$PATH:/home/mobiledev/.nvm/versions/node/v6.9.0/bin pm2 startup ubuntu -u mobiledev --hp /home/mobiledev" +``` + +**Save PM2 changes with the following command in the terminal prompt:** +``` +$ pm2 save +``` + +**Start with the following command in the terminal prompt:** +``` +$ pm2 start ~/profile.json +``` + +**Additional Commands** +``` +$ pm2 kill +$ pm2 monit +$ pm2 list +$ pm2 log 0 +``` + +[PM2 documentation](http://pm2.keymetrics.io/docs/usage/quick-start/) + +--- + +## WebStorm +>WebStorm is a JavaScript IDE for client-side development and server-side development with Node.js. + +[WebStorm Website](https://www.jetbrains.com/webstorm/) + +--- + +## Visual Studio Code +>Visual Studio Code is a source code editor developed by Microsoft for Windows, Linux and macOS. It includes support for debugging, embedded Git control, syntax highlighting, intelligent code completion, snippets, and code refactoring. + +[Download Visual Studio Code](http://code.visualstudio.com) + +--- + +## Chromium +>Chromium is the open-source web browser project from which Google Chrome draws its source code.[5] The browsers share the majority of code and features, though there are some minor differences in features and they have different licensing. + + +**Install Chromium with the following command in the terminal prompt:** +``` +$ sudo apt-get install chromium-browser +``` + +--- + +## Brackets +>Brackets is an open source code editor for web designers and front-end developers. + +**Install Brackets with the following commands in the terminal prompt:** + +``` +$ sudo add-apt-repository ppa:webupd8team/brackets +$ sudo apt-get update +$ sudo apt-get install brackets +``` + +--- \ No newline at end of file diff --git a/angular-ios9-uiwebview.patch.js b/angular-ios9-uiwebview.patch.js new file mode 100644 index 0000000..58d8be1 --- /dev/null +++ b/angular-ios9-uiwebview.patch.js @@ -0,0 +1,75 @@ +/** + * ================== angular-ios9-uiwebview.patch.js v1.1.1 ================== + * + * This patch works around iOS9 UIWebView regression that causes infinite digest + * errors in Angular. + * + * The patch can be applied to Angular 1.2.0 – 1.4.5. Newer versions of Angular + * have the workaround baked in. + * + * To apply this patch load/bundle this file with your application and add a + * dependency on the "ngIOS9UIWebViewPatch" module to your main app module. + * + * For example: + * + * ``` + * angular.module('myApp', ['ngRoute'])` + * ``` + * + * becomes + * + * ``` + * angular.module('myApp', ['ngRoute', 'ngIOS9UIWebViewPatch']) + * ``` + * + * + * More info: + * - https://openradar.appspot.com/22186109 + * - https://github.com/angular/angular.js/issues/12241 + * - https://github.com/driftyco/ionic/issues/4082 + * + * + * @license AngularJS + * (c) 2010-2015 Google, Inc. http://angularjs.org + * License: MIT + */ + +angular.module('ngIOS9UIWebViewPatch', ['ng']).config(['$provide', function($provide) { + 'use strict'; + + $provide.decorator('$browser', ['$delegate', '$window', function($delegate, $window) { + + if (isIOS9UIWebView($window.navigator.userAgent)) { + return applyIOS9Shim($delegate); + } + + return $delegate; + + function isIOS9UIWebView(userAgent) { + return /(iPhone|iPad|iPod).* OS 9_\d/.test(userAgent) && !/Version\/9\./.test(userAgent); + } + + function applyIOS9Shim(browser) { + var pendingLocationUrl = null; + var originalUrlFn= browser.url; + + browser.url = function() { + if (arguments.length) { + pendingLocationUrl = arguments[0]; + return originalUrlFn.apply(browser, arguments); + } + + return pendingLocationUrl || originalUrlFn.apply(browser, arguments); + }; + + window.addEventListener('popstate', clearPendingLocationUrl, false); + window.addEventListener('hashchange', clearPendingLocationUrl, false); + + function clearPendingLocationUrl() { + pendingLocationUrl = null; + } + + return browser; + } + }]); +}]); diff --git a/app-settings.json b/app-settings.json new file mode 100644 index 0000000..678f899 --- /dev/null +++ b/app-settings.json @@ -0,0 +1,12 @@ +[ + { + "type":"group", + "title":"Common", + "items":[{ + "title":"API URL", + "type":"textfield", + "key":"apiurl", + "default": "10.3.90.7" + }] + } +] diff --git a/app/authentication/auth.mod.ts b/app/authentication/auth.mod.ts new file mode 100644 index 0000000..322db3a --- /dev/null +++ b/app/authentication/auth.mod.ts @@ -0,0 +1,19 @@ +import AuthConfig = require('./auth.routes'); +import Dectorators = require('../infrastructure/Dectorators/Components'); +import authenticationService = require('./services/authentication.service'); +import authenticationInterceptor = require('./services/authentication.interceptor'); +import LoginComponent = require('./components/login-view/login'); + + +@Dectorators.module('auth') +export class Mod { + constructor(angular: ng.IAngularStatic) { + angular.module(Mod.$componentName, []) + .factory(authenticationService.AuthenticationService.$componentName, authenticationService.AuthenticationService.$factory) + .factory(authenticationInterceptor.AuthenticationInterceptor.$componentName, + authenticationInterceptor.AuthenticationInterceptor.$factory) + .controller(LoginComponent.Controller.$componentName, LoginComponent.Controller) + .directive(LoginComponent.Directive.$componentName, LoginComponent.Directive.$factory) + .config(AuthConfig.Config); + } +} diff --git a/app/authentication/auth.routes.ts b/app/authentication/auth.routes.ts new file mode 100644 index 0000000..12cd100 --- /dev/null +++ b/app/authentication/auth.routes.ts @@ -0,0 +1,27 @@ +export class Config { + static $inject: Array = ['$stateProvider', + '$urlRouterProvider', + '$httpProvider']; + + constructor($stateProvider: ng.ui.IStateProvider, + $urlRouterProvider: ng.route.IRouteProvider, + $httpProvider: ng.IHttpProvider) { + + $stateProvider.state('login', { + url: '/login', + params: { + hasLoggedOut: false, + redirected: false + }, + template: '
' + + ' ' + + '
' + }); + + $stateProvider.state('logout', { + url: '/logout' + }); + + $httpProvider.interceptors.push('authenticationInterceptor'); + } +} diff --git a/app/authentication/components/login-view/login.less b/app/authentication/components/login-view/login.less new file mode 100644 index 0000000..5a10877 --- /dev/null +++ b/app/authentication/components/login-view/login.less @@ -0,0 +1,93 @@ +#loginbox .panel { + box-shadow: 0 1px 11px rgba(0,0,0,.27); +} + +#login-form { + display: flex; + flex-direction: column; + align-items: center; + margin-top: 60px; + + .item-input { + width: 100%; + margin-bottom: 8px; + border-width: 0 0 3px 0; + + input { + font-size: 110%; + margin-top: -3px; + padding-left: 20px; + color: blue; + } + } + + * { + max-width: 300px; + } +} + +#logo-text { + /*position:absolute;*/ + color: #fbfafa; + font-size: 108%; + margin-left: -10px; + padding-right: 10px; + line-height: 37px; +} + +#logo-shape { + position: absolute; + top: 2; + right: 14px; + height: 28px; + width: 100%; + -webkit-transform: skew(24deg); + transform: skew(24deg); + margin-left: -10px; + margin-top: 1px; + z-index: -1; +} + +@media (max-width: 360px) and (min-width: 360px) { + #logo-shape { + margin-top: 0px; + } +} + +#chroma-text { + display: inline-block; + color: #00398A; + line-height: 37px; +} + +#chroma-logo { +} + +#chroma-logo-identifier { + display: inline-block; + position: relative; +} + +#login-button { + font-size: 22px; + margin-top: 15px; + border: 1px important; + + .spinner { + stroke: white; + fill: white; + } + +} + +#version-string { + font-size: 70%; +} + +.floating-prefs { + color: red; + z-index: 1000; + position: absolute !important; + top: 10; + right: 20; +} \ No newline at end of file diff --git a/app/authentication/components/login-view/login.spec.ts b/app/authentication/components/login-view/login.spec.ts new file mode 100644 index 0000000..8d67f64 --- /dev/null +++ b/app/authentication/components/login-view/login.spec.ts @@ -0,0 +1,147 @@ +import {Mod as CoreModule} from '../../../core/core.mod'; +import {Mod as LoginModule} from '../../auth.mod'; +import {Directive, Controller} from './login'; +import {ComponentTest} from '../../../infrastructure/ComponentHelper'; +import {AuthenticationService} from '../../services/authentication.service'; +import {Mod as FlightListMod} from '../../../flight-list/flight-list.mod'; +import {FlightService, IFlightService} from '../../../core/service/flightService'; +import {Mod as SiteSelectionMod} from '../../../site-selection/site-selection.mod'; +​ +class LoginViewTest extends ComponentTest { + public api: any; + public $state: ng.ui.IStateService; + public $cookies: ng.cookies.ICookiesService; + public $stateParams: ng.ui.IStateParamsService; + public authenticationService: AuthenticationService; + public flightService: FlightService; +​ + constructor() { + super(Directive.$componentName, + 'app/authentication/components/login-view/login.tpl.html'); + this.flushOnInit = false; + } +} +​ +describe('Login:', () => { + let instance: LoginViewTest; + let ctrl: Controller; +​ + beforeEach(() => { + if (!instance) { + angular.mock.module('ui.router'); + angular.mock.module('ionic'); + angular.mock.module('ngCookies'); + angular.mock.module('chroma.configuration'); +​ + angular.mock.module(CoreModule.$componentName); + angular.mock.module(LoginModule.$componentName); + angular.mock.module(FlightListMod.$componentName); + angular.mock.module(SiteSelectionMod.$componentName); +​ + new CoreModule(angular); + new LoginModule(angular); + new FlightListMod(angular); + new SiteSelectionMod(angular); + // let cookie: ng.cookies.ICookiesService = {} + // cookie['ASP.NET_SessionId'] = 'LOLOLOL'; +​ + // let auth: AuthenticationService = new AuthenticationService(); +​ + angular.mock.inject((api, $state, $cookies, authenticationService, flightService, siteSelectionService, $stateParams) => { + instance = new LoginViewTest(); + instance.api = api; + instance.$state = $state; + instance.$cookies = $cookies; + instance.authenticationService = authenticationService; + instance.flightService = flightService; + instance.$stateParams = $stateParams; + }); + } + }); +​ + it('Directive is compiled', () => { + instance.flushOnInit = true; + ctrl = instance.compile(); + expect(ctrl).toBeDefined(); + }); +​ + //Scenario: Login success with sites to select + //TODO: Ste Oates - I have commented this out because FSWH01 user has access to multiple sites + it('Login success with sites to select', () => { + //SETUP + instance.flushOnInit = false; + instance.$httpBackend.whenPOST(instance.api.authentication).respond({ + Data: { + SiteSelectionRequired: true, + Sites: { + Sites: [{ SiteName: 'testSite1', SiteId: '1', IATACode: 'TES' }, + { SiteName: 'testSite2', SiteId: '2', IATACode: 'TEZ' }] + } + } + }); + ctrl = instance.compile(); + + //GIVEN that I am logged out of the application + expect(ctrl.isLoggedOut()).toBeTruthy(); + //AND I have access to more than one site + //WHEN I enter the correct username and Password + ctrl.username = 'storedUsername'; + ctrl.password = 'storedPassword'; + spyOn(instance.$state, 'go').and.callFake(function(){ return;}); + ctrl.login(); +​ + instance.$httpBackend.flush(); + //THEN I should be presented with a list of sites to select from +​ + expect(ctrl.sites.length).toBeGreaterThan(1); + expect(ctrl.theresMoreThanOnePossibleSite(ctrl.sites)).toBeTruthy(); + expect(instance.$state.go).toHaveBeenCalledWith('chroma.site-selection'); + }); +​ + //Scenario: Successful logout of the application + it('Logout success', () => { + instance.flushOnInit = false; + ctrl = instance.compile(); + instance.$cookies['ASP.NET_SessionId'] = 'LOLOLOL'; +​ + //GIVEN that I am logged in to the application + spyOn(instance.$state, 'go').and.callThrough(); +​ + //ctrl.authenticationService = new AuthenticationService() + expect(ctrl.isLoggedOut()).toBeFalsy(); + //WHEN I choose to logout + instance.authenticationService.logout(); + //THEN I will be logged out of the application + expect(ctrl.isLoggedOut()).toBeTruthy(); + expect(instance.$state.go).toHaveBeenCalledWith('login'); + }); +​ + it('Session expired then open app then I get re-routed back to login', () => { + instance.flushOnInit = false; +​ + instance.$httpBackend.expectGET(instance.api.flightList + '?window=default').respond(401, {}); +​ + ctrl = instance.compile(); +​ + instance.$cookies['ASP.NET_SessionId'] = 'LOLOLOL'; + //GIVEN that my session has expired + //BUT i still have a cookie + expect(ctrl.isLoggedOut()).toBeFalsy(); + //WHEN i open the app and get routed to the flight View + spyOn(instance.$state, 'go').and.callThrough(); + instance.flightService.getFilter('default', true); +​ + instance.$httpBackend.flush(); + //THEN I should be rejected and rerouted back to login + expect(instance.$state.go).toHaveBeenCalledWith('login', {redirected: true}); + }); +​ + it('should alert the user that their session has timed out if redirected', () => { + instance.flushOnInit = false; +​ + ctrl = instance.compile(); + instance.$stateParams = {hasLoggedOut: false, redirected: true}; +​ + expect(ctrl.error).toEqual('Your session has timed out please login again'); + }); +}); diff --git a/app/authentication/components/login-view/login.tpl.html b/app/authentication/components/login-view/login.tpl.html new file mode 100644 index 0000000..2303ed1 --- /dev/null +++ b/app/authentication/components/login-view/login.tpl.html @@ -0,0 +1,71 @@ + + + + + diff --git a/app/authentication/components/login-view/login.ts b/app/authentication/components/login-view/login.ts new file mode 100644 index 0000000..2c37197 --- /dev/null +++ b/app/authentication/components/login-view/login.ts @@ -0,0 +1,188 @@ +import {controller, directive} from '../../../infrastructure/Dectorators/Components'; +import {AuthenticationService, IAuthData, IAuthenticationService} from '../../services/authentication.service'; +import {Mod} from '../../auth.mod'; + +export class Resources { + static USERNAME_MISSING: string = 'Please enter your username'; + static PASSWORD_MISSING: string = 'Please enter your password'; + static REDIRECTED_DUE_TO_TIMEOUT = 'Your session has timed out please login again'; +} + +export interface ILoginScope extends ng.IScope { + vm: Controller; +} + +export interface ISite { + SiteName: string; + SiteId: string; + IATACode: string; +} + +@controller(Mod, 'loginViewController', ['$ionicHistory', 'authenticationService', '$state', '$stateParams', 'siteSelectionService']) +export class Controller { + static cName: string = 'loginViewController'; + public error: string; + public sites: Array; + public status: string; + public username: string; + public password: string; + public versionString: string; + public prefs: any; + + constructor( + private $ionicHistory: any, + private authenticationService: AuthenticationService, + private $state: ng.ui.IStateService, + public $stateParams: ng.ui.IStateParamsService, + public siteSelectionService: any) { + let looseParams: any = this.$stateParams; + let redirected: Boolean = looseParams.redirected; + this.status = 'awaitingLogin'; + this.versionString = 'Version: 00000'; + this.prefs = (typeof AppPreferences !== 'undefined') ? new AppPreferences() : plugins.appPreferences; + if (typeof cordova !== 'undefined' && typeof cordova.getAppVersion !== 'undefined') { + cordova.getAppVersion.getVersionNumber().then(function (version) { + this.versionString = version; + angular.element($('#version-string')).scope().$apply(); + }.bind(this)); + } + + if (redirected === true) { + this.error = Resources.REDIRECTED_DUE_TO_TIMEOUT; + } + + document.addEventListener('resume', function () { + // Cordova resumes + this.retrieveSettings(); + }.bind(this), false); + + document.addEventListener('deviceready', function () { + this.retrieveSettings(); + }.bind(this), false); + } + + public login() { + if (this.loginIsValid()) { + this.status = 'loggingIn'; + this.authenticationService.authenticate(this.username, this.password).then((response: any) => { + if (response.error !== undefined) { + this.error = response.error; + } else if (response.Data && response.Data.LoginSuccess === false) { + this.error = 'Invalid Username/Password entered'; + this.status = 'awaitingLogin'; + } else { + if (response.Data.Error !== undefined && response.Data.Error === true) { + this.error = 'something went wrong connecting to the server'; + this.status = 'awaitingLogin'; + return; + } + if (response.Data.LoginSuccess !== undefined && response.Data.LoginSuccess === false) { + this.error = 'Invalid Username/Password entered'; + this.status = 'awaitingLogin'; + return; + } + this.sites = response.Data.Sites.Sites; + if (this.theresMoreThanOnePossibleSite(this.sites)) { + this.storeSites(this.sites); + this.$state.go('chroma.site-selection'); + } else { + this.$state.go('chroma.flight-list'); + } + } + this.status = 'awaitingLogin'; + }).catch(() => { + this.error = 'Invalid Username/Password entered'; + this.status = 'awaitingLogin'; + }); + } + } + + public retrieveSettings() { + function ok(value) { + this.authenticationService.updateApi(value); + } + + function fail(error) { + console.error(error); + } + + this.prefs.fetch(ok.bind(this), fail, 'apiurl'); + }; + + public showSettings() { + function fail (error) { + console.error(error); + } + + this.prefs.show(null, fail); + } + + public theresMoreThanOnePossibleSite(sites: Array): Boolean { + if (sites.length > 1) { + return true; + } + return false; + } + + public storeSites(sites: Array): void { + this.siteSelectionService.storeAvailableSites(sites); + } + + public isLoggedOut(): Boolean { + return this.authenticationService.isLoggedOut(); + } + + public loginIsValid() { + if (!this.username || this.username === '') { + this.error = Resources.USERNAME_MISSING; + return false; + } + + if (!this.password || this.password === '') { + this.error = Resources.PASSWORD_MISSING; + return false; + } + + return true; + } +} + +@directive(Mod, 'chromaLoginView', ['$stateParams']) +export class Directive implements ng.IDirective { + controller: any = Controller.$componentName; + controllerAs: string = 'vm'; + templateUrl: string = 'app/authentication/components/login-view/login.tpl.html'; + restrict: string = 'E'; + scope: any = {}; + + constructor(private $stateParams: ng.ui.IStateParamsService) { + } + + link: ng.IDirectiveLinkFn = (scope: ILoginScope, element: ng.IAugmentedJQuery) => { + let loseParams: any = this.$stateParams; + let hasLoggedOut: Boolean = loseParams.hasLoggedOut; + + var loginForm = $('#login-form'); + var height = loginForm.height(); + + loginForm.height(0); + loginForm.css('opacity', 0); + + var logo = $('#chroma-logo'); + logo.css('opacity', 0); + + var animationDuration = 500; + + setTimeout(() => { + logo.fadeTo(animationDuration, 1); + + setTimeout(() => { + loginForm.animate({ height: height + 30 }, + animationDuration, () => { + loginForm.fadeTo(animationDuration, 1); + }); + + }, animationDuration); + }, 200); + } +} diff --git a/app/authentication/services/authentication.interceptor.ts b/app/authentication/services/authentication.interceptor.ts new file mode 100644 index 0000000..20973d9 --- /dev/null +++ b/app/authentication/services/authentication.interceptor.ts @@ -0,0 +1,19 @@ +import {controller, directive, factory} from '../../infrastructure/Dectorators/Components'; +import {Mod} from '../auth.mod'; + +@factory(Mod, 'authenticationInterceptor', ['$q', '$injector']) +export class AuthenticationInterceptor { + constructor(private $q: ng.IQService, private $injector: ng.auto.IInjectorService) { + }; + + responseError = (rejection) => { + let state: ng.ui.IStateService = this.$injector.get('$state'); + + if (rejection.status === 401) { + state.go('login', { redirected: true }); + return this.$q.reject(rejection); + } + + return this.$q.reject(rejection); + } +} diff --git a/app/authentication/services/authentication.service.ts b/app/authentication/services/authentication.service.ts new file mode 100644 index 0000000..15b4679 --- /dev/null +++ b/app/authentication/services/authentication.service.ts @@ -0,0 +1,77 @@ +import {controller, directive, factory} from '../../infrastructure/Dectorators/Components'; +import {Mod} from '../auth.mod'; + +export interface IAuthenticationService { + authenticate(username: string, password: string): ng.IPromise; + logout(): void; +} + +export interface IAuthData { + error: string; +} + +@factory(Mod, 'authenticationService', ['$http', '$q', '$cookies', 'api', '$state']) +export class AuthenticationService implements IAuthenticationService { + + constructor(private $http: ng.IHttpService, + private $q: ng.IQService, + private $cookies: ng.cookies.ICookiesService, + private api: any, + private $state: ng.ui.IStateService) { + } + + authenticate(username: string, password: string): ng.IPromise { + var data = { + Username: username, + Password: password, ActiveDirectoryUsername: '' + }; + + return this.$http.post(this.api.authentication, data).then((response: ng.IHttpPromiseCallbackArg) => { + if (response.data) { + return response.data; + } + }, (error: any) => { return { error: 'Unable to connect to Chroma' }; }); + } + + isLoggedOut(): Boolean { + if (this.$cookies['ASP.NET_SessionId'] != null) { + return false; + } + return true; + }; + + logout(): void { + delete this.$cookies['ASP.NET_SessionId']; + this.$state.go('login'); + }; + + updateApi(_newBase:string): void { + let newBase = _newBase; + let validPrefix = /^(ftp|http|https):\/\/[^ "]+$/.test(newBase); + + if (!validPrefix) { + newBase = 'http://' + newBase; + } + + newBase = newBase.replace(/\/?$/, ''); + + this.api.endpoint = newBase + '/api/'; + this.api.flightList = newBase + '/api/flights'; + this.api.authentication = newBase + '/api/auth'; + this.api.detail = newBase + '/api/detail/'; + this.api.imageSource = newBase + '/api/GetOperatorImage'; + this.api.setSite = newBase + '/api/setSite'; + this.api.getWindows = newBase + '/api/getWindows'; + this.api.transactions = newBase + '/api/transactions'; + this.api.cancelTransaction = newBase + '/api/cancelTransaction'; + this.api.confirmTransaction = newBase + '/api/confirmTransaction'; + this.api.createTransaction = newBase + '/api/createTransaction'; + this.api.getTransactionCodes = newBase + '/api/getTransactionCodes'; + this.api.getTransactionsAccess = newBase + '/api/getUserAccessRightsForTransaction'; + this.api.getTransactionConfig = newBase + '/api/getTransactionConfig'; + this.api.signalrHubs = newBase + '/signalr/hubs'; + this.api.prmList = newBase + '/api/prmList'; + + }; + +} diff --git a/app/chroma.app.ts b/app/chroma.app.ts new file mode 100644 index 0000000..dd082d6 --- /dev/null +++ b/app/chroma.app.ts @@ -0,0 +1,95 @@ +import Auth = require('./authentication/auth.mod'); +import Core = require('./core/core.mod'); +import FlightList = require('./flight-list/flight-list.mod'); +import FlightDetail from './flight-detail/flight-detail.mod'; +import SiteSelection = require('./site-selection/site-selection.mod'); +import {Mod as WindowList} from './window-list/window-list.mod'; + +export class App { + + static appName: string = 'chroma.app'; + + dep: Array = ['ui.router', + 'ionic', + 'ngCookies', + 'ngIOS9UIWebViewPatch', + 'chroma.templates', + 'chroma.configuration', + 'chroma.framework']; + + mods: Array = [ + Core.Mod.$componentName, + Auth.Mod.$componentName, + FlightList.Mod.$componentName, + FlightDetail.$componentName, + SiteSelection.Mod.$componentName, + WindowList.$componentName + ]; + + auth: Auth.Mod; + core: Core.Mod; + flightList: FlightList.Mod; + flightDetail: FlightDetail; + SiteSelection: SiteSelection.Mod; + windowList: WindowList; + + constructor(angular: ng.IAngularStatic) { + this.auth = new Auth.Mod(angular); + this.core = new Core.Mod(angular); + this.flightList = new FlightList.Mod(angular); + this.flightDetail = new FlightDetail(angular); + this.SiteSelection = new SiteSelection.Mod(angular); + this.windowList = new WindowList(angular); + + angular.module(App.appName, this.dep.concat(this.mods)).config(( + $ionicConfigProvider: ionic.utility.IonicConfigProvider, + $compileProvider: ng.ICompileProvider, + $httpProvider: ng.IHttpProvider, $provide: any) => { + + $ionicConfigProvider.navBar.alignTitle('center'); + $ionicConfigProvider.views.maxCache(0); + + $httpProvider.defaults.withCredentials = true; + $compileProvider.debugInfoEnabled(false); + + $provide.decorator('$exceptionHandler', ['$delegate', '$injector', ($delegate, $injector) => (exception, cause) => { + $delegate(exception, cause); + let alertBox: ionic.popup.IonicPopupService = $injector.get('$ionicPopup'); + let instance: ionic.popup.IonicPopupPromise = alertBox.show({ + template: `
+ ${exception} +
+ Restarting the AODB is recommended.
+
`, + title: 'Unexpected Error', + buttons: [ + { + text: 'Continue', onTap: (e) => { + instance.close(); + } + }, + { + text: 'Close App', + type: 'button-assertive', + onTap: function(e) { + let ionicInstance: any = ionic; + ionicInstance.Platform.exitApp(); + } + } + ] + }); + }]); + }).run(function($ionicPlatform) { + $ionicPlatform.registerBackButtonAction(function(e) { + e.preventDefault(); + return false; + }, 101); + }); + + angular.bootstrap(document, [App.appName]); + + if (typeof hockeyapp !== 'undefined') { + hockeyapp.start(null, null, '8ca6b61ff4374109b416a476ceb29688'); + } + } +} diff --git a/app/core/core.config.ts b/app/core/core.config.ts new file mode 100644 index 0000000..3843dd2 --- /dev/null +++ b/app/core/core.config.ts @@ -0,0 +1,23 @@ +import {ChromaStateService} from './service/chromaStateService'; + +export class Routes { + static $inject: Array = ['$stateProvider', + '$urlRouterProvider', + '$httpProvider', + 'chromaStateProvider']; + constructor($stateProvider: ng.ui.IStateProvider, + $urlRouterProvider: ng.route.IRouteProvider, + $httpProvider: ng.IHttpProvider, + chromaStateProvider: ChromaStateService) { + + chromaStateProvider.setStateProvider($stateProvider); + + $stateProvider.state('chroma', { + url: '/chroma', + abstract: false, + template: '' + }); + + $urlRouterProvider.otherwise('/login'); + } +} diff --git a/app/core/core.mod.ts b/app/core/core.mod.ts new file mode 100644 index 0000000..cffa60b --- /dev/null +++ b/app/core/core.mod.ts @@ -0,0 +1,23 @@ +import {module} from '../infrastructure/Dectorators/Components'; +import {Routes} from './core.config'; +import {FlightService, IFlightService} from './service/flightService'; +import {SignalrService, ISignalrService} from './service/signalRService'; +import {PushHandlerService, IPushHandlerService} from './service/pushHandler.service'; +import {FocusMe} from './service/helpers'; +import {ChromaStateService, IChromaStateService} from './service/chromaStateService'; +import {Directive as FrameDir, Controller as FrameCtrl} from './frame/frame'; + +@module('core') +export class Mod { + constructor(angular: ng.IAngularStatic) { + angular.module(Mod.$componentName, []) + .factory(SignalrService.$componentName, SignalrService.$factory) + .factory(PushHandlerService.$componentName, PushHandlerService.$factory) + .provider(ChromaStateService.$componentName, ChromaStateService) + .factory(FlightService.$componentName, FlightService.$factory) + .controller(FrameCtrl.$componentName, FrameCtrl) + .directive(FrameDir.$componentName, FrameDir.$factory) + .directive(FocusMe.$componentName, FocusMe.$factory) + .config(Routes); + } +} diff --git a/app/core/frame/frame.less b/app/core/frame/frame.less new file mode 100644 index 0000000..394847e --- /dev/null +++ b/app/core/frame/frame.less @@ -0,0 +1,36 @@ + +.flight-menu { + background-color: #eaebec; + padding-top: 44px; + + a { + background-color: #eaebec; + + &.selected { + background-color: white !important; + + i { + color: #00398a; + } + } + } + + .item { + border: 0 important; + } + + i { + font-size: 200%; + color: #5d5d5d; + } +} + +.bar { + //background-color: #00398A !important; + border-bottom: 3px solid #F7F1F1; + + .title { + color: #00398a; + font-family: Roboto-Thin; + } +} diff --git a/app/core/frame/frame.spec.ts b/app/core/frame/frame.spec.ts new file mode 100644 index 0000000..4efa701 --- /dev/null +++ b/app/core/frame/frame.spec.ts @@ -0,0 +1,113 @@ + +import {Directive, Controller} from './frame' +import {ComponentTest} from '../../infrastructure/ComponentHelper' +import {Mod as Core} from '../../core/core.mod'; +import {Mod as Auth} from '../../authentication/auth.mod'; + +class FrameViewTest extends ComponentTest { + public $state: ng.ui.IStateService; + public $window: ng.IWindowService; + public $rootScope: ng.IRootScopeService; + public $ionicHistory: ionic.navigation.IonicHistoryService; + constructor() { + super(Directive.$componentName, 'app/core/frame/frame.tpl.html'); + } +} + +describe('Frame: ', () => { + let test: FrameViewTest, + ctrl: Controller; + + beforeEach(() => { + new Core(angular); + new Auth(angular); + + angular.mock.module('ui.router'); + angular.mock.module('ionic'); + angular.mock.module('chroma.configuration'); + angular.mock.module('ngCookies'); + + angular.mock.module(Core.$componentName); + angular.mock.module(Auth.$componentName); + }); + + beforeEach(() => { + angular.mock.inject(($state, $window, $rootScope, $ionicHistory) => { + test = new FrameViewTest(); + test.$state = $state; + test.$window = $window; + test.$rootScope = $rootScope; + test.$ionicHistory = $ionicHistory; + ctrl = test.compile(); + }); + }); + + it('Directive can be compiled', () => { + expect(ctrl).toBeDefined(); + }) + + it('When no matches, IonicBack is not called', () => { + spyOn(test.$ionicHistory, 'goBack'); + ctrl.currentState = 'chroma.undefined-state'; + ctrl.back(); + expect(test.$ionicHistory.goBack).not.toHaveBeenCalled(); + }) + + + it('Logout called if back pressed without state', () => { + spyOn(ctrl.authenticationService, 'logout'); + ctrl.back(); + expect(ctrl.authenticationService.logout).toHaveBeenCalled(); + }) + + it('Logout called if back pressed on Site Selection state', () => { + spyOn(ctrl.authenticationService, 'logout'); + ctrl.currentState = 'chroma.site-selection'; + ctrl.back(); + expect(ctrl.authenticationService.logout).toHaveBeenCalled(); + }) + + it('Window List called if back pressed on flight List state', () => { + spyOn(test.$state, 'go'); + ctrl.currentState = 'chroma.flight-list'; + ctrl.back(); + expect(test.$state.go).toHaveBeenCalledWith('chroma.window-list'); + }) + + it('Site Selection List called if back pressed on Window List state', () => { + spyOn(test.$state, 'go'); + ctrl.currentState = 'chroma.window-list'; + ctrl.back(); + expect(test.$state.go).toHaveBeenCalledWith('chroma.site-selection'); + }) + + it('Flight List NOT called if back pressed on Flight Detail state and not saved filter', () => { + spyOn(test.$state, 'go'); + spyOn(test.$window.sessionStorage, 'getItem').and.returnValue(undefined); + ctrl.currentState = 'chroma.flight-detail'; + ctrl.back(); + expect(test.$state.go).not.toHaveBeenCalledWith('chroma.flight-list', { filter: 'test-filter' }); + }) + + it('Flight List called if back pressed on Flight Detail state', () => { + spyOn(test.$state, 'go'); + spyOn(test.$window.sessionStorage, 'getItem').and.returnValue('test-filter'); + ctrl.currentState = 'chroma.flight-detail'; + ctrl.back(); + expect(test.$state.go) + .toHaveBeenCalledWith('chroma.flight-list', { filter: 'test-filter' }); + }) + + it('Current State is updated on $steChangeStart event', () =>{ + let testState : string = 'test-state123'; + test.$rootScope.$emit('$stateChangeStart', {name : testState}); + expect(ctrl.currentState).toBe(testState); + }); + + it('isFlightDetailState stays insync with current state', () =>{ + let testState : string = 'flight-detail'; + test.$rootScope.$emit('$stateChangeStart', {name : testState}); + expect(ctrl.currentState).toBe(testState); + expect(ctrl.isFlightDetailState).toBe(true); + }); +}) diff --git a/app/core/frame/frame.tpl.html b/app/core/frame/frame.tpl.html new file mode 100644 index 0000000..4301173 --- /dev/null +++ b/app/core/frame/frame.tpl.html @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + +

Chroma Mobile

+
+ + + Select Site + + + Logout + + +
+ + + + + + + + +
diff --git a/app/core/frame/frame.ts b/app/core/frame/frame.ts new file mode 100644 index 0000000..5f4adfd --- /dev/null +++ b/app/core/frame/frame.ts @@ -0,0 +1,73 @@ +import {directive, controller} from '../../infrastructure/Dectorators/Components'; +import {IChromaStateService} from '../../core/service/chromaStateService'; +import Core = require('../core.mod'); +import {AuthenticationService} from '../../authentication/services/authentication.service'; +import {IPushHandlerService} from '../../core/service/pushHandler.service'; + +@directive(Core.Mod, 'chromaFrame', []) +export class Directive implements ng.IDirective { + templateUrl: string = 'app/core/frame/frame.tpl.html'; + restrict: string = 'E'; + controllerAs: string = 'vm'; + controller: string = Controller.$componentName; + scope: any = {}; +} + +@controller(Core.Mod, 'frameController', ['$rootScope', '$ionicHistory', '$window', '$state', '$ionicPlatform', 'chromaState', 'authenticationService', 'pushHandlerService']) +export class Controller { + public currentState: string; + public states: Array; + public isFlightDetailState: boolean = false; + constructor( + private $rootScope: ng.IRootScopeService, + private $ionicHistory: ionic.navigation.IonicHistoryService, + private $window: ng.IWindowService, + private $state: ng.ui.IStateService, + private $ionicPlatform: ionic.platform.IonicPlatformService, + + private chromaState: IChromaStateService, + public authenticationService: AuthenticationService, + private pushHandlerService: IPushHandlerService + ) { + this.$rootScope.$on('$stateChangeStart', (event, toState) => { + this.currentState = toState.name; + this.isFlightDetailState = this.IsState('flight-detail'); + }); + this.states = this.chromaState.states; + this.pushHandlerService.registerForNotifications(); + + + this.$ionicPlatform.onHardwareBackButton((e) => { + e.stopPropagation(); + this.back(); + }); + this.states = this.chromaState.states; + } + public logout(): void { + this.authenticationService.logout(); + } + public goToSiteSelection(): void { + this.$state.go('chroma.site-selection'); + } + public back(): void { + if (this.currentState === undefined) { + this.logout(); + } else if (this.IsState('chroma.site-selection')) { + this.authenticationService.logout(); + } else if (this.IsState('chroma.flight-list')) { + this.$state.go('chroma.window-list'); + } else if (this.IsState('chroma.window-list')) { + this.$state.go('chroma.site-selection'); + } else if (this.IsState('chroma.flight-detail.transaction-detail')) { + this.$state.go('chroma.flight-detail.transaction-list'); + } else if (this.IsState('chroma.flight-detail')) { + let filter = this.$window.sessionStorage.getItem('chroma:current-filter'); + if (filter) { + this.$state.go('chroma.flight-list', { filter: filter }); + } + } + } + private IsState(state: string): boolean { + return this.currentState.indexOf(state) > -1; + } +} diff --git a/app/core/less/aodb.less b/app/core/less/aodb.less new file mode 100644 index 0000000..7e34913 --- /dev/null +++ b/app/core/less/aodb.less @@ -0,0 +1,117 @@ +@primary-color: #00398a; + +.primary-color { + color: @primary-color !important; +} + +.primary-background { + background-color: @primary-color; +} + +.white { + color: white !important; +} + +.bar .button.button-clear { + color: @primary-color !important; +} + +.arrival-col { + color: #fd2424; +} + +.departure-col { + color: red; +} + +input { + color: #8c8c8c !important; +} + +.spinner { + &.primary-color { + stroke: @primary-color; + fill: @primary-color; + } +} + +.list-search { + margin: 0 0 25px; +} + +button { + &.action { + background-color: transparent; + color: @primary-color !important; + border-color: @primary-color !important; + } + + &.action { + &:hover { + background-color: @primary-color !important; + color: white !important; + } + } +} + +.pull-right { + float: right; +} + +/*.popup { + margin-top: -200px; +}*/ + +.chroma-list { + .card { + &.ng-enter { + animation: fadeInRight 0.3s; + } + + &.ng-leave { + animation: fadeOutLeft 0.3s; + } + + &.ng-enter-stagger { + animation-delay: 25ms; + animation-duration: 0; + } + } + + .chroma-list-item { + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); + padding: 15px; + border-color: #F3F1F1; + + &.ng-enter { + animation: fadeInRight 0.3s; + } + + &.ng-leave { + animation: fadeOutLeft 0.3s; + } + + &.ng-enter-stagger { + animation-delay: 25ms; + animation-duration: 0; + } + } +} + +.errors { + margin-top: 25px; + background-color: white; + padding: 10px; + border: 1px solid red; + color: red; +} + +.card .item:last-child, .list-inset .item:last-child, .padding > .list .item:last-child { + border-radius: 0; +} + + +.no-animate { + -webkit-transition: none !important; + transition: none !important; +} \ No newline at end of file diff --git a/app/core/service/chromaStateService.ts b/app/core/service/chromaStateService.ts new file mode 100644 index 0000000..8144733 --- /dev/null +++ b/app/core/service/chromaStateService.ts @@ -0,0 +1,50 @@ +import {Mod} from '../core.mod'; +import {service} from '../../infrastructure/Dectorators/Components'; + +export interface IChromaStateService { + states: Array; + addState(name: string, state: IState); + stateProvider: ng.ui.IStateProvider; +} + +interface IState extends ng.ui.IState { + display: any; + icon: any; + subView: boolean; +} + +@service(Mod, 'chromaState') +export class ChromaStateService implements ng.IServiceProvider { + + public stateProvider: ng.ui.IStateProvider; + public states: Array = new Array(); + + public setStateProvider($stateProvider: ng.ui.IStateProvider) { + this.stateProvider = $stateProvider; + } + + + public $get(): IChromaStateService { + return { + stateProvider: this.stateProvider, + states: this.states, + addState: (name: string, state: IState) => { + let added = false; + this.states.forEach((s) => { + if (s.name === name) { + added = true; + } + }); + if (!added) { + this.states.push({ + name: name, + display: state.display, + icon: state.icon, + subView: state.subView + }); + this.stateProvider.state(name, state); + } + } + }; + } +} diff --git a/app/core/service/flightService.ts b/app/core/service/flightService.ts new file mode 100644 index 0000000..0756b87 --- /dev/null +++ b/app/core/service/flightService.ts @@ -0,0 +1,51 @@ +import Dectorators = require('../../infrastructure/Dectorators/Components'); +import Core = require('../core.mod'); + +export interface IFlightListRequest { + Flights: Array; + RequestId: string; +} + +export interface IFlightDetail { + Id: string; + PhysFlightId: string; + Type: string; + Number: string; + Operator: string; + AircraftType: string; + Registration: string; + Location: string; + Scheduled: string; + Estimated: string; + Actual: string; + Terminal: string; + Stand: string; + FlightConcat: string; +} + +export interface IFlightService { + getFilter(filter: string, broadcast: boolean): ng.IPromise; +} + +@Dectorators.factory(Core.Mod, 'flightService', ['$http', '$q', '$rootScope', 'api']) +export class FlightService implements IFlightService { + + constructor(private $http: ng.IHttpService, + private $q: ng.IQService, + private $rootScope: ng.IScope, + private api: any) { + } + + public getFilter(filter: string, broadcast: boolean): ng.IPromise { + let def: ng.IDeferred = this.$q.defer(); + + this.$http.get(this.api.flightList + '?window=' + filter).success((data: any, status) => { + def.resolve(data); + if (broadcast) { + this.$rootScope.$broadcast('scroll.refreshComplete'); + } + }); + + return def.promise; + } +} diff --git a/app/core/service/helpers.ts b/app/core/service/helpers.ts new file mode 100644 index 0000000..6ae45cf --- /dev/null +++ b/app/core/service/helpers.ts @@ -0,0 +1,16 @@ +import Dectorators = require('../../infrastructure/Dectorators/Components'); +import Core = require('../core.mod'); + + +@Dectorators.directive(Core.Mod, 'focusMe', ['$timeout']) +export class FocusMe implements ng.IDirective { + restrict: string = 'EA'; + scope: any = {}; + constructor(private $timeout: ng.ITimeoutService) { + } + link: ng.IDirectiveLinkFn = (scope, element, attrs) => { + this.$timeout(() => { + element[0].focus(); + }, 750); + } +} diff --git a/app/core/service/pushHandler.service.ts b/app/core/service/pushHandler.service.ts new file mode 100644 index 0000000..e4d767d --- /dev/null +++ b/app/core/service/pushHandler.service.ts @@ -0,0 +1,60 @@ + +import {factory} from '../../infrastructure/Dectorators/Components'; +import {Mod} from '../../core/core.mod'; + + +export interface IPushHandlerService { + registerForNotifications(); + getDeviceToken(); +} + +@factory(Mod, 'pushHandlerService', ['$window']) +export class PushHandlerService implements IPushHandlerService { + constructor(private $window : ng.IWindowService) { + + } + + public registerForNotifications() { + if (PushNotification !== undefined) { // we are on the emulator otherwise + let push = PushNotification.init({ + 'android': { + 'senderID': '194436060542', + 'icon': 'icon-96-xhdpi-TransparentText.png', + 'iconColor': 'grey' + }, + 'ios': { + 'alert': 'true', + 'badge': 'true', + 'sound': 'true' + } + }); + push.on('registration', this.onRegistered); + push.on('notification', this.onNotification); + push.on('error', this.onError); + } + } + + private onNotification(data) { + //alert('got notification ' + data.additionalData.alert); + return true; + } + + private onRegistered = (data) => { + // alert('Got token ' + data.registrationId); + this.storeDeviceToken(data.registrationId); + } + + private onError(e) { + // alert('push error ' + e.message); + } + + public getDeviceToken(): string { + return this.$window.sessionStorage.getItem('chroma:device-token'); + } + + public storeDeviceToken(deviceToken: string) { + this.$window.sessionStorage.setItem('chroma:device-token', deviceToken); + } + + +} \ No newline at end of file diff --git a/app/core/service/signalRService.ts b/app/core/service/signalRService.ts new file mode 100644 index 0000000..5d3e378 --- /dev/null +++ b/app/core/service/signalRService.ts @@ -0,0 +1,63 @@ + +import {factory} from '../../infrastructure/Dectorators/Components'; +import {Mod} from '../core.mod'; +import {IPushHandlerService} from './pushHandler.service'; + + +export interface ISignalrService { + start(jq: any, callbackMethod: any, scope: any); +} + +@factory(Mod, 'signalrService', ['api', 'pushHandlerService', '$ionicPlatform']) +export class SignalrService implements ISignalrService { + + constructor(private api: any, + private pushHandlerService: IPushHandlerService, + private $ionicPlatform: any) { + } + + proxy: any; + + callbackMethod: any; + + createHub(jq : any, scope: any) { + //let jq = $; + var connection = jq.hubConnection(this.api.signalrHubs, {useDefaultPath: false}); + + var mobileHubProxy = connection.createHubProxy('mobileHub'); + + connection.logging = true; + + mobileHubProxy.on('recieveHandlingTransactionAdd', (message) => { + console.log('transaction recieved' + 'name: ' + name + 'mesage: ' + message); + this.callbackMethod('recieveHandlingTransactionAdd', scope, message); + }); + + mobileHubProxy.on('recieveHandlingTransactionCancel', (message) => { + console.log('transaction cancelled' + 'name: ' + name + 'mesage: ' + message); + this.callbackMethod('recieveHandlingTransactionCancelled', scope, message); + }); + + connection.start().done(() => { + var platform = undefined; + + if (this.$ionicPlatform.is('android')) { + platform = 1; + } + + if (this.$ionicPlatform.is('ios')) { + platform = 0; + } + + mobileHubProxy.invoke('mobileRegister', platform, this.pushHandlerService.getDeviceToken()); + }); + + } + + public start(jq : any, callbackMethod: any, scope: any) { + this.createHub(jq, scope); + this.callbackMethod = callbackMethod; + } + + +} \ No newline at end of file diff --git a/app/flight-detail/detail/flight-detail.less b/app/flight-detail/detail/flight-detail.less new file mode 100644 index 0000000..a156c39 --- /dev/null +++ b/app/flight-detail/detail/flight-detail.less @@ -0,0 +1,67 @@ +.value-holder { + width: 50%; +} + +.readonly[disabled] { + background-color: transparent !important; + color: black !important; +} + +.flight-container { + font-size: 115%; + background-color: white !important; + box-shadow: -1px 1px 1px 1px rgb(234, 232, 232); + padding: 3px 0 !important; + + .header-row { + font-size: 130%; + + .a-d-ind { + font-size: 110%; + margin-top: -3px; + } + } + + .concat { + margin-top: 15px; + font-size: 105%; + } + + .description { + } + + .field.col, + .field .row { + padding-top: 0; + } +} + +.group-list { + margin-top: 5px; + + .editor-field { + background-color: transparent !important; + + .input-label { + width: 55%; + color: #A09F9F; + } + + input { + text-overflow: ellipsis; + } + + input[disabled] { + background-color: transparent !important; + color: black !important; + } + } +} + +.rotate-45 { + transform: rotate(45deg); +} + +.rotate-225 { + transform: rotate(225deg); +} diff --git a/app/flight-detail/detail/flight-detail.spec.ts b/app/flight-detail/detail/flight-detail.spec.ts new file mode 100644 index 0000000..5d38e5f --- /dev/null +++ b/app/flight-detail/detail/flight-detail.spec.ts @@ -0,0 +1,162 @@ +import {ComponentTest} from '../../infrastructure/ComponentHelper'; +import {Directive as DetailDir, Controller as DetailCtrl, FlightDetailParams} from './flight-detail'; + +import DetailMod from '../flight-detail.mod'; +import {Mod as CoreMod} from '../../core/core.mod'; + +import {IFlightInformationModel} from '../services/flightInformationService'; +import {IFlightDetail} from '../../core/service/flightService'; + + +class FlightDetailTest extends ComponentTest { + constructor() { + super(DetailDir.$componentName, 'app/flight-detail/detail/flight-detail.tpl.html') + } +} + +class TestInstance { + public test: FlightDetailTest; + public api: any; + + public $httpBackend: ng.IHttpBackendService; + public $state: ng.ui.IStateService; + public $stateParams: ng.ui.IStateParamsService; + public $rootScope: ng.IRootScopeService; + + constructor() { + angular.mock.inject(($httpBackend, $state, $stateParams, $rootScope, api) => { + this.$httpBackend = $httpBackend; + this.$state = $state; + this.$stateParams = $stateParams; + this.$rootScope = $rootScope; + this.api = api; + }); + } + + public getSelectedFlight(): IFlightDetail { + return { + Id: '1', Type: 'A', Operator: 'SK', Number: '0214', AircraftType: '333', + Registration: 'PK-GPE', Location: 'MAN', Scheduled: '09:00', Estimated: + '09:00', Actual: '09:00', Terminal: 'T1', Stand: 'A1', FlightConcat: 'SK0214' + }; + } + + public setupForListGet(): IFlightInformationModel { + let model: IFlightInformationModel = { + Flight: undefined, + Groups: [{ "Name": "Detail", "Display": "Details", "Icon": "ion-navicon" }], + Fields: undefined, + Editors: undefined, + IsOutsideOfWindow: false + }; + + this.$httpBackend.expectGET(`${this.api.detail}?flightId=${this.getSelectedFlight().Id}&requestId=ste1234567`).respond(201, model); + + return model; + } +} + + +describe('Flight Details:', () => { + let instance: TestInstance; + + beforeEach(() => { + + new DetailMod(angular); + new CoreMod(angular); + + angular.mock.module('ui.router'); + angular.mock.module('ionic'); + angular.mock.module('chroma.configuration') + + angular.mock.module(DetailMod.$componentName); + angular.mock.module(CoreMod.$componentName); + + instance = new TestInstance(); + instance.test = new FlightDetailTest(); + }); + + describe('Framework: ChromaDateFilter', () => { + let $filter: any; + + beforeEach(() => { + angular.mock.inject((_$filter_) => { + $filter = _$filter_; + }); + }); + + it('ChromaDateFilter: If input is empty, return empty', () => { + let result = $filter('chromaDateFilter')('', false); + expect(result).toBe(''); + }); + + it('ChromaDateFilter: If input is default DateTime, return empty', () => { + let result = $filter('chromaDateFilter')('/Date(-62135596800000)/', false); + expect(result).toBe(''); + }); + + it('ChromaDateFilter: return HH:mm if not a Date request', () => { + let result = $filter('chromaDateFilter')('/Date(1447243800000)/', false); + expect(result).toBe('12:10'); + }); + + it('ChromaDateFilter: return [DD] HH:mm if a Date request', () => { + let result = $filter('chromaDateFilter')("/Date(1447243800000)/", true); + expect(result).toBe('[11] 12:10'); + }); + }); + + describe('Scenario: Viewing flights by window', () => { + //Given that I have selected a window + // And select a flight that I want to View + //Then I should see the flights information + //Grouped by category + it('Groups should be displayed', function () { + let model: IFlightInformationModel, + ctrl: DetailCtrl, + params: FlightDetailParams, + baseStateName: string, + expectedStateName: string; + + params = instance.$stateParams; + + params.flight = instance.getSelectedFlight(); + + params.requestId = 'ste1234567'; + + baseStateName = 'chroma.flight-detail.'; + + spyOn(instance.$state, "go").and.callThrough(); + + model = instance.setupForListGet(); + + ctrl = instance.test.compile() + + expectedStateName = baseStateName + model.Groups[0].Name; + + expect(instance.$state.go).toHaveBeenCalledWith(expectedStateName); + }) + + it('View title updated on navigation', function () { + let model: IFlightInformationModel, + ctrl: DetailCtrl, + params: FlightDetailParams, + newGroup: string = "NewGroup123"; + + params = instance.$stateParams; + + params.flight = instance.getSelectedFlight(); + + params.requestId = 'ste1234567'; + + model = instance.setupForListGet(); + + ctrl = instance.test.compile() + + instance.$rootScope.$emit('flightGroupChanged', { Display: newGroup }) + + expect(ctrl.viewTitle).toBe(newGroup); + }) + }) + +}) diff --git a/app/flight-detail/detail/flight-detail.tpl.html b/app/flight-detail/detail/flight-detail.tpl.html new file mode 100644 index 0000000..0de7ebd --- /dev/null +++ b/app/flight-detail/detail/flight-detail.tpl.html @@ -0,0 +1,64 @@ + + + +
+

+
This flight is outside of the selected Flight Window and is no longer viewable.
+ Go back +

+
+
+
+
+ +
+
+ +
+
+
+ + + +
+
+
+

+ {{vm.flight.Operator}}{{vm.flight.Number}} + / {{vm.flight.Location}} + / {{vm.flight.Registration}} + + A: {{vm.flight.Actual | chromaDateFilter}} + E: {{vm.flight.Estimated | chromaDateFilter}} + S: {{vm.flight.Scheduled | chromaDateFilter}} + +

+
+
+
+ {{vm.flight.AircraftType}} +
+
+ {{vm.flight.Terminal}} +
+
+ {{vm.flight.Stand}} +
+
+
+ Inbound +
+
+ Outbound +
+
+
+ +
+
+
+ +
+ +
+
diff --git a/app/flight-detail/detail/flight-detail.ts b/app/flight-detail/detail/flight-detail.ts new file mode 100644 index 0000000..a264cf8 --- /dev/null +++ b/app/flight-detail/detail/flight-detail.ts @@ -0,0 +1,169 @@ +import {controller, directive} from '../../infrastructure/Dectorators/Components'; +import {FlightListParams} from '../../flight-list/list/flight-list'; +import {IFlightDetail} from '../../core/service/flightService'; +import {IChromaStateService} from '../../core/service/chromaStateService'; +import {IFlightInformationService, IFlightInformationModel, IFlightInformationGroup, IUserAccessModel} from + '../services/flightInformationService'; +import Mod from '../flight-detail.mod'; + + +export interface FlightDetailParams extends FlightListParams { + flight: IFlightDetail; + requestId: string; +} + +@controller(Mod, 'flightDetailController', ['$stateParams', '$state', '$rootScope', '$window', 'chromaState', 'flightInformationService']) +export class Controller { + + public flight: IFlightDetail; + public model: IFlightInformationModel; + public loading: boolean = true; + public viewTitle: string; + + constructor(private $stateParams: FlightDetailParams, + private $state: ng.ui.IStateService, + private $rootScope: ng.IRootScopeService, + private $window: ng.IWindowService, + private chromaState: IChromaStateService, + private flightInformationService: IFlightInformationService) { + + this.getFlight(true); + + this.$rootScope.$on('flightGroupChanged', (event: ng.IAngularEvent, group: IFlightInformationGroup) => { + this.viewTitle = group.Display; + }); + + this.$rootScope.$on('chroma:flight-updated', () => { + this.getFlight(false); + }); + } + + private getFlight(buildGroups: Boolean): void { + this.flightInformationService.getFlight(this.$stateParams.flight, this.$stateParams.requestId) + .then((m: IFlightInformationModel) => { + this.flight = m.Flight; + this.buildView(m, buildGroups); + this.flightInformationService.getTransactionAccess() + .then((tranAccess: IUserAccessModel) => { + if (tranAccess.Enabled && tranAccess.View) { + this.addTransactionState(tranAccess); + } + }); + this.addPRMState(); + }); + } + + private addTransactionState(tranAccess: IUserAccessModel) { + this.chromaState.addState('chroma.flight-detail.transaction-list', { + url: '/transaction-list', + display: 'Transactions', + icon: 'ion-social-usd', + subView: false, + params: { + tranAccessModel: tranAccess + }, + views: { + 'flight-detail': { + template: `` + } + } + }); + this.chromaState.addState('chroma.flight-detail.transaction-detail', { + url: '/transaction-detail', + display: 'Transaction Detail', + icon: '', + subView: true, + params: { + transaction: null, + tranAccess: undefined, + columnConfig: undefined + }, + views: { + 'flight-detail': { + template: `` + } + } + }); + } + + private addPRMState() { + this.chromaState.addState('chroma.flight-detail.prm-list', { + url: '/prm-list', + display: 'Prms', + icon: 'ion-social-tux', + subView: false, + views: { + 'flight-detail': { + template: `` + } + } + }); + this.chromaState.addState('chroma.flight-detail.prm-detail', { + url: '/prm-detail', + display: 'PRM Detail', + icon: '', + subView: true, + params: { + prmList: null + }, + views: { + 'flight-detail': { + template: `` + } + } + }); + } + + private goBack(): void { + let previousWindow: string = + this.$window.sessionStorage.getItem('chroma:current-filter'); + this.$state.go('chroma.flight-list', { filter: previousWindow }); + } + + private buildView(model: IFlightInformationModel, buildGroups: Boolean): void { + if (model.IsOutsideOfWindow) { + this.loading = false; + this.model = model; + return; + } + + if (buildGroups && model.Groups && model.Groups.length > 0 && !model.IsOutsideOfWindow) { + model.Groups.forEach((grp: IFlightInformationGroup) => { + this.chromaState.addState('chroma.flight-detail.' + grp.Name, { + url: '/' + grp.Name, + display: grp.Display, + icon: grp.Icon, + subView: false, + params: { + group: grp + }, + views: { + 'flight-detail': { + template: `` + } + } + }); + }); + } + + this.model = model; + + if (buildGroups) { + this.$state.go(this.chromaState.states[0].name); + } + + this.loading = false; + + this.$rootScope.$broadcast('scroll.refreshComplete'); + } +} + +@directive(Mod, 'chromaFlightDetail') +export class Directive implements ng.IDirective { + controller: string = Controller.$componentName; + controllerAs: string = 'vm'; + templateUrl: string = 'app/flight-detail/detail/flight-detail.tpl.html'; + restrict: string = 'E'; + replace: boolean = false; + scope: any = true; +} diff --git a/app/flight-detail/editors/baseEditor.ts b/app/flight-detail/editors/baseEditor.ts new file mode 100644 index 0000000..a0f59df --- /dev/null +++ b/app/flight-detail/editors/baseEditor.ts @@ -0,0 +1,48 @@ +import * as InformationService from '../services/flightInformationService'; + +export interface IUpdateResonse { + Success: boolean; + Error: string; +} + +export class BaseEditorController { + public field: InformationService.IFlightInformation; + public model: InformationService.IFlightInformationModel; + public definition: InformationService.IFlightEditor; + public instance: ionic.popup.IonicPopupPromise; + + public status: string; + public error: string; + public updateUrl: string; + + constructor(private $http: ng.IHttpService, + private $rootScope: ng.IRootScopeService, + private $timeout: ng.ITimeoutService, + private api: any) { + this.updateUrl = this.api.endpoint + this.definition.Url; + } + + public updateValue(requestParams: any): void { + if (this.status === 'E' || this.status === 'S' || this.updateUrl === '') { + this.instance.close(); + return; + } + this.status = 'P'; + this.$http.post(this.updateUrl, requestParams).success((response: IUpdateResonse) => { + this.handleUpdateResult(response, requestParams); + this.$rootScope.$emit('chroma:flight-updated'); + }); + } + + private handleUpdateResult(response: IUpdateResonse, request: any): void { + if ((response && response.Success) || (request.IsDelete && response)) { + this.status = 'S'; + this.$timeout(() => { + this.instance.close(); + }, 600); + } else { + this.status = 'E'; + this.error = response.Error; + } + } +} diff --git a/app/flight-detail/editors/datetime/datetime-holder.tpl.html b/app/flight-detail/editors/datetime/datetime-holder.tpl.html new file mode 100644 index 0000000..67938be --- /dev/null +++ b/app/flight-detail/editors/datetime/datetime-holder.tpl.html @@ -0,0 +1,5 @@ + + \ No newline at end of file diff --git a/app/flight-detail/editors/datetime/datetime.spec.ts b/app/flight-detail/editors/datetime/datetime.spec.ts new file mode 100644 index 0000000..44d6913 --- /dev/null +++ b/app/flight-detail/editors/datetime/datetime.spec.ts @@ -0,0 +1,182 @@ +import {ComponentTest} from '../../../infrastructure/ComponentHelper'; + +import DetailMod from '../../flight-detail.mod'; +import {Mod as CoreMod} from '../../../core/core.mod'; + +import {Directive, Controller} from './datetime'; + +import * as InformationService from "../../services/flightInformationService"; + +class DatetimeEditorTest extends ComponentTest { + public compileString: string = ` `; + + constructor() { + super(Directive.$componentName, 'app/flight-detail/editors/datetime/datetime.tpl.html'); + } + + public getTestingScope(): any { + return { + field: { + Value: '', + Name: 'Crew', + Editor: 'datetime', + Group: 'Details', + Mapping: 'SCCREW' + }, + definition: { Url: 'testURL' }, + model: { + Flight: { Id: '0001' } + }, instance: { + close() { } + } + }; + } + + public setupForRequest(scope: any, responseObj: any, afterCtrlBuld: any = undefined, beforeUpdate: any = undefined): Controller { + + let ctrl = this.compile(scope, this.compileString); + + if (afterCtrlBuld) { + afterCtrlBuld(ctrl); + } + + this.$httpBackend.expectPOST(ctrl.updateUrl).respond(201, responseObj); + + if (beforeUpdate) { + beforeUpdate(ctrl); + } + + ctrl.update(); + + this.$httpBackend.flush(); + + return ctrl; + } +} + +describe('Datetime Editor:', () => { + let instance: DatetimeEditorTest, + detailMod: DetailMod, + coreMod: CoreMod; + + beforeEach(() => { + detailMod = new DetailMod(angular); + coreMod = new CoreMod(angular); + + angular.mock.module('ui.router'); + angular.mock.module('ionic'); + angular.mock.module('chroma.configuration'); + + angular.mock.module(DetailMod.$componentName); + angular.mock.module(CoreMod.$componentName); + + instance = new DatetimeEditorTest(); + }); + + describe('Framework:', () => { + it('Compiles with required properties', () => { + let ctrl: Controller, + scope: any; + + scope = instance.getTestingScope(); + + ctrl = instance.compile(scope, instance.compileString); + + expect(ctrl).toBeDefined(); + expect(ctrl.field).toBeDefined(); + expect(ctrl.definition).toBeDefined(); + expect(ctrl.model).toBeDefined(); + expect(ctrl.instance).toBeDefined(); + }); + }); + + describe('Behaviour', () => { + + it('Malformed time will display error', () =>{ + let ctrl: Controller, scope: any, valid: boolean; + + scope = instance.getTestingScope(); + + ctrl = instance.compile(scope, instance.compileString); + + ctrl.update(); + + expect(ctrl.error).toBe('Date/Time not in the correct format'); + }); + + it('Time value displayed as empty if field has no value', () => { + let ctrl: Controller, + scope: any; + + scope = instance.getTestingScope(); + + ctrl = instance.compile(scope, instance.compileString); + + expect(ctrl.wrapper.timeValue).toBe(undefined); + }) + + it('Time value displayed as 09:40 with 13/11/2015 09:40:00', () => { + let ctrl: Controller, + scope: any; + + scope = instance.getTestingScope(); + + scope.field.Value = '13/11/2015 09:40:00'; + + ctrl = instance.compile(scope, instance.compileString); + + expect(ctrl.wrapper.timeValue).toBe('09:40'); + }) + + it('Successful update with validate datetime', () => { + let ctrl: Controller, scope: any, valid: boolean; + + scope = instance.getTestingScope(); + + scope.field.Value = '13/11/2015 09:11:00'; + + ctrl = instance.compile(scope, instance.compileString); + + ctrl.wrapper.timeValue = '19:50'; + + instance.$httpBackend.expectPOST(ctrl.updateUrl).respond((method, url, data: string, headers, params) => { + let parsedArgs = JSON.parse(data); + valid = parsedArgs.NewValue === '13/11/2015, 7:50:00 PM'; + return [201, { Success: true }]; + }); + + ctrl.update(); + + instance.$httpBackend.flush(); + + expect(valid).toBe(true); + }); + + it('Successful update with validate datetime that starts with a 0', () => { + let ctrl: Controller, scope: any, valid: boolean; + + scope = instance.getTestingScope(); + + scope.field.Value = '13/11/2015 09:20:00'; + + ctrl = instance.compile(scope, instance.compileString); + + ctrl.wrapper.timeValue = '09:50'; + + instance.$httpBackend.expectPOST(ctrl.updateUrl).respond((method, url, data: string, headers, params) => { + let parsedArgs = JSON.parse(data); + valid = parsedArgs.NewValue === '13/11/2015, 9:50:00 AM'; + return [201, { Success: true }]; + }); + + ctrl.update(); + + instance.$httpBackend.flush(); + + expect(valid).toBe(true); + }); + + + }) + +}); diff --git a/app/flight-detail/editors/datetime/datetime.tpl.html b/app/flight-detail/editors/datetime/datetime.tpl.html new file mode 100644 index 0000000..493729d --- /dev/null +++ b/app/flight-detail/editors/datetime/datetime.tpl.html @@ -0,0 +1,52 @@ +
+
+
+ +
+
+ +
+ +
+
+ + + +
+
+ {{vm.error}} + + + + +
+
diff --git a/app/flight-detail/editors/datetime/datetime.ts b/app/flight-detail/editors/datetime/datetime.ts new file mode 100644 index 0000000..33723da --- /dev/null +++ b/app/flight-detail/editors/datetime/datetime.ts @@ -0,0 +1,119 @@ +import {controller, directive} from '../../../infrastructure/Dectorators/Components'; +import * as InformationService from '../../services/flightInformationService'; +import Mod from '../../flight-detail.mod'; +import * as BaseEditor from '../baseEditor'; +//TESTONLY import * as moment from 'moment' + +export class DateWrapper { + //actual value + private _value: Date; + + //Original value: only used to check if the date was removed + public originalValue: string; + + //working value: what angular is bound to + public workingValue: Date; + + public timeValue: string; + + constructor(value: string) { + if (value != null && value.slice(-1) === 'Z') { + this._value = moment(value).toDate(); + this.workingValue = moment(value).toDate(); + } else { + this._value = moment(value, 'DD/MM/YYYY hh:mm:ss').toDate(); + this.workingValue = moment(value, 'DD/MM/YYYY hh:mm:ss').toDate(); + } + + this.originalValue = value; + if (value !== '') { + this.timeValue = `${this.addZero(this.workingValue.getHours()) }:${this.addZero(this.workingValue.getMinutes()) }`; + } + } + + public getValue(): string { + if (!this.workingValue) { + return ''; + } + this._value.setFullYear(this.workingValue.getFullYear()); + this._value.setMonth(this.workingValue.getMonth()); + this._value.setDate(this.workingValue.getDate()); + + let timeSeg = this.timeValue.split(':'); + let hours = timeSeg[0]; + + this._value.setHours(parseInt(this.trimZero(hours), 10)); + this._value.setMinutes(parseInt(timeSeg[1], 10)); + + return this._value.toISOString(); + } + + private addZero(i: any): string | number { + if (i < 10) { + return '0' + i.toString(); + } + return i; + } + private trimZero(i: any): string { + if (i < 10) { + let returnStr = i.toString(); + return returnStr.substr(1, 1); + } + return i.toString(); + } +} + +@controller(Mod, 'dateTimeEditorController', ['$http', '$rootScope', '$timeout', 'api']) +export class Controller extends BaseEditor.BaseEditorController { + public wrapper: DateWrapper; + + constructor($http: ng.IHttpService, $rootScope: ng.IRootScopeService, $timeout: ng.ITimeoutService, api: any, Jquery: any) { + super($http, $rootScope, $timeout, api); + this.wrapper = new DateWrapper(this.field.Value); + } + + public update(): void { + if (this.definition.Url !== '') { + this.error = ''; + + var val = this.extractVal(); + if (val !== undefined) { + super.updateValue({ + Id: this.model.Flight.Id, + NewValue: val, + Mapping: this.field.Mapping, + IsDelete: this.wrapper.originalValue && !val + }); + } + } else { + this.field.Value = this.extractVal(); + this.instance.close(); + } + } + + private extractVal() { + let val: string = undefined; + try { + val = this.wrapper.getValue(); + } catch (error) { + this.error = 'Date/Time not in the correct format'; + } + return val; + } +} + +@directive(Mod, 'chromaDatetimeEditor') +export class Directive implements ng.IDirective { + controller = Controller.$componentName; + controllerAs = 'vm'; + templateUrl = 'app/flight-detail/editors/datetime/datetime.tpl.html'; + restrict = 'E'; + replace = false; + bindToController = true; + scope: any = { + field: '=', + definition: '=', + instance: '=', + model: '=' + }; +} diff --git a/app/flight-detail/editors/editors.less b/app/flight-detail/editors/editors.less new file mode 100644 index 0000000..403b404 --- /dev/null +++ b/app/flight-detail/editors/editors.less @@ -0,0 +1,64 @@ +@primary-color: #00398a; +@success-green: #689F38; +@error-red: #c62828; + + .invalid { + color: @error-red !important; + } + + +.editor { + .clear-action { + margin: 5px; + font-size: 110%; + } + + .cancel-button { + font-size: 250%; + } + + + .item-input { + &[disabled] { + background-color: #f8f8f8; + } + + input { + padding-right: 0px; + } + } + + .popup-head { + padding-bottom: 5px; + } + + .popup-title { + color: #00398a; + font-family: 'Roboto-Thin'; + } + + button.action { + font-size: 140%; + + i { + font-size: 200%; + } + + &.pending { + background-color: transparent !important; + } + + &.success { + background-color: @success-green !important; + border-color: @success-green !important; + } + + &.error { + background-color: @error-red !important; + border-color: @error-red !important; + } + } + button.action[disabled]{ + opacity:0.5; + } +} diff --git a/app/flight-detail/editors/freetext/freetext-holder.tpl.html b/app/flight-detail/editors/freetext/freetext-holder.tpl.html new file mode 100644 index 0000000..f0a85cf --- /dev/null +++ b/app/flight-detail/editors/freetext/freetext-holder.tpl.html @@ -0,0 +1,5 @@ + + \ No newline at end of file diff --git a/app/flight-detail/editors/freetext/freetext.spec.ts b/app/flight-detail/editors/freetext/freetext.spec.ts new file mode 100644 index 0000000..0ab26c0 --- /dev/null +++ b/app/flight-detail/editors/freetext/freetext.spec.ts @@ -0,0 +1,150 @@ +import {ComponentTest} from '../../../infrastructure/ComponentHelper'; + +import DetailMod from '../../flight-detail.mod'; +import {Mod as CoreMod} from '../../../core/core.mod'; + +import {Directive, Controller} from './freetext' + +import * as InformationService from "../../services/flightInformationService"; + +class FreeTextEditorTest extends ComponentTest { + public compileString: string = ` `; + constructor() { + super(Directive.$componentName, 'app/flight-detail/editors/freetext/freetext.tpl.html'); + } + public getTestingScope(): any { + return { + field: { + Value: 'testValue', + Name: 'Crew', + Editor: 'freetext', + Group: 'Details', + Mapping: 'SCCREW' + }, + definition: { + Url: 'testURL' + }, + model: { + Flight: { + Id: '0001' + } + }, + instance: { + close() { + + } + } + }; + } + public setupForRequest(scope: any, responseObj: any, beforeUpdate: any = undefined): Controller { + + let ctrl = this.compile(scope, this.compileString); + + this.$httpBackend.expectPOST(ctrl.updateUrl).respond(201, responseObj); + + if (beforeUpdate) { + beforeUpdate(ctrl); + } + + ctrl.update(); + + this.$httpBackend.flush(); + + return ctrl; + } +} + +describe('Freetext Editor:', () => { + let instance: FreeTextEditorTest, + detailMod: DetailMod, + coreMod: CoreMod; + beforeEach(() => { + detailMod = new DetailMod(angular); + coreMod = new CoreMod(angular); + + angular.mock.module('ui.router'); + angular.mock.module('ionic'); + angular.mock.module('chroma.configuration'); + + angular.mock.module(DetailMod.$componentName); + angular.mock.module(CoreMod.$componentName); + + instance = new FreeTextEditorTest(); + }); + describe('Framework:', () => { + it('Compiles with required properties', () => { + let ctrl: Controller, + scope: any; + + scope = instance.getTestingScope(); + + ctrl = instance.compile(scope, instance.compileString); + + expect(ctrl).toBeDefined(); + expect(ctrl.field).toBeDefined(); + expect(ctrl.definition).toBeDefined(); + expect(ctrl.model).toBeDefined(); + expect(ctrl.instance).toBeDefined(); + }); + + it('Popup closes if previous action complete', () => { + let ctrl: Controller, scope: any; + + scope = instance.getTestingScope(); + + ctrl = instance.setupForRequest(scope, { Success: false }); + + spyOn(ctrl.instance, 'close').and.callThrough(); + + ctrl.update(); + + expect(ctrl.instance.close).toHaveBeenCalled(); + }); + }); + describe('Behaviour', () => { + it('Flight updated even broadcast on update regardless on status', () => { + let ctrl: Controller, scope: any, + flightUpdateEvent: string = 'chroma:flight-updated'; + + scope = instance.getTestingScope(); + + spyOn(instance.$rootScope, '$emit').and.callThrough(); + + instance.setupForRequest(scope, { Success: true }); + + expect(instance.$rootScope.$emit).toHaveBeenCalledWith(flightUpdateEvent); + }); + + it('Status becomes S if successful Update', () => { + let ctrl: Controller, scope: any; + + scope = instance.getTestingScope(); + + ctrl = instance.setupForRequest(scope, { Success: true }); + + expect(ctrl.status).toBe('S'); + }); + + it('Status becomes S if successful Delete', () => { + let ctrl: Controller, scope: any; + + scope = instance.getTestingScope(); + + ctrl = instance.setupForRequest(scope, {}, (controller: Controller) => { + controller.value = ''; + }); + + expect(ctrl.status).toBe('S'); + }); + + it('Status becomes E if on failed update or delete', () => { + let ctrl: Controller, scope: any; + + scope = instance.getTestingScope(); + + ctrl = instance.setupForRequest(scope, { Success: false }); + + expect(ctrl.status).toBe('E'); + }); + }); +}); diff --git a/app/flight-detail/editors/freetext/freetext.tpl.html b/app/flight-detail/editors/freetext/freetext.tpl.html new file mode 100644 index 0000000..bc9a17a --- /dev/null +++ b/app/flight-detail/editors/freetext/freetext.tpl.html @@ -0,0 +1,38 @@ +
+
+
+ +
+
+
+ +
+
+ {{vm.error}} + + + + +
+
diff --git a/app/flight-detail/editors/freetext/freetext.ts b/app/flight-detail/editors/freetext/freetext.ts new file mode 100644 index 0000000..e070711 --- /dev/null +++ b/app/flight-detail/editors/freetext/freetext.ts @@ -0,0 +1,69 @@ +import {controller, directive} from '../../../infrastructure/Dectorators/Components'; +import * as InformationService from '../../services/flightInformationService'; +import Mod from '../../flight-detail.mod'; +import * as BaseEditor from '../baseEditor'; + +interface IFlightUpdateRequest { + Id: string; + NewValue: string; + Mapping: string; + IsDelete: Boolean; +} + +@controller(Mod, 'freeTextEditorController', ['$http', '$rootScope', '$timeout', 'api']) +export class Controller extends BaseEditor.BaseEditorController { + public value: string; + public originalValue: string; + + constructor($http: ng.IHttpService, $rootScope: ng.IRootScopeService, $timeout: ng.ITimeoutService, api: any, jquery: any) { + super($http, $rootScope, $timeout, api); + this.value = this.field.Value; + this.originalValue = this.value; + } + + public update(): void { + if (this.valueNotChanged()) { + this.instance.close(); + return; + } + + if (this.definition.Url !== '') { + this.updateValue(this.createRequestParams()); + } else { + this.field.Value = this.value; + this.instance.close(); + } + } + + private valueNotChanged() { + if (this.value === this.originalValue) { + return true; + } + return false; + } + + private createRequestParams(): IFlightUpdateRequest { + return { + Id: this.model.Flight.Id, + NewValue: this.value, + Mapping: this.field.Mapping, + IsDelete: this.originalValue && this.value === '' + }; + } +} + +@directive(Mod, 'chromaFreetextEditor') +export class Directive implements ng.IDirective { + controller: string = Controller.$componentName; + controllerAs: string = 'vm'; + templateUrl: string = 'app/flight-detail/editors/freetext/freetext.tpl.html'; + restrict: string = 'E'; + replace: boolean = false; + bindToController: boolean = true; + scope: any = { + field: '=', + definition: '=', + instance: '=', + model: '=' + }; +} diff --git a/app/flight-detail/editors/lookup/lookup-holder.tpl.html b/app/flight-detail/editors/lookup/lookup-holder.tpl.html new file mode 100644 index 0000000..8337bf3 --- /dev/null +++ b/app/flight-detail/editors/lookup/lookup-holder.tpl.html @@ -0,0 +1,6 @@ + + \ No newline at end of file diff --git a/app/flight-detail/editors/lookup/lookup.tpl.html b/app/flight-detail/editors/lookup/lookup.tpl.html new file mode 100644 index 0000000..6bd3d23 --- /dev/null +++ b/app/flight-detail/editors/lookup/lookup.tpl.html @@ -0,0 +1,20 @@ + + \ No newline at end of file diff --git a/app/flight-detail/editors/lookup/lookup.ts b/app/flight-detail/editors/lookup/lookup.ts new file mode 100644 index 0000000..1ba8767 --- /dev/null +++ b/app/flight-detail/editors/lookup/lookup.ts @@ -0,0 +1,49 @@ +import {controller, directive} from '../../../infrastructure/Dectorators/Components'; +import Mod from '../../flight-detail.mod'; +import {LookupModel, LookupEditorField} from '../../services/flightInformationService'; +import * as BaseEditor from '../baseEditor'; + + + +@controller(Mod, 'lookupEditorController', ['$http', '$rootScope', '$timeout', 'api']) +export class Controller extends BaseEditor.BaseEditorController { + constructor($http: ng.IHttpService, $rootScope: ng.IRootScopeService, $timeout: ng.ITimeoutService, api: any) { + super($http, $rootScope, $timeout, api); + } + + public lookupmodel: LookupModel; + + public searchInput: string; + + public onSearchTextChanged() { + var field: LookupEditorField; + field = this.field as LookupEditorField; + field.LookupModel.searchString = this.searchInput; + field.LookupModel.search(); + } + + public selectItem(item: any) { + var field: LookupEditorField; + field = this.field as LookupEditorField; + field.LookupModel.onSelected(item); + this.instance.close(); + } + +} + +@directive(Mod, 'chromaLookupEditor') +export class Directive implements ng.IDirective { + controller = Controller.$componentName; + controllerAs = 'vm'; + templateUrl:string = 'app/flight-detail/editors/lookup/lookup.tpl.html'; + restrict:string = 'E'; + replace: boolean = false; + bindToController:boolean = true; + scope: any = { + field: '=', + definition: '=', + instance: '=', + model: '=', + lookupmodel: '=' + }; +} \ No newline at end of file diff --git a/app/flight-detail/editors/readonly/readonly.less b/app/flight-detail/editors/readonly/readonly.less new file mode 100644 index 0000000..6b9297f --- /dev/null +++ b/app/flight-detail/editors/readonly/readonly.less @@ -0,0 +1,13 @@ +@primary-color: #00398a; + +.editor-readonly{ + .popup-head{ + padding-bottom: 5px; + } + .popup-title{ + color: #00398a; + } + button.action{ + font-size: 100% + } +} diff --git a/app/flight-detail/editors/readonly/readonly.tpl.html b/app/flight-detail/editors/readonly/readonly.tpl.html new file mode 100644 index 0000000..aa611c0 --- /dev/null +++ b/app/flight-detail/editors/readonly/readonly.tpl.html @@ -0,0 +1,15 @@ + +
+
+ +
+
+
+
+ +
+
diff --git a/app/flight-detail/flight-detail.config.ts b/app/flight-detail/flight-detail.config.ts new file mode 100644 index 0000000..2019787 --- /dev/null +++ b/app/flight-detail/flight-detail.config.ts @@ -0,0 +1,20 @@ +import {inject} from '../infrastructure/Dectorators/Components'; + +@inject(['$stateProvider']) +export class Routes { + constructor($stateProvider: ng.ui.IStateProvider) { + $stateProvider.state('chroma.flight-detail', { + url: '/flight-detail/:id', + params: { + flight: undefined, + id: undefined, + requestId: undefined + }, + views: { + 'content': { + template: '' + } + } + }); + } +} diff --git a/app/flight-detail/flight-detail.mod.ts b/app/flight-detail/flight-detail.mod.ts new file mode 100644 index 0000000..c192374 --- /dev/null +++ b/app/flight-detail/flight-detail.mod.ts @@ -0,0 +1,57 @@ +import {module} from '../infrastructure/Dectorators/Components'; +import {Routes} from './flight-detail.config'; +import {Controller as FltDetailCtrl, Directive as FltDetailDir} from './detail/flight-detail'; +import {Controller as TransactionLstCtrl, Directive as TransactionLstDir} from './transactions/transaction-list'; +import {Controller as TransactionDetCtrl, Directive as TransactionDetDir} from './transactions/transaction-detail'; +import {Controller as PrmLstCtrl, Directive as PrmLstDir} from './prm/prm-list'; +import {Controller as FltGroupCtrl, Directive as FltGroupDir} from './group/flight-group'; +import {Controller as FreeTextCtrl, Directive as FreeTextDir} from './editors/freetext/freetext'; +import {Controller as DateTimeCtrl, Directive as DateTimeDir} from './editors/datetime/datetime'; +import {Controller as LookupCtrl, Directive as LookupCtrlDir} from './editors/lookup/lookup'; +import {FlightInformationService} from './services/flightInformationService'; +import {TransactionService} from './services/transactionService'; +import {PrmService} from './services/prmService'; + +@module('flight-detail') +export default class Mod { + constructor(angular: ng.IAngularStatic) { + angular.module(Mod.$componentName, []) + .factory(FlightInformationService.$componentName, FlightInformationService.$factory) + + .controller(FltDetailCtrl.$componentName, FltDetailCtrl) + .directive(FltDetailDir.$componentName, FltDetailDir.$factory) + + .controller(TransactionLstCtrl.$componentName, TransactionLstCtrl) + .directive(TransactionLstDir.$componentName, TransactionLstDir.$factory) + .factory(TransactionService.$componentName, TransactionService.$factory) + + .controller(PrmLstCtrl.$componentName, PrmLstCtrl) + .directive(PrmLstDir.$componentName, PrmLstDir.$factory) + .factory(PrmService.$componentName, PrmService.$factory) + + .controller(TransactionDetCtrl.$componentName, TransactionDetCtrl) + .directive(TransactionDetDir.$componentName, TransactionDetDir.$factory) + + .controller(FltGroupCtrl.$componentName, FltGroupCtrl) + .directive(FltGroupDir.$componentName, FltGroupDir.$factory) + + .controller(FreeTextCtrl.$componentName, FreeTextCtrl) + .directive(FreeTextDir.$componentName, FreeTextDir.$factory) + + .controller(DateTimeCtrl.$componentName, DateTimeCtrl) + .directive(DateTimeDir.$componentName, DateTimeDir.$factory) + + .controller(LookupCtrl.$componentName, LookupCtrl) + .directive(LookupCtrlDir.$componentName, LookupCtrlDir.$factory) + + + .filter('chromaDateFilter', $filter => (filterText, date) => { + if (!filterText || filterText === '/Date(-62135596800000)/') { + return ''; + } + + return date ? $filter('date')(parseInt(filterText.substr(6), 10), '[dd] HH:mm') : $filter('date')(parseInt(filterText.substr(6), 10), 'HH:mm'); + }) + .config(Routes); + } +} \ No newline at end of file diff --git a/app/flight-detail/group/flight-group.spec.ts b/app/flight-detail/group/flight-group.spec.ts new file mode 100644 index 0000000..bbb0498 --- /dev/null +++ b/app/flight-detail/group/flight-group.spec.ts @@ -0,0 +1,241 @@ +import {ComponentTest} from '../../infrastructure/ComponentHelper'; +import {Directive as GroupDir, Controller as GroupCtrl, IGroupParams} from './flight-group'; + +import DetailMod from '../flight-detail.mod'; +import {Mod as CoreMod} from '../../core/core.mod'; + +import {IFlightInformationModel, IFlightInformation} from '../services/flightInformationService'; +import {IFlightDetail} from '../../core/service/flightService'; +import * as InformationService from "../services/flightInformationService"; +import * as Flightdetail from "../detail/flight-detail"; + +class FlightGroupTest extends ComponentTest { + constructor() { + super(GroupDir.$componentName, 'app/flight-detail/group/flight-group.tpl.html'); + } +} + + +class TestInstance { + public compileString: string = ""; + + public test: FlightGroupTest; + public testModel: IFlightInformationModel; + public api: any; + + public $httpBackend: ng.IHttpBackendService; + public $state: ng.ui.IStateService; + public $stateParams: ng.ui.IStateParamsService; + public $rootScope: any; + public $ionicPopup: any; + + constructor() { + angular.mock.inject(($httpBackend, $state, $stateParams, $ionicPopup, $rootScope, api) => { + this.$httpBackend = $httpBackend; + this.$state = $state; + this.$stateParams = $stateParams; + this.$ionicPopup = $ionicPopup; + this.$rootScope = $rootScope; + this.api = api; + }); + } + public setup(): void { + this.testModel = { + IsOutsideOfWindow: false, + Flight: { + Id: undefined, + Location: undefined, + Operator: undefined, + Number: undefined, + AircraftType: undefined, + Registration: undefined, + Stand: undefined, + Terminal: undefined, + Actual: undefined, + Scheduled: undefined, + Estimated: undefined, + FlightConcat: undefined, + Type: 'D' + }, + Groups: undefined, + Fields: [ + { + "Value": '', + "Name": 'Mail Weight', + "Editor": 'freetext', + "Mapping": 'MAIL_WEIGHT', + "Group": 'Deadload', + "Restrict": "A" + }, + { + "Value": '', + "Name": 'PAX Weight', + "Editor": 'freetext', + "Mapping": 'PAX_WEIGHT', + "Group": 'General' + } + ], + Editors: [ + { + Name: 'freetext', + Type: 'freetext', + Url: 'test' + } + ] + }; + this.getStateParams(); + } + public getStateParams(): void { + let params: any = this.$stateParams; + + params.group = { + "Name": 'Deadload', + "Display": 'Deadload Figures', + "Icon": 'ion-navicon' + }; + } +} + + +describe('Flight Group:', () => { + let instance: TestInstance; + + beforeEach(() => { + + new DetailMod(angular); + new CoreMod(angular); + + angular.mock.module('ui.router'); + angular.mock.module('ionic'); + angular.mock.module('chroma.configuration'); + + angular.mock.module(DetailMod.$componentName); + angular.mock.module(CoreMod.$componentName); + + instance = new TestInstance(); + instance.test = new FlightGroupTest(); + }); + + describe('Framework:', () => { + it('View Refreshed on pull down', () => { + let ctrl: GroupCtrl, + flightUpdateEvent: string = 'chroma:flight-updated'; + + spyOn(instance.$rootScope, '$emit').and.callThrough(); + + instance.setup(); + + ctrl = instance.test.compile({ model: instance.testModel }, instance.compileString); + + ctrl.update(); + + expect(instance.$rootScope.$emit).toHaveBeenCalledWith(flightUpdateEvent); + }); + + it('Filter correct removes fields with restrictions', () => { + let ctrl: GroupCtrl, + valid: Boolean; + + spyOn(instance.$rootScope, '$emit').and.callThrough(); + + instance.setup(); + + ctrl = instance.test.compile({ model: instance.testModel }, instance.compileString); + + valid = ctrl.fieldFilter(instance.testModel.Fields[1]); + + expect(valid).toBe(false); + }); + + it('Filter returns fields for correct group', () => { + let ctrl: GroupCtrl, + valid: Boolean; + + instance.setup(); + + ctrl = instance.test.compile({ model: instance.testModel }, instance.compileString); + + valid = ctrl.fieldFilter(instance.testModel.Fields[0]); + + expect(valid).toBe(false); + }); + }); + + describe('Scenario: Updating Mail Weight', () => { + //Given that I have chosen to enter a dead load for flight SAS6876 + //And the limit is 99999kg + //When I enter a mail weight of 34.67kg for flight SAS6876 + //Then flight SAS6876 is updated with a mail weight of 34.67kg + it('Directive loaded and required Params present', function() { + let ctrl: GroupCtrl; + + instance.setup(); + + ctrl = instance.test.compile({ model: instance.testModel }, instance.compileString); + + expect(ctrl.group).toBeDefined(); + + expect(ctrl.model).toBeDefined(); + }); + + it('Readonly Editor has no interaction', () => { + let ctrl: GroupCtrl, + testField: IFlightInformation; + + testField = { + "Value": '', + "Name": '', + "Editor": 'Readonly', + "Group": '', + "Mapping": '' + }; + + spyOn(instance.$ionicPopup, 'show').and.returnValue(false); + + instance.setup(); + + ctrl = instance.test.compile({ model: instance.testModel }, instance.compileString); + + ctrl.editorFor(testField); + + expect(instance.$ionicPopup.show).not.toHaveBeenCalled(); + }); + + it('Freetext Editor shown', () => { + let ctrl: GroupCtrl, + testField: IFlightInformation, + argumentsAreCorrect: boolean = false; + + testField = { + "Value": '', + "Name": 'PAX Weight', + "Editor": 'freetext', + "Group": 'Deadload', + "Mapping": 'PAX_WEIGHT' + }; + + spyOn(instance.$ionicPopup, 'show').and.callFake((popup) => { + let comparableTemplate = `app/flight-detail/editors/${testField.Editor}/${testField.Editor}-holder.tpl.html`; + let compareableClass = `editor editor-${testField.Editor}`; + let comparableTitle = `Update ${testField.Name}`; + + if (popup.templateUrl === comparableTemplate && + popup.cssClass === compareableClass && + popup.title === comparableTitle) { + argumentsAreCorrect = true; + } + }); + + instance.setup(); + + ctrl = instance.test.compile({ model: instance.testModel }, instance.compileString); + + ctrl.editorFor(testField); + + expect(argumentsAreCorrect).toBe(true); + + }); + + }); + +}); diff --git a/app/flight-detail/group/flight-group.tpl.html b/app/flight-detail/group/flight-group.tpl.html new file mode 100644 index 0000000..e7142f0 --- /dev/null +++ b/app/flight-detail/group/flight-group.tpl.html @@ -0,0 +1,17 @@ + + + + +
+ +
+
+
diff --git a/app/flight-detail/group/flight-group.ts b/app/flight-detail/group/flight-group.ts new file mode 100644 index 0000000..1d950c4 --- /dev/null +++ b/app/flight-detail/group/flight-group.ts @@ -0,0 +1,81 @@ +import {controller, directive} from '../../infrastructure/Dectorators/Components'; +import {Controller as FlightDetailController} from '../detail/flight-detail'; +import Mod from '../flight-detail.mod'; +import * as InformationService from '../services/flightInformationService'; + +export interface IGroupScope { + group: string; + vm: IController; +} + +export interface IGroupParams { + group: InformationService.IFlightInformationGroup; +} +export interface IController extends IGroupScope { + model: InformationService.IFlightInformationModel; +} + +@controller(Mod, 'flightGroupController', ['$ionicPopup', '$rootScope', '$stateParams']) +export class Controller { + public group: InformationService.IFlightInformationGroup; + public model: InformationService.IFlightInformationModel; + public fieldFilter: (field: InformationService.IFlightInformation) => Boolean; + + constructor(private $ionicPopup: ionic.popup.IonicPopupService, + private $rootScope: ng.IRootScopeService, private $stateParams: IGroupParams) { + this.group = $stateParams.group; + + this.fieldFilter = (field: InformationService.IFlightInformation) => { + if (this.$stateParams && this.$stateParams.group) { + if (!field.Restrict || field.Restrict === '') { + return field.Group.toLowerCase() === this.$stateParams.group.Name.toLowerCase(); + } else { + return field.Group === this.group.Name + && this.model.Flight.Type === field.Restrict; + } + } + }; + + $rootScope.$emit('flightGroupChanged', this.group); + } + + public editorFor(field: InformationService.IFlightInformation) { + if (field.Editor.toLowerCase() === 'readonly') { return; } + let editor = field.Editor.toLowerCase(); + let modalScope: any = this.$rootScope.$new(); + let editorDefinition: InformationService.IFlightEditor; + + this.model.Editors.forEach(e => { + if (e.Name.toLowerCase() === editor) { + editorDefinition = e; + } + }); + + modalScope.model = this.model; + modalScope.field = field; + modalScope.editor = editorDefinition; + + modalScope.instance = this.$ionicPopup.show({ + templateUrl: `app/flight-detail/editors/${editor}/${editor}-holder.tpl.html`, + cssClass: `editor editor-${editor}`, + title: `Update ${field.Name}`, + scope: modalScope + }); + } + public update(): void { + this.$rootScope.$emit('chroma:flight-updated'); + } +} + +@directive(Mod, 'chromaFlightDetailGroup') +export class Directive implements ng.IDirective { + controller: string = Controller.$componentName; + controllerAs: string = 'vm'; + templateUrl: string = 'app/flight-detail/group/flight-group.tpl.html'; + restrict: string = 'E'; + replace: boolean = false; + bindToController: boolean = true; + scope: any = { + model: '=' + }; +} diff --git a/app/flight-detail/prm/prm-list.less b/app/flight-detail/prm/prm-list.less new file mode 100644 index 0000000..e69de29 diff --git a/app/flight-detail/prm/prm-list.spec.ts b/app/flight-detail/prm/prm-list.spec.ts new file mode 100644 index 0000000..e69de29 diff --git a/app/flight-detail/prm/prm-list.tpl.html b/app/flight-detail/prm/prm-list.tpl.html new file mode 100644 index 0000000..c8992ea --- /dev/null +++ b/app/flight-detail/prm/prm-list.tpl.html @@ -0,0 +1,7 @@ + + +
+ Hello World! +
+
+
\ No newline at end of file diff --git a/app/flight-detail/prm/prm-list.ts b/app/flight-detail/prm/prm-list.ts new file mode 100644 index 0000000..febf86d --- /dev/null +++ b/app/flight-detail/prm/prm-list.ts @@ -0,0 +1,53 @@ +import {controller, directive} from '../../infrastructure/Dectorators/Components'; +import {Mod} from './prm.mod'; +import {IPrmService, IPrmDetail, IPrmListRequest} from '../services/prmService'; +import * as InformationService from '../services/flightInformationService'; +import {IFlightDetail} from '../../core/service/flightService'; + +export interface PrmListParams extends ng.ui.IStateParamsService { + flightId: string; +} + +@controller(Mod, 'prmListController', ['prmService', '$stateParams', '$state', '$rootScope', 'chromaState']) +export class Controller { + public static NO_PRM = 'This flight has no passengers with reduced movement'; + public prms: Array; + public message: string; + public request: IPrmListRequest; + public flightId: string; + public model: IFlightDetail; + + constructor(private prmService: IPrmService, + private $stateParams: PrmListParams, + private $state: ng.ui.IStateService, + private $rootScope: ng.IScope) { + this.load(); + } + + private load() : void { + this.prmService.getPrmList(this.model.Id, this.model.PhysFlightId) + .then((r) => this.onPrmLoad(r)); + } + + private onPrmLoad(request: any): void { + this.request = request; + this.prms = request; + + if (!this.prms || this.prms.length === 0) { + this.message = Controller.NO_PRM; + } + } +} + +@directive(Mod, 'chromaPrmList', ['$stateParams']) +export class Directive implements ng.IDirective { + controller: string = Controller.$componentName; + controllerAs: string = 'vm'; + templateUrl: string = 'app/flight-detail/prm/prm-list.tpl.html'; + restrict: string = 'E'; + replace: boolean = false; + bindToController: boolean = true; + scope: any = { + model: '=' + }; +} \ No newline at end of file diff --git a/app/flight-detail/prm/prm.config.ts b/app/flight-detail/prm/prm.config.ts new file mode 100644 index 0000000..30c031c --- /dev/null +++ b/app/flight-detail/prm/prm.config.ts @@ -0,0 +1,19 @@ +import {inject} from '../../infrastructure/Dectorators/Components'; + +@inject(['$stateProvider']) +export class Routes { + constructor($stateProvider: ng.ui.IStateProvider) { + $stateProvider + .state('chroma.flight-detail.prm-list', { + url: '/prm-list', + params: { + prm: undefined + }, + views: { + 'detail':{ + template: '' + } + } + }); + } +} \ No newline at end of file diff --git a/app/flight-detail/prm/prm.mod.ts b/app/flight-detail/prm/prm.mod.ts new file mode 100644 index 0000000..e81ed64 --- /dev/null +++ b/app/flight-detail/prm/prm.mod.ts @@ -0,0 +1,16 @@ +import Dectorators = require('../../infrastructure/Dectorators/Components'); +import PrmListComp = require('./prm-list'); +import {PrmService} from '../services/prmService'; +import Config = require ('./prm.config'); + +@Dectorators.module('prm-list') +export class Mod { + constructor(angular: ng.IAngularStatic) { + angular.module(Mod.$componentName, []) + .factory(PrmService.$componentName, PrmService.$factory) + + .controller(PrmListComp.Controller.$componentName, PrmListComp.Controller) + .directive(PrmListComp.Directive.$componentName, PrmListComp.Directive.$factory) + .config(Config.Routes); + } +} \ No newline at end of file diff --git a/app/flight-detail/services/flightInformationService.spec.ts b/app/flight-detail/services/flightInformationService.spec.ts new file mode 100644 index 0000000..8393474 --- /dev/null +++ b/app/flight-detail/services/flightInformationService.spec.ts @@ -0,0 +1,82 @@ +import {FlightInformationService} from './flightInformationService'; +import {IFlightDetail} from '../../core/service/flightService'; + +describe('Framework: Flight info service', () => { + + let service: FlightInformationService, + sourceUrl: string = 'test'; + + beforeEach(() => { + service = new FlightInformationService(null, null, null, { + imageSource: sourceUrl + }); + }); + + it('Get Operater URL: Should concat URL based on API and Operator Code', () => { + let operator = "SteAir"; + expect(service.getOperatorUrl(operator)).toBe(`${sourceUrl}?code=${operator}`); + }); + + it('Get Time Display: Should return nothing for null flight', () => { + expect(service.getTimeDisplayEnum(undefined)).toBe(''); + }); + + it('Get Time Display: Should return A for flight with Actual', () => { + let flight: IFlightDetail = { + Id: undefined, + Operator: undefined, + Number: undefined, + Stand: undefined, + Scheduled: undefined, + Terminal: undefined, + Type: undefined, + Estimated: undefined, + Registration: undefined, + AircraftType: undefined, + Location: undefined, + Actual: '0000', + FlightConcat: undefined + } + expect(service.getTimeDisplayEnum(flight)).toBe('A'); + }); + + it('Get Time Display: Should return E for flight with Estimated', () => { + let flight: IFlightDetail = { + Id: undefined, + Operator: undefined, + Number: undefined, + Stand: undefined, + Scheduled: undefined, + Terminal: undefined, + Type: undefined, + Estimated: '0000', + Registration: undefined, + AircraftType: undefined, + Location: undefined, + Actual: undefined, + FlightConcat: undefined + }; + + expect(service.getTimeDisplayEnum(flight)).toBe('E'); + }); + + it('Get Time Display: Should return S for flight with Schedule', () => { + let flight: IFlightDetail = { + Id: undefined, + Operator: undefined, + Number: undefined, + Stand: undefined, + Scheduled: '0000', + Terminal: undefined, + Type: undefined, + Estimated: undefined, + Registration: undefined, + AircraftType: undefined, + Location: undefined, + Actual: undefined, + FlightConcat: undefined + }; + + expect(service.getTimeDisplayEnum(flight)).toBe('S'); + }); +}); diff --git a/app/flight-detail/services/flightInformationService.ts b/app/flight-detail/services/flightInformationService.ts new file mode 100644 index 0000000..ee8b98d --- /dev/null +++ b/app/flight-detail/services/flightInformationService.ts @@ -0,0 +1,154 @@ +import {factory} from '../../infrastructure/Dectorators/Components'; +import {IFlightDetail} from '../../core/service/flightService'; +import {Mod} from '../../core/core.mod'; + +export interface IFlightInformationModel { + Fields: Array; + Groups: Array; + Editors: Array; + Flight: IFlightDetail; + IsOutsideOfWindow: boolean; +} + +export class LookupModel implements ILookupModel { + public searchString: string; + public lookupList: Array; + public results: Array; + public viewScope: any; + lookupField: string; + resultField: string; + public search() { + // + }; + public onSelected(item: any) { + // + }; +} + +export interface ILookupModel { + lookupField: string; + resultField: string; + viewScope: any; + search() : any; + onSelected(item: any); +} + +export class EditorField implements IFlightInformation { + constructor(public Name: string, + public Value: string, + public Editor: string, + public Group: string, + public Mapping: string, + public Restrict?: string, + public IsRequired?: boolean, + public Invisible?: boolean, + public Invalid?: boolean) { + } + + public ChangeEventHandler() { + // + } +} + + export class LookupEditorField implements EditorField { + constructor(public Name: string, + public Value: string, + public Editor: string, + public Group: string, + public Mapping: string, + public LookupModel: LookupModel, + public Restrict?: string, + public IsRequired?: boolean, + public Invisible?: boolean, + public Invalid?: boolean) { + } + + public ChangeEventHandler() { + // + } + } + + +export interface IFlightInformation { + Value: string; + Name: string; + Editor: string; + Group: string; + Mapping: string; + Restrict?:string; +} + +export interface IFlightInformationGroup { + Name: string; + Display: string; + Icon: string; +} + +export interface IFlightEditor { + Name: string; + Type: string; + Url: string; +} + +export interface IUserAccessModel { + ProfileCode: string; + FunctionDefinition: string; + Enabled: boolean; + Update: boolean; + Add: boolean; + Delete: boolean; + View: boolean; + FuncEnabled: boolean; + FuncPackage: boolean; + FuncProcedure: boolean; + FuncParamaters: boolean; +} + +export interface IFlightInformationService { + getFlight(flight: IFlightDetail, requestId: string): ng.IPromise; + getOperatorUrl(operator: string): string; + getTimeDisplayEnum(flight: IFlightDetail): string; + getTransactionAccess(): ng.IPromise; +} + +@factory(Mod, 'flightInformationService', ['$http', '$q', '$rootScope', 'api']) +export class FlightInformationService implements IFlightInformationService { + constructor(private $http: ng.IHttpService, + private $q: ng.IQService, + private $rootScope: ng.IScope, + private api: any) { + } + public getFlight(flight: IFlightDetail, requestId: string): ng.IPromise { + let def: ng.IDeferred = this.$q.defer(); + this.$http.get(`${this.api.detail}?flightId=${flight.Id}&requestId=${requestId}`).success((data, status) => { + def.resolve(data); + }); + return def.promise; + } + + getOperatorUrl(operator: string): string { + return `${this.api.imageSource}?code=${operator}`; + } + + public getTransactionAccess(): ng.IPromise { + let def: ng.IDeferred = this.$q.defer(); + this.$http.get(this.api.getTransactionsAccess) + .success((data) => { + def.resolve(data); + }); + return def.promise; + } + + getTimeDisplayEnum(flight: IFlightDetail): string { + if (!flight) { + return ''; + } + + if (flight.Actual && flight.Actual !== '' && flight.Actual !== '/Date(-62135596800000)/') { + return 'A'; + } else if (flight.Estimated && flight.Estimated !== '' && flight.Estimated !== '/Date(-62135596800000)/') { + return 'E'; + } + return 'S'; + } +} diff --git a/app/flight-detail/services/prmService.ts b/app/flight-detail/services/prmService.ts new file mode 100644 index 0000000..1b22eb6 --- /dev/null +++ b/app/flight-detail/services/prmService.ts @@ -0,0 +1,35 @@ +import Decorators = require('../../infrastructure/Dectorators/Components'); +import Core = require('../../core/core.mod'); + +export interface IPrmListRequest { + Prms: Array; +} + +export interface IPrmDetail { + Passenger: string; + Remark: string; + Comment: string; + Status: string; +} + +export interface IPrmService { + getPrmList(flightId: string, physFlight: string) : ng.IPromise; +} + +@Decorators.factory(Core.Mod, 'prmService', ['$http', '$q', '$rootScope', 'api']) +export class PrmService implements IPrmService { + constructor(private $http: ng.IHttpService, + private $q: ng.IQService, + private $rootScope: ng.IScope, + private api: any) { + + } + + getPrmList(flightId: string, physFlight: string) : ng.IPromise { + let def: ng.IDeferred = this.$q.defer(); + this.$http.get(`${this.api.prmList}?flightId=${flightId}&physFlight=${physFlight}`).success((data: any, status) => { + def.resolve(data); + }); + return def.promise; + } +} \ No newline at end of file diff --git a/app/flight-detail/services/transactionService.ts b/app/flight-detail/services/transactionService.ts new file mode 100644 index 0000000..cf32bee --- /dev/null +++ b/app/flight-detail/services/transactionService.ts @@ -0,0 +1,141 @@ +import Decorators = require('../../infrastructure/Dectorators/Components'); +import Core = require('../../core/core.mod'); +import {IUpdateResonse} from '../editors/baseEditor'; + +export interface ITransactionListRequest { + Transactions: Array; +} + +export interface ITransactionCodesRequest { + TransactionCodes: Array; +} + +export interface IUpdateResonse { + Success: boolean; + Error: string; +} + +export interface ITransactionConfigRequest { + TransactionConfig: Array; +} + +export interface ITransactionDetail { + PublflightId: string; + PhysflightId: string; + Id: string; + Code:string; + Name:string; + Quantity: number; + Duration: string; + PONumber: string; + StartTime: string; + EndTime:string; + Confirmed: boolean; + Cancelled: boolean; + CodeType: number; + Timestamp: number; +} + +export interface ITransactionConfig { + ColumnName: string; + Index: number; + HeaderText: string; + Justify: string; + Visible: boolean; + Width: number; + Description: string; + Editable: boolean; + Highlight: boolean; + Length: number; +} + +export class TransactionCode { + Name: string; + Code: string; + CodeType: number; +} + +export interface ITransactionService { + getTransactions(flightId: string, physFlight: string): ng.IPromise; + confirmTransaction(transaction: ITransactionDetail); + cancelTransaction(transaction: ITransactionDetail); + createTransaction(transaction: ITransactionDetail); + getTransactionCodes() : ng.IPromise; + getTransactionConfig(flightId: string, physFlight: string) : ng.IPromise; +} + +@Decorators.factory(Core.Mod, 'transactionService', ['$http', '$q', '$rootScope', 'api']) +export class TransactionService implements ITransactionService { + constructor(private $http: ng.IHttpService, + private $q: ng.IQService, + private $rootScope: ng.IScope, + private api: any) { + + } + + private status: string; + private error: string; + + getTransactions(flightId: string, physFlight:string) : ng.IPromise { + let def: ng.IDeferred = this.$q.defer(); + this.$http.get(`${this.api.transactions}?flightId=${flightId}&physFlight=${physFlight}`).success((data: any, status) => { + def.resolve(data); + }); + return def.promise; + } + + getTransactionConfig(flightId: string, physFlight: string) : ng.IPromise { + let def: ng.IDeferred = this.$q.defer(); + this.$http.get(`${this.api.getTransactionConfig}?flightId=${flightId}&physFlight=${physFlight}`).success((data: any, status) => { + def.resolve(data); + }); + return def.promise; + } + + confirmTransaction(transaction: ITransactionDetail) : ng.IPromise { + let def: ng.IDeferred = this.$q.defer(); + this.$http.post(this.api.confirmTransaction, transaction) + .success((response: IUpdateResonse) => { + this.handleUpdateResult(response); + def.resolve(response); + }); + return def.promise; + } + + cancelTransaction(transaction: ITransactionDetail) : ng.IPromise { + let def: ng.IDeferred = this.$q.defer(); + this.$http.post(this.api.cancelTransaction, transaction) + .success((response: IUpdateResonse) => { + this.handleUpdateResult(response); + def.resolve(response); + }); + return def.promise; + } + + createTransaction(transaction: ITransactionDetail) : ng.IPromise { + let def: ng.IDeferred = this.$q.defer(); + this.$http.post(this.api.createTransaction, transaction) + .success((response: IUpdateResonse) => { + def.resolve(response); + }); + return def.promise; + } + + getTransactionCodes() : ng.IPromise { + let def: ng.IDeferred = this.$q.defer(); + this.$http.get(this.api.getTransactionCodes) + .success((data: any) => { + def.resolve(data); + }); + return def.promise; + } + + private handleUpdateResult(response: IUpdateResonse): void { + if ((response && response.Success)) { + this.status = 'S'; + } else { + this.status = 'E'; + this.error = response.Error; + } + } +} \ No newline at end of file diff --git a/app/flight-detail/transactions/transaction-detail.tpl.html b/app/flight-detail/transactions/transaction-detail.tpl.html new file mode 100644 index 0000000..6be32be --- /dev/null +++ b/app/flight-detail/transactions/transaction-detail.tpl.html @@ -0,0 +1,83 @@ + + + + +
+
+ +
+
+ + +
+ +
+ +
+
+ +
+
\ No newline at end of file diff --git a/app/flight-detail/transactions/transaction-detail.ts b/app/flight-detail/transactions/transaction-detail.ts new file mode 100644 index 0000000..4ecf4b2 --- /dev/null +++ b/app/flight-detail/transactions/transaction-detail.ts @@ -0,0 +1,413 @@ +import {controller, directive} from '../../infrastructure/Dectorators/Components'; +import {ITransactionDetail} from '../services/transactionService'; +import {Mod} from './transaction.mod'; +import {IFlightInformation} from '../services/flightInformationService'; +import {IFlightDetail} from '../../core/service/flightService'; +import {ITransactionService, TransactionCode, ITransactionConfig} from '../services/transactionService'; +import * as InformationService from '../services/flightInformationService'; +import {LookupModel, EditorField, LookupEditorField} from '../services/flightInformationService'; + +export interface TransactionDetailParams extends ng.ui.IStateParamsService { + transaction: ITransactionDetail; + flight: IFlightDetail; + tranAccess: InformationService.IUserAccessModel; + columnConfig: Array; +} + +export class TransactionDetail implements ITransactionDetail { + constructor(public PublflightId: string, + public Id: string, + public Code:string, + public Name:string, + public Quantity: number, + public Duration: string, + public PONumber: string, + public StartTime: string, + public EndTime: string, + public PhysflightId: string, + public Confirmed: boolean, + public Cancelled: boolean, + public CodeType: number, + public Timestamp: number) { + } +} + +enum TransactionType { + QuantityOnly = 1, + TimesOnly, + TimeDurationAndQuantity +} + + + export class Editor implements InformationService.IFlightEditor { + constructor(public Name: string, + public Type: string, + public Url:string) { + + } + } + +@controller(Mod, 'transactionDetailController', ['$state', '$scope', '$stateParams', '$ionicPopup', '$rootScope', 'transactionService']) +export class Controller { + public model: ITransactionDetail; + public fields: Array; + public editors: Array; + public columnConfig: Array; + public IsNewAdd: boolean = false; + public flightId: string; + public physFlightId: string; + public lookupModel: LookupModel; + public confirmStatus: string; + public createStatus: string; + public cancelStatus: string; + public editStatus: string; + public selectedTranCode: TransactionCode; + public recalculatingDuration: boolean = false; + public recalculationFromDuration: boolean = false; + + constructor(private $state : ng.ui.IStateService, + private $scope: ng.IScope, + private $stateParams: TransactionDetailParams, + private $ionicPopup: ionic.popup.IonicPopupService, + private $rootScope: ng.IRootScopeService, + private transactionService: ITransactionService) { + this.model = $stateParams.transaction; + this.flightId = $stateParams.flight.Id; + this.physFlightId = $stateParams.flight.PhysFlightId; + if (this.model === null) { + this.initNewModel(); + this.IsNewAdd = true; + } + + this.columnConfig = $stateParams.columnConfig; + if (this.columnConfig === null) { + console.log('failed to get column config'); + } + + this.editors = []; + this.editors.push({Name: 'readonly', Type: 'readonly', Url: ''}); + this.editors.push({Name: 'datetime', Type: 'datetime', Url: ''}); + this.editors.push({Name: 'freetext', Type: 'freetext', Url: ''}); + this.editors.push({Name: 'lookup', Type: 'lookup', Url: '' }) ; + + this.createLookupModel(); + + this.buildFieldsFromModel(); + + if (!this.IsNewAdd) { + var trancode = new TransactionCode(); + trancode.CodeType = this.model.CodeType; + this.runDisplayLogic(trancode, false); + } else { + this.editorFor(this.fields[1]); + } + + } + + private initNewModel() { + this.model = new TransactionDetail(this.flightId, '', '', '', 0, '', '', '', '', this.physFlightId, false, false, 1, 0); + } + + public OnStartTimeChanged = (newValue, oldValue) => { + if (!this.recalculationFromDuration) { + if (oldValue.Value === newValue.Value) { + return; + } + + if (this.fieldByName('EndTime').Value !== '') { + this.recalculatingDuration = true; + this.recalculateDuration(); + } + } + this.recalculationFromDuration = false; + } + + public OnEndTimeChanged = (newValue, oldValue) => { + if (!this.recalculationFromDuration) { + if (oldValue.Value === newValue.Value) { + return; + } + + if (this.fieldByName('StartTime').Value !== '') { + this.recalculatingDuration = true; + this.recalculateDuration(); + } + } + + this.recalculationFromDuration = false; + } + + private recalculateDuration() { + var start = moment(this.fieldByName('StartTime').Value); + var end = moment(this.fieldByName('EndTime').Value); + this.fieldByName('Duration').Value = Math.round(moment.duration(end.diff(start)).asMinutes()).toString(); + } + + public OnDurationChanged = (newValue, oldValue) => { + if (!this.recalculatingDuration) { + if (oldValue.Value === newValue.Value) { + return; + } + + this.recalculationFromDuration = true; + + if (this.fieldByName('StartTime').Value !== '') { + this.recalculateEndTimeFromDurationAndCurrentStartTime(); + } else { + this.recalculateEndTimeFromStartIsNowPlusDuration(); + } + } + this.recalculatingDuration = false; + } + + private recalculateEndTimeFromDurationAndCurrentStartTime() { + var currentStart = moment(this.fieldByName('StartTime').Value); + this.fieldByName('EndTime').Value = currentStart.add(this.fieldByName('Duration').Value, 'minutes').toISOString(); + } + + private recalculateEndTimeFromStartIsNowPlusDuration() { + var startIsNow = moment(new Date()); + this.fieldByName('StartTime').Value = startIsNow.toISOString(); + this.fieldByName('EndTime').Value = startIsNow.add(this.fieldByName('Duration').Value, 'minutes').toISOString(); + } + + private addWatches() { + this.$scope.$watch('vm.fields[4]', this.OnStartTimeChanged, true); + this.$scope.$watch('vm.fields[5]', this.OnEndTimeChanged, true); + this.$scope.$watch('vm.fields[6]', this.OnDurationChanged, true); + } + + private createLookupModel() { + this.lookupModel = new LookupModel(); + this.lookupModel.searchString = ''; + this.lookupModel.resultField = 'Name'; + this.transactionService.getTransactionCodes() + .then((r) => this.onTransactionCodesLoad(r)); + + var self = this; + this.lookupModel.results = []; + + this.lookupModel.onSelected = (selectedTransactionCode: any) => { + self.runDisplayLogic(selectedTransactionCode, true); + self.selectedTranCode = selectedTransactionCode; + }; + + this.lookupModel.search = () => { + this.lookupModel.results = self.lookupModel.lookupList.filter(item => + item.Code.indexOf(self.lookupModel.searchString.toUpperCase()) !== -1 || + item.Name.indexOf(self.lookupModel.searchString.toUpperCase()) !== -1); + }; + } + + private onTransactionCodesLoad(request: any) : void { + this.lookupModel.lookupList = request; + this.lookupModel.results = this.lookupModel.lookupList; + } + + private findCode(value: any, searchStr: string) { + return value.Name === searchStr; + } + + public runDisplayLogic(selectedTransactionCode, notCreatedYet: boolean) { + var trancode = selectedTransactionCode as TransactionCode; + var fields = this.fields as EditorField[]; + + if (notCreatedYet) { + this.resetFields(fields); + fields[0].Value = selectedTransactionCode.Name; + fields[1].Value = selectedTransactionCode.Code; + } + + if (trancode.CodeType === TransactionType.QuantityOnly) { + fields[6].Invisible = true; //duration + fields[4].Invisible = true; //StartTime + fields[5].Invisible = true; //EndTime + } else if (trancode.CodeType === TransactionType.TimesOnly) { + fields[3].Invisible = true; + } + } + + private resetFields(fields: EditorField[]) { + for (var i = 0; i < fields.length; i++) { + fields[i].Invisible = false; + if (fields[i].Editor === 'datetime') { + fields[i].Value = ''; + } else { + fields[i].Value = null; + } + } + } + + private confirmTransaction() { + this.buildModelFromEditorFields(); + this.confirmStatus = 'P'; + this.transactionService.confirmTransaction(this.model) + .then(() => { + this.confirmStatus = 'S'; + this.$state.go('chroma.flight-detail.transaction-list'); + }); + } + + private cancelTransaction() { + this.buildModelFromEditorFields(); + this.cancelStatus = 'P'; + this.transactionService.cancelTransaction(this.model) + .then(() => { + this.cancelStatus = 'S'; + this.$state.go('chroma.flight-detail.transaction-list'); + }); + } + + private buildFieldsFromModel() { + this.fields = []; + + this.fields.push(new EditorField('Name', this.model.Name, 'readonly', '', '', '', true, false)); + this.fields.push(new LookupEditorField('Code', this.model.Code, this.editorOrReadonly('FLGTTRAN_TRANCATG_CODE', 'lookup'), '', '', this.lookupModel, '', true, false)); + this.fields.push(new EditorField('PONumber', this.model.PONumber, this.editorOrReadonly('FLGTTRAN_PO_NUMBER', 'freetext'), '', '', '', true, false)); + this.fields.push(new EditorField('Quantity', this.model.Quantity.toString(), this.editorOrReadonly('FLGTTRAN_QUANTITY', 'freetext'), '', '', '', true, false)); + this.fields.push(new EditorField('StartTime', this.model.StartTime, this.editorOrReadonly('FLGTTRAN_START_DATE_TIME', 'datetime') , '', '', '', true, false)); + this.fields.push(new EditorField('EndTime', this.model.EndTime, this.editorOrReadonly('FLGTTRAN_END_DATE_TIME', 'datetime'), '', '', '', true, false)); + this.fields.push(new EditorField('Duration', this.model.Duration, this.editorOrReadonly('FLGTTRAN_DURATION', 'freetext'), '', '', '', true, false)); + + this.addWatches(); + } + + private editorOrReadonly(fieldName: string, type: string) { + var editable = this.columnAccessByFieldName(fieldName); + if (editable) { + return type; + } + return 'readonly'; + } + + private columnAccessByFieldName(name: string) : boolean { + if (this.IsNewAdd !== true) { + return false; //can't edit fields on modify screen + } + + let col : ITransactionConfig = this.columnConfig.filter(item => item.ColumnName.indexOf(name) !== - 1)[0]; + return col.Editable; + } + + private createTransaction() { + this.buildModelFromEditorFields(); + if (this.formIsValid()) { + this.transactionService.createTransaction(this.model) + .then(() => + this.$state.go('chroma.flight-detail.transaction-list') + ); + } + } + + private formIsValid() : boolean { + let editorFields = this.fields as Array; + var valid = true; + + editorFields.forEach(element => { + if (element.Invisible === false) { + if (!this.validateQuantity(element)) { + valid = false; + } + if (!this.validateTimes(element)) { + valid = false; + } + if (!this.validateTimesAndQuantity(element)) { + valid = false; + } + } + }); + return valid; + } + + private validateQuantity(element: EditorField) : boolean { + if (this.selectedTranCode.CodeType === TransactionType.QuantityOnly || this.selectedTranCode.CodeType === TransactionType.TimeDurationAndQuantity) { + if (element.Name === 'Quantity' && (element.Value === '' || element.Value === null)) { + element.Invalid = true; + return false; + } + } + return true; + } + + private validateTimes(element: EditorField) : boolean { + if (this.selectedTranCode.CodeType === TransactionType.TimesOnly || this.selectedTranCode.CodeType === TransactionType.TimeDurationAndQuantity) { + if ((element.Name === 'StartTime' || element.Name === 'EndTime' || element.Name === 'Duration') + && (element.Value === '' || element.Value === null)) { + element.Invalid = true; + return false; + } + } + return true; + } + + private validateTimesAndQuantity(element: EditorField) : boolean { + if (this.selectedTranCode.CodeType === TransactionType.TimeDurationAndQuantity) { + return this.validateTimes(element) && this.validateQuantity(element); + } + return true; + } + + private buildModelFromEditorFields() { + var publflgt = this.model.PublflightId; + var Id = this.model.Id; + var physFlightId = this.model.PhysflightId; + var timestamp = this.model.Timestamp; + + this.model = new TransactionDetail(publflgt, + Id, + this.fieldByName('Code').Value, + this.fieldByName('Name').Value, + Number(this.fieldByName('Quantity').Value), + this.fieldByName('Duration').Value, + this.fieldByName('PONumber').Value, + this.fieldByName('StartTime').Value, + this.fieldByName('EndTime').Value, + physFlightId, + this.model.Confirmed, + this.model.Cancelled, 1, + timestamp); + } + + private fieldByName(name: string) : IFlightInformation { + let field : IFlightInformation = this.fields.filter(item => item.Name.indexOf(name) !== -1)[0]; + return field; + } + + public editorFor(field: InformationService.IFlightInformation) { + if (field.Editor.toLowerCase() === 'readonly') { return; } + let editor = field.Editor.toLowerCase(); + let modalScope: any = this.$rootScope.$new(); + let editorDefinition: InformationService.IFlightEditor; + + this.editors.forEach(e => { + if (e.Name.toLowerCase() === editor) { + editorDefinition = e; + } + }); + + modalScope.model = this.model; + modalScope.field = field; + modalScope.editor = editorDefinition; + + if (field.Editor.toLowerCase() === 'lookup') { + modalScope.lookupModel = this.lookupModel; + } + + modalScope.instance = this.$ionicPopup.show({ + templateUrl: `app/flight-detail/editors/${editor}/${editor}-holder.tpl.html`, + cssClass: `editor editor-${editor}`, + title: `Update ${field.Name}`, + scope: modalScope + }); + } +} + +@directive(Mod, 'chromaTransactionDetail') +export class Directive implements ng.IDirective { + controller: string = Controller.$componentName; + controllerAs: string = 'vm'; + templateUrl: string = 'app/flight-detail/transactions/transaction-detail.tpl.html'; + restrict: string = 'E'; + replace: boolean = false; + scope: any = true; +} \ No newline at end of file diff --git a/app/flight-detail/transactions/transaction-list.less b/app/flight-detail/transactions/transaction-list.less new file mode 100644 index 0000000..c554d84 --- /dev/null +++ b/app/flight-detail/transactions/transaction-list.less @@ -0,0 +1,105 @@ +.icon-base{ + font-size: 110%; +} + +.icon-status-off{ + .icon-base; + color:lightgrey; +} + +.icon-status-on-green{ + .icon-base; + color:green; +} + +.icon-status-on-red{ + .icon-base; + color: red; +} + +.large-descriptor{ + font-size:15pt; +} + +body { + cursor: url("http://ionicframework.com/img/finger.png"), auto; +} + +button.button-icon.round-overlay-button { + position: absolute; + height: 56px; + width: 56px; + border-radius: 50%; + min-height: 56px; + padding: 0; + border: none; + background-color: #ffc900; + color: white; + box-shadow: 0 2px 10px 0 rgba(0, 0, 0, 0.16), 0 2px 5px 0 rgba(0, 0, 0, 0.26); + transition: all linear 220ms; + transform: translate3d(0, 0, 0); + backface-visibility: hidden; +} +button.button-icon.round-overlay-button.energized { + background-color: #ffc900; + color: white; +} +button.button-icon.round-overlay-button.energized.activated { + background-color: #b38d00; +} +button.button-icon.round-overlay-button.assertive { + background-color: #567aae; + color: white; +} +button.button-icon.round-overlay-button.assertive.activated { + background-color: #00398a; +} +button.button-icon.round-overlay-button.positive { + background-color: #387ef5; + color: white; +} +button.button-icon.round-overlay-button.positive.activated { + background-color: #0b56d6; +} +button.button-icon.round-overlay-button.stable { + background-color: rgba(0, 0, 0, 0.26); + color: rgba(0, 0, 0, 0.26); +} +button.button-icon.round-overlay-button.stable.activated { + background-color: rgba(0, 0, 0, 0.26); +} +button.button-icon.round-overlay-button.icon:before { + font-size: 24px; +} +button.button-icon.round-overlay-button.small { + height: 40px; + width: 40px; + min-height: 40px; + padding: 0; + border: none; +} +button.button-icon.round-overlay-button.small.icon:before { + line-height: 40px; +} +button.button-icon.round-overlay-button.activated { + opacity: 1; + box-shadow: 0 6px 20px 0 rgba(0, 0, 0, 0.19), 0 8px 17px 0 rgba(0, 0, 0, 0.2); +} +button.button-icon.round-overlay-button.left { + left: 1px; + top: 16px; +} +button.button-icon.round-overlay-button.bottom-edge-right { + bottom: -24px; + right: 150px; + z-index: 12; +} +button.button-icon.round-overlay-button.bottom-right { + bottom: 0; + margin-bottom: 20px; + right: 10px; + z-index: 2; +} +button.button-icon.round-overlay-button.bottom-right.slide-down { + transform: translate3d(0, 88px, 0); +} \ No newline at end of file diff --git a/app/flight-detail/transactions/transaction-list.spec.ts b/app/flight-detail/transactions/transaction-list.spec.ts new file mode 100644 index 0000000..e8673d6 --- /dev/null +++ b/app/flight-detail/transactions/transaction-list.spec.ts @@ -0,0 +1,138 @@ +import {Directive, Controller, TransactionListParams} from './transaction-list' +import {ComponentTest} from '../../infrastructure/ComponentHelper'; +import {Mod as CoreModule} from '../../core/core.mod'; +import FlightDetailModule from '../../flight-detail/flight-detail.mod'; +import {ITransactionDetail} from '../services/transactionService'; +import {IFlightDetail} from '../../core/service/flightService'; + + +class TransactionListTest extends ComponentTest { + public api: any; + public $stateParams: TransactionListParams; + public $state: ng.ui.IStateService; + public transactions: Array; + public ctrl: Controller; + public testModel: IFlightDetail; + public compileString: string = ''; + + constructor(){ + super(Directive.$componentName, 'app/flight-detail/transactions/transaction-list.tpl.html'); + } + + public setup(): void { + this.testModel = { + Id: "123", + Location: undefined, + Operator: undefined, + Number: undefined, + AircraftType: undefined, + Registration: undefined, + Stand: undefined, + Terminal: undefined, + Actual: undefined, + Scheduled: undefined, + Estimated: undefined, + Type: 'D' + } + } + + public buildTransactionList(count: number): void { + this.transactions = []; + + for(let i=0; i < count; i++){ + let iStr = i.toString(); + this.transactions.push({ + Id: iStr, + Code: iStr + iStr + iStr, + Name: 'Transaction' + i, + Duration: '250', + PONumber: 'ZZZZ' + i.toString(), + StartTime: '09:00', + EndTime: '12:4' + iStr, + Quantity: i * i, + Confirmed: true, + Cancelled:false + }); + } + } + + public setupForSuccessfulGet(): void { + this.$stateParams.flightId = '123'; + console.log(this.transactions) + this.buildTransactionList(4); + console.log(this.transactions); + let expectedUrl = this.api.transactions + "?flightId=" + this.$stateParams.flightId; + + this.$httpBackend.expectGET(expectedUrl) + .respond(201, { + Transactions: this.transactions + }); + + this.ctrl = this.compile({model: this.testModel}, this.compileString); + console.log(this.ctrl); + } +} + +describe('Transaction List View Tests', () => { + let instance: TransactionListTest, + core: CoreModule, + flightDetail: FlightDetailModule; + + beforeEach(() => { + if(!instance) { + core = new CoreModule(angular); + flightDetail = new FlightDetailModule(angular); + + angular.mock.module('ui.router'); + angular.mock.module('ionic'); + angular.mock.module('chroma.configuration'); + angular.mock.module(CoreModule.$componentName); + angular.mock.module(FlightDetailModule.$componentName); + + angular.mock.inject((api, $state, $stateParams) => { + instance = new TransactionListTest(); + instance.setup(); + instance.api = api; + instance.$state = $state; + instance.$stateParams = $stateParams; + }); + } + }); + + it('Directive is compiled', () => { + instance.flushOnInit = false; + + instance.setup(); + + instance.ctrl = instance.compile({model: this.testModel}, instance.compileString); + console.log(instance.ctrl); + expect(instance.ctrl).toBeDefined(); + }); + + it('Flight has 4 transactions and 4 transactions are displayed', () => { + console.log(instance); + instance.setupForSuccessfulGet(); + + console.log(instance.ctrl); + + expect(instance.ctrl).toBeDefined(); + expect(instance.ctrl.transactions).toBeDefined(); + expect(instance.ctrl.transactions.length).toEqual(4); + expect(instance.ctrl.transactions).toEqual(instance.transactions); + }); + + it('Transaction Detail shown when transaction pressed', () => { + instance.setupForSuccessfulGet(); + + let firstTran = instance.ctrl.transactions[0]; + + spyOn(instance.$state, "go"); + + instance.ctrl.showTransactionDetail(firstTran); + + expect(instance.$state.go).toHaveBeenCalledWith('chroma.flight-detail.transaction-detail', { + transaction: firstTran + }); + }); +}); + diff --git a/app/flight-detail/transactions/transaction-list.tpl.html b/app/flight-detail/transactions/transaction-list.tpl.html new file mode 100644 index 0000000..9a3ddf8 --- /dev/null +++ b/app/flight-detail/transactions/transaction-list.tpl.html @@ -0,0 +1,69 @@ + + +
+
+ +
+
+ + + + + + + + +
+
+ + {{trn.Name}} + +
+
+
+ + +
+
+
+
+ PONum: {{trn.PONumber}}   +
+
+ Code: {{trn.Code}}   +
+
+ Dur: {{trn.Duration}} +
+
+
+
+
+ Quan: {{trn.Quantity}} +
+
+ Start: {{trn.StartTime}} +
+
+
+
+
+
+
+ End: {{trn.EndTime}} +
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/app/flight-detail/transactions/transaction-list.ts b/app/flight-detail/transactions/transaction-list.ts new file mode 100644 index 0000000..17e9a99 --- /dev/null +++ b/app/flight-detail/transactions/transaction-list.ts @@ -0,0 +1,117 @@ +import {controller, directive} from '../../infrastructure/Dectorators/Components'; +import {Mod} from './transaction.mod'; +import {ITransactionService, ITransactionDetail, ITransactionConfig, ITransactionListRequest} from '../services/transactionService'; +import * as InformationService from '../services/flightInformationService'; +import {IFlightDetail} from '../../core/service/flightService'; + +export interface TransactionListParams extends ng.ui.IStateParamsService { + flightId: string; + transaction:any; + tranAccessModel: InformationService.IUserAccessModel; +} + + +@controller(Mod, 'transactionListController', ['transactionService', '$stateParams', '$state', '$rootScope', 'chromaState']) +export class Controller { + public static NO_TRANSACTIONS = 'This flight has no transactions'; + public transactions: Array; + public message: string; + public request: ITransactionListRequest; + public flightId: string; + public model: IFlightDetail; + public columnConfig: Array; + public signalRInitiated: boolean; + public status: string; + public loading: boolean = true; + + constructor(private transactionService: ITransactionService, + private $stateParams: TransactionListParams, + private $state: ng.ui.IStateService, + private $rootScope: ng.IScope) { + this.load(); + } + + public load() : void { + this.status = 'loadingAddPage'; + this.transactionService.getTransactionConfig(this.model.Id, this.model.PhysFlightId) + .then((colConfig) => { + this.status = 'awaitingAdd'; + this.transactionService.getTransactions(this.model.Id, this.model.PhysFlightId) + .then((transactions) => this.onTransactionsLoad(transactions, colConfig)); + }); + } + + private setupSignalRHandler = () => { + this.$rootScope.$on('recieveHandlingTransactionAdd', (event, args) => { + this.load(); + console.log('transaction received in transaction list view with Id ' + args.message.TransactionId); + }); + + this.$rootScope.$on('recieveHandlingTransactionCancelled', (event, args) => { + if (this.transactions.length > 0) { + var matchedTransaction = this.transactions.filter(item => item.Id.indexOf(args.message.TransactionId) !== -1)[0]; + if (matchedTransaction) { + matchedTransaction.Cancelled = true; + this.load(); + } + } + console.log('transaction cancelled in transaction list view with Id ' + args.message.TransactionId); + }); + } + + + + private onTransactionsLoad(transactions: any, colConfig): void { + this.transactions = transactions; + this.columnConfig = colConfig; + + this.loading = false; + + if (this.signalRInitiated !== true) { + this.setupSignalRHandler(); + this.signalRInitiated = true; + } + + if (!this.transactions || this.transactions.length === 0) { + this.message = Controller.NO_TRANSACTIONS; + } + + } + + public showTransactionDetail(transaction: ITransactionDetail) { + if (this.columnConfig !== null) { + this.$state.go('chroma.flight-detail.transaction-detail', { + transaction: transaction, + tranAccess: this.$stateParams.tranAccessModel, + columnConfig: this.columnConfig + }); + } else { + console.log('columnConfig is null'); + } + } + + public showAddTransaction() { + if (this.columnConfig != null) { + this.$state.go('chroma.flight-detail.transaction-detail', { + transaction: undefined, + tranAccess: this.$stateParams.tranAccessModel, + columnConfig: this.columnConfig + }); + } else { + console.log('columnConfig is null'); + } + } +} + +@directive(Mod, 'chromaTransactionList', ['$stateParams']) +export class Directive implements ng.IDirective { + controller: string = Controller.$componentName; + controllerAs: string = 'vm'; + templateUrl: string = 'app/flight-detail/transactions/transaction-list.tpl.html'; + restrict: string = 'E'; + replace: boolean = false; + bindToController: boolean = true; + scope: any = { + model: '=' + }; +} \ No newline at end of file diff --git a/app/flight-detail/transactions/transaction.config.ts b/app/flight-detail/transactions/transaction.config.ts new file mode 100644 index 0000000..e1edd83 --- /dev/null +++ b/app/flight-detail/transactions/transaction.config.ts @@ -0,0 +1,19 @@ +import {inject} from '../../infrastructure/Dectorators/Components'; + +@inject(['$stateProvider']) +export class Routes { + constructor ($stateProvider: ng.ui.IStateProvider) { + $stateProvider + .state('chroma.flight-detail.transaction-detail', { + url: '/transaction-detail', + params: { + transaction: undefined + }, + views: { + 'detail':{ + template: '' + } + } + }); + } +} \ No newline at end of file diff --git a/app/flight-detail/transactions/transaction.mod.ts b/app/flight-detail/transactions/transaction.mod.ts new file mode 100644 index 0000000..7582a1a --- /dev/null +++ b/app/flight-detail/transactions/transaction.mod.ts @@ -0,0 +1,21 @@ +import Dectorators = require('../../infrastructure/Dectorators/Components'); +import TransactionListComp = require('./transaction-list'); +import TransactionDetailComp = require('./transaction-detail'); +import {TransactionService} from '../services/transactionService'; +import Config = require('./transaction.config'); + +@Dectorators.module('transaction-list') +export class Mod { + constructor (angular: ng.IAngularStatic) { + angular.module(Mod.$componentName, []) + .factory(TransactionService.$componentName, TransactionService.$factory) + + .controller(TransactionListComp.Controller.$componentName, TransactionListComp.Controller) + .directive(TransactionListComp.Directive.$componentName, TransactionListComp.Directive.$factory) + + .controller(TransactionDetailComp.Controller.$componentName, TransactionDetailComp.Controller) + .directive(TransactionDetailComp.Directive.$componentName, TransactionDetailComp.Directive.$factory) + + .config(Config.Routes); + } +} \ No newline at end of file diff --git a/app/flight-list/flight-list.config.ts b/app/flight-list/flight-list.config.ts new file mode 100644 index 0000000..6f7a5b8 --- /dev/null +++ b/app/flight-list/flight-list.config.ts @@ -0,0 +1,16 @@ +import FlightService = require('../core/service/flightService'); + +export class Routes { + static $inject: Array = ['$stateProvider']; + + constructor($stateProvider: ng.ui.IStateProvider) { + $stateProvider.state('chroma.flight-list', { + url: '/flight-list/:filter', + views: { + 'content': { + template: '' + } + } + }); + } +} diff --git a/app/flight-list/flight-list.mod.ts b/app/flight-list/flight-list.mod.ts new file mode 100644 index 0000000..3583f48 --- /dev/null +++ b/app/flight-list/flight-list.mod.ts @@ -0,0 +1,38 @@ +import Dectorators = require('../infrastructure/Dectorators/Components'); +import FlightListComp = require('./list/flight-list'); +import Config = require('./flight-list.config'); + +@Dectorators.module('flight-list') +export class Mod { + constructor(angular: ng.IAngularStatic) { + angular.module(Mod.$componentName, []) + .controller(FlightListComp.Controller.$componentName, FlightListComp.Controller) + .directive(FlightListComp.Directive.$componentName, FlightListComp.Directive.$factory) + .filter('fieldListFilter', () => { + return (items: any, query: any, fields: any) => { + if (items == null || query == null || fields == null) { + return items; + } + + var filtered = []; + var letterMatch = new RegExp(query, 'i'); + + for (var i = 0; i < items.length; i++) { + var item = items[i]; + + for (var j = 0; j < fields.length; j++) { + if (query && query.length > 0) { + if (letterMatch.test(item[fields[j]].substring(0, query.length))) { + filtered.push(item); + } + } else { + filtered.push(item); + } + } + } + return filtered; + }; + }) + .config(Config.Routes); + } +} diff --git a/app/flight-list/list/flight-list.less b/app/flight-list/list/flight-list.less new file mode 100644 index 0000000..cc34fb7 --- /dev/null +++ b/app/flight-list/list/flight-list.less @@ -0,0 +1,88 @@ +@arrivalColor: #f44336; +@departureColor: #1565c0; + +.search-container { + margin-top: 5px; +} + +.search-input { + padding-bottom: 0; +} + +.padding-top { + padding-top: 5px; +} + +.flight-detail { + padding-right: 0; + + &.flight-header { + padding: 10px 0 10px 0 !important; + font-size: 110%; + + img { + top: 14px !important; + left: 10px !important; + max-width: 60px !important; + max-height: 60px !important; + } + } + + img { + top: 14px !important; + left: 10px !important; + max-width: 50px !important; + max-height: 50px !important; + } + + .arrival { + border: 1px solid @arrivalColor; + + .ind-text { + color: @arrivalColor; + small { + font-size: 75%; + } + } + } + + .departure { + border: 1px solid @departureColor; + + .ind-text { + color: @departureColor; + small { + font-size: 75%; + } + } + } + + .descriptor { + font-family: Roboto-Thin; + color: #d2d2d2; + } + + .item { + color: #b6b5b5; + border-color: transparent; + } + + .item { + .row { + padding: 0; + padding-top: 5px; + + .col { + padding: 0; + } + } + } + + .shunt-down-text { + margin-top: 3px; + } +} + +.ionic-refresher-content { + color: #00398a; +} diff --git a/app/flight-list/list/flight-list.spec.ts b/app/flight-list/list/flight-list.spec.ts new file mode 100644 index 0000000..c211336 --- /dev/null +++ b/app/flight-list/list/flight-list.spec.ts @@ -0,0 +1,268 @@ +import {Mod as CoreModule} from '../../core/core.mod'; +import {Mod as FlightListModule} from '../flight-list.mod'; +import FlightDetailModule from '../../flight-detail/flight-detail.mod'; +import {Directive, Controller, FlightListParams} from './flight-list'; +import {IFlightDetail} from './../../core/service/flightService'; +import {ComponentTest} from'../../infrastructure/ComponentHelper'; + +class FlightListTest extends ComponentTest { + public api: any; + public $stateParams: FlightListParams; + public $state: ng.ui.IStateService; + public flights: Array; + public ctrl: Controller; + constructor() { + super(Directive.$componentName, + 'app/flight-list/list/flight-list.tpl.html'); + } + public buildFlights(count: number): void { + this.flights = []; + for (let i = 0; i < count; i++) { + this.flights.push({ + Id: '1', Type: 'A', Operator: 'SK', Number: '0214' + i, AircraftType: '333' + i, + Registration: 'PK-GPE' + i, Location: 'MAN', Scheduled: '09:00', Estimated: + '09:00', Actual: '09:00', Terminal: 'T1', Stand: 'A' + i, FlightConcat: 'SK' + '0214' + i + }); + } + } + public setUpForSuccessfulGet(): void { + this.$stateParams.filter = "default"; + + this.buildFlights(5); + + let expectedUrl = this.api.flightList + "?window=" + this.$stateParams.filter; + + this.$httpBackend.expectGET(expectedUrl) + .respond(201, { Flights: this.flights, RequestId: 'ste1234567' }); + + this.ctrl = this.compile(); + } + + public setUpForNoFlightsGet(): void { + this.$stateParams.filter = "default"; + + let expectedUrl = this.api.flightList + "?window=" + this.$stateParams.filter; + + this.$httpBackend.expectGET(expectedUrl) + .respond(201, { Flights: new Array(), RequestId: 'ste1234567' }); + + this.ctrl = this.compile(); + } +} + +describe('Framework: fieldListFilter', () => { + let $filter: any; + let instance: FlightListTest, + flightList: FlightListModule, + core: CoreModule, + flightDetail: FlightDetailModule; + + beforeEach(() => { + if (!instance) { + core = new CoreModule(angular); + flightList = new FlightListModule(angular); + flightDetail = new FlightDetailModule(angular); + + angular.mock.module('ui.router'); + angular.mock.module('ionic'); + angular.mock.module('chroma.configuration'); + angular.mock.module(CoreModule.$componentName); + angular.mock.module(FlightDetailModule.$componentName); + angular.mock.module(FlightListModule.$componentName); + + angular.mock.inject((_$filter_, $state, $stateParams, api) => { + instance = new FlightListTest(); + $filter = _$filter_; + instance.$state = $state; + instance.$stateParams = $stateParams; + instance.api = api; + }); + } + + }); + + it('Flight Filter: should return flight SK02141 when I search with SK02141', () => { + instance.setUpForSuccessfulGet(); + + instance.buildFlights(5); + + let result = $filter('fieldListFilter')(instance.ctrl.flights, 'SK02141', ['Number', + 'Operator', 'AircraftType', 'Location', 'Terminal', 'Registration', + 'Stand', 'FlightConcat']); + + expect(result.length).toBe(1); + + expect(result[0].FlightConcat).toBe('SK02141'); + + }); + + it('fieldListFilter: filter should be registered', () => { + let result = $filter('fieldListFilter'); + + expect(result).not.toBeUndefined(); + }); + + it('fieldListFilter: empty query string should return all flight results', () => { + instance.buildFlights(5); + + let result = $filter('fieldListFilter')(instance.ctrl.flights, '', ['Number', + 'Operator', 'AircraftType', 'Location', 'Terminal', 'Registration', + 'Stand', 'FlightConcat']); + + expect(instance.ctrl.flights.length).toBe(5); + }); + + it('fieldListFilter: should return flight with stand A1 when I search for A1', () => { + instance.setUpForSuccessfulGet(); + + instance.buildFlights(5); + + let result = $filter('fieldListFilter')(instance.ctrl.flights, 'A1', ['Number', + 'Operator', 'AircraftType', 'Location', 'Terminal', 'Registration', + 'Stand', 'FlightConcat']); + + expect(result.length).toBe(1); + + expect(result[0].Stand).toBe('A1'); + }); + + + it('fieldListFilter: should return flight with aircraft type 331 when I search for 331', () => { + instance.setUpForSuccessfulGet(); + + instance.buildFlights(5); + + let result = $filter('fieldListFilter')(instance.ctrl.flights, '3331', ['Number', + 'Operator', 'AircraftType', 'Location', 'Terminal', 'Registration', + 'Stand', 'FlightConcat']); + + expect(result.length).toBe(1); + + expect(result[0].AircraftType).toBe('3331'); + }); + + it('fieldListFilter: should return flight with registration PK-GPE2 when I search for PK-GPE2', () => { + instance.setUpForSuccessfulGet(); + + instance.buildFlights(5); + + let result = $filter('fieldListFilter')(instance.ctrl.flights, 'PK-GPE2', ['Number', + 'Operator', 'AircraftType', 'Location', 'Terminal', 'Registration', + 'Stand', 'FlightConcat']); + + expect(result.length).toBe(1); + + expect(result[0].Registration).toBe('PK-GPE2'); + }); + + it('fieldListFilter: should return all flights when I search for PK-GPE as they all start with that', () => { + instance.setUpForSuccessfulGet(); + + instance.buildFlights(5); + + let result = $filter('fieldListFilter')(instance.ctrl.flights, 'PK-GPE', ['Number', + 'Operator', 'AircraftType', 'Location', 'Terminal', 'Registration', + 'Stand', 'FlightConcat']); + + expect(result.length).toBe(5); + }); + + it('fieldListFilter: should return all flights when I search T1 as they are all assigned that terminal', () => { + instance.setUpForSuccessfulGet(); + + instance.buildFlights(5); + + let result = $filter('fieldListFilter')(instance.ctrl.flights, 'T1', ['Number', + 'Operator', 'AircraftType', 'Location', 'Terminal', 'Registration', + 'Stand', 'FlightConcat']); + + expect(result.length).toBe(5); + }); +}); + +describe('Flight List View Tests', () => { + let instance: FlightListTest, + core: CoreModule, + flightDetail: FlightDetailModule, + flightList: FlightListModule; + + beforeEach(() => { + if (!instance) { + core = new CoreModule(angular); + flightDetail = new FlightDetailModule(angular); + flightList = new FlightListModule(angular); + + angular.mock.module('ui.router'); + angular.mock.module('ionic'); + angular.mock.module('chroma.configuration'); + angular.mock.module(CoreModule.$componentName); + angular.mock.module(FlightDetailModule.$componentName); + angular.mock.module(FlightListModule.$componentName); + + angular.mock.inject((api, $state, $stateParams) => { + instance = new FlightListTest(); + instance.api = api; + instance.$state = $state; + instance.$stateParams = $stateParams; + }); + } + }); + + it('Filter has 5 flights and 5 flights displayed', () => { + instance.setUpForSuccessfulGet(); + expect(instance.ctrl).toBeDefined(); + expect(instance.ctrl.flights).toBeDefined(); + expect(instance.ctrl.flights.length).toEqual(5); + expect(instance.ctrl.flights).toEqual(instance.flights); + }); + + it('New flight is added when refreshed', () => { + + instance.setUpForSuccessfulGet(); + + var currentCount = instance.ctrl.flights.length; + + instance.buildFlights(6); + + let expectedUrl = instance.api.flightList + "?window=" + instance.$stateParams.filter; + + instance.$httpBackend.expectGET(expectedUrl) + .respond(201, { Flights: instance.flights, RequestId: 'ste1234567' }); + + instance.ctrl.load(false); + + instance.$httpBackend.flush(); + + expect(instance.ctrl.flights.length).toBe(6); + + expect(instance.ctrl.flights.length).toBeGreaterThan(currentCount); + }); + + it('Detail shown when flight pressed', () => { + + let firstFlight = instance.flights[0], + requestId = 'ste1234567'; + + spyOn(instance.$state, "go"); + + instance.ctrl.showDetail(firstFlight); + + expect(instance.$state.go).toHaveBeenCalledWith('chroma.flight-detail', { + id: firstFlight.Id, + flight: firstFlight, + requestId: requestId + }); + + }); + + it('No flights error message displayed', () => { + + instance.setUpForNoFlightsGet(); + + expect(instance.ctrl.flights.length).toBe(0); + + expect(instance.ctrl.message).toBe(Controller.NO_FLIGHTS_MESSAGE); + }); + + +}); diff --git a/app/flight-list/list/flight-list.tpl.html b/app/flight-list/list/flight-list.tpl.html new file mode 100644 index 0000000..307ecf7 --- /dev/null +++ b/app/flight-list/list/flight-list.tpl.html @@ -0,0 +1,66 @@ + + + +
+

+
{{vm.message}}
+ Go back? +

+
+ + +
+
diff --git a/app/flight-list/list/flight-list.ts b/app/flight-list/list/flight-list.ts new file mode 100644 index 0000000..3eb6c32 --- /dev/null +++ b/app/flight-list/list/flight-list.ts @@ -0,0 +1,67 @@ + +import {controller, directive} from '../../infrastructure/Dectorators/Components'; +import {FlightService, IFlightDetail, IFlightListRequest, IFlightService} from '../../core/service/flightService'; +import {IFlightInformationService} from '../../flight-detail/services/flightInformationService'; +import {Mod} from '../flight-list.mod'; + +export interface FlightListParams extends ng.ui.IStateParamsService { + filter: string; +} + +@controller(Mod, 'flightListController', ['flightService', '$stateParams', '$state', '$window', 'flightInformationService']) +export class Controller { + + public static NO_FLIGHTS_MESSAGE = 'This window has no flights'; + + public flights: Array; + public request: IFlightListRequest; + public loading: boolean = true; + public window: string; + public message: string; + + constructor(private flightService: IFlightService, + private $stateParams: FlightListParams, + private $state: ng.ui.IStateService, + private $window: ng.IWindowService, + public flightInformationService: IFlightInformationService) { + this.window = this.$stateParams.filter; + this.$window.sessionStorage.setItem('chroma:current-filter', this.window); + this.load(); + } + public load(initial: boolean = true): void { + if (!initial) { + this.loading = true; + } + + this.flightService.getFilter(this.window, !initial) + .then((r) => this.onFilterLoad(r)); + } + private onFilterLoad(request: any): void { + this.request = request; + + this.flights = request.Flights; + + if (!this.flights || this.flights.length === 0) { + this.message = Controller.NO_FLIGHTS_MESSAGE; + } + + this.loading = false; + } + public showDetail(flight: IFlightDetail): void { + this.$state.go('chroma.flight-detail', { + id: flight.Id, + flight: flight, + requestId: this.request.RequestId + }); + } +} + +@directive(Mod, 'chromaFlightList', ['$stateParams']) +export class Directive implements ng.IDirective { + controller: string = Controller.$componentName; + controllerAs: string = 'vm'; + templateUrl: string = 'app/flight-list/list/flight-list.tpl.html'; + restrict: string = 'E'; + replace: boolean = false; + scope: any = true; +} diff --git a/app/index.html b/app/index.html new file mode 100644 index 0000000..fa7c8be --- /dev/null +++ b/app/index.html @@ -0,0 +1,47 @@ + + + + Chroma AODB + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/infrastructure/ComponentHelper.ts b/app/infrastructure/ComponentHelper.ts new file mode 100644 index 0000000..98c177d --- /dev/null +++ b/app/infrastructure/ComponentHelper.ts @@ -0,0 +1,72 @@ +class BaseComponentTest { + public $compile: ng.ICompileService; + public $rootScope: ng.IRootScopeService; + public $httpBackend: ng.IHttpBackendService; + public $templateCache: ng.ITemplateCacheService; + + constructor() { + angular.mock.inject(($compile, $rootScope, $httpBackend, $templateCache) => { + this.$compile = $compile; + this.$rootScope = $rootScope; + this.$httpBackend = $httpBackend; + this.$templateCache = $templateCache; + }); + } +} + + +export class ComponentTest extends BaseComponentTest { + + public templateURL: string; + public componentName: string; + public flushOnInit: boolean; + + constructor(componentName: string, templateURL: string) { + super(); + this.componentName = componentName; + this.templateURL = templateURL; + this.flushOnInit = true; + + this.$httpBackend.expectGET(this.templateURL) + .respond(201, this.$templateCache.get(this.templateURL)); + + } + public compile(args: any = null, customCompileString: string = null): T { + let actCompName = this.componentName.replace(/([a-z])([A-Z])/g, '$1:$2'); + let scope: any = this.$rootScope.$new(); + let dir: any; + if (args) { + console.log(args); + angular.extend(this.$rootScope, args); + + if (customCompileString) { + dir = this.$compile(angular.element(customCompileString))(scope); + } else { + console.log(args); + dir = this.$compile(angular.element(`<${actCompName}>`))(scope); + console.log(dir); + } + + scope.$digest(); + + if (this.flushOnInit) { + this.$httpBackend.flush(); + } + + } else { + dir = this.$compile(angular.element(`<${actCompName}>`))(scope); + scope.$digest(); + if (this.flushOnInit) { + this.$httpBackend.flush(); + } + } + if (dir.controller(this.componentName) === undefined) { + console.log(this.componentName); + console.log(dir); + } else { + console.log(dir); + } + + return dir.controller(this.componentName); + } +} diff --git a/app/infrastructure/Dectorators/Components.ts b/app/infrastructure/Dectorators/Components.ts new file mode 100644 index 0000000..acaf38f --- /dev/null +++ b/app/infrastructure/Dectorators/Components.ts @@ -0,0 +1,88 @@ +function log(text: string) { + let w: any = window; + if (w.debuging) { + console.log(text); + } +} + +export function inject(deps: Array) { + return (obj: any) => { + obj.$inject = deps; + }; +} + +export function module(name: string, dep: Array = []) { + return (obj: any) => { + + let modName = 'chroma.' + name; + + obj.$componentName = modName; + + log(`${modName} registered`); + }; +} + +export function service(mod: any, name: string, dep: Array = []) { + return (obj: any) => { + obj.$inject = dep; + + obj.$componentName = name; + + log(`Service/Provider ${name} registered.`); + }; +} + +export function controller(mod: any, name: string, dep: Array = []) { + + return (obj: any) => { + + obj.$inject = dep; + + obj.$componentName = name; + + log(`Controller ${name} registered.`); + }; +} + +export function factory(mod: any, name: string, dep: Array = []) { + + return (obj: any) => { + + obj.$componentName = name; + + obj.$inject = dep; + + const factory: Function = function(...args: any[]) { + var instance = Object.create(obj.prototype); + instance.constructor.apply(instance, arguments); + return instance; + }; + + factory.$inject = dep; + + obj.$factory = factory; + + log(`Component ${name} registered.`); + }; +} + +export function directive(mod: any, name: string, dep: Array = []) { + return (obj: any) => { + + obj.$componentName = name; + + obj.$inject = dep; + + const factory: Function = function(...args: any[]) { + var instance = Object.create(obj.prototype); + instance.constructor.apply(instance, arguments); + return instance; + }; + + factory.$inject = dep; + + obj.$factory = factory; + + log(`Component ${name} registered.`); + }; +} diff --git a/app/site-selection/service/site-selection.service.ts b/app/site-selection/service/site-selection.service.ts new file mode 100644 index 0000000..2fbb167 --- /dev/null +++ b/app/site-selection/service/site-selection.service.ts @@ -0,0 +1,45 @@ +import {factory} from '../../infrastructure/Dectorators/Components'; +import {Mod} from '../../core/core.mod'; + +export interface ISite { + siteId: string; + siteName: string; +} + +export interface ISiteReponseData { + error: string; +} + +export interface ISiteSelectionService { + setSite(siteId: number): ng.IPromise; + getSitesFromStorage(): Array; + storeAvailableSites(sites: Array); +} + +@factory(Mod, 'siteSelectionService', ['$http', '$q', '$window', 'api']) +export class SiteSelectionService implements ISiteSelectionService { + constructor(private $http: ng.IHttpService, + private $q: ng.IQService, + private $window: ng.IWindowService, + private api: any) { + + } + + public setSite(siteId: number): ng.IPromise { + var data = { SelectedSiteId: siteId }; + return this.$http.post(this.api.setSite, data) + .then((response: ng.IHttpPromiseCallbackArg) => { + if (response.data) { + return response.data; + } + }); + } + + public getSitesFromStorage(): Array { + return >JSON.parse(this.$window.sessionStorage.getItem('chroma:site-list')); + } + + public storeAvailableSites(sites: Array) { + this.$window.sessionStorage.setItem('chroma:site-list', JSON.stringify(sites)); + } +} diff --git a/app/site-selection/site-selection.config.ts b/app/site-selection/site-selection.config.ts new file mode 100644 index 0000000..62b5078 --- /dev/null +++ b/app/site-selection/site-selection.config.ts @@ -0,0 +1,14 @@ +export class Routes { + static $inject: Array = ['$stateProvider']; + + constructor($stateProvider: ng.ui.IStateProvider) { + $stateProvider.state('chroma.site-selection', { + url: '/site-selection', + views: { + 'content': { + template: '' + } + } + }); + } +} diff --git a/app/site-selection/site-selection.mod.ts b/app/site-selection/site-selection.mod.ts new file mode 100644 index 0000000..82ba01f --- /dev/null +++ b/app/site-selection/site-selection.mod.ts @@ -0,0 +1,15 @@ +import {module} from '../infrastructure/Dectorators/Components'; +import Config = require('./site-selection.config'); +import SiteSelectionComp = require('./view/site-selection'); +import{SiteSelectionService} from './service/site-selection.service'; + +@module('site-selection') +export class Mod { + constructor(angular: ng.IAngularStatic) { + angular.module(Mod.$componentName, []) + .controller(SiteSelectionComp.Controller.$componentName, SiteSelectionComp.Controller) + .directive(SiteSelectionComp.Directive.$componentName, SiteSelectionComp.Directive.$factory) + .factory(SiteSelectionService.$componentName, SiteSelectionService.$factory) + .config(Config.Routes); + } +} diff --git a/app/site-selection/view/site-selection.spec.ts b/app/site-selection/view/site-selection.spec.ts new file mode 100644 index 0000000..47e8604 --- /dev/null +++ b/app/site-selection/view/site-selection.spec.ts @@ -0,0 +1,101 @@ +import {Mod as CoreModule} from '../../core/core.mod'; +import {Mod as SiteSelectionMod} from '../site-selection.mod'; +import {ComponentTest} from '../../infrastructure/ComponentHelper'; +import {Directive, Controller} from './site-selection'; +import {SiteSelectionService} from '../service/site-selection.service'; +import {Mod as FlightListMod} from '../../flight-list/flight-list.mod'; +import {Mod as WindowListMod} from '../../window-list/window-list.mod'; + + +class SiteSelectionTest extends ComponentTest { + public api: any; + public $state: ng.ui.IStateService; + public siteSelectionService: SiteSelectionService; + + constructor() { + super(Directive.$componentName, + 'app/site-selection/view/site-selection.tpl.html'); + } +} + +describe('Site selection view Tests', () => { + let instance: SiteSelectionTest, + core: CoreModule, + siteSelection: SiteSelectionMod, + flightList: FlightListMod, + windowList: WindowListMod; + + let ctrl: Controller; + + beforeEach(() => { + if (!instance) { + angular.mock.module('ui.router'); + angular.mock.module('ionic'); + angular.mock.module('chroma.configuration'); + angular.mock.module(CoreModule.$componentName); + angular.mock.module(SiteSelectionMod.$componentName); + angular.mock.module(FlightListMod.$componentName); + angular.mock.module(WindowListMod.$componentName); + + core = new CoreModule(angular); + siteSelection = new SiteSelectionMod(angular); + flightList = new FlightListMod(angular); + windowList = new WindowListMod(angular); + + angular.mock.inject((api, $state, siteSelectionService) => { + instance = new SiteSelectionTest(); + instance.api = api; + instance.$state = $state; + instance.siteSelectionService = siteSelectionService; + }); + } + }); + + it('Directive is compiled', () => { + instance.flushOnInit = true; + ctrl = instance.compile(); + expect(ctrl).toBeDefined(); + }); + + it('There are 4 sites to select therefore 4 are displayed', () => { + //GIVEN I have acess to 4 sites + spyOn(instance.siteSelectionService, 'getSitesFromStorage').and.returnValue( + [{ SiteName: 'testSite1', SiteId: '1', IATACode: 'TES' }, + { SiteName: 'testSite2', SiteId: '2', IATACode: 'TEZ' }, + { SiteName: 'testSite3', SiteId: '3', IATACode: 'TEZ3' }, + { SiteName: 'testSite4', SiteId: '4', IATACode: 'TEZ4' }] + ); + //WHEN I am asked to select a site + instance.flushOnInit = false; + ctrl = instance.compile(); + //THEN I should have 4 sites to chose from + expect(ctrl.sites.length).toEqual(4); + }); + + it('Site is sucessfully selected flight list should be loaded', () => { + instance.flushOnInit = false; + ctrl = instance.compile(); + instance.$httpBackend.whenPOST(instance.api.setSite).respond(200, { + Data: { + Error: false, + } + }); + spyOn(instance.$state, 'go').and.callThrough(); + ctrl.setSite(23); + instance.$httpBackend.flush(); + expect(instance.$state.go).toHaveBeenCalledWith('chroma.window-list'); + }); + + it('Site selection is not Successful error should be displayed', () => { + instance.flushOnInit = false; + ctrl = instance.compile(); + instance.$httpBackend.expectPOST(instance.api.setSite).respond(200, { + Data: { + Error: true, + } + }); + ctrl.setSite(23); + instance.$httpBackend.flush(); + expect(ctrl.error).toBe('problem selecting site'); + }); +}); diff --git a/app/site-selection/view/site-selection.tpl.html b/app/site-selection/view/site-selection.tpl.html new file mode 100644 index 0000000..f8ebe6f --- /dev/null +++ b/app/site-selection/view/site-selection.tpl.html @@ -0,0 +1,18 @@ + + +
+
+ +
+
+ + + +
+ {{site.SiteName}} +
+
+
+
+
+
diff --git a/app/site-selection/view/site-selection.ts b/app/site-selection/view/site-selection.ts new file mode 100644 index 0000000..21ab8e4 --- /dev/null +++ b/app/site-selection/view/site-selection.ts @@ -0,0 +1,35 @@ +import {controller, directive} from '../../infrastructure/Dectorators/Components'; +import {Mod} from '../site-selection.mod'; +import {SiteSelectionService, ISiteSelectionService, ISite} from '../service/site-selection.service'; + + +@controller(Mod, 'siteSelectionController', ['siteSelectionService', '$state']) +export class Controller { + public sites: Array; + public error: string; + + constructor(private siteSelectionService: ISiteSelectionService, + private $state: ng.ui.IStateService) { + this.sites = siteSelectionService.getSitesFromStorage(); + } + + public setSite(siteId: number) { + this.siteSelectionService.setSite(siteId).then((response: any) => { + if (response.Data.Error) { + this.error = 'problem selecting site'; + } else { + this.$state.go('chroma.window-list'); + } + }); + } +} + +@directive(Mod, 'chromaSiteSelection') +export class Directive implements ng.IDirective { + controller: string = Controller.$componentName; + controllerAs: string = 'vm'; + templateUrl: string = 'app/site-selection/view/site-selection.tpl.html'; + restring: string = 'E'; + replace: boolean = false; + scope: any = true; +} diff --git a/app/window-list/list/window-list.spec.ts b/app/window-list/list/window-list.spec.ts new file mode 100644 index 0000000..4a7ea54 --- /dev/null +++ b/app/window-list/list/window-list.spec.ts @@ -0,0 +1,84 @@ +import {Mod as CoreModule} from '../../core/core.mod'; +import {Mod as WindowListMod} from '../window-list.mod'; +import {ComponentTest} from '../../infrastructure/ComponentHelper'; +import {Directive, Controller, IFlightWindow} from './window-list'; + + +class WindowListTest extends ComponentTest { + public api: any; + public $state: ng.ui.IStateService; + constructor() { + super(Directive.$componentName, 'app/window-list/list/window-list.tpl.html'); + } +} + +describe('Window list view Tests', () => { + let instance: WindowListTest, + core: CoreModule, + windowList: WindowListMod, + ctrl: Controller; + + beforeEach(() => { + if (!instance) { + angular.mock.module('ui.router'); + angular.mock.module('ionic'); + angular.mock.module('chroma.configuration'); + angular.mock.module(CoreModule.$componentName); + angular.mock.module(WindowListMod.$componentName); + core = new CoreModule(angular); + windowList = new WindowListMod(angular); + angular.mock.inject((api, $state) => { + instance = new WindowListTest(); + instance.api = api; + instance.$state = $state; + }); + } + }); + + it('Directive is compiled', () => { + instance.$httpBackend.expectGET(instance.api.getWindows).respond(200, []); + ctrl = instance.compile(); + expect(ctrl).toBeDefined(); + expect(ctrl.windows).toBeDefined(); + expect(ctrl.windows.length).toBe(0); + }); + + it('2 Windows are displayed and reversed', () => { + + let windows: Array = [{ Name: '1' }, { Name: '2' }]; + + instance.$httpBackend.expectGET(instance.api.getWindows).respond(200, windows); + + ctrl = instance.compile(); + + expect(ctrl.windows.length).toBe(2) + + expect(ctrl.windows[0].Name).toBe('2'); + }) + + it('2 Windows are displayed and reversed', () => { + + let windows: Array = [{ Name: '1' }, { Name: '2' }]; + + instance.$httpBackend.expectGET(instance.api.getWindows).respond(200, windows); + + ctrl = instance.compile(); + + expect(ctrl.windows.length).toBe(2) + + expect(ctrl.windows[0].Name).toBe('2'); + }) + + it('Flight list state is called on goToWindow', () => { + + spyOn(instance.$state, 'go').and.returnValue(false); + + instance.$httpBackend.expectGET(instance.api.getWindows).respond(200, []); + + ctrl = instance.compile(); + + ctrl.goToWindow({Name : 'test-123'}); + + expect(instance.$state.go).toHaveBeenCalledWith('chroma.flight-list', {filter : 'test-123'}); + }) +}); diff --git a/app/window-list/list/window-list.tpl.html b/app/window-list/list/window-list.tpl.html new file mode 100644 index 0000000..25acca8 --- /dev/null +++ b/app/window-list/list/window-list.tpl.html @@ -0,0 +1,33 @@ + + +
+
+ +
+
+ + + +
+
+ {{window.Name}} +
+ +
+
+
+ +
+ Chroma default flight filter +
+ + {{window.Description}} +
+ {{window.Type}} +
+
+
+
+
+
+
diff --git a/app/window-list/list/window-list.ts b/app/window-list/list/window-list.ts new file mode 100644 index 0000000..d4c3595 --- /dev/null +++ b/app/window-list/list/window-list.ts @@ -0,0 +1,44 @@ +import {controller, directive} from '../../infrastructure/Dectorators/Components'; +import {Mod} from '../window-list.mod'; +import {ISignalrService} from '../../core/service/signalRService'; + +export interface IFlightWindow { + Name: string; +} + +@controller(Mod, 'windowListController', ['signalrService', '$rootScope', '$http', '$state', '$window', 'api']) +export class Controller { + public loading: boolean; + public currentWindow:string; + public windows: Array; + + constructor( private signalrService: ISignalrService, + private $rootScope: ng.IScope, + private $http: ng.IHttpService, + private $state: ng.ui.IStateService, + private $window: ng.IWindowService, + private api: any) { + this.currentWindow = $window.sessionStorage.getItem('chroma:current-filter'); + this.$http.get(api.getWindows).success((response: Array) => { + this.windows = response.reverse(); + }); + } + public goToWindow(window: IFlightWindow): void { + this.signalrService.start($, this.signalRCallback, this.$rootScope); + this.$state.go('chroma.flight-list', { filter: window.Name }); + } + + public signalRCallback(event: string, scope: any, message: any) { + scope.$broadcast(event, {message: message}); + } +} + +@directive(Mod, 'chromaWindowList') +export class Directive implements ng.IDirective { + controller: string = Controller.$componentName; + controllerAs: string = 'vm'; + templateUrl: string = 'app/window-list/list/window-list.tpl.html'; + restring: string = 'E'; + replace: boolean = false; + scope: any = true; +} diff --git a/app/window-list/window-list.mod.ts b/app/window-list/window-list.mod.ts new file mode 100644 index 0000000..3fdf336 --- /dev/null +++ b/app/window-list/window-list.mod.ts @@ -0,0 +1,21 @@ +import {module} from '../infrastructure/Dectorators/Components'; +import {Controller, Directive} from './list/window-list'; + +@module('window-list') +export class Mod { + constructor(angular: ng.IAngularStatic) { + angular.module(Mod.$componentName, []) + .controller(Controller.$componentName, Controller) + .directive(Directive.$componentName, Directive.$factory) + .config(($stateProvider: ng.ui.IStateProvider) => { + $stateProvider.state('chroma.window-list', { + url: '/window-list', + views: { + 'content': { + template: '' + } + } + }); + }); + } +} diff --git a/bower.json b/bower.json new file mode 100644 index 0000000..a42c08d --- /dev/null +++ b/bower.json @@ -0,0 +1,29 @@ +{ + "name": "chroma.cordova", + "version": "0.0.0", + "license": "MIT", + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ], + "dependencies": { + "angular": "~1.3.15", + "angular-ui-router": "~0.2.13", + "angular-animate": "~1.3.15", + "angular-mocks": "~1.3.15", + "jasmine-jquery": "~2.1.0", + "angular-resource": "*", + "moment": "*" + }, + "resolutions": { + "angular": ">=1.3.8" + }, + "devDependencies": { + "ionic-service-core": "~0.1.10", + "ngCordova": "~0.1.20-alpha", + "ionic-service-push": "~0.1.13" + } +} diff --git a/build.json b/build.json new file mode 100644 index 0000000..5628062 --- /dev/null +++ b/build.json @@ -0,0 +1,14 @@ +{ + "ios": { + "debug": { + "developmentTeam":"DA3XCEKC7Z", + "provisioningProfile" : "1a1555b1-8483-466e-abd4-1822170b5a4c" + + }, + "release": { + "developmentTeam":"DA3XCEKC7Z", + "provisioningProfile" : "1a1555b1-8483-466e-abd4-1822170b5a4c" + + } + } +} diff --git a/build/configuration/ConfigTransform.ps1 b/build/configuration/ConfigTransform.ps1 new file mode 100644 index 0000000..11ec539 --- /dev/null +++ b/build/configuration/ConfigTransform.ps1 @@ -0,0 +1,6 @@ +param( + [String] $APIURL = "" +) + + +(get-content app.config.js.token).Replace('__APIURL__', $APIURL) | set-content app.config.js \ No newline at end of file diff --git a/build/configuration/app.config.js b/build/configuration/app.config.js new file mode 100644 index 0000000..b24750a --- /dev/null +++ b/build/configuration/app.config.js @@ -0,0 +1,49 @@ + +var base = "http://10.14.64.82:89"; + +angular.module('chroma.configuration', []).constant('api', { + + //STE OATES MACHINE + // endpoint: 'http://10.14.30.91/api/',l + // flightList: 'http://10.14.30.91/api/flights', + // authentication: 'http://10.14.30.91/api/auth', + // detail: 'http://10.14.30.91/api/detail/', + // imageSource: 'http://10.14.30.91/api/GetOperatorImage', + // setSite: 'http://10.14.30.91/api/setSite', + // getWindows: 'http://10.14.30.91/api/getWindows' + + //JAMES DILCOCK MACHINE + endpoint: base + '/api/', + flightList: base + '/api/flights', + authentication: base +'/api/auth', + detail: base + '/api/detail/', + imageSource: base + '/api/GletOperatorImage', + setSite: base + '/api/setSite', + getWindows: base + '/api/getWindows', + transactions: base + '/api/transactions', + cancelTransaction: base + '/api/cancelTransaction', + confirmTransaction: base + '/api/confirmTransaction', + createTransaction: base + '/api/createTransaction', + getTransactionCodes: base + '/api/getTransactionCodes', + getTransactionsAccess: base + '/api/getUserAccessRightsForTransaction', + getTransactionConfig: base + '/api/getTransactionConfig', + signalrHubs: base + '/signalr/hubs' + + //TESTING MACHINE +// endpoint: 'http://t-t-v-chrapp14:81/api/', +// flightList: 'http://t-t-v-chrapp14:81/api/flights', +// authentication: 'http://t-t-v-chrapp14:81/api/auth', +// detail: 'http://t-t-v-chrapp14:81/api/detail/', +// imageSource: 'http://t-t-v-chrapp14:81/api/GetOperatorImage', +// setSite: 'http://t-t-v-chrapp14:81/api/setSite', +// getWindows: 'http://t-t-v-chrapp14:81/api/getWindows' + + //ADE CLOUD CHROMA END POINT + //endpoint: 'http://chromademo.cloudapp.net:81/api/', + //flightList: 'http://chromademo.cloudapp.net:81/api/flights', + //authentication: 'http://chromademo.cloudapp.net:81/api/auth', + //detail: 'http://chromademo.cloudapp.net:81/api/detail/', + //imageSource: 'http://chromademo.cloudapp.net:81/api/GetOperatorImage', + //setSite: 'http://chromademo.cloudapp.net:81/api/setSite', + //getWindows: 'http://chromademo.cloudapp.net:81/api/getWindows' +}); diff --git a/build/configuration/app.config.js.token b/build/configuration/app.config.js.token new file mode 100644 index 0000000..1200702 --- /dev/null +++ b/build/configuration/app.config.js.token @@ -0,0 +1,17 @@ +angular.module('chroma.configuration', []).constant('api', { + endpoint: 'http://__APIURL__/api/', + flightList: 'http://__APIURL__/api/flights/', + authentication: 'http://__APIURL__/api/auth', + detail: 'http://__APIURL__/api/detail/', + imageSource :'http://__APIURL__/api/GetOperatorImage', + setSite: 'http://__APIURL__/api/setSite', + getWindows: 'http://__APIURL__/api/getWindows', + transactions: 'http://__APIURL__/api/transactions', + cancelTransaction: 'http://__APIURL__/api/cancelTransaction', + confirmTransaction: 'http://__APIURL__/api/confirmTransaction', + createTransaction: 'http://__APIURL__/api/createTransaction', + getTransactionCodes: 'http://__APIURL__/api/getTransactionCodes', + getTransactionsAccess: 'http://__APIURL__/api/getUserAccessRightsForTransaction', + getTransactionConfig: 'http://__APIURL__/api/getTransactionConfig', + signalrHubs: 'http://__APIURL__/signalr/hubs' +}); \ No newline at end of file diff --git a/build/fastlane/Appfile b/build/fastlane/Appfile new file mode 100644 index 0000000..6d2f7e1 --- /dev/null +++ b/build/fastlane/Appfile @@ -0,0 +1,7 @@ +app_identifier "com.lmco.chroma" # The bundle identifier of your app +apple_id "MobileAppsTeam@leidos.com" # Your Apple email address + +team_id "DA3XCEKC7Z" # Developer Portal Team ID + +# you can even provide different app identifiers, Apple IDs and team names per lane: +# More information: https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Appfile.md \ No newline at end of file diff --git a/build/fastlane/Fastlane b/build/fastlane/Fastlane new file mode 100644 index 0000000..7c054dc --- /dev/null +++ b/build/fastlane/Fastlane @@ -0,0 +1,68 @@ +# Shamelessly taken from here: https://github.com/xinbenlv/rent.zzn.im/tree/master/haoshiyou/fastlane +# A fastlane file, see https://fastlane.tools/ for reference + +# Update fastlane automatically if a new version is available: +update_fastlane + +fastlane_version "1.106.2" + +ios_project_path = "platforms/ios/haoshiyou.xcodeproj" + +before_all do + ENV["SLACK_URL"] = + "https://hooks.slack.com/services/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" +end + +private_lane :increment_version do + sh("node scripts/increment_build_number.js") +end + + +desc "Do a new iOS build using ionic." +private_lane :ionic_ios_build do + sh("ionic build ios --release") +endl + +desc "Do a new iOS deploy using sigh and gym" +private_lane :ios_deploy do + sigh + gym( + scheme: "haoshiyou", + project: ios_project_path) +end + +desc "Do a new iOS upload to iTunes Connect using deliver." +private_lane :ios_upload do + deliver(force: true) + slack(message: "Successfully deployed to iTunes Connect at Version " + + "#{get_version_number(xcodeproj:ios_project_path)}.") +end + + +platform :ios do + desc "Deploy a new version to the App Store/" + lane :deploy do + increment_version + ionic_ios_build + ios_deploy + ios_upload + end +end + + +desc "Deploy to all platforms." +lane :deploy_all do |options| + increment_version + + ionic_ios_build + + ios_deploy + + ios_upload +end + +# TODO(zzn): +# - 1. add deployment for web +# - 2. merge web flow into deploy_all +# - 3. add other workflows: test, pilot, prod +# - 4. add support "dev" scheme \ No newline at end of file diff --git a/build/fastlane/fastlane.old b/build/fastlane/fastlane.old new file mode 100644 index 0000000..d40c4e0 --- /dev/null +++ b/build/fastlane/fastlane.old @@ -0,0 +1,108 @@ +# A fastlane file, see https://fastlane.tools/ for reference + +# Update fastlane automatically if a new version is available: +update_fastlane + +fastlane_version "1.106.2" + +ios_project_path = "platforms/ios/haoshiyou.xcodeproj" +android_release_path = "releases/haoshiyou-android-release.apk" + +before_all do + ENV["SLACK_URL"] = + "https://hooks.slack.com/services/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" +end + +private_lane :increment_version do + sh("node scripts/increment_build_number.js") +end + + +desc "Do a new iOS build using ionic." +private_lane :ionic_ios_build do + sh("ionic build ios --release") +end + +desc "Do a new iOS deploy using sigh and gym" +private_lane :ios_deploy do + sigh + gym( + scheme: "haoshiyou", + project: ios_project_path) +end + +desc "Do a new iOS upload to iTunes Connect using deliver." +private_lane :ios_upload do + deliver(force: true) + slack(message: "Successfully deployed to iTunes Connect at Version " + + "#{get_version_number(xcodeproj:ios_project_path)}.") +end + +desc "Do a new Android build" +private_lane :ionic_android_build do + sh("ionic build android --release") +end + +desc "Do a new Android deploy using jarsigner and zipaliagn." +private_lane :android_deploy do |options| + sh("cd .. && jarsigner -verbose " + + "-storepass #{options[:storepass]} " + + "-sigalg SHA1withRSA -digestalg SHA1 " + + "-keystore fastlane/release-cred/haoshiyou-android.keystore " + + "platforms/android/build/outputs/apk/android-release-unsigned.apk alias_name") + + sh("cd .. && ${HOME}/Library/Android/sdk/build-tools/23.0.3/zipalign -f " + + "-v 4 platforms/android/build/outputs/apk/android-release-unsigned.apk " + + android_release_path) +end + +desc "Do a new Android upload to Google Play Console using supply." +private_lane :android_upload do + supply( + track: "alpha", + apk: android_release_path, + json_key: "fastlane/release-cred/haoshiyou-play-release-manager-credentials.json", + package_name: "org.haoshiyou.app" + ) + slack(message: "Successfully deployed to Google Play.") # TODO(xinbenlv): add version +end + +platform :ios do + desc "Deploy a new version to the App Store/" + lane :deploy do + increment_version + ionic_ios_build + ios_deploy + ios_upload + end +end + +platform :android do + desc "Deploy a new version to the Google Play Store." + lane :deploy do |options| + increment_version + ionic_android_build + android_deploy(options) + android_upload + end +end + +desc "Deploy to all platforms." +lane :deploy_all do |options| + increment_version + + ionic_android_build + ionic_ios_build + + android_deploy(options) + ios_deploy + + ios_upload + android_upload +end + +# TODO(zzn): +# - 1. add deployment for web +# - 2. merge web flow into deploy_all +# - 3. add other workflows: test, pilot, prod +# - 4. add support "dev" scheme \ No newline at end of file diff --git a/build/gulp.config.js b/build/gulp.config.js new file mode 100644 index 0000000..66fa276 --- /dev/null +++ b/build/gulp.config.js @@ -0,0 +1,110 @@ +module.exports = function () { + var argv = require('yargs').argv; + var build = argv.build || 'Test'; + var root = './'; + var clientApp = root + 'app/'; + var reportDir = root + 'report/'; + + var config = { + buildName: build, + sourceApp: './app/', + allInfrastructure: './app/infrastructure/**/*.ts', + allModules: './app/**/*.mod.ts', + allRoutes: './app/**/*.routes.ts', + allInterceptors: './app/**/*.interceptor.ts', + allRun: './app/**/*.run.ts', + allTypescript: './app/**/*.ts', + allTemplates: './app/**/*.tpl.html', + allHtml: './app/**/*.html', + allLess: './app/**/*.less', + allTypings: './tooling/typings/**/*.d.ts', + allFiles: './app/**', + exludeTestFiles: '!./app/**/*.spec.ts', + excludeE2ETestFiles: '!./app/**/*.e2e.js', + allOutput: './www/**/*', + allOutputJavascript: './www/**/*.js', + allOutputMinCss: './www/**/*.min.css', + allOutputCss: './www/**/*.css', + ignoreAllMinCss: '!./www/**/*.min.css', + ignoreJavascriptLib: '!**/lib/**/**', + e2eSpecs: './**/*.e2e.js', + configurationFile: './build/configuration/app.config.js', + configurationTokenFile: './build/configuration/app.config.js.token', + requiredJavascript: [ + './node_modules/local-chromaux/dist/lib/ionic/js/ionic.bundle.js', + './bower_components/jquery/dist/jquery.js', + './bower_components/jasmine-jquery/lib/jasmine-jquery.js', + './bower_components/angular-mocks/angular-mocks.js', + './node_modules/angular-cookies/angular-cookies.js', + './bower_components/angular-animate/angular-animate.js', + './bower_components/angular-ui-router/release/angular-ui-router.js', + './bower_components/moment/moment.js', + './node_modules/local-chromaux/dist/js/*.js', + './node_modules/systemjs/dist/system.js', + './angular-ios9-uiwebview.patch.js', + './lib/jquery.signalR-2.2.1.js', + './lib/push.js' + ], + requiredJavascriptDest: './www/scripts/lib', + requiredCSS: [ + './bower_components/bootstrap/dist/css/bootstrap.css', + './ionic/css/ionic.css', + './node_modules/local-chromaux/dist/css/*.css', + './node_modules/local-chromaux/dist/lib/ionic/css/*.css' + ], + requiredFonts: [ + './node_modules/local-chromaux/dist/fonts/*.*', + './node_modules/local-chromaux/dist/lib/ionic/fonts/*.*' + ], + requiredCSSDest: './www/css/lib', + root: root, + reportDir: reportDir, + /** + * plato + */ + plato: { + js: clientApp + '**/*.js' + }, + }; + + /** + * karma settings + */ + config.karma = getKarmaOptions(); + + return config; + + function getKarmaOptions() { + var options = { + files: [ + './bower_components/moment/moment.js', + './bower_components/angular/angular.js', + './bower_components/jquery/dist/jquery.js', + './node_modules/local-chromaux/dist/lib/ionic/js/ionic.bundle.js', + './node_modules/angular-cookies/angular-cookies.js', + './bower_components/angular-mocks/angular-mocks.js', + './www/scripts/lib/chroma-framework.js', + './www/scripts/chroma.templates.compiled.js', + './build/configuration/app.config.js', + './tests/compiled/lib/moment.js', + './tests/compiled/!(lib)/**/*.js' + ], + exclude: ['./tests/compiled/lib'], + coverage: { + dir: reportDir + 'coverage', + reporters: [{ + type: 'html', + subdir: 'report-html' + }, { + type: 'text-summary' + + }, + { type: 'lcov', subdir: 'report-lcov' }, ] + }, + preprocessors: {} + }; + options.preprocessors['./tests/compiled/!(lib)/**/!(*.spec)*.js'] = ['coverage']; + return options; + } + +}; diff --git a/build/gulp/add-hockeyapp.js b/build/gulp/add-hockeyapp.js new file mode 100644 index 0000000..48abddb --- /dev/null +++ b/build/gulp/add-hockeyapp.js @@ -0,0 +1,15 @@ +/** + * Created by martin on 10/31/16. + */ +var gulp = require('gulp'); +var exec = require('child_process').exec; + +module.exports = gulp.task('add-hockeyapp', function() { + + exec('cordova plugin add cordova-plugin-hockeyapp@latest', function (err, stdout, stderr) { + console.log(stdout); + console.log(stderr); + }); + + +}); diff --git a/build/gulp/add-pushnotifications.js b/build/gulp/add-pushnotifications.js new file mode 100644 index 0000000..ef57567 --- /dev/null +++ b/build/gulp/add-pushnotifications.js @@ -0,0 +1,14 @@ +/** + * Created by martin on 10/31/16. + */ +var gulp = require('gulp'); +var exec = require('child_process').exec; + +module.exports = gulp.task('add-pushnotifications', function() { + + exec('cordova plugin add phonegap-plugin-push --variable SENDER_ID=194436060542', function (err, stdout, stderr) { + console.log(stdout); + console.log(stderr); + }); + +}); diff --git a/build/gulp/compile-js.js b/build/gulp/compile-js.js new file mode 100644 index 0000000..3696353 --- /dev/null +++ b/build/gulp/compile-js.js @@ -0,0 +1,32 @@ + +var gulp = require('gulp'), + config = require('../gulp.config')(), + tsc = require('gulp-typescript'), + tsProject = tsc.createProject('./tsconfig.json'), + tslint = require('gulp-tslint'); + +var tsSource = ['./tooling/typings/tsd.d.ts', + '!./app/**/*.spec.ts', + './app/**/!(*.spec.ts)*.ts']; + +module.exports = gulp.task('ts-lint', function () { + + return gulp.src(tsSource) + .pipe(tslint({formatter:"verbose"})) + .pipe(tslint.report()); +}); + +module.exports = gulp.task('compile-js', ['ts-lint'], function () { + + if (environment !== 'development') { + tsProject.options.sourceMap = false; + } + + gulp.src(config.configurationFile) + .pipe(gulp.dest('./www/scripts/')); + + var result = gulp.src(tsSource) + .pipe(tsProject()); + + return result.js.pipe(gulp.dest('./www/js')); +}); diff --git a/build/gulp/compile-less.js b/build/gulp/compile-less.js new file mode 100644 index 0000000..e2fe198 --- /dev/null +++ b/build/gulp/compile-less.js @@ -0,0 +1,27 @@ +var gulp = require('gulp'), + less = require('gulp-less'), + config = require('../gulp.config')(), + concat = require('gulp-concat'), + sourcemaps = require('gulp-sourcemaps'), + postcss = require('gulp-postcss'), + minifyCSS = require('gulp-minify-css'); +autoprefixer = require('autoprefixer'); + +module.exports = gulp.task('compile-less', function () { + var ret; + if (environment === 'development') { + ret = gulp.src(config.allLess) + .pipe(less()) + .pipe(concat('chroma.compiled.css')) + .pipe(postcss([autoprefixer({ browsers: ['last 2 versions'] })])) + .pipe(gulp.dest('./www/css/')); + } else { + ret = gulp.src(config.allLess) + .pipe(less()) + .pipe(minifyCSS()) + .pipe(concat('chroma.compiled.css')) + .pipe(gulp.dest('./www/css/')); + } + + return ret; +}); diff --git a/build/gulp/compile-template-cache.js b/build/gulp/compile-template-cache.js new file mode 100644 index 0000000..335287e --- /dev/null +++ b/build/gulp/compile-template-cache.js @@ -0,0 +1,16 @@ +var config = require('../gulp.config')(), + gulp = require('gulp'); + +module.exports = gulp.task('compile-template-cache', function () { + var ngTemplates = require('gulp-ng-templates'); + return gulp.src(['./app/**/*.tpl.html', './app/**/*.html']) + .pipe(ngTemplates({ + filename: 'chroma.templates.compiled.js', + standalone: true, + module: 'chroma.templates', + path: function (path, base) { + return 'app/' + path.replace(base, '').replace('', ''); + } + })) + .pipe(gulp.dest('./www/scripts')); +}); diff --git a/build/gulp/compile-template.js b/build/gulp/compile-template.js new file mode 100644 index 0000000..34b0c5c --- /dev/null +++ b/build/gulp/compile-template.js @@ -0,0 +1,20 @@ +var gulp = require('gulp'), + minifyHTML = require('gulp-minify-html'); + +module.exports = gulp.task('compile-template', function () { + var ret; + if (environment === 'development') { + ret = gulp.src('./www/app/**/*.tpl.html') + .pipe(gulp.dest('./www/app/')); + } else { + var opts = { + conditionals: true, + spare: true + }; + ret = gulp.src(['./app/**/*.tpl.html', './app/**/*.html']) + .pipe(minifyHTML(opts)) + .pipe(gulp.dest('./www/app/')); + + } + return ret; +}); diff --git a/build/gulp/compile-tests.js b/build/gulp/compile-tests.js new file mode 100644 index 0000000..499ec5f --- /dev/null +++ b/build/gulp/compile-tests.js @@ -0,0 +1,30 @@ + +var gulp = require('gulp'), + config = require('../gulp.config')(), + tsc = require('gulp-typescript'), + replace = require('gulp-replace'), + sourcemaps = require('gulp-sourcemaps'); + +module.exports = gulp.task('compile-tests', function () { + + gulp.src(config.requiredJavascript).pipe(gulp.dest('./tests/compiled/lib')); + + var result = gulp.src(['./tooling/typings/tsd.d.ts', './app/**/*.ts']) + .pipe(replace(/\/\/TESTONLY/g, '')) + .pipe(sourcemaps.init()) + .pipe(tsc({ + target: "ES5", + module: "commonjs", + noImplicitAny: false, + removeComments: true, + reserveConstEnums: true, + experimentalDecorators: true + })); + + return result.js + .pipe(sourcemaps.write('./')) + .pipe(replace(/\/\/TESTONLY/g, '')) + .pipe(replace(/(var __decorate = \(this && this.__decorate\))/g, '$1/* istanbul ignore next */')) + .pipe(replace(/(var __extends = \(this && this.__extends \))/g, '$1/* istanbul ignore next */')) + .pipe(gulp.dest('./tests/compiled')); +}); diff --git a/build/gulp/copy-index.js b/build/gulp/copy-index.js new file mode 100644 index 0000000..00ebc0c --- /dev/null +++ b/build/gulp/copy-index.js @@ -0,0 +1,6 @@ +var gulp = require('gulp'); + +module.exports = gulp.task('copy-index', function () { + return gulp.src('./app/index.html') + .pipe(gulp.dest('./www/')); +}); diff --git a/build/gulp/copy-resources.js b/build/gulp/copy-resources.js new file mode 100644 index 0000000..5bc4373 --- /dev/null +++ b/build/gulp/copy-resources.js @@ -0,0 +1,11 @@ +var gulp = require('gulp'); + +module.exports = gulp.task('copy-resources', function () { + return gulp.src('./res/shared/**/*.*') + .pipe(gulp.dest('./www/res/')); +}); + +module.exports = gulp.task('copy-android-resources', function () { + return gulp.src(['res/drawable-*/**/*','res/mipmap-*/**/*']) + .pipe(gulp.dest('./platforms/android/res/')); +}); \ No newline at end of file diff --git a/build/gulp/gitversion.js b/build/gulp/gitversion.js new file mode 100644 index 0000000..6f86200 --- /dev/null +++ b/build/gulp/gitversion.js @@ -0,0 +1,23 @@ +/** + * Created by martin on 10/31/16. + */ +var gulp = require('gulp'); +var exec = require('child_process').exec; +var xmlEdit = require('gulp-edit-xml'); + +module.exports = gulp.task('gitversion', function() { + + exec('gitversion', function (err, stdout, stderr) { + + var gitJson = JSON.parse(stdout); + + gulp.src("./config.xml") + .pipe(xmlEdit(function(xml) { + xml.widget.$.version = gitJson.NuGetVersionV2; + return xml; + })) + .pipe(gulp.dest(".")); + + }); + +}); diff --git a/build/gulp/hockey-upload-android.js b/build/gulp/hockey-upload-android.js new file mode 100644 index 0000000..4ca4e60 --- /dev/null +++ b/build/gulp/hockey-upload-android.js @@ -0,0 +1,36 @@ +/** + * Created by martin on 11/8/16. + */ +var gulp = require('gulp'); +var rename = require('gulp-rename'); +var hockeyApp = require('gulp-hockeyapp'); +//var wait = require('gulp-wait'); + +gulp.task('rename-android', function () { + return gulp.src(["./platforms/android/build/outputs/apk/android-debug.apk"]) + .pipe(rename("com.lmco.chroma.apk")) + .pipe(gulp.dest('./platforms/android/build/outputs/apk/')); + +}); + +gulp.task('hockey-upload-android', ['rename-android'], function (done) { + var hockeyOptions = { + id: 'db782aaeada547618462264f1dd06e2b', + apiToken: 'ef010a5e7057469da01e98ec8c826457', + inputFile: './platforms/android/build/outputs/apk/com.lmco.chroma.apk', + notify: 1, + status: 2 + }; + + hockeyApp.upload(hockeyOptions).then( + function (response) { + // All is ok, build was uploaded + console.log(' 🏒 Hockey Android upload done'); + }, + function (err) { + // Something is wrong... + console.error(err); + } + ); + +}); \ No newline at end of file diff --git a/build/gulp/hockey-upload-ios.js b/build/gulp/hockey-upload-ios.js new file mode 100644 index 0000000..94eeadc --- /dev/null +++ b/build/gulp/hockey-upload-ios.js @@ -0,0 +1,28 @@ +/** + * Created by martin on 11/8/16. + */ +var gulp = require('gulp'); +var rename = require('gulp-rename'); +var hockeyApp = require('gulp-hockeyapp'); + + +gulp.task('hockey-upload-ios', function(done) { + var hockeyOptions = { + id: '8ca6b61ff4374109b416a476ceb29688', + apiToken: 'd4f642638f554e9296c75af2fadb49ab', + inputFile: './platforms/ios/AODBMobile.xcarchive', + notify: 1, + status: 2 + }; + + hockeyApp.upload(hockeyOptions).then( + function(response) { + // All is ok, build was uploaded + console.log(' 🏒 Hockey iOS upload done'); + }, + function(err) { + // Something is wrong... + console.error(err); + } + ); +}); diff --git a/build/gulp/install.js b/build/gulp/install.js new file mode 100644 index 0000000..6180046 --- /dev/null +++ b/build/gulp/install.js @@ -0,0 +1,9 @@ +var gulp = require('gulp'), + install = require('gulp-install'), + config = require('../gulp.config.js')(); + +module.exports = gulp.task('install', function() { + gulp.src(config.requiredJavascript).pipe(gulp.dest('./www/scripts/lib')); + gulp.src(config.requiredCSS).pipe(gulp.dest('./www/css/lib')); + gulp.src(config.requiredFonts).pipe(gulp.dest('./www/css/fonts')); +}); diff --git a/build/gulp/min-css-dependencies.js b/build/gulp/min-css-dependencies.js new file mode 100644 index 0000000..e9360a7 --- /dev/null +++ b/build/gulp/min-css-dependencies.js @@ -0,0 +1,12 @@ +var gulp = require('gulp'), + less = require('gulp-less'), + config = require('../gulp.config')(), + concat = require('gulp-concat'), + minifyCSS = require('gulp-minify-css'); + +module.exports = gulp.task('min-css-dependencies', function() { + var source = config.requiredCSSDest + '/**/*.css'; + return gulp.src(source) + .pipe(minifyCSS()) + .pipe(gulp.dest(config.requiredCSSDest)); +}); diff --git a/build/gulp/min-js-dependencies.js b/build/gulp/min-js-dependencies.js new file mode 100644 index 0000000..dae5fcc --- /dev/null +++ b/build/gulp/min-js-dependencies.js @@ -0,0 +1,11 @@ +var gulp = require('gulp'), + uglify = require('gulp-uglify'), + config = require('../gulp.config')(); + +module.exports = gulp.task('min-js-dependencies', function() { + var sourceFiles = config.requiredJavascriptDest + '/*.js'; + + return gulp.src(sourceFiles) + .pipe(uglify()) + .pipe(gulp.dest(config.requiredJavascriptDest)); +}); diff --git a/build/gulp/purge-previous-ionic.js b/build/gulp/purge-previous-ionic.js new file mode 100644 index 0000000..4ef7b8c --- /dev/null +++ b/build/gulp/purge-previous-ionic.js @@ -0,0 +1,11 @@ +/** + * Created by MobileAppsTeam on 11/11/2016. + */ + +var gulp = require('gulp'); +var clean = require('gulp-clean'); + +gulp.task('purge-previous-ionic', function () { + return gulp.src('platforms', {read: false}) + .pipe(clean()); +}); diff --git a/build/gulp/run-tests.js b/build/gulp/run-tests.js new file mode 100644 index 0000000..697a94d --- /dev/null +++ b/build/gulp/run-tests.js @@ -0,0 +1,28 @@ +var gulp = require('gulp'), + path = require('path'), + util = require('gulp-util'), + log = util.log, + config = require('../gulp.config')(), + args = require('yargs').argv, + server = require('karma').Server; + +module.exports = + gulp.task('run-tests', function (done) { + startTests(done); + }); + +/** + * Start the tests using karma. + * @param {boolean} singleRun - True means run once and end (CI), or keep running (dev) + * @param {Function} done - Callback to fire when karma is done + * @return {undefined} + */ +function startTests(done) { + log("Running Tests on Environment: " + environment); + + var karma = new server({ + configFile: path.join(__dirname, '../../karma.conf.js') + }); + + karma.start(); +} diff --git a/build/gulp/sonar.js b/build/gulp/sonar.js new file mode 100644 index 0000000..641a7b1 --- /dev/null +++ b/build/gulp/sonar.js @@ -0,0 +1,64 @@ +var gulp = require('gulp'), + sonar = require('gulp-sonar'), + config = require('../gulp.config')(), + util = require('gulp-util'), + args = require('yargs').argv; + +module.exports = gulp.task('sonar', function () { + var tsoptions = { + sonar: { + host: { + url: 'http://i-t-v-tf04:9000' + }, + jdbc: { + url: 'jdbc:postgresql://i-t-v-tf04:5432/sonar', + username: 'sonar', + password: 'sonar' + }, + projectKey: 'AODBMobile-TS', + projectName: 'AODB Mobile Application Typescript', + projectVersion: args.version, + language: 'ts', + sources: 'app, build', + // comma-delimited string of source directories + sourceEncoding: 'UTF-8', + coverage: { + exclusions: '**/*.spec.ts, **/build/**/*' + }, + ts: { + tslintpath: 'node_modules/tslint/bin/tslint' + } + } + }; + + var weboptions = { + sonar: { + host: { + url: 'http://i-t-v-tf04:9000' + }, + jdbc: { + url: 'jdbc:postgresql://i-t-v-tf04:5432/sonar', + username: 'sonar', + password: 'sonar' + }, + projectKey: 'AODBMobile-HTML', + projectName: 'AODB Mobile Application HTML', + projectVersion: args.version, + language: 'web', + sources: 'app', + // comma-delimited string of source directories + sourceEncoding: 'UTF-8', + web: { + file: { + suffixes: '.html' + } + } + } + }; + + // gulp source doesn't matter, all files are referenced in options object above + return gulp.src('thisFileDoesNotExist.js', { read: false }) + .pipe(sonar(tsoptions)) + .pipe(sonar(weboptions)) + .on('error', util.log); +}); diff --git a/build/gulp/update-url.js b/build/gulp/update-url.js new file mode 100644 index 0000000..7edc47a --- /dev/null +++ b/build/gulp/update-url.js @@ -0,0 +1,20 @@ +/** + * Created by martin on 10/31/16. + */ +var gulp = require('gulp'); +var argv = require('yargs').argv; +var replace = require('gulp-string-replace'); +var rename = require("gulp-rename"); + +module.exports = gulp.task('update-url', function() { + + // Call using gulp update-url --url=NEWURL + + var apiURL = argv.url; + + gulp.src(["./build/configuration/app.config.js.token"]) + .pipe(replace(new RegExp('__APIURL__', 'g'), apiURL)) + .pipe(rename("app.config.js")) + .pipe(gulp.dest('./build/configuration/')) + +}); diff --git a/build/gulp/watch.js b/build/gulp/watch.js new file mode 100644 index 0000000..9af24a4 --- /dev/null +++ b/build/gulp/watch.js @@ -0,0 +1,19 @@ +var gulp = require('gulp'), + config = require('../gulp.config')(), + watch = require('gulp-watch'); + +module.exports = + gulp.task('watch', function() { + watch(config.allLess, function() { + gulp.start('compile-less'); + }); + watch(config.allTemplates, function() { + gulp.start('compile-template-cache'); + }); + watch(config.allTypescript, function() { + gulp.start(['compile-js']); + }); + watch(config.allHtml, function() { + gulp.start('compile-template'); + }); + }); diff --git a/changeList.json b/changeList.json new file mode 100644 index 0000000..64e7b2c --- /dev/null +++ b/changeList.json @@ -0,0 +1,678 @@ +{ + "changedFilesIos": [ + "Scripts\\typings\\angularjs\\angular-resource.d.ts", + "Scripts\\typings\\angularjs\\angular.d.ts", + "Scripts\\typings\\angularjs\\angular-sanitize.d.ts", + "Scripts\\typings\\jquery\\jquery.d.ts", + "Scripts\\typings\\jasmine\\jasmine.d.ts", + "Scripts\\typings\\angularjs\\angular-mocks.d.ts", + "Scripts\\typings\\angularjs\\angular-route.d.ts", + "Scripts\\typings\\angularjs\\angular-animate.d.ts", + "Scripts\\typings\\angularjs\\angular-cookies.d.ts", + "build\\development\\compile-less.js", + "app\\prm\\task-workflow\\prm.less", + "ionic.project", + "www\\lib\\ionic\\js\\angular\\angular-animate.js", + "res\\icons\\ios\\Icon-60@3x.png", + "www\\lib\\ionic\\js\\angular\\angular.min.js", + "app\\prm\\models\\rejectReason.js", + "www\\font\\Nexa Bold.otf", + "bower.json", + "www\\res\\logo.png", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\info\\index.html", + "app\\prm\\task-workflow\\info\\info.tpl.html", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\authentication\\services\\authentication.service.js.html", + "app\\e2e\\login\\login.e2e.js", + "mockups\\MI5-Promt-View.PNG", + "app\\prm\\task-workflow\\_view\\view.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\error\\error.routes.js.html", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\core\\index.html", + "build\\development\\eol.js", + "res\\icons\\android\\icon-72-hdpi.png", + "www\\lib\\ionic\\css\\ionic.min.css", + "www\\scripts\\lib\\angular-resource.js", + "build\\shared\\copy-resources.js", + "res\\screens\\android\\screen-mdpi-landscape.png", + "merges\\android\\scripts\\android2.3-jscompat.js", + "build\\server\\e2e-tests.js", + "merges\\windows\\scripts\\winstore-jscompat.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\authentication\\auth.run.js.html", + "res\\icons\\ios\\icon-60.png", + "res\\icons\\ios\\Icon@2x.png", + ".jshintrc", + "app\\authentication\\components\\loginView\\loginView.js", + "www\\font\\Roboto-BlackItalic.ttf", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\detail\\detail.js.html", + "res\\screens\\ios\\screen-iphone-landscape-736h.png", + "protractor\\spec\\login.spec.js", + "app\\authentication\\specs\\auth.feature", + "app\\prm\\prm.routes.js", + "app\\authentication\\services\\authentication.service.js", + "res\\icons\\windows\\StoreLogo.scale-100.png", + "app\\authentication\\specs\\token.feature", + "www\\lib\\ionic\\js\\angular\\angular-sanitize.js", + "app\\prm\\constants\\flightType.js", + "DSCRelease\\PRMWeb.ps1", + "app\\prm\\task-workflow\\reject\\reject.less", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\index.html", + "DSCRelease\\PRMMockups.ps1", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\assigned\\assigned.js.html", + "www\\font\\Roboto-Black.ttf", + "www\\lib\\ionic\\js\\ionic.bundle.min.js", + "app\\chroma.app.js", + "build\\configuration\\app.config.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\base.css", + "mockups\\turnround.png", + "res\\icons\\android\\icon-48-mdpi.png", + "build\\shared\\copy-chroma-ux.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\core\\services\\index.html", + "app\\core\\core.mod.js", + "www\\lib\\ionic\\js\\ionic.min.js", + "app\\error\\specs\\error.spec.js", + "build\\configuration\\app.config.js.token", + "build\\development\\compile-template.js", + "www\\scripts\\lib\\angular.js", + "mockups\\M5-View.PNG", + "build\\server\\plato.js", + "app\\authentication\\components\\loginView\\loginView.tpl.html", + "www\\font\\Nexa-Bold.otf", + "www\\font\\Roboto-Bold.ttf", + "res\\icons\\ios\\icon-72.png", + "res\\icons\\ios\\icon-76.png", + "app\\core\\core.routes.js", + "res\\screens\\ios\\screen-ipad-portrait-2x.png", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\assigned\\index.html", + "mockups\\gating.jpg", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\core\\services\\user.service.js.html", + "www\\lib\\ionic\\js\\angular-ui\\angular-ui-router.js", + "build\\server\\compile-less.js", + "build\\development\\vet.js", + "res\\screens\\ios\\screen-iphone-portrait-2x.png", + "www\\scripts\\lib\\angular-ui-router.js", + "www\\font\\Nexa Light.otf", + "app\\authentication\\auth.run.js", + "app\\prm\\task-workflow\\reject\\reject.spec.js", + "app\\prm\\prm.mod.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\core\\services\\navigation.service.js.html", + "www\\lib\\ionic\\css\\ionic.css", + "res\\icons\\windows\\Square71x71Logo.scale-240.png", + "www\\lib\\ionic\\js\\ionic.bundle.js", + "merges\\android\\scripts\\platformOverrides.js", + "www\\font\\Roboto-LightItalic.ttf", + "res\\icons\\ios\\iTunesArtwork@2x.png", + "_references.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\_container\\index.html", + "app\\prm\\task-workflow\\assigned\\assigned.js.orig", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\authentication\\components\\loginView\\loginView.controller.js.html", + "Properties\\PublishProfiles\\EndToEnd.pubxml", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\_container\\container.js.html", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\reject\\reject.js.html", + "app\\prm\\task-workflow\\_view\\view.spec.js", + "www\\lib\\ionic\\js\\ionic-angular.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\authentication\\auth.routes.js.html", + "res\\screens\\android\\screen-hdpi-portrait.png", + "app\\authentication\\specs\\auth.spec.js", + "app\\error\\error.html", + "res\\icons\\ios\\Icon-Small-50.png", + "res\\icons\\ios\\Icon-Small-40.png", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\chroma.app.js.html", + "www\\font\\Roboto-ThinItalic.ttf", + "app\\authentication\\specs\\token.spec.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\detail\\index.html", + "res\\icons\\windows\\StoreLogo.scale-240.png", + "res\\icons\\ios\\Icon-72@2x.png", + "res\\icons\\ios\\Icon-76@2x.png", + "protractor.ci.firefox.conf.js", + "www\\lib\\ionic\\js\\ionic-angular.min.js", + "build\\server\\run-tests.js", + "www\\lib\\ionic\\js\\angular-ui\\angular-ui-router.min.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\reject\\reject.controller.js.html", + "www\\lib\\ionic\\fonts\\ionicons.ttf", + "www\\scripts\\lib\\bard.js", + "res\\screens\\ios\\screen-ipad-landscape.png", + "build\\server\\min-js-dependencies.js", + "res\\icons\\ios\\Icon-Small@3x.png", + "res\\icons\\ios\\Icon-Small@2x.png", + "www\\lib\\ionic\\version.json", + "www\\font\\Roboto-Italic.ttf", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\no-task-available\\index.html", + "build\\development\\browser-sync.js", + "www\\font\\Roboto-Light.ttf", + "mockups\\turnaround.jpg", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\info\\info.js.html", + "mockups\\MI5-Alt-View.PNG", + "mockups\\mockloginscreen.png", + "packages.config", + "res\\icons\\ios\\Icon-Small-50@2x.png", + "res\\icons\\ios\\icon-60-3x.png", + "karma.conf.js", + "app\\prm\\task-workflow\\assigned\\assigned.controller.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\reject\\index.html", + "app\\prm\\task-workflow\\assigned\\assigned.spec.js", + "config.xml", + "www\\lib\\ionic\\js\\angular\\angular.js", + "res\\icons\\ios\\Icon-Small-40@2x.png", + "res\\icons\\ios\\Icon-Small-40@3x.png", + "res\\screens\\wp8\\SplashScreenImage.jpg", + "app\\core\\services\\navigation.service.js", + "app\\prm\\task-workflow\\no-task-available\\noTaskAvailable.tpl.html", + "www\\font\\Nexa-Light.otf", + "build\\server\\compile-js.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\error\\components\\errorView.js.html", + "res\\screens\\ios\\screen-ipad-landscape-2x.png", + "app\\authentication\\auth.mod.js", + "app\\prm\\task-workflow\\info\\info.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\info\\info.controller.js.html", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\error\\components\\errorView.controller.js.html", + "www\\scripts\\chroma.compiled.js", + "www\\lib\\ionic\\js\\angular\\angular-sanitize.min.js", + "res\\screens\\ios\\screen-iphone-568h-2x.png", + "res\\icons\\windows\\Square150x150Logo.scale-100.png", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\_view\\view.js.html", + "www\\lib\\ionic\\js\\angular\\angular-resource.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\constants\\index.html", + "app\\authentication\\components\\loginView\\loginView.tpl.html.orig", + "app\\prm\\task-workflow\\assigned\\assigned.js", + "gulpfile.js", + "package.json", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\error\\index.html", + "mockups\\MI70-View.PNG", + "protractor.ci.ieEdge.conf.js", + "app\\prm\\constants\\stageStatus.js", + "app\\prm\\task-workflow\\assigned\\assigned.tpl.html", + "www\\font\\Roboto-BoldItalic.ttf", + "build\\shared\\vet.js", + "res\\screens\\android\\screen-ldpi-landscape.png", + "res\\icons\\windows\\Wide310x150Logo.scale-240.png", + "res\\icons\\windows\\Wide310x150Logo.scale-100.png", + "res\\icons\\ios\\icon-72-2x.png", + "res\\icons\\ios\\icon-76-2x.png", + "app\\authentication\\views\\loginView.html", + "build\\development\\e2e-tests.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\prm.routes.js.html", + "www\\css\\chroma-framework.css", + "www\\lib\\ionic\\fonts\\ionicons.svg", + "res\\icons\\ios\\icon-small.png", + "protractor.ci.ie11.conf.js", + "app\\prm\\task-workflow\\reject\\reject.controller.js", + "karma.conf.dev.js", + "mockups\\checkin.jpg", + "www\\scripts\\lib\\jquery.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\sorter.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\constants\\stageStatus.js.html", + "www\\font\\Roboto-MediumItalic.ttf", + "build\\shared\\install.js", + "res\\icons\\windows\\Square30x30Logo.scale-100.png", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\authentication\\interceptors\\index.html", + ".jscsrc", + "res\\icons\\ios\\Icon.png", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\error\\components\\index.html", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\models\\task.js.html", + "app\\error\\components\\errorView.js", + "app\\authentication\\components\\loginView\\loginView.controller.js", + "www\\lib\\ionic\\fonts\\ionicons.eot", + "www\\css\\chroma.compiled.css", + "res\\icons\\ios\\Icon-60@2x.png", + "app\\error\\components\\errorView.less", + "res\\icons\\wp8\\Background.png", + "build\\development\\watch.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\authentication\\services\\index.html", + "config.xml.orig", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\authentication\\components\\loginView\\index.html", + "www\\index.html", + "res\\icons\\ios\\icon-40.png", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\assigned\\assigned.controller.js.html", + "res\\shared\\logo.png", + "res\\icons\\ios\\icon-60-2x.png", + "www\\lib\\ionic\\fonts\\ionicons.woff", + "Chroma.PRM.Mobile.nuspec", + "app\\prm\\task-workflow\\info\\info.spec.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\prettify.css", + "app\\error\\error.routes.js", + "res\\screens\\android\\screen-ldpi-portrait.png", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\_view\\view.controller.js.html", + "protractor.ci.ie10.conf.js", + "www\\font\\Roboto-Medium.ttf", + "build\\server\\compile-template.js", + "build\\development\\run-tests.js", + "BrowserStackLocal.exe.old", + "res\\native\\android\\ant.properties", + "res\\icons\\windows\\Square310x310Logo.scale-100.png", + "www\\scripts\\lib\\ionic.bundle.js", + "DSCRelease\\PRMWeb_Octo.ps1", + "app\\authentication\\components\\loginView\\loginView.less", + "build\\configuration\\app.config.js.orig", + "taco.json", + "res\\icons\\windows\\Square150x150Logo.scale-240.png", + "www\\scripts\\chroma.templates.compiled.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\models\\index.html", + "res\\icons\\android\\icon-36-ldpi.png", + "merges\\windows\\scripts\\platformOverrides.js", + "www\\font\\Roboto-Thin.ttf", + "res\\screens\\ios\\screen-iphone-portrait.png", + "app\\error\\components\\errorView.tpl.html", + "res\\screens\\android\\screen-xhdpi-portrait.png", + "res\\icons\\ios\\icon-50-2x.png", + "res\\icons\\ios\\icon-57-2x.png", + "mockups\\List-View.PNG", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\_view\\index.html", + "build\\development\\trim-whitespace.js", + "res\\icons\\ios\\icon-50.png", + "res\\icons\\ios\\icon-57.png", + "www\\font\\Roboto-Regular.ttf", + "mockups\\despatche.jpg", + "app\\core\\services\\user.service.js", + "app\\prm\\task-workflow\\_view\\view.tpl.html", + "res\\icons\\ios\\icon-small-2x.png", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\authentication\\interceptors\\auth.interceptor.js.html", + "build\\development\\copy-resources.js", + "res\\icons\\windows\\Square70x70Logo.scale-100.png", + "protractor.ci.chrome.conf.js", + "res\\screens\\windows\\SplashScreen.scale-240.png", + "app\\prm\\models\\task.js", + "mockups\\Login-View.PNG", + "www\\scripts\\lib\\jasmine-jquery.js", + "res\\icons\\android\\icon-96-xhdpi.png", + "app\\prm\\task-workflow\\info\\info.less", + "www\\lib\\ionic\\js\\angular\\angular-animate.min.js", + "app\\prm\\task-workflow\\reject\\reject.tpl.html", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\index.html", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\authentication\\index.html", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\no-task-available\\noTaskAvailable.js.html", + "res\\icons\\wp8\\ApplicationIcon.png", + "build\\gulp.config.js", + "protractor.conf.js", + "build\\shared\\copy-index.js", + "app\\prm\\task-workflow\\no-task-available\\noTaskAvailable.spec.js", + "app\\authentication\\interceptors\\auth.interceptor.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\authentication\\auth.mod.js.html", + "build\\shared\\compile-template-cache.js", + "res\\icons\\ios\\icon-40-2x.png", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\prm.mod.js.html", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\core\\core.mod.js.html", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\index.html", + "res\\screens\\ios\\screen-iphone-portrait-667h.png", + "app\\prm\\task-workflow\\_view\\view.controller.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\constants\\flightType.js.html", + "res\\screens\\android\\screen-hdpi-landscape.png", + "res\\screens\\windows\\SplashScreenPhone.scale-240.png", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\prettify.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\sort-arrow-sprite.png", + "res\\screens\\windows\\SplashScreen.scale-100.png", + "res\\screens\\ios\\screen-iphone-portrait-736h.png", + "res\\screens\\ios\\screen-ipad-portrait.png", + "res\\screens\\ios.rar", + "www\\scripts\\lib\\angular-mocks.js", + "www\\scripts\\chroma.compiled.js.map", + "app\\authentication\\auth.routes.js", + "Chroma.PRM.Mobile.DSC.nuspec", + "www\\lib\\ionic\\js\\ionic.js", + "DSCRelease\\PRMTVDisplay.ps1", + "app\\prm\\task-workflow\\info\\info.controller.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\models\\rejectReason.js.html", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\authentication\\components\\loginView\\loginView.js.html", + "www\\scripts\\app.config.js", + "app\\index.html", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\core\\core.routes.js.html", + "app\\prm\\task-workflow\\reject\\reject.js", + "app\\prm\\task-workflow\\no-task-available\\noTaskAvailable.js", + "gulpfile_server.js", + "build\\server\\min-css-dependencies.js", + "www\\scripts\\lib\\angular-animate.js", + "res\\screens\\android\\screen-xhdpi-landscape.png", + "build\\development\\copy-index.js", + "app\\prm\\task-workflow\\assigned\\assigned.less", + "app\\error\\components\\errorView.controller.js", + "www\\lib\\ionic\\js\\angular\\angular-resource.min.js", + "DSCRelease\\PRMReports.ps1", + "build\\development\\compile-js.js", + "app\\error\\error.mod.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\error\\error.mod.js.html", + "www\\js\\chroma-framework.js", + "build\\development\\copy-chroma-ux.js", + "res\\icons\\windows\\Square44x44Logo.scale-240.png", + "res\\screens\\android\\screen-mdpi-portrait.png", + "protractor.ci.safari.conf.js" + ], + "deletedFilesIos": [], + "addedPluginsIos": [], + "deletedPluginsIos": [], + "changedFiles": [ + "Scripts\\typings\\angularjs\\angular-resource.d.ts", + "Scripts\\typings\\angularjs\\angular.d.ts", + "Scripts\\typings\\angularjs\\angular-sanitize.d.ts", + "Scripts\\typings\\jquery\\jquery.d.ts", + "Scripts\\typings\\jasmine\\jasmine.d.ts", + "Scripts\\typings\\angularjs\\angular-mocks.d.ts", + "Scripts\\typings\\angularjs\\angular-route.d.ts", + "Scripts\\typings\\angularjs\\angular-animate.d.ts", + "Scripts\\typings\\angularjs\\angular-cookies.d.ts", + "build\\development\\compile-less.js", + "app\\prm\\task-workflow\\prm.less", + "ionic.project", + "www\\lib\\ionic\\js\\angular\\angular-animate.js", + "res\\icons\\ios\\Icon-60@3x.png", + "www\\lib\\ionic\\js\\angular\\angular.min.js", + "app\\prm\\models\\rejectReason.js", + "www\\font\\Nexa Bold.otf", + "bower.json", + "www\\res\\logo.png", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\info\\index.html", + "app\\prm\\task-workflow\\info\\info.tpl.html", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\authentication\\services\\authentication.service.js.html", + "app\\e2e\\login\\login.e2e.js", + "mockups\\MI5-Promt-View.PNG", + "app\\prm\\task-workflow\\_view\\view.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\error\\error.routes.js.html", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\core\\index.html", + "build\\development\\eol.js", + "res\\icons\\android\\icon-72-hdpi.png", + "www\\lib\\ionic\\css\\ionic.min.css", + "www\\scripts\\lib\\angular-resource.js", + "build\\shared\\copy-resources.js", + "res\\screens\\android\\screen-mdpi-landscape.png", + "merges\\android\\scripts\\android2.3-jscompat.js", + "build\\server\\e2e-tests.js", + "merges\\windows\\scripts\\winstore-jscompat.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\authentication\\auth.run.js.html", + "res\\icons\\ios\\icon-60.png", + "res\\icons\\ios\\Icon@2x.png", + ".jshintrc", + "app\\authentication\\components\\loginView\\loginView.js", + "www\\font\\Roboto-BlackItalic.ttf", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\detail\\detail.js.html", + "res\\screens\\ios\\screen-iphone-landscape-736h.png", + "protractor\\spec\\login.spec.js", + "app\\authentication\\specs\\auth.feature", + "app\\prm\\prm.routes.js", + "app\\authentication\\services\\authentication.service.js", + "res\\icons\\windows\\StoreLogo.scale-100.png", + "app\\authentication\\specs\\token.feature", + "www\\lib\\ionic\\js\\angular\\angular-sanitize.js", + "app\\prm\\constants\\flightType.js", + "DSCRelease\\PRMWeb.ps1", + "app\\prm\\task-workflow\\reject\\reject.less", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\index.html", + "DSCRelease\\PRMMockups.ps1", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\assigned\\assigned.js.html", + "www\\font\\Roboto-Black.ttf", + "www\\lib\\ionic\\js\\ionic.bundle.min.js", + "app\\chroma.app.js", + "build\\configuration\\app.config.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\base.css", + "mockups\\turnround.png", + "res\\icons\\android\\icon-48-mdpi.png", + "build\\shared\\copy-chroma-ux.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\core\\services\\index.html", + "app\\core\\core.mod.js", + "www\\lib\\ionic\\js\\ionic.min.js", + "app\\error\\specs\\error.spec.js", + "build\\configuration\\app.config.js.token", + "build\\development\\compile-template.js", + "www\\scripts\\lib\\angular.js", + "mockups\\M5-View.PNG", + "build\\server\\plato.js", + "app\\authentication\\components\\loginView\\loginView.tpl.html", + "www\\font\\Nexa-Bold.otf", + "www\\font\\Roboto-Bold.ttf", + "res\\icons\\ios\\icon-72.png", + "res\\icons\\ios\\icon-76.png", + "app\\core\\core.routes.js", + "res\\screens\\ios\\screen-ipad-portrait-2x.png", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\assigned\\index.html", + "mockups\\gating.jpg", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\core\\services\\user.service.js.html", + "www\\lib\\ionic\\js\\angular-ui\\angular-ui-router.js", + "build\\server\\compile-less.js", + "build\\development\\vet.js", + "res\\screens\\ios\\screen-iphone-portrait-2x.png", + "www\\scripts\\lib\\angular-ui-router.js", + "www\\font\\Nexa Light.otf", + "app\\authentication\\auth.run.js", + "app\\prm\\task-workflow\\reject\\reject.spec.js", + "app\\prm\\prm.mod.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\core\\services\\navigation.service.js.html", + "www\\lib\\ionic\\css\\ionic.css", + "res\\icons\\windows\\Square71x71Logo.scale-240.png", + "www\\lib\\ionic\\js\\ionic.bundle.js", + "merges\\android\\scripts\\platformOverrides.js", + "www\\font\\Roboto-LightItalic.ttf", + "res\\icons\\ios\\iTunesArtwork@2x.png", + "_references.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\_container\\index.html", + "app\\prm\\task-workflow\\assigned\\assigned.js.orig", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\authentication\\components\\loginView\\loginView.controller.js.html", + "Properties\\PublishProfiles\\EndToEnd.pubxml", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\_container\\container.js.html", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\reject\\reject.js.html", + "app\\prm\\task-workflow\\_view\\view.spec.js", + "www\\lib\\ionic\\js\\ionic-angular.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\authentication\\auth.routes.js.html", + "res\\screens\\android\\screen-hdpi-portrait.png", + "app\\authentication\\specs\\auth.spec.js", + "app\\error\\error.html", + "res\\icons\\ios\\Icon-Small-50.png", + "res\\icons\\ios\\Icon-Small-40.png", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\chroma.app.js.html", + "www\\font\\Roboto-ThinItalic.ttf", + "app\\authentication\\specs\\token.spec.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\detail\\index.html", + "res\\icons\\windows\\StoreLogo.scale-240.png", + "res\\icons\\ios\\Icon-72@2x.png", + "res\\icons\\ios\\Icon-76@2x.png", + "protractor.ci.firefox.conf.js", + "www\\lib\\ionic\\js\\ionic-angular.min.js", + "build\\server\\run-tests.js", + "www\\lib\\ionic\\js\\angular-ui\\angular-ui-router.min.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\reject\\reject.controller.js.html", + "www\\lib\\ionic\\fonts\\ionicons.ttf", + "www\\scripts\\lib\\bard.js", + "res\\screens\\ios\\screen-ipad-landscape.png", + "build\\server\\min-js-dependencies.js", + "res\\icons\\ios\\Icon-Small@3x.png", + "res\\icons\\ios\\Icon-Small@2x.png", + "www\\lib\\ionic\\version.json", + "www\\font\\Roboto-Italic.ttf", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\no-task-available\\index.html", + "build\\development\\browser-sync.js", + "www\\font\\Roboto-Light.ttf", + "mockups\\turnaround.jpg", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\info\\info.js.html", + "mockups\\MI5-Alt-View.PNG", + "mockups\\mockloginscreen.png", + "packages.config", + "res\\icons\\ios\\Icon-Small-50@2x.png", + "res\\icons\\ios\\icon-60-3x.png", + "karma.conf.js", + "app\\prm\\task-workflow\\assigned\\assigned.controller.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\reject\\index.html", + "app\\prm\\task-workflow\\assigned\\assigned.spec.js", + "config.xml", + "www\\lib\\ionic\\js\\angular\\angular.js", + "res\\icons\\ios\\Icon-Small-40@2x.png", + "res\\icons\\ios\\Icon-Small-40@3x.png", + "res\\screens\\wp8\\SplashScreenImage.jpg", + "app\\core\\services\\navigation.service.js", + "app\\prm\\task-workflow\\no-task-available\\noTaskAvailable.tpl.html", + "www\\font\\Nexa-Light.otf", + "build\\server\\compile-js.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\error\\components\\errorView.js.html", + "res\\screens\\ios\\screen-ipad-landscape-2x.png", + "app\\authentication\\auth.mod.js", + "app\\prm\\task-workflow\\info\\info.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\info\\info.controller.js.html", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\error\\components\\errorView.controller.js.html", + "www\\scripts\\chroma.compiled.js", + "www\\lib\\ionic\\js\\angular\\angular-sanitize.min.js", + "res\\screens\\ios\\screen-iphone-568h-2x.png", + "res\\icons\\windows\\Square150x150Logo.scale-100.png", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\_view\\view.js.html", + "www\\lib\\ionic\\js\\angular\\angular-resource.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\constants\\index.html", + "app\\authentication\\components\\loginView\\loginView.tpl.html.orig", + "app\\prm\\task-workflow\\assigned\\assigned.js", + "gulpfile.js", + "package.json", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\error\\index.html", + "mockups\\MI70-View.PNG", + "protractor.ci.ieEdge.conf.js", + "app\\prm\\constants\\stageStatus.js", + "app\\prm\\task-workflow\\assigned\\assigned.tpl.html", + "www\\font\\Roboto-BoldItalic.ttf", + "build\\shared\\vet.js", + "res\\screens\\android\\screen-ldpi-landscape.png", + "res\\icons\\windows\\Wide310x150Logo.scale-240.png", + "res\\icons\\windows\\Wide310x150Logo.scale-100.png", + "res\\icons\\ios\\icon-72-2x.png", + "res\\icons\\ios\\icon-76-2x.png", + "app\\authentication\\views\\loginView.html", + "build\\development\\e2e-tests.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\prm.routes.js.html", + "www\\css\\chroma-framework.css", + "www\\lib\\ionic\\fonts\\ionicons.svg", + "res\\icons\\ios\\icon-small.png", + "protractor.ci.ie11.conf.js", + "app\\prm\\task-workflow\\reject\\reject.controller.js", + "karma.conf.dev.js", + "mockups\\checkin.jpg", + "www\\scripts\\lib\\jquery.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\sorter.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\constants\\stageStatus.js.html", + "www\\font\\Roboto-MediumItalic.ttf", + "build\\shared\\install.js", + "res\\icons\\windows\\Square30x30Logo.scale-100.png", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\authentication\\interceptors\\index.html", + ".jscsrc", + "res\\icons\\ios\\Icon.png", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\error\\components\\index.html", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\models\\task.js.html", + "app\\error\\components\\errorView.js", + "app\\authentication\\components\\loginView\\loginView.controller.js", + "www\\lib\\ionic\\fonts\\ionicons.eot", + "www\\css\\chroma.compiled.css", + "res\\icons\\ios\\Icon-60@2x.png", + "app\\error\\components\\errorView.less", + "res\\icons\\wp8\\Background.png", + "build\\development\\watch.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\authentication\\services\\index.html", + "config.xml.orig", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\authentication\\components\\loginView\\index.html", + "www\\index.html", + "res\\icons\\ios\\icon-40.png", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\assigned\\assigned.controller.js.html", + "res\\shared\\logo.png", + "res\\icons\\ios\\icon-60-2x.png", + "www\\lib\\ionic\\fonts\\ionicons.woff", + "Chroma.PRM.Mobile.nuspec", + "app\\prm\\task-workflow\\info\\info.spec.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\prettify.css", + "app\\error\\error.routes.js", + "res\\screens\\android\\screen-ldpi-portrait.png", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\_view\\view.controller.js.html", + "protractor.ci.ie10.conf.js", + "www\\font\\Roboto-Medium.ttf", + "build\\server\\compile-template.js", + "build\\development\\run-tests.js", + "BrowserStackLocal.exe.old", + "res\\native\\android\\ant.properties", + "res\\icons\\windows\\Square310x310Logo.scale-100.png", + "www\\scripts\\lib\\ionic.bundle.js", + "DSCRelease\\PRMWeb_Octo.ps1", + "app\\authentication\\components\\loginView\\loginView.less", + "build\\configuration\\app.config.js.orig", + "taco.json", + "res\\icons\\windows\\Square150x150Logo.scale-240.png", + "www\\scripts\\chroma.templates.compiled.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\models\\index.html", + "res\\icons\\android\\icon-36-ldpi.png", + "merges\\windows\\scripts\\platformOverrides.js", + "www\\font\\Roboto-Thin.ttf", + "res\\screens\\ios\\screen-iphone-portrait.png", + "app\\error\\components\\errorView.tpl.html", + "res\\screens\\android\\screen-xhdpi-portrait.png", + "res\\icons\\ios\\icon-50-2x.png", + "res\\icons\\ios\\icon-57-2x.png", + "mockups\\List-View.PNG", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\_view\\index.html", + "build\\development\\trim-whitespace.js", + "res\\icons\\ios\\icon-50.png", + "res\\icons\\ios\\icon-57.png", + "www\\font\\Roboto-Regular.ttf", + "mockups\\despatche.jpg", + "app\\core\\services\\user.service.js", + "app\\prm\\task-workflow\\_view\\view.tpl.html", + "res\\icons\\ios\\icon-small-2x.png", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\authentication\\interceptors\\auth.interceptor.js.html", + "build\\development\\copy-resources.js", + "res\\icons\\windows\\Square70x70Logo.scale-100.png", + "protractor.ci.chrome.conf.js", + "res\\screens\\windows\\SplashScreen.scale-240.png", + "app\\prm\\models\\task.js", + "mockups\\Login-View.PNG", + "www\\scripts\\lib\\jasmine-jquery.js", + "res\\icons\\android\\icon-96-xhdpi.png", + "app\\prm\\task-workflow\\info\\info.less", + "www\\lib\\ionic\\js\\angular\\angular-animate.min.js", + "app\\prm\\task-workflow\\reject\\reject.tpl.html", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\index.html", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\authentication\\index.html", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\task-workflow\\no-task-available\\noTaskAvailable.js.html", + "res\\icons\\wp8\\ApplicationIcon.png", + "build\\gulp.config.js", + "protractor.conf.js", + "build\\shared\\copy-index.js", + "app\\prm\\task-workflow\\no-task-available\\noTaskAvailable.spec.js", + "app\\authentication\\interceptors\\auth.interceptor.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\authentication\\auth.mod.js.html", + "build\\shared\\compile-template-cache.js", + "res\\icons\\ios\\icon-40-2x.png", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\prm.mod.js.html", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\core\\core.mod.js.html", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\index.html", + "res\\screens\\ios\\screen-iphone-portrait-667h.png", + "app\\prm\\task-workflow\\_view\\view.controller.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\constants\\flightType.js.html", + "res\\screens\\android\\screen-hdpi-landscape.png", + "res\\screens\\windows\\SplashScreenPhone.scale-240.png", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\prettify.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\sort-arrow-sprite.png", + "res\\screens\\windows\\SplashScreen.scale-100.png", + "res\\screens\\ios\\screen-iphone-portrait-736h.png", + "res\\screens\\ios\\screen-ipad-portrait.png", + "res\\screens\\ios.rar", + "www\\scripts\\lib\\angular-mocks.js", + "www\\scripts\\chroma.compiled.js.map", + "app\\authentication\\auth.routes.js", + "Chroma.PRM.Mobile.DSC.nuspec", + "www\\lib\\ionic\\js\\ionic.js", + "DSCRelease\\PRMTVDisplay.ps1", + "app\\prm\\task-workflow\\info\\info.controller.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\prm\\models\\rejectReason.js.html", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\authentication\\components\\loginView\\loginView.js.html", + "www\\scripts\\app.config.js", + "app\\index.html", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\core\\core.routes.js.html", + "app\\prm\\task-workflow\\reject\\reject.js", + "app\\prm\\task-workflow\\no-task-available\\noTaskAvailable.js", + "gulpfile_server.js", + "build\\server\\min-css-dependencies.js", + "www\\scripts\\lib\\angular-animate.js", + "res\\screens\\android\\screen-xhdpi-landscape.png", + "build\\development\\copy-index.js", + "app\\prm\\task-workflow\\assigned\\assigned.less", + "app\\error\\components\\errorView.controller.js", + "www\\lib\\ionic\\js\\angular\\angular-resource.min.js", + "DSCRelease\\PRMReports.ps1", + "build\\development\\compile-js.js", + "app\\error\\error.mod.js", + "coverage\\Chrome 44.0.2403 (Windows 7 0.0.0)\\app\\error\\error.mod.js.html", + "www\\js\\chroma-framework.js", + "build\\development\\copy-chroma-ux.js", + "res\\icons\\windows\\Square44x44Logo.scale-240.png", + "res\\screens\\android\\screen-mdpi-portrait.png", + "protractor.ci.safari.conf.js" + ], + "deletedFiles": [], + "addedPlugins": [], + "deletedPlugins": [] +} \ No newline at end of file diff --git a/chroma_aodb_profile.mobileprovision b/chroma_aodb_profile.mobileprovision new file mode 100644 index 0000000..6492694 Binary files /dev/null and b/chroma_aodb_profile.mobileprovision differ diff --git a/config.js b/config.js new file mode 100644 index 0000000..a3f5938 --- /dev/null +++ b/config.js @@ -0,0 +1,51 @@ +System.config({ + baseURL: "/", + defaultJSExtensions: true, + transpiler: "babel", + babelOptions: { + "optional": [ + "runtime", + "optimisation.modules.system" + ] + }, + paths: { + "github:*": "jspm_packages/github/*", + "npm:*": "jspm_packages/npm/*" + }, + + map: { + "babel": "npm:babel-core@5.8.25", + "babel-runtime": "npm:babel-runtime@5.8.25", + "core-js": "npm:core-js@1.2.1", + "github:jspm/nodelibs-assert@0.1.0": { + "assert": "npm:assert@1.3.0" + }, + "github:jspm/nodelibs-process@0.1.2": { + "process": "npm:process@0.11.2" + }, + "github:jspm/nodelibs-util@0.1.0": { + "util": "npm:util@0.10.3" + }, + "npm:assert@1.3.0": { + "util": "npm:util@0.10.3" + }, + "npm:babel-runtime@5.8.25": { + "process": "github:jspm/nodelibs-process@0.1.2" + }, + "npm:core-js@1.2.1": { + "fs": "github:jspm/nodelibs-fs@0.1.2", + "process": "github:jspm/nodelibs-process@0.1.2", + "systemjs-json": "github:systemjs/plugin-json@0.1.0" + }, + "npm:inherits@2.0.1": { + "util": "github:jspm/nodelibs-util@0.1.0" + }, + "npm:process@0.11.2": { + "assert": "github:jspm/nodelibs-assert@0.1.0" + }, + "npm:util@0.10.3": { + "inherits": "npm:inherits@2.0.1", + "process": "github:jspm/nodelibs-process@0.1.2" + } + } +}); diff --git a/config.xml b/config.xml new file mode 100644 index 0000000..c831cdc --- /dev/null +++ b/config.xml @@ -0,0 +1,86 @@ + + + AODBMobile + AODB Mobile client + Lockheed Martin + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..6538ab9 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,30 @@ +/// +var util = require('gulp-util'); +environment = util.env.environment || 'development'; + +require('./build/gulp/run-tests'); +require('./build/gulp/compile-js'); +require('./build/gulp/compile-tests'); +require('./build/gulp/compile-less'); +require('./build/gulp/compile-template'); +require('./build/gulp/watch'); +require('./build/gulp/min-js-dependencies'); +require('./build/gulp/min-css-dependencies'); +require('./build/gulp/install'); +require('./build/gulp/compile-template-cache'); +require('./build/gulp/copy-resources'); +require('./build/gulp/copy-index'); +require('./build/gulp/install'); +require('./build/gulp/sonar'); +require('./build/gulp/update-url'); +require('./build/gulp/add-pushnotifications'); +require('./build/gulp/add-hockeyapp'); +require('./build/gulp/gitversion'); +require('./build/gulp/hockey-upload-android'); +require('./build/gulp/hockey-upload-ios'); +require('./build/gulp/purge-previous-ionic'); + +var g = require('gulp'); + +g.task('test', ['compile-tests', 'run-tests']); +g.task('build', ['copy-resources', 'copy-index', 'compile-js', 'compile-less', 'compile-template', 'compile-template-cache','install', 'purge-previous-ionic']); diff --git a/ionic.project b/ionic.project new file mode 100644 index 0000000..592c6ea --- /dev/null +++ b/ionic.project @@ -0,0 +1,4 @@ +{ + "name": "AODB.Mobile", + "app_id": "e5b00de9" +} diff --git a/karma.conf.js b/karma.conf.js new file mode 100644 index 0000000..4f1dd7a --- /dev/null +++ b/karma.conf.js @@ -0,0 +1,93 @@ +// Karma configurationi +// Generated on Tue Apr 21 2015 09:09:36 GMT+0100 (GMT Daylight Time) + +module.exports = function (config) { + var gulpConfig = require('./build/gulp.config')(); + config.set({ + // base path that will be used to resolve all patterns (eg. files, exclude) + basePath: '', + + // frameworks to use + // available frameworks: https://npmjs.org/browse/keyword/karma-adapter + frameworks: ['systemjs', 'jasmine'], + + // list of files / patterns to load in the browser + files: gulpConfig.karma.files, + + preprocessors: gulpConfig.karma.preprocessors, + + // list of files to exclude + exclude: gulpConfig.karma.exclude, + + systemjs: { + config: { + transpiler: 'babel', + defaultJSExtensions: true, + "baseURL": "./tests/compiled/", + "map": { + "app": './tests/compiled' + }, + "paths": { + 'systemjs': './../../jspm_packages/system.js', + 'system-polyfills': './../../jspm_packages/system-polyfills.js', + 'es6-module-loader': './../../node_modules/es6-module-loader/dist/es6-module-loader.js', + 'phantomjs-polyfill': './../../node_modules/phantomjs-polyfill/bind-polyfill.js', + 'moment': 'lib/moment.js' + } + } + }, + + + reporters: ['progress', 'coverage'], + + coverageReporter: { + reporters: gulpConfig.karma.coverage.reporters, + dir: gulpConfig.karma.coverage.dir + }, + + noResolve: false, + + htmlReporter: { + outputDir: './report/unittests', // where to put the reports + templatePath: null, // set if you moved jasmine_template.html + focusOnFailures: true, // reports show failures on start + namedFiles: false, // name files instead of creating sub-directories + pageTitle: null, // page title for reports; browser info by default + urlFriendlyName: false // simply replaces spaces with _ for files/dirs + }, + + // web server port + port: 9876, + + // enable / disable colors in the output (reporters and logs) + colors: true, + + // level of logging + // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG + logLevel: config.LOG_INFO, + + // enable / disable watching file and executing tests whenever any file changes + autoWatch: true, + + // start these browsers + // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher + //browsers: ['PhantomJS'], + browsers: ['PhantomJS'], + + plugins: [ + 'karma-systemjs', + 'karma-typescript-preprocessor', + 'karma-chrome-launcher', + 'karma-coverage', + 'karma-html-reporter', + 'karma-jasmine', + 'karma-jasmine-html-reporter', + 'karma-phantomjs-launcher', + 'phantomjs' + ], + + // Continuous Integration mode + // if true, Karma captures browsers, runs the tests and exits + singleRun: true + }); +}; diff --git a/lib/jquery.signalR-2.2.1.js b/lib/jquery.signalR-2.2.1.js new file mode 100644 index 0000000..9e40960 --- /dev/null +++ b/lib/jquery.signalR-2.2.1.js @@ -0,0 +1,2955 @@ +/* jquery.signalR.core.js */ +/*global window:false */ +/*! + * ASP.NET SignalR JavaScript Library v2.2.1 + * http://signalr.net/ + * + * Copyright (c) .NET Foundation. All rights reserved. + * Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + * + */ + +/// +/// +(function ($, window, undefined) { + + var resources = { + nojQuery: "jQuery was not found. Please ensure jQuery is referenced before the SignalR client JavaScript file.", + noTransportOnInit: "No transport could be initialized successfully. Try specifying a different transport or none at all for auto initialization.", + errorOnNegotiate: "Error during negotiation request.", + stoppedWhileLoading: "The connection was stopped during page load.", + stoppedWhileNegotiating: "The connection was stopped during the negotiate request.", + errorParsingNegotiateResponse: "Error parsing negotiate response.", + errorDuringStartRequest: "Error during start request. Stopping the connection.", + stoppedDuringStartRequest: "The connection was stopped during the start request.", + errorParsingStartResponse: "Error parsing start response: '{0}'. Stopping the connection.", + invalidStartResponse: "Invalid start response: '{0}'. Stopping the connection.", + protocolIncompatible: "You are using a version of the client that isn't compatible with the server. Client version {0}, server version {1}.", + sendFailed: "Send failed.", + parseFailed: "Failed at parsing response: {0}", + longPollFailed: "Long polling request failed.", + eventSourceFailedToConnect: "EventSource failed to connect.", + eventSourceError: "Error raised by EventSource", + webSocketClosed: "WebSocket closed.", + pingServerFailedInvalidResponse: "Invalid ping response when pinging server: '{0}'.", + pingServerFailed: "Failed to ping server.", + pingServerFailedStatusCode: "Failed to ping server. Server responded with status code {0}, stopping the connection.", + pingServerFailedParse: "Failed to parse ping server response, stopping the connection.", + noConnectionTransport: "Connection is in an invalid state, there is no transport active.", + webSocketsInvalidState: "The Web Socket transport is in an invalid state, transitioning into reconnecting.", + reconnectTimeout: "Couldn't reconnect within the configured timeout of {0} ms, disconnecting.", + reconnectWindowTimeout: "The client has been inactive since {0} and it has exceeded the inactivity timeout of {1} ms. Stopping the connection." + }; + + if (typeof ($) !== "function") { + // no jQuery! + throw new Error(resources.nojQuery); + } + + var signalR, + _connection, + _pageLoaded = (window.document.readyState === "complete"), + _pageWindow = $(window), + _negotiateAbortText = "__Negotiate Aborted__", + events = { + onStart: "onStart", + onStarting: "onStarting", + onReceived: "onReceived", + onError: "onError", + onConnectionSlow: "onConnectionSlow", + onReconnecting: "onReconnecting", + onReconnect: "onReconnect", + onStateChanged: "onStateChanged", + onDisconnect: "onDisconnect" + }, + ajaxDefaults = { + processData: true, + timeout: null, + async: true, + global: false, + cache: false + }, + log = function (msg, logging) { + if (logging === false) { + return; + } + var m; + if (typeof (window.console) === "undefined") { + return; + } + m = "[" + new Date().toTimeString() + "] SignalR: " + msg; + if (window.console.debug) { + window.console.debug(m); + } else if (window.console.log) { + window.console.log(m); + } + }, + + changeState = function (connection, expectedState, newState) { + if (expectedState === connection.state) { + connection.state = newState; + + $(connection).triggerHandler(events.onStateChanged, [{ oldState: expectedState, newState: newState }]); + return true; + } + + return false; + }, + + isDisconnecting = function (connection) { + return connection.state === signalR.connectionState.disconnected; + }, + + supportsKeepAlive = function (connection) { + return connection._.keepAliveData.activated && + connection.transport.supportsKeepAlive(connection); + }, + + configureStopReconnectingTimeout = function (connection) { + var stopReconnectingTimeout, + onReconnectTimeout; + + // Check if this connection has already been configured to stop reconnecting after a specified timeout. + // Without this check if a connection is stopped then started events will be bound multiple times. + if (!connection._.configuredStopReconnectingTimeout) { + onReconnectTimeout = function (connection) { + var message = signalR._.format(signalR.resources.reconnectTimeout, connection.disconnectTimeout); + connection.log(message); + $(connection).triggerHandler(events.onError, [signalR._.error(message, /* source */ "TimeoutException")]); + connection.stop(/* async */ false, /* notifyServer */ false); + }; + + connection.reconnecting(function () { + var connection = this; + + // Guard against state changing in a previous user defined even handler + if (connection.state === signalR.connectionState.reconnecting) { + stopReconnectingTimeout = window.setTimeout(function () { onReconnectTimeout(connection); }, connection.disconnectTimeout); + } + }); + + connection.stateChanged(function (data) { + if (data.oldState === signalR.connectionState.reconnecting) { + // Clear the pending reconnect timeout check + window.clearTimeout(stopReconnectingTimeout); + } + }); + + connection._.configuredStopReconnectingTimeout = true; + } + }; + + signalR = function (url, qs, logging) { + /// Creates a new SignalR connection for the given url + /// The URL of the long polling endpoint + /// + /// [Optional] Custom querystring parameters to add to the connection URL. + /// If an object, every non-function member will be added to the querystring. + /// If a string, it's added to the QS as specified. + /// + /// + /// [Optional] A flag indicating whether connection logging is enabled to the browser + /// console/log. Defaults to false. + /// + + return new signalR.fn.init(url, qs, logging); + }; + + signalR._ = { + defaultContentType: "application/x-www-form-urlencoded; charset=UTF-8", + + ieVersion: (function () { + var version, + matches; + + if (window.navigator.appName === 'Microsoft Internet Explorer') { + // Check if the user agent has the pattern "MSIE (one or more numbers).(one or more numbers)"; + matches = /MSIE ([0-9]+\.[0-9]+)/.exec(window.navigator.userAgent); + + if (matches) { + version = window.parseFloat(matches[1]); + } + } + + // undefined value means not IE + return version; + })(), + + error: function (message, source, context) { + var e = new Error(message); + e.source = source; + + if (typeof context !== "undefined") { + e.context = context; + } + + return e; + }, + + transportError: function (message, transport, source, context) { + var e = this.error(message, source, context); + e.transport = transport ? transport.name : undefined; + return e; + }, + + format: function () { + /// Usage: format("Hi {0}, you are {1}!", "Foo", 100) + var s = arguments[0]; + for (var i = 0; i < arguments.length - 1; i++) { + s = s.replace("{" + i + "}", arguments[i + 1]); + } + return s; + }, + + firefoxMajorVersion: function (userAgent) { + // Firefox user agents: http://useragentstring.com/pages/Firefox/ + var matches = userAgent.match(/Firefox\/(\d+)/); + if (!matches || !matches.length || matches.length < 2) { + return 0; + } + return parseInt(matches[1], 10 /* radix */); + }, + + configurePingInterval: function (connection) { + var config = connection._.config, + onFail = function (error) { + $(connection).triggerHandler(events.onError, [error]); + }; + + if (config && !connection._.pingIntervalId && config.pingInterval) { + connection._.pingIntervalId = window.setInterval(function () { + signalR.transports._logic.pingServer(connection).fail(onFail); + }, config.pingInterval); + } + } + }; + + signalR.events = events; + + signalR.resources = resources; + + signalR.ajaxDefaults = ajaxDefaults; + + signalR.changeState = changeState; + + signalR.isDisconnecting = isDisconnecting; + + signalR.connectionState = { + connecting: 0, + connected: 1, + reconnecting: 2, + disconnected: 4 + }; + + signalR.hub = { + start: function () { + // This will get replaced with the real hub connection start method when hubs is referenced correctly + throw new Error("SignalR: Error loading hubs. Ensure your hubs reference is correct, e.g. ."); + } + }; + + // .on() was added in version 1.7.0, .load() was removed in version 3.0.0 so we fallback to .load() if .on() does + // not exist to not break existing applications + if (typeof _pageWindow.on == "function") { + _pageWindow.on("load", function () { _pageLoaded = true; }); + } + else { + _pageWindow.load(function () { _pageLoaded = true; }); + } + + function validateTransport(requestedTransport, connection) { + /// Validates the requested transport by cross checking it with the pre-defined signalR.transports + /// The designated transports that the user has specified. + /// The connection that will be using the requested transports. Used for logging purposes. + /// + + if ($.isArray(requestedTransport)) { + // Go through transport array and remove an "invalid" tranports + for (var i = requestedTransport.length - 1; i >= 0; i--) { + var transport = requestedTransport[i]; + if ($.type(transport) !== "string" || !signalR.transports[transport]) { + connection.log("Invalid transport: " + transport + ", removing it from the transports list."); + requestedTransport.splice(i, 1); + } + } + + // Verify we still have transports left, if we dont then we have invalid transports + if (requestedTransport.length === 0) { + connection.log("No transports remain within the specified transport array."); + requestedTransport = null; + } + } else if (!signalR.transports[requestedTransport] && requestedTransport !== "auto") { + connection.log("Invalid transport: " + requestedTransport.toString() + "."); + requestedTransport = null; + } else if (requestedTransport === "auto" && signalR._.ieVersion <= 8) { + // If we're doing an auto transport and we're IE8 then force longPolling, #1764 + return ["longPolling"]; + + } + + return requestedTransport; + } + + function getDefaultPort(protocol) { + if (protocol === "http:") { + return 80; + } else if (protocol === "https:") { + return 443; + } + } + + function addDefaultPort(protocol, url) { + // Remove ports from url. We have to check if there's a / or end of line + // following the port in order to avoid removing ports such as 8080. + if (url.match(/:\d+$/)) { + return url; + } else { + return url + ":" + getDefaultPort(protocol); + } + } + + function ConnectingMessageBuffer(connection, drainCallback) { + var that = this, + buffer = []; + + that.tryBuffer = function (message) { + if (connection.state === $.signalR.connectionState.connecting) { + buffer.push(message); + + return true; + } + + return false; + }; + + that.drain = function () { + // Ensure that the connection is connected when we drain (do not want to drain while a connection is not active) + if (connection.state === $.signalR.connectionState.connected) { + while (buffer.length > 0) { + drainCallback(buffer.shift()); + } + } + }; + + that.clear = function () { + buffer = []; + }; + } + + signalR.fn = signalR.prototype = { + init: function (url, qs, logging) { + var $connection = $(this); + + this.url = url; + this.qs = qs; + this.lastError = null; + this._ = { + keepAliveData: {}, + connectingMessageBuffer: new ConnectingMessageBuffer(this, function (message) { + $connection.triggerHandler(events.onReceived, [message]); + }), + lastMessageAt: new Date().getTime(), + lastActiveAt: new Date().getTime(), + beatInterval: 5000, // Default value, will only be overridden if keep alive is enabled, + beatHandle: null, + totalTransportConnectTimeout: 0 // This will be the sum of the TransportConnectTimeout sent in response to negotiate and connection.transportConnectTimeout + }; + if (typeof (logging) === "boolean") { + this.logging = logging; + } + }, + + _parseResponse: function (response) { + var that = this; + + if (!response) { + return response; + } else if (typeof response === "string") { + return that.json.parse(response); + } else { + return response; + } + }, + + _originalJson: window.JSON, + + json: window.JSON, + + isCrossDomain: function (url, against) { + /// Checks if url is cross domain + /// The base URL + /// + /// An optional argument to compare the URL against, if not specified it will be set to window.location. + /// If specified it must contain a protocol and a host property. + /// + var link; + + url = $.trim(url); + + against = against || window.location; + + if (url.indexOf("http") !== 0) { + return false; + } + + // Create an anchor tag. + link = window.document.createElement("a"); + link.href = url; + + // When checking for cross domain we have to special case port 80 because the window.location will remove the + return link.protocol + addDefaultPort(link.protocol, link.host) !== against.protocol + addDefaultPort(against.protocol, against.host); + }, + + ajaxDataType: "text", + + contentType: "application/json; charset=UTF-8", + + logging: false, + + state: signalR.connectionState.disconnected, + + clientProtocol: "1.5", + + reconnectDelay: 2000, + + transportConnectTimeout: 0, + + disconnectTimeout: 30000, // This should be set by the server in response to the negotiate request (30s default) + + reconnectWindow: 30000, // This should be set by the server in response to the negotiate request + + keepAliveWarnAt: 2 / 3, // Warn user of slow connection if we breach the X% mark of the keep alive timeout + + start: function (options, callback) { + /// Starts the connection + /// Options map + /// A callback function to execute when the connection has started + var connection = this, + config = { + pingInterval: 300000, + waitForPageLoad: true, + transport: "auto", + jsonp: false + }, + initialize, + deferred = connection._deferral || $.Deferred(), // Check to see if there is a pre-existing deferral that's being built on, if so we want to keep using it + parser = window.document.createElement("a"); + + connection.lastError = null; + + // Persist the deferral so that if start is called multiple times the same deferral is used. + connection._deferral = deferred; + + if (!connection.json) { + // no JSON! + throw new Error("SignalR: No JSON parser found. Please ensure json2.js is referenced before the SignalR.js file if you need to support clients without native JSON parsing support, e.g. IE<8."); + } + + if ($.type(options) === "function") { + // Support calling with single callback parameter + callback = options; + } else if ($.type(options) === "object") { + $.extend(config, options); + if ($.type(config.callback) === "function") { + callback = config.callback; + } + } + + config.transport = validateTransport(config.transport, connection); + + // If the transport is invalid throw an error and abort start + if (!config.transport) { + throw new Error("SignalR: Invalid transport(s) specified, aborting start."); + } + + connection._.config = config; + + // Check to see if start is being called prior to page load + // If waitForPageLoad is true we then want to re-direct function call to the window load event + if (!_pageLoaded && config.waitForPageLoad === true) { + connection._.deferredStartHandler = function () { + connection.start(options, callback); + }; + _pageWindow.bind("load", connection._.deferredStartHandler); + + return deferred.promise(); + } + + // If we're already connecting just return the same deferral as the original connection start + if (connection.state === signalR.connectionState.connecting) { + return deferred.promise(); + } else if (changeState(connection, + signalR.connectionState.disconnected, + signalR.connectionState.connecting) === false) { + // We're not connecting so try and transition into connecting. + // If we fail to transition then we're either in connected or reconnecting. + + deferred.resolve(connection); + return deferred.promise(); + } + + configureStopReconnectingTimeout(connection); + + // Resolve the full url + parser.href = connection.url; + if (!parser.protocol || parser.protocol === ":") { + connection.protocol = window.document.location.protocol; + connection.host = parser.host || window.document.location.host; + } else { + connection.protocol = parser.protocol; + connection.host = parser.host; + } + + connection.baseUrl = connection.protocol + "//" + connection.host; + + // Set the websocket protocol + connection.wsProtocol = connection.protocol === "https:" ? "wss://" : "ws://"; + + // If jsonp with no/auto transport is specified, then set the transport to long polling + // since that is the only transport for which jsonp really makes sense. + // Some developers might actually choose to specify jsonp for same origin requests + // as demonstrated by Issue #623. + if (config.transport === "auto" && config.jsonp === true) { + config.transport = "longPolling"; + } + + // If the url is protocol relative, prepend the current windows protocol to the url. + if (connection.url.indexOf("//") === 0) { + connection.url = window.location.protocol + connection.url; + connection.log("Protocol relative URL detected, normalizing it to '" + connection.url + "'."); + } + + if (this.isCrossDomain(connection.url)) { + connection.log("Auto detected cross domain url."); + + if (config.transport === "auto") { + // TODO: Support XDM with foreverFrame + config.transport = ["webSockets", "serverSentEvents", "longPolling"]; + } + + if (typeof (config.withCredentials) === "undefined") { + config.withCredentials = false; + } + + // Determine if jsonp is the only choice for negotiation, ajaxSend and ajaxAbort. + // i.e. if the browser doesn't supports CORS + // If it is, ignore any preference to the contrary, and switch to jsonp. + if (!config.jsonp) { + config.jsonp = !$.support.cors; + + if (config.jsonp) { + connection.log("Using jsonp because this browser doesn't support CORS."); + } + } + + connection.contentType = signalR._.defaultContentType; + } + + connection.withCredentials = config.withCredentials; + + connection.ajaxDataType = config.jsonp ? "jsonp" : "text"; + + $(connection).bind(events.onStart, function (e, data) { + if ($.type(callback) === "function") { + callback.call(connection); + } + deferred.resolve(connection); + }); + + connection._.initHandler = signalR.transports._logic.initHandler(connection); + + initialize = function (transports, index) { + var noTransportError = signalR._.error(resources.noTransportOnInit); + + index = index || 0; + if (index >= transports.length) { + if (index === 0) { + connection.log("No transports supported by the server were selected."); + } else if (index === 1) { + connection.log("No fallback transports were selected."); + } else { + connection.log("Fallback transports exhausted."); + } + + // No transport initialized successfully + $(connection).triggerHandler(events.onError, [noTransportError]); + deferred.reject(noTransportError); + // Stop the connection if it has connected and move it into the disconnected state + connection.stop(); + return; + } + + // The connection was aborted + if (connection.state === signalR.connectionState.disconnected) { + return; + } + + var transportName = transports[index], + transport = signalR.transports[transportName], + onFallback = function () { + initialize(transports, index + 1); + }; + + connection.transport = transport; + + try { + connection._.initHandler.start(transport, function () { // success + // Firefox 11+ doesn't allow sync XHR withCredentials: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#withCredentials + var isFirefox11OrGreater = signalR._.firefoxMajorVersion(window.navigator.userAgent) >= 11, + asyncAbort = !!connection.withCredentials && isFirefox11OrGreater; + + connection.log("The start request succeeded. Transitioning to the connected state."); + + if (supportsKeepAlive(connection)) { + signalR.transports._logic.monitorKeepAlive(connection); + } + + signalR.transports._logic.startHeartbeat(connection); + + // Used to ensure low activity clients maintain their authentication. + // Must be configured once a transport has been decided to perform valid ping requests. + signalR._.configurePingInterval(connection); + + if (!changeState(connection, + signalR.connectionState.connecting, + signalR.connectionState.connected)) { + connection.log("WARNING! The connection was not in the connecting state."); + } + + // Drain any incoming buffered messages (messages that came in prior to connect) + connection._.connectingMessageBuffer.drain(); + + $(connection).triggerHandler(events.onStart); + + // wire the stop handler for when the user leaves the page + _pageWindow.bind("unload", function () { + connection.log("Window unloading, stopping the connection."); + + connection.stop(asyncAbort); + }); + + if (isFirefox11OrGreater) { + // Firefox does not fire cross-domain XHRs in the normal unload handler on tab close. + // #2400 + _pageWindow.bind("beforeunload", function () { + // If connection.stop() runs runs in beforeunload and fails, it will also fail + // in unload unless connection.stop() runs after a timeout. + window.setTimeout(function () { + connection.stop(asyncAbort); + }, 0); + }); + } + }, onFallback); + } + catch (error) { + connection.log(transport.name + " transport threw '" + error.message + "' when attempting to start."); + onFallback(); + } + }; + + var url = connection.url + "/negotiate", + onFailed = function (error, connection) { + var err = signalR._.error(resources.errorOnNegotiate, error, connection._.negotiateRequest); + + $(connection).triggerHandler(events.onError, err); + deferred.reject(err); + // Stop the connection if negotiate failed + connection.stop(); + }; + + $(connection).triggerHandler(events.onStarting); + + url = signalR.transports._logic.prepareQueryString(connection, url); + + connection.log("Negotiating with '" + url + "'."); + + // Save the ajax negotiate request object so we can abort it if stop is called while the request is in flight. + connection._.negotiateRequest = signalR.transports._logic.ajax(connection, { + url: url, + error: function (error, statusText) { + // We don't want to cause any errors if we're aborting our own negotiate request. + if (statusText !== _negotiateAbortText) { + onFailed(error, connection); + } else { + // This rejection will noop if the deferred has already been resolved or rejected. + deferred.reject(signalR._.error(resources.stoppedWhileNegotiating, null /* error */, connection._.negotiateRequest)); + } + }, + success: function (result) { + var res, + keepAliveData, + protocolError, + transports = [], + supportedTransports = []; + + try { + res = connection._parseResponse(result); + } catch (error) { + onFailed(signalR._.error(resources.errorParsingNegotiateResponse, error), connection); + return; + } + + keepAliveData = connection._.keepAliveData; + connection.appRelativeUrl = res.Url; + connection.id = res.ConnectionId; + connection.token = res.ConnectionToken; + connection.webSocketServerUrl = res.WebSocketServerUrl; + + // The long poll timeout is the ConnectionTimeout plus 10 seconds + connection._.pollTimeout = res.ConnectionTimeout * 1000 + 10000; // in ms + + // Once the server has labeled the PersistentConnection as Disconnected, we should stop attempting to reconnect + // after res.DisconnectTimeout seconds. + connection.disconnectTimeout = res.DisconnectTimeout * 1000; // in ms + + // Add the TransportConnectTimeout from the response to the transportConnectTimeout from the client to calculate the total timeout + connection._.totalTransportConnectTimeout = connection.transportConnectTimeout + res.TransportConnectTimeout * 1000; + + // If we have a keep alive + if (res.KeepAliveTimeout) { + // Register the keep alive data as activated + keepAliveData.activated = true; + + // Timeout to designate when to force the connection into reconnecting converted to milliseconds + keepAliveData.timeout = res.KeepAliveTimeout * 1000; + + // Timeout to designate when to warn the developer that the connection may be dead or is not responding. + keepAliveData.timeoutWarning = keepAliveData.timeout * connection.keepAliveWarnAt; + + // Instantiate the frequency in which we check the keep alive. It must be short in order to not miss/pick up any changes + connection._.beatInterval = (keepAliveData.timeout - keepAliveData.timeoutWarning) / 3; + } else { + keepAliveData.activated = false; + } + + connection.reconnectWindow = connection.disconnectTimeout + (keepAliveData.timeout || 0); + + if (!res.ProtocolVersion || res.ProtocolVersion !== connection.clientProtocol) { + protocolError = signalR._.error(signalR._.format(resources.protocolIncompatible, connection.clientProtocol, res.ProtocolVersion)); + $(connection).triggerHandler(events.onError, [protocolError]); + deferred.reject(protocolError); + + return; + } + + $.each(signalR.transports, function (key) { + if ((key.indexOf("_") === 0) || (key === "webSockets" && !res.TryWebSockets)) { + return true; + } + supportedTransports.push(key); + }); + + if ($.isArray(config.transport)) { + $.each(config.transport, function (_, transport) { + if ($.inArray(transport, supportedTransports) >= 0) { + transports.push(transport); + } + }); + } else if (config.transport === "auto") { + transports = supportedTransports; + } else if ($.inArray(config.transport, supportedTransports) >= 0) { + transports.push(config.transport); + } + + initialize(transports); + } + }); + + return deferred.promise(); + }, + + starting: function (callback) { + /// Adds a callback that will be invoked before anything is sent over the connection + /// A callback function to execute before the connection is fully instantiated. + /// + var connection = this; + $(connection).bind(events.onStarting, function (e, data) { + callback.call(connection); + }); + return connection; + }, + + send: function (data) { + /// Sends data over the connection + /// The data to send over the connection + /// + var connection = this; + + if (connection.state === signalR.connectionState.disconnected) { + // Connection hasn't been started yet + throw new Error("SignalR: Connection must be started before data can be sent. Call .start() before .send()"); + } + + if (connection.state === signalR.connectionState.connecting) { + // Connection hasn't been started yet + throw new Error("SignalR: Connection has not been fully initialized. Use .start().done() or .start().fail() to run logic after the connection has started."); + } + + connection.transport.send(connection, data); + // REVIEW: Should we return deferred here? + return connection; + }, + + received: function (callback) { + /// Adds a callback that will be invoked after anything is received over the connection + /// A callback function to execute when any data is received on the connection + /// + var connection = this; + $(connection).bind(events.onReceived, function (e, data) { + callback.call(connection, data); + }); + return connection; + }, + + stateChanged: function (callback) { + /// Adds a callback that will be invoked when the connection state changes + /// A callback function to execute when the connection state changes + /// + var connection = this; + $(connection).bind(events.onStateChanged, function (e, data) { + callback.call(connection, data); + }); + return connection; + }, + + error: function (callback) { + /// Adds a callback that will be invoked after an error occurs with the connection + /// A callback function to execute when an error occurs on the connection + /// + var connection = this; + $(connection).bind(events.onError, function (e, errorData, sendData) { + connection.lastError = errorData; + // In practice 'errorData' is the SignalR built error object. + // In practice 'sendData' is undefined for all error events except those triggered by + // 'ajaxSend' and 'webSockets.send'.'sendData' is the original send payload. + callback.call(connection, errorData, sendData); + }); + return connection; + }, + + disconnected: function (callback) { + /// Adds a callback that will be invoked when the client disconnects + /// A callback function to execute when the connection is broken + /// + var connection = this; + $(connection).bind(events.onDisconnect, function (e, data) { + callback.call(connection); + }); + return connection; + }, + + connectionSlow: function (callback) { + /// Adds a callback that will be invoked when the client detects a slow connection + /// A callback function to execute when the connection is slow + /// + var connection = this; + $(connection).bind(events.onConnectionSlow, function (e, data) { + callback.call(connection); + }); + + return connection; + }, + + reconnecting: function (callback) { + /// Adds a callback that will be invoked when the underlying transport begins reconnecting + /// A callback function to execute when the connection enters a reconnecting state + /// + var connection = this; + $(connection).bind(events.onReconnecting, function (e, data) { + callback.call(connection); + }); + return connection; + }, + + reconnected: function (callback) { + /// Adds a callback that will be invoked when the underlying transport reconnects + /// A callback function to execute when the connection is restored + /// + var connection = this; + $(connection).bind(events.onReconnect, function (e, data) { + callback.call(connection); + }); + return connection; + }, + + stop: function (async, notifyServer) { + /// Stops listening + /// Whether or not to asynchronously abort the connection + /// Whether we want to notify the server that we are aborting the connection + /// + var connection = this, + // Save deferral because this is always cleaned up + deferral = connection._deferral; + + // Verify that we've bound a load event. + if (connection._.deferredStartHandler) { + // Unbind the event. + _pageWindow.unbind("load", connection._.deferredStartHandler); + } + + // Always clean up private non-timeout based state. + delete connection._.config; + delete connection._.deferredStartHandler; + + // This needs to be checked despite the connection state because a connection start can be deferred until page load. + // If we've deferred the start due to a page load we need to unbind the "onLoad" -> start event. + if (!_pageLoaded && (!connection._.config || connection._.config.waitForPageLoad === true)) { + connection.log("Stopping connection prior to negotiate."); + + // If we have a deferral we should reject it + if (deferral) { + deferral.reject(signalR._.error(resources.stoppedWhileLoading)); + } + + // Short-circuit because the start has not been fully started. + return; + } + + if (connection.state === signalR.connectionState.disconnected) { + return; + } + + connection.log("Stopping connection."); + + // Clear this no matter what + window.clearTimeout(connection._.beatHandle); + window.clearInterval(connection._.pingIntervalId); + + if (connection.transport) { + connection.transport.stop(connection); + + if (notifyServer !== false) { + connection.transport.abort(connection, async); + } + + if (supportsKeepAlive(connection)) { + signalR.transports._logic.stopMonitoringKeepAlive(connection); + } + + connection.transport = null; + } + + if (connection._.negotiateRequest) { + // If the negotiation request has already completed this will noop. + connection._.negotiateRequest.abort(_negotiateAbortText); + delete connection._.negotiateRequest; + } + + // Ensure that initHandler.stop() is called before connection._deferral is deleted + if (connection._.initHandler) { + connection._.initHandler.stop(); + } + + delete connection._deferral; + delete connection.messageId; + delete connection.groupsToken; + delete connection.id; + delete connection._.pingIntervalId; + delete connection._.lastMessageAt; + delete connection._.lastActiveAt; + + // Clear out our message buffer + connection._.connectingMessageBuffer.clear(); + + // Trigger the disconnect event + changeState(connection, connection.state, signalR.connectionState.disconnected); + $(connection).triggerHandler(events.onDisconnect); + + return connection; + }, + + log: function (msg) { + log(msg, this.logging); + } + }; + + signalR.fn.init.prototype = signalR.fn; + + signalR.noConflict = function () { + /// Reinstates the original value of $.connection and returns the signalR object for manual assignment + /// + if ($.connection === signalR) { + $.connection = _connection; + } + return signalR; + }; + + if ($.connection) { + _connection = $.connection; + } + + $.connection = $.signalR = signalR; + +}(window.jQuery, window)); +/* jquery.signalR.transports.common.js */ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +/*global window:false */ +/// + +(function ($, window, undefined) { + + var signalR = $.signalR, + events = $.signalR.events, + changeState = $.signalR.changeState, + startAbortText = "__Start Aborted__", + transportLogic; + + signalR.transports = {}; + + function beat(connection) { + if (connection._.keepAliveData.monitoring) { + checkIfAlive(connection); + } + + // Ensure that we successfully marked active before continuing the heartbeat. + if (transportLogic.markActive(connection)) { + connection._.beatHandle = window.setTimeout(function () { + beat(connection); + }, connection._.beatInterval); + } + } + + function checkIfAlive(connection) { + var keepAliveData = connection._.keepAliveData, + timeElapsed; + + // Only check if we're connected + if (connection.state === signalR.connectionState.connected) { + timeElapsed = new Date().getTime() - connection._.lastMessageAt; + + // Check if the keep alive has completely timed out + if (timeElapsed >= keepAliveData.timeout) { + connection.log("Keep alive timed out. Notifying transport that connection has been lost."); + + // Notify transport that the connection has been lost + connection.transport.lostConnection(connection); + } else if (timeElapsed >= keepAliveData.timeoutWarning) { + // This is to assure that the user only gets a single warning + if (!keepAliveData.userNotified) { + connection.log("Keep alive has been missed, connection may be dead/slow."); + $(connection).triggerHandler(events.onConnectionSlow); + keepAliveData.userNotified = true; + } + } else { + keepAliveData.userNotified = false; + } + } + } + + function getAjaxUrl(connection, path) { + var url = connection.url + path; + + if (connection.transport) { + url += "?transport=" + connection.transport.name; + } + + return transportLogic.prepareQueryString(connection, url); + } + + function InitHandler(connection) { + this.connection = connection; + + this.startRequested = false; + this.startCompleted = false; + this.connectionStopped = false; + } + + InitHandler.prototype = { + start: function (transport, onSuccess, onFallback) { + var that = this, + connection = that.connection, + failCalled = false; + + if (that.startRequested || that.connectionStopped) { + connection.log("WARNING! " + transport.name + " transport cannot be started. Initialization ongoing or completed."); + return; + } + + connection.log(transport.name + " transport starting."); + + transport.start(connection, function () { + if (!failCalled) { + that.initReceived(transport, onSuccess); + } + }, function (error) { + // Don't allow the same transport to cause onFallback to be called twice + if (!failCalled) { + failCalled = true; + that.transportFailed(transport, error, onFallback); + } + + // Returns true if the transport should stop; + // false if it should attempt to reconnect + return !that.startCompleted || that.connectionStopped; + }); + + that.transportTimeoutHandle = window.setTimeout(function () { + if (!failCalled) { + failCalled = true; + connection.log(transport.name + " transport timed out when trying to connect."); + that.transportFailed(transport, undefined, onFallback); + } + }, connection._.totalTransportConnectTimeout); + }, + + stop: function () { + this.connectionStopped = true; + window.clearTimeout(this.transportTimeoutHandle); + signalR.transports._logic.tryAbortStartRequest(this.connection); + }, + + initReceived: function (transport, onSuccess) { + var that = this, + connection = that.connection; + + if (that.startRequested) { + connection.log("WARNING! The client received multiple init messages."); + return; + } + + if (that.connectionStopped) { + return; + } + + that.startRequested = true; + window.clearTimeout(that.transportTimeoutHandle); + + connection.log(transport.name + " transport connected. Initiating start request."); + signalR.transports._logic.ajaxStart(connection, function () { + that.startCompleted = true; + onSuccess(); + }); + }, + + transportFailed: function (transport, error, onFallback) { + var connection = this.connection, + deferred = connection._deferral, + wrappedError; + + if (this.connectionStopped) { + return; + } + + window.clearTimeout(this.transportTimeoutHandle); + + if (!this.startRequested) { + transport.stop(connection); + + connection.log(transport.name + " transport failed to connect. Attempting to fall back."); + onFallback(); + } else if (!this.startCompleted) { + // Do not attempt to fall back if a start request is ongoing during a transport failure. + // Instead, trigger an error and stop the connection. + wrappedError = signalR._.error(signalR.resources.errorDuringStartRequest, error); + + connection.log(transport.name + " transport failed during the start request. Stopping the connection."); + $(connection).triggerHandler(events.onError, [wrappedError]); + if (deferred) { + deferred.reject(wrappedError); + } + + connection.stop(); + } else { + // The start request has completed, but the connection has not stopped. + // No need to do anything here. The transport should attempt its normal reconnect logic. + } + } + }; + + transportLogic = signalR.transports._logic = { + ajax: function (connection, options) { + return $.ajax( + $.extend(/*deep copy*/ true, {}, $.signalR.ajaxDefaults, { + type: "GET", + data: {}, + xhrFields: { withCredentials: connection.withCredentials }, + contentType: connection.contentType, + dataType: connection.ajaxDataType + }, options)); + }, + + pingServer: function (connection) { + /// Pings the server + /// Connection associated with the server ping + /// + var url, + xhr, + deferral = $.Deferred(); + + if (connection.transport) { + url = connection.url + "/ping"; + + url = transportLogic.addQs(url, connection.qs); + + xhr = transportLogic.ajax(connection, { + url: url, + success: function (result) { + var data; + + try { + data = connection._parseResponse(result); + } + catch (error) { + deferral.reject( + signalR._.transportError( + signalR.resources.pingServerFailedParse, + connection.transport, + error, + xhr + ) + ); + connection.stop(); + return; + } + + if (data.Response === "pong") { + deferral.resolve(); + } + else { + deferral.reject( + signalR._.transportError( + signalR._.format(signalR.resources.pingServerFailedInvalidResponse, result), + connection.transport, + null /* error */, + xhr + ) + ); + } + }, + error: function (error) { + if (error.status === 401 || error.status === 403) { + deferral.reject( + signalR._.transportError( + signalR._.format(signalR.resources.pingServerFailedStatusCode, error.status), + connection.transport, + error, + xhr + ) + ); + connection.stop(); + } + else { + deferral.reject( + signalR._.transportError( + signalR.resources.pingServerFailed, + connection.transport, + error, + xhr + ) + ); + } + } + }); + } + else { + deferral.reject( + signalR._.transportError( + signalR.resources.noConnectionTransport, + connection.transport + ) + ); + } + + return deferral.promise(); + }, + + prepareQueryString: function (connection, url) { + var preparedUrl; + + // Use addQs to start since it handles the ?/& prefix for us + preparedUrl = transportLogic.addQs(url, "clientProtocol=" + connection.clientProtocol); + + // Add the user-specified query string params if any + preparedUrl = transportLogic.addQs(preparedUrl, connection.qs); + + if (connection.token) { + preparedUrl += "&connectionToken=" + window.encodeURIComponent(connection.token); + } + + if (connection.data) { + preparedUrl += "&connectionData=" + window.encodeURIComponent(connection.data); + } + + return preparedUrl; + }, + + addQs: function (url, qs) { + var appender = url.indexOf("?") !== -1 ? "&" : "?", + firstChar; + + if (!qs) { + return url; + } + + if (typeof (qs) === "object") { + return url + appender + $.param(qs); + } + + if (typeof (qs) === "string") { + firstChar = qs.charAt(0); + + if (firstChar === "?" || firstChar === "&") { + appender = ""; + } + + return url + appender + qs; + } + + throw new Error("Query string property must be either a string or object."); + }, + + // BUG #2953: The url needs to be same otherwise it will cause a memory leak + getUrl: function (connection, transport, reconnecting, poll, ajaxPost) { + /// Gets the url for making a GET based connect request + var baseUrl = transport === "webSockets" ? "" : connection.baseUrl, + url = baseUrl + connection.appRelativeUrl, + qs = "transport=" + transport; + + if (!ajaxPost && connection.groupsToken) { + qs += "&groupsToken=" + window.encodeURIComponent(connection.groupsToken); + } + + if (!reconnecting) { + url += "/connect"; + } else { + if (poll) { + // longPolling transport specific + url += "/poll"; + } else { + url += "/reconnect"; + } + + if (!ajaxPost && connection.messageId) { + qs += "&messageId=" + window.encodeURIComponent(connection.messageId); + } + } + url += "?" + qs; + url = transportLogic.prepareQueryString(connection, url); + + if (!ajaxPost) { + url += "&tid=" + Math.floor(Math.random() * 11); + } + + return url; + }, + + maximizePersistentResponse: function (minPersistentResponse) { + return { + MessageId: minPersistentResponse.C, + Messages: minPersistentResponse.M, + Initialized: typeof (minPersistentResponse.S) !== "undefined" ? true : false, + ShouldReconnect: typeof (minPersistentResponse.T) !== "undefined" ? true : false, + LongPollDelay: minPersistentResponse.L, + GroupsToken: minPersistentResponse.G + }; + }, + + updateGroups: function (connection, groupsToken) { + if (groupsToken) { + connection.groupsToken = groupsToken; + } + }, + + stringifySend: function (connection, message) { + if (typeof (message) === "string" || typeof (message) === "undefined" || message === null) { + return message; + } + return connection.json.stringify(message); + }, + + ajaxSend: function (connection, data) { + var payload = transportLogic.stringifySend(connection, data), + url = getAjaxUrl(connection, "/send"), + xhr, + onFail = function (error, connection) { + $(connection).triggerHandler(events.onError, [signalR._.transportError(signalR.resources.sendFailed, connection.transport, error, xhr), data]); + }; + + + xhr = transportLogic.ajax(connection, { + url: url, + type: connection.ajaxDataType === "jsonp" ? "GET" : "POST", + contentType: signalR._.defaultContentType, + data: { + data: payload + }, + success: function (result) { + var res; + + if (result) { + try { + res = connection._parseResponse(result); + } + catch (error) { + onFail(error, connection); + connection.stop(); + return; + } + + transportLogic.triggerReceived(connection, res); + } + }, + error: function (error, textStatus) { + if (textStatus === "abort" || textStatus === "parsererror") { + // The parsererror happens for sends that don't return any data, and hence + // don't write the jsonp callback to the response. This is harder to fix on the server + // so just hack around it on the client for now. + return; + } + + onFail(error, connection); + } + }); + + return xhr; + }, + + ajaxAbort: function (connection, async) { + if (typeof (connection.transport) === "undefined") { + return; + } + + // Async by default unless explicitly overidden + async = typeof async === "undefined" ? true : async; + + var url = getAjaxUrl(connection, "/abort"); + + transportLogic.ajax(connection, { + url: url, + async: async, + timeout: 1000, + type: "POST" + }); + + connection.log("Fired ajax abort async = " + async + "."); + }, + + ajaxStart: function (connection, onSuccess) { + var rejectDeferred = function (error) { + var deferred = connection._deferral; + if (deferred) { + deferred.reject(error); + } + }, + triggerStartError = function (error) { + connection.log("The start request failed. Stopping the connection."); + $(connection).triggerHandler(events.onError, [error]); + rejectDeferred(error); + connection.stop(); + }; + + connection._.startRequest = transportLogic.ajax(connection, { + url: getAjaxUrl(connection, "/start"), + success: function (result, statusText, xhr) { + var data; + + try { + data = connection._parseResponse(result); + } catch (error) { + triggerStartError(signalR._.error( + signalR._.format(signalR.resources.errorParsingStartResponse, result), + error, xhr)); + return; + } + + if (data.Response === "started") { + onSuccess(); + } else { + triggerStartError(signalR._.error( + signalR._.format(signalR.resources.invalidStartResponse, result), + null /* error */, xhr)); + } + }, + error: function (xhr, statusText, error) { + if (statusText !== startAbortText) { + triggerStartError(signalR._.error( + signalR.resources.errorDuringStartRequest, + error, xhr)); + } else { + // Stop has been called, no need to trigger the error handler + // or stop the connection again with onStartError + connection.log("The start request aborted because connection.stop() was called."); + rejectDeferred(signalR._.error( + signalR.resources.stoppedDuringStartRequest, + null /* error */, xhr)); + } + } + }); + }, + + tryAbortStartRequest: function (connection) { + if (connection._.startRequest) { + // If the start request has already completed this will noop. + connection._.startRequest.abort(startAbortText); + delete connection._.startRequest; + } + }, + + tryInitialize: function (connection, persistentResponse, onInitialized) { + if (persistentResponse.Initialized && onInitialized) { + onInitialized(); + } else if (persistentResponse.Initialized) { + connection.log("WARNING! The client received an init message after reconnecting."); + } + + }, + + triggerReceived: function (connection, data) { + if (!connection._.connectingMessageBuffer.tryBuffer(data)) { + $(connection).triggerHandler(events.onReceived, [data]); + } + }, + + processMessages: function (connection, minData, onInitialized) { + var data; + + // Update the last message time stamp + transportLogic.markLastMessage(connection); + + if (minData) { + data = transportLogic.maximizePersistentResponse(minData); + + transportLogic.updateGroups(connection, data.GroupsToken); + + if (data.MessageId) { + connection.messageId = data.MessageId; + } + + if (data.Messages) { + $.each(data.Messages, function (index, message) { + transportLogic.triggerReceived(connection, message); + }); + + transportLogic.tryInitialize(connection, data, onInitialized); + } + } + }, + + monitorKeepAlive: function (connection) { + var keepAliveData = connection._.keepAliveData; + + // If we haven't initiated the keep alive timeouts then we need to + if (!keepAliveData.monitoring) { + keepAliveData.monitoring = true; + + transportLogic.markLastMessage(connection); + + // Save the function so we can unbind it on stop + connection._.keepAliveData.reconnectKeepAliveUpdate = function () { + // Mark a new message so that keep alive doesn't time out connections + transportLogic.markLastMessage(connection); + }; + + // Update Keep alive on reconnect + $(connection).bind(events.onReconnect, connection._.keepAliveData.reconnectKeepAliveUpdate); + + connection.log("Now monitoring keep alive with a warning timeout of " + keepAliveData.timeoutWarning + ", keep alive timeout of " + keepAliveData.timeout + " and disconnecting timeout of " + connection.disconnectTimeout); + } else { + connection.log("Tried to monitor keep alive but it's already being monitored."); + } + }, + + stopMonitoringKeepAlive: function (connection) { + var keepAliveData = connection._.keepAliveData; + + // Only attempt to stop the keep alive monitoring if its being monitored + if (keepAliveData.monitoring) { + // Stop monitoring + keepAliveData.monitoring = false; + + // Remove the updateKeepAlive function from the reconnect event + $(connection).unbind(events.onReconnect, connection._.keepAliveData.reconnectKeepAliveUpdate); + + // Clear all the keep alive data + connection._.keepAliveData = {}; + connection.log("Stopping the monitoring of the keep alive."); + } + }, + + startHeartbeat: function (connection) { + connection._.lastActiveAt = new Date().getTime(); + beat(connection); + }, + + markLastMessage: function (connection) { + connection._.lastMessageAt = new Date().getTime(); + }, + + markActive: function (connection) { + if (transportLogic.verifyLastActive(connection)) { + connection._.lastActiveAt = new Date().getTime(); + return true; + } + + return false; + }, + + isConnectedOrReconnecting: function (connection) { + return connection.state === signalR.connectionState.connected || + connection.state === signalR.connectionState.reconnecting; + }, + + ensureReconnectingState: function (connection) { + if (changeState(connection, + signalR.connectionState.connected, + signalR.connectionState.reconnecting) === true) { + $(connection).triggerHandler(events.onReconnecting); + } + return connection.state === signalR.connectionState.reconnecting; + }, + + clearReconnectTimeout: function (connection) { + if (connection && connection._.reconnectTimeout) { + window.clearTimeout(connection._.reconnectTimeout); + delete connection._.reconnectTimeout; + } + }, + + verifyLastActive: function (connection) { + if (new Date().getTime() - connection._.lastActiveAt >= connection.reconnectWindow) { + var message = signalR._.format(signalR.resources.reconnectWindowTimeout, new Date(connection._.lastActiveAt), connection.reconnectWindow); + connection.log(message); + $(connection).triggerHandler(events.onError, [signalR._.error(message, /* source */ "TimeoutException")]); + connection.stop(/* async */ false, /* notifyServer */ false); + return false; + } + + return true; + }, + + reconnect: function (connection, transportName) { + var transport = signalR.transports[transportName]; + + // We should only set a reconnectTimeout if we are currently connected + // and a reconnectTimeout isn't already set. + if (transportLogic.isConnectedOrReconnecting(connection) && !connection._.reconnectTimeout) { + // Need to verify before the setTimeout occurs because an application sleep could occur during the setTimeout duration. + if (!transportLogic.verifyLastActive(connection)) { + return; + } + + connection._.reconnectTimeout = window.setTimeout(function () { + if (!transportLogic.verifyLastActive(connection)) { + return; + } + + transport.stop(connection); + + if (transportLogic.ensureReconnectingState(connection)) { + connection.log(transportName + " reconnecting."); + transport.start(connection); + } + }, connection.reconnectDelay); + } + }, + + handleParseFailure: function (connection, result, error, onFailed, context) { + var wrappedError = signalR._.transportError( + signalR._.format(signalR.resources.parseFailed, result), + connection.transport, + error, + context); + + // If we're in the initialization phase trigger onFailed, otherwise stop the connection. + if (onFailed && onFailed(wrappedError)) { + connection.log("Failed to parse server response while attempting to connect."); + } else { + $(connection).triggerHandler(events.onError, [wrappedError]); + connection.stop(); + } + }, + + initHandler: function (connection) { + return new InitHandler(connection); + }, + + foreverFrame: { + count: 0, + connections: {} + } + }; + +}(window.jQuery, window)); +/* jquery.signalR.transports.webSockets.js */ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + + +/*global window:false */ +/// + +(function ($, window, undefined) { + + var signalR = $.signalR, + events = $.signalR.events, + changeState = $.signalR.changeState, + transportLogic = signalR.transports._logic; + + signalR.transports.webSockets = { + name: "webSockets", + + supportsKeepAlive: function () { + return true; + }, + + send: function (connection, data) { + var payload = transportLogic.stringifySend(connection, data); + + try { + connection.socket.send(payload); + } catch (ex) { + $(connection).triggerHandler(events.onError, + [signalR._.transportError( + signalR.resources.webSocketsInvalidState, + connection.transport, + ex, + connection.socket + ), + data]); + } + }, + + start: function (connection, onSuccess, onFailed) { + var url, + opened = false, + that = this, + reconnecting = !onSuccess, + $connection = $(connection); + + if (!window.WebSocket) { + onFailed(); + return; + } + + if (!connection.socket) { + if (connection.webSocketServerUrl) { + url = connection.webSocketServerUrl; + } else { + url = connection.wsProtocol + connection.host; + } + + url += transportLogic.getUrl(connection, this.name, reconnecting); + + connection.log("Connecting to websocket endpoint '" + url + "'."); + connection.socket = new window.WebSocket(url); + + connection.socket.onopen = function () { + opened = true; + connection.log("Websocket opened."); + + transportLogic.clearReconnectTimeout(connection); + + if (changeState(connection, + signalR.connectionState.reconnecting, + signalR.connectionState.connected) === true) { + $connection.triggerHandler(events.onReconnect); + } + }; + + connection.socket.onclose = function (event) { + var error; + + // Only handle a socket close if the close is from the current socket. + // Sometimes on disconnect the server will push down an onclose event + // to an expired socket. + + if (this === connection.socket) { + if (opened && typeof event.wasClean !== "undefined" && event.wasClean === false) { + // Ideally this would use the websocket.onerror handler (rather than checking wasClean in onclose) but + // I found in some circumstances Chrome won't call onerror. This implementation seems to work on all browsers. + error = signalR._.transportError( + signalR.resources.webSocketClosed, + connection.transport, + event); + + connection.log("Unclean disconnect from websocket: " + (event.reason || "[no reason given].")); + } else { + connection.log("Websocket closed."); + } + + if (!onFailed || !onFailed(error)) { + if (error) { + $(connection).triggerHandler(events.onError, [error]); + } + + that.reconnect(connection); + } + } + }; + + connection.socket.onmessage = function (event) { + var data; + + try { + data = connection._parseResponse(event.data); + } + catch (error) { + transportLogic.handleParseFailure(connection, event.data, error, onFailed, event); + return; + } + + if (data) { + // data.M is PersistentResponse.Messages + if ($.isEmptyObject(data) || data.M) { + transportLogic.processMessages(connection, data, onSuccess); + } else { + // For websockets we need to trigger onReceived + // for callbacks to outgoing hub calls. + transportLogic.triggerReceived(connection, data); + } + } + }; + } + }, + + reconnect: function (connection) { + transportLogic.reconnect(connection, this.name); + }, + + lostConnection: function (connection) { + this.reconnect(connection); + }, + + stop: function (connection) { + // Don't trigger a reconnect after stopping + transportLogic.clearReconnectTimeout(connection); + + if (connection.socket) { + connection.log("Closing the Websocket."); + connection.socket.close(); + connection.socket = null; + } + }, + + abort: function (connection, async) { + transportLogic.ajaxAbort(connection, async); + } + }; + +}(window.jQuery, window)); +/* jquery.signalR.transports.serverSentEvents.js */ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + + +/*global window:false */ +/// + +(function ($, window, undefined) { + + var signalR = $.signalR, + events = $.signalR.events, + changeState = $.signalR.changeState, + transportLogic = signalR.transports._logic, + clearReconnectAttemptTimeout = function (connection) { + window.clearTimeout(connection._.reconnectAttemptTimeoutHandle); + delete connection._.reconnectAttemptTimeoutHandle; + }; + + signalR.transports.serverSentEvents = { + name: "serverSentEvents", + + supportsKeepAlive: function () { + return true; + }, + + timeOut: 3000, + + start: function (connection, onSuccess, onFailed) { + var that = this, + opened = false, + $connection = $(connection), + reconnecting = !onSuccess, + url; + + if (connection.eventSource) { + connection.log("The connection already has an event source. Stopping it."); + connection.stop(); + } + + if (!window.EventSource) { + if (onFailed) { + connection.log("This browser doesn't support SSE."); + onFailed(); + } + return; + } + + url = transportLogic.getUrl(connection, this.name, reconnecting); + + try { + connection.log("Attempting to connect to SSE endpoint '" + url + "'."); + connection.eventSource = new window.EventSource(url, { withCredentials: connection.withCredentials }); + } + catch (e) { + connection.log("EventSource failed trying to connect with error " + e.Message + "."); + if (onFailed) { + // The connection failed, call the failed callback + onFailed(); + } else { + $connection.triggerHandler(events.onError, [signalR._.transportError(signalR.resources.eventSourceFailedToConnect, connection.transport, e)]); + if (reconnecting) { + // If we were reconnecting, rather than doing initial connect, then try reconnect again + that.reconnect(connection); + } + } + return; + } + + if (reconnecting) { + connection._.reconnectAttemptTimeoutHandle = window.setTimeout(function () { + if (opened === false) { + // If we're reconnecting and the event source is attempting to connect, + // don't keep retrying. This causes duplicate connections to spawn. + if (connection.eventSource.readyState !== window.EventSource.OPEN) { + // If we were reconnecting, rather than doing initial connect, then try reconnect again + that.reconnect(connection); + } + } + }, + that.timeOut); + } + + connection.eventSource.addEventListener("open", function (e) { + connection.log("EventSource connected."); + + clearReconnectAttemptTimeout(connection); + transportLogic.clearReconnectTimeout(connection); + + if (opened === false) { + opened = true; + + if (changeState(connection, + signalR.connectionState.reconnecting, + signalR.connectionState.connected) === true) { + $connection.triggerHandler(events.onReconnect); + } + } + }, false); + + connection.eventSource.addEventListener("message", function (e) { + var res; + + // process messages + if (e.data === "initialized") { + return; + } + + try { + res = connection._parseResponse(e.data); + } + catch (error) { + transportLogic.handleParseFailure(connection, e.data, error, onFailed, e); + return; + } + + transportLogic.processMessages(connection, res, onSuccess); + }, false); + + connection.eventSource.addEventListener("error", function (e) { + var error = signalR._.transportError( + signalR.resources.eventSourceError, + connection.transport, + e); + + // Only handle an error if the error is from the current Event Source. + // Sometimes on disconnect the server will push down an error event + // to an expired Event Source. + if (this !== connection.eventSource) { + return; + } + + if (onFailed && onFailed(error)) { + return; + } + + connection.log("EventSource readyState: " + connection.eventSource.readyState + "."); + + if (e.eventPhase === window.EventSource.CLOSED) { + // We don't use the EventSource's native reconnect function as it + // doesn't allow us to change the URL when reconnecting. We need + // to change the URL to not include the /connect suffix, and pass + // the last message id we received. + connection.log("EventSource reconnecting due to the server connection ending."); + that.reconnect(connection); + } else { + // connection error + connection.log("EventSource error."); + $connection.triggerHandler(events.onError, [error]); + } + }, false); + }, + + reconnect: function (connection) { + transportLogic.reconnect(connection, this.name); + }, + + lostConnection: function (connection) { + this.reconnect(connection); + }, + + send: function (connection, data) { + transportLogic.ajaxSend(connection, data); + }, + + stop: function (connection) { + // Don't trigger a reconnect after stopping + clearReconnectAttemptTimeout(connection); + transportLogic.clearReconnectTimeout(connection); + + if (connection && connection.eventSource) { + connection.log("EventSource calling close()."); + connection.eventSource.close(); + connection.eventSource = null; + delete connection.eventSource; + } + }, + + abort: function (connection, async) { + transportLogic.ajaxAbort(connection, async); + } + }; + +}(window.jQuery, window)); +/* jquery.signalR.transports.foreverFrame.js */ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + + +/*global window:false */ +/// + +(function ($, window, undefined) { + + var signalR = $.signalR, + events = $.signalR.events, + changeState = $.signalR.changeState, + transportLogic = signalR.transports._logic, + createFrame = function () { + var frame = window.document.createElement("iframe"); + frame.setAttribute("style", "position:absolute;top:0;left:0;width:0;height:0;visibility:hidden;"); + return frame; + }, + // Used to prevent infinite loading icon spins in older versions of ie + // We build this object inside a closure so we don't pollute the rest of + // the foreverFrame transport with unnecessary functions/utilities. + loadPreventer = (function () { + var loadingFixIntervalId = null, + loadingFixInterval = 1000, + attachedTo = 0; + + return { + prevent: function () { + // Prevent additional iframe removal procedures from newer browsers + if (signalR._.ieVersion <= 8) { + // We only ever want to set the interval one time, so on the first attachedTo + if (attachedTo === 0) { + // Create and destroy iframe every 3 seconds to prevent loading icon, super hacky + loadingFixIntervalId = window.setInterval(function () { + var tempFrame = createFrame(); + + window.document.body.appendChild(tempFrame); + window.document.body.removeChild(tempFrame); + + tempFrame = null; + }, loadingFixInterval); + } + + attachedTo++; + } + }, + cancel: function () { + // Only clear the interval if there's only one more object that the loadPreventer is attachedTo + if (attachedTo === 1) { + window.clearInterval(loadingFixIntervalId); + } + + if (attachedTo > 0) { + attachedTo--; + } + } + }; + })(); + + signalR.transports.foreverFrame = { + name: "foreverFrame", + + supportsKeepAlive: function () { + return true; + }, + + // Added as a value here so we can create tests to verify functionality + iframeClearThreshold: 50, + + start: function (connection, onSuccess, onFailed) { + var that = this, + frameId = (transportLogic.foreverFrame.count += 1), + url, + frame = createFrame(), + frameLoadHandler = function () { + connection.log("Forever frame iframe finished loading and is no longer receiving messages."); + if (!onFailed || !onFailed()) { + that.reconnect(connection); + } + }; + + if (window.EventSource) { + // If the browser supports SSE, don't use Forever Frame + if (onFailed) { + connection.log("Forever Frame is not supported by SignalR on browsers with SSE support."); + onFailed(); + } + return; + } + + frame.setAttribute("data-signalr-connection-id", connection.id); + + // Start preventing loading icon + // This will only perform work if the loadPreventer is not attached to another connection. + loadPreventer.prevent(); + + // Build the url + url = transportLogic.getUrl(connection, this.name); + url += "&frameId=" + frameId; + + // add frame to the document prior to setting URL to avoid caching issues. + window.document.documentElement.appendChild(frame); + + connection.log("Binding to iframe's load event."); + + if (frame.addEventListener) { + frame.addEventListener("load", frameLoadHandler, false); + } else if (frame.attachEvent) { + frame.attachEvent("onload", frameLoadHandler); + } + + frame.src = url; + transportLogic.foreverFrame.connections[frameId] = connection; + + connection.frame = frame; + connection.frameId = frameId; + + if (onSuccess) { + connection.onSuccess = function () { + connection.log("Iframe transport started."); + onSuccess(); + }; + } + }, + + reconnect: function (connection) { + var that = this; + + // Need to verify connection state and verify before the setTimeout occurs because an application sleep could occur during the setTimeout duration. + if (transportLogic.isConnectedOrReconnecting(connection) && transportLogic.verifyLastActive(connection)) { + window.setTimeout(function () { + // Verify that we're ok to reconnect. + if (!transportLogic.verifyLastActive(connection)) { + return; + } + + if (connection.frame && transportLogic.ensureReconnectingState(connection)) { + var frame = connection.frame, + src = transportLogic.getUrl(connection, that.name, true) + "&frameId=" + connection.frameId; + connection.log("Updating iframe src to '" + src + "'."); + frame.src = src; + } + }, connection.reconnectDelay); + } + }, + + lostConnection: function (connection) { + this.reconnect(connection); + }, + + send: function (connection, data) { + transportLogic.ajaxSend(connection, data); + }, + + receive: function (connection, data) { + var cw, + body, + response; + + if (connection.json !== connection._originalJson) { + // If there's a custom JSON parser configured then serialize the object + // using the original (browser) JSON parser and then deserialize it using + // the custom parser (connection._parseResponse does that). This is so we + // can easily send the response from the server as "raw" JSON but still + // support custom JSON deserialization in the browser. + data = connection._originalJson.stringify(data); + } + + response = connection._parseResponse(data); + + transportLogic.processMessages(connection, response, connection.onSuccess); + + // Protect against connection stopping from a callback trigger within the processMessages above. + if (connection.state === $.signalR.connectionState.connected) { + // Delete the script & div elements + connection.frameMessageCount = (connection.frameMessageCount || 0) + 1; + if (connection.frameMessageCount > signalR.transports.foreverFrame.iframeClearThreshold) { + connection.frameMessageCount = 0; + cw = connection.frame.contentWindow || connection.frame.contentDocument; + if (cw && cw.document && cw.document.body) { + body = cw.document.body; + + // Remove all the child elements from the iframe's body to conserver memory + while (body.firstChild) { + body.removeChild(body.firstChild); + } + } + } + } + }, + + stop: function (connection) { + var cw = null; + + // Stop attempting to prevent loading icon + loadPreventer.cancel(); + + if (connection.frame) { + if (connection.frame.stop) { + connection.frame.stop(); + } else { + try { + cw = connection.frame.contentWindow || connection.frame.contentDocument; + if (cw.document && cw.document.execCommand) { + cw.document.execCommand("Stop"); + } + } + catch (e) { + connection.log("Error occurred when stopping foreverFrame transport. Message = " + e.message + "."); + } + } + + // Ensure the iframe is where we left it + if (connection.frame.parentNode === window.document.body) { + window.document.body.removeChild(connection.frame); + } + + delete transportLogic.foreverFrame.connections[connection.frameId]; + connection.frame = null; + connection.frameId = null; + delete connection.frame; + delete connection.frameId; + delete connection.onSuccess; + delete connection.frameMessageCount; + connection.log("Stopping forever frame."); + } + }, + + abort: function (connection, async) { + transportLogic.ajaxAbort(connection, async); + }, + + getConnection: function (id) { + return transportLogic.foreverFrame.connections[id]; + }, + + started: function (connection) { + if (changeState(connection, + signalR.connectionState.reconnecting, + signalR.connectionState.connected) === true) { + + $(connection).triggerHandler(events.onReconnect); + } + } + }; + +}(window.jQuery, window)); +/* jquery.signalR.transports.longPolling.js */ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + + +/*global window:false */ +/// + +(function ($, window, undefined) { + + var signalR = $.signalR, + events = $.signalR.events, + changeState = $.signalR.changeState, + isDisconnecting = $.signalR.isDisconnecting, + transportLogic = signalR.transports._logic; + + signalR.transports.longPolling = { + name: "longPolling", + + supportsKeepAlive: function () { + return false; + }, + + reconnectDelay: 3000, + + start: function (connection, onSuccess, onFailed) { + /// Starts the long polling connection + /// The SignalR connection to start + var that = this, + fireConnect = function () { + fireConnect = $.noop; + + connection.log("LongPolling connected."); + + if (onSuccess) { + onSuccess(); + } else { + connection.log("WARNING! The client received an init message after reconnecting."); + } + }, + tryFailConnect = function (error) { + if (onFailed(error)) { + connection.log("LongPolling failed to connect."); + return true; + } + + return false; + }, + privateData = connection._, + reconnectErrors = 0, + fireReconnected = function (instance) { + window.clearTimeout(privateData.reconnectTimeoutId); + privateData.reconnectTimeoutId = null; + + if (changeState(instance, + signalR.connectionState.reconnecting, + signalR.connectionState.connected) === true) { + // Successfully reconnected! + instance.log("Raising the reconnect event"); + $(instance).triggerHandler(events.onReconnect); + } + }, + // 1 hour + maxFireReconnectedTimeout = 3600000; + + if (connection.pollXhr) { + connection.log("Polling xhr requests already exists, aborting."); + connection.stop(); + } + + connection.messageId = null; + + privateData.reconnectTimeoutId = null; + + privateData.pollTimeoutId = window.setTimeout(function () { + (function poll(instance, raiseReconnect) { + var messageId = instance.messageId, + connect = (messageId === null), + reconnecting = !connect, + polling = !raiseReconnect, + url = transportLogic.getUrl(instance, that.name, reconnecting, polling, true /* use Post for longPolling */), + postData = {}; + + if (instance.messageId) { + postData.messageId = instance.messageId; + } + + if (instance.groupsToken) { + postData.groupsToken = instance.groupsToken; + } + + // If we've disconnected during the time we've tried to re-instantiate the poll then stop. + if (isDisconnecting(instance) === true) { + return; + } + + connection.log("Opening long polling request to '" + url + "'."); + instance.pollXhr = transportLogic.ajax(connection, { + xhrFields: { + onprogress: function () { + transportLogic.markLastMessage(connection); + } + }, + url: url, + type: "POST", + contentType: signalR._.defaultContentType, + data: postData, + timeout: connection._.pollTimeout, + success: function (result) { + var minData, + delay = 0, + data, + shouldReconnect; + + connection.log("Long poll complete."); + + // Reset our reconnect errors so if we transition into a reconnecting state again we trigger + // reconnected quickly + reconnectErrors = 0; + + try { + // Remove any keep-alives from the beginning of the result + minData = connection._parseResponse(result); + } + catch (error) { + transportLogic.handleParseFailure(instance, result, error, tryFailConnect, instance.pollXhr); + return; + } + + // If there's currently a timeout to trigger reconnect, fire it now before processing messages + if (privateData.reconnectTimeoutId !== null) { + fireReconnected(instance); + } + + if (minData) { + data = transportLogic.maximizePersistentResponse(minData); + } + + transportLogic.processMessages(instance, minData, fireConnect); + + if (data && + $.type(data.LongPollDelay) === "number") { + delay = data.LongPollDelay; + } + + if (isDisconnecting(instance) === true) { + return; + } + + shouldReconnect = data && data.ShouldReconnect; + if (shouldReconnect) { + // Transition into the reconnecting state + // If this fails then that means that the user transitioned the connection into a invalid state in processMessages. + if (!transportLogic.ensureReconnectingState(instance)) { + return; + } + } + + // We never want to pass a raiseReconnect flag after a successful poll. This is handled via the error function + if (delay > 0) { + privateData.pollTimeoutId = window.setTimeout(function () { + poll(instance, shouldReconnect); + }, delay); + } else { + poll(instance, shouldReconnect); + } + }, + + error: function (data, textStatus) { + var error = signalR._.transportError(signalR.resources.longPollFailed, connection.transport, data, instance.pollXhr); + + // Stop trying to trigger reconnect, connection is in an error state + // If we're not in the reconnect state this will noop + window.clearTimeout(privateData.reconnectTimeoutId); + privateData.reconnectTimeoutId = null; + + if (textStatus === "abort") { + connection.log("Aborted xhr request."); + return; + } + + if (!tryFailConnect(error)) { + + // Increment our reconnect errors, we assume all errors to be reconnect errors + // In the case that it's our first error this will cause Reconnect to be fired + // after 1 second due to reconnectErrors being = 1. + reconnectErrors++; + + if (connection.state !== signalR.connectionState.reconnecting) { + connection.log("An error occurred using longPolling. Status = " + textStatus + ". Response = " + data.responseText + "."); + $(instance).triggerHandler(events.onError, [error]); + } + + // We check the state here to verify that we're not in an invalid state prior to verifying Reconnect. + // If we're not in connected or reconnecting then the next ensureReconnectingState check will fail and will return. + // Therefore we don't want to change that failure code path. + if ((connection.state === signalR.connectionState.connected || + connection.state === signalR.connectionState.reconnecting) && + !transportLogic.verifyLastActive(connection)) { + return; + } + + // Transition into the reconnecting state + // If this fails then that means that the user transitioned the connection into the disconnected or connecting state within the above error handler trigger. + if (!transportLogic.ensureReconnectingState(instance)) { + return; + } + + // Call poll with the raiseReconnect flag as true after the reconnect delay + privateData.pollTimeoutId = window.setTimeout(function () { + poll(instance, true); + }, that.reconnectDelay); + } + } + }); + + // This will only ever pass after an error has occurred via the poll ajax procedure. + if (reconnecting && raiseReconnect === true) { + // We wait to reconnect depending on how many times we've failed to reconnect. + // This is essentially a heuristic that will exponentially increase in wait time before + // triggering reconnected. This depends on the "error" handler of Poll to cancel this + // timeout if it triggers before the Reconnected event fires. + // The Math.min at the end is to ensure that the reconnect timeout does not overflow. + privateData.reconnectTimeoutId = window.setTimeout(function () { fireReconnected(instance); }, Math.min(1000 * (Math.pow(2, reconnectErrors) - 1), maxFireReconnectedTimeout)); + } + }(connection)); + }, 250); // Have to delay initial poll so Chrome doesn't show loader spinner in tab + }, + + lostConnection: function (connection) { + if (connection.pollXhr) { + connection.pollXhr.abort("lostConnection"); + } + }, + + send: function (connection, data) { + transportLogic.ajaxSend(connection, data); + }, + + stop: function (connection) { + /// Stops the long polling connection + /// The SignalR connection to stop + + window.clearTimeout(connection._.pollTimeoutId); + window.clearTimeout(connection._.reconnectTimeoutId); + + delete connection._.pollTimeoutId; + delete connection._.reconnectTimeoutId; + + if (connection.pollXhr) { + connection.pollXhr.abort(); + connection.pollXhr = null; + delete connection.pollXhr; + } + }, + + abort: function (connection, async) { + transportLogic.ajaxAbort(connection, async); + } + }; + +}(window.jQuery, window)); +/* jquery.signalR.hubs.js */ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +/*global window:false */ +/// + +(function ($, window, undefined) { + + var eventNamespace = ".hubProxy", + signalR = $.signalR; + + function makeEventName(event) { + return event + eventNamespace; + } + + // Equivalent to Array.prototype.map + function map(arr, fun, thisp) { + var i, + length = arr.length, + result = []; + for (i = 0; i < length; i += 1) { + if (arr.hasOwnProperty(i)) { + result[i] = fun.call(thisp, arr[i], i, arr); + } + } + return result; + } + + function getArgValue(a) { + return $.isFunction(a) ? null : ($.type(a) === "undefined" ? null : a); + } + + function hasMembers(obj) { + for (var key in obj) { + // If we have any properties in our callback map then we have callbacks and can exit the loop via return + if (obj.hasOwnProperty(key)) { + return true; + } + } + + return false; + } + + function clearInvocationCallbacks(connection, error) { + /// + var callbacks = connection._.invocationCallbacks, + callback; + + if (hasMembers(callbacks)) { + connection.log("Clearing hub invocation callbacks with error: " + error + "."); + } + + // Reset the callback cache now as we have a local var referencing it + connection._.invocationCallbackId = 0; + delete connection._.invocationCallbacks; + connection._.invocationCallbacks = {}; + + // Loop over the callbacks and invoke them. + // We do this using a local var reference and *after* we've cleared the cache + // so that if a fail callback itself tries to invoke another method we don't + // end up with its callback in the list we're looping over. + for (var callbackId in callbacks) { + callback = callbacks[callbackId]; + callback.method.call(callback.scope, { E: error }); + } + } + + // hubProxy + function hubProxy(hubConnection, hubName) { + /// + /// Creates a new proxy object for the given hub connection that can be used to invoke + /// methods on server hubs and handle client method invocation requests from the server. + /// + return new hubProxy.fn.init(hubConnection, hubName); + } + + hubProxy.fn = hubProxy.prototype = { + init: function (connection, hubName) { + this.state = {}; + this.connection = connection; + this.hubName = hubName; + this._ = { + callbackMap: {} + }; + }, + + constructor: hubProxy, + + hasSubscriptions: function () { + return hasMembers(this._.callbackMap); + }, + + on: function (eventName, callback) { + /// Wires up a callback to be invoked when a invocation request is received from the server hub. + /// The name of the hub event to register the callback for. + /// The callback to be invoked. + var that = this, + callbackMap = that._.callbackMap; + + // Normalize the event name to lowercase + eventName = eventName.toLowerCase(); + + // If there is not an event registered for this callback yet we want to create its event space in the callback map. + if (!callbackMap[eventName]) { + callbackMap[eventName] = {}; + } + + // Map the callback to our encompassed function + callbackMap[eventName][callback] = function (e, data) { + callback.apply(that, data); + }; + + $(that).bind(makeEventName(eventName), callbackMap[eventName][callback]); + + return that; + }, + + off: function (eventName, callback) { + /// Removes the callback invocation request from the server hub for the given event name. + /// The name of the hub event to unregister the callback for. + /// The callback to be invoked. + var that = this, + callbackMap = that._.callbackMap, + callbackSpace; + + // Normalize the event name to lowercase + eventName = eventName.toLowerCase(); + + callbackSpace = callbackMap[eventName]; + + // Verify that there is an event space to unbind + if (callbackSpace) { + // Only unbind if there's an event bound with eventName and a callback with the specified callback + if (callbackSpace[callback]) { + $(that).unbind(makeEventName(eventName), callbackSpace[callback]); + + // Remove the callback from the callback map + delete callbackSpace[callback]; + + // Check if there are any members left on the event, if not we need to destroy it. + if (!hasMembers(callbackSpace)) { + delete callbackMap[eventName]; + } + } else if (!callback) { // Check if we're removing the whole event and we didn't error because of an invalid callback + $(that).unbind(makeEventName(eventName)); + + delete callbackMap[eventName]; + } + } + + return that; + }, + + invoke: function (methodName) { + /// Invokes a server hub method with the given arguments. + /// The name of the server hub method. + + var that = this, + connection = that.connection, + args = $.makeArray(arguments).slice(1), + argValues = map(args, getArgValue), + data = { H: that.hubName, M: methodName, A: argValues, I: connection._.invocationCallbackId }, + d = $.Deferred(), + callback = function (minResult) { + var result = that._maximizeHubResponse(minResult), + source, + error; + + // Update the hub state + $.extend(that.state, result.State); + + if (result.Progress) { + if (d.notifyWith) { + // Progress is only supported in jQuery 1.7+ + d.notifyWith(that, [result.Progress.Data]); + } else if(!connection._.progressjQueryVersionLogged) { + connection.log("A hub method invocation progress update was received but the version of jQuery in use (" + $.prototype.jquery + ") does not support progress updates. Upgrade to jQuery 1.7+ to receive progress notifications."); + connection._.progressjQueryVersionLogged = true; + } + } else if (result.Error) { + // Server hub method threw an exception, log it & reject the deferred + if (result.StackTrace) { + connection.log(result.Error + "\n" + result.StackTrace + "."); + } + + // result.ErrorData is only set if a HubException was thrown + source = result.IsHubException ? "HubException" : "Exception"; + error = signalR._.error(result.Error, source); + error.data = result.ErrorData; + + connection.log(that.hubName + "." + methodName + " failed to execute. Error: " + error.message); + d.rejectWith(that, [error]); + } else { + // Server invocation succeeded, resolve the deferred + connection.log("Invoked " + that.hubName + "." + methodName); + d.resolveWith(that, [result.Result]); + } + }; + + connection._.invocationCallbacks[connection._.invocationCallbackId.toString()] = { scope: that, method: callback }; + connection._.invocationCallbackId += 1; + + if (!$.isEmptyObject(that.state)) { + data.S = that.state; + } + + connection.log("Invoking " + that.hubName + "." + methodName); + connection.send(data); + + return d.promise(); + }, + + _maximizeHubResponse: function (minHubResponse) { + return { + State: minHubResponse.S, + Result: minHubResponse.R, + Progress: minHubResponse.P ? { + Id: minHubResponse.P.I, + Data: minHubResponse.P.D + } : null, + Id: minHubResponse.I, + IsHubException: minHubResponse.H, + Error: minHubResponse.E, + StackTrace: minHubResponse.T, + ErrorData: minHubResponse.D + }; + } + }; + + hubProxy.fn.init.prototype = hubProxy.fn; + + // hubConnection + function hubConnection(url, options) { + /// Creates a new hub connection. + /// [Optional] The hub route url, defaults to "/signalr". + /// [Optional] Settings to use when creating the hubConnection. + var settings = { + qs: null, + logging: false, + useDefaultPath: true + }; + + $.extend(settings, options); + + if (!url || settings.useDefaultPath) { + url = (url || "") + "/signalr"; + } + return new hubConnection.fn.init(url, settings); + } + + hubConnection.fn = hubConnection.prototype = $.connection(); + + hubConnection.fn.init = function (url, options) { + var settings = { + qs: null, + logging: false, + useDefaultPath: true + }, + connection = this; + + $.extend(settings, options); + + // Call the base constructor + $.signalR.fn.init.call(connection, url, settings.qs, settings.logging); + + // Object to store hub proxies for this connection + connection.proxies = {}; + + connection._.invocationCallbackId = 0; + connection._.invocationCallbacks = {}; + + // Wire up the received handler + connection.received(function (minData) { + var data, proxy, dataCallbackId, callback, hubName, eventName; + if (!minData) { + return; + } + + // We have to handle progress updates first in order to ensure old clients that receive + // progress updates enter the return value branch and then no-op when they can't find + // the callback in the map (because the minData.I value will not be a valid callback ID) + if (typeof (minData.P) !== "undefined") { + // Process progress notification + dataCallbackId = minData.P.I.toString(); + callback = connection._.invocationCallbacks[dataCallbackId]; + if (callback) { + callback.method.call(callback.scope, minData); + } + } else if (typeof (minData.I) !== "undefined") { + // We received the return value from a server method invocation, look up callback by id and call it + dataCallbackId = minData.I.toString(); + callback = connection._.invocationCallbacks[dataCallbackId]; + if (callback) { + // Delete the callback from the proxy + connection._.invocationCallbacks[dataCallbackId] = null; + delete connection._.invocationCallbacks[dataCallbackId]; + + // Invoke the callback + callback.method.call(callback.scope, minData); + } + } else { + data = this._maximizeClientHubInvocation(minData); + + // We received a client invocation request, i.e. broadcast from server hub + connection.log("Triggering client hub event '" + data.Method + "' on hub '" + data.Hub + "'."); + + // Normalize the names to lowercase + hubName = data.Hub.toLowerCase(); + eventName = data.Method.toLowerCase(); + + // Trigger the local invocation event + proxy = this.proxies[hubName]; + + // Update the hub state + $.extend(proxy.state, data.State); + $(proxy).triggerHandler(makeEventName(eventName), [data.Args]); + } + }); + + connection.error(function (errData, origData) { + var callbackId, callback; + + if (!origData) { + // No original data passed so this is not a send error + return; + } + + callbackId = origData.I; + callback = connection._.invocationCallbacks[callbackId]; + + // Verify that there is a callback bound (could have been cleared) + if (callback) { + // Delete the callback + connection._.invocationCallbacks[callbackId] = null; + delete connection._.invocationCallbacks[callbackId]; + + // Invoke the callback with an error to reject the promise + callback.method.call(callback.scope, { E: errData }); + } + }); + + connection.reconnecting(function () { + if (connection.transport && connection.transport.name === "webSockets") { + clearInvocationCallbacks(connection, "Connection started reconnecting before invocation result was received."); + } + }); + + connection.disconnected(function () { + clearInvocationCallbacks(connection, "Connection was disconnected before invocation result was received."); + }); + }; + + hubConnection.fn._maximizeClientHubInvocation = function (minClientHubInvocation) { + return { + Hub: minClientHubInvocation.H, + Method: minClientHubInvocation.M, + Args: minClientHubInvocation.A, + State: minClientHubInvocation.S + }; + }; + + hubConnection.fn._registerSubscribedHubs = function () { + /// + /// Sets the starting event to loop through the known hubs and register any new hubs + /// that have been added to the proxy. + /// + var connection = this; + + if (!connection._subscribedToHubs) { + connection._subscribedToHubs = true; + connection.starting(function () { + // Set the connection's data object with all the hub proxies with active subscriptions. + // These proxies will receive notifications from the server. + var subscribedHubs = []; + + $.each(connection.proxies, function (key) { + if (this.hasSubscriptions()) { + subscribedHubs.push({ name: key }); + connection.log("Client subscribed to hub '" + key + "'."); + } + }); + + if (subscribedHubs.length === 0) { + connection.log("No hubs have been subscribed to. The client will not receive data from hubs. To fix, declare at least one client side function prior to connection start for each hub you wish to subscribe to."); + } + + connection.data = connection.json.stringify(subscribedHubs); + }); + } + }; + + hubConnection.fn.createHubProxy = function (hubName) { + /// + /// Creates a new proxy object for the given hub connection that can be used to invoke + /// methods on server hubs and handle client method invocation requests from the server. + /// + /// + /// The name of the hub on the server to create the proxy for. + /// + + // Normalize the name to lowercase + hubName = hubName.toLowerCase(); + + var proxy = this.proxies[hubName]; + if (!proxy) { + proxy = hubProxy(this, hubName); + this.proxies[hubName] = proxy; + } + + this._registerSubscribedHubs(); + + return proxy; + }; + + hubConnection.fn.init.prototype = hubConnection.fn; + + $.hubConnection = hubConnection; + +}(window.jQuery, window)); +/* jquery.signalR.version.js */ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + + +/*global window:false */ +/// +(function ($, undefined) { + $.signalR.version = "2.2.1"; +}(window.jQuery)); diff --git a/lib/jquery.signalR-2.2.1.min.js b/lib/jquery.signalR-2.2.1.min.js new file mode 100644 index 0000000..54a95f1 --- /dev/null +++ b/lib/jquery.signalR-2.2.1.min.js @@ -0,0 +1,9 @@ +/*! + * ASP.NET SignalR JavaScript Library v2.2.1 + * http://signalr.net/ + * + * Copyright (c) .NET Foundation. All rights reserved. + * Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + * + */ +(function(n,t,i){function w(t,i){var u,f;if(n.isArray(t)){for(u=t.length-1;u>=0;u--)f=t[u],n.type(f)==="string"&&r.transports[f]||(i.log("Invalid transport: "+f+", removing it from the transports list."),t.splice(u,1));t.length===0&&(i.log("No transports remain within the specified transport array."),t=null)}else if(r.transports[t]||t==="auto"){if(t==="auto"&&r._.ieVersion<=8)return["longPolling"]}else i.log("Invalid transport: "+t.toString()+"."),t=null;return t}function b(n){return n==="http:"?80:n==="https:"?443:void 0}function a(n,t){return t.match(/:\d+$/)?t:t+":"+b(n)}function k(t,i){var u=this,r=[];u.tryBuffer=function(i){return t.state===n.signalR.connectionState.connecting?(r.push(i),!0):!1};u.drain=function(){if(t.state===n.signalR.connectionState.connected)while(r.length>0)i(r.shift())};u.clear=function(){r=[]}}var f={nojQuery:"jQuery was not found. Please ensure jQuery is referenced before the SignalR client JavaScript file.",noTransportOnInit:"No transport could be initialized successfully. Try specifying a different transport or none at all for auto initialization.",errorOnNegotiate:"Error during negotiation request.",stoppedWhileLoading:"The connection was stopped during page load.",stoppedWhileNegotiating:"The connection was stopped during the negotiate request.",errorParsingNegotiateResponse:"Error parsing negotiate response.",errorDuringStartRequest:"Error during start request. Stopping the connection.",stoppedDuringStartRequest:"The connection was stopped during the start request.",errorParsingStartResponse:"Error parsing start response: '{0}'. Stopping the connection.",invalidStartResponse:"Invalid start response: '{0}'. Stopping the connection.",protocolIncompatible:"You are using a version of the client that isn't compatible with the server. Client version {0}, server version {1}.",sendFailed:"Send failed.",parseFailed:"Failed at parsing response: {0}",longPollFailed:"Long polling request failed.",eventSourceFailedToConnect:"EventSource failed to connect.",eventSourceError:"Error raised by EventSource",webSocketClosed:"WebSocket closed.",pingServerFailedInvalidResponse:"Invalid ping response when pinging server: '{0}'.",pingServerFailed:"Failed to ping server.",pingServerFailedStatusCode:"Failed to ping server. Server responded with status code {0}, stopping the connection.",pingServerFailedParse:"Failed to parse ping server response, stopping the connection.",noConnectionTransport:"Connection is in an invalid state, there is no transport active.",webSocketsInvalidState:"The Web Socket transport is in an invalid state, transitioning into reconnecting.",reconnectTimeout:"Couldn't reconnect within the configured timeout of {0} ms, disconnecting.",reconnectWindowTimeout:"The client has been inactive since {0} and it has exceeded the inactivity timeout of {1} ms. Stopping the connection."};if(typeof n!="function")throw new Error(f.nojQuery);var r,h,o=t.document.readyState==="complete",e=n(t),c="__Negotiate Aborted__",u={onStart:"onStart",onStarting:"onStarting",onReceived:"onReceived",onError:"onError",onConnectionSlow:"onConnectionSlow",onReconnecting:"onReconnecting",onReconnect:"onReconnect",onStateChanged:"onStateChanged",onDisconnect:"onDisconnect"},v=function(n,i){if(i!==!1){var r;typeof t.console!="undefined"&&(r="["+(new Date).toTimeString()+"] SignalR: "+n,t.console.debug?t.console.debug(r):t.console.log&&t.console.log(r))}},s=function(t,i,r){return i===t.state?(t.state=r,n(t).triggerHandler(u.onStateChanged,[{oldState:i,newState:r}]),!0):!1},y=function(n){return n.state===r.connectionState.disconnected},l=function(n){return n._.keepAliveData.activated&&n.transport.supportsKeepAlive(n)},p=function(i){var f,e;i._.configuredStopReconnectingTimeout||(e=function(t){var i=r._.format(r.resources.reconnectTimeout,t.disconnectTimeout);t.log(i);n(t).triggerHandler(u.onError,[r._.error(i,"TimeoutException")]);t.stop(!1,!1)},i.reconnecting(function(){var n=this;n.state===r.connectionState.reconnecting&&(f=t.setTimeout(function(){e(n)},n.disconnectTimeout))}),i.stateChanged(function(n){n.oldState===r.connectionState.reconnecting&&t.clearTimeout(f)}),i._.configuredStopReconnectingTimeout=!0)};if(r=function(n,t,i){return new r.fn.init(n,t,i)},r._={defaultContentType:"application/x-www-form-urlencoded; charset=UTF-8",ieVersion:function(){var i,n;return t.navigator.appName==="Microsoft Internet Explorer"&&(n=/MSIE ([0-9]+\.[0-9]+)/.exec(t.navigator.userAgent),n&&(i=t.parseFloat(n[1]))),i}(),error:function(n,t,i){var r=new Error(n);return r.source=t,typeof i!="undefined"&&(r.context=i),r},transportError:function(n,t,r,u){var f=this.error(n,r,u);return f.transport=t?t.name:i,f},format:function(){for(var t=arguments[0],n=0;n<\/script>.");}},typeof e.on=="function")e.on("load",function(){o=!0});else e.load(function(){o=!0});r.fn=r.prototype={init:function(t,i,r){var f=n(this);this.url=t;this.qs=i;this.lastError=null;this._={keepAliveData:{},connectingMessageBuffer:new k(this,function(n){f.triggerHandler(u.onReceived,[n])}),lastMessageAt:(new Date).getTime(),lastActiveAt:(new Date).getTime(),beatInterval:5e3,beatHandle:null,totalTransportConnectTimeout:0};typeof r=="boolean"&&(this.logging=r)},_parseResponse:function(n){var t=this;return n?typeof n=="string"?t.json.parse(n):n:n},_originalJson:t.JSON,json:t.JSON,isCrossDomain:function(i,r){var u;return(i=n.trim(i),r=r||t.location,i.indexOf("http")!==0)?!1:(u=t.document.createElement("a"),u.href=i,u.protocol+a(u.protocol,u.host)!==r.protocol+a(r.protocol,r.host))},ajaxDataType:"text",contentType:"application/json; charset=UTF-8",logging:!1,state:r.connectionState.disconnected,clientProtocol:"1.5",reconnectDelay:2e3,transportConnectTimeout:0,disconnectTimeout:3e4,reconnectWindow:3e4,keepAliveWarnAt:2/3,start:function(i,h){var a=this,v={pingInterval:3e5,waitForPageLoad:!0,transport:"auto",jsonp:!1},d,y=a._deferral||n.Deferred(),b=t.document.createElement("a"),k,g;if(a.lastError=null,a._deferral=y,!a.json)throw new Error("SignalR: No JSON parser found. Please ensure json2.js is referenced before the SignalR.js file if you need to support clients without native JSON parsing support, e.g. IE<8.");if(n.type(i)==="function"?h=i:n.type(i)==="object"&&(n.extend(v,i),n.type(v.callback)==="function"&&(h=v.callback)),v.transport=w(v.transport,a),!v.transport)throw new Error("SignalR: Invalid transport(s) specified, aborting start.");return(a._.config=v,!o&&v.waitForPageLoad===!0)?(a._.deferredStartHandler=function(){a.start(i,h)},e.bind("load",a._.deferredStartHandler),y.promise()):a.state===r.connectionState.connecting?y.promise():s(a,r.connectionState.disconnected,r.connectionState.connecting)===!1?(y.resolve(a),y.promise()):(p(a),b.href=a.url,b.protocol&&b.protocol!==":"?(a.protocol=b.protocol,a.host=b.host):(a.protocol=t.document.location.protocol,a.host=b.host||t.document.location.host),a.baseUrl=a.protocol+"//"+a.host,a.wsProtocol=a.protocol==="https:"?"wss://":"ws://",v.transport==="auto"&&v.jsonp===!0&&(v.transport="longPolling"),a.url.indexOf("//")===0&&(a.url=t.location.protocol+a.url,a.log("Protocol relative URL detected, normalizing it to '"+a.url+"'.")),this.isCrossDomain(a.url)&&(a.log("Auto detected cross domain url."),v.transport==="auto"&&(v.transport=["webSockets","serverSentEvents","longPolling"]),typeof v.withCredentials=="undefined"&&(v.withCredentials=!0),v.jsonp||(v.jsonp=!n.support.cors,v.jsonp&&a.log("Using jsonp because this browser doesn't support CORS.")),a.contentType=r._.defaultContentType),a.withCredentials=v.withCredentials,a.ajaxDataType=v.jsonp?"jsonp":"text",n(a).bind(u.onStart,function(){n.type(h)==="function"&&h.call(a);y.resolve(a)}),a._.initHandler=r.transports._logic.initHandler(a),d=function(i,o){var c=r._.error(f.noTransportOnInit);if(o=o||0,o>=i.length){o===0?a.log("No transports supported by the server were selected."):o===1?a.log("No fallback transports were selected."):a.log("Fallback transports exhausted.");n(a).triggerHandler(u.onError,[c]);y.reject(c);a.stop();return}if(a.state!==r.connectionState.disconnected){var p=i[o],h=r.transports[p],v=function(){d(i,o+1)};a.transport=h;try{a._.initHandler.start(h,function(){var i=r._.firefoxMajorVersion(t.navigator.userAgent)>=11,f=!!a.withCredentials&&i;a.log("The start request succeeded. Transitioning to the connected state.");l(a)&&r.transports._logic.monitorKeepAlive(a);r.transports._logic.startHeartbeat(a);r._.configurePingInterval(a);s(a,r.connectionState.connecting,r.connectionState.connected)||a.log("WARNING! The connection was not in the connecting state.");a._.connectingMessageBuffer.drain();n(a).triggerHandler(u.onStart);e.bind("unload",function(){a.log("Window unloading, stopping the connection.");a.stop(f)});i&&e.bind("beforeunload",function(){t.setTimeout(function(){a.stop(f)},0)})},v)}catch(w){a.log(h.name+" transport threw '"+w.message+"' when attempting to start.");v()}}},k=a.url+"/negotiate",g=function(t,i){var e=r._.error(f.errorOnNegotiate,t,i._.negotiateRequest);n(i).triggerHandler(u.onError,e);y.reject(e);i.stop()},n(a).triggerHandler(u.onStarting),k=r.transports._logic.prepareQueryString(a,k),a.log("Negotiating with '"+k+"'."),a._.negotiateRequest=r.transports._logic.ajax(a,{url:k,error:function(n,t){t!==c?g(n,a):y.reject(r._.error(f.stoppedWhileNegotiating,null,a._.negotiateRequest))},success:function(t){var i,e,h,o=[],s=[];try{i=a._parseResponse(t)}catch(c){g(r._.error(f.errorParsingNegotiateResponse,c),a);return}if(e=a._.keepAliveData,a.appRelativeUrl=i.Url,a.id=i.ConnectionId,a.token=i.ConnectionToken,a.webSocketServerUrl=i.WebSocketServerUrl,a._.pollTimeout=i.ConnectionTimeout*1e3+1e4,a.disconnectTimeout=i.DisconnectTimeout*1e3,a._.totalTransportConnectTimeout=a.transportConnectTimeout+i.TransportConnectTimeout*1e3,i.KeepAliveTimeout?(e.activated=!0,e.timeout=i.KeepAliveTimeout*1e3,e.timeoutWarning=e.timeout*a.keepAliveWarnAt,a._.beatInterval=(e.timeout-e.timeoutWarning)/3):e.activated=!1,a.reconnectWindow=a.disconnectTimeout+(e.timeout||0),!i.ProtocolVersion||i.ProtocolVersion!==a.clientProtocol){h=r._.error(r._.format(f.protocolIncompatible,a.clientProtocol,i.ProtocolVersion));n(a).triggerHandler(u.onError,[h]);y.reject(h);return}n.each(r.transports,function(n){if(n.indexOf("_")===0||n==="webSockets"&&!i.TryWebSockets)return!0;s.push(n)});n.isArray(v.transport)?n.each(v.transport,function(t,i){n.inArray(i,s)>=0&&o.push(i)}):v.transport==="auto"?o=s:n.inArray(v.transport,s)>=0&&o.push(v.transport);d(o)}}),y.promise())},starting:function(t){var i=this;return n(i).bind(u.onStarting,function(){t.call(i)}),i},send:function(n){var t=this;if(t.state===r.connectionState.disconnected)throw new Error("SignalR: Connection must be started before data can be sent. Call .start() before .send()");if(t.state===r.connectionState.connecting)throw new Error("SignalR: Connection has not been fully initialized. Use .start().done() or .start().fail() to run logic after the connection has started.");return t.transport.send(t,n),t},received:function(t){var i=this;return n(i).bind(u.onReceived,function(n,r){t.call(i,r)}),i},stateChanged:function(t){var i=this;return n(i).bind(u.onStateChanged,function(n,r){t.call(i,r)}),i},error:function(t){var i=this;return n(i).bind(u.onError,function(n,r,u){i.lastError=r;t.call(i,r,u)}),i},disconnected:function(t){var i=this;return n(i).bind(u.onDisconnect,function(){t.call(i)}),i},connectionSlow:function(t){var i=this;return n(i).bind(u.onConnectionSlow,function(){t.call(i)}),i},reconnecting:function(t){var i=this;return n(i).bind(u.onReconnecting,function(){t.call(i)}),i},reconnected:function(t){var i=this;return n(i).bind(u.onReconnect,function(){t.call(i)}),i},stop:function(i,h){var a=this,v=a._deferral;if(a._.deferredStartHandler&&e.unbind("load",a._.deferredStartHandler),delete a._.config,delete a._.deferredStartHandler,!o&&(!a._.config||a._.config.waitForPageLoad===!0)){a.log("Stopping connection prior to negotiate.");v&&v.reject(r._.error(f.stoppedWhileLoading));return}if(a.state!==r.connectionState.disconnected)return a.log("Stopping connection."),t.clearTimeout(a._.beatHandle),t.clearInterval(a._.pingIntervalId),a.transport&&(a.transport.stop(a),h!==!1&&a.transport.abort(a,i),l(a)&&r.transports._logic.stopMonitoringKeepAlive(a),a.transport=null),a._.negotiateRequest&&(a._.negotiateRequest.abort(c),delete a._.negotiateRequest),a._.initHandler&&a._.initHandler.stop(),delete a._deferral,delete a.messageId,delete a.groupsToken,delete a.id,delete a._.pingIntervalId,delete a._.lastMessageAt,delete a._.lastActiveAt,a._.connectingMessageBuffer.clear(),s(a,a.state,r.connectionState.disconnected),n(a).triggerHandler(u.onDisconnect),a},log:function(n){v(n,this.logging)}};r.fn.init.prototype=r.fn;r.noConflict=function(){return n.connection===r&&(n.connection=h),r};n.connection&&(h=n.connection);n.connection=n.signalR=r})(window.jQuery,window),function(n,t,i){function s(n){n._.keepAliveData.monitoring&&l(n);u.markActive(n)&&(n._.beatHandle=t.setTimeout(function(){s(n)},n._.beatInterval))}function l(t){var i=t._.keepAliveData,u;t.state===r.connectionState.connected&&(u=(new Date).getTime()-t._.lastMessageAt,u>=i.timeout?(t.log("Keep alive timed out. Notifying transport that connection has been lost."),t.transport.lostConnection(t)):u>=i.timeoutWarning?i.userNotified||(t.log("Keep alive has been missed, connection may be dead/slow."),n(t).triggerHandler(f.onConnectionSlow),i.userNotified=!0):i.userNotified=!1)}function e(n,t){var i=n.url+t;return n.transport&&(i+="?transport="+n.transport.name),u.prepareQueryString(n,i)}function h(n){this.connection=n;this.startRequested=!1;this.startCompleted=!1;this.connectionStopped=!1}var r=n.signalR,f=n.signalR.events,c=n.signalR.changeState,o="__Start Aborted__",u;r.transports={};h.prototype={start:function(n,r,u){var f=this,e=f.connection,o=!1;if(f.startRequested||f.connectionStopped){e.log("WARNING! "+n.name+" transport cannot be started. Initialization ongoing or completed.");return}e.log(n.name+" transport starting.");n.start(e,function(){o||f.initReceived(n,r)},function(t){return o||(o=!0,f.transportFailed(n,t,u)),!f.startCompleted||f.connectionStopped});f.transportTimeoutHandle=t.setTimeout(function(){o||(o=!0,e.log(n.name+" transport timed out when trying to connect."),f.transportFailed(n,i,u))},e._.totalTransportConnectTimeout)},stop:function(){this.connectionStopped=!0;t.clearTimeout(this.transportTimeoutHandle);r.transports._logic.tryAbortStartRequest(this.connection)},initReceived:function(n,i){var u=this,f=u.connection;if(u.startRequested){f.log("WARNING! The client received multiple init messages.");return}u.connectionStopped||(u.startRequested=!0,t.clearTimeout(u.transportTimeoutHandle),f.log(n.name+" transport connected. Initiating start request."),r.transports._logic.ajaxStart(f,function(){u.startCompleted=!0;i()}))},transportFailed:function(i,u,e){var o=this.connection,h=o._deferral,s;this.connectionStopped||(t.clearTimeout(this.transportTimeoutHandle),this.startRequested?this.startCompleted||(s=r._.error(r.resources.errorDuringStartRequest,u),o.log(i.name+" transport failed during the start request. Stopping the connection."),n(o).triggerHandler(f.onError,[s]),h&&h.reject(s),o.stop()):(i.stop(o),o.log(i.name+" transport failed to connect. Attempting to fall back."),e()))}};u=r.transports._logic={ajax:function(t,i){return n.ajax(n.extend(!0,{},n.signalR.ajaxDefaults,{type:"GET",data:{},xhrFields:{withCredentials:t.withCredentials},contentType:t.contentType,dataType:t.ajaxDataType},i))},pingServer:function(t){var e,f,i=n.Deferred();return t.transport?(e=t.url+"/ping",e=u.addQs(e,t.qs),f=u.ajax(t,{url:e,success:function(n){var u;try{u=t._parseResponse(n)}catch(e){i.reject(r._.transportError(r.resources.pingServerFailedParse,t.transport,e,f));t.stop();return}u.Response==="pong"?i.resolve():i.reject(r._.transportError(r._.format(r.resources.pingServerFailedInvalidResponse,n),t.transport,null,f))},error:function(n){n.status===401||n.status===403?(i.reject(r._.transportError(r._.format(r.resources.pingServerFailedStatusCode,n.status),t.transport,n,f)),t.stop()):i.reject(r._.transportError(r.resources.pingServerFailed,t.transport,n,f))}})):i.reject(r._.transportError(r.resources.noConnectionTransport,t.transport)),i.promise()},prepareQueryString:function(n,i){var r;return r=u.addQs(i,"clientProtocol="+n.clientProtocol),r=u.addQs(r,n.qs),n.token&&(r+="&connectionToken="+t.encodeURIComponent(n.token)),n.data&&(r+="&connectionData="+t.encodeURIComponent(n.data)),r},addQs:function(t,i){var r=t.indexOf("?")!==-1?"&":"?",u;if(!i)return t;if(typeof i=="object")return t+r+n.param(i);if(typeof i=="string")return u=i.charAt(0),(u==="?"||u==="&")&&(r=""),t+r+i;throw new Error("Query string property must be either a string or object.");},getUrl:function(n,i,r,f,e){var h=i==="webSockets"?"":n.baseUrl,o=h+n.appRelativeUrl,s="transport="+i;return!e&&n.groupsToken&&(s+="&groupsToken="+t.encodeURIComponent(n.groupsToken)),r?(o+=f?"/poll":"/reconnect",!e&&n.messageId&&(s+="&messageId="+t.encodeURIComponent(n.messageId))):o+="/connect",o+="?"+s,o=u.prepareQueryString(n,o),e||(o+="&tid="+Math.floor(Math.random()*11)),o},maximizePersistentResponse:function(n){return{MessageId:n.C,Messages:n.M,Initialized:typeof n.S!="undefined"?!0:!1,ShouldReconnect:typeof n.T!="undefined"?!0:!1,LongPollDelay:n.L,GroupsToken:n.G}},updateGroups:function(n,t){t&&(n.groupsToken=t)},stringifySend:function(n,t){return typeof t=="string"||typeof t=="undefined"||t===null?t:n.json.stringify(t)},ajaxSend:function(t,i){var h=u.stringifySend(t,i),c=e(t,"/send"),o,s=function(t,u){n(u).triggerHandler(f.onError,[r._.transportError(r.resources.sendFailed,u.transport,t,o),i])};return o=u.ajax(t,{url:c,type:t.ajaxDataType==="jsonp"?"GET":"POST",contentType:r._.defaultContentType,data:{data:h},success:function(n){var i;if(n){try{i=t._parseResponse(n)}catch(r){s(r,t);t.stop();return}u.triggerReceived(t,i)}},error:function(n,i){i!=="abort"&&i!=="parsererror"&&s(n,t)}})},ajaxAbort:function(n,t){if(typeof n.transport!="undefined"){t=typeof t=="undefined"?!0:t;var i=e(n,"/abort");u.ajax(n,{url:i,async:t,timeout:1e3,type:"POST"});n.log("Fired ajax abort async = "+t+".")}},ajaxStart:function(t,i){var h=function(n){var i=t._deferral;i&&i.reject(n)},s=function(i){t.log("The start request failed. Stopping the connection.");n(t).triggerHandler(f.onError,[i]);h(i);t.stop()};t._.startRequest=u.ajax(t,{url:e(t,"/start"),success:function(n,u,f){var e;try{e=t._parseResponse(n)}catch(o){s(r._.error(r._.format(r.resources.errorParsingStartResponse,n),o,f));return}e.Response==="started"?i():s(r._.error(r._.format(r.resources.invalidStartResponse,n),null,f))},error:function(n,i,u){i!==o?s(r._.error(r.resources.errorDuringStartRequest,u,n)):(t.log("The start request aborted because connection.stop() was called."),h(r._.error(r.resources.stoppedDuringStartRequest,null,n)))}})},tryAbortStartRequest:function(n){n._.startRequest&&(n._.startRequest.abort(o),delete n._.startRequest)},tryInitialize:function(n,t,i){t.Initialized&&i?i():t.Initialized&&n.log("WARNING! The client received an init message after reconnecting.")},triggerReceived:function(t,i){t._.connectingMessageBuffer.tryBuffer(i)||n(t).triggerHandler(f.onReceived,[i])},processMessages:function(t,i,r){var f;u.markLastMessage(t);i&&(f=u.maximizePersistentResponse(i),u.updateGroups(t,f.GroupsToken),f.MessageId&&(t.messageId=f.MessageId),f.Messages&&(n.each(f.Messages,function(n,i){u.triggerReceived(t,i)}),u.tryInitialize(t,f,r)))},monitorKeepAlive:function(t){var i=t._.keepAliveData;i.monitoring?t.log("Tried to monitor keep alive but it's already being monitored."):(i.monitoring=!0,u.markLastMessage(t),t._.keepAliveData.reconnectKeepAliveUpdate=function(){u.markLastMessage(t)},n(t).bind(f.onReconnect,t._.keepAliveData.reconnectKeepAliveUpdate),t.log("Now monitoring keep alive with a warning timeout of "+i.timeoutWarning+", keep alive timeout of "+i.timeout+" and disconnecting timeout of "+t.disconnectTimeout))},stopMonitoringKeepAlive:function(t){var i=t._.keepAliveData;i.monitoring&&(i.monitoring=!1,n(t).unbind(f.onReconnect,t._.keepAliveData.reconnectKeepAliveUpdate),t._.keepAliveData={},t.log("Stopping the monitoring of the keep alive."))},startHeartbeat:function(n){n._.lastActiveAt=(new Date).getTime();s(n)},markLastMessage:function(n){n._.lastMessageAt=(new Date).getTime()},markActive:function(n){return u.verifyLastActive(n)?(n._.lastActiveAt=(new Date).getTime(),!0):!1},isConnectedOrReconnecting:function(n){return n.state===r.connectionState.connected||n.state===r.connectionState.reconnecting},ensureReconnectingState:function(t){return c(t,r.connectionState.connected,r.connectionState.reconnecting)===!0&&n(t).triggerHandler(f.onReconnecting),t.state===r.connectionState.reconnecting},clearReconnectTimeout:function(n){n&&n._.reconnectTimeout&&(t.clearTimeout(n._.reconnectTimeout),delete n._.reconnectTimeout)},verifyLastActive:function(t){if((new Date).getTime()-t._.lastActiveAt>=t.reconnectWindow){var i=r._.format(r.resources.reconnectWindowTimeout,new Date(t._.lastActiveAt),t.reconnectWindow);return t.log(i),n(t).triggerHandler(f.onError,[r._.error(i,"TimeoutException")]),t.stop(!1,!1),!1}return!0},reconnect:function(n,i){var f=r.transports[i];if(u.isConnectedOrReconnecting(n)&&!n._.reconnectTimeout){if(!u.verifyLastActive(n))return;n._.reconnectTimeout=t.setTimeout(function(){u.verifyLastActive(n)&&(f.stop(n),u.ensureReconnectingState(n)&&(n.log(i+" reconnecting."),f.start(n)))},n.reconnectDelay)}},handleParseFailure:function(t,i,u,e,o){var s=r._.transportError(r._.format(r.resources.parseFailed,i),t.transport,u,o);e&&e(s)?t.log("Failed to parse server response while attempting to connect."):(n(t).triggerHandler(f.onError,[s]),t.stop())},initHandler:function(n){return new h(n)},foreverFrame:{count:0,connections:{}}}}(window.jQuery,window),function(n,t){var r=n.signalR,u=n.signalR.events,f=n.signalR.changeState,i=r.transports._logic;r.transports.webSockets={name:"webSockets",supportsKeepAlive:function(){return!0},send:function(t,f){var e=i.stringifySend(t,f);try{t.socket.send(e)}catch(o){n(t).triggerHandler(u.onError,[r._.transportError(r.resources.webSocketsInvalidState,t.transport,o,t.socket),f])}},start:function(e,o,s){var h,c=!1,l=this,a=!o,v=n(e);if(!t.WebSocket){s();return}e.socket||(h=e.webSocketServerUrl?e.webSocketServerUrl:e.wsProtocol+e.host,h+=i.getUrl(e,this.name,a),e.log("Connecting to websocket endpoint '"+h+"'."),e.socket=new t.WebSocket(h),e.socket.onopen=function(){c=!0;e.log("Websocket opened.");i.clearReconnectTimeout(e);f(e,r.connectionState.reconnecting,r.connectionState.connected)===!0&&v.triggerHandler(u.onReconnect)},e.socket.onclose=function(t){var i;this===e.socket&&(c&&typeof t.wasClean!="undefined"&&t.wasClean===!1?(i=r._.transportError(r.resources.webSocketClosed,e.transport,t),e.log("Unclean disconnect from websocket: "+(t.reason||"[no reason given]."))):e.log("Websocket closed."),s&&s(i)||(i&&n(e).triggerHandler(u.onError,[i]),l.reconnect(e)))},e.socket.onmessage=function(t){var r;try{r=e._parseResponse(t.data)}catch(u){i.handleParseFailure(e,t.data,u,s,t);return}r&&(n.isEmptyObject(r)||r.M?i.processMessages(e,r,o):i.triggerReceived(e,r))})},reconnect:function(n){i.reconnect(n,this.name)},lostConnection:function(n){this.reconnect(n)},stop:function(n){i.clearReconnectTimeout(n);n.socket&&(n.log("Closing the Websocket."),n.socket.close(),n.socket=null)},abort:function(n,t){i.ajaxAbort(n,t)}}}(window.jQuery,window),function(n,t){var i=n.signalR,u=n.signalR.events,e=n.signalR.changeState,r=i.transports._logic,f=function(n){t.clearTimeout(n._.reconnectAttemptTimeoutHandle);delete n._.reconnectAttemptTimeoutHandle};i.transports.serverSentEvents={name:"serverSentEvents",supportsKeepAlive:function(){return!0},timeOut:3e3,start:function(o,s,h){var c=this,l=!1,a=n(o),v=!s,y;if(o.eventSource&&(o.log("The connection already has an event source. Stopping it."),o.stop()),!t.EventSource){h&&(o.log("This browser doesn't support SSE."),h());return}y=r.getUrl(o,this.name,v);try{o.log("Attempting to connect to SSE endpoint '"+y+"'.");o.eventSource=new t.EventSource(y,{withCredentials:o.withCredentials})}catch(p){o.log("EventSource failed trying to connect with error "+p.Message+".");h?h():(a.triggerHandler(u.onError,[i._.transportError(i.resources.eventSourceFailedToConnect,o.transport,p)]),v&&c.reconnect(o));return}v&&(o._.reconnectAttemptTimeoutHandle=t.setTimeout(function(){l===!1&&o.eventSource.readyState!==t.EventSource.OPEN&&c.reconnect(o)},c.timeOut));o.eventSource.addEventListener("open",function(){o.log("EventSource connected.");f(o);r.clearReconnectTimeout(o);l===!1&&(l=!0,e(o,i.connectionState.reconnecting,i.connectionState.connected)===!0&&a.triggerHandler(u.onReconnect))},!1);o.eventSource.addEventListener("message",function(n){var t;if(n.data!=="initialized"){try{t=o._parseResponse(n.data)}catch(i){r.handleParseFailure(o,n.data,i,h,n);return}r.processMessages(o,t,s)}},!1);o.eventSource.addEventListener("error",function(n){var r=i._.transportError(i.resources.eventSourceError,o.transport,n);this===o.eventSource&&(h&&h(r)||(o.log("EventSource readyState: "+o.eventSource.readyState+"."),n.eventPhase===t.EventSource.CLOSED?(o.log("EventSource reconnecting due to the server connection ending."),c.reconnect(o)):(o.log("EventSource error."),a.triggerHandler(u.onError,[r]))))},!1)},reconnect:function(n){r.reconnect(n,this.name)},lostConnection:function(n){this.reconnect(n)},send:function(n,t){r.ajaxSend(n,t)},stop:function(n){f(n);r.clearReconnectTimeout(n);n&&n.eventSource&&(n.log("EventSource calling close()."),n.eventSource.close(),n.eventSource=null,delete n.eventSource)},abort:function(n,t){r.ajaxAbort(n,t)}}}(window.jQuery,window),function(n,t){var r=n.signalR,e=n.signalR.events,o=n.signalR.changeState,i=r.transports._logic,u=function(){var n=t.document.createElement("iframe");return n.setAttribute("style","position:absolute;top:0;left:0;width:0;height:0;visibility:hidden;"),n},f=function(){var i=null,f=1e3,n=0;return{prevent:function(){r._.ieVersion<=8&&(n===0&&(i=t.setInterval(function(){var n=u();t.document.body.appendChild(n);t.document.body.removeChild(n);n=null},f)),n++)},cancel:function(){n===1&&t.clearInterval(i);n>0&&n--}}}();r.transports.foreverFrame={name:"foreverFrame",supportsKeepAlive:function(){return!0},iframeClearThreshold:50,start:function(n,r,e){var l=this,s=i.foreverFrame.count+=1,h,o=u(),c=function(){n.log("Forever frame iframe finished loading and is no longer receiving messages.");e&&e()||l.reconnect(n)};if(t.EventSource){e&&(n.log("Forever Frame is not supported by SignalR on browsers with SSE support."),e());return}o.setAttribute("data-signalr-connection-id",n.id);f.prevent();h=i.getUrl(n,this.name);h+="&frameId="+s;t.document.documentElement.appendChild(o);n.log("Binding to iframe's load event.");o.addEventListener?o.addEventListener("load",c,!1):o.attachEvent&&o.attachEvent("onload",c);o.src=h;i.foreverFrame.connections[s]=n;n.frame=o;n.frameId=s;r&&(n.onSuccess=function(){n.log("Iframe transport started.");r()})},reconnect:function(n){var r=this;i.isConnectedOrReconnecting(n)&&i.verifyLastActive(n)&&t.setTimeout(function(){if(i.verifyLastActive(n)&&n.frame&&i.ensureReconnectingState(n)){var u=n.frame,t=i.getUrl(n,r.name,!0)+"&frameId="+n.frameId;n.log("Updating iframe src to '"+t+"'.");u.src=t}},n.reconnectDelay)},lostConnection:function(n){this.reconnect(n)},send:function(n,t){i.ajaxSend(n,t)},receive:function(t,u){var f,e,o;if(t.json!==t._originalJson&&(u=t._originalJson.stringify(u)),o=t._parseResponse(u),i.processMessages(t,o,t.onSuccess),t.state===n.signalR.connectionState.connected&&(t.frameMessageCount=(t.frameMessageCount||0)+1,t.frameMessageCount>r.transports.foreverFrame.iframeClearThreshold&&(t.frameMessageCount=0,f=t.frame.contentWindow||t.frame.contentDocument,f&&f.document&&f.document.body)))for(e=f.document.body;e.firstChild;)e.removeChild(e.firstChild)},stop:function(n){var r=null;if(f.cancel(),n.frame){if(n.frame.stop)n.frame.stop();else try{r=n.frame.contentWindow||n.frame.contentDocument;r.document&&r.document.execCommand&&r.document.execCommand("Stop")}catch(u){n.log("Error occurred when stopping foreverFrame transport. Message = "+u.message+".")}n.frame.parentNode===t.document.body&&t.document.body.removeChild(n.frame);delete i.foreverFrame.connections[n.frameId];n.frame=null;n.frameId=null;delete n.frame;delete n.frameId;delete n.onSuccess;delete n.frameMessageCount;n.log("Stopping forever frame.")}},abort:function(n,t){i.ajaxAbort(n,t)},getConnection:function(n){return i.foreverFrame.connections[n]},started:function(t){o(t,r.connectionState.reconnecting,r.connectionState.connected)===!0&&n(t).triggerHandler(e.onReconnect)}}}(window.jQuery,window),function(n,t){var r=n.signalR,u=n.signalR.events,e=n.signalR.changeState,f=n.signalR.isDisconnecting,i=r.transports._logic;r.transports.longPolling={name:"longPolling",supportsKeepAlive:function(){return!1},reconnectDelay:3e3,start:function(o,s,h){var a=this,v=function(){v=n.noop;o.log("LongPolling connected.");s?s():o.log("WARNING! The client received an init message after reconnecting.")},y=function(n){return h(n)?(o.log("LongPolling failed to connect."),!0):!1},c=o._,l=0,p=function(i){t.clearTimeout(c.reconnectTimeoutId);c.reconnectTimeoutId=null;e(i,r.connectionState.reconnecting,r.connectionState.connected)===!0&&(i.log("Raising the reconnect event"),n(i).triggerHandler(u.onReconnect))},w=36e5;o.pollXhr&&(o.log("Polling xhr requests already exists, aborting."),o.stop());o.messageId=null;c.reconnectTimeoutId=null;c.pollTimeoutId=t.setTimeout(function(){(function e(s,h){var g=s.messageId,nt=g===null,k=!nt,tt=!h,d=i.getUrl(s,a.name,k,tt,!0),b={};(s.messageId&&(b.messageId=s.messageId),s.groupsToken&&(b.groupsToken=s.groupsToken),f(s)!==!0)&&(o.log("Opening long polling request to '"+d+"'."),s.pollXhr=i.ajax(o,{xhrFields:{onprogress:function(){i.markLastMessage(o)}},url:d,type:"POST",contentType:r._.defaultContentType,data:b,timeout:o._.pollTimeout,success:function(r){var h,w=0,u,a;o.log("Long poll complete.");l=0;try{h=o._parseResponse(r)}catch(b){i.handleParseFailure(s,r,b,y,s.pollXhr);return}(c.reconnectTimeoutId!==null&&p(s),h&&(u=i.maximizePersistentResponse(h)),i.processMessages(s,h,v),u&&n.type(u.LongPollDelay)==="number"&&(w=u.LongPollDelay),f(s)!==!0)&&(a=u&&u.ShouldReconnect,!a||i.ensureReconnectingState(s))&&(w>0?c.pollTimeoutId=t.setTimeout(function(){e(s,a)},w):e(s,a))},error:function(f,h){var v=r._.transportError(r.resources.longPollFailed,o.transport,f,s.pollXhr);if(t.clearTimeout(c.reconnectTimeoutId),c.reconnectTimeoutId=null,h==="abort"){o.log("Aborted xhr request.");return}if(!y(v)){if(l++,o.state!==r.connectionState.reconnecting&&(o.log("An error occurred using longPolling. Status = "+h+". Response = "+f.responseText+"."),n(s).triggerHandler(u.onError,[v])),(o.state===r.connectionState.connected||o.state===r.connectionState.reconnecting)&&!i.verifyLastActive(o))return;if(!i.ensureReconnectingState(s))return;c.pollTimeoutId=t.setTimeout(function(){e(s,!0)},a.reconnectDelay)}}}),k&&h===!0&&(c.reconnectTimeoutId=t.setTimeout(function(){p(s)},Math.min(1e3*(Math.pow(2,l)-1),w))))})(o)},250)},lostConnection:function(n){n.pollXhr&&n.pollXhr.abort("lostConnection")},send:function(n,t){i.ajaxSend(n,t)},stop:function(n){t.clearTimeout(n._.pollTimeoutId);t.clearTimeout(n._.reconnectTimeoutId);delete n._.pollTimeoutId;delete n._.reconnectTimeoutId;n.pollXhr&&(n.pollXhr.abort(),n.pollXhr=null,delete n.pollXhr)},abort:function(n,t){i.ajaxAbort(n,t)}}}(window.jQuery,window),function(n){function r(n){return n+e}function s(n,t,i){for(var f=n.length,u=[],r=0;r + + + + + diff --git a/path.txt b/path.txt new file mode 100644 index 0000000..f346158 --- /dev/null +++ b/path.txt @@ -0,0 +1 @@ +PATH=C:\ProgramData\Oracle\Java\javapath;C:\RailsInstaller\Git\cmd;C:\RailsInstaller\Ruby2.1.0\bin;C:\Ruby21\bin;C:\ProgramData\chocolatey\bin;C:\Python27\;C:\Python27\Scripts;C:\Perl\site\bin;C:\Perl\bin;C:\app\james.dilcock\product\11.2.0\client_1\bin;C:\PROGRAM FILES\DELL\DW WLAN CARD;C:\Windows\SYSTEM32;C:\Windows;C:\Windows\SYSTEM32\WBEM;C:\Windows\SYSTEM32\WINDOWSPOWERSHELL\V1.0\;C:\PROGRAM FILES\INTEL\WIFI\BIN\;C:\PROGRAM FILES\COMMON FILES\INTEL\WIRELESSCOMMON\;C:\Program Files\WIDCOMM\Bluetooth Software\;C:\Program Files\WIDCOMM\Bluetooth Software\syswow64;C:\Program Files (x86)\Microsoft ASP.NET\ASP.NET Web Pages\v1.0\;C:\Program Files\Microsoft SQL Server\110\Tools\Binn\;C:\Program Files (x86)\Microsoft Team Foundation Server 2012 Power Tools\;C:\Program Files (x86)\Microsoft Team Foundation Server 2012 Power Tools\Best Practices Analyzer\;C:\Program Files\NCover v4 Desktop;C:\Program Files (x86)\Microsoft SDKs\TypeScript\;C:\Program Files (x86)\QuickTime\QTSystem\;C:\Program Files (x86)\Windows Kits\8.1\Windows Performance Toolkit\;C:\Program Files (x86)\Calibre2\;C:\Program Files (x86)\Microsoft Team Foundation Server 2015 Power Tools\;C:\Program Files (x86)\Microsoft Team Foundation Server 2013 Power Tools\Best Practices Analyzer\;C:\Program Files\Microsoft\Web Platform Installer\;C:\Program Files (x86)\Git\cmd;C:\Program Files\Microsoft SQL Server\120\Tools\Binn\;C:\Program Files\nodejs\;c:\Program Files (x86)\Microsoft SQL Server\110\Tools\Binn\;c:\Program Files\Microsoft SQL Server\110\DTS\Binn\;C:\Windows\system32\config\systemprofile\.dnx\bin;C:\Program Files\Microsoft DNX\Dnvm\;C:\Program Files (x86)\Skype\Phone\;C:\Users\james.dilcock\.dnx\bin;C:\ProgramData\Oracle\Java\javapath;C:\RailsInstaller\Git\cmd;C:\RailsInstaller\Ruby2.1.0\bin;C:\Ruby21\bin;C:\ProgramData\chocolatey\bin;C:\Python27\;C:\Python27\Scripts;C:\Perl\site\bin;C:\Perl\bin;C:\app\james.dilcock\product\11.2.0\client_1\bin;C:\PROGRAM FILES\DELL\DW WLAN CARD;C:\Windows\SYSTEM32;C:\Windows;C:\Windows\SYSTEM32\WBEM;C:\Windows\SYSTEM32\WINDOWSPOWERSHELL\V1.0\;C:\PROGRAM FILES\INTEL\WIFI\BIN\;C:\PROGRAM FILES\COMMON FILES\INTEL\WIRELESSCOMMON\;C:\Program Files\WIDCOMM\Bluetooth Software\;C:\Program Files\WIDCOMM\Bluetooth Software\syswow64;C:\Program Files (x86)\Microsoft ASP.NET\ASP.NET Web Pages\v1.0\;C:\Program Files\Microsoft SQL Server\110\Tools\Binn\;C:\Program Files (x86)\Microsoft Team Foundation Server 2012 Power Tools\;C:\Program Files (x86)\Microsoft Team Foundation Server 2012 Power Tools\Best Practices Analyzer\;C:\Program Files\NCover v4 Desktop;C:\Program Files (x86)\Microsoft SDKs\TypeScript\;C:\Program Files (x86)\QuickTime\QTSystem\;C:\Pro diff --git a/res/native/android/ant.properties b/res/native/android/ant.properties new file mode 100644 index 0000000..433c949 --- /dev/null +++ b/res/native/android/ant.properties @@ -0,0 +1,4 @@ +key.store= +key.alias= +key.store.password= +key.alias.password= \ No newline at end of file diff --git a/res/shared/icon-96-xhdpi-TransparentText.png b/res/shared/icon-96-xhdpi-TransparentText.png new file mode 100644 index 0000000..faab706 Binary files /dev/null and b/res/shared/icon-96-xhdpi-TransparentText.png differ diff --git a/res/shared/icon.png b/res/shared/icon.png new file mode 100644 index 0000000..11656c5 Binary files /dev/null and b/res/shared/icon.png differ diff --git a/res/shared/logo.png b/res/shared/logo.png new file mode 100644 index 0000000..5144848 Binary files /dev/null and b/res/shared/logo.png differ diff --git a/res/shared/screen-xhdpi-portrait.png b/res/shared/screen-xhdpi-portrait.png new file mode 100644 index 0000000..365300e Binary files /dev/null and b/res/shared/screen-xhdpi-portrait.png differ diff --git a/resources/android/icon/drawable-hdpi-icon.png b/resources/android/icon/drawable-hdpi-icon.png new file mode 100644 index 0000000..121f0fc Binary files /dev/null and b/resources/android/icon/drawable-hdpi-icon.png differ diff --git a/resources/android/icon/drawable-ldpi-icon.png b/resources/android/icon/drawable-ldpi-icon.png new file mode 100644 index 0000000..c686d5e Binary files /dev/null and b/resources/android/icon/drawable-ldpi-icon.png differ diff --git a/resources/android/icon/drawable-mdpi-icon.png b/resources/android/icon/drawable-mdpi-icon.png new file mode 100644 index 0000000..7cbce04 Binary files /dev/null and b/resources/android/icon/drawable-mdpi-icon.png differ diff --git a/resources/android/icon/drawable-xhdpi-icon.png b/resources/android/icon/drawable-xhdpi-icon.png new file mode 100644 index 0000000..11656c5 Binary files /dev/null and b/resources/android/icon/drawable-xhdpi-icon.png differ diff --git a/resources/android/icon/drawable-xxhdpi-icon.png b/resources/android/icon/drawable-xxhdpi-icon.png new file mode 100644 index 0000000..12429bd Binary files /dev/null and b/resources/android/icon/drawable-xxhdpi-icon.png differ diff --git a/resources/android/icon/drawable-xxxhdpi-icon.png b/resources/android/icon/drawable-xxxhdpi-icon.png new file mode 100644 index 0000000..e2e4da8 Binary files /dev/null and b/resources/android/icon/drawable-xxxhdpi-icon.png differ diff --git a/resources/android/splash/drawable-land-hdpi-screen.png b/resources/android/splash/drawable-land-hdpi-screen.png new file mode 100644 index 0000000..8e1c006 Binary files /dev/null and b/resources/android/splash/drawable-land-hdpi-screen.png differ diff --git a/resources/android/splash/drawable-land-ldpi-screen.png b/resources/android/splash/drawable-land-ldpi-screen.png new file mode 100644 index 0000000..664f18a Binary files /dev/null and b/resources/android/splash/drawable-land-ldpi-screen.png differ diff --git a/resources/android/splash/drawable-land-mdpi-screen.png b/resources/android/splash/drawable-land-mdpi-screen.png new file mode 100644 index 0000000..14653fc Binary files /dev/null and b/resources/android/splash/drawable-land-mdpi-screen.png differ diff --git a/resources/android/splash/drawable-land-xhdpi-screen.png b/resources/android/splash/drawable-land-xhdpi-screen.png new file mode 100644 index 0000000..4897c46 Binary files /dev/null and b/resources/android/splash/drawable-land-xhdpi-screen.png differ diff --git a/resources/android/splash/drawable-land-xxhdpi-screen.png b/resources/android/splash/drawable-land-xxhdpi-screen.png new file mode 100644 index 0000000..274bcd5 Binary files /dev/null and b/resources/android/splash/drawable-land-xxhdpi-screen.png differ diff --git a/resources/android/splash/drawable-land-xxxhdpi-screen.png b/resources/android/splash/drawable-land-xxxhdpi-screen.png new file mode 100644 index 0000000..e8ba8e8 Binary files /dev/null and b/resources/android/splash/drawable-land-xxxhdpi-screen.png differ diff --git a/resources/android/splash/drawable-port-hdpi-screen.png b/resources/android/splash/drawable-port-hdpi-screen.png new file mode 100644 index 0000000..dbba9e6 Binary files /dev/null and b/resources/android/splash/drawable-port-hdpi-screen.png differ diff --git a/resources/android/splash/drawable-port-ldpi-screen.png b/resources/android/splash/drawable-port-ldpi-screen.png new file mode 100644 index 0000000..22396a2 Binary files /dev/null and b/resources/android/splash/drawable-port-ldpi-screen.png differ diff --git a/resources/android/splash/drawable-port-mdpi-screen.png b/resources/android/splash/drawable-port-mdpi-screen.png new file mode 100644 index 0000000..0b97b1b Binary files /dev/null and b/resources/android/splash/drawable-port-mdpi-screen.png differ diff --git a/resources/android/splash/drawable-port-xhdpi-screen.png b/resources/android/splash/drawable-port-xhdpi-screen.png new file mode 100644 index 0000000..3055e62 Binary files /dev/null and b/resources/android/splash/drawable-port-xhdpi-screen.png differ diff --git a/resources/android/splash/drawable-port-xxhdpi-screen.png b/resources/android/splash/drawable-port-xxhdpi-screen.png new file mode 100644 index 0000000..0b22f8b Binary files /dev/null and b/resources/android/splash/drawable-port-xxhdpi-screen.png differ diff --git a/resources/android/splash/drawable-port-xxxhdpi-screen.png b/resources/android/splash/drawable-port-xxxhdpi-screen.png new file mode 100644 index 0000000..2c36ae6 Binary files /dev/null and b/resources/android/splash/drawable-port-xxxhdpi-screen.png differ diff --git a/resources/icon.png b/resources/icon.png new file mode 100644 index 0000000..88569e4 Binary files /dev/null and b/resources/icon.png differ diff --git a/resources/ios/icon/icon-40.png b/resources/ios/icon/icon-40.png new file mode 100644 index 0000000..fb93f1c Binary files /dev/null and b/resources/ios/icon/icon-40.png differ diff --git a/resources/ios/icon/icon-40@2x.png b/resources/ios/icon/icon-40@2x.png new file mode 100644 index 0000000..4a9aed5 Binary files /dev/null and b/resources/ios/icon/icon-40@2x.png differ diff --git a/resources/ios/icon/icon-40@3x.png b/resources/ios/icon/icon-40@3x.png new file mode 100644 index 0000000..5dd4bec Binary files /dev/null and b/resources/ios/icon/icon-40@3x.png differ diff --git a/resources/ios/icon/icon-50.png b/resources/ios/icon/icon-50.png new file mode 100644 index 0000000..5372464 Binary files /dev/null and b/resources/ios/icon/icon-50.png differ diff --git a/resources/ios/icon/icon-50@2x.png b/resources/ios/icon/icon-50@2x.png new file mode 100644 index 0000000..b944fad Binary files /dev/null and b/resources/ios/icon/icon-50@2x.png differ diff --git a/resources/ios/icon/icon-60.png b/resources/ios/icon/icon-60.png new file mode 100644 index 0000000..8b8c70f Binary files /dev/null and b/resources/ios/icon/icon-60.png differ diff --git a/resources/ios/icon/icon-60@2x.png b/resources/ios/icon/icon-60@2x.png new file mode 100644 index 0000000..32e3749 Binary files /dev/null and b/resources/ios/icon/icon-60@2x.png differ diff --git a/resources/ios/icon/icon-60@3x.png b/resources/ios/icon/icon-60@3x.png new file mode 100644 index 0000000..91ece30 Binary files /dev/null and b/resources/ios/icon/icon-60@3x.png differ diff --git a/resources/ios/icon/icon-72.png b/resources/ios/icon/icon-72.png new file mode 100644 index 0000000..9ac96c3 Binary files /dev/null and b/resources/ios/icon/icon-72.png differ diff --git a/resources/ios/icon/icon-72@2x.png b/resources/ios/icon/icon-72@2x.png new file mode 100644 index 0000000..e26a6a5 Binary files /dev/null and b/resources/ios/icon/icon-72@2x.png differ diff --git a/resources/ios/icon/icon-76.png b/resources/ios/icon/icon-76.png new file mode 100644 index 0000000..3578639 Binary files /dev/null and b/resources/ios/icon/icon-76.png differ diff --git a/resources/ios/icon/icon-76@2x.png b/resources/ios/icon/icon-76@2x.png new file mode 100644 index 0000000..bc756df Binary files /dev/null and b/resources/ios/icon/icon-76@2x.png differ diff --git a/resources/ios/icon/icon-83.5@2x.png b/resources/ios/icon/icon-83.5@2x.png new file mode 100644 index 0000000..cd810e4 Binary files /dev/null and b/resources/ios/icon/icon-83.5@2x.png differ diff --git a/resources/ios/icon/icon-small.png b/resources/ios/icon/icon-small.png new file mode 100644 index 0000000..3433709 Binary files /dev/null and b/resources/ios/icon/icon-small.png differ diff --git a/resources/ios/icon/icon-small@2x.png b/resources/ios/icon/icon-small@2x.png new file mode 100644 index 0000000..c6f2da4 Binary files /dev/null and b/resources/ios/icon/icon-small@2x.png differ diff --git a/resources/ios/icon/icon-small@3x.png b/resources/ios/icon/icon-small@3x.png new file mode 100644 index 0000000..d492a42 Binary files /dev/null and b/resources/ios/icon/icon-small@3x.png differ diff --git a/resources/ios/icon/icon.png b/resources/ios/icon/icon.png new file mode 100644 index 0000000..441eea0 Binary files /dev/null and b/resources/ios/icon/icon.png differ diff --git a/resources/ios/icon/icon@2x.png b/resources/ios/icon/icon@2x.png new file mode 100644 index 0000000..7c36b16 Binary files /dev/null and b/resources/ios/icon/icon@2x.png differ diff --git a/resources/ios/splash/Default-568h@2x~iphone.png b/resources/ios/splash/Default-568h@2x~iphone.png new file mode 100644 index 0000000..64d608d Binary files /dev/null and b/resources/ios/splash/Default-568h@2x~iphone.png differ diff --git a/resources/ios/splash/Default-667h.png b/resources/ios/splash/Default-667h.png new file mode 100644 index 0000000..76f113c Binary files /dev/null and b/resources/ios/splash/Default-667h.png differ diff --git a/resources/ios/splash/Default-736h.png b/resources/ios/splash/Default-736h.png new file mode 100644 index 0000000..d4b3676 Binary files /dev/null and b/resources/ios/splash/Default-736h.png differ diff --git a/resources/ios/splash/Default-Landscape-736h.png b/resources/ios/splash/Default-Landscape-736h.png new file mode 100644 index 0000000..003dba6 Binary files /dev/null and b/resources/ios/splash/Default-Landscape-736h.png differ diff --git a/resources/ios/splash/Default-Landscape@2x~ipad.png b/resources/ios/splash/Default-Landscape@2x~ipad.png new file mode 100644 index 0000000..3378ec9 Binary files /dev/null and b/resources/ios/splash/Default-Landscape@2x~ipad.png differ diff --git a/resources/ios/splash/Default-Landscape@~ipadpro.png b/resources/ios/splash/Default-Landscape@~ipadpro.png new file mode 100644 index 0000000..83badab Binary files /dev/null and b/resources/ios/splash/Default-Landscape@~ipadpro.png differ diff --git a/resources/ios/splash/Default-Landscape~ipad.png b/resources/ios/splash/Default-Landscape~ipad.png new file mode 100644 index 0000000..0ad1e61 Binary files /dev/null and b/resources/ios/splash/Default-Landscape~ipad.png differ diff --git a/resources/ios/splash/Default-Portrait@2x~ipad.png b/resources/ios/splash/Default-Portrait@2x~ipad.png new file mode 100644 index 0000000..cd1b022 Binary files /dev/null and b/resources/ios/splash/Default-Portrait@2x~ipad.png differ diff --git a/resources/ios/splash/Default-Portrait@~ipadpro.png b/resources/ios/splash/Default-Portrait@~ipadpro.png new file mode 100644 index 0000000..8ce773b Binary files /dev/null and b/resources/ios/splash/Default-Portrait@~ipadpro.png differ diff --git a/resources/ios/splash/Default-Portrait~ipad.png b/resources/ios/splash/Default-Portrait~ipad.png new file mode 100644 index 0000000..17d4c4c Binary files /dev/null and b/resources/ios/splash/Default-Portrait~ipad.png differ diff --git a/resources/ios/splash/Default@2x~iphone.png b/resources/ios/splash/Default@2x~iphone.png new file mode 100644 index 0000000..dce73da Binary files /dev/null and b/resources/ios/splash/Default@2x~iphone.png differ diff --git a/resources/ios/splash/Default~iphone.png b/resources/ios/splash/Default~iphone.png new file mode 100644 index 0000000..0b97b1b Binary files /dev/null and b/resources/ios/splash/Default~iphone.png differ diff --git a/resources/splash.png b/resources/splash.png new file mode 100644 index 0000000..04bd72d Binary files /dev/null and b/resources/splash.png differ diff --git a/system.config.js b/system.config.js new file mode 100644 index 0000000..46a0d60 --- /dev/null +++ b/system.config.js @@ -0,0 +1,8 @@ +System.config({ + defaultJSExtensions: true, + paths: { + "*": "*.js", + 'moment': 'lib/moment.js' + } + +}); diff --git a/taco.json b/taco.json new file mode 100644 index 0000000..b372e14 --- /dev/null +++ b/taco.json @@ -0,0 +1,3 @@ +{ + "cordova-cli": "4.3.1" +} diff --git a/tooling/IonicBuild/AODB.keystore b/tooling/IonicBuild/AODB.keystore new file mode 100644 index 0000000..36aa975 Binary files /dev/null and b/tooling/IonicBuild/AODB.keystore differ diff --git a/tooling/IonicBuild/CordovaConfig.json b/tooling/IonicBuild/CordovaConfig.json new file mode 100644 index 0000000..1b9fb5b --- /dev/null +++ b/tooling/IonicBuild/CordovaConfig.json @@ -0,0 +1,18 @@ +{ + "android": { + "debug": { + "keystore": "AODB.keystore", + "storePassword": "Pa55w0rd", + "alias": "AODB", + "password": "Pa55w0rd", + "keystoreType": "" + }, + "release": { + "keystore": "AODB.keystore", + "storePassword": "Pa55w0rd", + "alias": "AODB", + "password": "Pa55w0rd", + "keystoreType": "" + } + } +} \ No newline at end of file diff --git a/tooling/IonicBuild/Ionic-Build.ps1 b/tooling/IonicBuild/Ionic-Build.ps1 new file mode 100644 index 0000000..b482b48 --- /dev/null +++ b/tooling/IonicBuild/Ionic-Build.ps1 @@ -0,0 +1,74 @@ +param( + [String] $Debug = [System.Convert]::ToBoolean('false'), + [String] $VersionOverride = $GITVERSION_NUGETVERSIONV2 +) + +$Debug = [System.Convert]::ToBoolean($Debug) + +function RenameAPK($debug, $VersionOverride, $BuildOutputPath, $CordovaOutputAPK) +{ + $debugAppender = "" + if($debug) + { + $debugAppender = "-debug" + } + + ##Move and Rename the build with either Semantic Versioning or the VersionOverride + if($VersionOverride) + { + $newPackageName = "AODB.Mobile-" + $VersionOverride + $debugAppender + ".apk"; + Rename-Item $BuildOutputPath$CordovaOutputApk $newPackageName + } + elseif($GITVERSION_NUGETVERSIONV2) + { + $newPackageName = "AODB.Mobile-" + $GITVERSION.NUGETVERSIONV2 + $debugAppender + ".apk"; + Rename-Item $BuildOutputPath$CordovaOutputApk $newPackageName + } + else + { + $newPackageName = "PRM.Mobile-0.0.1" + $debugAppender + ".apk" + Rename-Item $BuildOutputPath$CordovaOutputApk $newPackageName + } + + return $newPackageName +} + +function CopyAPK($BuildOutputPath, $PackageName) +{ + if(Test-Path apk) + { + Copy-Item $BuildOutputPath$PackageName apk\$PackageName + } + else + { + New-Item -ItemType Directory apk + Copy-Item $BuildOutputPath$PackageName apk\$PackageName + } +} + +##Reset based on Package.JSON Plugins and Platforms. +ionic state reset + +##Update Config.xml Version +$configXmlPath = "config.xml"; +$xml = [xml](Get-Content $configXmlPath); +$xml.widget.version = $VersionOverride; +$xml.Save($configXmlPath); + +$BuildOutputPath = "platforms\android\build\outputs\apk\" +##Build Release +ionic build --release --buildConfig '.\tooling\IonicBuild\CordovaConfig.json' +$CordovaOutputReleaseApk = "android-release.apk" +$ReleasePackageName = RenameAPK $false $versionOverride $BuildOutputPath $CordovaOutputReleaseApk +CopyAPK $BuildOutputPath $ReleasePackageName + +if($Debug) +{ + ionic build + $CordovaOutputDebugApk = "android-debug.apk" + $DebugPackageName = RenameAPK $true $versionOverride $BuildOutputPath $CordovaOutputDebugApk + CopyAPK $BuildOutputPath $DebugPackageName +} + +exit + diff --git a/tooling/MacBuild/BowerInstall.sh b/tooling/MacBuild/BowerInstall.sh new file mode 100644 index 0000000..54c55e6 --- /dev/null +++ b/tooling/MacBuild/BowerInstall.sh @@ -0,0 +1 @@ +bower install --silent \ No newline at end of file diff --git a/tooling/MacBuild/GitConfig.sh b/tooling/MacBuild/GitConfig.sh new file mode 100644 index 0000000..5a4b2dc --- /dev/null +++ b/tooling/MacBuild/GitConfig.sh @@ -0,0 +1,4 @@ +echo "running gitconfig" +echo pwd + +git config --global url.https://github.com/.insteadOf git://github.com/; git config --system http.sslverify false; \ No newline at end of file diff --git a/tooling/MacBuild/IonicBuildAndroid.sh b/tooling/MacBuild/IonicBuildAndroid.sh new file mode 100644 index 0000000..35b9d64 --- /dev/null +++ b/tooling/MacBuild/IonicBuildAndroid.sh @@ -0,0 +1 @@ +ionic prepare android && ionic build android --device \ No newline at end of file diff --git a/tooling/MacBuild/IonicBuildIos.sh b/tooling/MacBuild/IonicBuildIos.sh new file mode 100644 index 0000000..b8f0953 --- /dev/null +++ b/tooling/MacBuild/IonicBuildIos.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +ionic prepare ios && ionic build ios --device \ No newline at end of file diff --git a/tooling/MacBuild/IonicPlatformAddAndroid.sh b/tooling/MacBuild/IonicPlatformAddAndroid.sh new file mode 100644 index 0000000..c7a0071 --- /dev/null +++ b/tooling/MacBuild/IonicPlatformAddAndroid.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +ionic platform add android + +gulp copy-android-resources \ No newline at end of file diff --git a/tooling/MacBuild/IonicPlatformAddIos.sh b/tooling/MacBuild/IonicPlatformAddIos.sh new file mode 100644 index 0000000..6c204f8 --- /dev/null +++ b/tooling/MacBuild/IonicPlatformAddIos.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +ionic platform add ios \ No newline at end of file diff --git a/tooling/MacBuild/JspmInstall.sh b/tooling/MacBuild/JspmInstall.sh new file mode 100644 index 0000000..01bd21d --- /dev/null +++ b/tooling/MacBuild/JspmInstall.sh @@ -0,0 +1 @@ +jspm install \ No newline at end of file diff --git a/tooling/MacBuild/PhantomJsFix.sh b/tooling/MacBuild/PhantomJsFix.sh new file mode 100644 index 0000000..3f7bc2e --- /dev/null +++ b/tooling/MacBuild/PhantomJsFix.sh @@ -0,0 +1 @@ +npm install phantomjs \ No newline at end of file diff --git a/tooling/MacBuild/RunXcodeWithSigningId.sh b/tooling/MacBuild/RunXcodeWithSigningId.sh new file mode 100644 index 0000000..5876c87 --- /dev/null +++ b/tooling/MacBuild/RunXcodeWithSigningId.sh @@ -0,0 +1 @@ +xcrun -sdk iphoneos PackageApplication -v "/gitrepos/aodb/aodb/platforms/ios/build/device/Aodb Mobile.app" -o "/gitrepos/aodb/aodb/platforms/ios/build/device/AODB Moble.ipa" --embed "chroma_aodb_profile.mobileprovision" --sign "iPhone Developer: Manuel Heidler (T4T24YTS3E)" \ No newline at end of file diff --git a/tooling/MacBuild/gitConfig.sh b/tooling/MacBuild/gitConfig.sh new file mode 100644 index 0000000..5a4b2dc --- /dev/null +++ b/tooling/MacBuild/gitConfig.sh @@ -0,0 +1,4 @@ +echo "running gitconfig" +echo pwd + +git config --global url.https://github.com/.insteadOf git://github.com/; git config --system http.sslverify false; \ No newline at end of file diff --git a/tooling/MacBuild/uploadHockeyApp.sh b/tooling/MacBuild/uploadHockeyApp.sh new file mode 100755 index 0000000..902c2f0 --- /dev/null +++ b/tooling/MacBuild/uploadHockeyApp.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +SOURCE_PATH="/Users/MobileAppsTeam/aodb-vsts-agent/_work/1/s" +# SOURCE_PATH="$HOME/latest_build" +BUILD_DEST="/Users/MobileAppsTeam/aodb-vsts-agent/_work/1/s/platforms/ios" +# BUILD_DEST="$HOME/latest_build/platforms/ios" + +IPA_FILE="AODBMobile.xcarchive" +SYMBOLS="AODBMobile.app.dSYM" + +echo Waiting for $IPA_FILE to complete generation.... + +while ! [ -d "$BUILD_DEST/$IPA_FILE" ]; +do + echo "#" + sleep 3 +done + + +/usr/local/bin/puck -submit=auto -download=true -notify=true -source_path="$SOURCE_PATH" -api_token=d4f642638f554e9296c75af2fadb49ab -app_id=8ca6b61ff4374109b416a476ceb29688 "$BUILD_DEST/$IPA_FILE" diff --git a/tooling/MacBuild/uploadManualHockeyApp.sh b/tooling/MacBuild/uploadManualHockeyApp.sh new file mode 100755 index 0000000..74168c0 --- /dev/null +++ b/tooling/MacBuild/uploadManualHockeyApp.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +#SOURCE_PATH="/Users/MobileAppsTeam/aodb-vsts-agent/_work/1/s" + SOURCE_PATH="$HOME/latest_build" +#BUILD_DEST="/Users/MobileAppsTeam/aodb-vsts-agent/_work/1/s/platforms/ios" + BUILD_DEST="$HOME/latest_build/platforms/ios" + +IPA_FILE="AODBMobile.xcarchive" +SYMBOLS="AODBMobile.app.dSYM" + +echo Waiting for $IPA_FILE to complete generation.... + +while ! [ -d "$BUILD_DEST/$IPA_FILE" ]; +do + echo "#" + sleep 3 +done + + +/usr/local/bin/puck -submit=auto -download=true -notify=true -source_path="$SOURCE_PATH" -api_token=d4f642638f554e9296c75af2fadb49ab -app_id=8ca6b61ff4374109b416a476ceb29688 "$BUILD_DEST/$IPA_FILE" diff --git a/tooling/MacBuild/xcode8.js b/tooling/MacBuild/xcode8.js new file mode 100644 index 0000000..c5d1471 --- /dev/null +++ b/tooling/MacBuild/xcode8.js @@ -0,0 +1,37 @@ +"use strict"; + +var fs = require('fs'); +var path = require('path'); + +module.exports = function(context) { + var encoding = 'utf-8'; + var filepath = 'platforms/ios/cordova/build.xcconfig'; + + if (context.opts.cordova.platforms.indexOf('ios') === -1) return; + if (!context.opts.options) return; + if (!context.opts.options.buildConfig) return; + + + var buildType = context.opts.options.release ? 'release' : 'debug'; + + var buildConfigPath = context.opts.options.buildConfig; + if (!path.isAbsolute(buildConfigPath)) { + buildConfigPath = path.join(context.opts.projectRoot, context.opts.options.buildConfig); + } + var config = require(buildConfigPath); + + + if (!config.ios) return; + if (!config.ios[buildType]) return; + if (!config.ios[buildType].developmentTeam) return; + + + var xcconfig = fs.readFileSync(filepath, encoding); + + if (xcconfig.indexOf('DEVELOPMENT_TEAM') === -1) { + var content = '\nDEVELOPMENT_TEAM = ' + config.ios[buildType].developmentTeam; + + xcconfig += content; + fs.writeFileSync(filepath, xcconfig, encoding); + } +}; \ No newline at end of file diff --git a/tooling/typings/angular-signalr-hub/angular-signalr-hub.d.ts b/tooling/typings/angular-signalr-hub/angular-signalr-hub.d.ts new file mode 100644 index 0000000..03fa642 --- /dev/null +++ b/tooling/typings/angular-signalr-hub/angular-signalr-hub.d.ts @@ -0,0 +1,73 @@ +// Type definitions for angular-signalr-hub v1.5.0 +// Project: https://github.com/JustMaier/angular-signalr-hub +// Definitions by: Adam Santaniello +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + +/// + +declare namespace ngSignalr { + interface HubFactory { + /** + * Creates a new Hub connection + */ + new (hubName: string, options: HubOptions): Hub + } + + class Hub { + hubName: string; + connection: SignalR.Connection; + proxy: SignalR.Hub.Proxy; + + on(event: string, fn: (...args: any[]) => void): void; + invoke(method: string, ...args: any[]): JQueryDeferred; + disconnect(): void; + connect(): JQueryPromise; + } + + interface HubOptions { + /** + * Collection of client side callbacks + */ + listeners?: { [index: string]: (...args: any[]) => void }; + + /** + * String array of server side methods which the client can call + */ + methods?: Array; + + /** + * Sets the root path for the SignalR web service + */ + rootPath?: string; + + /** + * Object representing additional query params to be sent on connection + */ + queryParams?: { [index: string]: string }; + + /** + * Function to handle hub connection errors + */ + errorHandler?: (error: string) => void; + + /** + * Enable/disable logging + */ + logging?: boolean; + + /** + * Use a shared global connection or create a new one just for this hub, defaults to true + */ + useSharedConnection?: boolean; + + /** + * Sets transport method (e.g 'longPolling' or ['webSockets', 'longPolling'] ) + */ + transport?: any; + + /** + * Function to handle hub connection state changed event + */ + stateChanged?: (state: SignalR.StateChanged) => void; + } +} diff --git a/tooling/typings/angular-ui-router/angular-ui-router.d.ts b/tooling/typings/angular-ui-router/angular-ui-router.d.ts new file mode 100644 index 0000000..ff0d6ce --- /dev/null +++ b/tooling/typings/angular-ui-router/angular-ui-router.d.ts @@ -0,0 +1,328 @@ +// Type definitions for Angular JS 1.1.5+ (ui.router module) +// Project: https://github.com/angular-ui/ui-router +// Definitions by: Michel Salib +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +/// + +// Support for AMD require +declare module 'angular-ui-router' { + var _: string; + export = _; +} + +declare module angular.ui { + + interface IState { + name?: string; + /** + * String HTML content, or function that returns an HTML string + */ + template?: string | {(): string}; + /** + * String URL path to template file OR Function, returns URL path string + */ + templateUrl?: string | {(params: IStateParamsService): string}; + /** + * Function, returns HTML content string + */ + templateProvider?: Function | Array; + /** + * A controller paired to the state. Function OR name as String + */ + controller?: Function | string; + controllerAs?: string; + /** + * Function (injectable), returns the actual controller function or string. + */ + controllerProvider?: Function; + + /** + * Specifies the parent state of this state + */ + parent?: string | IState + + + resolve?: {}; + /** + * A url with optional parameters. When a state is navigated or transitioned to, the $stateParams service will be populated with any parameters that were passed. + */ + url?: string | IUrlMatcher; + /** + * A map which optionally configures parameters declared in the url, or defines additional non-url parameters. Only use this within a state if you are not using url. Otherwise you can specify your parameters within the url. When a state is navigated or transitioned to, the $stateParams service will be populated with any parameters that were passed. + */ + params?: any; + /** + * Use the views property to set up multiple views. If you don't need multiple views within a single state this property is not needed. Tip: remember that often nested views are more useful and powerful than multiple sibling views. + */ + views?: {}; + abstract?: boolean; + /** + * Callback function for when a state is entered. Good way to trigger an action or dispatch an event, such as opening a dialog. + * If minifying your scripts, make sure to explicitly annotate this function, because it won't be automatically annotated by your build tools. + */ + onEnter?: Function|(string|Function)[]; + /** + * Callback functions for when a state is entered and exited. Good way to trigger an action or dispatch an event, such as opening a dialog. + * If minifying your scripts, make sure to explicitly annotate this function, because it won't be automatically annotated by your build tools. + */ + onExit?: Function|(string|Function)[]; + /** + * Arbitrary data object, useful for custom configuration. + */ + data?: any; + /** + * Boolean (default true). If false will not re-trigger the same state just because a search/query parameter has changed. Useful for when you'd like to modify $location.search() without triggering a reload. + */ + reloadOnSearch?: boolean; + } + + interface IStateProvider extends angular.IServiceProvider { + state(name:string, config:IState): IStateProvider; + state(config:IState): IStateProvider; + decorator(name?: string, decorator?: (state: IState, parent: Function) => any): any; + } + + interface IUrlMatcher { + concat(pattern: string): IUrlMatcher; + exec(path: string, searchParams: {}): {}; + parameters(): string[]; + format(values: {}): string; + } + + interface IUrlMatcherFactory { + /** + * Creates a UrlMatcher for the specified pattern. + * + * @param pattern {string} The URL pattern. + * + * @returns {IUrlMatcher} The UrlMatcher. + */ + compile(pattern: string): IUrlMatcher; + /** + * Returns true if the specified object is a UrlMatcher, or false otherwise. + * + * @param o {any} The object to perform the type check against. + * + * @returns {boolean} Returns true if the object matches the IUrlMatcher interface, by implementing all the same methods. + */ + isMatcher(o: any): boolean; + /** + * Returns a type definition for the specified name + * + * @param name {string} The type definition name + * + * @returns {IType} The type definition + */ + type(name: string): IType; + /** + * Registers a custom Type object that can be used to generate URLs with typed parameters. + * + * @param {IType} definition The type definition. + * @param {any[]} inlineAnnotedDefinitionFn A function that is injected before the app runtime starts. The result of this function is merged into the existing definition. + * + * @returns {IUrlMatcherFactory} Returns $urlMatcherFactoryProvider. + */ + type(name: string, definition: IType, inlineAnnotedDefinitionFn?: any[]): IUrlMatcherFactory; + /** + * Registers a custom Type object that can be used to generate URLs with typed parameters. + * + * @param {IType} definition The type definition. + * @param {any[]} inlineAnnotedDefinitionFn A function that is injected before the app runtime starts. The result of this function is merged into the existing definition. + * + * @returns {IUrlMatcherFactory} Returns $urlMatcherFactoryProvider. + */ + type(name: string, definition: IType, definitionFn?: (...args:any[]) => IType): IUrlMatcherFactory; + /** + * Defines whether URL matching should be case sensitive (the default behavior), or not. + * + * @param value {boolean} false to match URL in a case sensitive manner; otherwise true; + * + * @returns {boolean} the current value of caseInsensitive + */ + caseInsensitive(value?: boolean): boolean; + /** + * Sets the default behavior when generating or matching URLs with default parameter values + * + * @param value {string} A string that defines the default parameter URL squashing behavior. nosquash: When generating an href with a default parameter value, do not squash the parameter value from the URL slash: When generating an href with a default parameter value, squash (remove) the parameter value, and, if the parameter is surrounded by slashes, squash (remove) one slash from the URL any other string, e.g. "~": When generating an href with a default parameter value, squash (remove) the parameter value from the URL and replace it with this string. + */ + defaultSquashPolicy(value: string): void; + /** + * Defines whether URLs should match trailing slashes, or not (the default behavior). + * + * @param value {boolean} false to match trailing slashes in URLs, otherwise true. + * + * @returns {boolean} the current value of strictMode + */ + strictMode(value?: boolean): boolean; + } + + interface IUrlRouterProvider extends angular.IServiceProvider { + when(whenPath: RegExp, handler: Function): IUrlRouterProvider; + when(whenPath: RegExp, handler: any[]): IUrlRouterProvider; + when(whenPath: RegExp, toPath: string): IUrlRouterProvider; + when(whenPath: IUrlMatcher, hanlder: Function): IUrlRouterProvider; + when(whenPath: IUrlMatcher, handler: any[]): IUrlRouterProvider; + when(whenPath: IUrlMatcher, toPath: string): IUrlRouterProvider; + when(whenPath: string, handler: Function): IUrlRouterProvider; + when(whenPath: string, handler: any[]): IUrlRouterProvider; + when(whenPath: string, toPath: string): IUrlRouterProvider; + otherwise(handler: Function): IUrlRouterProvider; + otherwise(handler: any[]): IUrlRouterProvider; + otherwise(path: string): IUrlRouterProvider; + rule(handler: Function): IUrlRouterProvider; + rule(handler: any[]): IUrlRouterProvider; + /** + * Disables (or enables) deferring location change interception. + * + * If you wish to customize the behavior of syncing the URL (for example, if you wish to defer a transition but maintain the current URL), call this method at configuration time. Then, at run time, call $urlRouter.listen() after you have configured your own $locationChangeSuccess event handler. + * + * @param {boolean} defer Indicates whether to defer location change interception. Passing no parameter is equivalent to true. + */ + deferIntercept(defer?: boolean): void; + } + + interface IStateOptions { + /** + * {boolean=true|string=} - If true will update the url in the location bar, if false will not. If string, must be "replace", which will update url and also replace last history record. + */ + location?: boolean | string; + /** + * {boolean=true}, If true will inherit url parameters from current url. + */ + inherit?: boolean; + /** + * {object=$state.$current}, When transitioning with relative path (e.g '^'), defines which state to be relative from. + */ + relative?: IState; + /** + * {boolean=true}, If true will broadcast $stateChangeStart and $stateChangeSuccess events. + */ + notify?: boolean; + /** + * {boolean=false}, If true will force transition even if the state or params have not changed, aka a reload of the same state. It differs from reloadOnSearch because you'd use this when you want to force a reload when everything is the same, including search params. + */ + reload?: boolean; + } + + interface IHrefOptions { + lossy?: boolean; + inherit?: boolean; + relative?: IState; + absolute?: boolean; + } + + interface IStateService { + /** + * Convenience method for transitioning to a new state. $state.go calls $state.transitionTo internally but automatically sets options to { location: true, inherit: true, relative: $state.$current, notify: true }. This allows you to easily use an absolute or relative to path and specify only the parameters you'd like to update (while letting unspecified parameters inherit from the currently active ancestor states). + * + * @param to Absolute state name or relative state path. Some examples: + * + * $state.go('contact.detail') - will go to the contact.detail state + * $state.go('^') - will go to a parent state + * $state.go('^.sibling') - will go to a sibling state + * $state.go('.child.grandchild') - will go to grandchild state + * + * @param params A map of the parameters that will be sent to the state, will populate $stateParams. Any parameters that are not specified will be inherited from currently defined parameters. This allows, for example, going to a sibling state that shares parameters specified in a parent state. Parameter inheritance only works between common ancestor states, I.e. transitioning to a sibling will get you the parameters for all parents, transitioning to a child will get you all current parameters, etc. + * + * @param options Options object. + */ + go(to: string, params?: {}, options?: IStateOptions): angular.IPromise; + go(to: IState, params?: {}, options?: IStateOptions): angular.IPromise; + transitionTo(state: string, params?: {}, updateLocation?: boolean): void; + transitionTo(state: IState, params?: {}, updateLocation?: boolean): void; + transitionTo(state: string, params?: {}, options?: IStateOptions): void; + transitionTo(state: IState, params?: {}, options?: IStateOptions): void; + includes(state: string, params?: {}): boolean; + is(state:string, params?: {}): boolean; + is(state: IState, params?: {}): boolean; + href(state: IState, params?: {}, options?: IHrefOptions): string; + href(state: string, params?: {}, options?: IHrefOptions): string; + get(state: string): IState; + get(): IState[]; + current: IState; + params: IStateParamsService; + reload(): void; + + $current: IResolvedState; + } + + interface IResolvedState { + locals: { + /** + * Currently resolved "resolve" values from the current state + */ + globals: { [key: string]: any; }; + }; + } + + interface IStateParamsService { + [key: string]: any; + } + + interface IUrlRouterService { + /* + * Triggers an update; the same update that happens when the address bar + * url changes, aka $locationChangeSuccess. + * + * This method is useful when you need to use preventDefault() on the + * $locationChangeSuccess event, perform some custom logic (route protection, + * auth, config, redirection, etc) and then finally proceed with the transition + * by calling $urlRouter.sync(). + * + */ + sync(): void; + listen(): void; + } + + interface IUiViewScrollProvider { + /* + * Reverts back to using the core $anchorScroll service for scrolling + * based on the url anchor. + */ + useAnchorScroll(): void; + } + + interface IType { + /** + * Converts a parameter value (from URL string or transition param) to a custom/native value. + * + * @param val {string} The URL parameter value to decode. + * @param key {string} The name of the parameter in which val is stored. Can be used for meta-programming of Type objects. + * + * @returns {any} Returns a custom representation of the URL parameter value. + */ + decode(val: string, key: string): any; + /** + * Encodes a custom/native type value to a string that can be embedded in a URL. Note that the return value does not need to be URL-safe (i.e. passed through encodeURIComponent()), it only needs to be a representation of val that has been coerced to a string. + * + * @param val {any} The value to encode. + * @param key {string} The name of the parameter in which val is stored. Can be used for meta-programming of Type objects. + * + * @returns {string} Returns a string representation of val that can be encoded in a URL. + */ + encode(val: any, key: string): string; + /** + * Determines whether two decoded values are equivalent. + * + * @param a {any} A value to compare against. + * @param b {any} A value to compare against. + * + * @returns {boolean} Returns true if the values are equivalent/equal, otherwise false. + */ + equals? (a: any, b: any): boolean; + /** + * Detects whether a value is of a particular type. Accepts a native (decoded) value and determines whether it matches the current Type object. + * + * @param val {any} The value to check. + * @param key {any} Optional. If the type check is happening in the context of a specific UrlMatcher object, this is the name of the parameter in which val is stored. Can be used for meta-programming of Type objects. + * + * @returns {boolean} Returns true if the value matches the type, otherwise false. + */ + is(val: any, key: string): boolean; + /** + * The regular expression pattern used to match values of this type when coming from a substring of a URL. + */ + pattern?: RegExp; + } +} diff --git a/tooling/typings/angularjs/angular-animate.d.ts b/tooling/typings/angularjs/angular-animate.d.ts new file mode 100644 index 0000000..35fe10c --- /dev/null +++ b/tooling/typings/angularjs/angular-animate.d.ts @@ -0,0 +1,261 @@ +// Type definitions for Angular JS 1.3 (ngAnimate module) +// Project: http://angularjs.org +// Definitions by: Michel Salib , Adi Dahiya , Raphael Schweizer , Cody Schaaf +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +/// + +declare module "angular-animate" { + var _: string; + export = _; +} + +/** + * ngAnimate module (angular-animate.js) + */ +declare module angular.animate { + interface IAnimateFactory extends Function { + enter?: (element: ng.IAugmentedJQuery, doneFn: Function) => IAnimateCssRunner|void; + leave?: (element: ng.IAugmentedJQuery, doneFn: Function) => IAnimateCssRunner|void; + addClass?: (element: ng.IAugmentedJQuery, className: string, doneFn: Function) => IAnimateCssRunner|void; + removeClass?: (element: ng.IAugmentedJQuery, className: string, doneFn: Function) => IAnimateCssRunner|void; + setClass?: (element: ng.IAugmentedJQuery, className: string, doneFn: Function) => IAnimateCssRunner|void; + } + + /** + * AnimateService + * see http://docs.angularjs.org/api/ngAnimate/service/$animate + */ + interface IAnimateService extends angular.IAnimateService { + /** + * Globally enables / disables animations. + * + * @param element If provided then the element will be used to represent the enable/disable operation. + * @param value If provided then set the animation on or off. + * @returns current animation state + */ + enabled(element?: JQuery, value?: boolean): boolean; + + /** + * Performs an inline animation on the element. + * + * @param element the element that will be the focus of the animation + * @param from a collection of CSS styles that will be applied to the element at the start of the animation + * @param to a collection of CSS styles that the element will animate towards + * @param className an optional CSS class that will be added to the element for the duration of the animation (the default class is 'ng-inline-animate') + * @param options an optional collection of styles that will be picked up by the CSS transition/animation + * @returns the animation callback promise + */ + animate(element: JQuery, from: any, to: any, className?: string, options?: IAnimationOptions): IPromise; + + /** + * Appends the element to the parentElement element that resides in the document and then runs the enter animation. + * + * @param element the element that will be the focus of the enter animation + * @param parentElement the parent element of the element that will be the focus of the enter animation + * @param afterElement the sibling element (which is the previous element) of the element that will be the focus of the enter animation + * @param options an optional collection of styles that will be picked up by the CSS transition/animation + * @returns the animation callback promise + */ + enter(element: JQuery, parentElement: JQuery, afterElement?: JQuery, options?: IAnimationOptions): IPromise; + + /** + * Runs the leave animation operation and, upon completion, removes the element from the DOM. + * + * @param element the element that will be the focus of the leave animation + * @param options an optional collection of styles that will be picked up by the CSS transition/animation + * @returns the animation callback promise + */ + leave(element: JQuery, options?: IAnimationOptions): IPromise; + + /** + * Fires the move DOM operation. Just before the animation starts, the animate service will either append + * it into the parentElement container or add the element directly after the afterElement element if present. + * Then the move animation will be run. + * + * @param element the element that will be the focus of the move animation + * @param parentElement the parent element of the element that will be the focus of the move animation + * @param afterElement the sibling element (which is the previous element) of the element that will be the focus of the move animation + * @returns the animation callback promise + */ + move(element: JQuery, parentElement: JQuery, afterElement?: JQuery): IPromise; + + /** + * Triggers a custom animation event based off the className variable and then attaches the className + * value to the element as a CSS class. + * + * @param element the element that will be animated + * @param className the CSS class that will be added to the element and then animated + * @param options an optional collection of styles that will be picked up by the CSS transition/animation + * @returns the animation callback promise + */ + addClass(element: JQuery, className: string, options?: IAnimationOptions): IPromise; + + /** + * Triggers a custom animation event based off the className variable and then removes the CSS class + * provided by the className value from the element. + * + * @param element the element that will be animated + * @param className the CSS class that will be animated and then removed from the element + * @param options an optional collection of styles that will be picked up by the CSS transition/animation + * @returns the animation callback promise + */ + removeClass(element: JQuery, className: string, options?: IAnimationOptions): IPromise; + + /** + * Adds and/or removes the given CSS classes to and from the element. Once complete, the done() callback + * will be fired (if provided). + * + * @param element the element which will have its CSS classes changed removed from it + * @param add the CSS classes which will be added to the element + * @param remove the CSS class which will be removed from the element CSS classes have been set on the element + * @param options an optional collection of styles that will be picked up by the CSS transition/animation + * @returns the animation callback promise + */ + setClass(element: JQuery, add: string, remove: string, options?: IAnimationOptions): IPromise; + + /** + * Cancels the provided animation. + */ + cancel(animationPromise: IPromise): void; + } + + /** + * AngularProvider + * see http://docs.angularjs.org/api/ngAnimate/provider/$animateProvider + */ + interface IAnimateProvider { + /** + * Registers a new injectable animation factory function. + * + * @param name The name of the animation. + * @param factory The factory function that will be executed to return the animation object. + */ + register(name: string, factory: () => IAnimateCallbackObject): void; + + /** + * Gets and/or sets the CSS class expression that is checked when performing an animation. + * + * @param expression The className expression which will be checked against all animations. + * @returns The current CSS className expression value. If null then there is no expression value. + */ + classNameFilter(expression?: RegExp): RegExp; + } + + /** + * Angular Animation Options + * see https://docs.angularjs.org/api/ngAnimate/#applying-directive-specific-styles-to-an-animation + */ + interface IAnimationOptions { + /** + * The ending CSS styles (a key/value object) that will be applied across the animation via a CSS transition. + */ + to?: Object; + + /** + * The starting CSS styles (a key/value object) that will be applied at the start of the animation. + */ + from?: Object; + + /** + * The DOM event (e.g. enter, leave, move). When used, a generated CSS class of ng-EVENT and + * ng-EVENT-active will be applied to the element during the animation. Multiple events can be provided when + * spaces are used as a separator. (Note that this will not perform any DOM operation.) + */ + event?: string; + + /** + * The CSS easing value that will be applied to the transition or keyframe animation (or both). + */ + easing?: string; + + /** + * The raw CSS transition style that will be used (e.g. 1s linear all). + */ + transition?: string; + + /** + * The raw CSS keyframe animation style that will be used (e.g. 1s my_animation linear). + */ + keyframe?: string; + + /** + * A space separated list of CSS classes that will be added to the element and spread across the animation. + */ + addClass?: string; + + /** + * A space separated list of CSS classes that will be removed from the element and spread across + * the animation. + */ + removeClass?: string; + + /** + * A number value representing the total duration of the transition and/or keyframe (note that a value + * of 1 is 1000ms). If a value of 0 is provided then the animation will be skipped entirely. + */ + duration?: number; + + /** + * A number value representing the total delay of the transition and/or keyframe (note that a value of + * 1 is 1000ms). If a value of true is used then whatever delay value is detected from the CSS classes will be + * mirrored on the elements styles (e.g. by setting delay true then the style value of the element will be + * transition-delay: DETECTED_VALUE). Using true is useful when you want the CSS classes and inline styles to + * all share the same CSS delay value. + */ + delay?: number; + + /** + * A numeric time value representing the delay between successively animated elements (Click here to + * learn how CSS-based staggering works in ngAnimate.) + */ + stagger?: number; + + /** + * The numeric index representing the stagger item (e.g. a value of 5 is equal to the sixth item + * in the stagger; therefore when a stagger option value of 0.1 is used then there will be a stagger delay of 600ms) + * applyClassesEarly - Whether or not the classes being added or removed will be used when detecting the animation. + * This is set by $animate when enter/leave/move animations are fired to ensure that the CSS classes are resolved in time. + * (Note that this will prevent any transitions from occuring on the classes being added and removed.) + */ + staggerIndex?: number; + } + + interface IAnimateCssRunner { + /** + * Starts the animation + * + * @returns The animation runner with a done function for supplying a callback. + */ + start(): IAnimateCssRunnerStart; + + /** + * Ends (aborts) the animation + */ + end(): void; + } + + interface IAnimateCssRunnerStart extends IPromise { + /** + * Allows you to add done callbacks to the running animation + * + * @param callbackFn: the callback function to be run + */ + done(callbackFn: (animationFinished: boolean) => void): void; + } + + /** + * AnimateCssService + * see http://docs.angularjs.org/api/ngAnimate/service/$animateCss + */ + interface IAnimateCssService { + (element: JQuery, animateCssOptions: IAnimationOptions): IAnimateCssRunner; + } + +} + +declare module angular { + interface IModule { + animate(cssSelector: string, animateFactory: angular.animate.IAnimateFactory): IModule; + } +} diff --git a/tooling/typings/angularjs/angular-cookies.d.ts b/tooling/typings/angularjs/angular-cookies.d.ts new file mode 100644 index 0000000..ec14bd7 --- /dev/null +++ b/tooling/typings/angularjs/angular-cookies.d.ts @@ -0,0 +1,63 @@ +// Type definitions for Angular JS 1.4 (ngCookies module) +// Project: http://angularjs.org +// Definitions by: Diego Vilar , Anthony Ciccarello +// Definitions: https://github.com/borisyankov/DefinitelyTyped + + +/// + +declare module "angular-cookies" { + var _: string; + export = _; +} + +/** + * ngCookies module (angular-cookies.js) + */ +declare module angular.cookies { + + /** + * CookieService + * see http://docs.angularjs.org/api/ngCookies.$cookies + */ + interface ICookiesService { + [index: string]: any; + } + + /** + * CookieStoreService + * see http://docs.angularjs.org/api/ngCookies.$cookieStore + */ + // interface ICookiesService { + // get(key: string): string; + // getObject(key: string): any; + // getAll(): any; + // put(key: string, value: string, options?: any): void; + // putObject(key: string, value: any, options?: any): void; + // remove(key: string, options?: any): void; + // } + + /** + * CookieStoreService DEPRECATED + * see https://code.angularjs.org/1.2.26/docs/api/ngCookies/service/$cookieStore + */ + interface ICookieStoreService { + /** + * Returns the value of given cookie key + * @param key Id to use for lookup + */ + get(key: string): any; + /** + * Sets a value for given cookie key + * @param key Id for the value + * @param value Value to be stored + */ + put(key: string, value: any): void; + /** + * Remove given cookie + * @param key Id of the key-value pair to delete + */ + remove(key: string): void; + } + +} diff --git a/tooling/typings/angularjs/angular-mocks.d.ts b/tooling/typings/angularjs/angular-mocks.d.ts new file mode 100644 index 0000000..3113881 --- /dev/null +++ b/tooling/typings/angularjs/angular-mocks.d.ts @@ -0,0 +1,318 @@ +// Type definitions for Angular JS 1.3 (ngMock, ngMockE2E module) +// Project: http://angularjs.org +// Definitions by: Diego Vilar , Tony Curtis +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +/// + +declare module "angular-mocks/ngMock" { + var _: string; + export = _; +} + +declare module "angular-mocks/ngMockE2E" { + var _: string; + export = _; +} + +declare module "angular-mocks/ngAnimateMock" { + var _: string; + export = _; +} + +/////////////////////////////////////////////////////////////////////////////// +// ngMock module (angular-mocks.js) +/////////////////////////////////////////////////////////////////////////////// +declare module angular { + + /////////////////////////////////////////////////////////////////////////// + // AngularStatic + // We reopen it to add the MockStatic definition + /////////////////////////////////////////////////////////////////////////// + interface IAngularStatic { + mock: IMockStatic; + } + + // see https://docs.angularjs.org/api/ngMock/function/angular.mock.inject + interface IInjectStatic { + (...fns: Function[]): any; + (...inlineAnnotatedConstructor: any[]): any; // this overload is undocumented, but works + strictDi(val?: boolean): void; + } + + interface IMockStatic { + // see https://docs.angularjs.org/api/ngMock/function/angular.mock.dump + dump(obj: any): string; + + inject: IInjectStatic + + // see https://docs.angularjs.org/api/ngMock/function/angular.mock.module + module(...modules: any[]): any; + + // see https://docs.angularjs.org/api/ngMock/type/angular.mock.TzDate + TzDate(offset: number, timestamp: number): Date; + TzDate(offset: number, timestamp: string): Date; + } + + /////////////////////////////////////////////////////////////////////////// + // ExceptionHandlerService + // see https://docs.angularjs.org/api/ngMock/service/$exceptionHandler + // see https://docs.angularjs.org/api/ngMock/provider/$exceptionHandlerProvider + /////////////////////////////////////////////////////////////////////////// + interface IExceptionHandlerProvider extends IServiceProvider { + mode(mode: string): void; + } + + /////////////////////////////////////////////////////////////////////////// + // TimeoutService + // see https://docs.angularjs.org/api/ngMock/service/$timeout + // Augments the original service + /////////////////////////////////////////////////////////////////////////// + interface ITimeoutService { + flush(delay?: number): void; + flushNext(expectedDelay?: number): void; + verifyNoPendingTasks(): void; + } + + /////////////////////////////////////////////////////////////////////////// + // IntervalService + // see https://docs.angularjs.org/api/ngMock/service/$interval + // Augments the original service + /////////////////////////////////////////////////////////////////////////// + interface IIntervalService { + flush(millis?: number): number; + } + + /////////////////////////////////////////////////////////////////////////// + // LogService + // see https://docs.angularjs.org/api/ngMock/service/$log + // Augments the original service + /////////////////////////////////////////////////////////////////////////// + interface ILogService { + assertEmpty(): void; + reset(): void; + } + + interface ILogCall { + logs: string[]; + } + + /////////////////////////////////////////////////////////////////////////// + // HttpBackendService + // see https://docs.angularjs.org/api/ngMock/service/$httpBackend + /////////////////////////////////////////////////////////////////////////// + interface IHttpBackendService { + /** + * Flushes all pending requests using the trained responses. + * @param count Number of responses to flush (in the order they arrived). If undefined, all pending requests will be flushed. + */ + flush(count?: number): void; + + /** + * Resets all request expectations, but preserves all backend definitions. + */ + resetExpectations(): void; + + /** + * Verifies that all of the requests defined via the expect api were made. If any of the requests were not made, verifyNoOutstandingExpectation throws an exception. + */ + verifyNoOutstandingExpectation(): void; + + /** + * Verifies that there are no outstanding requests that need to be flushed. + */ + verifyNoOutstandingRequest(): void; + + /** + * Creates a new request expectation. + * Throws a preformatted error if expectation(s) don't match supplied string, regular expression, object, or if function returns false. + * Returns an object with respond method that controls how a matched request is handled. + * @param method HTTP method. + * @param url HTTP url string, regular expression or function that receives a url and returns true if the url matches the current expctation. + * @param data HTTP request body string, json object, regular expression or function that receives the data and returns true if the data matches the current expectation. + * @param headers HTTP headers object or function that receives the headers and returns true if the headers match the current expectation. + */ + expect(method: string, url: string | RegExp | ((url: string) => boolean), data?: string | RegExp | Object | ((data: string) => boolean), headers?: Object | ((object: Object) => boolean)) :mock.IRequestHandler; + + /** + * Creates a new request expectation for DELETE requests. + * Throws a preformatted error if expectation(s) don't match supplied string, regular expression, object, or if function returns false. + * Returns an object with respond method that controls how a matched request is handled. + * @param url HTTP url string, regular expression or function that receives a url and returns true if the url is as expected. + * @param headers HTTP headers object to be compared with the HTTP headers in the request. + */ + expectDELETE(url: string | RegExp | ((url: string) => boolean), headers?: Object): mock.IRequestHandler; + + /** + * Creates a new request expectation for GET requests. + * Throws a preformatted error if expectation(s) don't match supplied string, regular expression, object, or if function returns false. + * Returns an object with respond method that controls how a matched request is handled. + * @param url HTTP url string, regular expression or function that receives a url and returns true if the url matches the current expctation. + * @param headers HTTP headers object to be compared with the HTTP headers in the request. + */ + expectGET(url: string | RegExp | ((url: string) => boolean), headers?: Object): mock.IRequestHandler; + + /** + * Creates a new request expectation for HEAD requests. + * Throws a preformatted error if expectation(s) don't match supplied string, regular expression, object, or if function returns false. + * Returns an object with respond method that controls how a matched request is handled. + * @param url HTTP url string, regular expression or function that receives a url and returns true if the url matches the current expctation. + * @param headers HTTP headers object to be compared with the HTTP headers in the request. + */ + expectHEAD(url: string | RegExp | ((url: string) => boolean), headers?: Object): mock.IRequestHandler; + + /** + * Creates a new request expectation for JSONP requests. + * Throws a preformatted error if expectation(s) don't match supplied string, regular expression, or if function returns false. + * Returns an object with respond method that controls how a matched request is handled. + * @param url HTTP url string, regular expression or function that receives a url and returns true if the url matches the current expctation. + */ + expectJSONP(url: string | RegExp | ((url: string) => boolean)): mock.IRequestHandler; + + /** + * Creates a new request expectation for PATCH requests. + * Throws a preformatted error if expectation(s) don't match supplied string, regular expression, object, or if function returns false. + * Returns an object with respond method that controls how a matched request is handled. + * @param url HTTP url string, regular expression or function that receives a url and returns true if the url matches the current expctation. + * @param data HTTP request body string, json object, regular expression or function that receives the data and returns true if the data matches the current expectation. + * @param headers HTTP headers object or function that receives the headers and returns true if the headers match the current expectation. + */ + expectPATCH(url: string | RegExp | ((url: string) => boolean), data?: string | RegExp | Object | ((data: string) => boolean), headers?: Object): mock.IRequestHandler; + + /** + * Creates a new request expectation for POST requests. + * Throws a preformatted error if expectation(s) don't match supplied string, regular expression, object, or if function returns false. + * Returns an object with respond method that controls how a matched request is handled. + * @param url HTTP url string, regular expression or function that receives a url and returns true if the url matches the current expctation. + * @param data HTTP request body string, json object, regular expression or function that receives the data and returns true if the data matches the current expectation. + * @param headers HTTP headers object or function that receives the headers and returns true if the headers match the current expectation. + */ + expectPOST(url: string | RegExp | ((url: string) => boolean), data?: string | RegExp | Object | ((data: string) => boolean), headers?: Object): mock.IRequestHandler; + + /** + * Creates a new request expectation for PUT requests. + * Throws a preformatted error if expectation(s) don't match supplied string, regular expression, object, or if function returns false. + * Returns an object with respond method that controls how a matched request is handled. + * @param url HTTP url string, regular expression or function that receives a url and returns true if the url matches the current expctation. + * @param data HTTP request body string, json object, regular expression or function that receives the data and returns true if the data matches the current expectation. + * @param headers HTTP headers object or function that receives the headers and returns true if the headers match the current expectation. + */ + expectPUT(url: string | RegExp | ((url: string) => boolean), data?: string | RegExp | Object | ((data: string) => boolean), headers?: Object): mock.IRequestHandler; + + /** + * Creates a new backend definition. + * Returns an object with respond method that controls how a matched request is handled. + * @param method HTTP method. + * @param url HTTP url string, regular expression or function that receives a url and returns true if the url matches the current expctation. + * @param data HTTP request body string, json object, regular expression or function that receives the data and returns true if the data matches the current expectation. + * @param headers HTTP headers object or function that receives the headers and returns true if the headers match the current expectation. + */ + when(method: string, url: string | RegExp | ((url: string) => boolean), data?: string | RegExp | Object | ((data: string) => boolean), headers?: Object | ((object: Object) => boolean)): mock.IRequestHandler; + + /** + * Creates a new backend definition for DELETE requests. + * Returns an object with respond method that controls how a matched request is handled. + * @param url HTTP url string, regular expression or function that receives a url and returns true if the url matches the current expctation. + * @param headers HTTP headers object or function that receives the headers and returns true if the headers match the current expectation. + */ + whenDELETE(url: string | RegExp | ((url: string) => boolean), headers?: Object | ((object: Object) => boolean)): mock.IRequestHandler; + + /** + * Creates a new backend definition for GET requests. + * Returns an object with respond method that controls how a matched request is handled. + * @param url HTTP url string, regular expression or function that receives a url and returns true if the url matches the current expctation. + * @param headers HTTP headers object or function that receives the headers and returns true if the headers match the current expectation. + */ + whenGET(url: string | RegExp | ((url: string) => boolean), headers?: Object | ((object: Object) => boolean)): mock.IRequestHandler; + + /** + * Creates a new backend definition for HEAD requests. + * Returns an object with respond method that controls how a matched request is handled. + * @param url HTTP url string, regular expression or function that receives a url and returns true if the url matches the current expctation. + * @param headers HTTP headers object or function that receives the headers and returns true if the headers match the current expectation. + */ + whenHEAD(url: string | RegExp | ((url: string) => boolean), headers?: Object | ((object: Object) => boolean)): mock.IRequestHandler; + + /** + * Creates a new backend definition for JSONP requests. + * Returns an object with respond method that controls how a matched request is handled. + * @param url HTTP url string, regular expression or function that receives a url and returns true if the url matches the current expctation. + * @param headers HTTP headers object or function that receives the headers and returns true if the headers match the current expectation. + */ + whenJSONP(url: string | RegExp | ((url: string) => boolean)): mock.IRequestHandler; + + /** + * Creates a new backend definition for PATCH requests. + * Returns an object with respond method that controls how a matched request is handled. + * @param url HTTP url string, regular expression or function that receives a url and returns true if the url matches the current expctation. + * @param data HTTP request body string, json object, regular expression or function that receives the data and returns true if the data matches the current expectation. + * @param headers HTTP headers object or function that receives the headers and returns true if the headers match the current expectation. + */ + whenPATCH(url: string | RegExp | ((url: string) => boolean), data?: string | RegExp | Object | ((data: string) => boolean), headers?: Object | ((object: Object) => boolean)): mock.IRequestHandler; + + /** + * Creates a new backend definition for POST requests. + * Returns an object with respond method that controls how a matched request is handled. + * @param url HTTP url string, regular expression or function that receives a url and returns true if the url matches the current expctation. + * @param data HTTP request body string, json object, regular expression or function that receives the data and returns true if the data matches the current expectation. + * @param headers HTTP headers object or function that receives the headers and returns true if the headers match the current expectation. + */ + whenPOST(url: string | RegExp | ((url: string) => boolean), data?: string | RegExp | Object | ((data: string) => boolean), headers?: Object | ((object: Object) => boolean)): mock.IRequestHandler; + + /** + * Creates a new backend definition for PUT requests. + * Returns an object with respond method that controls how a matched request is handled. + * @param url HTTP url string, regular expression or function that receives a url and returns true if the url matches the current expctation. + * @param data HTTP request body string, json object, regular expression or function that receives the data and returns true if the data matches the current expectation. + * @param headers HTTP headers object or function that receives the headers and returns true if the headers match the current expectation. + */ + whenPUT(url: string | RegExp | ((url: string) => boolean), data?: string | RegExp | Object | ((data: string) => boolean), headers?: Object | ((object: Object) => boolean)): mock.IRequestHandler; + } + + export module mock { + // returned interface by the the mocked HttpBackendService expect/when methods + interface IRequestHandler { + + /** + * Controls the response for a matched request using a function to construct the response. + * Returns the RequestHandler object for possible overrides. + * @param func Function that receives the request HTTP method, url, data, and headers and returns an array containing response status (number), data, headers, and status text. + */ + respond(func: ((method: string, url: string, data: string | Object, headers: Object) => [number, string | Object, Object, string])): IRequestHandler; + + /** + * Controls the response for a matched request using supplied static data to construct the response. + * Returns the RequestHandler object for possible overrides. + * @param status HTTP status code to add to the response. + * @param data Data to add to the response. + * @param headers Headers object to add to the response. + * @param responseText Response text to add to the response. + */ + respond(status: number, data: string | Object, headers?: Object, responseText?: string): IRequestHandler; + + /** + * Controls the response for a matched request using the HTTP status code 200 and supplied static data to construct the response. + * Returns the RequestHandler object for possible overrides. + * @param data Data to add to the response. + * @param headers Headers object to add to the response. + * @param responseText Response text to add to the response. + */ + respond(data: string | Object, headers?: Object, responseText?: string): IRequestHandler; + + // Available when ngMockE2E is loaded + /** + * Any request matching a backend definition or expectation with passThrough handler will be passed through to the real backend (an XHR request will be made to the server.) + */ + passThrough(): IRequestHandler; + } + + } + +} + +/////////////////////////////////////////////////////////////////////////////// +// functions attached to global object (window) +/////////////////////////////////////////////////////////////////////////////// +//Use `angular.mock.module` instead of `module`, as `module` conflicts with commonjs. +//declare var module: (...modules: any[]) => any; +declare var inject: angular.IInjectStatic; diff --git a/tooling/typings/angularjs/angular-resource.d.ts b/tooling/typings/angularjs/angular-resource.d.ts new file mode 100644 index 0000000..4688a9c --- /dev/null +++ b/tooling/typings/angularjs/angular-resource.d.ts @@ -0,0 +1,171 @@ +// Type definitions for Angular JS 1.3 (ngResource module) +// Project: http://angularjs.org +// Definitions by: Diego Vilar , Michael Jess +// Definitions: https://github.com/daptiv/DefinitelyTyped + +/// + + +/////////////////////////////////////////////////////////////////////////////// +// ngResource module (angular-resource.js) +/////////////////////////////////////////////////////////////////////////////// +declare module angular.resource { + + /** + * Currently supported options for the $resource factory options argument. + */ + interface IResourceOptions { + /** + * If true then the trailing slashes from any calculated URL will be stripped (defaults to true) + */ + stripTrailingSlashes?: boolean; + } + + + /////////////////////////////////////////////////////////////////////////// + // ResourceService + // see http://docs.angularjs.org/api/ngResource.$resource + // Most part of the following definitions were achieved by analyzing the + // actual implementation, since the documentation doesn't seem to cover + // that deeply. + /////////////////////////////////////////////////////////////////////////// + interface IResourceService { + (url: string, paramDefaults?: any, + /** example: {update: { method: 'PUT' }, delete: deleteDescriptor } + where deleteDescriptor : IActionDescriptor */ + actions?: any, options?: IResourceOptions): IResourceClass>; + (url: string, paramDefaults?: any, + /** example: {update: { method: 'PUT' }, delete: deleteDescriptor } + where deleteDescriptor : IActionDescriptor */ + actions?: any, options?: IResourceOptions): U; + (url: string, paramDefaults?: any, + /** example: {update: { method: 'PUT' }, delete: deleteDescriptor } + where deleteDescriptor : IActionDescriptor */ + actions?: any, options?: IResourceOptions): IResourceClass; + } + + // Just a reference to facilitate describing new actions + interface IActionDescriptor { + url?: string; + method: string; + isArray?: boolean; + params?: any; + headers?: any; + } + + // Baseclass for everyresource with default actions. + // If you define your new actions for the resource, you will need + // to extend this interface and typecast the ResourceClass to it. + // + // In case of passing the first argument as anything but a function, + // it's gonna be considered data if the action method is POST, PUT or + // PATCH (in other words, methods with body). Otherwise, it's going + // to be considered as parameters to the request. + // https://github.com/angular/angular.js/blob/v1.2.0/src/ngResource/resource.js#L461-L465 + // + // Only those methods with an HTTP body do have 'data' as first parameter: + // https://github.com/angular/angular.js/blob/v1.2.0/src/ngResource/resource.js#L463 + // More specifically, those methods are POST, PUT and PATCH: + // https://github.com/angular/angular.js/blob/v1.2.0/src/ngResource/resource.js#L432 + // + // Also, static calls always return the IResource (or IResourceArray) retrieved + // https://github.com/angular/angular.js/blob/v1.2.0/src/ngResource/resource.js#L538-L549 + interface IResourceClass { + new(dataOrParams? : any) : T; + get(): T; + get(params: Object): T; + get(success: Function, error?: Function): T; + get(params: Object, success: Function, error?: Function): T; + get(params: Object, data: Object, success?: Function, error?: Function): T; + + query(): IResourceArray; + query(params: Object): IResourceArray; + query(success: Function, error?: Function): IResourceArray; + query(params: Object, success: Function, error?: Function): IResourceArray; + query(params: Object, data: Object, success?: Function, error?: Function): IResourceArray; + + save(): T; + save(data: Object): T; + save(success: Function, error?: Function): T; + save(data: Object, success: Function, error?: Function): T; + save(params: Object, data: Object, success?: Function, error?: Function): T; + + remove(): T; + remove(params: Object): T; + remove(success: Function, error?: Function): T; + remove(params: Object, success: Function, error?: Function): T; + remove(params: Object, data: Object, success?: Function, error?: Function): T; + + delete(): T; + delete(params: Object): T; + delete(success: Function, error?: Function): T; + delete(params: Object, success: Function, error?: Function): T; + delete(params: Object, data: Object, success?: Function, error?: Function): T; + } + + // Instance calls always return the the promise of the request which retrieved the object + // https://github.com/angular/angular.js/blob/v1.2.0/src/ngResource/resource.js#L538-L546 + interface IResource { + $get(): angular.IPromise; + $get(params?: Object, success?: Function, error?: Function): angular.IPromise; + $get(success: Function, error?: Function): angular.IPromise; + + $query(): angular.IPromise>; + $query(params?: Object, success?: Function, error?: Function): angular.IPromise>; + $query(success: Function, error?: Function): angular.IPromise>; + + $save(): angular.IPromise; + $save(params?: Object, success?: Function, error?: Function): angular.IPromise; + $save(success: Function, error?: Function): angular.IPromise; + + $remove(): angular.IPromise; + $remove(params?: Object, success?: Function, error?: Function): angular.IPromise; + $remove(success: Function, error?: Function): angular.IPromise; + + $delete(): angular.IPromise; + $delete(params?: Object, success?: Function, error?: Function): angular.IPromise; + $delete(success: Function, error?: Function): angular.IPromise; + + /** the promise of the original server interaction that created this instance. **/ + $promise : angular.IPromise; + $resolved : boolean; + } + + /** + * Really just a regular Array object with $promise and $resolve attached to it + */ + interface IResourceArray extends Array { + /** the promise of the original server interaction that created this collection. **/ + $promise : angular.IPromise>; + $resolved : boolean; + } + + /** when creating a resource factory via IModule.factory */ + interface IResourceServiceFactoryFunction { + ($resource: angular.resource.IResourceService): IResourceClass; + >($resource: angular.resource.IResourceService): U; + } + + // IResourceServiceProvider used to configure global settings + interface IResourceServiceProvider extends angular.IServiceProvider { + + defaults: IResourceOptions; + } + +} + +/** extensions to base ng based on using angular-resource */ +declare module angular { + + interface IModule { + /** creating a resource service factory */ + factory(name: string, resourceServiceFactoryFunction: angular.resource.IResourceServiceFactoryFunction): IModule; + } +} + +interface Array +{ + /** the promise of the original server interaction that created this collection. **/ + $promise : angular.IPromise>; + $resolved : boolean; +} diff --git a/tooling/typings/angularjs/angular-route.d.ts b/tooling/typings/angularjs/angular-route.d.ts new file mode 100644 index 0000000..662b2c1 --- /dev/null +++ b/tooling/typings/angularjs/angular-route.d.ts @@ -0,0 +1,142 @@ +// Type definitions for Angular JS 1.3 (ngRoute module) +// Project: http://angularjs.org +// Definitions by: Jonathan Park +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +/// + +declare module "angular-route" { + var _: string; + export = _; +} + +/////////////////////////////////////////////////////////////////////////////// +// ngRoute module (angular-route.js) +/////////////////////////////////////////////////////////////////////////////// +declare module angular.route { + + /////////////////////////////////////////////////////////////////////////// + // RouteParamsService + // see http://docs.angularjs.org/api/ngRoute.$routeParams + /////////////////////////////////////////////////////////////////////////// + interface IRouteParamsService { + [key: string]: any; + } + + /////////////////////////////////////////////////////////////////////////// + // RouteService + // see http://docs.angularjs.org/api/ngRoute.$route + // see http://docs.angularjs.org/api/ngRoute.$routeProvider + /////////////////////////////////////////////////////////////////////////// + interface IRouteService { + reload(): void; + routes: any; + + // May not always be available. For instance, current will not be available + // to a controller that was not initialized as a result of a route maching. + current?: ICurrentRoute; + } + + + /** + * see http://docs.angularjs.org/api/ngRoute/provider/$routeProvider#when for API documentation + */ + interface IRoute { + /** + * {(string|function()=} + * Controller fn that should be associated with newly created scope or the name of a registered controller if passed as a string. + */ + controller?: string|Function; + /** + * A controller alias name. If present the controller will be published to scope under the controllerAs name. + */ + controllerAs?: string; + /** + * Undocumented? + */ + name?: string; + /** + * {string=|function()=} + * Html template as a string or a function that returns an html template as a string which should be used by ngView or ngInclude directives. This property takes precedence over templateUrl. + * + * If template is a function, it will be called with the following parameters: + * + * {Array.} - route parameters extracted from the current $location.path() by applying the current route + */ + template?: string|{($routeParams?: angular.route.IRouteParamsService) : string;} + /** + * {string=|function()=} + * Path or function that returns a path to an html template that should be used by ngView. + * + * If templateUrl is a function, it will be called with the following parameters: + * + * {Array.} - route parameters extracted from the current $location.path() by applying the current route + */ + templateUrl?: string|{ ($routeParams?: angular.route.IRouteParamsService): string; } + /** + * {Object.=} - An optional map of dependencies which should be injected into the controller. If any of these dependencies are promises, the router will wait for them all to be resolved or one to be rejected before the controller is instantiated. If all the promises are resolved successfully, the values of the resolved promises are injected and $routeChangeSuccess event is fired. If any of the promises are rejected the $routeChangeError event is fired. The map object is: + * + * - key - {string}: a name of a dependency to be injected into the controller. + * - factory - {string|function}: If string then it is an alias for a service. Otherwise if function, then it is injected and the return value is treated as the dependency. If the result is a promise, it is resolved before its value is injected into the controller. Be aware that ngRoute.$routeParams will still refer to the previous route within these resolve functions. Use $route.current.params to access the new route parameters, instead. + */ + resolve?: {[key: string]: any}; + /** + * {(string|function())=} + * Value to update $location path with and trigger route redirection. + * + * If redirectTo is a function, it will be called with the following parameters: + * + * - {Object.} - route parameters extracted from the current $location.path() by applying the current route templateUrl. + * - {string} - current $location.path() + * - {Object} - current $location.search() + * - The custom redirectTo function is expected to return a string which will be used to update $location.path() and $location.search(). + */ + redirectTo?: string|{($routeParams?: angular.route.IRouteParamsService, $locationPath?: string, $locationSearch?: any) : string}; + /** + * Reload route when only $location.search() or $location.hash() changes. + * + * This option defaults to true. If the option is set to false and url in the browser changes, then $routeUpdate event is broadcasted on the root scope. + */ + reloadOnSearch?: boolean; + /** + * Match routes without being case sensitive + * + * This option defaults to false. If the option is set to true, then the particular route can be matched without being case sensitive + */ + caseInsensitiveMatch?: boolean; + } + + // see http://docs.angularjs.org/api/ng.$route#current + interface ICurrentRoute extends IRoute { + locals: { + [index: string]: any; + $scope: IScope; + $template: string; + }; + + params: any; + } + + interface IRouteProvider extends IServiceProvider { + /** + * Sets route definition that will be used on route change when no other route definition is matched. + * + * @params Mapping information to be assigned to $route.current. + */ + otherwise(params: IRoute): IRouteProvider; + /** + * Adds a new route definition to the $route service. + * + * @param path Route path (matched against $location.path). If $location.path contains redundant trailing slash or is missing one, the route will still match and the $location.path will be updated to add or drop the trailing slash to exactly match the route definition. + * + * - path can contain named groups starting with a colon: e.g. :name. All characters up to the next slash are matched and stored in $routeParams under the given name when the route matches. + * - path can contain named groups starting with a colon and ending with a star: e.g.:name*. All characters are eagerly stored in $routeParams under the given name when the route matches. + * - path can contain optional named groups with a question mark: e.g.:name?. + * + * For example, routes like /color/:color/largecode/:largecode*\/edit will match /color/brown/largecode/code/with/slashes/edit and extract: color: brown and largecode: code/with/slashes. + * + * @param route Mapping information to be assigned to $route.current on route match. + */ + when(path: string, route: IRoute): IRouteProvider; + } +} diff --git a/tooling/typings/angularjs/angular-sanitize.d.ts b/tooling/typings/angularjs/angular-sanitize.d.ts new file mode 100644 index 0000000..d5d541f --- /dev/null +++ b/tooling/typings/angularjs/angular-sanitize.d.ts @@ -0,0 +1,40 @@ +// Type definitions for Angular JS 1.3 (ngSanitize module) +// Project: http://angularjs.org +// Definitions by: Diego Vilar +// Definitions: https://github.com/borisyankov/DefinitelyTyped + + +/// + +declare module "angular-sanitize" { + var _: string; + export = _; +} + +/////////////////////////////////////////////////////////////////////////////// +// ngSanitize module (angular-sanitize.js) +/////////////////////////////////////////////////////////////////////////////// +declare module angular.sanitize { + + /////////////////////////////////////////////////////////////////////////// + // SanitizeService + // see http://docs.angularjs.org/api/ngSanitize.$sanitize + /////////////////////////////////////////////////////////////////////////// + interface ISanitizeService { + (html: string): string; + } + + /////////////////////////////////////////////////////////////////////////// + // Filters included with the ngSanitize + // see https://github.com/angular/angular.js/tree/v1.2.0/src/ngSanitize/filter + /////////////////////////////////////////////////////////////////////////// + export module filter { + + // Finds links in text input and turns them into html links. + // Supports http/https/ftp/mailto and plain email address links. + // see http://code.angularjs.org/1.2.0/docs/api/ngSanitize.filter:linky + interface ILinky { + (text: string, target?: string): string; + } + } +} diff --git a/tooling/typings/angularjs/angular.d.ts b/tooling/typings/angularjs/angular.d.ts new file mode 100644 index 0000000..dac8828 --- /dev/null +++ b/tooling/typings/angularjs/angular.d.ts @@ -0,0 +1,1790 @@ +// Type definitions for Angular JS 1.4+ +// Project: http://angularjs.org +// Definitions by: Diego Vilar +// Definitions: https://github.com/borisyankov/DefinitelyTyped + + +/// + +declare var angular: angular.IAngularStatic; + +// Support for painless dependency injection +interface Function { + $inject?: string[]; +} + +// Collapse angular into ng +import ng = angular; +// Support AMD require +declare module 'angular' { + export = angular; +} + +/////////////////////////////////////////////////////////////////////////////// +// ng module (angular.js) +/////////////////////////////////////////////////////////////////////////////// +declare module angular { + + // not directly implemented, but ensures that constructed class implements $get + interface IServiceProviderClass { + new (...args: any[]): IServiceProvider; + } + + interface IServiceProviderFactory { + (...args: any[]): IServiceProvider; + } + + // All service providers extend this interface + interface IServiceProvider { + $get: any; + } + + interface IAngularBootstrapConfig { + strictDi?: boolean; + } + + /////////////////////////////////////////////////////////////////////////// + // AngularStatic + // see http://docs.angularjs.org/api + /////////////////////////////////////////////////////////////////////////// + interface IAngularStatic { + bind(context: any, fn: Function, ...args: any[]): Function; + + /** + * Use this function to manually start up angular application. + * + * @param element DOM element which is the root of angular application. + * @param modules An array of modules to load into the application. + * Each item in the array should be the name of a predefined module or a (DI annotated) + * function that will be invoked by the injector as a run block. + * @param config an object for defining configuration options for the application. The following keys are supported: + * - `strictDi`: disable automatic function annotation for the application. This is meant to assist in finding bugs which break minified code. + */ + bootstrap(element: string, modules?: string, config?: IAngularBootstrapConfig): auto.IInjectorService; + /** + * Use this function to manually start up angular application. + * + * @param element DOM element which is the root of angular application. + * @param modules An array of modules to load into the application. + * Each item in the array should be the name of a predefined module or a (DI annotated) + * function that will be invoked by the injector as a run block. + * @param config an object for defining configuration options for the application. The following keys are supported: + * - `strictDi`: disable automatic function annotation for the application. This is meant to assist in finding bugs which break minified code. + */ + bootstrap(element: string, modules?: Function, config?: IAngularBootstrapConfig): auto.IInjectorService; + /** + * Use this function to manually start up angular application. + * + * @param element DOM element which is the root of angular application. + * @param modules An array of modules to load into the application. + * Each item in the array should be the name of a predefined module or a (DI annotated) + * function that will be invoked by the injector as a run block. + * @param config an object for defining configuration options for the application. The following keys are supported: + * - `strictDi`: disable automatic function annotation for the application. This is meant to assist in finding bugs which break minified code. + */ + bootstrap(element: string, modules?: string[], config?: IAngularBootstrapConfig): auto.IInjectorService; + /** + * Use this function to manually start up angular application. + * + * @param element DOM element which is the root of angular application. + * @param modules An array of modules to load into the application. + * Each item in the array should be the name of a predefined module or a (DI annotated) + * function that will be invoked by the injector as a run block. + * @param config an object for defining configuration options for the application. The following keys are supported: + * - `strictDi`: disable automatic function annotation for the application. This is meant to assist in finding bugs which break minified code. + */ + bootstrap(element: JQuery, modules?: string, config?: IAngularBootstrapConfig): auto.IInjectorService; + /** + * Use this function to manually start up angular application. + * + * @param element DOM element which is the root of angular application. + * @param modules An array of modules to load into the application. + * Each item in the array should be the name of a predefined module or a (DI annotated) + * function that will be invoked by the injector as a run block. + * @param config an object for defining configuration options for the application. The following keys are supported: + * - `strictDi`: disable automatic function annotation for the application. This is meant to assist in finding bugs which break minified code. + */ + bootstrap(element: JQuery, modules?: Function, config?: IAngularBootstrapConfig): auto.IInjectorService; + /** + * Use this function to manually start up angular application. + * + * @param element DOM element which is the root of angular application. + * @param modules An array of modules to load into the application. + * Each item in the array should be the name of a predefined module or a (DI annotated) + * function that will be invoked by the injector as a run block. + * @param config an object for defining configuration options for the application. The following keys are supported: + * - `strictDi`: disable automatic function annotation for the application. This is meant to assist in finding bugs which break minified code. + */ + bootstrap(element: JQuery, modules?: string[], config?: IAngularBootstrapConfig): auto.IInjectorService; + /** + * Use this function to manually start up angular application. + * + * @param element DOM element which is the root of angular application. + * @param modules An array of modules to load into the application. + * Each item in the array should be the name of a predefined module or a (DI annotated) + * function that will be invoked by the injector as a run block. + * @param config an object for defining configuration options for the application. The following keys are supported: + * - `strictDi`: disable automatic function annotation for the application. This is meant to assist in finding bugs which break minified code. + */ + bootstrap(element: Element, modules?: string, config?: IAngularBootstrapConfig): auto.IInjectorService; + /** + * Use this function to manually start up angular application. + * + * @param element DOM element which is the root of angular application. + * @param modules An array of modules to load into the application. + * Each item in the array should be the name of a predefined module or a (DI annotated) + * function that will be invoked by the injector as a run block. + * @param config an object for defining configuration options for the application. The following keys are supported: + * - `strictDi`: disable automatic function annotation for the application. This is meant to assist in finding bugs which break minified code. + */ + bootstrap(element: Element, modules?: Function, config?: IAngularBootstrapConfig): auto.IInjectorService; + /** + * Use this function to manually start up angular application. + * + * @param element DOM element which is the root of angular application. + * @param modules An array of modules to load into the application. + * Each item in the array should be the name of a predefined module or a (DI annotated) + * function that will be invoked by the injector as a run block. + * @param config an object for defining configuration options for the application. The following keys are supported: + * - `strictDi`: disable automatic function annotation for the application. This is meant to assist in finding bugs which break minified code. + */ + bootstrap(element: Element, modules?: string[], config?: IAngularBootstrapConfig): auto.IInjectorService; + /** + * Use this function to manually start up angular application. + * + * @param element DOM element which is the root of angular application. + * @param modules An array of modules to load into the application. + * Each item in the array should be the name of a predefined module or a (DI annotated) + * function that will be invoked by the injector as a run block. + * @param config an object for defining configuration options for the application. The following keys are supported: + * - `strictDi`: disable automatic function annotation for the application. This is meant to assist in finding bugs which break minified code. + */ + bootstrap(element: Document, modules?: string, config?: IAngularBootstrapConfig): auto.IInjectorService; + /** + * Use this function to manually start up angular application. + * + * @param element DOM element which is the root of angular application. + * @param modules An array of modules to load into the application. + * Each item in the array should be the name of a predefined module or a (DI annotated) + * function that will be invoked by the injector as a run block. + * @param config an object for defining configuration options for the application. The following keys are supported: + * - `strictDi`: disable automatic function annotation for the application. This is meant to assist in finding bugs which break minified code. + */ + bootstrap(element: Document, modules?: Function, config?: IAngularBootstrapConfig): auto.IInjectorService; + /** + * Use this function to manually start up angular application. + * + * @param element DOM element which is the root of angular application. + * @param modules An array of modules to load into the application. + * Each item in the array should be the name of a predefined module or a (DI annotated) + * function that will be invoked by the injector as a run block. + * @param config an object for defining configuration options for the application. The following keys are supported: + * - `strictDi`: disable automatic function annotation for the application. This is meant to assist in finding bugs which break minified code. + */ + bootstrap(element: Document, modules?: string[], config?: IAngularBootstrapConfig): auto.IInjectorService; + + /** + * Creates a deep copy of source, which should be an object or an array. + * + * - If no destination is supplied, a copy of the object or array is created. + * - If a destination is provided, all of its elements (for array) or properties (for objects) are deleted and then all elements/properties from the source are copied to it. + * - If source is not an object or array (inc. null and undefined), source is returned. + * - If source is identical to 'destination' an exception will be thrown. + * + * @param source The source that will be used to make a copy. Can be any type, including primitives, null, and undefined. + * @param destination Destination into which the source is copied. If provided, must be of the same type as source. + */ + copy(source: T, destination?: T): T; + + /** + * Wraps a raw DOM element or HTML string as a jQuery element. + * + * If jQuery is available, angular.element is an alias for the jQuery function. If jQuery is not available, angular.element delegates to Angular's built-in subset of jQuery, called "jQuery lite" or "jqLite." + */ + element: IAugmentedJQueryStatic; + equals(value1: any, value2: any): boolean; + extend(destination: any, ...sources: any[]): any; + + /** + * Invokes the iterator function once for each item in obj collection, which can be either an object or an array. The iterator function is invoked with iterator(value, key), where value is the value of an object property or an array element and key is the object property key or array element index. Specifying a context for the function is optional. + * + * It is worth noting that .forEach does not iterate over inherited properties because it filters using the hasOwnProperty method. + * + * @param obj Object to iterate over. + * @param iterator Iterator function. + * @param context Object to become context (this) for the iterator function. + */ + forEach(obj: T[], iterator: (value: T, key: number) => any, context?: any): any; + /** + * Invokes the iterator function once for each item in obj collection, which can be either an object or an array. The iterator function is invoked with iterator(value, key), where value is the value of an object property or an array element and key is the object property key or array element index. Specifying a context for the function is optional. + * + * It is worth noting that .forEach does not iterate over inherited properties because it filters using the hasOwnProperty method. + * + * @param obj Object to iterate over. + * @param iterator Iterator function. + * @param context Object to become context (this) for the iterator function. + */ + forEach(obj: { [index: string]: T; }, iterator: (value: T, key: string) => any, context?: any): any; + /** + * Invokes the iterator function once for each item in obj collection, which can be either an object or an array. The iterator function is invoked with iterator(value, key), where value is the value of an object property or an array element and key is the object property key or array element index. Specifying a context for the function is optional. + * + * It is worth noting that .forEach does not iterate over inherited properties because it filters using the hasOwnProperty method. + * + * @param obj Object to iterate over. + * @param iterator Iterator function. + * @param context Object to become context (this) for the iterator function. + */ + forEach(obj: any, iterator: (value: any, key: any) => any, context?: any): any; + + fromJson(json: string): any; + identity(arg?: T): T; + injector(modules?: any[], strictDi?: boolean): auto.IInjectorService; + isArray(value: any): boolean; + isDate(value: any): boolean; + isDefined(value: any): boolean; + isElement(value: any): boolean; + isFunction(value: any): boolean; + isNumber(value: any): boolean; + isObject(value: any): boolean; + isString(value: any): boolean; + isUndefined(value: any): boolean; + lowercase(str: string): string; + + /** + * Deeply extends the destination object dst by copying own enumerable properties from the src object(s) to dst. You can specify multiple src objects. If you want to preserve original objects, you can do so by passing an empty object as the target: var object = angular.merge({}, object1, object2). + * + * Unlike extend(), merge() recursively descends into object properties of source objects, performing a deep copy. + * + * @param dst Destination object. + * @param src Source object(s). + */ + merge(dst: any, ...src: any[]): any; + + /** + * The angular.module is a global place for creating, registering and retrieving Angular modules. All modules (angular core or 3rd party) that should be available to an application must be registered using this mechanism. + * + * When passed two or more arguments, a new module is created. If passed only one argument, an existing module (the name passed as the first argument to module) is retrieved. + * + * @param name The name of the module to create or retrieve. + * @param requires The names of modules this module depends on. If specified then new module is being created. If unspecified then the module is being retrieved for further configuration. + * @param configFn Optional configuration function for the module. + */ + module( + name: string, + requires?: string[], + configFn?: Function): IModule; + + noop(...args: any[]): void; + reloadWithDebugInfo(): void; + toJson(obj: any, pretty?: boolean): string; + uppercase(str: string): string; + version: { + full: string; + major: number; + minor: number; + dot: number; + codeName: string; + }; + } + + /////////////////////////////////////////////////////////////////////////// + // Module + // see http://docs.angularjs.org/api/angular.Module + /////////////////////////////////////////////////////////////////////////// + interface IModule { + animation(name: string, animationFactory: Function): IModule; + animation(name: string, inlineAnnotatedFunction: any[]): IModule; + animation(object: Object): IModule; + /** + * Use this method to register work which needs to be performed on module loading. + * + * @param configFn Execute this function on module load. Useful for service configuration. + */ + config(configFn: Function): IModule; + /** + * Use this method to register work which needs to be performed on module loading. + * + * @param inlineAnnotatedFunction Execute this function on module load. Useful for service configuration. + */ + config(inlineAnnotatedFunction: any[]): IModule; + /** + * Register a constant service, such as a string, a number, an array, an object or a function, with the $injector. Unlike value it can be injected into a module configuration function (see config) and it cannot be overridden by an Angular decorator. + * + * @param name The name of the constant. + * @param value The constant value. + */ + constant(name: string, value: any): IModule; + constant(object: Object): IModule; + /** + * The $controller service is used by Angular to create new controllers. + * + * This provider allows controller registration via the register method. + * + * @param name Controller name, or an object map of controllers where the keys are the names and the values are the constructors. + * @param controllerConstructor Controller constructor fn (optionally decorated with DI annotations in the array notation). + */ + controller(name: string, controllerConstructor: Function): IModule; + /** + * The $controller service is used by Angular to create new controllers. + * + * This provider allows controller registration via the register method. + * + * @param name Controller name, or an object map of controllers where the keys are the names and the values are the constructors. + * @param controllerConstructor Controller constructor fn (optionally decorated with DI annotations in the array notation). + */ + controller(name: string, inlineAnnotatedConstructor: any[]): IModule; + controller(object: Object): IModule; + /** + * Register a new directive with the compiler. + * + * @param name Name of the directive in camel-case (i.e. ngBind which will match as ng-bind) + * @param directiveFactory An injectable directive factory function. + */ + directive(name: string, directiveFactory: IDirectiveFactory): IModule; + /** + * Register a new directive with the compiler. + * + * @param name Name of the directive in camel-case (i.e. ngBind which will match as ng-bind) + * @param directiveFactory An injectable directive factory function. + */ + directive(name: string, inlineAnnotatedFunction: any[]): IModule; + directive(object: Object): IModule; + /** + * Register a service factory, which will be called to return the service instance. This is short for registering a service where its provider consists of only a $get property, which is the given service factory function. You should use $provide.factory(getFn) if you do not need to configure your service in a provider. + * + * @param name The name of the instance. + * @param $getFn The $getFn for the instance creation. Internally this is a short hand for $provide.provider(name, {$get: $getFn}). + */ + factory(name: string, $getFn: Function): IModule; + /** + * Register a service factory, which will be called to return the service instance. This is short for registering a service where its provider consists of only a $get property, which is the given service factory function. You should use $provide.factory(getFn) if you do not need to configure your service in a provider. + * + * @param name The name of the instance. + * @param inlineAnnotatedFunction The $getFn for the instance creation. Internally this is a short hand for $provide.provider(name, {$get: $getFn}). + */ + factory(name: string, inlineAnnotatedFunction: any[]): IModule; + factory(object: Object): IModule; + filter(name: string, filterFactoryFunction: Function): IModule; + filter(name: string, inlineAnnotatedFunction: any[]): IModule; + filter(object: Object): IModule; + provider(name: string, serviceProviderFactory: IServiceProviderFactory): IModule; + provider(name: string, serviceProviderConstructor: IServiceProviderClass): IModule; + provider(name: string, inlineAnnotatedConstructor: any[]): IModule; + provider(name: string, providerObject: IServiceProvider): IModule; + provider(object: Object): IModule; + /** + * Run blocks are the closest thing in Angular to the main method. A run block is the code which needs to run to kickstart the application. It is executed after all of the service have been configured and the injector has been created. Run blocks typically contain code which is hard to unit-test, and for this reason should be declared in isolated modules, so that they can be ignored in the unit-tests. + */ + run(initializationFunction: Function): IModule; + /** + * Run blocks are the closest thing in Angular to the main method. A run block is the code which needs to run to kickstart the application. It is executed after all of the service have been configured and the injector has been created. Run blocks typically contain code which is hard to unit-test, and for this reason should be declared in isolated modules, so that they can be ignored in the unit-tests. + */ + run(inlineAnnotatedFunction: any[]): IModule; + service(name: string, serviceConstructor: Function): IModule; + service(name: string, inlineAnnotatedConstructor: any[]): IModule; + service(object: Object): IModule; + /** + * Register a value service with the $injector, such as a string, a number, an array, an object or a function. This is short for registering a service where its provider's $get property is a factory function that takes no arguments and returns the value service. + + Value services are similar to constant services, except that they cannot be injected into a module configuration function (see config) but they can be overridden by an Angular decorator. + * + * @param name The name of the instance. + * @param value The value. + */ + value(name: string, value: any): IModule; + value(object: Object): IModule; + + /** + * Register a service decorator with the $injector. A service decorator intercepts the creation of a service, allowing it to override or modify the behaviour of the service. The object returned by the decorator may be the original service, or a new service object which replaces or wraps and delegates to the original service. + * @param name The name of the service to decorate + * @param decorator This function will be invoked when the service needs to be instantiated and should return the decorated service instance. The function is called using the injector.invoke method and is therefore fully injectable. Local injection arguments: $delegate - The original service instance, which can be monkey patched, configured, decorated or delegated to. + */ + decorator(name:string, decoratorConstructor: Function): IModule; + decorator(name:string, inlineAnnotatedConstructor: any[]): IModule; + + // Properties + name: string; + requires: string[]; + } + + /////////////////////////////////////////////////////////////////////////// + // Attributes + // see http://docs.angularjs.org/api/ng.$compile.directive.Attributes + /////////////////////////////////////////////////////////////////////////// + interface IAttributes { + /** + * this is necessary to be able to access the scoped attributes. it's not very elegant + * because you have to use attrs['foo'] instead of attrs.foo but I don't know of a better way + * this should really be limited to return string but it creates this problem: http://stackoverflow.com/q/17201854/165656 + */ + [name: string]: any; + + /** + * Converts an attribute name (e.g. dash/colon/underscore-delimited string, optionally prefixed with x- or data-) to its normalized, camelCase form. + * + * Also there is special case for Moz prefix starting with upper case letter. + * + * For further information check out the guide on @see https://docs.angularjs.org/guide/directive#matching-directives + */ + $normalize(name: string): void; + + /** + * Adds the CSS class value specified by the classVal parameter to the + * element. If animations are enabled then an animation will be triggered + * for the class addition. + */ + $addClass(classVal: string): void; + + /** + * Removes the CSS class value specified by the classVal parameter from the + * element. If animations are enabled then an animation will be triggered for + * the class removal. + */ + $removeClass(classVal: string): void; + + /** + * Set DOM element attribute value. + */ + $set(key: string, value: any): void; + + /** + * Observes an interpolated attribute. + * The observer function will be invoked once during the next $digest + * following compilation. The observer is then invoked whenever the + * interpolated value changes. + */ + $observe(name: string, fn: (value?: T) => any): Function; + + /** + * A map of DOM element attribute names to the normalized name. This is needed + * to do reverse lookup from normalized name back to actual name. + */ + $attr: Object; + } + + /** + * form.FormController - type in module ng + * see https://docs.angularjs.org/api/ng/type/form.FormController + */ + interface IFormController { + + /** + * Indexer which should return ng.INgModelController for most properties but cannot because of "All named properties must be assignable to string indexer type" constraint - see https://github.com/Microsoft/TypeScript/issues/272 + */ + [name: string]: any; + + $pristine: boolean; + $dirty: boolean; + $valid: boolean; + $invalid: boolean; + $submitted: boolean; + $error: any; + $addControl(control: INgModelController): void; + $removeControl(control: INgModelController): void; + $setValidity(validationErrorKey: string, isValid: boolean, control: INgModelController): void; + $setDirty(): void; + $setPristine(): void; + $commitViewValue(): void; + $rollbackViewValue(): void; + $setSubmitted(): void; + $setUntouched(): void; + } + + /////////////////////////////////////////////////////////////////////////// + // NgModelController + // see http://docs.angularjs.org/api/ng.directive:ngModel.NgModelController + /////////////////////////////////////////////////////////////////////////// + interface INgModelController { + $render(): void; + $setValidity(validationErrorKey: string, isValid: boolean): void; + // Documentation states viewValue and modelValue to be a string but other + // types do work and it's common to use them. + $setViewValue(value: any, trigger?: string): void; + $setPristine(): void; + $setDirty(): void; + $validate(): void; + $setTouched(): void; + $setUntouched(): void; + $rollbackViewValue(): void; + $commitViewValue(): void; + $isEmpty(value: any): boolean; + + $viewValue: any; + + $modelValue: any; + + $parsers: IModelParser[]; + $formatters: IModelFormatter[]; + $viewChangeListeners: IModelViewChangeListener[]; + $error: any; + $name: string; + + $touched: boolean; + $untouched: boolean; + + $validators: IModelValidators; + $asyncValidators: IAsyncModelValidators; + + $pending: any; + $pristine: boolean; + $dirty: boolean; + $valid: boolean; + $invalid: boolean; + } + + interface IModelValidators { + /** + * viewValue is any because it can be an object that is called in the view like $viewValue.name:$viewValue.subName + */ + [index: string]: (modelValue: any, viewValue: any) => boolean; + } + + interface IAsyncModelValidators { + [index: string]: (modelValue: any, viewValue: any) => IPromise; + } + + interface IModelParser { + (value: any): any; + } + + interface IModelFormatter { + (value: any): any; + } + + interface IModelViewChangeListener { + (): void; + } + + /** + * $rootScope - $rootScopeProvider - service in module ng + * see https://docs.angularjs.org/api/ng/type/$rootScope.Scope and https://docs.angularjs.org/api/ng/service/$rootScope + */ + interface IRootScopeService { + [index: string]: any; + + $apply(): any; + $apply(exp: string): any; + $apply(exp: (scope: IScope) => any): any; + + $applyAsync(): any; + $applyAsync(exp: string): any; + $applyAsync(exp: (scope: IScope) => any): any; + + /** + * Dispatches an event name downwards to all child scopes (and their children) notifying the registered $rootScope.Scope listeners. + * + * The event life cycle starts at the scope on which $broadcast was called. All listeners listening for name event on this scope get notified. Afterwards, the event propagates to all direct and indirect scopes of the current scope and calls all registered listeners along the way. The event cannot be canceled. + * + * Any exception emitted from the listeners will be passed onto the $exceptionHandler service. + * + * @param name Event name to broadcast. + * @param args Optional one or more arguments which will be passed onto the event listeners. + */ + $broadcast(name: string, ...args: any[]): IAngularEvent; + $destroy(): void; + $digest(): void; + /** + * Dispatches an event name upwards through the scope hierarchy notifying the registered $rootScope.Scope listeners. + * + * The event life cycle starts at the scope on which $emit was called. All listeners listening for name event on this scope get notified. Afterwards, the event traverses upwards toward the root scope and calls all registered listeners along the way. The event will stop propagating if one of the listeners cancels it. + * + * Any exception emitted from the listeners will be passed onto the $exceptionHandler service. + * + * @param name Event name to emit. + * @param args Optional one or more arguments which will be passed onto the event listeners. + */ + $emit(name: string, ...args: any[]): IAngularEvent; + + $eval(): any; + $eval(expression: string, locals?: Object): any; + $eval(expression: (scope: IScope) => any, locals?: Object): any; + + $evalAsync(): void; + $evalAsync(expression: string): void; + $evalAsync(expression: (scope: IScope) => any): void; + + // Defaults to false by the implementation checking strategy + $new(isolate?: boolean, parent?: IScope): IScope; + + /** + * Listens on events of a given type. See $emit for discussion of event life cycle. + * + * The event listener function format is: function(event, args...). + * + * @param name Event name to listen on. + * @param listener Function to call when the event is emitted. + */ + $on(name: string, listener: (event: IAngularEvent, ...args: any[]) => any): Function; + + $watch(watchExpression: string, listener?: string, objectEquality?: boolean): Function; + $watch(watchExpression: string, listener?: (newValue: T, oldValue: T, scope: IScope) => any, objectEquality?: boolean): Function; + $watch(watchExpression: (scope: IScope) => any, listener?: string, objectEquality?: boolean): Function; + $watch(watchExpression: (scope: IScope) => T, listener?: (newValue: T, oldValue: T, scope: IScope) => any, objectEquality?: boolean): Function; + + $watchCollection(watchExpression: string, listener: (newValue: T, oldValue: T, scope: IScope) => any): Function; + $watchCollection(watchExpression: (scope: IScope) => T, listener: (newValue: T, oldValue: T, scope: IScope) => any): Function; + + $watchGroup(watchExpressions: any[], listener: (newValue: any, oldValue: any, scope: IScope) => any): Function; + $watchGroup(watchExpressions: { (scope: IScope): any }[], listener: (newValue: any, oldValue: any, scope: IScope) => any): Function; + + $parent: IScope; + $root: IRootScopeService; + $id: number; + + // Hidden members + $$isolateBindings: any; + $$phase: any; + } + + interface IScope extends IRootScopeService { } + + /** + * $scope for ngRepeat directive. + * see https://docs.angularjs.org/api/ng/directive/ngRepeat + */ + interface IRepeatScope extends IScope { + + /** + * iterator offset of the repeated element (0..length-1). + */ + $index: number; + + /** + * true if the repeated element is first in the iterator. + */ + $first: boolean; + + /** + * true if the repeated element is between the first and last in the iterator. + */ + $middle: boolean; + + /** + * true if the repeated element is last in the iterator. + */ + $last: boolean; + + /** + * true if the iterator position $index is even (otherwise false). + */ + $even: boolean; + + /** + * true if the iterator position $index is odd (otherwise false). + */ + $odd: boolean; + + } + + interface IAngularEvent { + /** + * the scope on which the event was $emit-ed or $broadcast-ed. + */ + targetScope: IScope; + /** + * the scope that is currently handling the event. Once the event propagates through the scope hierarchy, this property is set to null. + */ + currentScope: IScope; + /** + * name of the event. + */ + name: string; + /** + * calling stopPropagation function will cancel further event propagation (available only for events that were $emit-ed). + */ + stopPropagation?: Function; + /** + * calling preventDefault sets defaultPrevented flag to true. + */ + preventDefault: Function; + /** + * true if preventDefault was called. + */ + defaultPrevented: boolean; + } + + /////////////////////////////////////////////////////////////////////////// + // WindowService + // see http://docs.angularjs.org/api/ng.$window + /////////////////////////////////////////////////////////////////////////// + interface IWindowService extends Window { + [key: string]: any; + } + + /////////////////////////////////////////////////////////////////////////// + // BrowserService + // TODO undocumented, so we need to get it from the source code + /////////////////////////////////////////////////////////////////////////// + interface IBrowserService { + defer: angular.ITimeoutService; + [key: string]: any; + } + + /////////////////////////////////////////////////////////////////////////// + // TimeoutService + // see http://docs.angularjs.org/api/ng.$timeout + /////////////////////////////////////////////////////////////////////////// + interface ITimeoutService { + (delay?: number, invokeApply?: boolean): IPromise; + (fn: (...args: any[]) => T, delay?: number, invokeApply?: boolean, ...args: any[]): IPromise; + cancel(promise?: IPromise): boolean; + } + + /////////////////////////////////////////////////////////////////////////// + // IntervalService + // see http://docs.angularjs.org/api/ng.$interval + /////////////////////////////////////////////////////////////////////////// + interface IIntervalService { + (func: Function, delay: number, count?: number, invokeApply?: boolean): IPromise; + cancel(promise: IPromise): boolean; + } + + /////////////////////////////////////////////////////////////////////////// + // AngularProvider + // see http://docs.angularjs.org/api/ng/provider/$animateProvider + /////////////////////////////////////////////////////////////////////////// + interface IAnimateProvider { + /** + * Registers a new injectable animation factory function. + * + * @param name The name of the animation. + * @param factory The factory function that will be executed to return the animation object. + */ + register(name: string, factory: () => IAnimateCallbackObject): void; + + /** + * Gets and/or sets the CSS class expression that is checked when performing an animation. + * + * @param expression The className expression which will be checked against all animations. + * @returns The current CSS className expression value. If null then there is no expression value. + */ + classNameFilter(expression?: RegExp): RegExp; + } + + /** + * The animation object which contains callback functions for each event that is expected to be animated. + */ + interface IAnimateCallbackObject { + eventFn(element: Node, doneFn: () => void): Function; + } + + /** + * $filter - $filterProvider - service in module ng + * + * Filters are used for formatting data displayed to the user. + * + * see https://docs.angularjs.org/api/ng/service/$filter + */ + interface IFilterService { + /** + * Usage: + * $filter(name); + * + * @param name Name of the filter function to retrieve + */ + (name: string): IFilterFunc; + } + + interface IFilterFunc { + (array: T[], expression: string | IFilterPatternObject | IFilterPredicateFunc, comparator?: IFilterComparatorFunc|boolean): T[]; + } + + interface IFilterPatternObject { + [name: string]: string; + } + + interface IFilterPredicateFunc { + (value: T, index: number, array: T[]): T[]; + } + + interface IFilterComparatorFunc { + (actual: T, expected: T): boolean; + } + + /** + * $filterProvider - $filter - provider in module ng + * + * Filters are just functions which transform input to an output. However filters need to be Dependency Injected. To achieve this a filter definition consists of a factory function which is annotated with dependencies and is responsible for creating a filter function. + * + * see https://docs.angularjs.org/api/ng/provider/$filterProvider + */ + interface IFilterProvider extends IServiceProvider { + /** + * register(name); + * + * @param name Name of the filter function, or an object map of filters where the keys are the filter names and the values are the filter factories. Note: Filter names must be valid angular Expressions identifiers, such as uppercase or orderBy. Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace your filters, then you can use capitalization (myappSubsectionFilterx) or underscores (myapp_subsection_filterx). + */ + register(name: string | {}): IServiceProvider; + } + + /////////////////////////////////////////////////////////////////////////// + // LocaleService + // see http://docs.angularjs.org/api/ng.$locale + /////////////////////////////////////////////////////////////////////////// + interface ILocaleService { + id: string; + + // These are not documented + // Check angular's i18n files for exemples + NUMBER_FORMATS: ILocaleNumberFormatDescriptor; + DATETIME_FORMATS: ILocaleDateTimeFormatDescriptor; + pluralCat: (num: any) => string; + } + + interface ILocaleNumberFormatDescriptor { + DECIMAL_SEP: string; + GROUP_SEP: string; + PATTERNS: ILocaleNumberPatternDescriptor[]; + CURRENCY_SYM: string; + } + + interface ILocaleNumberPatternDescriptor { + minInt: number; + minFrac: number; + maxFrac: number; + posPre: string; + posSuf: string; + negPre: string; + negSuf: string; + gSize: number; + lgSize: number; + } + + interface ILocaleDateTimeFormatDescriptor { + MONTH: string[]; + SHORTMONTH: string[]; + DAY: string[]; + SHORTDAY: string[]; + AMPMS: string[]; + medium: string; + short: string; + fullDate: string; + longDate: string; + mediumDate: string; + shortDate: string; + mediumTime: string; + shortTime: string; + } + + /////////////////////////////////////////////////////////////////////////// + // LogService + // see http://docs.angularjs.org/api/ng.$log + // see http://docs.angularjs.org/api/ng.$logProvider + /////////////////////////////////////////////////////////////////////////// + interface ILogService { + debug: ILogCall; + error: ILogCall; + info: ILogCall; + log: ILogCall; + warn: ILogCall; + } + + interface ILogProvider extends IServiceProvider { + debugEnabled(): boolean; + debugEnabled(enabled: boolean): ILogProvider; + } + + // We define this as separate interface so we can reopen it later for + // the ngMock module. + interface ILogCall { + (...args: any[]): void; + } + + /////////////////////////////////////////////////////////////////////////// + // ParseService + // see http://docs.angularjs.org/api/ng.$parse + // see http://docs.angularjs.org/api/ng.$parseProvider + /////////////////////////////////////////////////////////////////////////// + interface IParseService { + (expression: string): ICompiledExpression; + } + + interface IParseProvider { + logPromiseWarnings(): boolean; + logPromiseWarnings(value: boolean): IParseProvider; + + unwrapPromises(): boolean; + unwrapPromises(value: boolean): IParseProvider; + } + + interface ICompiledExpression { + (context: any, locals?: any): any; + + // If value is not provided, undefined is gonna be used since the implementation + // does not check the parameter. Let's force a value for consistency. If consumer + // whants to undefine it, pass the undefined value explicitly. + assign(context: any, value: any): any; + } + + /** + * $location - $locationProvider - service in module ng + * see https://docs.angularjs.org/api/ng/service/$location + */ + interface ILocationService { + absUrl(): string; + hash(): string; + hash(newHash: string): ILocationService; + host(): string; + + /** + * Return path of current url + */ + path(): string; + + /** + * Change path when called with parameter and return $location. + * Note: Path should always begin with forward slash (/), this method will add the forward slash if it is missing. + * + * @param path New path + */ + path(path: string): ILocationService; + + port(): number; + protocol(): string; + replace(): ILocationService; + + /** + * Return search part (as object) of current url + */ + search(): any; + + /** + * Change search part when called with parameter and return $location. + * + * @param search When called with a single argument the method acts as a setter, setting the search component of $location to the specified value. + * + * If the argument is a hash object containing an array of values, these values will be encoded as duplicate search parameters in the url. + */ + search(search: any): ILocationService; + + /** + * Change search part when called with parameter and return $location. + * + * @param search New search params + * @param paramValue If search is a string or a Number, then paramValue will override only a single search property. If paramValue is null, the property specified via the first argument will be deleted. If paramValue is an array, it will override the property of the search component of $location specified via the first argument. If paramValue is true, the property specified via the first argument will be added with no value nor trailing equal sign. + */ + search(search: string, paramValue: string|number|string[]|boolean): ILocationService; + + state(): any; + state(state: any): ILocationService; + url(): string; + url(url: string): ILocationService; + } + + interface ILocationProvider extends IServiceProvider { + hashPrefix(): string; + hashPrefix(prefix: string): ILocationProvider; + html5Mode(): boolean; + + // Documentation states that parameter is string, but + // implementation tests it as boolean, which makes more sense + // since this is a toggler + html5Mode(active: boolean): ILocationProvider; + html5Mode(mode: { enabled?: boolean; requireBase?: boolean; rewriteLinks?: boolean; }): ILocationProvider; + } + + /////////////////////////////////////////////////////////////////////////// + // DocumentService + // see http://docs.angularjs.org/api/ng.$document + /////////////////////////////////////////////////////////////////////////// + interface IDocumentService extends IAugmentedJQuery {} + + /////////////////////////////////////////////////////////////////////////// + // ExceptionHandlerService + // see http://docs.angularjs.org/api/ng.$exceptionHandler + /////////////////////////////////////////////////////////////////////////// + interface IExceptionHandlerService { + (exception: Error, cause?: string): void; + } + + /////////////////////////////////////////////////////////////////////////// + // RootElementService + // see http://docs.angularjs.org/api/ng.$rootElement + /////////////////////////////////////////////////////////////////////////// + interface IRootElementService extends JQuery {} + + interface IQResolveReject { + (): void; + (value: T): void; + } + /** + * $q - service in module ng + * A promise/deferred implementation inspired by Kris Kowal's Q. + * See http://docs.angularjs.org/api/ng/service/$q + */ + interface IQService { + new (resolver: (resolve: IQResolveReject) => any): IPromise; + new (resolver: (resolve: IQResolveReject, reject: IQResolveReject) => any): IPromise; + (resolver: (resolve: IQResolveReject) => any): IPromise; + (resolver: (resolve: IQResolveReject, reject: IQResolveReject) => any): IPromise; + + /** + * Combines multiple promises into a single promise that is resolved when all of the input promises are resolved. + * + * Returns a single promise that will be resolved with an array of values, each value corresponding to the promise at the same index in the promises array. If any of the promises is resolved with a rejection, this resulting promise will be rejected with the same rejection value. + * + * @param promises An array of promises. + */ + all(promises: IPromise[]): IPromise; + /** + * Combines multiple promises into a single promise that is resolved when all of the input promises are resolved. + * + * Returns a single promise that will be resolved with a hash of values, each value corresponding to the promise at the same key in the promises hash. If any of the promises is resolved with a rejection, this resulting promise will be rejected with the same rejection value. + * + * @param promises A hash of promises. + */ + all(promises: { [id: string]: IPromise; }): IPromise<{ [id: string]: any; }>; + all(promises: { [id: string]: IPromise; }): IPromise; + /** + * Creates a Deferred object which represents a task which will finish in the future. + */ + defer(): IDeferred; + /** + * Creates a promise that is resolved as rejected with the specified reason. This api should be used to forward rejection in a chain of promises. If you are dealing with the last promise in a promise chain, you don't need to worry about it. + * + * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of reject as the throw keyword in JavaScript. This also means that if you "catch" an error via a promise error callback and you want to forward the error to the promise derived from the current promise, you have to "rethrow" the error by returning a rejection constructed via reject. + * + * @param reason Constant, message, exception or an object representing the rejection reason. + */ + reject(reason?: any): IPromise; + /** + * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise. This is useful when you are dealing with an object that might or might not be a promise, or if the promise comes from a source that can't be trusted. + * + * @param value Value or a promise + */ + when(value: IPromise|T): IPromise; + /** + * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise. This is useful when you are dealing with an object that might or might not be a promise, or if the promise comes from a source that can't be trusted. + * + * @param value Value or a promise + */ + when(): IPromise; + } + + interface IPromise { + /** + * Regardless of when the promise was or will be resolved or rejected, then calls one of the success or error callbacks asynchronously as soon as the result is available. The callbacks are called with a single argument: the result or rejection reason. Additionally, the notify callback may be called zero or more times to provide a progress indication, before the promise is resolved or rejected. + * The successCallBack may return IPromise for when a $q.reject() needs to be returned + * This method returns a new promise which is resolved or rejected via the return value of the successCallback, errorCallback. It also notifies via the return value of the notifyCallback method. The promise can not be resolved or rejected from the notifyCallback method. + */ + then(successCallback: (promiseValue: T) => IHttpPromise|IPromise|TResult|IPromise, errorCallback?: (reason: any) => any, notifyCallback?: (state: any) => any): IPromise; + + /** + * Shorthand for promise.then(null, errorCallback) + */ + catch(onRejected: (reason: any) => IHttpPromise|IPromise|TResult): IPromise; + + /** + * Allows you to observe either the fulfillment or rejection of a promise, but to do so without modifying the final value. This is useful to release resources or do some clean-up that needs to be done whether the promise was rejected or resolved. See the full specification for more information. + * + * Because finally is a reserved word in JavaScript and reserved keywords are not supported as property names by ES3, you'll need to invoke the method like promise['finally'](callback) to make your code IE8 and Android 2.x compatible. + */ + finally(finallyCallback: () => any): IPromise; + } + + interface IDeferred { + resolve(value?: T): void; + reject(reason?: any): void; + notify(state?: any): void; + promise: IPromise; + } + + /////////////////////////////////////////////////////////////////////////// + // AnchorScrollService + // see http://docs.angularjs.org/api/ng.$anchorScroll + /////////////////////////////////////////////////////////////////////////// + interface IAnchorScrollService { + (): void; + (hash: string): void; + yOffset: any; + } + + interface IAnchorScrollProvider extends IServiceProvider { + disableAutoScrolling(): void; + } + + /** + * $cacheFactory - service in module ng + * + * Factory that constructs Cache objects and gives access to them. + * + * see https://docs.angularjs.org/api/ng/service/$cacheFactory + */ + interface ICacheFactoryService { + /** + * Factory that constructs Cache objects and gives access to them. + * + * @param cacheId Name or id of the newly created cache. + * @param optionsMap Options object that specifies the cache behavior. Properties: + * + * capacity — turns the cache into LRU cache. + */ + (cacheId: string, optionsMap?: { capacity?: number; }): ICacheObject; + + /** + * Get information about all the caches that have been created. + * @returns key-value map of cacheId to the result of calling cache#info + */ + info(): any; + + /** + * Get access to a cache object by the cacheId used when it was created. + * + * @param cacheId Name or id of a cache to access. + */ + get(cacheId: string): ICacheObject; + } + + /** + * $cacheFactory.Cache - type in module ng + * + * A cache object used to store and retrieve data, primarily used by $http and the script directive to cache templates and other data. + * + * see https://docs.angularjs.org/api/ng/type/$cacheFactory.Cache + */ + interface ICacheObject { + /** + * Retrieve information regarding a particular Cache. + */ + info(): { + /** + * the id of the cache instance + */ + id: string; + + /** + * the number of entries kept in the cache instance + */ + size: number; + + //...: any additional properties from the options object when creating the cache. + }; + + /** + * Inserts a named entry into the Cache object to be retrieved later, and incrementing the size of the cache if the key was not already present in the cache. If behaving like an LRU cache, it will also remove stale entries from the set. + * + * It will not insert undefined values into the cache. + * + * @param key the key under which the cached data is stored. + * @param value the value to store alongside the key. If it is undefined, the key will not be stored. + */ + put(key: string, value?: T): T; + + /** + * Retrieves named data stored in the Cache object. + * + * @param key the key of the data to be retrieved + */ + get(key: string): T; + + /** + * Removes an entry from the Cache object. + * + * @param key the key of the entry to be removed + */ + remove(key: string): void; + + /** + * Clears the cache object of any entries. + */ + removeAll(): void; + + /** + * Destroys the Cache object entirely, removing it from the $cacheFactory set. + */ + destroy(): void; + } + + /////////////////////////////////////////////////////////////////////////// + // CompileService + // see http://docs.angularjs.org/api/ng.$compile + // see http://docs.angularjs.org/api/ng.$compileProvider + /////////////////////////////////////////////////////////////////////////// + interface ICompileService { + (element: string, transclude?: ITranscludeFunction, maxPriority?: number): ITemplateLinkingFunction; + (element: Element, transclude?: ITranscludeFunction, maxPriority?: number): ITemplateLinkingFunction; + (element: JQuery, transclude?: ITranscludeFunction, maxPriority?: number): ITemplateLinkingFunction; + } + + interface ICompileProvider extends IServiceProvider { + directive(name: string, directiveFactory: Function): ICompileProvider; + + // Undocumented, but it is there... + directive(directivesMap: any): ICompileProvider; + + aHrefSanitizationWhitelist(): RegExp; + aHrefSanitizationWhitelist(regexp: RegExp): ICompileProvider; + + imgSrcSanitizationWhitelist(): RegExp; + imgSrcSanitizationWhitelist(regexp: RegExp): ICompileProvider; + + debugInfoEnabled(enabled?: boolean): any; + } + + interface ICloneAttachFunction { + // Let's hint but not force cloneAttachFn's signature + (clonedElement?: JQuery, scope?: IScope): any; + } + + // This corresponds to the "publicLinkFn" returned by $compile. + interface ITemplateLinkingFunction { + (scope: IScope, cloneAttachFn?: ICloneAttachFunction): IAugmentedJQuery; + } + + // This corresponds to $transclude (and also the transclude function passed to link). + interface ITranscludeFunction { + // If the scope is provided, then the cloneAttachFn must be as well. + (scope: IScope, cloneAttachFn: ICloneAttachFunction): IAugmentedJQuery; + // If one argument is provided, then it's assumed to be the cloneAttachFn. + (cloneAttachFn?: ICloneAttachFunction): IAugmentedJQuery; + } + + /////////////////////////////////////////////////////////////////////////// + // ControllerService + // see http://docs.angularjs.org/api/ng.$controller + // see http://docs.angularjs.org/api/ng.$controllerProvider + /////////////////////////////////////////////////////////////////////////// + interface IControllerService { + // Although the documentation doesn't state this, locals are optional + (controllerConstructor: Function, locals?: any, bindToController?: any): any; + (controllerName: string, locals?: any, bindToController?: any): any; + } + + interface IControllerProvider extends IServiceProvider { + register(name: string, controllerConstructor: Function): void; + register(name: string, dependencyAnnotatedConstructor: any[]): void; + allowGlobals(): void; + } + + /** + * HttpService + * see http://docs.angularjs.org/api/ng/service/$http + */ + interface IHttpService { + /** + * Object describing the request to be made and how it should be processed. + */ + (config: IRequestConfig): IHttpPromise; + + /** + * Shortcut method to perform GET request. + * + * @param url Relative or absolute URL specifying the destination of the request + * @param config Optional configuration object + */ + get(url: string, config?: IRequestShortcutConfig): IHttpPromise; + + /** + * Shortcut method to perform DELETE request. + * + * @param url Relative or absolute URL specifying the destination of the request + * @param config Optional configuration object + */ + delete(url: string, config?: IRequestShortcutConfig): IHttpPromise; + + /** + * Shortcut method to perform HEAD request. + * + * @param url Relative or absolute URL specifying the destination of the request + * @param config Optional configuration object + */ + head(url: string, config?: IRequestShortcutConfig): IHttpPromise; + + /** + * Shortcut method to perform JSONP request. + * + * @param url Relative or absolute URL specifying the destination of the request + * @param config Optional configuration object + */ + jsonp(url: string, config?: IRequestShortcutConfig): IHttpPromise; + + /** + * Shortcut method to perform POST request. + * + * @param url Relative or absolute URL specifying the destination of the request + * @param data Request content + * @param config Optional configuration object + */ + post(url: string, data: any, config?: IRequestShortcutConfig): IHttpPromise; + + /** + * Shortcut method to perform PUT request. + * + * @param url Relative or absolute URL specifying the destination of the request + * @param data Request content + * @param config Optional configuration object + */ + put(url: string, data: any, config?: IRequestShortcutConfig): IHttpPromise; + + /** + * Shortcut method to perform PATCH request. + * + * @param url Relative or absolute URL specifying the destination of the request + * @param data Request content + * @param config Optional configuration object + */ + patch(url: string, data: any, config?: IRequestShortcutConfig): IHttpPromise; + + /** + * Runtime equivalent of the $httpProvider.defaults property. Allows configuration of default headers, withCredentials as well as request and response transformations. + */ + defaults: IHttpProviderDefaults; + + /** + * Array of config objects for currently pending requests. This is primarily meant to be used for debugging purposes. + */ + pendingRequests: IRequestConfig[]; + } + + /** + * Object describing the request to be made and how it should be processed. + * see http://docs.angularjs.org/api/ng/service/$http#usage + */ + interface IRequestShortcutConfig extends IHttpProviderDefaults { + /** + * {Object.} + * Map of strings or objects which will be turned to ?key1=value1&key2=value2 after the url. If the value is not a string, it will be JSONified. + */ + params?: any; + + /** + * {string|Object} + * Data to be sent as the request message data. + */ + data?: any; + + /** + * Timeout in milliseconds, or promise that should abort the request when resolved. + */ + timeout?: number|IPromise; + + /** + * See [XMLHttpRequest.responseType]https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#xmlhttprequest-responsetype + */ + responseType?: string; + } + + /** + * Object describing the request to be made and how it should be processed. + * see http://docs.angularjs.org/api/ng/service/$http#usage + */ + interface IRequestConfig extends IRequestShortcutConfig { + /** + * HTTP method (e.g. 'GET', 'POST', etc) + */ + method: string; + /** + * Absolute or relative URL of the resource that is being requested. + */ + url: string; + } + + interface IHttpHeadersGetter { + (): { [name: string]: string; }; + (headerName: string): string; + } + + interface IHttpPromiseCallback { + (data: T, status: number, headers: IHttpHeadersGetter, config: IRequestConfig): void; + } + + interface IHttpPromiseCallbackArg { + data?: T; + status?: number; + headers?: IHttpHeadersGetter; + config?: IRequestConfig; + statusText?: string; + } + + interface IHttpPromise extends IPromise> { + success(callback: IHttpPromiseCallback): IHttpPromise; + error(callback: IHttpPromiseCallback): IHttpPromise; + then(successCallback: (response: IHttpPromiseCallbackArg) => IPromise|TResult, errorCallback?: (response: IHttpPromiseCallbackArg) => any): IPromise; + } + + // See the jsdoc for transformData() at https://github.com/angular/angular.js/blob/master/src/ng/http.js#L228 + interface IHttpResquestTransformer { + (data: any, headersGetter: IHttpHeadersGetter): any; + } + + // The definition of fields are the same as IHttpPromiseCallbackArg + interface IHttpResponseTransformer { + (data: any, headersGetter: IHttpHeadersGetter, status: number): any; + } + + interface IHttpRequestConfigHeaders { + [requestType: string]: string|(() => string); + common?: string|(() => string); + get?: string|(() => string); + post?: string|(() => string); + put?: string|(() => string); + patch?: string|(() => string); + } + + /** + * Object that controls the defaults for $http provider. Not all fields of IRequestShortcutConfig can be configured + * via defaults and the docs do not say which. The following is based on the inspection of the source code. + * https://docs.angularjs.org/api/ng/service/$http#defaults + * https://docs.angularjs.org/api/ng/service/$http#usage + * https://docs.angularjs.org/api/ng/provider/$httpProvider The properties section + */ + interface IHttpProviderDefaults { + /** + * {boolean|Cache} + * If true, a default $http cache will be used to cache the GET request, otherwise if a cache instance built with $cacheFactory, this cache will be used for caching. + */ + cache?: any; + + /** + * Transform function or an array of such functions. The transform function takes the http request body and + * headers and returns its transformed (typically serialized) version. + * @see {@link https://docs.angularjs.org/api/ng/service/$http#transforming-requests-and-responses} + */ + transformRequest?: IHttpResquestTransformer |IHttpResquestTransformer[]; + + /** + * Transform function or an array of such functions. The transform function takes the http response body and + * headers and returns its transformed (typically deserialized) version. + */ + transformResponse?: IHttpResponseTransformer | IHttpResponseTransformer[]; + + /** + * Map of strings or functions which return strings representing HTTP headers to send to the server. If the + * return value of a function is null, the header will not be sent. + * The key of the map is the request verb in lower case. The "common" key applies to all requests. + * @see {@link https://docs.angularjs.org/api/ng/service/$http#setting-http-headers} + */ + headers?: IHttpRequestConfigHeaders; + + /** Name of HTTP header to populate with the XSRF token. */ + xsrfHeaderName?: string; + + /** Name of cookie containing the XSRF token. */ + xsrfCookieName?: string; + + /** + * whether to to set the withCredentials flag on the XHR object. See [requests with credentials]https://developer.mozilla.org/en/http_access_control#section_5 for more information. + */ + withCredentials?: boolean; + + /** + * A function used to the prepare string representation of request parameters (specified as an object). If + * specified as string, it is interpreted as a function registered with the $injector. Defaults to + * $httpParamSerializer. + */ + paramSerializer?: string | ((obj: any) => string); + } + + interface IHttpInterceptor { + request?: (config: IRequestConfig) => IRequestConfig|IPromise; + requestError?: (rejection: any) => any; + response?: (response: IHttpPromiseCallbackArg) => IPromise|T; + responseError?: (rejection: any) => any; + } + + interface IHttpInterceptorFactory { + (...args: any[]): IHttpInterceptor; + } + + interface IHttpProvider extends IServiceProvider { + defaults: IHttpProviderDefaults; + + /** + * Register service factories (names or implementations) for interceptors which are called before and after + * each request. + */ + interceptors: (string|IHttpInterceptorFactory|(string|IHttpInterceptorFactory)[])[]; + useApplyAsync(): boolean; + useApplyAsync(value: boolean): IHttpProvider; + + /** + * + * @param {boolean=} value If true, `$http` will return a normal promise without the `success` and `error` methods. + * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining. + * otherwise, returns the current configured value. + */ + useLegacyPromiseExtensions(value:boolean) : boolean | IHttpProvider; + } + + /////////////////////////////////////////////////////////////////////////// + // HttpBackendService + // see http://docs.angularjs.org/api/ng.$httpBackend + // You should never need to use this service directly. + /////////////////////////////////////////////////////////////////////////// + interface IHttpBackendService { + // XXX Perhaps define callback signature in the future + (method: string, url: string, post?: any, callback?: Function, headers?: any, timeout?: number, withCredentials?: boolean): void; + } + + /////////////////////////////////////////////////////////////////////////// + // InterpolateService + // see http://docs.angularjs.org/api/ng.$interpolate + // see http://docs.angularjs.org/api/ng.$interpolateProvider + /////////////////////////////////////////////////////////////////////////// + interface IInterpolateService { + (text: string, mustHaveExpression?: boolean, trustedContext?: string, allOrNothing?: boolean): IInterpolationFunction; + endSymbol(): string; + startSymbol(): string; + } + + interface IInterpolationFunction { + (context: any): string; + } + + interface IInterpolateProvider extends IServiceProvider { + startSymbol(): string; + startSymbol(value: string): IInterpolateProvider; + endSymbol(): string; + endSymbol(value: string): IInterpolateProvider; + } + + /////////////////////////////////////////////////////////////////////////// + // TemplateCacheService + // see http://docs.angularjs.org/api/ng.$templateCache + /////////////////////////////////////////////////////////////////////////// + interface ITemplateCacheService extends ICacheObject {} + + /////////////////////////////////////////////////////////////////////////// + // SCEService + // see http://docs.angularjs.org/api/ng.$sce + /////////////////////////////////////////////////////////////////////////// + interface ISCEService { + getTrusted(type: string, mayBeTrusted: any): any; + getTrustedCss(value: any): any; + getTrustedHtml(value: any): any; + getTrustedJs(value: any): any; + getTrustedResourceUrl(value: any): any; + getTrustedUrl(value: any): any; + parse(type: string, expression: string): (context: any, locals: any) => any; + parseAsCss(expression: string): (context: any, locals: any) => any; + parseAsHtml(expression: string): (context: any, locals: any) => any; + parseAsJs(expression: string): (context: any, locals: any) => any; + parseAsResourceUrl(expression: string): (context: any, locals: any) => any; + parseAsUrl(expression: string): (context: any, locals: any) => any; + trustAs(type: string, value: any): any; + trustAsHtml(value: any): any; + trustAsJs(value: any): any; + trustAsResourceUrl(value: any): any; + trustAsUrl(value: any): any; + isEnabled(): boolean; + } + + /////////////////////////////////////////////////////////////////////////// + // SCEProvider + // see http://docs.angularjs.org/api/ng.$sceProvider + /////////////////////////////////////////////////////////////////////////// + interface ISCEProvider extends IServiceProvider { + enabled(value: boolean): void; + } + + /////////////////////////////////////////////////////////////////////////// + // SCEDelegateService + // see http://docs.angularjs.org/api/ng.$sceDelegate + /////////////////////////////////////////////////////////////////////////// + interface ISCEDelegateService { + getTrusted(type: string, mayBeTrusted: any): any; + trustAs(type: string, value: any): any; + valueOf(value: any): any; + } + + + /////////////////////////////////////////////////////////////////////////// + // SCEDelegateProvider + // see http://docs.angularjs.org/api/ng.$sceDelegateProvider + /////////////////////////////////////////////////////////////////////////// + interface ISCEDelegateProvider extends IServiceProvider { + resourceUrlBlacklist(blacklist: any[]): void; + resourceUrlWhitelist(whitelist: any[]): void; + resourceUrlBlacklist(): any[]; + resourceUrlWhitelist(): any[]; + } + + /** + * $templateRequest service + * see http://docs.angularjs.org/api/ng/service/$templateRequest + */ + interface ITemplateRequestService { + /** + * Downloads a template using $http and, upon success, stores the + * contents inside of $templateCache. + * + * If the HTTP request fails or the response data of the HTTP request is + * empty then a $compile error will be thrown (unless + * {ignoreRequestError} is set to true). + * + * @param tpl The template URL. + * @param ignoreRequestError Whether or not to ignore the exception + * when the request fails or the template is + * empty. + * + * @return A promise whose value is the template content. + */ + (tpl: string, ignoreRequestError?: boolean): IPromise; + /** + * total amount of pending template requests being downloaded. + * @type {number} + */ + totalPendingRequests: number; + } + + /////////////////////////////////////////////////////////////////////////// + // Directive + // see http://docs.angularjs.org/api/ng.$compileProvider#directive + // and http://docs.angularjs.org/guide/directive + /////////////////////////////////////////////////////////////////////////// + + interface IDirectiveFactory { + (...args: any[]): IDirective; + } + + interface IDirectiveLinkFn { + ( + scope: IScope, + instanceElement: IAugmentedJQuery, + instanceAttributes: IAttributes, + controller: {}, + transclude: ITranscludeFunction + ): void; + } + + interface IDirectivePrePost { + pre?: IDirectiveLinkFn; + post?: IDirectiveLinkFn; + } + + interface IDirectiveCompileFn { + ( + templateElement: IAugmentedJQuery, + templateAttributes: IAttributes, + transclude: ITranscludeFunction + ): IDirectivePrePost; + } + + interface IDirective { + compile?: IDirectiveCompileFn; + controller?: any; + controllerAs?: string; + bindToController?: boolean|Object; + link?: IDirectiveLinkFn | IDirectivePrePost; + name?: string; + priority?: number; + replace?: boolean; + require?: any; + restrict?: string; + scope?: any; + template?: any; + templateUrl?: any; + terminal?: boolean; + transclude?: any; + } + + /** + * angular.element + * when calling angular.element, angular returns a jQuery object, + * augmented with additional methods like e.g. scope. + * see: http://docs.angularjs.org/api/angular.element + */ + interface IAugmentedJQueryStatic extends JQueryStatic { + (selector: string, context?: any): IAugmentedJQuery; + (element: Element): IAugmentedJQuery; + (object: {}): IAugmentedJQuery; + (elementArray: Element[]): IAugmentedJQuery; + (object: JQuery): IAugmentedJQuery; + (func: Function): IAugmentedJQuery; + (array: any[]): IAugmentedJQuery; + (): IAugmentedJQuery; + } + + interface IAugmentedJQuery extends JQuery { + // TODO: events, how to define? + //$destroy + + find(selector: string): IAugmentedJQuery; + find(element: any): IAugmentedJQuery; + find(obj: JQuery): IAugmentedJQuery; + controller(): any; + controller(name: string): any; + injector(): any; + scope(): IScope; + isolateScope(): IScope; + + inheritedData(key: string, value: any): JQuery; + inheritedData(obj: { [key: string]: any; }): JQuery; + inheritedData(key?: string): any; + } + + /////////////////////////////////////////////////////////////////////// + // AnimateService + // see http://docs.angularjs.org/api/ng.$animate + /////////////////////////////////////////////////////////////////////// + interface IAnimateService { + addClass(element: JQuery, className: string, done?: Function): IPromise; + enter(element: JQuery, parent: JQuery, after: JQuery, done?: Function): void; + leave(element: JQuery, done?: Function): void; + move(element: JQuery, parent: JQuery, after: JQuery, done?: Function): void; + removeClass(element: JQuery, className: string, done?: Function): void; + } + + /////////////////////////////////////////////////////////////////////////// + // AUTO module (angular.js) + /////////////////////////////////////////////////////////////////////////// + export module auto { + + /////////////////////////////////////////////////////////////////////// + // InjectorService + // see http://docs.angularjs.org/api/AUTO.$injector + /////////////////////////////////////////////////////////////////////// + interface IInjectorService { + annotate(fn: Function): string[]; + annotate(inlineAnnotatedFunction: any[]): string[]; + get(name: string, caller?: string): T; + has(name: string): boolean; + instantiate(typeConstructor: Function, locals?: any): T; + invoke(inlineAnnotatedFunction: any[]): any; + invoke(func: Function, context?: any, locals?: any): any; + } + + /////////////////////////////////////////////////////////////////////// + // ProvideService + // see http://docs.angularjs.org/api/AUTO.$provide + /////////////////////////////////////////////////////////////////////// + interface IProvideService { + // Documentation says it returns the registered instance, but actual + // implementation does not return anything. + // constant(name: string, value: any): any; + /** + * Register a constant service, such as a string, a number, an array, an object or a function, with the $injector. Unlike value it can be injected into a module configuration function (see config) and it cannot be overridden by an Angular decorator. + * + * @param name The name of the constant. + * @param value The constant value. + */ + constant(name: string, value: any): void; + + /** + * Register a service decorator with the $injector. A service decorator intercepts the creation of a service, allowing it to override or modify the behaviour of the service. The object returned by the decorator may be the original service, or a new service object which replaces or wraps and delegates to the original service. + * + * @param name The name of the service to decorate. + * @param decorator This function will be invoked when the service needs to be instantiated and should return the decorated service instance. The function is called using the injector.invoke method and is therefore fully injectable. Local injection arguments: + * + * $delegate - The original service instance, which can be monkey patched, configured, decorated or delegated to. + */ + decorator(name: string, decorator: Function): void; + /** + * Register a service decorator with the $injector. A service decorator intercepts the creation of a service, allowing it to override or modify the behaviour of the service. The object returned by the decorator may be the original service, or a new service object which replaces or wraps and delegates to the original service. + * + * @param name The name of the service to decorate. + * @param inlineAnnotatedFunction This function will be invoked when the service needs to be instantiated and should return the decorated service instance. The function is called using the injector.invoke method and is therefore fully injectable. Local injection arguments: + * + * $delegate - The original service instance, which can be monkey patched, configured, decorated or delegated to. + */ + decorator(name: string, inlineAnnotatedFunction: any[]): void; + factory(name: string, serviceFactoryFunction: Function): IServiceProvider; + factory(name: string, inlineAnnotatedFunction: any[]): IServiceProvider; + provider(name: string, provider: IServiceProvider): IServiceProvider; + provider(name: string, serviceProviderConstructor: Function): IServiceProvider; + service(name: string, constructor: Function): IServiceProvider; + value(name: string, value: any): IServiceProvider; + } + + } +} diff --git a/tooling/typings/chroma.d.ts b/tooling/typings/chroma.d.ts new file mode 100644 index 0000000..62689b8 --- /dev/null +++ b/tooling/typings/chroma.d.ts @@ -0,0 +1,4 @@ +interface Function { + $componentName?: string; + $factory?: any; +} diff --git a/tooling/typings/cordova-plugin-app-preferences/cordova-plugin-app-preferences.d.ts b/tooling/typings/cordova-plugin-app-preferences/cordova-plugin-app-preferences.d.ts new file mode 100644 index 0000000..8e5cbb3 --- /dev/null +++ b/tooling/typings/cordova-plugin-app-preferences/cordova-plugin-app-preferences.d.ts @@ -0,0 +1,29 @@ +/** + * Created by martin on 11/21/16. + */ +interface Plugins { + getAppVersion: { + prepareKey: any; + fetch: any; + store: any; + remove: any; + clearAll: any; + show: any; + watch: any; + }; + appPreferences: any; +} + +interface Window { + plugins: Plugins; + AppPreferences: any; +} + +declare let plugins: Plugins; + +declare let AppPreferences: any; + +declare module 'plugins' { + export = plugins; +} + diff --git a/tooling/typings/cordova-plugin-app-version/cordova-plugin-app-version.d.ts b/tooling/typings/cordova-plugin-app-version/cordova-plugin-app-version.d.ts new file mode 100644 index 0000000..68ccfa9 --- /dev/null +++ b/tooling/typings/cordova-plugin-app-version/cordova-plugin-app-version.d.ts @@ -0,0 +1,25 @@ +// Type definitions for cordova-plugin-app-version v0.1.7 +// Project: https://github.com/whiteoctober/cordova-plugin-app-version +// Definitions by: Markus Wagner +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + +/// + +interface Cordova { + getAppVersion: { + getAppName: () => JQueryPromise; + getPackageName: () => JQueryPromise; + getVersionCode: () => JQueryPromise; + getVersionNumber: () => JQueryPromise; + }; +} + +interface Window { + cordova: Cordova; +} + +declare var cordova: Cordova; + +declare module 'cordova' { + export = cordova; +} \ No newline at end of file diff --git a/tooling/typings/cordova-plugin-hockeyapp/cordova-plugin-hockeyapp.d.ts b/tooling/typings/cordova-plugin-hockeyapp/cordova-plugin-hockeyapp.d.ts new file mode 100644 index 0000000..4ae3ea8 --- /dev/null +++ b/tooling/typings/cordova-plugin-hockeyapp/cordova-plugin-hockeyapp.d.ts @@ -0,0 +1,29 @@ +/** + * Created by martin on 11/3/16. + */ + +interface Hockeyapp { + start: (success: any, failure: any, appId: any, autoSend?: any, ignoreDefaultHandler?: any, loginMode?: any, appSecret?: any) => void; + feedback: (success: any, failure: any) => void; + forceCrash: (success: any, failure: any) => void; + checkForUpdate: (success: any, failure: any) => void; + addMetaData: (success: any, failure: any, data: any) => void; + trackEvent: (success: any, failure: any, eventName: any) => void; + + loginMode: { + ANONYMOUS: any, + EMAIL_ONLY: any, + EMAIL_PASSWORD: any, + VALIDATE: any + }; +} + +interface Window { + hockeyapp: Hockeyapp; +} + +declare let hockeyapp: Hockeyapp; + +declare module 'hockeyapp' { + export = hockeyapp; +} \ No newline at end of file diff --git a/tooling/typings/ionic/ionic.d.ts b/tooling/typings/ionic/ionic.d.ts new file mode 100644 index 0000000..239f775 --- /dev/null +++ b/tooling/typings/ionic/ionic.d.ts @@ -0,0 +1,300 @@ +// Type definitions for Ionic +// Project: http://ionicframework.com +// Definitions by: Spencer Williams +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +/// + +interface IonicStatic { + version: string; +} + +declare var ionic: IonicStatic; + +declare module 'ionic' { + export = ionic; +} + +declare module ionic { + module actionSheet { + interface IonicActionSheetService { + show(options: IonicActionSheetOptions): ()=>void; + } + interface IonicActionSheetOptions { + buttons?: Array; + titleText?: string; + cancelText?: string; + destructiveText?: string; + cancel?: ()=>any; + buttonClicked?: (index: any)=>any; + destructiveButtonClicked?: ()=>any; + cancelOnStateChange?: boolean; + cssClass?: string; + } + } + module backdrop { + interface IonicBackdropService { + retain(): void; + release(): void; + } + } + module gestures { + interface IonicGestureService { + on(eventType: string, callback: (e: any)=>any, $element: ng.IAugmentedJQuery, options: any): IonicGesture; + off(gesture: IonicGesture, eventType: string, callback: (e: any)=>any): void; + } + + interface IonicGesture { + element: Element; + enabled: boolean; + options: {stop_browser_behavior: string }; + on(gesture: string, handler: Function): IonicGesture; + off(gesture: string, handler: Function): IonicGesture; + trigger(gesture: string, eventData: any): IonicGesture; + enable(state: boolean): IonicGesture; + } + + } + module list { + interface IonicListDelegate { + showReorder(showReorder?: boolean): boolean; + showDelete(showDelete?: boolean): boolean; + canSwipeItems(canSwipeItems?: boolean): boolean; + closeOptionButtons(): void; + $getByHandle(handle: string): IonicListDelegate; + } + } + module loading { + interface IonicLoadingService { + show(opts?: IonicLoadingOptions): void; + hide(): void; + } + interface IonicLoadingOptions { + template?: string; + templateUrl?: string; + scope?: any; + noBackdrop?: boolean; + hideOnStateChange?: boolean; + delay?: number; + duration?: number; + } + } + module modal { + interface IonicModalService { + fromTemplate(templateString: string, options?: IonicModalOptions): IonicModalController; + fromTemplateUrl(templateUrl: string, options?: IonicModalOptions): ng.IPromise; + } + + interface IonicModalController { + initialize(options: IonicModalOptions): void; + show(): ng.IPromise; + hide(): ng.IPromise; + isShown(): boolean; + } + + interface IonicModalOptions { + scope?: any; + animation?: string; + focusFirstInput?: boolean; + backdropClickToClose?: boolean; + hardwareBackButtonClose?: boolean; + } + } + module navigation { + interface IonicNavBarDelegate { + align(direction?: string): void; + showBackButton(show?: boolean): boolean; + showBar(show?: boolean): boolean; + title(title: string): void; + } + + interface IonicHistoryService { + viewHistory(): any; + + currentView(): any; + currentHistoryId(): string; + currentTitle(val?: string): string; + + backView(): any; + backTitle(): string; + + forwardView(): any; + + currentStateName(): string; + + goBack(backCount?: number): void; + clearHistory(): void; + clearCache(): ng.IPromise; + nextViewOptions(options: IonicHistoryNextViewOptions): void; + } + interface IonicHistoryNextViewOptions { + disableAnimate?: boolean; + disableBack?: boolean; + historyRoot?: boolean; + } + } + module platform { + interface IonicPlatformService { + onHardwareBackButton(callback: Function): void; + offHardwareBackButton(callback: Function): void; + registerBackButtonAction(callback: Function, priority: number, actionId?: any): Function; + on(type: string, callback: Function): Function; + ready(callback?: Function): ng.IPromise; + } + } + module popover { + interface IonicPopoverService { + fromTemplate(templateString: string, options: IonicPopoverOptions): IonicPopoverController; + fromTemplateUrl(templateUrl: string, options: IonicPopoverOptions): ng.IPromise; + } + interface IonicPopoverController { + initialize(options: IonicPopoverOptions): void; + show($event?: any): ng.IPromise; + hide(): ng.IPromise; + isShown(): boolean; + } + interface IonicPopoverOptions { + scope?: any; + focusFirstInput?: boolean; + backdropClickToClose?: boolean; + hardwareBackButtonClose?: boolean; + } + } + module popup { + interface IonicPopupService { + show(options: IonicPopupFullOptions): IonicPopupPromise; + alert(options: IonicPopupAlertOptions): IonicPopupPromise; + confirm(options: IonicPopupConfirmOptions): IonicPopupPromise; + prompt(options: IonicPopupPromptOptions): IonicPopupPromise; + } + + interface IonicPopupPromise extends ng.IPromise { + close(value?: any): any; + } + interface IonicPopupBaseOptions { + title?: string; + cssClass?: string; + subTitle?: string; + template?: string; + templateUrl?: string; + } + interface IonicPopupFullOptions extends IonicPopupBaseOptions { + scope?: any; + buttons?: Array; + } + interface IonicPopupButton { + text: string; + type?: string; + onTap?(event?: any): void; + } + interface IonicPopupAlertOptions extends IonicPopupBaseOptions { + okText?: string; + okType?: string; + } + interface IonicPopupConfirmOptions extends IonicPopupBaseOptions { + cancelText?: string; + cancelType?: string; + okText?: string; + okType?: string; + } + interface IonicPopupPromptOptions extends IonicPopupBaseOptions { + inputType?: string; + inputPlaceholder?: string; + cancelText?: string; + cancelType?: string; + okText?: string; + okType?: string; + } + } + module scroll { + interface IonicScrollDelegate { + resize(): void; + scrollTop(shouldAnimate?: boolean): void; + scrollBottom(shouldAnimate?: boolean): void; + scrollTo(left: number, top: number, shouldAnimate?: boolean): void; + scrollBy(left: number, top: number, shouldAnimate?: boolean): void; + zoomTo(level: number, animate?: boolean, originLeft?: number, originTop?: number): void; + zoomBy(factor: number, animate?: boolean, originLeft?: number, originTop?: number): void; + getScrollPosition(): {left: number; top: number}; + anchorScroll(shouldAnimate?: boolean): void; + freezeScroll(shouldFreeze?: boolean): boolean; + freezeAllScrolls(shouldFreeze?: boolean): boolean; + getScrollView(): any; + $getByHandle(handle: string): IonicScrollDelegate; + } + } + module sideMenu { + interface IonicSideMenuDelegate { + toggleLeft(isOpen?: boolean): void; + toggleRight(isOpen?: boolean): void; + getOpenRatio(): number; + isOpen(): boolean; + isOpenLeft(): boolean; + isOpenRight(): boolean; + canDragContent(canDrag?: boolean): boolean; + edgeDragThreshold(value?: boolean|number): boolean; + $getByHandle(handle: string): IonicSideMenuDelegate; + } + } + module slideBox { + interface IonicSlideBoxDelegate { + update(): void; + slide(to: number, speed?: number): void; + enableSlide(shouldEnable?: boolean): boolean; + previous(speed?: number): void; + next(speed?: number): void; + stop(): void; + start(): void; + currentIndex(): number; + slidesCount(): number; + $getByHandle(handle: string): IonicSlideBoxDelegate; + } + } + module tabs { + interface IonicTabsDelegate { + select(index: number): void; + selectedIndex(): number; + $getByHandle(handle: string): IonicTabsDelegate; + } + } + module utility { + interface IonicConfigProvider { + views: { + transition(transition?: string): string; + maxCache(maxNumber?: number): number; + forwardCache(value?: boolean): boolean; + }; + scrolling: { + jsScrolling(value?: boolean): boolean; + }; + backButton: { + icon(value?: string): string; + text(value?: string): string; + previousTitleText(value?: boolean): boolean; + }; + form: { + checkbox(value?: string): string; + toggle(value?: string): string; + }; + spinner: { + icon(value?: string): string; + }; + tabs: { + style(value?: string): string; + position(value?: string): string; + }; + templates: { + maxPrefetch(value?: number): number; + }; + navBar: { + alignTitle(value?: string): string; + positionPrimaryButtons(value?: string): string; + positionSecondaryButtons(value?: string): string; + }; + } + interface IonicPositionService { + position(element: any): {top: number; left: number; width: number; height: number}; + offset(element: any): {top: number; left: number; width: number; height: number}; + } + } +} diff --git a/tooling/typings/jasmine/jasmine.d.ts b/tooling/typings/jasmine/jasmine.d.ts new file mode 100644 index 0000000..24108f6 --- /dev/null +++ b/tooling/typings/jasmine/jasmine.d.ts @@ -0,0 +1,496 @@ +// Type definitions for Jasmine 2.2 +// Project: http://jasmine.github.io/ +// Definitions by: Boris Yankov , Theodore Brown , David Pärsson +// Definitions: https://github.com/borisyankov/DefinitelyTyped + + +// For ddescribe / iit use : https://github.com/borisyankov/DefinitelyTyped/blob/master/karma-jasmine/karma-jasmine.d.ts + +declare function describe(description: string, specDefinitions: () => void): void; +declare function fdescribe(description: string, specDefinitions: () => void): void; +declare function xdescribe(description: string, specDefinitions: () => void): void; + +declare function it(expectation: string, assertion?: () => void, timeout?: number): void; +declare function it(expectation: string, assertion?: (done: () => void) => void, timeout?: number): void; +declare function fit(expectation: string, assertion?: () => void, timeout?: number): void; +declare function fit(expectation: string, assertion?: (done: () => void) => void, timeout?: number): void; +declare function xit(expectation: string, assertion?: () => void, timeout?: number): void; +declare function xit(expectation: string, assertion?: (done: () => void) => void, timeout?: number): void; + +/** If you call the function pending anywhere in the spec body, no matter the expectations, the spec will be marked pending. */ +declare function pending(reason?: string): void; + +declare function beforeEach(action: () => void, timeout?: number): void; +declare function beforeEach(action: (done: () => void) => void, timeout?: number): void; +declare function afterEach(action: () => void, timeout?: number): void; +declare function afterEach(action: (done: () => void) => void, timeout?: number): void; + +declare function beforeAll(action: () => void, timeout?: number): void; +declare function beforeAll(action: (done: () => void) => void, timeout?: number): void; +declare function afterAll(action: () => void, timeout?: number): void; +declare function afterAll(action: (done: () => void) => void, timeout?: number): void; + +declare function expect(spy: Function): jasmine.Matchers; +declare function expect(actual: any): jasmine.Matchers; + +declare function fail(e?: any): void; + +declare function spyOn(object: any, method: string): jasmine.Spy; + +declare function runs(asyncMethod: Function): void; +declare function waitsFor(latchMethod: () => boolean, failureMessage?: string, timeout?: number): void; +declare function waits(timeout?: number): void; + +declare module jasmine { + + var clock: () => Clock; + + function any(aclass: any): Any; + function anything(): Any; + function arrayContaining(sample: any[]): ArrayContaining; + function objectContaining(sample: any): ObjectContaining; + function createSpy(name: string, originalFn?: Function): Spy; + function createSpyObj(baseName: string, methodNames: any[]): any; + function createSpyObj(baseName: string, methodNames: any[]): T; + function pp(value: any): string; + function getEnv(): Env; + function addCustomEqualityTester(equalityTester: CustomEqualityTester): void; + function addMatchers(matchers: CustomMatcherFactories): void; + function stringMatching(str: string): Any; + function stringMatching(str: RegExp): Any; + + interface Any { + + new (expectedClass: any): any; + + jasmineMatches(other: any): boolean; + jasmineToString(): string; + } + + // taken from TypeScript lib.core.es6.d.ts, applicable to CustomMatchers.contains() + interface ArrayLike { + length: number; + [n: number]: T; + } + + interface ArrayContaining { + new (sample: any[]): any; + + asymmetricMatch(other: any): boolean; + jasmineToString(): string; + } + + interface ObjectContaining { + new (sample: any): any; + + jasmineMatches(other: any, mismatchKeys: any[], mismatchValues: any[]): boolean; + jasmineToString(): string; + } + + interface Block { + + new (env: Env, func: SpecFunction, spec: Spec): any; + + execute(onComplete: () => void): void; + } + + interface WaitsBlock extends Block { + new (env: Env, timeout: number, spec: Spec): any; + } + + interface WaitsForBlock extends Block { + new (env: Env, timeout: number, latchFunction: SpecFunction, message: string, spec: Spec): any; + } + + interface Clock { + install(): void; + uninstall(): void; + /** Calls to any registered callback are triggered when the clock is ticked forward via the jasmine.clock().tick function, which takes a number of milliseconds. */ + tick(ms: number): void; + mockDate(date?: Date): void; + } + + interface CustomEqualityTester { + (first: any, second: any): boolean; + } + + interface CustomMatcher { + compare(actual: T, expected: T): CustomMatcherResult; + compare(actual: any, expected: any): CustomMatcherResult; + } + + interface CustomMatcherFactory { + (util: MatchersUtil, customEqualityTesters: Array): CustomMatcher; + } + + interface CustomMatcherFactories { + [index: string]: CustomMatcherFactory; + } + + interface CustomMatcherResult { + pass: boolean; + message: string; + } + + interface MatchersUtil { + equals(a: any, b: any, customTesters?: Array): boolean; + contains(haystack: ArrayLike | string, needle: any, customTesters?: Array): boolean; + buildFailureMessage(matcherName: string, isNot: boolean, actual: any, ...expected: Array): string; + } + + interface Env { + setTimeout: any; + clearTimeout: void; + setInterval: any; + clearInterval: void; + updateInterval: number; + + currentSpec: Spec; + + matchersClass: Matchers; + + version(): any; + versionString(): string; + nextSpecId(): number; + addReporter(reporter: Reporter): void; + execute(): void; + describe(description: string, specDefinitions: () => void): Suite; + // ddescribe(description: string, specDefinitions: () => void): Suite; Not a part of jasmine. Angular team adds these + beforeEach(beforeEachFunction: () => void): void; + beforeAll(beforeAllFunction: () => void): void; + currentRunner(): Runner; + afterEach(afterEachFunction: () => void): void; + afterAll(afterAllFunction: () => void): void; + xdescribe(desc: string, specDefinitions: () => void): XSuite; + it(description: string, func: () => void): Spec; + // iit(description: string, func: () => void): Spec; Not a part of jasmine. Angular team adds these + xit(desc: string, func: () => void): XSpec; + compareRegExps_(a: RegExp, b: RegExp, mismatchKeys: string[], mismatchValues: string[]): boolean; + compareObjects_(a: any, b: any, mismatchKeys: string[], mismatchValues: string[]): boolean; + equals_(a: any, b: any, mismatchKeys: string[], mismatchValues: string[]): boolean; + contains_(haystack: any, needle: any): boolean; + addCustomEqualityTester(equalityTester: CustomEqualityTester): void; + addMatchers(matchers: CustomMatcherFactories): void; + specFilter(spec: Spec): boolean; + } + + interface FakeTimer { + + new (): any; + + reset(): void; + tick(millis: number): void; + runFunctionsWithinRange(oldMillis: number, nowMillis: number): void; + scheduleFunction(timeoutKey: any, funcToCall: () => void, millis: number, recurring: boolean): void; + } + + interface HtmlReporter { + new (): any; + } + + interface HtmlSpecFilter { + new (): any; + } + + interface Result { + type: string; + } + + interface NestedResults extends Result { + description: string; + + totalCount: number; + passedCount: number; + failedCount: number; + + skipped: boolean; + + rollupCounts(result: NestedResults): void; + log(values: any): void; + getItems(): Result[]; + addResult(result: Result): void; + passed(): boolean; + } + + interface MessageResult extends Result { + values: any; + trace: Trace; + } + + interface ExpectationResult extends Result { + matcherName: string; + passed(): boolean; + expected: any; + actual: any; + message: string; + trace: Trace; + } + + interface Trace { + name: string; + message: string; + stack: any; + } + + interface PrettyPrinter { + + new (): any; + + format(value: any): void; + iterateObject(obj: any, fn: (property: string, isGetter: boolean) => void): void; + emitScalar(value: any): void; + emitString(value: string): void; + emitArray(array: any[]): void; + emitObject(obj: any): void; + append(value: any): void; + } + + interface StringPrettyPrinter extends PrettyPrinter { + } + + interface Queue { + + new (env: any): any; + + env: Env; + ensured: boolean[]; + blocks: Block[]; + running: boolean; + index: number; + offset: number; + abort: boolean; + + addBefore(block: Block, ensure?: boolean): void; + add(block: any, ensure?: boolean): void; + insertNext(block: any, ensure?: boolean): void; + start(onComplete?: () => void): void; + isRunning(): boolean; + next_(): void; + results(): NestedResults; + } + + interface Matchers { + + new (env: Env, actual: any, spec: Env, isNot?: boolean): any; + + env: Env; + actual: any; + spec: Env; + isNot?: boolean; + message(): any; + + toBe(expected: any, expectationFailOutput?: any): boolean; + toEqual(expected: any, expectationFailOutput?: any): boolean; + toMatch(expected: any, expectationFailOutput?: any): boolean; + toBeDefined(expectationFailOutput?: any): boolean; + toBeUndefined(expectationFailOutput?: any): boolean; + toBeNull(expectationFailOutput?: any): boolean; + toBeNaN(): boolean; + toBeTruthy(expectationFailOutput?: any): boolean; + toBeFalsy(expectationFailOutput?: any): boolean; + toHaveBeenCalled(): boolean; + toHaveBeenCalledWith(...params: any[]): boolean; + toContain(expected: any, expectationFailOutput?: any): boolean; + toBeLessThan(expected: any, expectationFailOutput?: any): boolean; + toBeGreaterThan(expected: any, expectationFailOutput?: any): boolean; + toBeCloseTo(expected: any, precision: any, expectationFailOutput?: any): boolean; + toContainHtml(expected: string): boolean; + toContainText(expected: string): boolean; + toThrow(expected?: any): boolean; + toThrowError(expected?: any, message?: string): boolean; + not: Matchers; + + Any: Any; + } + + interface Reporter { + reportRunnerStarting(runner: Runner): void; + reportRunnerResults(runner: Runner): void; + reportSuiteResults(suite: Suite): void; + reportSpecStarting(spec: Spec): void; + reportSpecResults(spec: Spec): void; + log(str: string): void; + } + + interface MultiReporter extends Reporter { + addReporter(reporter: Reporter): void; + } + + interface Runner { + + new (env: Env): any; + + execute(): void; + beforeEach(beforeEachFunction: SpecFunction): void; + afterEach(afterEachFunction: SpecFunction): void; + beforeAll(beforeAllFunction: SpecFunction): void; + afterAll(afterAllFunction: SpecFunction): void; + finishCallback(): void; + addSuite(suite: Suite): void; + add(block: Block): void; + specs(): Spec[]; + suites(): Suite[]; + topLevelSuites(): Suite[]; + results(): NestedResults; + } + + interface SpecFunction { + (spec?: Spec): void; + } + + interface SuiteOrSpec { + id: number; + env: Env; + description: string; + queue: Queue; + } + + interface Spec extends SuiteOrSpec { + + new (env: Env, suite: Suite, description: string): any; + + suite: Suite; + + afterCallbacks: SpecFunction[]; + spies_: Spy[]; + + results_: NestedResults; + matchersClass: Matchers; + + getFullName(): string; + results(): NestedResults; + log(arguments: any): any; + runs(func: SpecFunction): Spec; + addToQueue(block: Block): void; + addMatcherResult(result: Result): void; + expect(actual: any): any; + waits(timeout: number): Spec; + waitsFor(latchFunction: SpecFunction, timeoutMessage?: string, timeout?: number): Spec; + fail(e?: any): void; + getMatchersClass_(): Matchers; + addMatchers(matchersPrototype: CustomMatcherFactories): void; + finishCallback(): void; + finish(onComplete?: () => void): void; + after(doAfter: SpecFunction): void; + execute(onComplete?: () => void): any; + addBeforesAndAftersToQueue(): void; + explodes(): void; + spyOn(obj: any, methodName: string, ignoreMethodDoesntExist: boolean): Spy; + removeAllSpies(): void; + } + + interface XSpec { + id: number; + runs(): void; + } + + interface Suite extends SuiteOrSpec { + + new (env: Env, description: string, specDefinitions: () => void, parentSuite: Suite): any; + + parentSuite: Suite; + + getFullName(): string; + finish(onComplete?: () => void): void; + beforeEach(beforeEachFunction: SpecFunction): void; + afterEach(afterEachFunction: SpecFunction): void; + beforeAll(beforeAllFunction: SpecFunction): void; + afterAll(afterAllFunction: SpecFunction): void; + results(): NestedResults; + add(suiteOrSpec: SuiteOrSpec): void; + specs(): Spec[]; + suites(): Suite[]; + children(): any[]; + execute(onComplete?: () => void): void; + } + + interface XSuite { + execute(): void; + } + + interface Spy { + (...params: any[]): any; + + identity: string; + and: SpyAnd; + calls: Calls; + mostRecentCall: { args: any[]; }; + argsForCall: any[]; + wasCalled: boolean; + } + + interface SpyAnd { + /** By chaining the spy with and.callThrough, the spy will still track all calls to it but in addition it will delegate to the actual implementation. */ + callThrough(): Spy; + /** By chaining the spy with and.returnValue, all calls to the function will return a specific value. */ + returnValue(val: any): void; + /** By chaining the spy with and.callFake, all calls to the spy will delegate to the supplied function. */ + callFake(fn: Function): Spy; + /** By chaining the spy with and.throwError, all calls to the spy will throw the specified value. */ + throwError(msg: string): void; + /** When a calling strategy is used for a spy, the original stubbing behavior can be returned at any time with and.stub. */ + stub(): Spy; + } + + interface Calls { + /** By chaining the spy with calls.any(), will return false if the spy has not been called at all, and then true once at least one call happens. **/ + any(): boolean; + /** By chaining the spy with calls.count(), will return the number of times the spy was called **/ + count(): number; + /** By chaining the spy with calls.argsFor(), will return the arguments passed to call number index **/ + argsFor(index: number): any[]; + /** By chaining the spy with calls.allArgs(), will return the arguments to all calls **/ + allArgs(): any[]; + /** By chaining the spy with calls.all(), will return the context (the this) and arguments passed all calls **/ + all(): CallInfo[]; + /** By chaining the spy with calls.mostRecent(), will return the context (the this) and arguments for the most recent call **/ + mostRecent(): CallInfo; + /** By chaining the spy with calls.first(), will return the context (the this) and arguments for the first call **/ + first(): CallInfo; + /** By chaining the spy with calls.reset(), will clears all tracking for a spy **/ + reset(): void; + } + + interface CallInfo { + /** The context (the this) for the call */ + object: any; + /** All arguments passed to the call */ + args: any[]; + } + + interface Util { + inherit(childClass: Function, parentClass: Function): any; + formatException(e: any): any; + htmlEscape(str: string): string; + argsToArray(args: any): any; + extend(destination: any, source: any): any; + } + + interface JsApiReporter extends Reporter { + + started: boolean; + finished: boolean; + result: any; + messages: any; + + new (): any; + + suites(): Suite[]; + summarize_(suiteOrSpec: SuiteOrSpec): any; + results(): any; + resultsForSpec(specId: any): any; + log(str: any): any; + resultsForSpecs(specIds: any): any; + summarizeResult_(result: any): any; + } + + interface Jasmine { + Spec: Spec; + clock: Clock; + util: Util; + } + + export var HtmlReporter: HtmlReporter; + export var HtmlSpecFilter: HtmlSpecFilter; + export var DEFAULT_TIMEOUT_INTERVAL: number; +} diff --git a/tooling/typings/jquery/jquery.d.ts b/tooling/typings/jquery/jquery.d.ts new file mode 100644 index 0000000..51618b7 --- /dev/null +++ b/tooling/typings/jquery/jquery.d.ts @@ -0,0 +1,3178 @@ +// Type definitions for jQuery 1.10.x / 2.0.x +// Project: http://jquery.com/ +// Definitions by: Boris Yankov , Christian Hoffmeister , Steve Fenton , Diullei Gomes , Tass Iliopoulos , Jason Swearingen , Sean Hill , Guus Goossens , Kelly Summerlin , Basarat Ali Syed , Nicholas Wolverson , Derek Cicerone , Andrew Gaspar , James Harrison Fisher , Seikichi Kondo , Benjamin Jackman , Poul Sorensen , Josh Strobl , John Reilly , Dick van den Brink +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +/* ***************************************************************************** +Copyright (c) Microsoft Corporation. All rights reserved. +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +this file except in compliance with the License. You may obtain a copy of the +License at http://www.apache.org/licenses/LICENSE-2.0 + +THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED +WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +MERCHANTABLITY OR NON-INFRINGEMENT. + +See the Apache Version 2.0 License for specific language governing permissions +and limitations under the License. +***************************************************************************** */ + + +/** + * Interface for the AJAX setting that will configure the AJAX request + */ +interface JQueryAjaxSettings { + /** + * The content type sent in the request header that tells the server what kind of response it will accept in return. If the accepts setting needs modification, it is recommended to do so once in the $.ajaxSetup() method. + */ + accepts?: any; + /** + * By default, all requests are sent asynchronously (i.e. this is set to true by default). If you need synchronous requests, set this option to false. Cross-domain requests and dataType: "jsonp" requests do not support synchronous operation. Note that synchronous requests may temporarily lock the browser, disabling any actions while the request is active. As of jQuery 1.8, the use of async: false with jqXHR ($.Deferred) is deprecated; you must use the success/error/complete callback options instead of the corresponding methods of the jqXHR object such as jqXHR.done() or the deprecated jqXHR.success(). + */ + async?: boolean; + /** + * A pre-request callback function that can be used to modify the jqXHR (in jQuery 1.4.x, XMLHTTPRequest) object before it is sent. Use this to set custom headers, etc. The jqXHR and settings objects are passed as arguments. This is an Ajax Event. Returning false in the beforeSend function will cancel the request. As of jQuery 1.5, the beforeSend option will be called regardless of the type of request. + */ + beforeSend? (jqXHR: JQueryXHR, settings: JQueryAjaxSettings): any; + /** + * If set to false, it will force requested pages not to be cached by the browser. Note: Setting cache to false will only work correctly with HEAD and GET requests. It works by appending "_={timestamp}" to the GET parameters. The parameter is not needed for other types of requests, except in IE8 when a POST is made to a URL that has already been requested by a GET. + */ + cache?: boolean; + /** + * A function to be called when the request finishes (after success and error callbacks are executed). The function gets passed two arguments: The jqXHR (in jQuery 1.4.x, XMLHTTPRequest) object and a string categorizing the status of the request ("success", "notmodified", "error", "timeout", "abort", or "parsererror"). As of jQuery 1.5, the complete setting can accept an array of functions. Each function will be called in turn. This is an Ajax Event. + */ + complete? (jqXHR: JQueryXHR, textStatus: string): any; + /** + * An object of string/regular-expression pairs that determine how jQuery will parse the response, given its content type. (version added: 1.5) + */ + contents?: { [key: string]: any; }; + //According to jQuery.ajax source code, ajax's option actually allows contentType to set to "false" + // https://github.com/borisyankov/DefinitelyTyped/issues/742 + /** + * When sending data to the server, use this content type. Default is "application/x-www-form-urlencoded; charset=UTF-8", which is fine for most cases. If you explicitly pass in a content-type to $.ajax(), then it is always sent to the server (even if no data is sent). The W3C XMLHttpRequest specification dictates that the charset is always UTF-8; specifying another charset will not force the browser to change the encoding. + */ + contentType?: any; + /** + * This object will be made the context of all Ajax-related callbacks. By default, the context is an object that represents the ajax settings used in the call ($.ajaxSettings merged with the settings passed to $.ajax). + */ + context?: any; + /** + * An object containing dataType-to-dataType converters. Each converter's value is a function that returns the transformed value of the response. (version added: 1.5) + */ + converters?: { [key: string]: any; }; + /** + * If you wish to force a crossDomain request (such as JSONP) on the same domain, set the value of crossDomain to true. This allows, for example, server-side redirection to another domain. (version added: 1.5) + */ + crossDomain?: boolean; + /** + * Data to be sent to the server. It is converted to a query string, if not already a string. It's appended to the url for GET-requests. See processData option to prevent this automatic processing. Object must be Key/Value pairs. If value is an Array, jQuery serializes multiple values with same key based on the value of the traditional setting (described below). + */ + data?: any; + /** + * A function to be used to handle the raw response data of XMLHttpRequest.This is a pre-filtering function to sanitize the response. You should return the sanitized data. The function accepts two arguments: The raw data returned from the server and the 'dataType' parameter. + */ + dataFilter? (data: any, ty: any): any; + /** + * The type of data that you're expecting back from the server. If none is specified, jQuery will try to infer it based on the MIME type of the response (an XML MIME type will yield XML, in 1.4 JSON will yield a JavaScript object, in 1.4 script will execute the script, and anything else will be returned as a string). + */ + dataType?: string; + /** + * A function to be called if the request fails. The function receives three arguments: The jqXHR (in jQuery 1.4.x, XMLHttpRequest) object, a string describing the type of error that occurred and an optional exception object, if one occurred. Possible values for the second argument (besides null) are "timeout", "error", "abort", and "parsererror". When an HTTP error occurs, errorThrown receives the textual portion of the HTTP status, such as "Not Found" or "Internal Server Error." As of jQuery 1.5, the error setting can accept an array of functions. Each function will be called in turn. Note: This handler is not called for cross-domain script and cross-domain JSONP requests. This is an Ajax Event. + */ + error? (jqXHR: JQueryXHR, textStatus: string, errorThrown: string): any; + /** + * Whether to trigger global Ajax event handlers for this request. The default is true. Set to false to prevent the global handlers like ajaxStart or ajaxStop from being triggered. This can be used to control various Ajax Events. + */ + global?: boolean; + /** + * An object of additional header key/value pairs to send along with requests using the XMLHttpRequest transport. The header X-Requested-With: XMLHttpRequest is always added, but its default XMLHttpRequest value can be changed here. Values in the headers setting can also be overwritten from within the beforeSend function. (version added: 1.5) + */ + headers?: { [key: string]: any; }; + /** + * Allow the request to be successful only if the response has changed since the last request. This is done by checking the Last-Modified header. Default value is false, ignoring the header. In jQuery 1.4 this technique also checks the 'etag' specified by the server to catch unmodified data. + */ + ifModified?: boolean; + /** + * Allow the current environment to be recognized as "local," (e.g. the filesystem), even if jQuery does not recognize it as such by default. The following protocols are currently recognized as local: file, *-extension, and widget. If the isLocal setting needs modification, it is recommended to do so once in the $.ajaxSetup() method. (version added: 1.5.1) + */ + isLocal?: boolean; + /** + * Override the callback function name in a jsonp request. This value will be used instead of 'callback' in the 'callback=?' part of the query string in the url. So {jsonp:'onJSONPLoad'} would result in 'onJSONPLoad=?' passed to the server. As of jQuery 1.5, setting the jsonp option to false prevents jQuery from adding the "?callback" string to the URL or attempting to use "=?" for transformation. In this case, you should also explicitly set the jsonpCallback setting. For example, { jsonp: false, jsonpCallback: "callbackName" } + */ + jsonp?: any; + /** + * Specify the callback function name for a JSONP request. This value will be used instead of the random name automatically generated by jQuery. It is preferable to let jQuery generate a unique name as it'll make it easier to manage the requests and provide callbacks and error handling. You may want to specify the callback when you want to enable better browser caching of GET requests. As of jQuery 1.5, you can also use a function for this setting, in which case the value of jsonpCallback is set to the return value of that function. + */ + jsonpCallback?: any; + /** + * The HTTP method to use for the request (e.g. "POST", "GET", "PUT"). (version added: 1.9.0) + */ + method?: string; + /** + * A mime type to override the XHR mime type. (version added: 1.5.1) + */ + mimeType?: string; + /** + * A password to be used with XMLHttpRequest in response to an HTTP access authentication request. + */ + password?: string; + /** + * By default, data passed in to the data option as an object (technically, anything other than a string) will be processed and transformed into a query string, fitting to the default content-type "application/x-www-form-urlencoded". If you want to send a DOMDocument, or other non-processed data, set this option to false. + */ + processData?: boolean; + /** + * Only applies when the "script" transport is used (e.g., cross-domain requests with "jsonp" or "script" dataType and "GET" type). Sets the charset attribute on the script tag used in the request. Used when the character set on the local page is not the same as the one on the remote script. + */ + scriptCharset?: string; + /** + * An object of numeric HTTP codes and functions to be called when the response has the corresponding code. f the request is successful, the status code functions take the same parameters as the success callback; if it results in an error (including 3xx redirect), they take the same parameters as the error callback. (version added: 1.5) + */ + statusCode?: { [key: string]: any; }; + /** + * A function to be called if the request succeeds. The function gets passed three arguments: The data returned from the server, formatted according to the dataType parameter; a string describing the status; and the jqXHR (in jQuery 1.4.x, XMLHttpRequest) object. As of jQuery 1.5, the success setting can accept an array of functions. Each function will be called in turn. This is an Ajax Event. + */ + success? (data: any, textStatus: string, jqXHR: JQueryXHR): any; + /** + * Set a timeout (in milliseconds) for the request. This will override any global timeout set with $.ajaxSetup(). The timeout period starts at the point the $.ajax call is made; if several other requests are in progress and the browser has no connections available, it is possible for a request to time out before it can be sent. In jQuery 1.4.x and below, the XMLHttpRequest object will be in an invalid state if the request times out; accessing any object members may throw an exception. In Firefox 3.0+ only, script and JSONP requests cannot be cancelled by a timeout; the script will run even if it arrives after the timeout period. + */ + timeout?: number; + /** + * Set this to true if you wish to use the traditional style of param serialization. + */ + traditional?: boolean; + /** + * The type of request to make ("POST" or "GET"), default is "GET". Note: Other HTTP request methods, such as PUT and DELETE, can also be used here, but they are not supported by all browsers. + */ + type?: string; + /** + * A string containing the URL to which the request is sent. + */ + url?: string; + /** + * A username to be used with XMLHttpRequest in response to an HTTP access authentication request. + */ + username?: string; + /** + * Callback for creating the XMLHttpRequest object. Defaults to the ActiveXObject when available (IE), the XMLHttpRequest otherwise. Override to provide your own implementation for XMLHttpRequest or enhancements to the factory. + */ + xhr?: any; + /** + * An object of fieldName-fieldValue pairs to set on the native XHR object. For example, you can use it to set withCredentials to true for cross-domain requests if needed. In jQuery 1.5, the withCredentials property was not propagated to the native XHR and thus CORS requests requiring it would ignore this flag. For this reason, we recommend using jQuery 1.5.1+ should you require the use of it. (version added: 1.5.1) + */ + xhrFields?: { [key: string]: any; }; +} + +/** + * Interface for the jqXHR object + */ +interface JQueryXHR extends XMLHttpRequest, JQueryPromise { + /** + * The .overrideMimeType() method may be used in the beforeSend() callback function, for example, to modify the response content-type header. As of jQuery 1.5.1, the jqXHR object also contains the overrideMimeType() method (it was available in jQuery 1.4.x, as well, but was temporarily removed in jQuery 1.5). + */ + overrideMimeType(mimeType: string): any; + /** + * Cancel the request. + * + * @param statusText A string passed as the textStatus parameter for the done callback. Default value: "canceled" + */ + abort(statusText?: string): void; + /** + * Incorporates the functionality of the .done() and .fail() methods, allowing (as of jQuery 1.8) the underlying Promise to be manipulated. Refer to deferred.then() for implementation details. + */ + then(doneCallback: (data: any, textStatus: string, jqXHR: JQueryXHR) => void, failCallback?: (jqXHR: JQueryXHR, textStatus: string, errorThrown: any) => void): JQueryPromise; + /** + * Property containing the parsed response if the response Content-Type is json + */ + responseJSON?: any; + /** + * A function to be called if the request fails. + */ + error(xhr: JQueryXHR, textStatus: string, errorThrown: string): void; +} + +/** + * Interface for the JQuery callback + */ +interface JQueryCallback { + /** + * Add a callback or a collection of callbacks to a callback list. + * + * @param callbacks A function, or array of functions, that are to be added to the callback list. + */ + add(callbacks: Function): JQueryCallback; + /** + * Add a callback or a collection of callbacks to a callback list. + * + * @param callbacks A function, or array of functions, that are to be added to the callback list. + */ + add(callbacks: Function[]): JQueryCallback; + + /** + * Disable a callback list from doing anything more. + */ + disable(): JQueryCallback; + + /** + * Determine if the callbacks list has been disabled. + */ + disabled(): boolean; + + /** + * Remove all of the callbacks from a list. + */ + empty(): JQueryCallback; + + /** + * Call all of the callbacks with the given arguments + * + * @param arguments The argument or list of arguments to pass back to the callback list. + */ + fire(...arguments: any[]): JQueryCallback; + + /** + * Determine if the callbacks have already been called at least once. + */ + fired(): boolean; + + /** + * Call all callbacks in a list with the given context and arguments. + * + * @param context A reference to the context in which the callbacks in the list should be fired. + * @param arguments An argument, or array of arguments, to pass to the callbacks in the list. + */ + fireWith(context?: any, args?: any[]): JQueryCallback; + + /** + * Determine whether a supplied callback is in a list + * + * @param callback The callback to search for. + */ + has(callback: Function): boolean; + + /** + * Lock a callback list in its current state. + */ + lock(): JQueryCallback; + + /** + * Determine if the callbacks list has been locked. + */ + locked(): boolean; + + /** + * Remove a callback or a collection of callbacks from a callback list. + * + * @param callbacks A function, or array of functions, that are to be removed from the callback list. + */ + remove(callbacks: Function): JQueryCallback; + /** + * Remove a callback or a collection of callbacks from a callback list. + * + * @param callbacks A function, or array of functions, that are to be removed from the callback list. + */ + remove(callbacks: Function[]): JQueryCallback; +} + +/** + * Allows jQuery Promises to interop with non-jQuery promises + */ +interface JQueryGenericPromise { + /** + * Add handlers to be called when the Deferred object is resolved, rejected, or still in progress. + * + * @param doneFilter A function that is called when the Deferred is resolved. + * @param failFilter An optional function that is called when the Deferred is rejected. + */ + then(doneFilter: (value?: T, ...values: any[]) => U|JQueryPromise, failFilter?: (...reasons: any[]) => any, progressFilter?: (...progression: any[]) => any): JQueryPromise; + + /** + * Add handlers to be called when the Deferred object is resolved, rejected, or still in progress. + * + * @param doneFilter A function that is called when the Deferred is resolved. + * @param failFilter An optional function that is called when the Deferred is rejected. + */ + then(doneFilter: (value?: T, ...values: any[]) => void, failFilter?: (...reasons: any[]) => any, progressFilter?: (...progression: any[]) => any): JQueryPromise; +} + +/** + * Interface for the JQuery promise/deferred callbacks + */ +interface JQueryPromiseCallback { + (value?: T, ...args: any[]): void; +} + +interface JQueryPromiseOperator { + (callback1: JQueryPromiseCallback|JQueryPromiseCallback[], ...callbacksN: Array|JQueryPromiseCallback[]>): JQueryPromise; +} + +/** + * Interface for the JQuery promise, part of callbacks + */ +interface JQueryPromise extends JQueryGenericPromise { + /** + * Determine the current state of a Deferred object. + */ + state(): string; + /** + * Add handlers to be called when the Deferred object is either resolved or rejected. + * + * @param alwaysCallbacks1 A function, or array of functions, that is called when the Deferred is resolved or rejected. + * @param alwaysCallbacks2 Optional additional functions, or arrays of functions, that are called when the Deferred is resolved or rejected. + */ + always(alwaysCallback1?: JQueryPromiseCallback|JQueryPromiseCallback[], ...alwaysCallbacksN: Array|JQueryPromiseCallback[]>): JQueryPromise; + /** + * Add handlers to be called when the Deferred object is resolved. + * + * @param doneCallbacks1 A function, or array of functions, that are called when the Deferred is resolved. + * @param doneCallbacks2 Optional additional functions, or arrays of functions, that are called when the Deferred is resolved. + */ + done(doneCallback1?: JQueryPromiseCallback|JQueryPromiseCallback[], ...doneCallbackN: Array|JQueryPromiseCallback[]>): JQueryPromise; + /** + * Add handlers to be called when the Deferred object is rejected. + * + * @param failCallbacks1 A function, or array of functions, that are called when the Deferred is rejected. + * @param failCallbacks2 Optional additional functions, or arrays of functions, that are called when the Deferred is rejected. + */ + fail(failCallback1?: JQueryPromiseCallback|JQueryPromiseCallback[], ...failCallbacksN: Array|JQueryPromiseCallback[]>): JQueryPromise; + /** + * Add handlers to be called when the Deferred object generates progress notifications. + * + * @param progressCallbacks A function, or array of functions, to be called when the Deferred generates progress notifications. + */ + progress(progressCallback1?: JQueryPromiseCallback|JQueryPromiseCallback[], ...progressCallbackN: Array|JQueryPromiseCallback[]>): JQueryPromise; + + // Deprecated - given no typings + pipe(doneFilter?: (x: any) => any, failFilter?: (x: any) => any, progressFilter?: (x: any) => any): JQueryPromise; +} + +/** + * Interface for the JQuery deferred, part of callbacks + */ +interface JQueryDeferred extends JQueryGenericPromise { + /** + * Determine the current state of a Deferred object. + */ + state(): string; + /** + * Add handlers to be called when the Deferred object is either resolved or rejected. + * + * @param alwaysCallbacks1 A function, or array of functions, that is called when the Deferred is resolved or rejected. + * @param alwaysCallbacks2 Optional additional functions, or arrays of functions, that are called when the Deferred is resolved or rejected. + */ + always(alwaysCallback1?: JQueryPromiseCallback|JQueryPromiseCallback[], ...alwaysCallbacksN: Array|JQueryPromiseCallback[]>): JQueryDeferred; + /** + * Add handlers to be called when the Deferred object is resolved. + * + * @param doneCallbacks1 A function, or array of functions, that are called when the Deferred is resolved. + * @param doneCallbacks2 Optional additional functions, or arrays of functions, that are called when the Deferred is resolved. + */ + done(doneCallback1?: JQueryPromiseCallback|JQueryPromiseCallback[], ...doneCallbackN: Array|JQueryPromiseCallback[]>): JQueryDeferred; + /** + * Add handlers to be called when the Deferred object is rejected. + * + * @param failCallbacks1 A function, or array of functions, that are called when the Deferred is rejected. + * @param failCallbacks2 Optional additional functions, or arrays of functions, that are called when the Deferred is rejected. + */ + fail(failCallback1?: JQueryPromiseCallback|JQueryPromiseCallback[], ...failCallbacksN: Array|JQueryPromiseCallback[]>): JQueryDeferred; + /** + * Add handlers to be called when the Deferred object generates progress notifications. + * + * @param progressCallbacks A function, or array of functions, to be called when the Deferred generates progress notifications. + */ + progress(progressCallback1?: JQueryPromiseCallback|JQueryPromiseCallback[], ...progressCallbackN: Array|JQueryPromiseCallback[]>): JQueryDeferred; + + /** + * Call the progressCallbacks on a Deferred object with the given args. + * + * @param args Optional arguments that are passed to the progressCallbacks. + */ + notify(value?: any, ...args: any[]): JQueryDeferred; + + /** + * Call the progressCallbacks on a Deferred object with the given context and args. + * + * @param context Context passed to the progressCallbacks as the this object. + * @param args Optional arguments that are passed to the progressCallbacks. + */ + notifyWith(context: any, value?: any[]): JQueryDeferred; + + /** + * Reject a Deferred object and call any failCallbacks with the given args. + * + * @param args Optional arguments that are passed to the failCallbacks. + */ + reject(value?: any, ...args: any[]): JQueryDeferred; + /** + * Reject a Deferred object and call any failCallbacks with the given context and args. + * + * @param context Context passed to the failCallbacks as the this object. + * @param args An optional array of arguments that are passed to the failCallbacks. + */ + rejectWith(context: any, value?: any[]): JQueryDeferred; + + /** + * Resolve a Deferred object and call any doneCallbacks with the given args. + * + * @param value First argument passed to doneCallbacks. + * @param args Optional subsequent arguments that are passed to the doneCallbacks. + */ + resolve(value?: T, ...args: any[]): JQueryDeferred; + + /** + * Resolve a Deferred object and call any doneCallbacks with the given context and args. + * + * @param context Context passed to the doneCallbacks as the this object. + * @param args An optional array of arguments that are passed to the doneCallbacks. + */ + resolveWith(context: any, value?: T[]): JQueryDeferred; + + /** + * Return a Deferred's Promise object. + * + * @param target Object onto which the promise methods have to be attached + */ + promise(target?: any): JQueryPromise; + + // Deprecated - given no typings + pipe(doneFilter?: (x: any) => any, failFilter?: (x: any) => any, progressFilter?: (x: any) => any): JQueryPromise; +} + +/** + * Interface of the JQuery extension of the W3C event object + */ +interface BaseJQueryEventObject extends Event { + data: any; + delegateTarget: Element; + isDefaultPrevented(): boolean; + isImmediatePropagationStopped(): boolean; + isPropagationStopped(): boolean; + namespace: string; + originalEvent: Event; + preventDefault(): any; + relatedTarget: Element; + result: any; + stopImmediatePropagation(): void; + stopPropagation(): void; + target: Element; + pageX: number; + pageY: number; + which: number; + metaKey: boolean; +} + +interface JQueryInputEventObject extends BaseJQueryEventObject { + altKey: boolean; + ctrlKey: boolean; + metaKey: boolean; + shiftKey: boolean; +} + +interface JQueryMouseEventObject extends JQueryInputEventObject { + button: number; + clientX: number; + clientY: number; + offsetX: number; + offsetY: number; + pageX: number; + pageY: number; + screenX: number; + screenY: number; +} + +interface JQueryKeyEventObject extends JQueryInputEventObject { + char: any; + charCode: number; + key: any; + keyCode: number; +} + +interface JQueryEventObject extends BaseJQueryEventObject, JQueryInputEventObject, JQueryMouseEventObject, JQueryKeyEventObject{ +} + +/* + Collection of properties of the current browser +*/ + +interface JQuerySupport { + ajax?: boolean; + boxModel?: boolean; + changeBubbles?: boolean; + checkClone?: boolean; + checkOn?: boolean; + cors?: boolean; + cssFloat?: boolean; + hrefNormalized?: boolean; + htmlSerialize?: boolean; + leadingWhitespace?: boolean; + noCloneChecked?: boolean; + noCloneEvent?: boolean; + opacity?: boolean; + optDisabled?: boolean; + optSelected?: boolean; + scriptEval? (): boolean; + style?: boolean; + submitBubbles?: boolean; + tbody?: boolean; +} + +interface JQueryParam { + /** + * Create a serialized representation of an array or object, suitable for use in a URL query string or Ajax request. + * + * @param obj An array or object to serialize. + */ + (obj: any): string; + + /** + * Create a serialized representation of an array or object, suitable for use in a URL query string or Ajax request. + * + * @param obj An array or object to serialize. + * @param traditional A Boolean indicating whether to perform a traditional "shallow" serialization. + */ + (obj: any, traditional: boolean): string; +} + +/** + * The interface used to construct jQuery events (with $.Event). It is + * defined separately instead of inline in JQueryStatic to allow + * overriding the construction function with specific strings + * returning specific event objects. + */ +interface JQueryEventConstructor { + (name: string, eventProperties?: any): JQueryEventObject; + new (name: string, eventProperties?: any): JQueryEventObject; +} + +/** + * The interface used to specify coordinates. + */ +interface JQueryCoordinates { + left: number; + top: number; +} + +/** + * Elements in the array returned by serializeArray() + */ +interface JQuerySerializeArrayElement { + name: string; + value: string; +} + +interface JQueryAnimationOptions { + /** + * A string or number determining how long the animation will run. + */ + duration?: any; + /** + * A string indicating which easing function to use for the transition. + */ + easing?: string; + /** + * A function to call once the animation is complete. + */ + complete?: Function; + /** + * A function to be called for each animated property of each animated element. This function provides an opportunity to modify the Tween object to change the value of the property before it is set. + */ + step?: (now: number, tween: any) => any; + /** + * A function to be called after each step of the animation, only once per animated element regardless of the number of animated properties. (version added: 1.8) + */ + progress?: (animation: JQueryPromise, progress: number, remainingMs: number) => any; + /** + * A function to call when the animation begins. (version added: 1.8) + */ + start?: (animation: JQueryPromise) => any; + /** + * A function to be called when the animation completes (its Promise object is resolved). (version added: 1.8) + */ + done?: (animation: JQueryPromise, jumpedToEnd: boolean) => any; + /** + * A function to be called when the animation fails to complete (its Promise object is rejected). (version added: 1.8) + */ + fail?: (animation: JQueryPromise, jumpedToEnd: boolean) => any; + /** + * A function to be called when the animation completes or stops without completing (its Promise object is either resolved or rejected). (version added: 1.8) + */ + always?: (animation: JQueryPromise, jumpedToEnd: boolean) => any; + /** + * A Boolean indicating whether to place the animation in the effects queue. If false, the animation will begin immediately. As of jQuery 1.7, the queue option can also accept a string, in which case the animation is added to the queue represented by that string. When a custom queue name is used the animation does not automatically start; you must call .dequeue("queuename") to start it. + */ + queue?: any; + /** + * A map of one or more of the CSS properties defined by the properties argument and their corresponding easing functions. (version added: 1.4) + */ + specialEasing?: Object; +} + +/** + * Static members of jQuery (those on $ and jQuery themselves) + */ +interface JQueryStatic { + + /** + * Perform an asynchronous HTTP (Ajax) request. + * + * @param settings A set of key/value pairs that configure the Ajax request. All settings are optional. A default can be set for any option with $.ajaxSetup(). + */ + ajax(settings: JQueryAjaxSettings): JQueryXHR; + /** + * Perform an asynchronous HTTP (Ajax) request. + * + * @param url A string containing the URL to which the request is sent. + * @param settings A set of key/value pairs that configure the Ajax request. All settings are optional. A default can be set for any option with $.ajaxSetup(). + */ + ajax(url: string, settings?: JQueryAjaxSettings): JQueryXHR; + + /** + * Handle custom Ajax options or modify existing options before each request is sent and before they are processed by $.ajax(). + * + * @param dataTypes An optional string containing one or more space-separated dataTypes + * @param handler A handler to set default values for future Ajax requests. + */ + ajaxPrefilter(dataTypes: string, handler: (opts: any, originalOpts: JQueryAjaxSettings, jqXHR: JQueryXHR) => any): void; + /** + * Handle custom Ajax options or modify existing options before each request is sent and before they are processed by $.ajax(). + * + * @param handler A handler to set default values for future Ajax requests. + */ + ajaxPrefilter(handler: (opts: any, originalOpts: JQueryAjaxSettings, jqXHR: JQueryXHR) => any): void; + + ajaxSettings: JQueryAjaxSettings; + + /** + * Set default values for future Ajax requests. Its use is not recommended. + * + * @param options A set of key/value pairs that configure the default Ajax request. All options are optional. + */ + ajaxSetup(options: JQueryAjaxSettings): void; + + /** + * Load data from the server using a HTTP GET request. + * + * @param url A string containing the URL to which the request is sent. + * @param success A callback function that is executed if the request succeeds. + * @param dataType The type of data expected from the server. Default: Intelligent Guess (xml, json, script, or html). + */ + get(url: string, success?: (data: any, textStatus: string, jqXHR: JQueryXHR) => any, dataType?: string): JQueryXHR; + /** + * Load data from the server using a HTTP GET request. + * + * @param url A string containing the URL to which the request is sent. + * @param data A plain object or string that is sent to the server with the request. + * @param success A callback function that is executed if the request succeeds. + * @param dataType The type of data expected from the server. Default: Intelligent Guess (xml, json, script, or html). + */ + get(url: string, data?: Object|string, success?: (data: any, textStatus: string, jqXHR: JQueryXHR) => any, dataType?: string): JQueryXHR; + /** + * Load JSON-encoded data from the server using a GET HTTP request. + * + * @param url A string containing the URL to which the request is sent. + * @param success A callback function that is executed if the request succeeds. + */ + getJSON(url: string, success?: (data: any, textStatus: string, jqXHR: JQueryXHR) => any): JQueryXHR; + /** + * Load JSON-encoded data from the server using a GET HTTP request. + * + * @param url A string containing the URL to which the request is sent. + * @param data A plain object or string that is sent to the server with the request. + * @param success A callback function that is executed if the request succeeds. + */ + getJSON(url: string, data?: Object|string, success?: (data: any, textStatus: string, jqXHR: JQueryXHR) => any): JQueryXHR; + /** + * Load a JavaScript file from the server using a GET HTTP request, then execute it. + * + * @param url A string containing the URL to which the request is sent. + * @param success A callback function that is executed if the request succeeds. + */ + getScript(url: string, success?: (script: string, textStatus: string, jqXHR: JQueryXHR) => any): JQueryXHR; + + /** + * Create a serialized representation of an array or object, suitable for use in a URL query string or Ajax request. + */ + param: JQueryParam; + + /** + * Load data from the server using a HTTP POST request. + * + * @param url A string containing the URL to which the request is sent. + * @param success A callback function that is executed if the request succeeds. Required if dataType is provided, but can be null in that case. + * @param dataType The type of data expected from the server. Default: Intelligent Guess (xml, json, script, text, html). + */ + post(url: string, success?: (data: any, textStatus: string, jqXHR: JQueryXHR) => any, dataType?: string): JQueryXHR; + /** + * Load data from the server using a HTTP POST request. + * + * @param url A string containing the URL to which the request is sent. + * @param data A plain object or string that is sent to the server with the request. + * @param success A callback function that is executed if the request succeeds. Required if dataType is provided, but can be null in that case. + * @param dataType The type of data expected from the server. Default: Intelligent Guess (xml, json, script, text, html). + */ + post(url: string, data?: Object|string, success?: (data: any, textStatus: string, jqXHR: JQueryXHR) => any, dataType?: string): JQueryXHR; + + /** + * A multi-purpose callbacks list object that provides a powerful way to manage callback lists. + * + * @param flags An optional list of space-separated flags that change how the callback list behaves. + */ + Callbacks(flags?: string): JQueryCallback; + + /** + * Holds or releases the execution of jQuery's ready event. + * + * @param hold Indicates whether the ready hold is being requested or released + */ + holdReady(hold: boolean): void; + + /** + * Accepts a string containing a CSS selector which is then used to match a set of elements. + * + * @param selector A string containing a selector expression + * @param context A DOM Element, Document, or jQuery to use as context + */ + (selector: string, context?: Element|JQuery): JQuery; + + /** + * Accepts a string containing a CSS selector which is then used to match a set of elements. + * + * @param element A DOM element to wrap in a jQuery object. + */ + (element: Element): JQuery; + + /** + * Accepts a string containing a CSS selector which is then used to match a set of elements. + * + * @param elementArray An array containing a set of DOM elements to wrap in a jQuery object. + */ + (elementArray: Element[]): JQuery; + + /** + * Binds a function to be executed when the DOM has finished loading. + * + * @param callback A function to execute after the DOM is ready. + */ + (callback: (jQueryAlias?: JQueryStatic) => any): JQuery; + + /** + * Accepts a string containing a CSS selector which is then used to match a set of elements. + * + * @param object A plain object to wrap in a jQuery object. + */ + (object: {}): JQuery; + + /** + * Accepts a string containing a CSS selector which is then used to match a set of elements. + * + * @param object An existing jQuery object to clone. + */ + (object: JQuery): JQuery; + + /** + * Specify a function to execute when the DOM is fully loaded. + */ + (): JQuery; + + /** + * Creates DOM elements on the fly from the provided string of raw HTML. + * + * @param html A string of HTML to create on the fly. Note that this parses HTML, not XML. + * @param ownerDocument A document in which the new elements will be created. + */ + (html: string, ownerDocument?: Document): JQuery; + + /** + * Creates DOM elements on the fly from the provided string of raw HTML. + * + * @param html A string defining a single, standalone, HTML element (e.g.
or
). + * @param attributes An object of attributes, events, and methods to call on the newly-created element. + */ + (html: string, attributes: Object): JQuery; + + /** + * Relinquish jQuery's control of the $ variable. + * + * @param removeAll A Boolean indicating whether to remove all jQuery variables from the global scope (including jQuery itself). + */ + noConflict(removeAll?: boolean): Object; + + /** + * Provides a way to execute callback functions based on one or more objects, usually Deferred objects that represent asynchronous events. + * + * @param deferreds One or more Deferred objects, or plain JavaScript objects. + */ + when(...deferreds: Array/* as JQueryDeferred */>): JQueryPromise; + + /** + * Hook directly into jQuery to override how particular CSS properties are retrieved or set, normalize CSS property naming, or create custom properties. + */ + cssHooks: { [key: string]: any; }; + cssNumber: any; + + /** + * Store arbitrary data associated with the specified element. Returns the value that was set. + * + * @param element The DOM element to associate with the data. + * @param key A string naming the piece of data to set. + * @param value The new data value. + */ + data(element: Element, key: string, value: T): T; + /** + * Returns value at named data store for the element, as set by jQuery.data(element, name, value), or the full data store for the element. + * + * @param element The DOM element to associate with the data. + * @param key A string naming the piece of data to set. + */ + data(element: Element, key: string): any; + /** + * Returns value at named data store for the element, as set by jQuery.data(element, name, value), or the full data store for the element. + * + * @param element The DOM element to associate with the data. + */ + data(element: Element): any; + + /** + * Execute the next function on the queue for the matched element. + * + * @param element A DOM element from which to remove and execute a queued function. + * @param queueName A string containing the name of the queue. Defaults to fx, the standard effects queue. + */ + dequeue(element: Element, queueName?: string): void; + + /** + * Determine whether an element has any jQuery data associated with it. + * + * @param element A DOM element to be checked for data. + */ + hasData(element: Element): boolean; + + /** + * Show the queue of functions to be executed on the matched element. + * + * @param element A DOM element to inspect for an attached queue. + * @param queueName A string containing the name of the queue. Defaults to fx, the standard effects queue. + */ + queue(element: Element, queueName?: string): any[]; + /** + * Manipulate the queue of functions to be executed on the matched element. + * + * @param element A DOM element where the array of queued functions is attached. + * @param queueName A string containing the name of the queue. Defaults to fx, the standard effects queue. + * @param newQueue An array of functions to replace the current queue contents. + */ + queue(element: Element, queueName: string, newQueue: Function[]): JQuery; + /** + * Manipulate the queue of functions to be executed on the matched element. + * + * @param element A DOM element on which to add a queued function. + * @param queueName A string containing the name of the queue. Defaults to fx, the standard effects queue. + * @param callback The new function to add to the queue. + */ + queue(element: Element, queueName: string, callback: Function): JQuery; + + /** + * Remove a previously-stored piece of data. + * + * @param element A DOM element from which to remove data. + * @param name A string naming the piece of data to remove. + */ + removeData(element: Element, name?: string): JQuery; + + /** + * A constructor function that returns a chainable utility object with methods to register multiple callbacks into callback queues, invoke callback queues, and relay the success or failure state of any synchronous or asynchronous function. + * + * @param beforeStart A function that is called just before the constructor returns. + */ + Deferred(beforeStart?: (deferred: JQueryDeferred) => any): JQueryDeferred; + + /** + * Effects + */ + fx: { + tick: () => void; + /** + * The rate (in milliseconds) at which animations fire. + */ + interval: number; + stop: () => void; + speeds: { slow: number; fast: number; }; + /** + * Globally disable all animations. + */ + off: boolean; + step: any; + }; + + /** + * Takes a function and returns a new one that will always have a particular context. + * + * @param fnction The function whose context will be changed. + * @param context The object to which the context (this) of the function should be set. + * @param additionalArguments Any number of arguments to be passed to the function referenced in the function argument. + */ + proxy(fnction: (...args: any[]) => any, context: Object, ...additionalArguments: any[]): any; + /** + * Takes a function and returns a new one that will always have a particular context. + * + * @param context The object to which the context (this) of the function should be set. + * @param name The name of the function whose context will be changed (should be a property of the context object). + * @param additionalArguments Any number of arguments to be passed to the function named in the name argument. + */ + proxy(context: Object, name: string, ...additionalArguments: any[]): any; + + Event: JQueryEventConstructor; + + /** + * Takes a string and throws an exception containing it. + * + * @param message The message to send out. + */ + error(message: any): JQuery; + + expr: any; + fn: any; //TODO: Decide how we want to type this + + isReady: boolean; + + // Properties + support: JQuerySupport; + + /** + * Check to see if a DOM element is a descendant of another DOM element. + * + * @param container The DOM element that may contain the other element. + * @param contained The DOM element that may be contained by (a descendant of) the other element. + */ + contains(container: Element, contained: Element): boolean; + + /** + * A generic iterator function, which can be used to seamlessly iterate over both objects and arrays. Arrays and array-like objects with a length property (such as a function's arguments object) are iterated by numeric index, from 0 to length-1. Other objects are iterated via their named properties. + * + * @param collection The object or array to iterate over. + * @param callback The function that will be executed on every object. + */ + each( + collection: T[], + callback: (indexInArray: number, valueOfElement: T) => any + ): any; + + /** + * A generic iterator function, which can be used to seamlessly iterate over both objects and arrays. Arrays and array-like objects with a length property (such as a function's arguments object) are iterated by numeric index, from 0 to length-1. Other objects are iterated via their named properties. + * + * @param collection The object or array to iterate over. + * @param callback The function that will be executed on every object. + */ + each( + collection: any, + callback: (indexInArray: any, valueOfElement: any) => any + ): any; + + /** + * Merge the contents of two or more objects together into the first object. + * + * @param target An object that will receive the new properties if additional objects are passed in or that will extend the jQuery namespace if it is the sole argument. + * @param object1 An object containing additional properties to merge in. + * @param objectN Additional objects containing properties to merge in. + */ + extend(target: any, object1?: any, ...objectN: any[]): any; + /** + * Merge the contents of two or more objects together into the first object. + * + * @param deep If true, the merge becomes recursive (aka. deep copy). + * @param target The object to extend. It will receive the new properties. + * @param object1 An object containing additional properties to merge in. + * @param objectN Additional objects containing properties to merge in. + */ + extend(deep: boolean, target: any, object1?: any, ...objectN: any[]): any; + + /** + * Execute some JavaScript code globally. + * + * @param code The JavaScript code to execute. + */ + globalEval(code: string): any; + + /** + * Finds the elements of an array which satisfy a filter function. The original array is not affected. + * + * @param array The array to search through. + * @param func The function to process each item against. The first argument to the function is the item, and the second argument is the index. The function should return a Boolean value. this will be the global window object. + * @param invert If "invert" is false, or not provided, then the function returns an array consisting of all elements for which "callback" returns true. If "invert" is true, then the function returns an array consisting of all elements for which "callback" returns false. + */ + grep(array: T[], func: (elementOfArray: T, indexInArray: number) => boolean, invert?: boolean): T[]; + + /** + * Search for a specified value within an array and return its index (or -1 if not found). + * + * @param value The value to search for. + * @param array An array through which to search. + * @param fromIndex he index of the array at which to begin the search. The default is 0, which will search the whole array. + */ + inArray(value: T, array: T[], fromIndex?: number): number; + + /** + * Determine whether the argument is an array. + * + * @param obj Object to test whether or not it is an array. + */ + isArray(obj: any): boolean; + /** + * Check to see if an object is empty (contains no enumerable properties). + * + * @param obj The object that will be checked to see if it's empty. + */ + isEmptyObject(obj: any): boolean; + /** + * Determine if the argument passed is a Javascript function object. + * + * @param obj Object to test whether or not it is a function. + */ + isFunction(obj: any): boolean; + /** + * Determines whether its argument is a number. + * + * @param obj The value to be tested. + */ + isNumeric(value: any): boolean; + /** + * Check to see if an object is a plain object (created using "{}" or "new Object"). + * + * @param obj The object that will be checked to see if it's a plain object. + */ + isPlainObject(obj: any): boolean; + /** + * Determine whether the argument is a window. + * + * @param obj Object to test whether or not it is a window. + */ + isWindow(obj: any): boolean; + /** + * Check to see if a DOM node is within an XML document (or is an XML document). + * + * @param node he DOM node that will be checked to see if it's in an XML document. + */ + isXMLDoc(node: Node): boolean; + + /** + * Convert an array-like object into a true JavaScript array. + * + * @param obj Any object to turn into a native Array. + */ + makeArray(obj: any): any[]; + + /** + * Translate all items in an array or object to new array of items. + * + * @param array The Array to translate. + * @param callback The function to process each item against. The first argument to the function is the array item, the second argument is the index in array The function can return any value. Within the function, this refers to the global (window) object. + */ + map(array: T[], callback: (elementOfArray: T, indexInArray: number) => U): U[]; + /** + * Translate all items in an array or object to new array of items. + * + * @param arrayOrObject The Array or Object to translate. + * @param callback The function to process each item against. The first argument to the function is the value; the second argument is the index or key of the array or object property. The function can return any value to add to the array. A returned array will be flattened into the resulting array. Within the function, this refers to the global (window) object. + */ + map(arrayOrObject: any, callback: (value: any, indexOrKey: any) => any): any; + + /** + * Merge the contents of two arrays together into the first array. + * + * @param first The first array to merge, the elements of second added. + * @param second The second array to merge into the first, unaltered. + */ + merge(first: T[], second: T[]): T[]; + + /** + * An empty function. + */ + noop(): any; + + /** + * Return a number representing the current time. + */ + now(): number; + + /** + * Takes a well-formed JSON string and returns the resulting JavaScript object. + * + * @param json The JSON string to parse. + */ + parseJSON(json: string): any; + + /** + * Parses a string into an XML document. + * + * @param data a well-formed XML string to be parsed + */ + parseXML(data: string): XMLDocument; + + /** + * Remove the whitespace from the beginning and end of a string. + * + * @param str Remove the whitespace from the beginning and end of a string. + */ + trim(str: string): string; + + /** + * Determine the internal JavaScript [[Class]] of an object. + * + * @param obj Object to get the internal JavaScript [[Class]] of. + */ + type(obj: any): string; + + /** + * Sorts an array of DOM elements, in place, with the duplicates removed. Note that this only works on arrays of DOM elements, not strings or numbers. + * + * @param array The Array of DOM elements. + */ + unique(array: Element[]): Element[]; + + /** + * Parses a string into an array of DOM nodes. + * + * @param data HTML string to be parsed + * @param context DOM element to serve as the context in which the HTML fragment will be created + * @param keepScripts A Boolean indicating whether to include scripts passed in the HTML string + */ + parseHTML(data: string, context?: HTMLElement, keepScripts?: boolean): any[]; + + /** + * Parses a string into an array of DOM nodes. + * + * @param data HTML string to be parsed + * @param context DOM element to serve as the context in which the HTML fragment will be created + * @param keepScripts A Boolean indicating whether to include scripts passed in the HTML string + */ + parseHTML(data: string, context?: Document, keepScripts?: boolean): any[]; +} + +/** + * The jQuery instance members + */ +interface JQuery { + /** + * Register a handler to be called when Ajax requests complete. This is an AjaxEvent. + * + * @param handler The function to be invoked. + */ + ajaxComplete(handler: (event: JQueryEventObject, XMLHttpRequest: XMLHttpRequest, ajaxOptions: any) => any): JQuery; + /** + * Register a handler to be called when Ajax requests complete with an error. This is an Ajax Event. + * + * @param handler The function to be invoked. + */ + ajaxError(handler: (event: JQueryEventObject, jqXHR: JQueryXHR, ajaxSettings: JQueryAjaxSettings, thrownError: any) => any): JQuery; + /** + * Attach a function to be executed before an Ajax request is sent. This is an Ajax Event. + * + * @param handler The function to be invoked. + */ + ajaxSend(handler: (event: JQueryEventObject, jqXHR: JQueryXHR, ajaxOptions: JQueryAjaxSettings) => any): JQuery; + /** + * Register a handler to be called when the first Ajax request begins. This is an Ajax Event. + * + * @param handler The function to be invoked. + */ + ajaxStart(handler: () => any): JQuery; + /** + * Register a handler to be called when all Ajax requests have completed. This is an Ajax Event. + * + * @param handler The function to be invoked. + */ + ajaxStop(handler: () => any): JQuery; + /** + * Attach a function to be executed whenever an Ajax request completes successfully. This is an Ajax Event. + * + * @param handler The function to be invoked. + */ + ajaxSuccess(handler: (event: JQueryEventObject, XMLHttpRequest: XMLHttpRequest, ajaxOptions: JQueryAjaxSettings) => any): JQuery; + + /** + * Load data from the server and place the returned HTML into the matched element. + * + * @param url A string containing the URL to which the request is sent. + * @param data A plain object or string that is sent to the server with the request. + * @param complete A callback function that is executed when the request completes. + */ + load(url: string, data?: string|Object, complete?: (responseText: string, textStatus: string, XMLHttpRequest: XMLHttpRequest) => any): JQuery; + + /** + * Encode a set of form elements as a string for submission. + */ + serialize(): string; + /** + * Encode a set of form elements as an array of names and values. + */ + serializeArray(): JQuerySerializeArrayElement[]; + + /** + * Adds the specified class(es) to each of the set of matched elements. + * + * @param className One or more space-separated classes to be added to the class attribute of each matched element. + */ + addClass(className: string): JQuery; + /** + * Adds the specified class(es) to each of the set of matched elements. + * + * @param function A function returning one or more space-separated class names to be added to the existing class name(s). Receives the index position of the element in the set and the existing class name(s) as arguments. Within the function, this refers to the current element in the set. + */ + addClass(func: (index: number, className: string) => string): JQuery; + + /** + * Add the previous set of elements on the stack to the current set, optionally filtered by a selector. + */ + addBack(selector?: string): JQuery; + + /** + * Get the value of an attribute for the first element in the set of matched elements. + * + * @param attributeName The name of the attribute to get. + */ + attr(attributeName: string): string; + /** + * Set one or more attributes for the set of matched elements. + * + * @param attributeName The name of the attribute to set. + * @param value A value to set for the attribute. + */ + attr(attributeName: string, value: string|number): JQuery; + /** + * Set one or more attributes for the set of matched elements. + * + * @param attributeName The name of the attribute to set. + * @param func A function returning the value to set. this is the current element. Receives the index position of the element in the set and the old attribute value as arguments. + */ + attr(attributeName: string, func: (index: number, attr: string) => string|number): JQuery; + /** + * Set one or more attributes for the set of matched elements. + * + * @param attributes An object of attribute-value pairs to set. + */ + attr(attributes: Object): JQuery; + + /** + * Determine whether any of the matched elements are assigned the given class. + * + * @param className The class name to search for. + */ + hasClass(className: string): boolean; + + /** + * Get the HTML contents of the first element in the set of matched elements. + */ + html(): string; + /** + * Set the HTML contents of each element in the set of matched elements. + * + * @param htmlString A string of HTML to set as the content of each matched element. + */ + html(htmlString: string): JQuery; + /** + * Set the HTML contents of each element in the set of matched elements. + * + * @param func A function returning the HTML content to set. Receives the index position of the element in the set and the old HTML value as arguments. jQuery empties the element before calling the function; use the oldhtml argument to reference the previous content. Within the function, this refers to the current element in the set. + */ + html(func: (index: number, oldhtml: string) => string): JQuery; + /** + * Set the HTML contents of each element in the set of matched elements. + * + * @param func A function returning the HTML content to set. Receives the index position of the element in the set and the old HTML value as arguments. jQuery empties the element before calling the function; use the oldhtml argument to reference the previous content. Within the function, this refers to the current element in the set. + */ + + /** + * Get the value of a property for the first element in the set of matched elements. + * + * @param propertyName The name of the property to get. + */ + prop(propertyName: string): any; + /** + * Set one or more properties for the set of matched elements. + * + * @param propertyName The name of the property to set. + * @param value A value to set for the property. + */ + prop(propertyName: string, value: string|number|boolean): JQuery; + /** + * Set one or more properties for the set of matched elements. + * + * @param properties An object of property-value pairs to set. + */ + prop(properties: Object): JQuery; + /** + * Set one or more properties for the set of matched elements. + * + * @param propertyName The name of the property to set. + * @param func A function returning the value to set. Receives the index position of the element in the set and the old property value as arguments. Within the function, the keyword this refers to the current element. + */ + prop(propertyName: string, func: (index: number, oldPropertyValue: any) => any): JQuery; + + /** + * Remove an attribute from each element in the set of matched elements. + * + * @param attributeName An attribute to remove; as of version 1.7, it can be a space-separated list of attributes. + */ + removeAttr(attributeName: string): JQuery; + + /** + * Remove a single class, multiple classes, or all classes from each element in the set of matched elements. + * + * @param className One or more space-separated classes to be removed from the class attribute of each matched element. + */ + removeClass(className?: string): JQuery; + /** + * Remove a single class, multiple classes, or all classes from each element in the set of matched elements. + * + * @param function A function returning one or more space-separated class names to be removed. Receives the index position of the element in the set and the old class value as arguments. + */ + removeClass(func: (index: number, className: string) => string): JQuery; + + /** + * Remove a property for the set of matched elements. + * + * @param propertyName The name of the property to remove. + */ + removeProp(propertyName: string): JQuery; + + /** + * Add or remove one or more classes from each element in the set of matched elements, depending on either the class's presence or the value of the switch argument. + * + * @param className One or more class names (separated by spaces) to be toggled for each element in the matched set. + * @param swtch A Boolean (not just truthy/falsy) value to determine whether the class should be added or removed. + */ + toggleClass(className: string, swtch?: boolean): JQuery; + /** + * Add or remove one or more classes from each element in the set of matched elements, depending on either the class's presence or the value of the switch argument. + * + * @param swtch A boolean value to determine whether the class should be added or removed. + */ + toggleClass(swtch?: boolean): JQuery; + /** + * Add or remove one or more classes from each element in the set of matched elements, depending on either the class's presence or the value of the switch argument. + * + * @param func A function that returns class names to be toggled in the class attribute of each element in the matched set. Receives the index position of the element in the set, the old class value, and the switch as arguments. + * @param swtch A boolean value to determine whether the class should be added or removed. + */ + toggleClass(func: (index: number, className: string, swtch: boolean) => string, swtch?: boolean): JQuery; + + /** + * Get the current value of the first element in the set of matched elements. + */ + val(): any; + /** + * Set the value of each element in the set of matched elements. + * + * @param value A string of text or an array of strings corresponding to the value of each matched element to set as selected/checked. + */ + val(value: string|string[]): JQuery; + /** + * Set the value of each element in the set of matched elements. + * + * @param func A function returning the value to set. this is the current element. Receives the index position of the element in the set and the old value as arguments. + */ + val(func: (index: number, value: string) => string): JQuery; + + + /** + * Get the value of style properties for the first element in the set of matched elements. + * + * @param propertyName A CSS property. + */ + css(propertyName: string): string; + /** + * Set one or more CSS properties for the set of matched elements. + * + * @param propertyName A CSS property name. + * @param value A value to set for the property. + */ + css(propertyName: string, value: string|number): JQuery; + /** + * Set one or more CSS properties for the set of matched elements. + * + * @param propertyName A CSS property name. + * @param value A function returning the value to set. this is the current element. Receives the index position of the element in the set and the old value as arguments. + */ + css(propertyName: string, value: (index: number, value: string) => string|number): JQuery; + /** + * Set one or more CSS properties for the set of matched elements. + * + * @param properties An object of property-value pairs to set. + */ + css(properties: Object): JQuery; + + /** + * Get the current computed height for the first element in the set of matched elements. + */ + height(): number; + /** + * Set the CSS height of every matched element. + * + * @param value An integer representing the number of pixels, or an integer with an optional unit of measure appended (as a string). + */ + height(value: number|string): JQuery; + /** + * Set the CSS height of every matched element. + * + * @param func A function returning the height to set. Receives the index position of the element in the set and the old height as arguments. Within the function, this refers to the current element in the set. + */ + height(func: (index: number, height: number) => number|string): JQuery; + + /** + * Get the current computed height for the first element in the set of matched elements, including padding but not border. + */ + innerHeight(): number; + + /** + * Sets the inner height on elements in the set of matched elements, including padding but not border. + * + * @param value An integer representing the number of pixels, or an integer along with an optional unit of measure appended (as a string). + */ + innerHeight(height: number|string): JQuery; + + /** + * Get the current computed width for the first element in the set of matched elements, including padding but not border. + */ + innerWidth(): number; + + /** + * Sets the inner width on elements in the set of matched elements, including padding but not border. + * + * @param value An integer representing the number of pixels, or an integer along with an optional unit of measure appended (as a string). + */ + innerWidth(width: number|string): JQuery; + + /** + * Get the current coordinates of the first element in the set of matched elements, relative to the document. + */ + offset(): JQueryCoordinates; + /** + * An object containing the properties top and left, which are integers indicating the new top and left coordinates for the elements. + * + * @param coordinates An object containing the properties top and left, which are integers indicating the new top and left coordinates for the elements. + */ + offset(coordinates: JQueryCoordinates): JQuery; + /** + * An object containing the properties top and left, which are integers indicating the new top and left coordinates for the elements. + * + * @param func A function to return the coordinates to set. Receives the index of the element in the collection as the first argument and the current coordinates as the second argument. The function should return an object with the new top and left properties. + */ + offset(func: (index: number, coords: JQueryCoordinates) => JQueryCoordinates): JQuery; + + /** + * Get the current computed height for the first element in the set of matched elements, including padding, border, and optionally margin. Returns an integer (without "px") representation of the value or null if called on an empty set of elements. + * + * @param includeMargin A Boolean indicating whether to include the element's margin in the calculation. + */ + outerHeight(includeMargin?: boolean): number; + + /** + * Sets the outer height on elements in the set of matched elements, including padding and border. + * + * @param value An integer representing the number of pixels, or an integer along with an optional unit of measure appended (as a string). + */ + outerHeight(height: number|string): JQuery; + + /** + * Get the current computed width for the first element in the set of matched elements, including padding and border. + * + * @param includeMargin A Boolean indicating whether to include the element's margin in the calculation. + */ + outerWidth(includeMargin?: boolean): number; + + /** + * Sets the outer width on elements in the set of matched elements, including padding and border. + * + * @param value An integer representing the number of pixels, or an integer along with an optional unit of measure appended (as a string). + */ + outerWidth(width: number|string): JQuery; + + /** + * Get the current coordinates of the first element in the set of matched elements, relative to the offset parent. + */ + position(): JQueryCoordinates; + + /** + * Get the current horizontal position of the scroll bar for the first element in the set of matched elements or set the horizontal position of the scroll bar for every matched element. + */ + scrollLeft(): number; + /** + * Set the current horizontal position of the scroll bar for each of the set of matched elements. + * + * @param value An integer indicating the new position to set the scroll bar to. + */ + scrollLeft(value: number): JQuery; + + /** + * Get the current vertical position of the scroll bar for the first element in the set of matched elements or set the vertical position of the scroll bar for every matched element. + */ + scrollTop(): number; + /** + * Set the current vertical position of the scroll bar for each of the set of matched elements. + * + * @param value An integer indicating the new position to set the scroll bar to. + */ + scrollTop(value: number): JQuery; + + /** + * Get the current computed width for the first element in the set of matched elements. + */ + width(): number; + /** + * Set the CSS width of each element in the set of matched elements. + * + * @param value An integer representing the number of pixels, or an integer along with an optional unit of measure appended (as a string). + */ + width(value: number|string): JQuery; + /** + * Set the CSS width of each element in the set of matched elements. + * + * @param func A function returning the width to set. Receives the index position of the element in the set and the old width as arguments. Within the function, this refers to the current element in the set. + */ + width(func: (index: number, width: number) => number|string): JQuery; + + /** + * Remove from the queue all items that have not yet been run. + * + * @param queueName A string containing the name of the queue. Defaults to fx, the standard effects queue. + */ + clearQueue(queueName?: string): JQuery; + + /** + * Store arbitrary data associated with the matched elements. + * + * @param key A string naming the piece of data to set. + * @param value The new data value; it can be any Javascript type including Array or Object. + */ + data(key: string, value: any): JQuery; + /** + * Return the value at the named data store for the first element in the jQuery collection, as set by data(name, value) or by an HTML5 data-* attribute. + * + * @param key Name of the data stored. + */ + data(key: string): any; + /** + * Store arbitrary data associated with the matched elements. + * + * @param obj An object of key-value pairs of data to update. + */ + data(obj: { [key: string]: any; }): JQuery; + /** + * Return the value at the named data store for the first element in the jQuery collection, as set by data(name, value) or by an HTML5 data-* attribute. + */ + data(): any; + + /** + * Execute the next function on the queue for the matched elements. + * + * @param queueName A string containing the name of the queue. Defaults to fx, the standard effects queue. + */ + dequeue(queueName?: string): JQuery; + + /** + * Remove a previously-stored piece of data. + * + * @param name A string naming the piece of data to delete or space-separated string naming the pieces of data to delete. + */ + removeData(name: string): JQuery; + /** + * Remove a previously-stored piece of data. + * + * @param list An array of strings naming the pieces of data to delete. + */ + removeData(list: string[]): JQuery; + + /** + * Return a Promise object to observe when all actions of a certain type bound to the collection, queued or not, have finished. + * + * @param type The type of queue that needs to be observed. (default: fx) + * @param target Object onto which the promise methods have to be attached + */ + promise(type?: string, target?: Object): JQueryPromise; + + /** + * Perform a custom animation of a set of CSS properties. + * + * @param properties An object of CSS properties and values that the animation will move toward. + * @param duration A string or number determining how long the animation will run. + * @param complete A function to call once the animation is complete. + */ + animate(properties: Object, duration?: string|number, complete?: Function): JQuery; + /** + * Perform a custom animation of a set of CSS properties. + * + * @param properties An object of CSS properties and values that the animation will move toward. + * @param duration A string or number determining how long the animation will run. + * @param easing A string indicating which easing function to use for the transition. (default: swing) + * @param complete A function to call once the animation is complete. + */ + animate(properties: Object, duration?: string|number, easing?: string, complete?: Function): JQuery; + /** + * Perform a custom animation of a set of CSS properties. + * + * @param properties An object of CSS properties and values that the animation will move toward. + * @param options A map of additional options to pass to the method. + */ + animate(properties: Object, options: JQueryAnimationOptions): JQuery; + + /** + * Set a timer to delay execution of subsequent items in the queue. + * + * @param duration An integer indicating the number of milliseconds to delay execution of the next item in the queue. + * @param queueName A string containing the name of the queue. Defaults to fx, the standard effects queue. + */ + delay(duration: number, queueName?: string): JQuery; + + /** + * Display the matched elements by fading them to opaque. + * + * @param duration A string or number determining how long the animation will run. + * @param complete A function to call once the animation is complete. + */ + fadeIn(duration?: number|string, complete?: Function): JQuery; + /** + * Display the matched elements by fading them to opaque. + * + * @param duration A string or number determining how long the animation will run. + * @param easing A string indicating which easing function to use for the transition. + * @param complete A function to call once the animation is complete. + */ + fadeIn(duration?: number|string, easing?: string, complete?: Function): JQuery; + /** + * Display the matched elements by fading them to opaque. + * + * @param options A map of additional options to pass to the method. + */ + fadeIn(options: JQueryAnimationOptions): JQuery; + + /** + * Hide the matched elements by fading them to transparent. + * + * @param duration A string or number determining how long the animation will run. + * @param complete A function to call once the animation is complete. + */ + fadeOut(duration?: number|string, complete?: Function): JQuery; + /** + * Hide the matched elements by fading them to transparent. + * + * @param duration A string or number determining how long the animation will run. + * @param easing A string indicating which easing function to use for the transition. + * @param complete A function to call once the animation is complete. + */ + fadeOut(duration?: number|string, easing?: string, complete?: Function): JQuery; + /** + * Hide the matched elements by fading them to transparent. + * + * @param options A map of additional options to pass to the method. + */ + fadeOut(options: JQueryAnimationOptions): JQuery; + + /** + * Adjust the opacity of the matched elements. + * + * @param duration A string or number determining how long the animation will run. + * @param opacity A number between 0 and 1 denoting the target opacity. + * @param complete A function to call once the animation is complete. + */ + fadeTo(duration: string|number, opacity: number, complete?: Function): JQuery; + /** + * Adjust the opacity of the matched elements. + * + * @param duration A string or number determining how long the animation will run. + * @param opacity A number between 0 and 1 denoting the target opacity. + * @param easing A string indicating which easing function to use for the transition. + * @param complete A function to call once the animation is complete. + */ + fadeTo(duration: string|number, opacity: number, easing?: string, complete?: Function): JQuery; + + /** + * Display or hide the matched elements by animating their opacity. + * + * @param duration A string or number determining how long the animation will run. + * @param complete A function to call once the animation is complete. + */ + fadeToggle(duration?: number|string, complete?: Function): JQuery; + /** + * Display or hide the matched elements by animating their opacity. + * + * @param duration A string or number determining how long the animation will run. + * @param easing A string indicating which easing function to use for the transition. + * @param complete A function to call once the animation is complete. + */ + fadeToggle(duration?: number|string, easing?: string, complete?: Function): JQuery; + /** + * Display or hide the matched elements by animating their opacity. + * + * @param options A map of additional options to pass to the method. + */ + fadeToggle(options: JQueryAnimationOptions): JQuery; + + /** + * Stop the currently-running animation, remove all queued animations, and complete all animations for the matched elements. + * + * @param queue The name of the queue in which to stop animations. + */ + finish(queue?: string): JQuery; + + /** + * Hide the matched elements. + * + * @param duration A string or number determining how long the animation will run. + * @param complete A function to call once the animation is complete. + */ + hide(duration?: number|string, complete?: Function): JQuery; + /** + * Hide the matched elements. + * + * @param duration A string or number determining how long the animation will run. + * @param easing A string indicating which easing function to use for the transition. + * @param complete A function to call once the animation is complete. + */ + hide(duration?: number|string, easing?: string, complete?: Function): JQuery; + /** + * Hide the matched elements. + * + * @param options A map of additional options to pass to the method. + */ + hide(options: JQueryAnimationOptions): JQuery; + + /** + * Display the matched elements. + * + * @param duration A string or number determining how long the animation will run. + * @param complete A function to call once the animation is complete. + */ + show(duration?: number|string, complete?: Function): JQuery; + /** + * Display the matched elements. + * + * @param duration A string or number determining how long the animation will run. + * @param easing A string indicating which easing function to use for the transition. + * @param complete A function to call once the animation is complete. + */ + show(duration?: number|string, easing?: string, complete?: Function): JQuery; + /** + * Display the matched elements. + * + * @param options A map of additional options to pass to the method. + */ + show(options: JQueryAnimationOptions): JQuery; + + /** + * Display the matched elements with a sliding motion. + * + * @param duration A string or number determining how long the animation will run. + * @param complete A function to call once the animation is complete. + */ + slideDown(duration?: number|string, complete?: Function): JQuery; + /** + * Display the matched elements with a sliding motion. + * + * @param duration A string or number determining how long the animation will run. + * @param easing A string indicating which easing function to use for the transition. + * @param complete A function to call once the animation is complete. + */ + slideDown(duration?: number|string, easing?: string, complete?: Function): JQuery; + /** + * Display the matched elements with a sliding motion. + * + * @param options A map of additional options to pass to the method. + */ + slideDown(options: JQueryAnimationOptions): JQuery; + + /** + * Display or hide the matched elements with a sliding motion. + * + * @param duration A string or number determining how long the animation will run. + * @param complete A function to call once the animation is complete. + */ + slideToggle(duration?: number|string, complete?: Function): JQuery; + /** + * Display or hide the matched elements with a sliding motion. + * + * @param duration A string or number determining how long the animation will run. + * @param easing A string indicating which easing function to use for the transition. + * @param complete A function to call once the animation is complete. + */ + slideToggle(duration?: number|string, easing?: string, complete?: Function): JQuery; + /** + * Display or hide the matched elements with a sliding motion. + * + * @param options A map of additional options to pass to the method. + */ + slideToggle(options: JQueryAnimationOptions): JQuery; + + /** + * Hide the matched elements with a sliding motion. + * + * @param duration A string or number determining how long the animation will run. + * @param complete A function to call once the animation is complete. + */ + slideUp(duration?: number|string, complete?: Function): JQuery; + /** + * Hide the matched elements with a sliding motion. + * + * @param duration A string or number determining how long the animation will run. + * @param easing A string indicating which easing function to use for the transition. + * @param complete A function to call once the animation is complete. + */ + slideUp(duration?: number|string, easing?: string, complete?: Function): JQuery; + /** + * Hide the matched elements with a sliding motion. + * + * @param options A map of additional options to pass to the method. + */ + slideUp(options: JQueryAnimationOptions): JQuery; + + /** + * Stop the currently-running animation on the matched elements. + * + * @param clearQueue A Boolean indicating whether to remove queued animation as well. Defaults to false. + * @param jumpToEnd A Boolean indicating whether to complete the current animation immediately. Defaults to false. + */ + stop(clearQueue?: boolean, jumpToEnd?: boolean): JQuery; + /** + * Stop the currently-running animation on the matched elements. + * + * @param queue The name of the queue in which to stop animations. + * @param clearQueue A Boolean indicating whether to remove queued animation as well. Defaults to false. + * @param jumpToEnd A Boolean indicating whether to complete the current animation immediately. Defaults to false. + */ + stop(queue?: string, clearQueue?: boolean, jumpToEnd?: boolean): JQuery; + + /** + * Display or hide the matched elements. + * + * @param duration A string or number determining how long the animation will run. + * @param complete A function to call once the animation is complete. + */ + toggle(duration?: number|string, complete?: Function): JQuery; + /** + * Display or hide the matched elements. + * + * @param duration A string or number determining how long the animation will run. + * @param easing A string indicating which easing function to use for the transition. + * @param complete A function to call once the animation is complete. + */ + toggle(duration?: number|string, easing?: string, complete?: Function): JQuery; + /** + * Display or hide the matched elements. + * + * @param options A map of additional options to pass to the method. + */ + toggle(options: JQueryAnimationOptions): JQuery; + /** + * Display or hide the matched elements. + * + * @param showOrHide A Boolean indicating whether to show or hide the elements. + */ + toggle(showOrHide: boolean): JQuery; + + /** + * Attach a handler to an event for the elements. + * + * @param eventType A string containing one or more DOM event types, such as "click" or "submit," or custom event names. + * @param eventData An object containing data that will be passed to the event handler. + * @param handler A function to execute each time the event is triggered. + */ + bind(eventType: string, eventData: any, handler: (eventObject: JQueryEventObject) => any): JQuery; + /** + * Attach a handler to an event for the elements. + * + * @param eventType A string containing one or more DOM event types, such as "click" or "submit," or custom event names. + * @param handler A function to execute each time the event is triggered. + */ + bind(eventType: string, handler: (eventObject: JQueryEventObject) => any): JQuery; + /** + * Attach a handler to an event for the elements. + * + * @param eventType A string containing one or more DOM event types, such as "click" or "submit," or custom event names. + * @param eventData An object containing data that will be passed to the event handler. + * @param preventBubble Setting the third argument to false will attach a function that prevents the default action from occurring and stops the event from bubbling. The default is true. + */ + bind(eventType: string, eventData: any, preventBubble: boolean): JQuery; + /** + * Attach a handler to an event for the elements. + * + * @param eventType A string containing one or more DOM event types, such as "click" or "submit," or custom event names. + * @param preventBubble Setting the third argument to false will attach a function that prevents the default action from occurring and stops the event from bubbling. The default is true. + */ + bind(eventType: string, preventBubble: boolean): JQuery; + /** + * Attach a handler to an event for the elements. + * + * @param events An object containing one or more DOM event types and functions to execute for them. + */ + bind(events: any): JQuery; + + /** + * Trigger the "blur" event on an element + */ + blur(): JQuery; + /** + * Bind an event handler to the "blur" JavaScript event + * + * @param handler A function to execute each time the event is triggered. + */ + blur(handler: (eventObject: JQueryEventObject) => any): JQuery; + /** + * Bind an event handler to the "blur" JavaScript event + * + * @param eventData An object containing data that will be passed to the event handler. + * @param handler A function to execute each time the event is triggered. + */ + blur(eventData?: any, handler?: (eventObject: JQueryEventObject) => any): JQuery; + + /** + * Trigger the "change" event on an element. + */ + change(): JQuery; + /** + * Bind an event handler to the "change" JavaScript event + * + * @param handler A function to execute each time the event is triggered. + */ + change(handler: (eventObject: JQueryEventObject) => any): JQuery; + /** + * Bind an event handler to the "change" JavaScript event + * + * @param eventData An object containing data that will be passed to the event handler. + * @param handler A function to execute each time the event is triggered. + */ + change(eventData?: any, handler?: (eventObject: JQueryEventObject) => any): JQuery; + + /** + * Trigger the "click" event on an element. + */ + click(): JQuery; + /** + * Bind an event handler to the "click" JavaScript event + * + * @param eventData An object containing data that will be passed to the event handler. + */ + click(handler: (eventObject: JQueryEventObject) => any): JQuery; + /** + * Bind an event handler to the "click" JavaScript event + * + * @param eventData An object containing data that will be passed to the event handler. + * @param handler A function to execute each time the event is triggered. + */ + click(eventData?: any, handler?: (eventObject: JQueryEventObject) => any): JQuery; + + /** + * Trigger the "dblclick" event on an element. + */ + dblclick(): JQuery; + /** + * Bind an event handler to the "dblclick" JavaScript event + * + * @param handler A function to execute each time the event is triggered. + */ + dblclick(handler: (eventObject: JQueryEventObject) => any): JQuery; + /** + * Bind an event handler to the "dblclick" JavaScript event + * + * @param eventData An object containing data that will be passed to the event handler. + * @param handler A function to execute each time the event is triggered. + */ + dblclick(eventData?: any, handler?: (eventObject: JQueryEventObject) => any): JQuery; + + delegate(selector: any, eventType: string, handler: (eventObject: JQueryEventObject) => any): JQuery; + delegate(selector: any, eventType: string, eventData: any, handler: (eventObject: JQueryEventObject) => any): JQuery; + + /** + * Trigger the "focus" event on an element. + */ + focus(): JQuery; + /** + * Bind an event handler to the "focus" JavaScript event + * + * @param handler A function to execute each time the event is triggered. + */ + focus(handler: (eventObject: JQueryEventObject) => any): JQuery; + /** + * Bind an event handler to the "focus" JavaScript event + * + * @param eventData An object containing data that will be passed to the event handler. + * @param handler A function to execute each time the event is triggered. + */ + focus(eventData?: any, handler?: (eventObject: JQueryEventObject) => any): JQuery; + + /** + * Bind an event handler to the "focusin" JavaScript event + * + * @param handler A function to execute each time the event is triggered. + */ + focusin(handler: (eventObject: JQueryEventObject) => any): JQuery; + /** + * Bind an event handler to the "focusin" JavaScript event + * + * @param eventData An object containing data that will be passed to the event handler. + * @param handler A function to execute each time the event is triggered. + */ + focusin(eventData: Object, handler: (eventObject: JQueryEventObject) => any): JQuery; + + /** + * Bind an event handler to the "focusout" JavaScript event + * + * @param handler A function to execute each time the event is triggered. + */ + focusout(handler: (eventObject: JQueryEventObject) => any): JQuery; + /** + * Bind an event handler to the "focusout" JavaScript event + * + * @param eventData An object containing data that will be passed to the event handler. + * @param handler A function to execute each time the event is triggered. + */ + focusout(eventData: Object, handler: (eventObject: JQueryEventObject) => any): JQuery; + + /** + * Bind two handlers to the matched elements, to be executed when the mouse pointer enters and leaves the elements. + * + * @param handlerIn A function to execute when the mouse pointer enters the element. + * @param handlerOut A function to execute when the mouse pointer leaves the element. + */ + hover(handlerIn: (eventObject: JQueryEventObject) => any, handlerOut: (eventObject: JQueryEventObject) => any): JQuery; + /** + * Bind a single handler to the matched elements, to be executed when the mouse pointer enters or leaves the elements. + * + * @param handlerInOut A function to execute when the mouse pointer enters or leaves the element. + */ + hover(handlerInOut: (eventObject: JQueryEventObject) => any): JQuery; + + /** + * Trigger the "keydown" event on an element. + */ + keydown(): JQuery; + /** + * Bind an event handler to the "keydown" JavaScript event + * + * @param handler A function to execute each time the event is triggered. + */ + keydown(handler: (eventObject: JQueryKeyEventObject) => any): JQuery; + /** + * Bind an event handler to the "keydown" JavaScript event + * + * @param eventData An object containing data that will be passed to the event handler. + * @param handler A function to execute each time the event is triggered. + */ + keydown(eventData?: any, handler?: (eventObject: JQueryKeyEventObject) => any): JQuery; + + /** + * Trigger the "keypress" event on an element. + */ + keypress(): JQuery; + /** + * Bind an event handler to the "keypress" JavaScript event + * + * @param handler A function to execute each time the event is triggered. + */ + keypress(handler: (eventObject: JQueryKeyEventObject) => any): JQuery; + /** + * Bind an event handler to the "keypress" JavaScript event + * + * @param eventData An object containing data that will be passed to the event handler. + * @param handler A function to execute each time the event is triggered. + */ + keypress(eventData?: any, handler?: (eventObject: JQueryKeyEventObject) => any): JQuery; + + /** + * Trigger the "keyup" event on an element. + */ + keyup(): JQuery; + /** + * Bind an event handler to the "keyup" JavaScript event + * + * @param handler A function to execute each time the event is triggered. + */ + keyup(handler: (eventObject: JQueryKeyEventObject) => any): JQuery; + /** + * Bind an event handler to the "keyup" JavaScript event + * + * @param eventData An object containing data that will be passed to the event handler. + * @param handler A function to execute each time the event is triggered. + */ + keyup(eventData?: any, handler?: (eventObject: JQueryKeyEventObject) => any): JQuery; + + /** + * Bind an event handler to the "load" JavaScript event. + * + * @param handler A function to execute when the event is triggered. + */ + load(handler: (eventObject: JQueryEventObject) => any): JQuery; + /** + * Bind an event handler to the "load" JavaScript event. + * + * @param eventData An object containing data that will be passed to the event handler. + * @param handler A function to execute when the event is triggered. + */ + load(eventData?: any, handler?: (eventObject: JQueryEventObject) => any): JQuery; + + /** + * Trigger the "mousedown" event on an element. + */ + mousedown(): JQuery; + /** + * Bind an event handler to the "mousedown" JavaScript event. + * + * @param handler A function to execute when the event is triggered. + */ + mousedown(handler: (eventObject: JQueryMouseEventObject) => any): JQuery; + /** + * Bind an event handler to the "mousedown" JavaScript event. + * + * @param eventData An object containing data that will be passed to the event handler. + * @param handler A function to execute when the event is triggered. + */ + mousedown(eventData: Object, handler: (eventObject: JQueryMouseEventObject) => any): JQuery; + + /** + * Trigger the "mouseenter" event on an element. + */ + mouseenter(): JQuery; + /** + * Bind an event handler to be fired when the mouse enters an element. + * + * @param handler A function to execute when the event is triggered. + */ + mouseenter(handler: (eventObject: JQueryMouseEventObject) => any): JQuery; + /** + * Bind an event handler to be fired when the mouse enters an element. + * + * @param eventData An object containing data that will be passed to the event handler. + * @param handler A function to execute when the event is triggered. + */ + mouseenter(eventData: Object, handler: (eventObject: JQueryMouseEventObject) => any): JQuery; + + /** + * Trigger the "mouseleave" event on an element. + */ + mouseleave(): JQuery; + /** + * Bind an event handler to be fired when the mouse leaves an element. + * + * @param handler A function to execute when the event is triggered. + */ + mouseleave(handler: (eventObject: JQueryMouseEventObject) => any): JQuery; + /** + * Bind an event handler to be fired when the mouse leaves an element. + * + * @param eventData An object containing data that will be passed to the event handler. + * @param handler A function to execute when the event is triggered. + */ + mouseleave(eventData: Object, handler: (eventObject: JQueryMouseEventObject) => any): JQuery; + + /** + * Trigger the "mousemove" event on an element. + */ + mousemove(): JQuery; + /** + * Bind an event handler to the "mousemove" JavaScript event. + * + * @param handler A function to execute when the event is triggered. + */ + mousemove(handler: (eventObject: JQueryMouseEventObject) => any): JQuery; + /** + * Bind an event handler to the "mousemove" JavaScript event. + * + * @param eventData An object containing data that will be passed to the event handler. + * @param handler A function to execute when the event is triggered. + */ + mousemove(eventData: Object, handler: (eventObject: JQueryMouseEventObject) => any): JQuery; + + /** + * Trigger the "mouseout" event on an element. + */ + mouseout(): JQuery; + /** + * Bind an event handler to the "mouseout" JavaScript event. + * + * @param handler A function to execute when the event is triggered. + */ + mouseout(handler: (eventObject: JQueryMouseEventObject) => any): JQuery; + /** + * Bind an event handler to the "mouseout" JavaScript event. + * + * @param eventData An object containing data that will be passed to the event handler. + * @param handler A function to execute when the event is triggered. + */ + mouseout(eventData: Object, handler: (eventObject: JQueryMouseEventObject) => any): JQuery; + + /** + * Trigger the "mouseover" event on an element. + */ + mouseover(): JQuery; + /** + * Bind an event handler to the "mouseover" JavaScript event. + * + * @param handler A function to execute when the event is triggered. + */ + mouseover(handler: (eventObject: JQueryMouseEventObject) => any): JQuery; + /** + * Bind an event handler to the "mouseover" JavaScript event. + * + * @param eventData An object containing data that will be passed to the event handler. + * @param handler A function to execute when the event is triggered. + */ + mouseover(eventData: Object, handler: (eventObject: JQueryMouseEventObject) => any): JQuery; + + /** + * Trigger the "mouseup" event on an element. + */ + mouseup(): JQuery; + /** + * Bind an event handler to the "mouseup" JavaScript event. + * + * @param handler A function to execute when the event is triggered. + */ + mouseup(handler: (eventObject: JQueryMouseEventObject) => any): JQuery; + /** + * Bind an event handler to the "mouseup" JavaScript event. + * + * @param eventData An object containing data that will be passed to the event handler. + * @param handler A function to execute when the event is triggered. + */ + mouseup(eventData: Object, handler: (eventObject: JQueryMouseEventObject) => any): JQuery; + + /** + * Remove an event handler. + */ + off(): JQuery; + /** + * Remove an event handler. + * + * @param events One or more space-separated event types and optional namespaces, or just namespaces, such as "click", "keydown.myPlugin", or ".myPlugin". + * @param selector A selector which should match the one originally passed to .on() when attaching event handlers. + * @param handler A handler function previously attached for the event(s), or the special value false. + */ + off(events: string, selector?: string, handler?: (eventObject: JQueryEventObject) => any): JQuery; + /** + * Remove an event handler. + * + * @param events One or more space-separated event types and optional namespaces, or just namespaces, such as "click", "keydown.myPlugin", or ".myPlugin". + * @param handler A handler function previously attached for the event(s), or the special value false. + */ + off(events: string, handler: (eventObject: JQueryEventObject) => any): JQuery; + /** + * Remove an event handler. + * + * @param events An object where the string keys represent one or more space-separated event types and optional namespaces, and the values represent handler functions previously attached for the event(s). + * @param selector A selector which should match the one originally passed to .on() when attaching event handlers. + */ + off(events: { [key: string]: any; }, selector?: string): JQuery; + + /** + * Attach an event handler function for one or more events to the selected elements. + * + * @param events One or more space-separated event types and optional namespaces, such as "click" or "keydown.myPlugin". + * @param handler A function to execute when the event is triggered. The value false is also allowed as a shorthand for a function that simply does return false. Rest parameter args is for optional parameters passed to jQuery.trigger(). Note that the actual parameters on the event handler function must be marked as optional (? syntax). + */ + on(events: string, handler: (eventObject: JQueryEventObject, ...args: any[]) => any): JQuery; + /** + * Attach an event handler function for one or more events to the selected elements. + * + * @param events One or more space-separated event types and optional namespaces, such as "click" or "keydown.myPlugin". + * @param data Data to be passed to the handler in event.data when an event is triggered. + * @param handler A function to execute when the event is triggered. The value false is also allowed as a shorthand for a function that simply does return false. + */ + on(events: string, data : any, handler: (eventObject: JQueryEventObject, ...args: any[]) => any): JQuery; + /** + * Attach an event handler function for one or more events to the selected elements. + * + * @param events One or more space-separated event types and optional namespaces, such as "click" or "keydown.myPlugin". + * @param selector A selector string to filter the descendants of the selected elements that trigger the event. If the selector is null or omitted, the event is always triggered when it reaches the selected element. + * @param handler A function to execute when the event is triggered. The value false is also allowed as a shorthand for a function that simply does return false. + */ + on(events: string, selector: string, handler: (eventObject: JQueryEventObject, ...eventData: any[]) => any): JQuery; + /** + * Attach an event handler function for one or more events to the selected elements. + * + * @param events One or more space-separated event types and optional namespaces, such as "click" or "keydown.myPlugin". + * @param selector A selector string to filter the descendants of the selected elements that trigger the event. If the selector is null or omitted, the event is always triggered when it reaches the selected element. + * @param data Data to be passed to the handler in event.data when an event is triggered. + * @param handler A function to execute when the event is triggered. The value false is also allowed as a shorthand for a function that simply does return false. + */ + on(events: string, selector: string, data: any, handler: (eventObject: JQueryEventObject, ...eventData: any[]) => any): JQuery; + /** + * Attach an event handler function for one or more events to the selected elements. + * + * @param events An object in which the string keys represent one or more space-separated event types and optional namespaces, and the values represent a handler function to be called for the event(s). + * @param selector A selector string to filter the descendants of the selected elements that will call the handler. If the selector is null or omitted, the handler is always called when it reaches the selected element. + * @param data Data to be passed to the handler in event.data when an event occurs. + */ + on(events: { [key: string]: any; }, selector?: string, data?: any): JQuery; + /** + * Attach an event handler function for one or more events to the selected elements. + * + * @param events An object in which the string keys represent one or more space-separated event types and optional namespaces, and the values represent a handler function to be called for the event(s). + * @param data Data to be passed to the handler in event.data when an event occurs. + */ + on(events: { [key: string]: any; }, data?: any): JQuery; + + /** + * Attach a handler to an event for the elements. The handler is executed at most once per element per event type. + * + * @param events A string containing one or more JavaScript event types, such as "click" or "submit," or custom event names. + * @param handler A function to execute at the time the event is triggered. + */ + one(events: string, handler: (eventObject: JQueryEventObject) => any): JQuery; + /** + * Attach a handler to an event for the elements. The handler is executed at most once per element per event type. + * + * @param events A string containing one or more JavaScript event types, such as "click" or "submit," or custom event names. + * @param data An object containing data that will be passed to the event handler. + * @param handler A function to execute at the time the event is triggered. + */ + one(events: string, data: Object, handler: (eventObject: JQueryEventObject) => any): JQuery; + + /** + * Attach a handler to an event for the elements. The handler is executed at most once per element per event type. + * + * @param events One or more space-separated event types and optional namespaces, such as "click" or "keydown.myPlugin". + * @param selector A selector string to filter the descendants of the selected elements that trigger the event. If the selector is null or omitted, the event is always triggered when it reaches the selected element. + * @param handler A function to execute when the event is triggered. The value false is also allowed as a shorthand for a function that simply does return false. + */ + one(events: string, selector: string, handler: (eventObject: JQueryEventObject) => any): JQuery; + /** + * Attach a handler to an event for the elements. The handler is executed at most once per element per event type. + * + * @param events One or more space-separated event types and optional namespaces, such as "click" or "keydown.myPlugin". + * @param selector A selector string to filter the descendants of the selected elements that trigger the event. If the selector is null or omitted, the event is always triggered when it reaches the selected element. + * @param data Data to be passed to the handler in event.data when an event is triggered. + * @param handler A function to execute when the event is triggered. The value false is also allowed as a shorthand for a function that simply does return false. + */ + one(events: string, selector: string, data: any, handler: (eventObject: JQueryEventObject) => any): JQuery; + + /** + * Attach a handler to an event for the elements. The handler is executed at most once per element per event type. + * + * @param events An object in which the string keys represent one or more space-separated event types and optional namespaces, and the values represent a handler function to be called for the event(s). + * @param selector A selector string to filter the descendants of the selected elements that will call the handler. If the selector is null or omitted, the handler is always called when it reaches the selected element. + * @param data Data to be passed to the handler in event.data when an event occurs. + */ + one(events: { [key: string]: any; }, selector?: string, data?: any): JQuery; + + /** + * Attach a handler to an event for the elements. The handler is executed at most once per element per event type. + * + * @param events An object in which the string keys represent one or more space-separated event types and optional namespaces, and the values represent a handler function to be called for the event(s). + * @param data Data to be passed to the handler in event.data when an event occurs. + */ + one(events: { [key: string]: any; }, data?: any): JQuery; + + + /** + * Specify a function to execute when the DOM is fully loaded. + * + * @param handler A function to execute after the DOM is ready. + */ + ready(handler: (jQueryAlias?: JQueryStatic) => any): JQuery; + + /** + * Trigger the "resize" event on an element. + */ + resize(): JQuery; + /** + * Bind an event handler to the "resize" JavaScript event. + * + * @param handler A function to execute each time the event is triggered. + */ + resize(handler: (eventObject: JQueryEventObject) => any): JQuery; + /** + * Bind an event handler to the "resize" JavaScript event. + * + * @param eventData An object containing data that will be passed to the event handler. + * @param handler A function to execute each time the event is triggered. + */ + resize(eventData: Object, handler: (eventObject: JQueryEventObject) => any): JQuery; + + /** + * Trigger the "scroll" event on an element. + */ + scroll(): JQuery; + /** + * Bind an event handler to the "scroll" JavaScript event. + * + * @param handler A function to execute each time the event is triggered. + */ + scroll(handler: (eventObject: JQueryEventObject) => any): JQuery; + /** + * Bind an event handler to the "scroll" JavaScript event. + * + * @param eventData An object containing data that will be passed to the event handler. + * @param handler A function to execute each time the event is triggered. + */ + scroll(eventData: Object, handler: (eventObject: JQueryEventObject) => any): JQuery; + + /** + * Trigger the "select" event on an element. + */ + select(): JQuery; + /** + * Bind an event handler to the "select" JavaScript event. + * + * @param handler A function to execute each time the event is triggered. + */ + select(handler: (eventObject: JQueryEventObject) => any): JQuery; + /** + * Bind an event handler to the "select" JavaScript event. + * + * @param eventData An object containing data that will be passed to the event handler. + * @param handler A function to execute each time the event is triggered. + */ + select(eventData: Object, handler: (eventObject: JQueryEventObject) => any): JQuery; + + /** + * Trigger the "submit" event on an element. + */ + submit(): JQuery; + /** + * Bind an event handler to the "submit" JavaScript event + * + * @param handler A function to execute each time the event is triggered. + */ + submit(handler: (eventObject: JQueryEventObject) => any): JQuery; + /** + * Bind an event handler to the "submit" JavaScript event + * + * @param eventData An object containing data that will be passed to the event handler. + * @param handler A function to execute each time the event is triggered. + */ + submit(eventData?: any, handler?: (eventObject: JQueryEventObject) => any): JQuery; + + /** + * Execute all handlers and behaviors attached to the matched elements for the given event type. + * + * @param eventType A string containing a JavaScript event type, such as click or submit. + * @param extraParameters Additional parameters to pass along to the event handler. + */ + trigger(eventType: string, extraParameters?: any[]|Object): JQuery; + /** + * Execute all handlers and behaviors attached to the matched elements for the given event type. + * + * @param event A jQuery.Event object. + * @param extraParameters Additional parameters to pass along to the event handler. + */ + trigger(event: JQueryEventObject, extraParameters?: any[]|Object): JQuery; + + /** + * Execute all handlers attached to an element for an event. + * + * @param eventType A string containing a JavaScript event type, such as click or submit. + * @param extraParameters An array of additional parameters to pass along to the event handler. + */ + triggerHandler(eventType: string, ...extraParameters: any[]): Object; + + /** + * Execute all handlers attached to an element for an event. + * + * @param event A jQuery.Event object. + * @param extraParameters An array of additional parameters to pass along to the event handler. + */ + triggerHandler(event: JQueryEventObject, ...extraParameters: any[]): Object; + + /** + * Remove a previously-attached event handler from the elements. + * + * @param eventType A string containing a JavaScript event type, such as click or submit. + * @param handler The function that is to be no longer executed. + */ + unbind(eventType?: string, handler?: (eventObject: JQueryEventObject) => any): JQuery; + /** + * Remove a previously-attached event handler from the elements. + * + * @param eventType A string containing a JavaScript event type, such as click or submit. + * @param fls Unbinds the corresponding 'return false' function that was bound using .bind( eventType, false ). + */ + unbind(eventType: string, fls: boolean): JQuery; + /** + * Remove a previously-attached event handler from the elements. + * + * @param evt A JavaScript event object as passed to an event handler. + */ + unbind(evt: any): JQuery; + + /** + * Remove a handler from the event for all elements which match the current selector, based upon a specific set of root elements. + */ + undelegate(): JQuery; + /** + * Remove a handler from the event for all elements which match the current selector, based upon a specific set of root elements. + * + * @param selector A selector which will be used to filter the event results. + * @param eventType A string containing a JavaScript event type, such as "click" or "keydown" + * @param handler A function to execute at the time the event is triggered. + */ + undelegate(selector: string, eventType: string, handler?: (eventObject: JQueryEventObject) => any): JQuery; + /** + * Remove a handler from the event for all elements which match the current selector, based upon a specific set of root elements. + * + * @param selector A selector which will be used to filter the event results. + * @param events An object of one or more event types and previously bound functions to unbind from them. + */ + undelegate(selector: string, events: Object): JQuery; + /** + * Remove a handler from the event for all elements which match the current selector, based upon a specific set of root elements. + * + * @param namespace A string containing a namespace to unbind all events from. + */ + undelegate(namespace: string): JQuery; + + /** + * Bind an event handler to the "unload" JavaScript event. (DEPRECATED from v1.8) + * + * @param handler A function to execute when the event is triggered. + */ + unload(handler: (eventObject: JQueryEventObject) => any): JQuery; + /** + * Bind an event handler to the "unload" JavaScript event. (DEPRECATED from v1.8) + * + * @param eventData A plain object of data that will be passed to the event handler. + * @param handler A function to execute when the event is triggered. + */ + unload(eventData?: any, handler?: (eventObject: JQueryEventObject) => any): JQuery; + + /** + * The DOM node context originally passed to jQuery(); if none was passed then context will likely be the document. (DEPRECATED from v1.10) + */ + context: Element; + + jquery: string; + + /** + * Bind an event handler to the "error" JavaScript event. (DEPRECATED from v1.8) + * + * @param handler A function to execute when the event is triggered. + */ + error(handler: (eventObject: JQueryEventObject) => any): JQuery; + /** + * Bind an event handler to the "error" JavaScript event. (DEPRECATED from v1.8) + * + * @param eventData A plain object of data that will be passed to the event handler. + * @param handler A function to execute when the event is triggered. + */ + error(eventData: any, handler: (eventObject: JQueryEventObject) => any): JQuery; + + /** + * Add a collection of DOM elements onto the jQuery stack. + * + * @param elements An array of elements to push onto the stack and make into a new jQuery object. + */ + pushStack(elements: any[]): JQuery; + /** + * Add a collection of DOM elements onto the jQuery stack. + * + * @param elements An array of elements to push onto the stack and make into a new jQuery object. + * @param name The name of a jQuery method that generated the array of elements. + * @param arguments The arguments that were passed in to the jQuery method (for serialization). + */ + pushStack(elements: any[], name: string, arguments: any[]): JQuery; + + /** + * Insert content, specified by the parameter, after each element in the set of matched elements. + * + * param content1 HTML string, DOM element, array of elements, or jQuery object to insert after each element in the set of matched elements. + * param content2 One or more additional DOM elements, arrays of elements, HTML strings, or jQuery objects to insert after each element in the set of matched elements. + */ + after(content1: JQuery|any[]|Element|Text|string, ...content2: any[]): JQuery; + /** + * Insert content, specified by the parameter, after each element in the set of matched elements. + * + * param func A function that returns an HTML string, DOM element(s), or jQuery object to insert after each element in the set of matched elements. Receives the index position of the element in the set as an argument. Within the function, this refers to the current element in the set. + */ + after(func: (index: number, html: string) => string|Element|JQuery): JQuery; + + /** + * Insert content, specified by the parameter, to the end of each element in the set of matched elements. + * + * param content1 DOM element, array of elements, HTML string, or jQuery object to insert at the end of each element in the set of matched elements. + * param content2 One or more additional DOM elements, arrays of elements, HTML strings, or jQuery objects to insert at the end of each element in the set of matched elements. + */ + append(content1: JQuery|any[]|Element|Text|string, ...content2: any[]): JQuery; + /** + * Insert content, specified by the parameter, to the end of each element in the set of matched elements. + * + * param func A function that returns an HTML string, DOM element(s), or jQuery object to insert at the end of each element in the set of matched elements. Receives the index position of the element in the set and the old HTML value of the element as arguments. Within the function, this refers to the current element in the set. + */ + append(func: (index: number, html: string) => string|Element|JQuery): JQuery; + + /** + * Insert every element in the set of matched elements to the end of the target. + * + * @param target A selector, element, HTML string, array of elements, or jQuery object; the matched set of elements will be inserted at the end of the element(s) specified by this parameter. + */ + appendTo(target: JQuery|any[]|Element|string): JQuery; + + /** + * Insert content, specified by the parameter, before each element in the set of matched elements. + * + * param content1 HTML string, DOM element, array of elements, or jQuery object to insert before each element in the set of matched elements. + * param content2 One or more additional DOM elements, arrays of elements, HTML strings, or jQuery objects to insert before each element in the set of matched elements. + */ + before(content1: JQuery|any[]|Element|Text|string, ...content2: any[]): JQuery; + /** + * Insert content, specified by the parameter, before each element in the set of matched elements. + * + * param func A function that returns an HTML string, DOM element(s), or jQuery object to insert before each element in the set of matched elements. Receives the index position of the element in the set as an argument. Within the function, this refers to the current element in the set. + */ + before(func: (index: number, html: string) => string|Element|JQuery): JQuery; + + /** + * Create a deep copy of the set of matched elements. + * + * param withDataAndEvents A Boolean indicating whether event handlers and data should be copied along with the elements. The default value is false. + * param deepWithDataAndEvents A Boolean indicating whether event handlers and data for all children of the cloned element should be copied. By default its value matches the first argument's value (which defaults to false). + */ + clone(withDataAndEvents?: boolean, deepWithDataAndEvents?: boolean): JQuery; + + /** + * Remove the set of matched elements from the DOM. + * + * param selector A selector expression that filters the set of matched elements to be removed. + */ + detach(selector?: string): JQuery; + + /** + * Remove all child nodes of the set of matched elements from the DOM. + */ + empty(): JQuery; + + /** + * Insert every element in the set of matched elements after the target. + * + * param target A selector, element, array of elements, HTML string, or jQuery object; the matched set of elements will be inserted after the element(s) specified by this parameter. + */ + insertAfter(target: JQuery|any[]|Element|Text|string): JQuery; + + /** + * Insert every element in the set of matched elements before the target. + * + * param target A selector, element, array of elements, HTML string, or jQuery object; the matched set of elements will be inserted before the element(s) specified by this parameter. + */ + insertBefore(target: JQuery|any[]|Element|Text|string): JQuery; + + /** + * Insert content, specified by the parameter, to the beginning of each element in the set of matched elements. + * + * param content1 DOM element, array of elements, HTML string, or jQuery object to insert at the beginning of each element in the set of matched elements. + * param content2 One or more additional DOM elements, arrays of elements, HTML strings, or jQuery objects to insert at the beginning of each element in the set of matched elements. + */ + prepend(content1: JQuery|any[]|Element|Text|string, ...content2: any[]): JQuery; + /** + * Insert content, specified by the parameter, to the beginning of each element in the set of matched elements. + * + * param func A function that returns an HTML string, DOM element(s), or jQuery object to insert at the beginning of each element in the set of matched elements. Receives the index position of the element in the set and the old HTML value of the element as arguments. Within the function, this refers to the current element in the set. + */ + prepend(func: (index: number, html: string) => string|Element|JQuery): JQuery; + + /** + * Insert every element in the set of matched elements to the beginning of the target. + * + * @param target A selector, element, HTML string, array of elements, or jQuery object; the matched set of elements will be inserted at the beginning of the element(s) specified by this parameter. + */ + prependTo(target: JQuery|any[]|Element|string): JQuery; + + /** + * Remove the set of matched elements from the DOM. + * + * @param selector A selector expression that filters the set of matched elements to be removed. + */ + remove(selector?: string): JQuery; + + /** + * Replace each target element with the set of matched elements. + * + * @param target A selector string, jQuery object, DOM element, or array of elements indicating which element(s) to replace. + */ + replaceAll(target: JQuery|any[]|Element|string): JQuery; + + /** + * Replace each element in the set of matched elements with the provided new content and return the set of elements that was removed. + * + * param newContent The content to insert. May be an HTML string, DOM element, array of DOM elements, or jQuery object. + */ + replaceWith(newContent: JQuery|any[]|Element|Text|string): JQuery; + /** + * Replace each element in the set of matched elements with the provided new content and return the set of elements that was removed. + * + * param func A function that returns content with which to replace the set of matched elements. + */ + replaceWith(func: () => Element|JQuery): JQuery; + + /** + * Get the combined text contents of each element in the set of matched elements, including their descendants. + */ + text(): string; + /** + * Set the content of each element in the set of matched elements to the specified text. + * + * @param text The text to set as the content of each matched element. When Number or Boolean is supplied, it will be converted to a String representation. + */ + text(text: string|number|boolean): JQuery; + /** + * Set the content of each element in the set of matched elements to the specified text. + * + * @param func A function returning the text content to set. Receives the index position of the element in the set and the old text value as arguments. + */ + text(func: (index: number, text: string) => string): JQuery; + + /** + * Retrieve all the elements contained in the jQuery set, as an array. + */ + toArray(): any[]; + + /** + * Remove the parents of the set of matched elements from the DOM, leaving the matched elements in their place. + */ + unwrap(): JQuery; + + /** + * Wrap an HTML structure around each element in the set of matched elements. + * + * @param wrappingElement A selector, element, HTML string, or jQuery object specifying the structure to wrap around the matched elements. + */ + wrap(wrappingElement: JQuery|Element|string): JQuery; + /** + * Wrap an HTML structure around each element in the set of matched elements. + * + * @param func A callback function returning the HTML content or jQuery object to wrap around the matched elements. Receives the index position of the element in the set as an argument. Within the function, this refers to the current element in the set. + */ + wrap(func: (index: number) => string|JQuery): JQuery; + + /** + * Wrap an HTML structure around all elements in the set of matched elements. + * + * @param wrappingElement A selector, element, HTML string, or jQuery object specifying the structure to wrap around the matched elements. + */ + wrapAll(wrappingElement: JQuery|Element|string): JQuery; + wrapAll(func: (index: number) => string): JQuery; + + /** + * Wrap an HTML structure around the content of each element in the set of matched elements. + * + * @param wrappingElement An HTML snippet, selector expression, jQuery object, or DOM element specifying the structure to wrap around the content of the matched elements. + */ + wrapInner(wrappingElement: JQuery|Element|string): JQuery; + /** + * Wrap an HTML structure around the content of each element in the set of matched elements. + * + * @param func A callback function which generates a structure to wrap around the content of the matched elements. Receives the index position of the element in the set as an argument. Within the function, this refers to the current element in the set. + */ + wrapInner(func: (index: number) => string): JQuery; + + /** + * Iterate over a jQuery object, executing a function for each matched element. + * + * @param func A function to execute for each matched element. + */ + each(func: (index: number, elem: Element) => any): JQuery; + + /** + * Retrieve one of the elements matched by the jQuery object. + * + * @param index A zero-based integer indicating which element to retrieve. + */ + get(index: number): HTMLElement; + /** + * Retrieve the elements matched by the jQuery object. + */ + get(): any[]; + + /** + * Search for a given element from among the matched elements. + */ + index(): number; + /** + * Search for a given element from among the matched elements. + * + * @param selector A selector representing a jQuery collection in which to look for an element. + */ + index(selector: string|JQuery|Element): number; + + /** + * The number of elements in the jQuery object. + */ + length: number; + /** + * A selector representing selector passed to jQuery(), if any, when creating the original set. + * version deprecated: 1.7, removed: 1.9 + */ + selector: string; + [index: string]: any; + [index: number]: HTMLElement; + + /** + * Add elements to the set of matched elements. + * + * @param selector A string representing a selector expression to find additional elements to add to the set of matched elements. + * @param context The point in the document at which the selector should begin matching; similar to the context argument of the $(selector, context) method. + */ + add(selector: string, context?: Element): JQuery; + /** + * Add elements to the set of matched elements. + * + * @param elements One or more elements to add to the set of matched elements. + */ + add(...elements: Element[]): JQuery; + /** + * Add elements to the set of matched elements. + * + * @param html An HTML fragment to add to the set of matched elements. + */ + add(html: string): JQuery; + /** + * Add elements to the set of matched elements. + * + * @param obj An existing jQuery object to add to the set of matched elements. + */ + add(obj: JQuery): JQuery; + + /** + * Get the children of each element in the set of matched elements, optionally filtered by a selector. + * + * @param selector A string containing a selector expression to match elements against. + */ + children(selector?: string): JQuery; + + /** + * For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree. + * + * @param selector A string containing a selector expression to match elements against. + */ + closest(selector: string): JQuery; + /** + * For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree. + * + * @param selector A string containing a selector expression to match elements against. + * @param context A DOM element within which a matching element may be found. If no context is passed in then the context of the jQuery set will be used instead. + */ + closest(selector: string, context?: Element): JQuery; + /** + * For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree. + * + * @param obj A jQuery object to match elements against. + */ + closest(obj: JQuery): JQuery; + /** + * For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree. + * + * @param element An element to match elements against. + */ + closest(element: Element): JQuery; + + /** + * Get an array of all the elements and selectors matched against the current element up through the DOM tree. + * + * @param selectors An array or string containing a selector expression to match elements against (can also be a jQuery object). + * @param context A DOM element within which a matching element may be found. If no context is passed in then the context of the jQuery set will be used instead. + */ + closest(selectors: any, context?: Element): any[]; + + /** + * Get the children of each element in the set of matched elements, including text and comment nodes. + */ + contents(): JQuery; + + /** + * End the most recent filtering operation in the current chain and return the set of matched elements to its previous state. + */ + end(): JQuery; + + /** + * Reduce the set of matched elements to the one at the specified index. + * + * @param index An integer indicating the 0-based position of the element. OR An integer indicating the position of the element, counting backwards from the last element in the set. + * + */ + eq(index: number): JQuery; + + /** + * Reduce the set of matched elements to those that match the selector or pass the function's test. + * + * @param selector A string containing a selector expression to match the current set of elements against. + */ + filter(selector: string): JQuery; + /** + * Reduce the set of matched elements to those that match the selector or pass the function's test. + * + * @param func A function used as a test for each element in the set. this is the current DOM element. + */ + filter(func: (index: number, element: Element) => any): JQuery; + /** + * Reduce the set of matched elements to those that match the selector or pass the function's test. + * + * @param element An element to match the current set of elements against. + */ + filter(element: Element): JQuery; + /** + * Reduce the set of matched elements to those that match the selector or pass the function's test. + * + * @param obj An existing jQuery object to match the current set of elements against. + */ + filter(obj: JQuery): JQuery; + + /** + * Get the descendants of each element in the current set of matched elements, filtered by a selector, jQuery object, or element. + * + * @param selector A string containing a selector expression to match elements against. + */ + find(selector: string): JQuery; + /** + * Get the descendants of each element in the current set of matched elements, filtered by a selector, jQuery object, or element. + * + * @param element An element to match elements against. + */ + find(element: Element): JQuery; + /** + * Get the descendants of each element in the current set of matched elements, filtered by a selector, jQuery object, or element. + * + * @param obj A jQuery object to match elements against. + */ + find(obj: JQuery): JQuery; + + /** + * Reduce the set of matched elements to the first in the set. + */ + first(): JQuery; + + /** + * Reduce the set of matched elements to those that have a descendant that matches the selector or DOM element. + * + * @param selector A string containing a selector expression to match elements against. + */ + has(selector: string): JQuery; + /** + * Reduce the set of matched elements to those that have a descendant that matches the selector or DOM element. + * + * @param contained A DOM element to match elements against. + */ + has(contained: Element): JQuery; + + /** + * Check the current matched set of elements against a selector, element, or jQuery object and return true if at least one of these elements matches the given arguments. + * + * @param selector A string containing a selector expression to match elements against. + */ + is(selector: string): boolean; + /** + * Check the current matched set of elements against a selector, element, or jQuery object and return true if at least one of these elements matches the given arguments. + * + * @param func A function used as a test for the set of elements. It accepts one argument, index, which is the element's index in the jQuery collection.Within the function, this refers to the current DOM element. + */ + is(func: (index: number, element: Element) => boolean): boolean; + /** + * Check the current matched set of elements against a selector, element, or jQuery object and return true if at least one of these elements matches the given arguments. + * + * @param obj An existing jQuery object to match the current set of elements against. + */ + is(obj: JQuery): boolean; + /** + * Check the current matched set of elements against a selector, element, or jQuery object and return true if at least one of these elements matches the given arguments. + * + * @param elements One or more elements to match the current set of elements against. + */ + is(elements: any): boolean; + + /** + * Reduce the set of matched elements to the final one in the set. + */ + last(): JQuery; + + /** + * Pass each element in the current matched set through a function, producing a new jQuery object containing the return values. + * + * @param callback A function object that will be invoked for each element in the current set. + */ + map(callback: (index: number, domElement: Element) => any): JQuery; + + /** + * Get the immediately following sibling of each element in the set of matched elements. If a selector is provided, it retrieves the next sibling only if it matches that selector. + * + * @param selector A string containing a selector expression to match elements against. + */ + next(selector?: string): JQuery; + + /** + * Get all following siblings of each element in the set of matched elements, optionally filtered by a selector. + * + * @param selector A string containing a selector expression to match elements against. + */ + nextAll(selector?: string): JQuery; + + /** + * Get all following siblings of each element up to but not including the element matched by the selector, DOM node, or jQuery object passed. + * + * @param selector A string containing a selector expression to indicate where to stop matching following sibling elements. + * @param filter A string containing a selector expression to match elements against. + */ + nextUntil(selector?: string, filter?: string): JQuery; + /** + * Get all following siblings of each element up to but not including the element matched by the selector, DOM node, or jQuery object passed. + * + * @param element A DOM node or jQuery object indicating where to stop matching following sibling elements. + * @param filter A string containing a selector expression to match elements against. + */ + nextUntil(element?: Element, filter?: string): JQuery; + /** + * Get all following siblings of each element up to but not including the element matched by the selector, DOM node, or jQuery object passed. + * + * @param obj A DOM node or jQuery object indicating where to stop matching following sibling elements. + * @param filter A string containing a selector expression to match elements against. + */ + nextUntil(obj?: JQuery, filter?: string): JQuery; + + /** + * Remove elements from the set of matched elements. + * + * @param selector A string containing a selector expression to match elements against. + */ + not(selector: string): JQuery; + /** + * Remove elements from the set of matched elements. + * + * @param func A function used as a test for each element in the set. this is the current DOM element. + */ + not(func: (index: number, element: Element) => boolean): JQuery; + /** + * Remove elements from the set of matched elements. + * + * @param elements One or more DOM elements to remove from the matched set. + */ + not(...elements: Element[]): JQuery; + /** + * Remove elements from the set of matched elements. + * + * @param obj An existing jQuery object to match the current set of elements against. + */ + not(obj: JQuery): JQuery; + + /** + * Get the closest ancestor element that is positioned. + */ + offsetParent(): JQuery; + + /** + * Get the parent of each element in the current set of matched elements, optionally filtered by a selector. + * + * @param selector A string containing a selector expression to match elements against. + */ + parent(selector?: string): JQuery; + + /** + * Get the ancestors of each element in the current set of matched elements, optionally filtered by a selector. + * + * @param selector A string containing a selector expression to match elements against. + */ + parents(selector?: string): JQuery; + + /** + * Get the ancestors of each element in the current set of matched elements, up to but not including the element matched by the selector, DOM node, or jQuery object. + * + * @param selector A string containing a selector expression to indicate where to stop matching ancestor elements. + * @param filter A string containing a selector expression to match elements against. + */ + parentsUntil(selector?: string, filter?: string): JQuery; + /** + * Get the ancestors of each element in the current set of matched elements, up to but not including the element matched by the selector, DOM node, or jQuery object. + * + * @param element A DOM node or jQuery object indicating where to stop matching ancestor elements. + * @param filter A string containing a selector expression to match elements against. + */ + parentsUntil(element?: Element, filter?: string): JQuery; + /** + * Get the ancestors of each element in the current set of matched elements, up to but not including the element matched by the selector, DOM node, or jQuery object. + * + * @param obj A DOM node or jQuery object indicating where to stop matching ancestor elements. + * @param filter A string containing a selector expression to match elements against. + */ + parentsUntil(obj?: JQuery, filter?: string): JQuery; + + /** + * Get the immediately preceding sibling of each element in the set of matched elements, optionally filtered by a selector. + * + * @param selector A string containing a selector expression to match elements against. + */ + prev(selector?: string): JQuery; + + /** + * Get all preceding siblings of each element in the set of matched elements, optionally filtered by a selector. + * + * @param selector A string containing a selector expression to match elements against. + */ + prevAll(selector?: string): JQuery; + + /** + * Get all preceding siblings of each element up to but not including the element matched by the selector, DOM node, or jQuery object. + * + * @param selector A string containing a selector expression to indicate where to stop matching preceding sibling elements. + * @param filter A string containing a selector expression to match elements against. + */ + prevUntil(selector?: string, filter?: string): JQuery; + /** + * Get all preceding siblings of each element up to but not including the element matched by the selector, DOM node, or jQuery object. + * + * @param element A DOM node or jQuery object indicating where to stop matching preceding sibling elements. + * @param filter A string containing a selector expression to match elements against. + */ + prevUntil(element?: Element, filter?: string): JQuery; + /** + * Get all preceding siblings of each element up to but not including the element matched by the selector, DOM node, or jQuery object. + * + * @param obj A DOM node or jQuery object indicating where to stop matching preceding sibling elements. + * @param filter A string containing a selector expression to match elements against. + */ + prevUntil(obj?: JQuery, filter?: string): JQuery; + + /** + * Get the siblings of each element in the set of matched elements, optionally filtered by a selector. + * + * @param selector A string containing a selector expression to match elements against. + */ + siblings(selector?: string): JQuery; + + /** + * Reduce the set of matched elements to a subset specified by a range of indices. + * + * @param start An integer indicating the 0-based position at which the elements begin to be selected. If negative, it indicates an offset from the end of the set. + * @param end An integer indicating the 0-based position at which the elements stop being selected. If negative, it indicates an offset from the end of the set. If omitted, the range continues until the end of the set. + */ + slice(start: number, end?: number): JQuery; + + /** + * Show the queue of functions to be executed on the matched elements. + * + * @param queueName A string containing the name of the queue. Defaults to fx, the standard effects queue. + */ + queue(queueName?: string): any[]; + /** + * Manipulate the queue of functions to be executed, once for each matched element. + * + * @param newQueue An array of functions to replace the current queue contents. + */ + queue(newQueue: Function[]): JQuery; + /** + * Manipulate the queue of functions to be executed, once for each matched element. + * + * @param callback The new function to add to the queue, with a function to call that will dequeue the next item. + */ + queue(callback: Function): JQuery; + /** + * Manipulate the queue of functions to be executed, once for each matched element. + * + * @param queueName A string containing the name of the queue. Defaults to fx, the standard effects queue. + * @param newQueue An array of functions to replace the current queue contents. + */ + queue(queueName: string, newQueue: Function[]): JQuery; + /** + * Manipulate the queue of functions to be executed, once for each matched element. + * + * @param queueName A string containing the name of the queue. Defaults to fx, the standard effects queue. + * @param callback The new function to add to the queue, with a function to call that will dequeue the next item. + */ + queue(queueName: string, callback: Function): JQuery; +} +declare module "jquery" { + export = $; +} +declare var jQuery: JQueryStatic; +declare var $: JQueryStatic; diff --git a/tooling/typings/moment/moment-node.d.ts b/tooling/typings/moment/moment-node.d.ts new file mode 100644 index 0000000..babde41 --- /dev/null +++ b/tooling/typings/moment/moment-node.d.ts @@ -0,0 +1,479 @@ +// Type definitions for Moment.js 2.8.0 +// Project: https://github.com/timrwood/moment +// Definitions by: Michael Lakerveld , Aaron King , Hiroki Horiuchi , Dick van den Brink , Adi Dahiya , Matt Brooks +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +declare module moment { + + interface MomentInput { + /** Year */ + years?: number; + /** Year */ + year?: number; + /** Year */ + y?: number; + + /** Month */ + months?: number; + /** Month */ + month?: number; + /** Month */ + M?: number; + + /** Week */ + weeks?: number; + /** Week */ + week?: number; + /** Week */ + w?: number; + + /** Day/Date */ + days?: number; + /** Day/Date */ + day?: number; + /** Day/Date */ + date?: number; + /** Day/Date */ + d?: number; + + /** Hour */ + hours?: number; + /** Hour */ + hour?: number; + /** Hour */ + h?: number; + + /** Minute */ + minutes?: number; + /** Minute */ + minute?: number; + /** Minute */ + m?: number; + + /** Second */ + seconds?: number; + /** Second */ + second?: number; + /** Second */ + s?: number; + + /** Millisecond */ + milliseconds?: number; + /** Millisecond */ + millisecond?: number; + /** Millisecond */ + ms?: number; + } + + interface Duration { + humanize(withSuffix?: boolean): string; + + as(units: string): number; + + milliseconds(): number; + asMilliseconds(): number; + + seconds(): number; + asSeconds(): number; + + minutes(): number; + asMinutes(): number; + + hours(): number; + asHours(): number; + + days(): number; + asDays(): number; + + months(): number; + asMonths(): number; + + years(): number; + asYears(): number; + + add(n: number, p: string): Duration; + add(n: number): Duration; + add(d: Duration): Duration; + + subtract(n: number, p: string): Duration; + subtract(n: number): Duration; + subtract(d: Duration): Duration; + + toISOString(): string; + toJSON(): string; + } + + interface Moment { + format(format: string): string; + format(): string; + + fromNow(withoutSuffix?: boolean): string; + + startOf(unitOfTime: string): Moment; + endOf(unitOfTime: string): Moment; + + /** + * Mutates the original moment by adding time. (deprecated in 2.8.0) + * + * @param unitOfTime the unit of time you want to add (eg "years" / "hours" etc) + * @param amount the amount you want to add + */ + add(unitOfTime: string, amount: number): Moment; + /** + * Mutates the original moment by adding time. + * + * @param amount the amount you want to add + * @param unitOfTime the unit of time you want to add (eg "years" / "hours" etc) + */ + add(amount: number, unitOfTime: string): Moment; + /** + * Mutates the original moment by adding time. Note that the order of arguments can be flipped. + * + * @param amount the amount you want to add + * @param unitOfTime the unit of time you want to add (eg "years" / "hours" etc) + */ + add(amount: string, unitOfTime: string): Moment; + /** + * Mutates the original moment by adding time. + * + * @param objectLiteral an object literal that describes multiple time units {days:7,months:1} + */ + add(objectLiteral: MomentInput): Moment; + /** + * Mutates the original moment by adding time. + * + * @param duration a length of time + */ + add(duration: Duration): Moment; + + /** + * Mutates the original moment by subtracting time. (deprecated in 2.8.0) + * + * @param unitOfTime the unit of time you want to subtract (eg "years" / "hours" etc) + * @param amount the amount you want to subtract + */ + subtract(unitOfTime: string, amount: number): Moment; + /** + * Mutates the original moment by subtracting time. + * + * @param unitOfTime the unit of time you want to subtract (eg "years" / "hours" etc) + * @param amount the amount you want to subtract + */ + subtract(amount: number, unitOfTime: string): Moment; + /** + * Mutates the original moment by subtracting time. Note that the order of arguments can be flipped. + * + * @param amount the amount you want to add + * @param unitOfTime the unit of time you want to subtract (eg "years" / "hours" etc) + */ + subtract(amount: string, unitOfTime: string): Moment; + /** + * Mutates the original moment by subtracting time. + * + * @param objectLiteral an object literal that describes multiple time units {days:7,months:1} + */ + subtract(objectLiteral: MomentInput): Moment; + /** + * Mutates the original moment by subtracting time. + * + * @param duration a length of time + */ + subtract(duration: Duration): Moment; + + calendar(): string; + calendar(start: Moment): string; + calendar(start: Moment, formats: MomentCalendar): string; + + clone(): Moment; + + /** + * @return Unix timestamp, or milliseconds since the epoch. + */ + valueOf(): number; + + local(): Moment; // current date/time in local mode + + utc(): Moment; // current date/time in UTC mode + + isValid(): boolean; + invalidAt(): number; + + year(y: number): Moment; + year(): number; + quarter(): number; + quarter(q: number): Moment; + month(M: number): Moment; + month(M: string): Moment; + month(): number; + day(d: number): Moment; + day(d: string): Moment; + day(): number; + date(d: number): Moment; + date(): number; + hour(h: number): Moment; + hour(): number; + hours(h: number): Moment; + hours(): number; + minute(m: number): Moment; + minute(): number; + minutes(m: number): Moment; + minutes(): number; + second(s: number): Moment; + second(): number; + seconds(s: number): Moment; + seconds(): number; + millisecond(ms: number): Moment; + millisecond(): number; + milliseconds(ms: number): Moment; + milliseconds(): number; + weekday(): number; + weekday(d: number): Moment; + isoWeekday(): number; + isoWeekday(d: number): Moment; + weekYear(): number; + weekYear(d: number): Moment; + isoWeekYear(): number; + isoWeekYear(d: number): Moment; + week(): number; + week(d: number): Moment; + weeks(): number; + weeks(d: number): Moment; + isoWeek(): number; + isoWeek(d: number): Moment; + isoWeeks(): number; + isoWeeks(d: number): Moment; + weeksInYear(): number; + isoWeeksInYear(): number; + dayOfYear(): number; + dayOfYear(d: number): Moment; + + from(f: Moment|string|number|Date|number[], suffix?: boolean): string; + to(f: Moment|string|number|Date|number[], suffix?: boolean): string; + toNow(withoutPrefix?: boolean): string; + + diff(b: Moment): number; + diff(b: Moment, unitOfTime: string): number; + diff(b: Moment, unitOfTime: string, round: boolean): number; + + toArray(): number[]; + toDate(): Date; + toISOString(): string; + toJSON(): string; + unix(): number; + + isLeapYear(): boolean; + zone(): number; + zone(b: number): Moment; + zone(b: string): Moment; + utcOffset(): number; + utcOffset(b: number): Moment; + utcOffset(b: string): Moment; + daysInMonth(): number; + isDST(): boolean; + + isBefore(): boolean; + isBefore(b: Moment|string|number|Date|number[], granularity?: string): boolean; + + isAfter(): boolean; + isAfter(b: Moment|string|number|Date|number[], granularity?: string): boolean; + + isSame(b: Moment|string|number|Date|number[], granularity?: string): boolean; + isBetween(a: Moment|string|number|Date|number[], b: Moment|string|number|Date|number[], granularity?: string): boolean; + + // Deprecated as of 2.8.0. + lang(language: string): Moment; + lang(reset: boolean): Moment; + lang(): MomentLanguage; + + locale(language: string): Moment; + locale(reset: boolean): Moment; + locale(): string; + + localeData(language: string): Moment; + localeData(reset: boolean): Moment; + localeData(): MomentLanguage; + + // Deprecated as of 2.7.0. + max(date: Moment|string|number|Date|any[]): Moment; + max(date: string, format: string): Moment; + + // Deprecated as of 2.7.0. + min(date: Moment|string|number|Date|any[]): Moment; + min(date: string, format: string): Moment; + + get(unit: string): number; + set(unit: string, value: number): Moment; + set(objectLiteral: MomentInput): Moment; + } + + type formatFunction = () => string; + + interface MomentCalendar { + lastDay?: string | formatFunction; + sameDay?: string | formatFunction; + nextDay?: string | formatFunction; + lastWeek?: string | formatFunction; + nextWeek?: string | formatFunction; + sameElse?: string | formatFunction; + } + + interface BaseMomentLanguage { + months ?: any; + monthsShort ?: any; + weekdays ?: any; + weekdaysShort ?: any; + weekdaysMin ?: any; + relativeTime ?: MomentRelativeTime; + meridiem ?: (hour: number, minute: number, isLowercase: boolean) => string; + calendar ?: MomentCalendar; + ordinal ?: (num: number) => string; + } + + interface MomentLanguage extends BaseMomentLanguage { + longDateFormat?: MomentLongDateFormat; + } + + interface MomentLanguageData extends BaseMomentLanguage { + /** + * @param formatType should be L, LL, LLL, LLLL. + */ + longDateFormat(formatType: string): string; + } + + interface MomentLongDateFormat { + L: string; + LL: string; + LLL: string; + LLLL: string; + LT: string; + LTS: string; + l?: string; + ll?: string; + lll?: string; + llll?: string; + lt?: string; + lts?: string; + } + + interface MomentRelativeTime { + future: any; + past: any; + s: any; + m: any; + mm: any; + h: any; + hh: any; + d: any; + dd: any; + M: any; + MM: any; + y: any; + yy: any; + } + + interface MomentStatic { + version: string; + fn: Moment; + + (): Moment; + (date: number): Moment; + (date: number[]): Moment; + (date: string, format?: string, strict?: boolean): Moment; + (date: string, format?: string, language?: string, strict?: boolean): Moment; + (date: string, formats: string[], strict?: boolean): Moment; + (date: string, formats: string[], language?: string, strict?: boolean): Moment; + (date: string, specialFormat: () => void, strict?: boolean): Moment; + (date: string, specialFormat: () => void, language?: string, strict?: boolean): Moment; + (date: string, formatsIncludingSpecial: any[], strict?: boolean): Moment; + (date: string, formatsIncludingSpecial: any[], language?: string, strict?: boolean): Moment; + (date: Date): Moment; + (date: Moment): Moment; + (date: Object): Moment; + + utc(): Moment; + utc(date: number): Moment; + utc(date: number[]): Moment; + utc(date: string, format?: string, strict?: boolean): Moment; + utc(date: string, format?: string, language?: string, strict?: boolean): Moment; + utc(date: string, formats: string[], strict?: boolean): Moment; + utc(date: string, formats: string[], language?: string, strict?: boolean): Moment; + utc(date: Date): Moment; + utc(date: Moment): Moment; + utc(date: Object): Moment; + + unix(timestamp: number): Moment; + + invalid(parsingFlags?: Object): Moment; + isMoment(): boolean; + isMoment(m: any): boolean; + isDate(m: any): boolean; + isDuration(): boolean; + isDuration(d: any): boolean; + + // Deprecated in 2.8.0. + lang(language?: string): string; + lang(language?: string, definition?: MomentLanguage): string; + + locale(language?: string): string; + locale(language?: string[]): string; + locale(language?: string, definition?: MomentLanguage): string; + + localeData(language?: string): MomentLanguageData; + + longDateFormat: any; + relativeTime: any; + meridiem: (hour: number, minute: number, isLowercase: boolean) => string; + calendar: any; + ordinal: (num: number) => string; + + duration(milliseconds: Number): Duration; + duration(num: Number, unitOfTime: string): Duration; + duration(input: MomentInput): Duration; + duration(object: any): Duration; + duration(): Duration; + + parseZone(date: string): Moment; + + months(): string[]; + months(index: number): string; + months(format: string): string[]; + months(format: string, index: number): string; + monthsShort(): string[]; + monthsShort(index: number): string; + monthsShort(format: string): string[]; + monthsShort(format: string, index: number): string; + + weekdays(): string[]; + weekdays(index: number): string; + weekdays(format: string): string[]; + weekdays(format: string, index: number): string; + weekdaysShort(): string[]; + weekdaysShort(index: number): string; + weekdaysShort(format: string): string[]; + weekdaysShort(format: string, index: number): string; + weekdaysMin(): string[]; + weekdaysMin(index: number): string; + weekdaysMin(format: string): string[]; + weekdaysMin(format: string, index: number): string; + + min(...moments: Moment[]): Moment; + max(...moments: Moment[]): Moment; + + normalizeUnits(unit: string): string; + relativeTimeThreshold(threshold: string): number|boolean; + relativeTimeThreshold(threshold: string, limit:number): boolean; + + /** + * Constant used to enable explicit ISO_8601 format parsing. + */ + ISO_8601(): void; + + defaultFormat: string; + } + +} + +declare module 'moment' { + var moment: moment.MomentStatic; + export = moment; +} diff --git a/tooling/typings/moment/moment.d.ts b/tooling/typings/moment/moment.d.ts new file mode 100644 index 0000000..78b0901 --- /dev/null +++ b/tooling/typings/moment/moment.d.ts @@ -0,0 +1,8 @@ +// Type definitions for Moment.js 2.8.0 +// Project: https://github.com/timrwood/moment +// Definitions by: Michael Lakerveld , Aaron King , Hiroki Horiuchi , Dick van den Brink , Adi Dahiya , Matt Brooks +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +/// + +declare var moment: moment.MomentStatic; diff --git a/tooling/typings/phonegap-plugin-push/phonegap-plugin-push.d.ts b/tooling/typings/phonegap-plugin-push/phonegap-plugin-push.d.ts new file mode 100644 index 0000000..f72c8f7 --- /dev/null +++ b/tooling/typings/phonegap-plugin-push/phonegap-plugin-push.d.ts @@ -0,0 +1,277 @@ +// Type definitions for phonegap-plugin-push +// Project: https://github.com/phonegap/phonegap-plugin-push +// Definitions by: Frederico Galvão +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + +declare namespace PhonegapPluginPush { + type EventResponse = RegistrationEventResponse | NotificationEventResponse | Error + + interface PushNotification { + /** + * The event registration will be triggered on each successful registration with the 3rd party push service. + * @param event + * @param callback + */ + on(event: "registration", callback: (response: RegistrationEventResponse) => any): void + /** + * The event notification will be triggered each time a push notification is received by a 3rd party push service on the device. + * @param event + * @param callback + */ + on(event: "notification", callback: (response: NotificationEventResponse) => any): void + /** + * The event error will trigger when an internal error occurs and the cache is aborted. + * @param event + * @param callback + */ + on(event: "error", callback: (response: Error) => any): void + /** + * + * @param event Name of the event to listen to. See below(above) for all the event names. + * @param callback is called when the event is triggered. + * @param event + * @param callback + */ + on(event: string, callback: (response: EventResponse) => any): void + + off(event: "registration", callback: (response: RegistrationEventResponse) => any): void + off(event: "notification", callback: (response: NotificationEventResponse) => any): void + off(event: "error", callback: (response: Error) => any): void + /** + * As stated in the example, you will have to store your event handler if you are planning to remove it. + * @param event Name of the event type. The possible event names are the same as for the push.on function. + * @param callback handle to the function to get removed. + * @param event + * @param callback + */ + off(event: string, callback: (response: EventResponse) => any): void + + /** + * The unregister method is used when the application no longer wants to receive push notifications. + * Beware that this cleans up all event handlers previously registered, + * so you will need to re-register them if you want them to function again without an application reload. + * @param successHandler + * @param errorHandler + * @param topics + */ + unregister(successHandler: () => any, errorHandler?: () => any, topics?: string[]): void + + /*TODO according to js source code, "errorHandler" is optional, but is "count" also optional? I can't read objetive-C code (can anyone at all? I wonder...)*/ + /** + * Set the badge count visible when the app is not running + * + * The count is an integer indicating what number should show up in the badge. + * Passing 0 will clear the badge. + * Each notification event contains a data.count value which can be used to set the badge to correct number. + * @param successHandler + * @param errorHandler + * @param count + */ + setApplicationIconBadgeNumber(successHandler: () => any, errorHandler: () => any, count: number): void + /** + * Get the current badge count visible when the app is not running + * successHandler gets called with an integer which is the current badge count + * @param successHandler + * @param errorHandler + */ + getApplicationIconBadgeNumber(successHandler: (count: number) => any, errorHandler: () => any): void + + /** + * iOS only + * Tells the OS that you are done processing a background push notification. + * successHandler gets called when background push processing is successfully completed. + * @param successHandler + * @param errorHandler + * @param id + */ + finish(successHandler?: () => any, errorHandler?: () => any, id?: string): void + } + + /** + * platform specific initialization options. + */ + interface InitOptions { + /** + * Android specific initialization options. + */ + android?: { + /** + * Maps to the project number in the Google Developer Console. + */ + senderID: string + /** + * The name of a drawable resource to use as the small-icon. The name should not include the extension. + */ + icon?: string + /** + * Sets the background color of the small icon on Android 5.0 and greater. + * Supported Formats - http://developer.android.com/reference/android/graphics/Color.html#parseColor(java.lang.String) + */ + iconColor?: string + /** + * If true it plays the sound specified in the push data or the default system sound. Default is true. + */ + sound?: boolean + /** + * If true the device vibrates on receipt of notification. Default is true. + */ + vibrate?: boolean + /** + * If true the app clears all pending notifications when it is closed. Default is true. + */ + clearNotifications?: boolean + /** + * If true will always show a notification, even when the app is on the foreground. Default is false. + */ + forceShow?: boolean + /** + * If the array contains one or more strings each string will be used to subscribe to a GcmPubSub topic. + */ + topics?: string[] + } + + /** + * iOS specific initialization options. + */ + ios?: { + /** + * If true|"true" the device sets the badge number on receipt of notification. + * Default is false|"false". + * Note: the value you set this option to the first time you call the init method will be how the application always acts. + * Once this is set programmatically in the init method it can only be changed manually by the user in Settings>Notifications>App Name. + * This is normal iOS behaviour. + */ + badge?: boolean | string + /** + * If true|"true" the device plays a sound on receipt of notification. + * Default is false|"false". + * Note: the value you set this option to the first time you call the init method will be how the application always acts. + * Once this is set programmatically in the init method it can only be changed manually by the user in Settings>Notifications>App Name. + * This is normal iOS behaviour. + */ + sound?: boolean | string + /** + * If true|"true" the device shows an alert on receipt of notification. + * Default is false|"false". + * Note: the value you set this option to the first time you call the init method will be how the application always acts. + * Once this is set programmatically in the init method it can only be changed manually by the user in Settings>Notifications>App Name. + * This is normal iOS behaviour. + */ + alert?: boolean | string + /** + * If true|"true" the badge will be cleared on app startup. Default is false|"false". + */ + clearBadge?: boolean | string + /** + * The data required in order to enable Action Buttons for iOS. + * Action Buttons on iOS - https://github.com/phonegap/phonegap-plugin-push/blob/master/docs/PAYLOAD.md#action-buttons-1 + */ + categories?: CategoryArray + /** + * Maps to the project number in the Google Developer Console. Setting this uses GCM for notifications instead of native + */ + senderID?: string + /** + * Whether to use prod or sandbox GCM setting. Defaults to false. + */ + gcmSandbox?: boolean + /** + * If the array contains one or more strings each string will be used to subscribe to a GcmPubSub topic. Note: only usable in conjunction with senderID + */ + topics?: string[] + } + + /** + * Windows specific initialization options. + */ + windows?: { + + } + } + + interface CategoryArray { + [name: string]: CategoryAction + } + + interface CategoryAction { + yes?: CategoryActionData + no?: CategoryActionData + maybe?: CategoryActionData + } + + interface CategoryActionData { + callback: string + title: string + foreground: boolean + destructive: boolean + } + + interface RegistrationEventResponse { + /** + * The registration ID provided by the 3rd party remote push service. + */ + registrationId: string + } + + interface NotificationEventResponse { + /** + * The text of the push message sent from the 3rd party service. + */ + message: string + /** + * The optional title of the push message sent from the 3rd party service. + */ + title?: string + /** + * The number of messages to be displayed in the badge iOS or message count in the notification shade in Android. + * For windows, it represents the value in the badge notification which could be a number or a status glyph. + */ + count: string + /** + * The name of the sound file to be played upon receipt of the notification. + */ + sound: string + /** + * The path of the image file to be displayed in the notification. + */ + image: string + /** + * An optional collection of data sent by the 3rd party push service that does not fit in the above properties. + */ + additionalData: NotificationEventAdditionalData + } + + /** + * TODO: document all possible properties (I only got the android ones) + * + * Loosened up with a dictionary notation, but all non-defined properties need to use (map['prop']) notation + * + * Ideally the developer would overload (merged declaration) this or create a new interface that would extend this one + * so that he could specify any custom code without having to use array notation (map['prop']) for all of them. + */ + interface NotificationEventAdditionalData { + [name: string]: any + + /** + * Whether the notification was received while the app was in the foreground + */ + foreground?: boolean + /** + * Will be true if the application is started by clicking on the push notification, false if the app is already started. (Android/iOS only) + */ + coldstart?: boolean + collapse_key?: string + from?: string + notId?: string + } + + interface PushNotificationStatic { + init(options: InitOptions): PushNotification + new (options: InitOptions): PushNotification + } +} + +interface Window { + PushNotification: PhonegapPluginPush.PushNotificationStatic +} +declare var PushNotification: PhonegapPluginPush.PushNotificationStatic; diff --git a/tooling/typings/signalr/signalr.d.ts b/tooling/typings/signalr/signalr.d.ts new file mode 100644 index 0000000..a46116f --- /dev/null +++ b/tooling/typings/signalr/signalr.d.ts @@ -0,0 +1,365 @@ +// Type definitions for SignalR 2.2.0 +// Project: http://www.asp.net/signalr +// Definitions by: Boris Yankov , T. Michael Keesey , Giedrius Grabauskas +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + + +/// + + +declare namespace SignalR { + + const enum ConnectionState { + Connecting = 0, + Connected = 1, + Reconnecting = 2, + Disconnected = 4 + } + + interface AvailableEvents { + onStart: string; + onStarting: string; + onReceived: string; + onError: string; + onConnectionSlow: string; + onReconnect: string; + onStateChanged: string; + onDisconnect: string; + } + + interface Transport { + name: string; + supportsKeepAlive(): boolean; + send(connection: SignalR.Connection, data: any): void; + start(connection: SignalR.Connection, onSuccess: () => void, onFailed: (error?: ConnectionError) => void): void; + reconnect(connection: SignalR.Connection): void; + lostConnection(connection: SignalR.Connection): void; + stop(connection: SignalR.Connection): void; + abort(connection: SignalR.Connection, async: boolean): void; + } + + interface Transports { + foreverFrame: Transport; + longPolling: Transport; + serverSentEvents: Transport; + webSockets: Transport; + } + + namespace Hub { + + interface Proxy { + state: any; + connection: Connection; + hubName: string; + init(connection: Connection, hubName: string): void; + hasSubscriptions(): boolean; + /** + * Wires up a callback to be invoked when a invocation request is received from the server hub. + * + * @param eventName The name of the hub event to register the callback for. + * @param callback The callback to be invoked. + */ + on(eventName: string, callback: (...msg: any[]) => void): Proxy; + /** + * Removes the callback invocation request from the server hub for the given event name. + * + * @param eventName The name of the hub event to unregister the callback for. + * @param callback The callback to be invoked. + */ + off(eventName: string, callback: (...msg: any[]) => void): Proxy; + /** + * Invokes a server hub method with the given arguments. + * + * @param methodName The name of the server hub method. + */ + invoke(methodName: string, ...args: any[]): JQueryPromise; + } + + interface Options { + qs?: string; + logging?: boolean; + useDefaultPath?: boolean; + } + + interface ClientHubInvocation { + Hub: string; + Method: string; + Args: string; + State: string; + } + + interface Connection extends SignalR.Connection { + proxies: { [hubName: string]: any }; + transport: { name: string, supportsKeepAlive: () => boolean }; + /** + * Creates a new proxy object for the given hub connection that can be used to invoke + * methods on server hubs and handle client method invocation requests from the server. + * + * @param hubName The name of the hub on the server to create the proxy for. + */ + createHubProxy(hubName: string): Proxy; + } + + interface HubCreator { + /** + * Creates a new hub connection. + * + * @param url [Optional] The hub route url, defaults to "/signalr". + * @param options [Optional] Settings to use when creating the hubConnection. + */ + (url?: string, options?: Options): Connection; + } + + interface IHub { + start(): void; + } + + } + + interface StateChanged { + oldState: number; + newState: number; + } + + interface ConnectionStates { + connecting: number; + connected: number; + reconnecting: number; + disconnected: number; + } + + interface Resources { + nojQuery: string; + noTransportOnInit: string; + errorOnNegotiate: string; + stoppedWhileLoading: string; + stoppedWhileNegotiating: string; + errorParsingNegotiateResponse: string; + errorDuringStartRequest: string; + stoppedDuringStartRequest: string; + errorParsingStartResponse: string; + invalidStartResponse: string; + protocolIncompatible: string; + sendFailed: string; + parseFailed: string; + longPollFailed: string; + eventSourceFailedToConnect: string; + eventSourceError: string; + webSocketClosed: string; + pingServerFailedInvalidResponse: string; + pingServerFailed: string; + pingServerFailedStatusCode: string; + pingServerFailedParse: string; + noConnectionTransport: string; + webSocketsInvalidState: string; + reconnectTimeout: string; + reconnectWindowTimeout: string; + } + + interface AjaxDefaults { + processData: boolean; + timeout: number; + async: boolean; + global: boolean; + cache: boolean; + } + + interface ConnectionOptions { + transport?: string | Array | Transport; + callback?: Function; + waitForPageLoad?: boolean; + jsonp?: boolean; + pingInterval?: number; + } + + interface SimplifyLocation { + protocol: string; + host: string; + } + + interface ConnectionErrorContext { + readyState: number; + responseText: string; + status: number; + statusText: string; + } + + interface ConnectionError extends Error { + context: ConnectionErrorContext; + transport?: string; + source?: string; + } + + interface Connection { + clientProtocol: string; + ajaxDataType: string; + contentType: string; + id: string; + json: JSON; + logging: boolean; + url: string; + qs: string | Object; + state: number; + reconnectDelay: number; + transportConnectTimeout: number; + /** + * This should be set by the server in response to the negotiate request (30s default) + */ + disconnectTimeout: number; + /** + * This should be set by the server in response to the negotiate request + */ + reconnectWindow: number; + /** + * Warn user of slow connection if we breach the X% mark of the keep alive timeout + */ + keepAliveWarnAt: number; + + /** + * Starts the connection + */ + start(): JQueryPromise; + + /** + * Starts the connection + * + * @param callback A callback function to execute when the connection has started + */ + start(callback: () => void): JQueryPromise; + + /** + * Starts the connection + * + * @param options Options map + */ + start(options: ConnectionOptions): JQueryPromise; + + /** + * Starts the connection + * + * @param options Options map + * @param calback A callback function to execute when the connection has started + */ + start(options: ConnectionOptions, callback: () => void): JQueryPromise; + + /** + * Adds a callback that will be invoked before anything is sent over the connection + * + * @param calback A callback function to execute before the connection is fully instantiated. + */ + starting(callback: () => void): Connection; + + /** + * Sends data over the connection + * + * @param options Options map + * @param calback The data to send over the connection + */ + send(data: string): Connection; + + /** + * Adds a callback that will be invoked after anything is received over the connection + * + * @param calback A callback function to execute when any data is received on the connection + */ + received(callback: (data: any) => void): Connection; + + /** + * Adds a callback that will be invoked when the connection state changes + * + * @param calback A callback function to execute when the connection state changes + */ + stateChanged(callback: (change: StateChanged) => void): Connection; + + /** + * Adds a callback that will be invoked after an error occurs with the connection + * + * @param calback A callback function to execute when an error occurs on the connection + */ + error(callback: (error: ConnectionError) => void): Connection; + + /** + * Adds a callback that will be invoked when the client disconnects + * + * @param calback A callback function to execute when the connection is broken + */ + disconnected(callback: () => void): Connection; + + /** + * Adds a callback that will be invoked when the client detects a slow connection + * + * @param calback A callback function to execute when the connection is slow + */ + connectionSlow(callback: () => void): Connection; + + /** + * Adds a callback that will be invoked when the underlying transport begins reconnecting + * + * @param calback A callback function to execute when the connection enters a reconnecting state + */ + reconnecting(callback: () => void): Connection; + + /** + * Adds a callback that will be invoked when the underlying transport reconnects + * + * @param calback A callback function to execute when the connection is restored + */ + reconnected(callback: () => void): Connection; + + /** + * Stops listening + * + * @param async Whether or not to asynchronously abort the connection + * @param notifyServer Whether we want to notify the server that we are aborting the connection + */ + stop(async?: boolean, notifyServer?: boolean): Connection; + + log(msg: string): Connection; + + /** + * Checks if url is cross domain + * + * @param url The base URL + * @param against An optional argument to compare the URL against, if not specified it will be set to window.location. If specified it must contain a protocol and a host property. + */ + isCrossDomain(url: string, against?: Location | SimplifyLocation): boolean; + + hub: Hub.Connection; + + lastError: ConnectionError; + resources: Resources; + } +} + +interface SignalR { + /** + * Creates a new SignalR connection for the given url + * + * @param url The URL of the long polling endpoint + * @param queryString [Optional] Custom querystring parameters to add to the connection URL. If an object, every non-function member will be added to the querystring. If a string, it's added to the QS as specified. + * @param logging [Optional] A flag indicating whether connection logging is enabled to the browser console/log. Defaults to false. + */ + (url: string, queryString?: string | Object, logging?: boolean): SignalR.Connection; + ajaxDefaults: SignalR.AjaxDefaults; + changeState(connection: SignalR.Connection, expectedState: number, newState: number): void; + connectionState: SignalR.ConnectionStates; + events: SignalR.AvailableEvents; + transports: SignalR.Transports; + hub: SignalR.Hub.Connection; + hubConnection: SignalR.Hub.HubCreator; + isDisconnecting(connection: SignalR.Connection): boolean; + /** + * Reinstates the original value of $.connection and returns the signalR object for manual assignment. + */ + noConflict(): SignalR.Connection; + /** + * Current SignalR version. + */ + version: string; +} + +interface JQueryStatic { + signalR: SignalR; + connection: SignalR; + hubConnection: SignalR.Hub.HubCreator; +} diff --git a/tooling/typings/tsd.d.ts b/tooling/typings/tsd.d.ts new file mode 100644 index 0000000..a7683c4 --- /dev/null +++ b/tooling/typings/tsd.d.ts @@ -0,0 +1,17 @@ +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..a6227b9 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,80 @@ +{ + "filesGlob": [ + "./tooling/typings/tsd.d.ts", + "./app/infrastructure/**/*.ts", + "./app/**/*.mod.ts", + "./app/**/*.routes.ts", + "./app/**/*.interceptor.ts", + "./app/**/*.run.ts", + "./app/**/*.ts", + "./tests/lib/**/*.ts" + ], + "compilerOptions": { + "target": "ES5", + "module": "commonjs", + "noImplicitAny": false, + "removeComments": true, + "preserveConstEnums": true, + "sourceMap": true, + "experimentalDecorators": true, + "outDir": "www/js/app", + "inlineSourceMap": true, + "inlineSources": true + }, + "files": [ + "./tooling/typings/tsd.d.ts", + "./app/infrastructure/ComponentHelper.ts", + "./app/infrastructure/Dectorators/Components.ts", + "./app/authentication/auth.mod.ts", + "./app/core/core.mod.ts", + "./app/flight-detail/flight-detail.mod.ts", + "./app/flight-list/flight-list.mod.ts", + "./app/site-selection/site-selection.mod.ts", + "./app/window-list/window-list.mod.ts", + "./app/authentication/auth.routes.ts", + "./app/authentication/services/authentication.interceptor.ts", + "./app/authentication/components/login-view/login.spec.ts", + "./app/authentication/components/login-view/login.ts", + "./app/authentication/services/authentication.service.ts", + "./app/chroma.app.ts", + "./app/core/core.config.ts", + "./app/core/frame/frame.spec.ts", + "./app/core/frame/frame.ts", + "./app/core/service/chromaStateService.ts", + "./app/core/service/flightService.ts", + "./app/core/service/pushHandler.service.ts", + "./app/core/service/signalRService.ts", + "./app/core/service/helpers.ts", + "./app/flight-detail/detail/flight-detail.spec.ts", + "./app/flight-detail/detail/flight-detail.ts", + "./app/flight-detail/editors/baseEditor.ts", + "./app/flight-detail/editors/datetime/datetime.spec.ts", + "./app/flight-detail/editors/datetime/datetime.ts", + "./app/flight-detail/editors/freetext/freetext.spec.ts", + "./app/flight-detail/editors/freetext/freetext.ts", + "./app/flight-detail/editors/lookup/lookup.ts", + "./app/flight-detail/flight-detail.config.ts", + "./app/flight-detail/transactions/transaction-detail.ts", + "./app/flight-detail/transactions/transaction-list.ts", + "./app/flight-detail/transactions/transaction-list.spec.ts", + "./app/flight-detail/transactions/transaction.mod.ts", + "./app/flight-detail/group/flight-group.spec.ts", + "./app/flight-detail/group/flight-group.ts", + "./app/flight-detail/services/flightInformationService.spec.ts", + "./app/flight-detail/services/flightInformationService.ts", + "./app/flight-detail/services/prmService.ts", + "./app/flight-list/flight-list.config.ts", + "./app/flight-list/list/flight-list.spec.ts", + "./app/flight-list/list/flight-list.ts", + "./app/site-selection/service/site-selection.service.ts", + "./app/site-selection/site-selection.config.ts", + "./app/site-selection/view/site-selection.spec.ts", + "./app/site-selection/view/site-selection.ts", + "./app/window-list/list/window-list.spec.ts", + "./app/window-list/list/window-list.ts" + ], + "exclude": [], + "atom": { + "rewriteTsconfig": true + } +} diff --git a/tsd.json b/tsd.json new file mode 100644 index 0000000..33b86fb --- /dev/null +++ b/tsd.json @@ -0,0 +1,39 @@ +{ + "version": "v4", + "repo": "borisyankov/DefinitelyTyped", + "ref": "master", + "path": "tooling/typings", + "bundle": "tooling/typings/tsd.d.ts", + "installed": { + "jquery/jquery.d.ts": { + "commit": "32029fcb4e1a3ef8968711b545d77b584435729d" + }, + "jasmine/jasmine.d.ts": { + "commit": "32029fcb4e1a3ef8968711b545d77b584435729d" + }, + "angularjs/angular.d.ts": { + "commit": "32029fcb4e1a3ef8968711b545d77b584435729d" + }, + "angularjs/angular-animate.d.ts": { + "commit": "32029fcb4e1a3ef8968711b545d77b584435729d" + }, + "angularjs/angular-cookies.d.ts": { + "commit": "32029fcb4e1a3ef8968711b545d77b584435729d" + }, + "angularjs/angular-mocks.d.ts": { + "commit": "32029fcb4e1a3ef8968711b545d77b584435729d" + }, + "angularjs/angular-resource.d.ts": { + "commit": "32029fcb4e1a3ef8968711b545d77b584435729d" + }, + "angularjs/angular-route.d.ts": { + "commit": "32029fcb4e1a3ef8968711b545d77b584435729d" + }, + "angularjs/angular-sanitize.d.ts": { + "commit": "32029fcb4e1a3ef8968711b545d77b584435729d" + }, + "angular-ui-router/angular-ui-router.d.ts": { + "commit": "32029fcb4e1a3ef8968711b545d77b584435729d" + } + } +} diff --git a/tslint.json b/tslint.json new file mode 100644 index 0000000..610f2da --- /dev/null +++ b/tslint.json @@ -0,0 +1,47 @@ +{ + "rules": { + "class-name": true, + "curly": true, + "eofline": false, + "forin": true, + "indent": [true, 4], + "label-position": true, + "max-line-length": [false, 140], + "no-arg": true, + "no-bitwise": true, + "no-console": [true, + "debug", + "info", + "time", + "timeEnd", + "trace" + ], + "no-construct": true, + "no-debugger": true, + "no-duplicate-variable": true, + "no-empty": true, + "no-eval": true, + "no-require-imports": false, + "no-string-literal": false, + "trailing-comma": [true, {"multiline": "never", "singleline": "never"}], + "no-trailing-whitespace": true, + "no-use-before-declare": true, + "one-line": [true, + "check-open-brace", + "check-catch", + "check-else", + "check-whitespace" + ], + "quotemark": [true, "single"], + "radix": true, + "semicolon": true, + "triple-equals": [true, "allow-null-check"], + "variable-name": false, + "whitespace": [true, + "check-branch", + "check-decl", + "check-operator", + "check-separator" + ] + } +} diff --git a/wallaby.js b/wallaby.js new file mode 100644 index 0000000..268a138 --- /dev/null +++ b/wallaby.js @@ -0,0 +1,82 @@ + +module.exports = function (w) { + return { + files: [{ + pattern: 'jspm_packages/system.js', + instrument: false + }, { + pattern: 'system.config.js', + instrument: false + }, { + pattern: 'www/scripts/lib/jquery.js', + instrument: false + }, { + pattern: 'www/scripts/lib/ionic.bundle.js', + instrument: false + }, { + pattern: 'www/scripts/lib/angular-mocks.js', + instrument: false + }, { + pattern: 'www/scripts/lib/angular-cookies.js', + instrument: false + }, { + pattern: 'www/scripts/lib/angular-ui-router.js', + instrument: false + }, + { + pattern: 'www/scripts/lib/moment.js', + instrument: false + }, { + pattern: 'www/scripts/lib/chroma-framework.js', + instrument: false + }, { + pattern: 'www/scripts/app.config.js', + instrument: false + }, { + pattern: 'www/scripts/chroma.templates.compiled.js', + instrument: false + }, { + pattern: 'tests/lib/**/*.ts', + instrument: false + }, { + pattern: 'app/**/!(*.spec.ts)*.ts', + load: true + }], + + tests: [{ + pattern: 'app/**/*.spec.ts', + load: true + }], + + compilers: { + 'app/**/*.ts': w.compilers.typeScript({ + module: 3, + target: 1 + }), + 'tests/lib/**/*.ts': w.compilers.typeScript({ + module: 3, + target: 1 + }) + }, + + middleware: function (app, express) { + app.use('/jspm_packages', express.static(require('path').join(__dirname, 'jspm_packages'))); + app.use('/lib', express.static(require('path').join(__dirname, 'www/scripts/lib'))); + }, + + bootstrap: function (wallaby) { + wallaby.delayStart(); + + var promises = []; + + for (var i = 0, len = wallaby.loadedTests.length; i < len; i++) { + promises.push(System['import'](wallaby.loadedTests[i].replace(/\\/g, '/').replace(/\.js$/, ''))); + }; + + + Promise.all(promises).then(function () { + wallaby.start(); + }); + } + }; +};