+ 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. +
++ 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. +
+ \ No newline at end of file diff --git a/src/app/src/home.ts b/src/app/src/home.ts new file mode 100644 index 0000000..7e85b29 --- /dev/null +++ b/src/app/src/home.ts @@ -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")); + } +} \ No newline at end of file diff --git a/src/app/src/main.ts b/src/app/src/main.ts new file mode 100644 index 0000000..e3a450b --- /dev/null +++ b/src/app/src/main.ts @@ -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()); +} diff --git a/src/app/src/messages.ts b/src/app/src/messages.ts new file mode 100644 index 0000000..34fea18 --- /dev/null +++ b/src/app/src/messages.ts @@ -0,0 +1,11 @@ +export class ContactUpdated { + constructor(public contact) { } +} + +export class ContactViewed { + constructor(public contact) { } +} + +export class PageTitle { + constructor(public title: string) { } +} \ No newline at end of file diff --git a/src/app/src/resources/elements/loading-indicator.ts b/src/app/src/resources/elements/loading-indicator.ts new file mode 100644 index 0000000..a44560b --- /dev/null +++ b/src/app/src/resources/elements/loading-indicator.ts @@ -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(); + } + } +} \ No newline at end of file diff --git a/src/app/src/resources/index.ts b/src/app/src/resources/index.ts new file mode 100644 index 0000000..6ccb7c9 --- /dev/null +++ b/src/app/src/resources/index.ts @@ -0,0 +1,5 @@ +import {FrameworkConfiguration} from 'aurelia-framework'; + +export function configure(config: FrameworkConfiguration) { + config.globalResources(['./elements/loading-indicator']); +} diff --git a/src/app/src/styles.css b/src/app/src/styles.css new file mode 100644 index 0000000..071fef5 --- /dev/null +++ b/src/app/src/styles.css @@ -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; +} \ No newline at end of file diff --git a/src/app/src/utility.ts b/src/app/src/utility.ts new file mode 100644 index 0000000..769909b --- /dev/null +++ b/src/app/src/utility.ts @@ -0,0 +1,3 @@ +export function areEqual(obj1, obj2) { + return Object.keys(obj1).every((key) => obj2.hasOwnProperty(key) && (obj1[key] === obj2[key])); +}; \ No newline at end of file diff --git a/src/app/src/web-api.ts b/src/app/src/web-api.ts new file mode 100644 index 0000000..ad3552d --- /dev/null +++ b/src/app/src/web-api.ts @@ -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); + }); + } +} diff --git a/src/app/test/aurelia-karma.js b/src/app/test/aurelia-karma.js new file mode 100644 index 0000000..d76a928 --- /dev/null +++ b/src/app/test/aurelia-karma.js @@ -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); diff --git a/src/app/test/unit/app.spec.ts b/src/app/test/unit/app.spec.ts new file mode 100644 index 0000000..500fdb5 --- /dev/null +++ b/src/app/test/unit/app.spec.ts @@ -0,0 +1,7 @@ +import {App} from '../../src/app'; + +describe('the app', () => { + it('says hello', () => { + expect(new App().message).toBe('Hello World!'); + }); +}); diff --git a/src/app/test/unit/setup.ts b/src/app/test/unit/setup.ts new file mode 100644 index 0000000..a2498cc --- /dev/null +++ b/src/app/test/unit/setup.ts @@ -0,0 +1,3 @@ +import 'aurelia-polyfills'; +import {initialize} from 'aurelia-pal-browser'; +initialize(); diff --git a/src/app/tsconfig.json b/src/app/tsconfig.json new file mode 100644 index 0000000..82ad48d --- /dev/null +++ b/src/app/tsconfig.json @@ -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 + } +} diff --git a/src/app/tslint.json b/src/app/tslint.json new file mode 100644 index 0000000..a5240ac --- /dev/null +++ b/src/app/tslint.json @@ -0,0 +1,5 @@ +{ + "rules": { + + } +} diff --git a/src/app/typings.json b/src/app/typings.json new file mode 100644 index 0000000..ead2a23 --- /dev/null +++ b/src/app/typings.json @@ -0,0 +1,5 @@ +{ + "globalDependencies": { + "nprogress": "registry:dt/nprogress#0.0.0+20161119044246" + } +} diff --git a/src/app/typings/globals/nprogress/index.d.ts b/src/app/typings/globals/nprogress/index.d.ts new file mode 100644 index 0000000..06f92b5 --- /dev/null +++ b/src/app/typings/globals/nprogress/index.d.ts @@ -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; +} diff --git a/src/app/typings/globals/nprogress/typings.json b/src/app/typings/globals/nprogress/typings.json new file mode 100644 index 0000000..b0382ee --- /dev/null +++ b/src/app/typings/globals/nprogress/typings.json @@ -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" + } +} diff --git a/src/app/typings/index.d.ts b/src/app/typings/index.d.ts new file mode 100644 index 0000000..76470ca --- /dev/null +++ b/src/app/typings/index.d.ts @@ -0,0 +1 @@ +///