+Aurelia +Paket +FAKE
Interim commit; there may still be leftover files from the Aurelia tutorial
This commit is contained in:
parent
e522ab1ae1
commit
b0b20df36d
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -256,3 +256,4 @@ paket-files/
|
||||||
src/elm-stuff
|
src/elm-stuff
|
||||||
# Compiled application
|
# Compiled application
|
||||||
src/wwwroot/app.js
|
src/wwwroot/app.js
|
||||||
|
build/
|
108
.paket/Paket.Restore.targets
Normal file
108
.paket/Paket.Restore.targets
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<!-- Mark that this target file has been loaded. -->
|
||||||
|
<IsPaketRestoreTargetsFileLoaded>true</IsPaketRestoreTargetsFileLoaded>
|
||||||
|
<PaketToolsPath>$(MSBuildThisFileDirectory)</PaketToolsPath>
|
||||||
|
<MonoPath Condition="'$(MonoPath)' == '' And Exists('/Library/Frameworks/Mono.framework/Commands/mono')">/Library/Frameworks/Mono.framework/Commands/mono</MonoPath>
|
||||||
|
<MonoPath Condition="'$(MonoPath)' == ''">mono</MonoPath>
|
||||||
|
<!-- Paket command -->
|
||||||
|
<PaketExePath Condition=" '$(PaketExePath)' == '' AND Exists('$(PaketRootPath)paket.exe')">$(PaketRootPath)paket.exe</PaketExePath>
|
||||||
|
<PaketExePath Condition=" '$(PaketExePath)' == '' ">$(PaketToolsPath)paket.exe</PaketExePath>
|
||||||
|
<PaketCommand Condition=" '$(OS)' == 'Windows_NT'">"$(PaketExePath)"</PaketCommand>
|
||||||
|
<PaketCommand Condition=" '$(OS)' != 'Windows_NT' ">$(MonoPath) --runtime=v4.0.30319 "$(PaketExePath)"</PaketCommand>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Target Name="PaketRestore" BeforeTargets="_GenerateProjectRestoreGraphPerFramework;_GenerateRestoreGraphWalkPerFramework;CollectPackageReferences" >
|
||||||
|
|
||||||
|
<Exec Command='$(PaketCommand) restore --project "$(MSBuildProjectFullPath)" ' />
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<PaketReferencesFilePath>$(MSBuildProjectDirectory)/obj/$(MSBuildProjectFile).references</PaketReferencesFilePath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ReadLinesFromFile File="$(PaketReferencesFilePath)" >
|
||||||
|
<Output TaskParameter="Lines" ItemName="PaketReferencesFileLines"/>
|
||||||
|
</ReadLinesFromFile>
|
||||||
|
|
||||||
|
<ItemGroup Condition=" '@(PaketReferencesFileLines)' != '' " >
|
||||||
|
<PaketReferencesFileLinesInfo Include="@(PaketReferencesFileLines)" >
|
||||||
|
<PackageName>$([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[0])</PackageName>
|
||||||
|
<PackageVersion>$([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[1])</PackageVersion>
|
||||||
|
</PaketReferencesFileLinesInfo>
|
||||||
|
<PackageReference Include="%(PaketReferencesFileLinesInfo.PackageName)">
|
||||||
|
<Version>%(PaketReferencesFileLinesInfo.PackageVersion)</Version>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<RestoreConfigFile>$(MSBuildProjectDirectory)/obj/$(MSBuildProjectFile).NuGet.Config</RestoreConfigFile>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="PaketDisableDirectPack" AfterTargets="_IntermediatePack" BeforeTargets="GenerateNuspec" >
|
||||||
|
<PropertyGroup>
|
||||||
|
<ContinuePackingAfterGeneratingNuspec>false</ContinuePackingAfterGeneratingNuspec>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="PaketOverrideNuspec" AfterTargets="GenerateNuspec" >
|
||||||
|
<PropertyGroup>
|
||||||
|
<PaketReferencesFilePath>$(MSBuildProjectDirectory)/obj/$(MSBuildProjectFile).references</PaketReferencesFilePath>
|
||||||
|
<ContinuePackingAfterGeneratingNuspec>true</ContinuePackingAfterGeneratingNuspec>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<_NuspecFiles Include="$(BaseIntermediateOutputPath)*.nuspec"/>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<Exec Command='$(PaketCommand) fix-nuspec file "@(_NuspecFiles)" references-file "$(PaketReferencesFilePath)" ' />
|
||||||
|
|
||||||
|
<ConvertToAbsolutePath Condition="@(_NuspecFiles) != ''" Paths="@(_NuspecFiles)">
|
||||||
|
<Output TaskParameter="AbsolutePaths" PropertyName="NuspecFileAbsolutePath" />
|
||||||
|
</ConvertToAbsolutePath>
|
||||||
|
|
||||||
|
<!-- Call Pack -->
|
||||||
|
<PackTask PackItem="$(PackProjectInputFile)"
|
||||||
|
PackageFiles="@(_PackageFiles)"
|
||||||
|
PackageFilesToExclude="@(_PackageFilesToExclude)"
|
||||||
|
PackageVersion="$(PackageVersion)"
|
||||||
|
PackageId="$(PackageId)"
|
||||||
|
Title="$(Title)"
|
||||||
|
Authors="$(Authors)"
|
||||||
|
Description="$(Description)"
|
||||||
|
Copyright="$(Copyright)"
|
||||||
|
RequireLicenseAcceptance="$(PackageRequireLicenseAcceptance)"
|
||||||
|
LicenseUrl="$(PackageLicenseUrl)"
|
||||||
|
ProjectUrl="$(PackageProjectUrl)"
|
||||||
|
IconUrl="$(PackageIconUrl)"
|
||||||
|
ReleaseNotes="$(PackageReleaseNotes)"
|
||||||
|
Tags="$(PackageTags)"
|
||||||
|
TargetPathsToAssemblies="@(_TargetPathsToAssemblies->'%(FinalOutputPath)')"
|
||||||
|
TargetPathsToSymbols="@(_TargetPathsToSymbols)"
|
||||||
|
TargetFrameworks="@(_TargetFrameworks)"
|
||||||
|
AssemblyName="$(AssemblyName)"
|
||||||
|
PackageOutputPath="$(PackageOutputAbsolutePath)"
|
||||||
|
IncludeSymbols="$(IncludeSymbols)"
|
||||||
|
IncludeSource="$(IncludeSource)"
|
||||||
|
PackageTypes="$(PackageType)"
|
||||||
|
IsTool="$(IsTool)"
|
||||||
|
RepositoryUrl="$(RepositoryUrl)"
|
||||||
|
RepositoryType="$(RepositoryType)"
|
||||||
|
SourceFiles="@(_SourceFiles->Distinct())"
|
||||||
|
NoPackageAnalysis="$(NoPackageAnalysis)"
|
||||||
|
MinClientVersion="$(MinClientVersion)"
|
||||||
|
Serviceable="$(Serviceable)"
|
||||||
|
AssemblyReferences="@(_References)"
|
||||||
|
ContinuePackingAfterGeneratingNuspec="$(ContinuePackingAfterGeneratingNuspec)"
|
||||||
|
NuspecOutputPath="$(BaseIntermediateOutputPath)"
|
||||||
|
IncludeBuildOutput="$(IncludeBuildOutput)"
|
||||||
|
BuildOutputFolder="$(BuildOutputTargetFolder)"
|
||||||
|
ContentTargetFolders="$(ContentTargetFolders)"
|
||||||
|
RestoreOutputPath="$(RestoreOutputAbsolutePath)"
|
||||||
|
NuspecFile="$(NuspecFileAbsolutePath)"
|
||||||
|
NuspecBasePath="$(NuspecBasePath)"
|
||||||
|
NuspecProperties="$(NuspecProperties)"/>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
</Project>
|
BIN
.paket/paket.bootstrapper.exe
Normal file
BIN
.paket/paket.bootstrapper.exe
Normal file
Binary file not shown.
5
build-au.bat
Normal file
5
build-au.bat
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
@echo off
|
||||||
|
cd .\src\app
|
||||||
|
au build
|
||||||
|
cd ..\..
|
||||||
|
exit %errorlevel%
|
8
build.bat
Normal file
8
build.bat
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
@echo off
|
||||||
|
cls
|
||||||
|
.paket\paket.exe restore
|
||||||
|
if errorlevel 1 (
|
||||||
|
exit /b %errorlevel%
|
||||||
|
)
|
||||||
|
"packages\FAKE\tools\Fake.exe" build.fsx %1
|
||||||
|
pause
|
69
build.fsx
Normal file
69
build.fsx
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
#r "packages/FAKE/tools/FakeLib.dll"
|
||||||
|
open Fake
|
||||||
|
open System
|
||||||
|
|
||||||
|
let buildDir = "./build/"
|
||||||
|
|
||||||
|
/// Path to the Aurelia app
|
||||||
|
let appPath = "src" @@ "app"
|
||||||
|
|
||||||
|
/// Path to the Suave API
|
||||||
|
let apiPath = "src" @@ "api"
|
||||||
|
|
||||||
|
// --- Targets ---
|
||||||
|
|
||||||
|
Target "Clean" (fun _ ->
|
||||||
|
CleanDir buildDir
|
||||||
|
)
|
||||||
|
|
||||||
|
Target "BuildApp" (fun _ ->
|
||||||
|
let result =
|
||||||
|
ExecProcessAndReturnMessages (fun info ->
|
||||||
|
info.UseShellExecute <- false
|
||||||
|
info.FileName <- "." @@ "build-au.bat") (TimeSpan.FromMinutes 2.)
|
||||||
|
match result.ExitCode with
|
||||||
|
| 0 -> Log "AppBuild-Output: " result.Messages
|
||||||
|
| _ -> failwith "Aurelia build failed"
|
||||||
|
)
|
||||||
|
|
||||||
|
Target "CopyApp" (fun _ ->
|
||||||
|
let apiWebPath = apiPath @@ "wwwroot"
|
||||||
|
[ "scripts" @@ "app-bundle.js"
|
||||||
|
"scripts" @@ "vendor-bundle.js"
|
||||||
|
"index.html"
|
||||||
|
]
|
||||||
|
|> List.iter (fun file ->
|
||||||
|
IO.File.Copy (appPath @@ file, apiWebPath @@ file, true)
|
||||||
|
Log "CopyApp--Output: " (Seq.singleton file))
|
||||||
|
)
|
||||||
|
|
||||||
|
Target "BuildApi" (fun _ ->
|
||||||
|
!! "src/api/*.fsproj"
|
||||||
|
|> MSBuildRelease buildDir "Build"
|
||||||
|
|> Log "ApiBuild-Output: "
|
||||||
|
)
|
||||||
|
|
||||||
|
Target "Run" (fun _ ->
|
||||||
|
ExecProcess (fun info ->
|
||||||
|
info.FileName <- "dotnet"
|
||||||
|
info.Arguments <- "myPrayerJournal.dll"
|
||||||
|
info.WorkingDirectory <- "build") TimeSpan.MaxValue
|
||||||
|
|> ignore
|
||||||
|
)
|
||||||
|
|
||||||
|
Target "Default" (fun _ ->
|
||||||
|
Log "" Seq.empty
|
||||||
|
)
|
||||||
|
|
||||||
|
// --- Dependencies ---
|
||||||
|
|
||||||
|
"Clean"
|
||||||
|
==> "BuildApp"
|
||||||
|
==> "CopyApp"
|
||||||
|
==> "BuildApi"
|
||||||
|
==> "Default"
|
||||||
|
|
||||||
|
"BuildApi"
|
||||||
|
==> "Run"
|
||||||
|
|
||||||
|
RunTargetOrDefault "Default"
|
11
paket.dependencies
Normal file
11
paket.dependencies
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
source https://api.nuget.org/v3/index.json
|
||||||
|
nuget Auth0.AuthenticationApi
|
||||||
|
nuget FAKE
|
||||||
|
nuget FSharp.Core
|
||||||
|
nuget FSharp.NET.Sdk
|
||||||
|
nuget jose-jwt
|
||||||
|
nuget Microsoft.EntityFrameworkCore.Tools
|
||||||
|
nuget Newtonsoft.Json
|
||||||
|
nuget Npgsql.EntityFrameworkCore.PostgreSQL
|
||||||
|
nuget Suave
|
||||||
|
nuget Suave.Experimental
|
1065
paket.lock
Normal file
1065
paket.lock
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -176,16 +176,20 @@ let viewJournal =
|
||||||
let reqs = Data.Requests.allForUser (defaultArg (read ctx "user") "") dataCtx
|
let reqs = Data.Requests.allForUser (defaultArg (read ctx "user") "") dataCtx
|
||||||
OK (Views.journal reqs |> html ctx))
|
OK (Views.journal reqs |> html ctx))
|
||||||
|
|
||||||
|
let idx =
|
||||||
|
context (fun ctx ->
|
||||||
|
Console.WriteLine "serving index"
|
||||||
|
succeed)
|
||||||
/// Suave application
|
/// Suave application
|
||||||
let app =
|
let app =
|
||||||
statefulForSession
|
statefulForSession
|
||||||
>=> Auth.loggedOn
|
>=> Auth.loggedOn
|
||||||
>=> choose [
|
>=> choose [
|
||||||
path Route.home >=> viewHome
|
path Route.home >=> Files.browseFileHome "index.html"
|
||||||
path Route.journal >=> viewJournal
|
path Route.journal >=> viewJournal
|
||||||
path Route.User.logOn >=> Auth.handleSignIn
|
path Route.User.logOn >=> Auth.handleSignIn
|
||||||
path Route.User.logOff >=> Auth.handleSignOut
|
path Route.User.logOff >=> Auth.handleSignOut
|
||||||
Files.browseHome
|
Writers.setHeader "Cache-Control" "no-cache" >=> Files.browseHome
|
||||||
NOT_FOUND "Page not found."
|
NOT_FOUND "Page not found."
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -203,12 +207,18 @@ let suaveCfg =
|
||||||
serverKey = Text.Encoding.UTF8.GetBytes("12345678901234567890123456789012")
|
serverKey = Text.Encoding.UTF8.GetBytes("12345678901234567890123456789012")
|
||||||
cookieSerialiser = JsonNetCookieSerializer ()
|
cookieSerialiser = JsonNetCookieSerializer ()
|
||||||
}
|
}
|
||||||
|
open Suave.Utils
|
||||||
|
|
||||||
[<EntryPoint>]
|
[<EntryPoint>]
|
||||||
let main argv =
|
let main argv =
|
||||||
// Establish the data environment
|
// Establish the data environment
|
||||||
//liftDep getConn (Data.establishEnvironment >> Async.RunSynchronously)
|
//liftDep getConn (Data.establishEnvironment >> Async.RunSynchronously)
|
||||||
//|> run deps
|
//|> run deps
|
||||||
|
let writeKey key = File.WriteAllText ("key.txt", key)
|
||||||
|
Crypto.generateKey Crypto.KeySize
|
||||||
|
|> Convert.ToBase64String
|
||||||
|
|> writeKey
|
||||||
|
|
||||||
ensureDatabase ()
|
ensureDatabase ()
|
||||||
startWebServer suaveCfg app
|
startWebServer suaveCfg app
|
||||||
0
|
0
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
<Project Sdk="FSharp.NET.Sdk;Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<VersionPrefix>0.8.1</VersionPrefix>
|
<VersionPrefix>0.8.1</VersionPrefix>
|
||||||
<TargetFramework>netcoreapp1.1</TargetFramework>
|
<TargetFramework>netcoreapp1.1</TargetFramework>
|
||||||
<DebugType>portable</DebugType>
|
|
||||||
<AssemblyName>myPrayerJournal</AssemblyName>
|
<AssemblyName>myPrayerJournal</AssemblyName>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<PackageId>src</PackageId>
|
<PackageId>MyPrayerJournal</PackageId>
|
||||||
<PackageTargetFallback>$(PackageTargetFallback);dnxcore50</PackageTargetFallback>
|
|
||||||
<RuntimeFrameworkVersion>1.1.1</RuntimeFrameworkVersion>
|
<RuntimeFrameworkVersion>1.1.1</RuntimeFrameworkVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
@ -24,27 +22,15 @@
|
||||||
<None Update="appsettings.json">
|
<None Update="appsettings.json">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
|
<None Update="wwwroot/**">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<Import Project="..\..\packages\FSharp.NET.Sdk\build\FSharp.NET.Core.Sdk.targets" />
|
||||||
<PackageReference Include="FSharp.NET.Sdk" Version="1.0.*" PrivateAssets="All" />
|
<Import Project="..\..\.paket\Paket.Restore.targets" />
|
||||||
<PackageReference Include="FSharp.Core" Version="4.1.*" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Auth0.AuthenticationApi" Version="3.6.0" />
|
|
||||||
<PackageReference Include="jose-jwt" Version="2.3.0" />
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="1.0.0">
|
|
||||||
<PrivateAssets>All</PrivateAssets>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
|
|
||||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="1.1.0" />
|
|
||||||
<PackageReference Include="Suave" Version="2.0.0" />
|
|
||||||
<PackageReference Include="Suave.Experimental" Version="2.0.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<DotNetCliToolReference Include="dotnet-compile-fsc" Version="1.0.0-preview2.1-*" />
|
|
||||||
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="1.0.0" />
|
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="1.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
6
src/api/paket.references
Normal file
6
src/api/paket.references
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
Auth0.AuthenticationApi
|
||||||
|
jose-jwt
|
||||||
|
Newtonsoft.Json
|
||||||
|
Npgsql.EntityFrameworkCore.PostgreSQL
|
||||||
|
Suave
|
||||||
|
Suave.Experimental
|
12
src/app/.editorconfig
Normal file
12
src/app/.editorconfig
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# EditorConfig is awesome: http://EditorConfig.org
|
||||||
|
|
||||||
|
# top-most EditorConfig file
|
||||||
|
root = true
|
||||||
|
|
||||||
|
# Unix-style newlines with a newline ending every file
|
||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
# 2 space indentation
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
159
src/app/aurelia_project/aurelia.json
Normal file
159
src/app/aurelia_project/aurelia.json
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
{
|
||||||
|
"name": "my-prayer-journal",
|
||||||
|
"type": "project:application",
|
||||||
|
"platform": {
|
||||||
|
"id": "web",
|
||||||
|
"displayName": "Web",
|
||||||
|
"output": "scripts",
|
||||||
|
"index": "index.html",
|
||||||
|
"baseDir": "."
|
||||||
|
},
|
||||||
|
"transpiler": {
|
||||||
|
"id": "typescript",
|
||||||
|
"displayName": "TypeScript",
|
||||||
|
"fileExtension": ".ts",
|
||||||
|
"dtsSource": [
|
||||||
|
"./custom_typings/**/*.d.ts"
|
||||||
|
],
|
||||||
|
"source": "src/**/*.ts"
|
||||||
|
},
|
||||||
|
"markupProcessor": {
|
||||||
|
"id": "minimum",
|
||||||
|
"displayName": "Minimal Minification",
|
||||||
|
"fileExtension": ".html",
|
||||||
|
"source": "src/**/*.html"
|
||||||
|
},
|
||||||
|
"cssProcessor": {
|
||||||
|
"id": "none",
|
||||||
|
"displayName": "None",
|
||||||
|
"fileExtension": ".css",
|
||||||
|
"source": "src/**/*.css"
|
||||||
|
},
|
||||||
|
"editor": {
|
||||||
|
"id": "vscode",
|
||||||
|
"displayName": "Visual Studio Code"
|
||||||
|
},
|
||||||
|
"unitTestRunner": {
|
||||||
|
"id": "karma",
|
||||||
|
"displayName": "Karma",
|
||||||
|
"source": "test/unit/**/*.ts"
|
||||||
|
},
|
||||||
|
"paths": {
|
||||||
|
"root": "src",
|
||||||
|
"resources": "resources",
|
||||||
|
"elements": "resources/elements",
|
||||||
|
"attributes": "resources/attributes",
|
||||||
|
"valueConverters": "resources/value-converters",
|
||||||
|
"bindingBehaviors": "resources/binding-behaviors"
|
||||||
|
},
|
||||||
|
"testFramework": {
|
||||||
|
"id": "jasmine",
|
||||||
|
"displayName": "Jasmine"
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"id": "web",
|
||||||
|
"displayName": "Web",
|
||||||
|
"output": "scripts",
|
||||||
|
"index": "index.html",
|
||||||
|
"baseDir": "."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"loader": {
|
||||||
|
"type": "require",
|
||||||
|
"configTarget": "vendor-bundle.js",
|
||||||
|
"includeBundleMetadataInConfig": "auto",
|
||||||
|
"plugins": [
|
||||||
|
{
|
||||||
|
"name": "text",
|
||||||
|
"extensions": [
|
||||||
|
".html",
|
||||||
|
".css"
|
||||||
|
],
|
||||||
|
"stub": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"minify": "stage & prod",
|
||||||
|
"sourcemaps": "dev & stage"
|
||||||
|
},
|
||||||
|
"bundles": [
|
||||||
|
{
|
||||||
|
"name": "app-bundle.js",
|
||||||
|
"source": [
|
||||||
|
"[**/*.js]",
|
||||||
|
"**/*.{css,html}"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vendor-bundle.js",
|
||||||
|
"prepend": [
|
||||||
|
"node_modules/bluebird/js/browser/bluebird.core.js",
|
||||||
|
"node_modules/aurelia-cli/lib/resources/scripts/configure-bluebird.js",
|
||||||
|
"node_modules/requirejs/require.js"
|
||||||
|
],
|
||||||
|
"dependencies": [
|
||||||
|
"aurelia-binding",
|
||||||
|
"aurelia-bootstrapper",
|
||||||
|
"aurelia-dependency-injection",
|
||||||
|
"aurelia-event-aggregator",
|
||||||
|
"aurelia-framework",
|
||||||
|
"aurelia-history",
|
||||||
|
"aurelia-history-browser",
|
||||||
|
"aurelia-loader",
|
||||||
|
"aurelia-loader-default",
|
||||||
|
"aurelia-logging",
|
||||||
|
"aurelia-logging-console",
|
||||||
|
"aurelia-metadata",
|
||||||
|
"aurelia-pal",
|
||||||
|
"aurelia-pal-browser",
|
||||||
|
"aurelia-path",
|
||||||
|
"aurelia-polyfills",
|
||||||
|
"aurelia-route-recognizer",
|
||||||
|
"aurelia-router",
|
||||||
|
"aurelia-task-queue",
|
||||||
|
"aurelia-templating",
|
||||||
|
"aurelia-templating-binding",
|
||||||
|
"text",
|
||||||
|
{
|
||||||
|
"name": "aurelia-templating-resources",
|
||||||
|
"path": "../node_modules/aurelia-templating-resources/dist/amd",
|
||||||
|
"main": "aurelia-templating-resources"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "aurelia-templating-router",
|
||||||
|
"path": "../node_modules/aurelia-templating-router/dist/amd",
|
||||||
|
"main": "aurelia-templating-router"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "aurelia-testing",
|
||||||
|
"path": "../node_modules/aurelia-testing/dist/amd",
|
||||||
|
"main": "aurelia-testing",
|
||||||
|
"env": "dev"
|
||||||
|
},
|
||||||
|
"jquery",
|
||||||
|
{
|
||||||
|
"name": "bootstrap",
|
||||||
|
"path": "../node_modules/bootstrap/dist",
|
||||||
|
"main": "js/bootstrap.min",
|
||||||
|
"deps": ["jquery"],
|
||||||
|
"exports": "$",
|
||||||
|
"resources": [
|
||||||
|
"css/bootstrap.css"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "nprogress",
|
||||||
|
"path": "../node_modules/nprogress",
|
||||||
|
"main": "nprogress",
|
||||||
|
"resources": [
|
||||||
|
"nprogress.css"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
4
src/app/aurelia_project/environments/dev.ts
Normal file
4
src/app/aurelia_project/environments/dev.ts
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
export default {
|
||||||
|
debug: true,
|
||||||
|
testing: true
|
||||||
|
};
|
4
src/app/aurelia_project/environments/prod.ts
Normal file
4
src/app/aurelia_project/environments/prod.ts
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
export default {
|
||||||
|
debug: false,
|
||||||
|
testing: false
|
||||||
|
};
|
4
src/app/aurelia_project/environments/stage.ts
Normal file
4
src/app/aurelia_project/environments/stage.ts
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
export default {
|
||||||
|
debug: true,
|
||||||
|
testing: false
|
||||||
|
};
|
4
src/app/aurelia_project/generators/attribute.json
Normal file
4
src/app/aurelia_project/generators/attribute.json
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"name": "attribute",
|
||||||
|
"description": "Creates a custom attribute class and places it in the project resources."
|
||||||
|
}
|
38
src/app/aurelia_project/generators/attribute.ts
Normal file
38
src/app/aurelia_project/generators/attribute.ts
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
import {inject} from 'aurelia-dependency-injection';
|
||||||
|
import {Project, ProjectItem, CLIOptions, UI} from 'aurelia-cli';
|
||||||
|
|
||||||
|
@inject(Project, CLIOptions, UI)
|
||||||
|
export default class AttributeGenerator {
|
||||||
|
constructor(private project: Project, private options: CLIOptions, private ui: UI) { }
|
||||||
|
|
||||||
|
execute() {
|
||||||
|
return this.ui
|
||||||
|
.ensureAnswer(this.options.args[0], 'What would you like to call the custom attribute?')
|
||||||
|
.then(name => {
|
||||||
|
let fileName = this.project.makeFileName(name);
|
||||||
|
let className = this.project.makeClassName(name);
|
||||||
|
|
||||||
|
this.project.attributes.add(
|
||||||
|
ProjectItem.text(`${fileName}.ts`, this.generateSource(className))
|
||||||
|
);
|
||||||
|
|
||||||
|
return this.project.commitChanges()
|
||||||
|
.then(() => this.ui.log(`Created ${fileName}.`));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
generateSource(className) {
|
||||||
|
return `import {autoinject} from 'aurelia-framework';
|
||||||
|
|
||||||
|
@autoinject()
|
||||||
|
export class ${className}CustomAttribute {
|
||||||
|
constructor(private element: Element) { }
|
||||||
|
|
||||||
|
valueChanged(newValue, oldValue) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
`
|
||||||
|
}
|
||||||
|
}
|
4
src/app/aurelia_project/generators/binding-behavior.json
Normal file
4
src/app/aurelia_project/generators/binding-behavior.json
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"name": "binding-behavior",
|
||||||
|
"description": "Creates a binding behavior class and places it in the project resources."
|
||||||
|
}
|
37
src/app/aurelia_project/generators/binding-behavior.ts
Normal file
37
src/app/aurelia_project/generators/binding-behavior.ts
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import {inject} from 'aurelia-dependency-injection';
|
||||||
|
import {Project, ProjectItem, CLIOptions, UI} from 'aurelia-cli';
|
||||||
|
|
||||||
|
@inject(Project, CLIOptions, UI)
|
||||||
|
export default class BindingBehaviorGenerator {
|
||||||
|
constructor(private project: Project, private options: CLIOptions, private ui: UI) { }
|
||||||
|
|
||||||
|
execute() {
|
||||||
|
return this.ui
|
||||||
|
.ensureAnswer(this.options.args[0], 'What would you like to call the binding behavior?')
|
||||||
|
.then(name => {
|
||||||
|
let fileName = this.project.makeFileName(name);
|
||||||
|
let className = this.project.makeClassName(name);
|
||||||
|
|
||||||
|
this.project.bindingBehaviors.add(
|
||||||
|
ProjectItem.text(`${fileName}.ts`, this.generateSource(className))
|
||||||
|
);
|
||||||
|
|
||||||
|
return this.project.commitChanges()
|
||||||
|
.then(() => this.ui.log(`Created ${fileName}.`));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
generateSource(className) {
|
||||||
|
return `export class ${className}BindingBehavior {
|
||||||
|
bind(binding, source) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
unbind(binding, source) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
`
|
||||||
|
}
|
||||||
|
}
|
4
src/app/aurelia_project/generators/component.json
Normal file
4
src/app/aurelia_project/generators/component.json
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"name": "component",
|
||||||
|
"description": "Creates a custom component class and template (view model and view), placing them in the project source folder (or optionally in sub folders)."
|
||||||
|
}
|
49
src/app/aurelia_project/generators/component.ts
Normal file
49
src/app/aurelia_project/generators/component.ts
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
import { inject } from 'aurelia-dependency-injection';
|
||||||
|
import { Project, ProjectItem, CLIOptions, UI } from 'aurelia-cli';
|
||||||
|
|
||||||
|
var path = require('path');
|
||||||
|
|
||||||
|
@inject(Project, CLIOptions, UI)
|
||||||
|
export default class ElementGenerator {
|
||||||
|
constructor(private project: Project, private options: CLIOptions, private ui: UI) { }
|
||||||
|
|
||||||
|
execute() {
|
||||||
|
let self = this;
|
||||||
|
|
||||||
|
return this.ui
|
||||||
|
.ensureAnswer(this.options.args[0], 'What would you like to call the component?')
|
||||||
|
.then(name => {
|
||||||
|
|
||||||
|
return self.ui.ensureAnswer(this.options.args[1], 'What sub-folder would you like to add it to?\nIf it doesn\'t exist it will be created for you.\n\nDefault folder is the source folder (src).', ".")
|
||||||
|
.then(subFolders => {
|
||||||
|
|
||||||
|
let fileName = this.project.makeFileName(name);
|
||||||
|
let className = this.project.makeClassName(name);
|
||||||
|
|
||||||
|
self.project.root.add(
|
||||||
|
ProjectItem.text(path.join(subFolders, fileName + ".ts"), this.generateJSSource(className)),
|
||||||
|
ProjectItem.text(path.join(subFolders, fileName + ".html"), this.generateHTMLSource(className))
|
||||||
|
);
|
||||||
|
|
||||||
|
return this.project.commitChanges()
|
||||||
|
.then(() => this.ui.log(`Created ${name} in the '${path.join(self.project.root.name, subFolders)}' folder`));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
generateJSSource(className) {
|
||||||
|
return `export class ${className} {
|
||||||
|
message: string;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.message = 'Hello world';
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
}
|
||||||
|
|
||||||
|
generateHTMLSource(className) {
|
||||||
|
return `<template>
|
||||||
|
<h1>\${message}</h1>
|
||||||
|
</template>`
|
||||||
|
}
|
||||||
|
}
|
4
src/app/aurelia_project/generators/element.json
Normal file
4
src/app/aurelia_project/generators/element.json
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"name": "element",
|
||||||
|
"description": "Creates a custom element class and template, placing them in the project resources."
|
||||||
|
}
|
44
src/app/aurelia_project/generators/element.ts
Normal file
44
src/app/aurelia_project/generators/element.ts
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
import {inject} from 'aurelia-dependency-injection';
|
||||||
|
import {Project, ProjectItem, CLIOptions, UI} from 'aurelia-cli';
|
||||||
|
|
||||||
|
@inject(Project, CLIOptions, UI)
|
||||||
|
export default class ElementGenerator {
|
||||||
|
constructor(private project: Project, private options: CLIOptions, private ui: UI) { }
|
||||||
|
|
||||||
|
execute() {
|
||||||
|
return this.ui
|
||||||
|
.ensureAnswer(this.options.args[0], 'What would you like to call the custom element?')
|
||||||
|
.then(name => {
|
||||||
|
let fileName = this.project.makeFileName(name);
|
||||||
|
let className = this.project.makeClassName(name);
|
||||||
|
|
||||||
|
this.project.elements.add(
|
||||||
|
ProjectItem.text(`${fileName}.ts`, this.generateJSSource(className)),
|
||||||
|
ProjectItem.text(`${fileName}.html`, this.generateHTMLSource(className))
|
||||||
|
);
|
||||||
|
|
||||||
|
return this.project.commitChanges()
|
||||||
|
.then(() => this.ui.log(`Created ${fileName}.`));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
generateJSSource(className) {
|
||||||
|
return `import {bindable} from 'aurelia-framework';
|
||||||
|
|
||||||
|
export class ${className} {
|
||||||
|
@bindable value;
|
||||||
|
|
||||||
|
valueChanged(newValue, oldValue) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
generateHTMLSource(className) {
|
||||||
|
return `<template>
|
||||||
|
<h1>\${value}</h1>
|
||||||
|
</template>`
|
||||||
|
}
|
||||||
|
}
|
4
src/app/aurelia_project/generators/generator.json
Normal file
4
src/app/aurelia_project/generators/generator.json
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"name": "generator",
|
||||||
|
"description": "Creates a generator class and places it in the project generators folder."
|
||||||
|
}
|
65
src/app/aurelia_project/generators/generator.ts
Normal file
65
src/app/aurelia_project/generators/generator.ts
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
import {inject} from 'aurelia-dependency-injection';
|
||||||
|
import {Project, ProjectItem, CLIOptions, UI} from 'aurelia-cli';
|
||||||
|
|
||||||
|
@inject(Project, CLIOptions, UI)
|
||||||
|
export default class GeneratorGenerator {
|
||||||
|
constructor(private project: Project, private options: CLIOptions, private ui: UI) { }
|
||||||
|
|
||||||
|
execute() {
|
||||||
|
return this.ui
|
||||||
|
.ensureAnswer(this.options.args[0], 'What would you like to call the generator?')
|
||||||
|
.then(name => {
|
||||||
|
let fileName = this.project.makeFileName(name);
|
||||||
|
let className = this.project.makeClassName(name);
|
||||||
|
|
||||||
|
this.project.generators.add(
|
||||||
|
ProjectItem.text(`${fileName}.ts`, this.generateSource(className))
|
||||||
|
);
|
||||||
|
|
||||||
|
return this.project.commitChanges()
|
||||||
|
.then(() => this.ui.log(`Created ${fileName}.`));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
generateSource(className) {
|
||||||
|
return `import {autoinject} from 'aurelia-dependency-injection';
|
||||||
|
import {Project, ProjectItem, CLIOptions, UI} from 'aurelia-cli';
|
||||||
|
|
||||||
|
@autoinject()
|
||||||
|
export default class ${className}Generator {
|
||||||
|
constructor(private project: Project, private options: CLIOptions, private ui: UI) { }
|
||||||
|
|
||||||
|
execute() {
|
||||||
|
return this.ui
|
||||||
|
.ensureAnswer(this.options.args[0], 'What would you like to call the new item?')
|
||||||
|
.then(name => {
|
||||||
|
let fileName = this.project.makeFileName(name);
|
||||||
|
let className = this.project.makeClassName(name);
|
||||||
|
|
||||||
|
this.project.elements.add(
|
||||||
|
ProjectItem.text(\`\${fileName}.js\`, this.generateSource(className))
|
||||||
|
);
|
||||||
|
|
||||||
|
return this.project.commitChanges()
|
||||||
|
.then(() => this.ui.log(\`Created \${fileName}.\`));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
generateSource(className) {
|
||||||
|
return \`import {bindable} from 'aurelia-framework';
|
||||||
|
|
||||||
|
export class \${className} {
|
||||||
|
@bindable value;
|
||||||
|
|
||||||
|
valueChanged(newValue, oldValue) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
\`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
`
|
||||||
|
}
|
||||||
|
}
|
4
src/app/aurelia_project/generators/task.json
Normal file
4
src/app/aurelia_project/generators/task.json
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"name": "task",
|
||||||
|
"description": "Creates a task and places it in the project tasks folder."
|
||||||
|
}
|
37
src/app/aurelia_project/generators/task.ts
Normal file
37
src/app/aurelia_project/generators/task.ts
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import {inject} from 'aurelia-dependency-injection';
|
||||||
|
import {Project, ProjectItem, CLIOptions, UI} from 'aurelia-cli';
|
||||||
|
|
||||||
|
@inject(Project, CLIOptions, UI)
|
||||||
|
export default class TaskGenerator {
|
||||||
|
constructor(private project: Project, private options: CLIOptions, private ui: UI) { }
|
||||||
|
|
||||||
|
execute() {
|
||||||
|
return this.ui
|
||||||
|
.ensureAnswer(this.options.args[0], 'What would you like to call the task?')
|
||||||
|
.then(name => {
|
||||||
|
let fileName = this.project.makeFileName(name);
|
||||||
|
let functionName = this.project.makeFunctionName(name);
|
||||||
|
|
||||||
|
this.project.tasks.add(
|
||||||
|
ProjectItem.text(`${fileName}.ts`, this.generateSource(functionName))
|
||||||
|
);
|
||||||
|
|
||||||
|
return this.project.commitChanges()
|
||||||
|
.then(() => this.ui.log(`Created ${fileName}.`));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
generateSource(functionName) {
|
||||||
|
return `import * as gulp from 'gulp';
|
||||||
|
import * as changed from 'gulp-changed';
|
||||||
|
import * as project from '../aurelia.json';
|
||||||
|
|
||||||
|
export default function ${functionName}() {
|
||||||
|
return gulp.src(project.paths.???)
|
||||||
|
.pipe(changed(project.paths.output, {extension: '.???'}))
|
||||||
|
.pipe(gulp.dest(project.paths.output));
|
||||||
|
}
|
||||||
|
|
||||||
|
`
|
||||||
|
}
|
||||||
|
}
|
4
src/app/aurelia_project/generators/value-converter.json
Normal file
4
src/app/aurelia_project/generators/value-converter.json
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"name": "value-converter",
|
||||||
|
"description": "Creates a value converter class and places it in the project resources."
|
||||||
|
}
|
37
src/app/aurelia_project/generators/value-converter.ts
Normal file
37
src/app/aurelia_project/generators/value-converter.ts
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import {inject} from 'aurelia-dependency-injection';
|
||||||
|
import {Project, ProjectItem, CLIOptions, UI} from 'aurelia-cli';
|
||||||
|
|
||||||
|
@inject(Project, CLIOptions, UI)
|
||||||
|
export default class ValueConverterGenerator {
|
||||||
|
constructor(private project: Project, private options: CLIOptions, private ui: UI) { }
|
||||||
|
|
||||||
|
execute() {
|
||||||
|
return this.ui
|
||||||
|
.ensureAnswer(this.options.args[0], 'What would you like to call the value converter?')
|
||||||
|
.then(name => {
|
||||||
|
let fileName = this.project.makeFileName(name);
|
||||||
|
let className = this.project.makeClassName(name);
|
||||||
|
|
||||||
|
this.project.valueConverters.add(
|
||||||
|
ProjectItem.text(`${fileName}.ts`, this.generateSource(className))
|
||||||
|
);
|
||||||
|
|
||||||
|
return this.project.commitChanges()
|
||||||
|
.then(() => this.ui.log(`Created ${fileName}.`));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
generateSource(className) {
|
||||||
|
return `export class ${className}ValueConverter {
|
||||||
|
toView(value) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fromView(value) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
`
|
||||||
|
}
|
||||||
|
}
|
11
src/app/aurelia_project/tasks/build.json
Normal file
11
src/app/aurelia_project/tasks/build.json
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"name": "build",
|
||||||
|
"description": "Builds and processes all application assets.",
|
||||||
|
"flags": [
|
||||||
|
{
|
||||||
|
"name": "env",
|
||||||
|
"description": "Sets the build environment.",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
26
src/app/aurelia_project/tasks/build.ts
Normal file
26
src/app/aurelia_project/tasks/build.ts
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import * as gulp from 'gulp';
|
||||||
|
import transpile from './transpile';
|
||||||
|
import processMarkup from './process-markup';
|
||||||
|
import processCSS from './process-css';
|
||||||
|
import copyFiles from './copy-files';
|
||||||
|
import {build} from 'aurelia-cli';
|
||||||
|
import * as project from '../aurelia.json';
|
||||||
|
|
||||||
|
export default gulp.series(
|
||||||
|
readProjectConfiguration,
|
||||||
|
gulp.parallel(
|
||||||
|
transpile,
|
||||||
|
processMarkup,
|
||||||
|
processCSS,
|
||||||
|
copyFiles
|
||||||
|
),
|
||||||
|
writeBundles
|
||||||
|
);
|
||||||
|
|
||||||
|
function readProjectConfiguration() {
|
||||||
|
return build.src(project);
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeBundles() {
|
||||||
|
return build.dest();
|
||||||
|
}
|
45
src/app/aurelia_project/tasks/copy-files.ts
Normal file
45
src/app/aurelia_project/tasks/copy-files.ts
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
import * as gulp from 'gulp';
|
||||||
|
import * as path from 'path';
|
||||||
|
import * as minimatch from 'minimatch';
|
||||||
|
import * as changedInPlace from 'gulp-changed-in-place';
|
||||||
|
import * as project from '../aurelia.json';
|
||||||
|
|
||||||
|
export default function copyFiles(done) {
|
||||||
|
if (typeof project.build.copyFiles !== 'object') {
|
||||||
|
done();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const instruction = getNormalizedInstruction();
|
||||||
|
const files = Object.keys(instruction);
|
||||||
|
|
||||||
|
return gulp.src(files)
|
||||||
|
.pipe(changedInPlace({ firstPass: true }))
|
||||||
|
.pipe(gulp.dest(x => {
|
||||||
|
const filePath = prepareFilePath(x.path);
|
||||||
|
const key = files.find(f => minimatch(filePath, f));
|
||||||
|
return instruction[key];
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNormalizedInstruction() {
|
||||||
|
const files = project.build.copyFiles;
|
||||||
|
let normalizedInstruction = {};
|
||||||
|
|
||||||
|
for (let key in files) {
|
||||||
|
normalizedInstruction[path.posix.normalize(key)] = files[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
return normalizedInstruction;
|
||||||
|
}
|
||||||
|
|
||||||
|
function prepareFilePath(filePath) {
|
||||||
|
let preparedPath = filePath.replace(process.cwd(), '').substring(1);
|
||||||
|
|
||||||
|
//if we are running on windows we have to fix the path
|
||||||
|
if (/^win/.test(process.platform)) {
|
||||||
|
preparedPath = preparedPath.replace(/\\/g, '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
return preparedPath;
|
||||||
|
}
|
10
src/app/aurelia_project/tasks/process-css.ts
Normal file
10
src/app/aurelia_project/tasks/process-css.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import * as gulp from 'gulp';
|
||||||
|
import * as changedInPlace from 'gulp-changed-in-place';
|
||||||
|
import * as project from '../aurelia.json';
|
||||||
|
import {build} from 'aurelia-cli';
|
||||||
|
|
||||||
|
export default function processCSS() {
|
||||||
|
return gulp.src(project.cssProcessor.source)
|
||||||
|
.pipe(changedInPlace({firstPass:true}))
|
||||||
|
.pipe(build.bundle());
|
||||||
|
};
|
17
src/app/aurelia_project/tasks/process-markup.ts
Normal file
17
src/app/aurelia_project/tasks/process-markup.ts
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import * as gulp from 'gulp';
|
||||||
|
import * as htmlmin from 'gulp-htmlmin';
|
||||||
|
import * as changedInPlace from 'gulp-changed-in-place';
|
||||||
|
import * as project from '../aurelia.json';
|
||||||
|
import {build} from 'aurelia-cli';
|
||||||
|
|
||||||
|
export default function processMarkup() {
|
||||||
|
return gulp.src(project.markupProcessor.source)
|
||||||
|
.pipe(changedInPlace({firstPass:true}))
|
||||||
|
.pipe(htmlmin({
|
||||||
|
removeComments: true,
|
||||||
|
collapseWhitespace: true,
|
||||||
|
minifyCSS: true,
|
||||||
|
minifyJS: true
|
||||||
|
}))
|
||||||
|
.pipe(build.bundle());
|
||||||
|
}
|
16
src/app/aurelia_project/tasks/run.json
Normal file
16
src/app/aurelia_project/tasks/run.json
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"name": "run",
|
||||||
|
"description": "Builds the application and serves up the assets via a local web server, watching files for changes as you work.",
|
||||||
|
"flags": [
|
||||||
|
{
|
||||||
|
"name": "env",
|
||||||
|
"description": "Sets the build environment.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "watch",
|
||||||
|
"description": "Watches source files for changes and refreshes the app automatically.",
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
73
src/app/aurelia_project/tasks/run.ts
Normal file
73
src/app/aurelia_project/tasks/run.ts
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
import * as gulp from 'gulp';
|
||||||
|
import * as browserSync from 'browser-sync';
|
||||||
|
import * as historyApiFallback from 'connect-history-api-fallback/lib';
|
||||||
|
import * as project from '../aurelia.json';
|
||||||
|
import build from './build';
|
||||||
|
import {CLIOptions} from 'aurelia-cli';
|
||||||
|
|
||||||
|
function onChange(path) {
|
||||||
|
console.log(`File Changed: ${path}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function reload(done) {
|
||||||
|
browserSync.reload();
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
|
||||||
|
let serve = gulp.series(
|
||||||
|
build,
|
||||||
|
done => {
|
||||||
|
browserSync({
|
||||||
|
online: false,
|
||||||
|
open: false,
|
||||||
|
port: 9000,
|
||||||
|
logLevel: 'silent',
|
||||||
|
server: {
|
||||||
|
baseDir: [project.platform.baseDir],
|
||||||
|
middleware: [historyApiFallback(), function(req, res, next) {
|
||||||
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||||
|
next();
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}, function (err, bs) {
|
||||||
|
if (err) return done(err);
|
||||||
|
let urls = bs.options.get('urls').toJS();
|
||||||
|
console.log(`Application Available At: ${urls.local}`);
|
||||||
|
console.log(`BrowserSync Available At: ${urls.ui}`);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
let refresh = gulp.series(
|
||||||
|
build,
|
||||||
|
reload
|
||||||
|
);
|
||||||
|
|
||||||
|
let watch = function(refreshCb, onChangeCb) {
|
||||||
|
return function(done) {
|
||||||
|
gulp.watch(project.transpiler.source, refreshCb).on('change', onChangeCb);
|
||||||
|
gulp.watch(project.markupProcessor.source, refreshCb).on('change', onChangeCb);
|
||||||
|
gulp.watch(project.cssProcessor.source, refreshCb).on('change', onChangeCb);
|
||||||
|
|
||||||
|
//see if there are static files to be watched
|
||||||
|
if (typeof project.build.copyFiles === 'object') {
|
||||||
|
const files = Object.keys(project.build.copyFiles);
|
||||||
|
gulp.watch(files, refreshCb).on('change', onChangeCb);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
let run;
|
||||||
|
|
||||||
|
if (CLIOptions.hasFlag('watch')) {
|
||||||
|
run = gulp.series(
|
||||||
|
serve,
|
||||||
|
watch(refresh, onChange)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
run = serve;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { run as default, watch };
|
||||||
|
|
16
src/app/aurelia_project/tasks/test.json
Normal file
16
src/app/aurelia_project/tasks/test.json
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"name": "test",
|
||||||
|
"description": "Runs all unit tests and reports the results.",
|
||||||
|
"flags": [
|
||||||
|
{
|
||||||
|
"name": "env",
|
||||||
|
"description": "Sets the build environment.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "watch",
|
||||||
|
"description": "Watches test files for changes and re-runs the tests automatically.",
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
40
src/app/aurelia_project/tasks/test.ts
Normal file
40
src/app/aurelia_project/tasks/test.ts
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
import * as gulp from 'gulp';
|
||||||
|
import {Server as Karma} from 'karma';
|
||||||
|
import {CLIOptions} from 'aurelia-cli';
|
||||||
|
import build from './build';
|
||||||
|
import {watch} from './run';
|
||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
|
function log(message) {
|
||||||
|
console.log(message); //eslint-disable-line no-console
|
||||||
|
}
|
||||||
|
|
||||||
|
function onChange(path) {
|
||||||
|
log(`File Changed: ${path}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let karma = done => {
|
||||||
|
new Karma({
|
||||||
|
configFile: path.join(__dirname, '/../../karma.conf.js'),
|
||||||
|
singleRun: !CLIOptions.hasFlag('watch')
|
||||||
|
}, done).start();
|
||||||
|
};
|
||||||
|
|
||||||
|
let unit;
|
||||||
|
|
||||||
|
if (CLIOptions.hasFlag('watch')) {
|
||||||
|
unit = gulp.series(
|
||||||
|
build,
|
||||||
|
gulp.parallel(
|
||||||
|
watch(build, onChange),
|
||||||
|
karma
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
unit = gulp.series(
|
||||||
|
build,
|
||||||
|
karma
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default unit;
|
44
src/app/aurelia_project/tasks/transpile.ts
Normal file
44
src/app/aurelia_project/tasks/transpile.ts
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
import * as gulp from 'gulp';
|
||||||
|
import * as changedInPlace from 'gulp-changed-in-place';
|
||||||
|
import * as plumber from 'gulp-plumber';
|
||||||
|
import * as sourcemaps from 'gulp-sourcemaps';
|
||||||
|
import * as notify from 'gulp-notify';
|
||||||
|
import * as rename from 'gulp-rename';
|
||||||
|
import * as ts from 'gulp-typescript';
|
||||||
|
import * as project from '../aurelia.json';
|
||||||
|
import {CLIOptions, build} from 'aurelia-cli';
|
||||||
|
import * as eventStream from 'event-stream';
|
||||||
|
|
||||||
|
function configureEnvironment() {
|
||||||
|
let env = CLIOptions.getEnvironment();
|
||||||
|
|
||||||
|
return gulp.src(`aurelia_project/environments/${env}.ts`)
|
||||||
|
.pipe(changedInPlace({firstPass:true}))
|
||||||
|
.pipe(rename('environment.ts'))
|
||||||
|
.pipe(gulp.dest(project.paths.root));
|
||||||
|
}
|
||||||
|
|
||||||
|
var typescriptCompiler = typescriptCompiler || null;
|
||||||
|
|
||||||
|
function buildTypeScript() {
|
||||||
|
typescriptCompiler = ts.createProject('tsconfig.json', {
|
||||||
|
"typescript": require('typescript')
|
||||||
|
});
|
||||||
|
|
||||||
|
let dts = gulp.src(project.transpiler.dtsSource);
|
||||||
|
|
||||||
|
let src = gulp.src(project.transpiler.source)
|
||||||
|
.pipe(changedInPlace({firstPass: true}));
|
||||||
|
|
||||||
|
return eventStream.merge(dts, src)
|
||||||
|
.pipe(plumber({ errorHandler: notify.onError('Error: <%= error.message %>') }))
|
||||||
|
.pipe(sourcemaps.init())
|
||||||
|
.pipe(typescriptCompiler())
|
||||||
|
.pipe(sourcemaps.write({ sourceRoot: 'src' }))
|
||||||
|
.pipe(build.bundle());
|
||||||
|
}
|
||||||
|
|
||||||
|
export default gulp.series(
|
||||||
|
configureEnvironment,
|
||||||
|
buildTypeScript
|
||||||
|
);
|
BIN
src/app/favicon.ico
Normal file
BIN
src/app/favicon.ico
Normal file
Binary file not shown.
13
src/app/index.html
Normal file
13
src/app/index.html
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Aurelia</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<base href="/">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body aurelia-app="main">
|
||||||
|
<script src="scripts/vendor-bundle.js" data-main="aurelia-bootstrapper"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
44
src/app/karma.conf.js
Normal file
44
src/app/karma.conf.js
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
'use strict';
|
||||||
|
const path = require('path');
|
||||||
|
const project = require('./aurelia_project/aurelia.json');
|
||||||
|
const tsconfig = require('./tsconfig.json');
|
||||||
|
|
||||||
|
let testSrc = [
|
||||||
|
{ pattern: project.unitTestRunner.source, included: false },
|
||||||
|
'test/aurelia-karma.js'
|
||||||
|
];
|
||||||
|
|
||||||
|
let output = project.platform.output;
|
||||||
|
let appSrc = project.build.bundles.map(x => path.join(output, x.name));
|
||||||
|
let entryIndex = appSrc.indexOf(path.join(output, project.build.loader.configTarget));
|
||||||
|
let entryBundle = appSrc.splice(entryIndex, 1)[0];
|
||||||
|
let files = [entryBundle].concat(testSrc).concat(appSrc);
|
||||||
|
|
||||||
|
module.exports = function(config) {
|
||||||
|
config.set({
|
||||||
|
basePath: '',
|
||||||
|
frameworks: [project.testFramework.id],
|
||||||
|
files: files,
|
||||||
|
exclude: [],
|
||||||
|
preprocessors: {
|
||||||
|
[project.unitTestRunner.source]: [project.transpiler.id]
|
||||||
|
},
|
||||||
|
typescriptPreprocessor: {
|
||||||
|
typescript: require('typescript'),
|
||||||
|
options: tsconfig.compilerOptions
|
||||||
|
},
|
||||||
|
reporters: ['progress'],
|
||||||
|
port: 9876,
|
||||||
|
colors: true,
|
||||||
|
logLevel: config.LOG_INFO,
|
||||||
|
autoWatch: true,
|
||||||
|
browsers: ['Chrome'],
|
||||||
|
singleRun: false,
|
||||||
|
// client.args must be a array of string.
|
||||||
|
// Leave 'aurelia-root', project.paths.root in this order so we can find
|
||||||
|
// the root of the aurelia project.
|
||||||
|
client: {
|
||||||
|
args: ['aurelia-root', project.paths.root]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
52
src/app/package.json
Normal file
52
src/app/package.json
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
{
|
||||||
|
"name": "contact-manager",
|
||||||
|
"description": "An Aurelia client application.",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"repository": {
|
||||||
|
"type": "???",
|
||||||
|
"url": "???"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"aurelia-animator-css": "^1.0.1",
|
||||||
|
"aurelia-bootstrapper": "^2.1.0",
|
||||||
|
"bluebird": "^3.4.1",
|
||||||
|
"bootstrap": "^3.3.7",
|
||||||
|
"jquery": "^2.2.4",
|
||||||
|
"nprogress": "^0.2.0",
|
||||||
|
"requirejs": "^2.3.2",
|
||||||
|
"text": "github:requirejs/text#latest"
|
||||||
|
},
|
||||||
|
"peerDependencies": {},
|
||||||
|
"devDependencies": {
|
||||||
|
"aurelia-cli": "^0.27.0",
|
||||||
|
"aurelia-testing": "^1.0.0-beta.2.0.1",
|
||||||
|
"aurelia-tools": "^1.0.0",
|
||||||
|
"browser-sync": "^2.13.0",
|
||||||
|
"connect-history-api-fallback": "^1.2.0",
|
||||||
|
"gulp": "github:gulpjs/gulp#4.0",
|
||||||
|
"gulp-changed-in-place": "^2.0.3",
|
||||||
|
"gulp-plumber": "^1.1.0",
|
||||||
|
"gulp-rename": "^1.2.2",
|
||||||
|
"gulp-sourcemaps": "^2.0.0-alpha",
|
||||||
|
"gulp-notify": "^2.2.0",
|
||||||
|
"minimatch": "^3.0.2",
|
||||||
|
"through2": "^2.0.1",
|
||||||
|
"uglify-js": "^2.6.3",
|
||||||
|
"vinyl-fs": "^2.4.3",
|
||||||
|
"event-stream": "^3.3.3",
|
||||||
|
"gulp-typescript": "^3.1.4",
|
||||||
|
"gulp-tslint": "^5.0.0",
|
||||||
|
"tslint": "^3.11.0",
|
||||||
|
"typescript": ">=1.9.0-dev || ^2.0.0",
|
||||||
|
"@types/node": "^6.0.45",
|
||||||
|
"gulp-htmlmin": "^3.0.0",
|
||||||
|
"html-minifier": "^3.2.3",
|
||||||
|
"jasmine-core": "^2.4.1",
|
||||||
|
"karma": "^0.13.22",
|
||||||
|
"karma-chrome-launcher": "^1.0.1",
|
||||||
|
"karma-jasmine": "^1.0.2",
|
||||||
|
"karma-typescript-preprocessor": "^0.2.1",
|
||||||
|
"@types/jasmine": "^2.2.0"
|
||||||
|
}
|
||||||
|
}
|
34
src/app/src/app.html
Normal file
34
src/app/src/app.html
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<template>
|
||||||
|
<require from="bootstrap/css/bootstrap.css"></require>
|
||||||
|
<require from="./styles.css"></require>
|
||||||
|
|
||||||
|
<nav class="navbar navbar-inverse navbar-fixed-top">
|
||||||
|
<div class="container">
|
||||||
|
<div class="navbar-header">
|
||||||
|
<button class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
||||||
|
<span class="sr-only">Toggle navigation</span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
</button>
|
||||||
|
<a route-href="route: home" class="navbar-brand">myPrayerJournal</a>
|
||||||
|
</div>
|
||||||
|
<div class="navbar-collapse collapse">
|
||||||
|
<ul class="nav navbar-nav navbar-right">
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<loading-indicator loading.bind="router.isNavigating || api.isRequesting"></loading-indicator>
|
||||||
|
<div class="container body-content">
|
||||||
|
<div class="row">
|
||||||
|
<h2 class.bind="'mpj-page-title' + ('' === pageTitle ? ' hidden' : '')" textcontent.bind="pageTitle"></h2>
|
||||||
|
<router-view class="col-xs-12" swap-order="with"></router-view>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<footer class="mpj-footer">
|
||||||
|
<p class="text-right">myPrayerJournal v0.8.1</p>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
27
src/app/src/app.ts
Normal file
27
src/app/src/app.ts
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import {Router, RouterConfiguration} from "aurelia-router"
|
||||||
|
import {EventAggregator} from "aurelia-event-aggregator"
|
||||||
|
import {inject} from "aurelia-framework"
|
||||||
|
import {PageTitle} from "./messages"
|
||||||
|
import {WebAPI} from "./web-api"
|
||||||
|
|
||||||
|
@inject(WebAPI, EventAggregator)
|
||||||
|
export class App {
|
||||||
|
router: Router;
|
||||||
|
pageTitle: string;
|
||||||
|
|
||||||
|
constructor(public api: WebAPI, private ea: EventAggregator) {
|
||||||
|
this.ea.subscribe(PageTitle, msg => this.pageTitle = msg.title)
|
||||||
|
}
|
||||||
|
|
||||||
|
configureRouter(config: RouterConfiguration, router: Router){
|
||||||
|
config.title = "myPrayerJournal"
|
||||||
|
config.options.pushState = true
|
||||||
|
config.options.root = "/"
|
||||||
|
config.map([
|
||||||
|
{ route: "", moduleId: "home", name: "home", title: "Welcome" },
|
||||||
|
{ route: 'contacts/:id', moduleId: 'contact-detail', name:'contacts' }
|
||||||
|
])
|
||||||
|
|
||||||
|
this.router = router
|
||||||
|
}
|
||||||
|
}
|
42
src/app/src/contact-detail.html
Normal file
42
src/app/src/contact-detail.html
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
<template>
|
||||||
|
<div class="panel panel-primary">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h3 class="panel-title">Profile</h3>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<form role="form" class="form-horizontal">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label">First Name</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="text" placeholder="first name" class="form-control" value.bind="contact.firstName">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label">Last Name</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="text" placeholder="last name" class="form-control" value.bind="contact.lastName">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label">Email</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="text" placeholder="email" class="form-control" value.bind="contact.email">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label">Phone Number</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="text" placeholder="phone number" class="form-control" value.bind="contact.phoneNumber">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="button-bar">
|
||||||
|
<button class="btn btn-success" click.delegate="save()" disabled.bind="!canSave">Save</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
58
src/app/src/contact-detail.ts
Normal file
58
src/app/src/contact-detail.ts
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
import {inject} from 'aurelia-framework';
|
||||||
|
import {EventAggregator} from 'aurelia-event-aggregator';
|
||||||
|
import {WebAPI} from './web-api';
|
||||||
|
import {ContactUpdated,ContactViewed} from './messages';
|
||||||
|
import {areEqual} from './utility';
|
||||||
|
|
||||||
|
interface Contact {
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
|
email: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
@inject(WebAPI, EventAggregator)
|
||||||
|
export class ContactDetail {
|
||||||
|
routeConfig;
|
||||||
|
contact: Contact;
|
||||||
|
originalContact: Contact;
|
||||||
|
|
||||||
|
constructor(private api: WebAPI, private ea: EventAggregator) { }
|
||||||
|
|
||||||
|
activate(params, routeConfig) {
|
||||||
|
this.routeConfig = routeConfig;
|
||||||
|
|
||||||
|
return this.api.getContactDetails(params.id).then(contact => {
|
||||||
|
this.contact = <Contact>contact;
|
||||||
|
this.routeConfig.navModel.setTitle(this.contact.firstName);
|
||||||
|
this.originalContact = JSON.parse(JSON.stringify(this.contact));
|
||||||
|
this.ea.publish(new ContactViewed(this.contact));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get canSave() {
|
||||||
|
return this.contact.firstName && this.contact.lastName && !this.api.isRequesting;
|
||||||
|
}
|
||||||
|
|
||||||
|
save() {
|
||||||
|
this.api.saveContact(this.contact).then(contact => {
|
||||||
|
this.contact = <Contact>contact;
|
||||||
|
this.routeConfig.navModel.setTitle(this.contact.firstName);
|
||||||
|
this.originalContact = JSON.parse(JSON.stringify(this.contact));
|
||||||
|
this.ea.publish(new ContactUpdated(this.contact));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
canDeactivate() {
|
||||||
|
if(!areEqual(this.originalContact, this.contact)){
|
||||||
|
let result = confirm('You have unsaved changes. Are you sure you wish to leave?');
|
||||||
|
|
||||||
|
if(!result) {
|
||||||
|
this.ea.publish(new ContactViewed(this.contact));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
12
src/app/src/contact-list.html
Normal file
12
src/app/src/contact-list.html
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<template>
|
||||||
|
<div class="contact-list">
|
||||||
|
<ul class="list-group">
|
||||||
|
<li repeat.for="contact of contacts" class="list-group-item ${contact.id === $parent.selectedId ? 'active' : ''}">
|
||||||
|
<a route-href="route: contacts; params.bind: {id:contact.id}" click.delegate="$parent.select(contact)">
|
||||||
|
<h4 class="list-group-item-heading">${contact.firstName} ${contact.lastName}</h4>
|
||||||
|
<p class="list-group-item-text">${contact.email}</p>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</template>
|
28
src/app/src/contact-list.ts
Normal file
28
src/app/src/contact-list.ts
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import {EventAggregator} from 'aurelia-event-aggregator';
|
||||||
|
import {WebAPI} from './web-api';
|
||||||
|
import {ContactUpdated, ContactViewed} from './messages';
|
||||||
|
import {inject} from 'aurelia-framework';
|
||||||
|
|
||||||
|
@inject(WebAPI, EventAggregator)
|
||||||
|
export class ContactList {
|
||||||
|
contacts;
|
||||||
|
selectedId = 0;
|
||||||
|
|
||||||
|
constructor(private api: WebAPI, ea: EventAggregator) {
|
||||||
|
ea.subscribe(ContactViewed, msg => this.select(msg.contact));
|
||||||
|
ea.subscribe(ContactUpdated, msg => {
|
||||||
|
let id = msg.contact.id;
|
||||||
|
let found = this.contacts.find(x => x.id == id);
|
||||||
|
Object.assign(found, msg.contact);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
created() {
|
||||||
|
this.api.getContactList().then(contacts => this.contacts = contacts);
|
||||||
|
}
|
||||||
|
|
||||||
|
select(contact) {
|
||||||
|
this.selectedId = contact.id;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
4
src/app/src/environment.ts
Normal file
4
src/app/src/environment.ts
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
export default {
|
||||||
|
debug: true,
|
||||||
|
testing: true
|
||||||
|
};
|
11
src/app/src/home.html
Normal file
11
src/app/src/home.html
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<template>
|
||||||
|
<p>
|
||||||
|
myPrayerJournal is a place where individuals can record their prayer requests, record that they prayed for them,
|
||||||
|
update them as God moves in the situation, and record a final answer received on that request. It will also allow
|
||||||
|
individuals to review their answered prayers.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
This site is currently in very limited alpha, as it is being developed with a core group of test users. If this is
|
||||||
|
something you are interested in using, check back around mid-June 2017 to check on the development progress.
|
||||||
|
</p>
|
||||||
|
</template>
|
10
src/app/src/home.ts
Normal file
10
src/app/src/home.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import {inject} from 'aurelia-framework';
|
||||||
|
import {EventAggregator} from "aurelia-event-aggregator"
|
||||||
|
import {PageTitle} from "./messages"
|
||||||
|
|
||||||
|
@inject(EventAggregator)
|
||||||
|
export class Home {
|
||||||
|
constructor(private ea: EventAggregator) {
|
||||||
|
this.ea.publish(new PageTitle("Welcome to myPrayerJournal"));
|
||||||
|
}
|
||||||
|
}
|
18
src/app/src/main.ts
Normal file
18
src/app/src/main.ts
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import {Aurelia} from 'aurelia-framework'
|
||||||
|
import environment from './environment';
|
||||||
|
|
||||||
|
export function configure(aurelia: Aurelia) {
|
||||||
|
aurelia.use
|
||||||
|
.standardConfiguration()
|
||||||
|
.feature('resources');
|
||||||
|
|
||||||
|
if (environment.debug) {
|
||||||
|
aurelia.use.developmentLogging();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (environment.testing) {
|
||||||
|
aurelia.use.plugin('aurelia-testing');
|
||||||
|
}
|
||||||
|
|
||||||
|
aurelia.start().then(() => aurelia.setRoot());
|
||||||
|
}
|
11
src/app/src/messages.ts
Normal file
11
src/app/src/messages.ts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
export class ContactUpdated {
|
||||||
|
constructor(public contact) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ContactViewed {
|
||||||
|
constructor(public contact) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PageTitle {
|
||||||
|
constructor(public title: string) { }
|
||||||
|
}
|
15
src/app/src/resources/elements/loading-indicator.ts
Normal file
15
src/app/src/resources/elements/loading-indicator.ts
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import * as nprogress from 'nprogress';
|
||||||
|
import {bindable, noView} from 'aurelia-framework';
|
||||||
|
|
||||||
|
@noView(['nprogress/nprogress.css'])
|
||||||
|
export class LoadingIndicator {
|
||||||
|
@bindable loading = false;
|
||||||
|
|
||||||
|
loadingChanged(newValue) {
|
||||||
|
if (newValue) {
|
||||||
|
nprogress.start();
|
||||||
|
} else {
|
||||||
|
nprogress.done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
5
src/app/src/resources/index.ts
Normal file
5
src/app/src/resources/index.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import {FrameworkConfiguration} from 'aurelia-framework';
|
||||||
|
|
||||||
|
export function configure(config: FrameworkConfiguration) {
|
||||||
|
config.globalResources(['./elements/loading-indicator']);
|
||||||
|
}
|
35
src/app/src/styles.css
Normal file
35
src/app/src/styles.css
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
body {
|
||||||
|
padding-top: 70px;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wrapping element */
|
||||||
|
/* Set some basic padding to keep content from hitting the edges */
|
||||||
|
.body-content {
|
||||||
|
padding-left: 15px;
|
||||||
|
padding-right: 15px;
|
||||||
|
}
|
||||||
|
.material-icons.md-18 {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
.material-icons.md-24 {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
.material-icons.md-36 {
|
||||||
|
font-size: 36px;
|
||||||
|
}
|
||||||
|
.material-icons.md-48 {
|
||||||
|
font-size: 48px;
|
||||||
|
}
|
||||||
|
.material-icons {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
.mpj-page-title {
|
||||||
|
border-bottom: solid 1px lightgray;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.mpj-footer {
|
||||||
|
border-top: solid 1px lightgray;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
3
src/app/src/utility.ts
Normal file
3
src/app/src/utility.ts
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
export function areEqual(obj1, obj2) {
|
||||||
|
return Object.keys(obj1).every((key) => obj2.hasOwnProperty(key) && (obj1[key] === obj2[key]));
|
||||||
|
};
|
96
src/app/src/web-api.ts
Normal file
96
src/app/src/web-api.ts
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
let latency = 200;
|
||||||
|
let id = 0;
|
||||||
|
|
||||||
|
function getId(){
|
||||||
|
return ++id;
|
||||||
|
}
|
||||||
|
|
||||||
|
let contacts = [
|
||||||
|
{
|
||||||
|
id:getId(),
|
||||||
|
firstName:'John',
|
||||||
|
lastName:'Tolkien',
|
||||||
|
email:'tolkien@inklings.com',
|
||||||
|
phoneNumber:'867-5309'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id:getId(),
|
||||||
|
firstName:'Clive',
|
||||||
|
lastName:'Lewis',
|
||||||
|
email:'lewis@inklings.com',
|
||||||
|
phoneNumber:'867-5309'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id:getId(),
|
||||||
|
firstName:'Owen',
|
||||||
|
lastName:'Barfield',
|
||||||
|
email:'barfield@inklings.com',
|
||||||
|
phoneNumber:'867-5309'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id:getId(),
|
||||||
|
firstName:'Charles',
|
||||||
|
lastName:'Williams',
|
||||||
|
email:'williams@inklings.com',
|
||||||
|
phoneNumber:'867-5309'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id:getId(),
|
||||||
|
firstName:'Roger',
|
||||||
|
lastName:'Green',
|
||||||
|
email:'green@inklings.com',
|
||||||
|
phoneNumber:'867-5309'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
export class WebAPI {
|
||||||
|
isRequesting = false;
|
||||||
|
|
||||||
|
getContactList(){
|
||||||
|
this.isRequesting = true;
|
||||||
|
return new Promise(resolve => {
|
||||||
|
setTimeout(() => {
|
||||||
|
let results = contacts.map(x => { return {
|
||||||
|
id:x.id,
|
||||||
|
firstName:x.firstName,
|
||||||
|
lastName:x.lastName,
|
||||||
|
email:x.email
|
||||||
|
}});
|
||||||
|
resolve(results);
|
||||||
|
this.isRequesting = false;
|
||||||
|
}, latency);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getContactDetails(id){
|
||||||
|
this.isRequesting = true;
|
||||||
|
return new Promise(resolve => {
|
||||||
|
setTimeout(() => {
|
||||||
|
let found = contacts.filter(x => x.id == id)[0];
|
||||||
|
resolve(JSON.parse(JSON.stringify(found)));
|
||||||
|
this.isRequesting = false;
|
||||||
|
}, latency);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
saveContact(contact){
|
||||||
|
this.isRequesting = true;
|
||||||
|
return new Promise(resolve => {
|
||||||
|
setTimeout(() => {
|
||||||
|
let instance = JSON.parse(JSON.stringify(contact));
|
||||||
|
let found = contacts.filter(x => x.id == contact.id)[0];
|
||||||
|
|
||||||
|
if(found){
|
||||||
|
let index = contacts.indexOf(found);
|
||||||
|
contacts[index] = instance;
|
||||||
|
}else{
|
||||||
|
instance.id = getId();
|
||||||
|
contacts.push(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isRequesting = false;
|
||||||
|
resolve(instance);
|
||||||
|
}, latency);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
87
src/app/test/aurelia-karma.js
Normal file
87
src/app/test/aurelia-karma.js
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
(function(global) {
|
||||||
|
var karma = global.__karma__;
|
||||||
|
var requirejs = global.requirejs
|
||||||
|
var locationPathname = global.location.pathname;
|
||||||
|
var root = 'src';
|
||||||
|
karma.config.args.forEach(function(value, index) {
|
||||||
|
if (value === 'aurelia-root') {
|
||||||
|
root = karma.config.args[index + 1];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!karma || !requirejs) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizePath(path) {
|
||||||
|
var normalized = []
|
||||||
|
var parts = path
|
||||||
|
.split('?')[0] // cut off GET params, used by noext requirejs plugin
|
||||||
|
.split('/')
|
||||||
|
|
||||||
|
for (var i = 0; i < parts.length; i++) {
|
||||||
|
if (parts[i] === '.') {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parts[i] === '..' && normalized.length && normalized[normalized.length - 1] !== '..') {
|
||||||
|
normalized.pop()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
normalized.push(parts[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use case of testing source code. RequireJS doesn't add .js extension to files asked via sibling selector
|
||||||
|
// If normalized path doesn't include some type of extension, add the .js to it
|
||||||
|
if (normalized.length > 0 && normalized[normalized.length - 1].indexOf('.') < 0) {
|
||||||
|
normalized[normalized.length - 1] = normalized[normalized.length - 1] + '.js'
|
||||||
|
}
|
||||||
|
|
||||||
|
return normalized.join('/')
|
||||||
|
}
|
||||||
|
|
||||||
|
function patchRequireJS(files, originalLoadFn, locationPathname) {
|
||||||
|
var IS_DEBUG = /debug\.html$/.test(locationPathname)
|
||||||
|
|
||||||
|
requirejs.load = function (context, moduleName, url) {
|
||||||
|
url = normalizePath(url)
|
||||||
|
|
||||||
|
if (files.hasOwnProperty(url) && !IS_DEBUG) {
|
||||||
|
url = url + '?' + files[url]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (url.indexOf('/base') !== 0) {
|
||||||
|
url = '/base/' + url;
|
||||||
|
}
|
||||||
|
|
||||||
|
return originalLoadFn.call(this, context, moduleName, url)
|
||||||
|
}
|
||||||
|
|
||||||
|
var originalDefine = global.define;
|
||||||
|
global.define = function(name, deps, m) {
|
||||||
|
if (typeof name === 'string') {
|
||||||
|
originalDefine('/base/' + root + '/' + name, [name], function (result) { return result; });
|
||||||
|
}
|
||||||
|
|
||||||
|
return originalDefine(name, deps, m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function requireTests() {
|
||||||
|
var TEST_REGEXP = /(spec)\.js$/i;
|
||||||
|
var allTestFiles = ['/base/test/unit/setup.js'];
|
||||||
|
|
||||||
|
Object.keys(window.__karma__.files).forEach(function(file) {
|
||||||
|
if (TEST_REGEXP.test(file)) {
|
||||||
|
allTestFiles.push(file);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
require(allTestFiles, window.__karma__.start);
|
||||||
|
}
|
||||||
|
|
||||||
|
karma.loaded = function() {}; // make it async
|
||||||
|
patchRequireJS(karma.files, requirejs.load, locationPathname);
|
||||||
|
requireTests();
|
||||||
|
})(window);
|
7
src/app/test/unit/app.spec.ts
Normal file
7
src/app/test/unit/app.spec.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import {App} from '../../src/app';
|
||||||
|
|
||||||
|
describe('the app', () => {
|
||||||
|
it('says hello', () => {
|
||||||
|
expect(new App().message).toBe('Hello World!');
|
||||||
|
});
|
||||||
|
});
|
3
src/app/test/unit/setup.ts
Normal file
3
src/app/test/unit/setup.ts
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
import 'aurelia-polyfills';
|
||||||
|
import {initialize} from 'aurelia-pal-browser';
|
||||||
|
initialize();
|
27
src/app/tsconfig.json
Normal file
27
src/app/tsconfig.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"compileOnSave": false,
|
||||||
|
"compilerOptions": {
|
||||||
|
"sourceMap": true,
|
||||||
|
"target": "es5",
|
||||||
|
"module": "amd",
|
||||||
|
"declaration": false,
|
||||||
|
"noImplicitAny": false,
|
||||||
|
"removeComments": true,
|
||||||
|
"emitDecoratorMetadata": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"lib": ["es2017", "dom"]
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
"aurelia_project"
|
||||||
|
],
|
||||||
|
"filesGlob": [
|
||||||
|
"./src/**/*.ts",
|
||||||
|
"./test/**/*.ts",
|
||||||
|
"./custom_typings/**/*.d.ts"
|
||||||
|
],
|
||||||
|
"atom": {
|
||||||
|
"rewriteTsconfig": false
|
||||||
|
}
|
||||||
|
}
|
5
src/app/tslint.json
Normal file
5
src/app/tslint.json
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"rules": {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
5
src/app/typings.json
Normal file
5
src/app/typings.json
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"globalDependencies": {
|
||||||
|
"nprogress": "registry:dt/nprogress#0.0.0+20161119044246"
|
||||||
|
}
|
||||||
|
}
|
113
src/app/typings/globals/nprogress/index.d.ts
vendored
Normal file
113
src/app/typings/globals/nprogress/index.d.ts
vendored
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
// Generated by typings
|
||||||
|
// Source: https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/253e456e3c0bf4bd34afaceb7dcbae282da14066/nprogress/index.d.ts
|
||||||
|
interface NProgressStatic {
|
||||||
|
/**
|
||||||
|
* Shows the progress bar and begins trickling progress.
|
||||||
|
* @returns {NProgressConfigureOptions} The current NProgress object, useful for chaining.
|
||||||
|
*/
|
||||||
|
start(): NProgressStatic;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finishes loading by transitioning it to 100%, then fading out.
|
||||||
|
* @param {boolean} forceShow Forces the progress bar to show, even if it's not being shown. (The default behavior is that .done() will not do anything if .start() isn't called.)
|
||||||
|
* @returns {NProgressConfigureOptions} The current NProgress object, useful for chaining.
|
||||||
|
*/
|
||||||
|
done(forceShow?: boolean): NProgressStatic;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments the progress bar with a random amount. This will never get to 100%: use it for every image load (or similar).
|
||||||
|
* @returns {NProgressConfigureOptions} The current NProgress object, useful for chaining.
|
||||||
|
*/
|
||||||
|
inc(): NProgressStatic;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments the progress bar with a set amount.
|
||||||
|
* @param {number} amount This will get the current status value and adds the value until status is max 0.994
|
||||||
|
* @returns {NProgressConfigureOptions} The current NProgress object, useful for chaining.
|
||||||
|
*/
|
||||||
|
inc(amount: number): NProgressStatic;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the progress indicator.
|
||||||
|
*/
|
||||||
|
remove(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the progress percentage.
|
||||||
|
* @param {number} progressPercent A number between 0.0 and 1.0 that represents the progress percentage.
|
||||||
|
* @returns {NProgressConfigureOptions} The current NProgress object, useful for chaining.
|
||||||
|
*/
|
||||||
|
set(progressPercent: number): NProgressStatic;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures the progress indicator.
|
||||||
|
* @param {NProgressConfigureOptions} options An object containing the configuration options.
|
||||||
|
* @returns {NProgressConfigureOptions} The current NProgress object, useful for chaining.
|
||||||
|
*/
|
||||||
|
configure(options: NProgressConfigureOptions): NProgressStatic;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the NProgress version.
|
||||||
|
*/
|
||||||
|
version: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the status. If started, it will be the last progress number set.
|
||||||
|
*/
|
||||||
|
status: any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether progress has been started.
|
||||||
|
* @returns {boolean} Whether the progress has started.
|
||||||
|
*/
|
||||||
|
isStarted(): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface NProgressConfigureOptions {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CSS selector to change the parent DOM element of the progress. Default is body.
|
||||||
|
*/
|
||||||
|
parent?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The minimum progress percentage. Default is 0.08.
|
||||||
|
*/
|
||||||
|
minimum?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How often to trickle, in milliseconds. Default is 800.
|
||||||
|
*/
|
||||||
|
trickleSpeed?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to show the spinner. Defaults to true. Default is true.
|
||||||
|
*/
|
||||||
|
showSpinner?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to enable trickling the progress. Default is true.
|
||||||
|
*/
|
||||||
|
trickle?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The CSS easing animation to use. Default is 'linear'.
|
||||||
|
*/
|
||||||
|
easing?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The animation speed in milliseconds. Default is 200.
|
||||||
|
*/
|
||||||
|
speed?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The HTML markup inserted for the progress indicator. To keep the progress bar working, keep an element with role='bar' in there.
|
||||||
|
*/
|
||||||
|
template?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare var NProgress: NProgressStatic;
|
||||||
|
|
||||||
|
declare module "nprogress" {
|
||||||
|
export = NProgress;
|
||||||
|
}
|
8
src/app/typings/globals/nprogress/typings.json
Normal file
8
src/app/typings/globals/nprogress/typings.json
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"resolution": "main",
|
||||||
|
"tree": {
|
||||||
|
"src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/253e456e3c0bf4bd34afaceb7dcbae282da14066/nprogress/index.d.ts",
|
||||||
|
"raw": "registry:dt/nprogress#0.0.0+20161119044246",
|
||||||
|
"typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/253e456e3c0bf4bd34afaceb7dcbae282da14066/nprogress/index.d.ts"
|
||||||
|
}
|
||||||
|
}
|
1
src/app/typings/index.d.ts
vendored
Normal file
1
src/app/typings/index.d.ts
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/// <reference path="globals/nprogress/index.d.ts" />
|
Loading…
Reference in New Issue
Block a user