From df134b277cfc02e22356ef8d19982b44dded6e50 Mon Sep 17 00:00:00 2001 From: Steve Davis Date: Thu, 12 Feb 2015 13:41:51 -0600 Subject: [PATCH 001/367] Init --- .bowerrc | 5 + .gitignore | 6 + .gitmodules | 0 .travis.yml | 13 + Gruntfile.js | 553 +++++++++++++++++++++++++++++++++++++ LICENSE | 19 ++ README.md | 249 +++++++++++++++++ bower.json | 16 ++ build.config.js | 82 ++++++ changelog.tpl | 23 ++ karma/karma-unit.tpl.js | 25 ++ module.prefix | 1 + module.suffix | 1 + package.json | 35 +++ src/README.md | 48 ++++ src/app/README.md | 94 +++++++ src/app/app.js | 47 ++++ src/app/app.spec.js | 7 + src/app/home/README.md | 73 +++++ src/app/home/home.js | 34 +++ src/app/home/home.less | 0 src/app/home/home.spec.js | 14 + src/app/home/home.tpl.html | 4 + src/app/variables.less | 4 + src/assets/README.md | 4 + src/common/README.md | 24 ++ src/index.html | 16 ++ src/less/README.md | 28 ++ src/less/main.less | 246 +++++++++++++++++ tools.md | 213 ++++++++++++++ 30 files changed, 1884 insertions(+) create mode 100644 .bowerrc create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 .travis.yml create mode 100644 Gruntfile.js create mode 100644 LICENSE create mode 100644 README.md create mode 100644 bower.json create mode 100644 build.config.js create mode 100644 changelog.tpl create mode 100644 karma/karma-unit.tpl.js create mode 100644 module.prefix create mode 100644 module.suffix create mode 100644 package.json create mode 100644 src/README.md create mode 100644 src/app/README.md create mode 100644 src/app/app.js create mode 100644 src/app/app.spec.js create mode 100644 src/app/home/README.md create mode 100644 src/app/home/home.js create mode 100644 src/app/home/home.less create mode 100644 src/app/home/home.spec.js create mode 100644 src/app/home/home.tpl.html create mode 100644 src/app/variables.less create mode 100644 src/assets/README.md create mode 100644 src/common/README.md create mode 100644 src/index.html create mode 100644 src/less/README.md create mode 100644 src/less/main.less create mode 100644 tools.md diff --git a/.bowerrc b/.bowerrc new file mode 100644 index 00000000..1f984984 --- /dev/null +++ b/.bowerrc @@ -0,0 +1,5 @@ +{ + "directory": "vendor", + "json": "bower.json" +} + diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..ee56217c --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*.sw* +*~ +build/ +compile/ +node_modules/ +vendor/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..e69de29b diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..29f56d66 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,13 @@ +language: node_js +node_js: + - "0.10" + +before_script: + - export DISPLAY=:99.0 + - sh -e /etc/init.d/xvfb start + - npm install --quiet -g grunt-cli karma bower + - npm install + - bower install + +script: grunt + diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 00000000..8575a1ba --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,553 @@ +module.exports = function ( grunt ) { + + /** + * Load required Grunt tasks. These are installed based on the versions listed + * in `package.json` when you do `npm install` in this directory. + */ + grunt.loadNpmTasks('grunt-contrib-clean'); + grunt.loadNpmTasks('grunt-contrib-copy'); + grunt.loadNpmTasks('grunt-contrib-concat'); + grunt.loadNpmTasks('grunt-contrib-watch'); + grunt.loadNpmTasks('grunt-contrib-uglify'); + grunt.loadNpmTasks('grunt-less-imports'); + grunt.loadNpmTasks('grunt-contrib-less'); + grunt.loadNpmTasks('grunt-conventional-changelog'); + grunt.loadNpmTasks('grunt-karma'); + grunt.loadNpmTasks('grunt-ng-annotate'); + grunt.loadNpmTasks('grunt-html2js'); + grunt.loadNpmTasks('grunt-autoprefixer'); + + + /** + * Load in our build configuration file. + */ + var userConfig = require( './build.config.js' ); + + /** + * This is the configuration object Grunt uses to give each plugin its + * instructions. + */ + var taskConfig = { + /** + * We read in our `package.json` file so we can access the package name and + * version. It's already there, so we don't repeat ourselves here. + */ + pkg: grunt.file.readJSON("package.json"), + + /** + * The banner is the comment that is placed at the top of our compiled + * source files. It is first processed as a Grunt template, where the `<%=` + * pairs are evaluated based on this very configuration object. + */ + meta: { + banner: + '/**\n' + + ' * <%= pkg.name %> - v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %>\n' + + ' * <%= pkg.homepage %>\n' + + ' *\n' + + ' * Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' + + ' * Licensed <%= pkg.licenses.type %> <<%= pkg.licenses.url %>>\n' + + ' */\n' + }, + + /** + * Creates a changelog on a new version. + */ + changelog: { + options: { + dest: 'CHANGELOG.md', + template: 'changelog.tpl' + } + }, + + /** + * The directories to delete when `grunt clean` is executed. + */ + clean: [ + '<%= build_dir %>', + '<%= compile_dir %>' + ], + + /** + * The `copy` task just copies files from A to B. We use it here to copy + * our project assets (images, fonts, etc.) and javascripts into + * `build_dir`, and then to copy the assets to `compile_dir`. + */ + copy: { + build_app_assets: { + files: [ + { + src: [ '**' ], + dest: '<%= build_dir %>/assets/', + cwd: 'src/assets', + expand: true + } + ] + }, + build_vendor_assets: { + files: [ + { + src: [ '<%= vendor_files.assets %>' ], + dest: '<%= build_dir %>/assets/', + cwd: '.', + expand: true, + flatten: true + } + ] + }, + build_appjs: { + files: [ + { + src: [ '<%= app_files.js %>' ], + dest: '<%= build_dir %>/', + cwd: '.', + expand: true + } + ] + }, + build_vendorjs: { + files: [ + { + src: [ '<%= vendor_files.js %>' ], + dest: '<%= build_dir %>/', + cwd: '.', + expand: true + } + ] + }, + compile_assets: { + files: [ + { + src: [ '**' ], + dest: '<%= compile_dir %>/assets', + cwd: '<%= build_dir %>/assets', + expand: true + } + ] + } + }, + + /** + * `grunt concat` concatenates multiple source files into a single file. + */ + concat: { + /** + * The `build_css` target concatenates compiled CSS and vendor CSS + * together. + */ + build_css: { + src: [ + '<%= vendor_files.css %>', + '<%= build_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.css' + ], + dest: '<%= build_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.css' + }, + /** + * The `compile_js` target is the concatenation of our application source + * code and all specified vendor source code into a single file. + */ + compile_js: { + options: { + banner: '<%= meta.banner %>' + }, + src: [ + '<%= vendor_files.js %>', + 'module.prefix', + '<%= build_dir %>/src/**/*.js', + '<%= html2js.app.dest %>', + '<%= html2js.common.dest %>', + 'module.suffix' + ], + dest: '<%= compile_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.js' + } + }, + + /** + * `ng-annotate` annotates the sources before minifying. That is, it allows us + * to code without the array syntax. + */ + ngAnnotate: { + compile: { + files: [ + { + src: [ '<%= app_files.js %>' ], + cwd: '<%= build_dir %>', + dest: '<%= build_dir %>', + expand: true + } + ] + } + }, + + /** + * Minify the sources! + */ + uglify: { + compile: { + options: { + banner: '<%= meta.banner %>' + }, + files: { + '<%= concat.compile_js.dest %>': '<%= concat.compile_js.dest %>' + } + } + }, + + /** + * `grunt-less-imports` handles importing of all LESS files into the src/less/main.less file. + * The app_files.import_less array in the build.config.js file drives where to look for these files. + */ + less_imports: { + build: { + options: { + banner: '// This file was generated by the grunt-less-imports task in the build process. Do not alter this file, any changes you make will be overwritten the next time you build.' + }, + files: { + 'src/less/main.less': '<%= app_files.import_less %>' + } + } + }, + + /** + * `grunt-contrib-less` handles our LESS compilation and uglification automatically. + * Only our `main.less` file is included in compilation; all other files + * must be imported from this file. + */ + less: { + build: { + files: { + '<%= build_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.css': '<%= app_files.less %>' + } + }, + compile: { + files: { + '<%= build_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.css': '<%= app_files.less %>' + }, + options: { + cleancss: true, + compress: true + } + } + }, + + /** + * https://github.com/nDmitry/grunt-autoprefixer + * `autoprefixer` looks at the compiled CSS and adds any necessary + * browser-specific prefixes needed for newer CSS rules. The autoprefixer default + * options are set below and it is used in the build, compile, and watch tasks. + */ + autoprefixer: { + options: { + browsers: ['> 1%', 'last 2 versions', 'Firefox ESR', 'Opera 12.1'], + cascade: true, + remove: true, + diff: false, + map: false, + silent: false + }, + single_file: { + src: '<%= build_dir %>/assets/*.css', + dest: '<%= build_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.css' + } + }, + + /** + * HTML2JS is a Grunt plugin that takes all of your template files and + * places them into JavaScript files as strings that are added to + * AngularJS's template cache. This means that the templates too become + * part of the initial payload as one JavaScript file. Neat! + */ + html2js: { + /** + * These are the templates from `src/app`. + */ + app: { + options: { + base: 'src/app' + }, + src: [ '<%= app_files.atpl %>' ], + dest: '<%= build_dir %>/templates-app.js' + }, + + /** + * These are the templates from `src/common`. + */ + common: { + options: { + base: 'src/common' + }, + src: [ '<%= app_files.ctpl %>' ], + dest: '<%= build_dir %>/templates-common.js' + } + }, + + /** + * The Karma configurations. + */ + karma: { + options: { + configFile: '<%= build_dir %>/karma-unit.js' + }, + unit: { + port: 9019, + background: true + }, + continuous: { + singleRun: true + } + }, + + /** + * The `index` task compiles the `index.html` file as a Grunt template. CSS + * and JS files co-exist here but they get split apart later. + */ + index: { + + /** + * During development, we don't want to have wait for compilation, + * concatenation, minification, etc. So to avoid these steps, we simply + * add all script files directly to the `` of `index.html`. The + * `src` property contains the list of included files. + */ + build: { + dir: '<%= build_dir %>', + src: [ + '<%= vendor_files.js %>', + '<%= build_dir %>/src/**/*.js', + '<%= html2js.common.dest %>', + '<%= html2js.app.dest %>', + '<%= vendor_files.css %>', + '<%= build_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.css' + ] + }, + + /** + * When it is time to have a completely compiled application, we can + * alter the above to include only a single JavaScript and a single CSS + * file. Now we're back! + */ + compile: { + dir: '<%= compile_dir %>', + src: [ + '<%= concat.compile_js.dest %>', + '<%= vendor_files.css %>', + '<%= build_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.css' + ] + } + }, + + /** + * This task compiles the karma template so that changes to its file array + * don't have to be managed manually. + */ + karmaconfig: { + unit: { + dir: '<%= build_dir %>', + src: [ + '<%= vendor_files.js %>', + '<%= html2js.app.dest %>', + '<%= html2js.common.dest %>', + '<%= test_files.js %>' + ] + } + }, + + /** + * And for rapid development, we have a watch set up that checks to see if + * any of the files listed below change, and then to execute the listed + * tasks when they do. This just saves us from having to type "grunt" into + * the command-line every time we want to see what we're working on; we can + * instead just leave "grunt watch" running in a background terminal. Set it + * and forget it, as Ron Popeil used to tell us. + * + * But we don't need the same thing to happen for all the files. + */ + delta: { + /** + * By default, we want the Live Reload to work for all tasks; this is + * overridden in some tasks (like this file) where browser resources are + * unaffected. It runs by default on port 35729, which your browser + * plugin should auto-detect. + */ + options: { + livereload: true + }, + + /** + * When the Gruntfile changes, we just want to lint it. In fact, when + * your Gruntfile changes, it will automatically be reloaded! + */ + gruntfile: { + files: 'Gruntfile.js', + tasks: [ ], + options: { + livereload: false + } + }, + + /** + * When our JavaScript source files change, we want to run lint them and + * run our unit tests. + */ + jssrc: { + files: [ + '<%= app_files.js %>' + ], + tasks: [ 'karma:unit:run', 'copy:build_appjs' ] + }, + + /** + * When assets are changed, copy them. Note that this will *not* copy new + * files, so this is probably not very useful. + */ + assets: { + files: [ + 'src/assets/**/*' + ], + tasks: [ 'copy:build_app_assets', 'copy:build_vendor_assets' ] + }, + + /** + * When index.html changes, we need to compile it. + */ + html: { + files: [ '<%= app_files.html %>' ], + tasks: [ 'index:build' ] + }, + + /** + * When our templates change, we only rewrite the template cache. + */ + tpls: { + files: [ + '<%= app_files.atpl %>', + '<%= app_files.ctpl %>' + ], + tasks: [ 'html2js' ] + }, + + /** + * When the CSS files change, we need to compile and minify them. + */ + less: { + files: [ 'src/**/*.less' ], + tasks: [ 'less_imports:build', 'less:build', 'autoprefixer' ] + }, + + /** + * When a JavaScript unit test file changes, we only want to lint it and + * run the unit tests. We don't want to do any live reloading. + */ + jsunit: { + files: [ + '<%= app_files.jsunit %>' + ], + tasks: [ 'karma:unit:run' ], + options: { + livereload: false + } + } + } + }; + + grunt.initConfig( grunt.util._.extend( taskConfig, userConfig ) ); + + /** + * In order to make it safe to just compile or copy *only* what was changed, + * we need to ensure we are starting from a clean, fresh build. So we rename + * the `watch` task to `delta` (that's why the configuration var above is + * `delta`) and then add a new task called `watch` that does a clean build + * before watching for changes. + */ + grunt.renameTask( 'watch', 'delta' ); + grunt.registerTask( 'watch', [ 'build', 'karma:unit', 'delta' ] ); + + /** + * The default task is to build and compile. + */ + grunt.registerTask( 'default', [ 'build', 'compile' ] ); + + /** + * The `build` task gets your app ready to run for development and testing. + */ + grunt.registerTask( 'build', [ + 'clean', 'html2js', 'less_imports:build', 'less:build', + 'concat:build_css', 'copy:build_app_assets', 'copy:build_vendor_assets', 'autoprefixer', + 'copy:build_appjs', 'copy:build_vendorjs', 'index:build', 'karmaconfig', + 'karma:continuous' + ]); + + /** + * The `compile` task gets your app ready for deployment by concatenating and + * minifying your code. + */ + grunt.registerTask( 'compile', [ + 'less:compile', 'copy:compile_assets', 'autoprefixer', 'ngAnnotate', 'concat:compile_js', 'uglify', 'index:compile' + ]); + + /** + * A utility function to get all app JavaScript sources. + */ + function filterForJS ( files ) { + return files.filter( function ( file ) { + return file.match( /\.js$/ ); + }); + } + + /** + * A utility function to get all app CSS sources. + */ + function filterForCSS ( files ) { + return files.filter( function ( file ) { + return file.match( /\.css$/ ); + }); + } + + /** + * The index.html template includes the stylesheet and javascript sources + * based on dynamic names calculated in this Gruntfile. This task assembles + * the list into variables for the template to use and then runs the + * compilation. + */ + grunt.registerMultiTask( 'index', 'Process index.html template', function () { + var dirRE = new RegExp( '^('+grunt.config('build_dir')+'|'+grunt.config('compile_dir')+')\/', 'g' ); + var jsFiles = filterForJS( this.filesSrc ).map( function ( file ) { + return file.replace( dirRE, '' ); + }); + var cssFiles = filterForCSS( this.filesSrc ).map( function ( file ) { + return file.replace( dirRE, '' ); + }); + + grunt.file.copy('src/index.html', this.data.dir + '/index.html', { + process: function ( contents, path ) { + return grunt.template.process( contents, { + data: { + scripts: jsFiles, + styles: cssFiles, + version: grunt.config( 'pkg.version' ) + } + }); + } + }); + }); + + /** + * In order to avoid having to specify manually the files needed for karma to + * run, we use grunt to manage the list for us. The `karma/*` files are + * compiled as grunt templates for use by Karma. Yay! + */ + grunt.registerMultiTask( 'karmaconfig', 'Process karma config templates', function () { + var jsFiles = filterForJS( this.filesSrc ); + + grunt.file.copy( 'karma/karma-unit.tpl.js', grunt.config( 'build_dir' ) + '/karma-unit.js', { + process: function ( contents, path ) { + return grunt.template.process( contents, { + data: { + scripts: jsFiles + } + }); + } + }); + }); + +}; diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..3ccb9103 --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) Four51, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 00000000..a5e0d52b --- /dev/null +++ b/README.md @@ -0,0 +1,249 @@ +# OrderCloud +A seed project for custom Four51 Solutions +*** + +## Get started + +Install [node.js](http://nodejs.org/) and then: + +```sh +$ npm -g install grunt-cli karma bower +$ npm install +$ bower install +$ grunt build +``` + +You should now have a few more directories in your project. + +``` +OrderCloud/ + |- build/ + |- node_modules/ + |- vendor/ +``` + +## Configure WebStorm +WebStorm is our chosen development IDE. It provides an interface into the capabilities of the projects configuration. + +### Karma Unit Testing +Once you've installed the prerequisites and run your grunt build you can setup and run your Karma tests. + +Create a Run configuration using the Karma plugin with the following settings: + +Node interpreter: C:\Program Files (x86)\nodejs\node.exe + +Karma package: C:\Four51\WebFiles\SPASites\defaults\OrderCloud\node_modules\karma + +Configuration file: C:\Four51\WebFiles\SPASites\defaults\OrderCloud\build\karma-unit.js + + +### Overall Directory Structure + +At a high level, the structure looks roughly like this: + +``` +OrderCloud/ + |- grunt-tasks/ + |- karma/ + |- src/ + | |- app/ + | | |- + | |- assets/ + | | |- + | |- common/ + | | |- + | |- less/ + | | |- main.less + |- vendor/ + | |- angular-bootstrap/ + | |- bootstrap/ + | |- placeholders/ + |- .bowerrc + |- bower.json + |- build.config.js + |- Gruntfile.js + |- module.prefix + |- module.suffix + |- package.json +``` + +### Detailed Installation + +This section provides a little more detailed understanding of what goes into +getting `OrderCloud` up and running. Though `OrderCloud` is really simple +to use, it might help to have an understanding of the tools involved here, like +Node.js and Grunt and Bower. If you're completely new to highly organized, +modern JavaScript development, take a few short minutes to read [this overview +of the tools](tools.md) before continuing with this section. + +Here it is: + +`OrderCloud` uses [Grunt](http://gruntjs.org) as its build system, so +[Node.js](http://nodejs.org) is required. Also, Grunt by default no longer comes +with a command-line utility and Karma and Bower must end up in your global path +for the build system to find it, so they must be installed independently. Once +you have Node.js installed, you can simply use `npm` to make it all happen: + +```sh +$ npm -g install grunt-cli karma bower +``` + +And then install the remaining build dependencies locally: + +```sh +$ npm install +``` + +This will read the `dependencies` (empty by default) and the `devDependencies` +(which contains our build requirements) from `package.json` and install +everything needed into a folder called `node_modules/`. + +There are many Bower packages used by `OrderCloud`, like Twitter Bootstrap +and Angular UI, which are listed in `bower.js`. To install them into the +`vendor/` directory, simply run: + +```sh +$ bower install +``` + +In the future, should you want to add a new Bower package to your app, run the +`install` command: + +```sh +$ bower install packagename --save-dev +``` + +The `--save-dev` flag tells Bower to add the package at its current version to +our project's `bower.js` file so should another developer download our +application (or we download it from a different computer), we can simply run the +`bower install` command as above and all our dependencies will be installed for +us. Neat! + +Technically, `OrderCloud` is now ready to go. + +To ensure your setup works, launch grunt: + +```sh +$ grunt watch +``` + +The built files are placed in the `build/` directory by default. Open the +`build/index.html` file in your browser and check it out! Because everything is +compiled, no XHR requests are needed to retrieve templates, so until this needs +to communicate with your backend there is no need to run it from a web server. + +`watch` is actually an alias of the `grunt-contrib-watch` that will first run a +partial build before watching for file changes. With this setup, any file that +changes will trigger only those build tasks necessary to bring the app up to +date. For example, when a template file changes, the templates are recompiled +and concatenated, but when a test/spec file changes, only the tests are run. +This allows the watch command to complete in a fraction of the time it would +ordinarily take. + +In addition, if you're running a Live Reload plugin in your browser (see below), +you won't even have to refresh to see the changes! When the `watch` task detects +a file change, it will reload the page for you. Sweet. + +When you're ready to push your app into production, just run the `compile` +command: + +```sh +$ grunt compile +``` + +This will concatenate and minify your sources and place them by default into the +`release/` directory. There will only be three files: `index.html`, +`OrderCloud.js`, and `OrderCloud.css`. All of the vendor dependencies like +Bootstrap styles and AngularJS itself have been added to them for super-easy +deploying. If you use any assets (`src/assets/`) then they will be copied to +`release/` as is. + +Lastly, a complete build is always available by simply running the default +task, which runs `build` and then `compile`: + +```sh +$ grunt +``` + +### The Build System + +The best way to learn about the build system is by familiarizing yourself with +Grunt and then reading through the heavily documented build script, +`Gruntfile.js`. But you don't need to do that to be very productive with +`OrderCloud`. What follows in this section is a quick introduction to the +tasks provided and should be plenty to get you started. + +The driver of the process is the `delta` multi-task, which watches for file +changes using `grunt-contrib-watch` and executes one of nine tasks when a file +changes: + +* `delta:gruntfile` - When `Gruntfile.js` changes, this task runs the linter + (`jshint`) on that one file and reloads the configuration. +* `delta:assets` - When any file within `src/assets/` changes, all asset files + are copied to `build/assets/`. +* `delta:html` - When `src/index.html` changes, it is compiled as a Grunt + template, so script names, etc., are dynamically replaced with the correct + values configured dynamically by Grunt. +* `delta:less` - When any `*.less` file within `src/` changes, the + `src/less/main.less` file is linted and copied into + `build/assets/OrderCloud.css`. +* `delta:jssrc` - When any JavaScript file within `src/` that does not end in + `.spec.js` changes, all JavaScript sources are linted, all unit tests are run, + and the all source files are re-copied to `build/src`. + `build/src` in a structure mirroring where they were in `src/` so it's easy to + locate problems. +* `delta:tpls` - When any `*.tpl.html` file within `src/` changes, all templates + are put into strings in a JavaScript file (technically two, one for + `src/common/` and another for `src/app/`) that will add the template to + AngularJS's + [`$templateCache`](http://docs.angularjs.org/api/ng.$templateCache) so + template files are part of the initial JavaScript payload and do not require + any future XHR. The template cache files are `build/template-app.js` and + `build/template-common.js`. +* `delta:jsunit` - When any `*.spec.js` file in `src/` changes, the test files + are linted and the unit tests are executed. + +As covered in the previous section, `grunt watch` will execute a full build +up-front and then run any of the aforementioned `delta:*` tasks as needed to +ensure the fastest possible build. So whenever you're working on your project, +start with: + +```sh +$ grunt watch +``` + +And everything will be done automatically! + +### Build vs. Compile + +To make the build even faster, tasks are placed into two categories: build and +compile. The build tasks (like those we've been discussing) are the minimal +tasks required to run your app during development. + +Compile tasks, however, get your app ready for production. The compile tasks +include concatenation, minification, compression, etc. These tasks take a little +bit longer to run and are not at all necessary for development so are not called +automatically during build or watch. + +To initiate a full compile, you simply run the default task: + +```sh +$ grunt +``` + +This will perform a build and then a compile. The compiled site is located in `release/`, taking a cue from +traditional software development. To test that your full site works as +expected, open the `release/index.html` file in your browser. Voila! + +### Live Reload! + +`OrderCloud` also includes [Live Reload](http://livereload.com/), so you no +longer have to refresh your page after making changes! You need a Live Reload +browser plugin for this: + +- Chrome - [Chrome Webstore](https://chrome.google.com/webstore/detail/livereload/jnihajbhpnppcggbcgedagnkighmdlei) +- Firefox - [Download from Live Reload](http://download.livereload.com/2.0.8/LiveReload-2.0.8.xpi) +- Safari - [Download from Live Reload](http://download.livereload.com/2.0.9/LiveReload-2.0.9.safariextz) +- Internet Explorer - Not available. + +When you load your page, click the Live Reload icon in your toolbar. \ No newline at end of file diff --git a/bower.json b/bower.json new file mode 100644 index 00000000..a2cbe82a --- /dev/null +++ b/bower.json @@ -0,0 +1,16 @@ +{ + "name": "orderCloud", + "version": "2.1.0", + "devDependencies": { + "angular": "~1.3.0-rc.4", + "angular-mocks": "~1.3.0-rc.4", + "bootstrap": "~3.1", + "angular-bootstrap": "~0.10.0", + "angular-ui-router": "~0.2", + "ambient": "~1.2.2", + "angular-animate": "~1.3.13", + "angular-cookies": "~1.3.13", + "angularjs-toaster": "~0.4.10" + }, + "dependencies": {} +} diff --git a/build.config.js b/build.config.js new file mode 100644 index 00000000..f688b1b3 --- /dev/null +++ b/build.config.js @@ -0,0 +1,82 @@ +/** + * This file/module contains all configuration for the build process. + */ +module.exports = { + /** + * The `build_dir` folder is where our projects are compiled during + * development and the `compile_dir` folder is where our app resides once it's + * completely built. + */ + build_dir: 'build', + compile_dir: 'compile', + + /** + * This is a collection of file patterns that refer to our app code (the + * stuff in `src/`). These file paths are used in the configuration of + * build tasks. `js` is all project javascript, less tests. `ctpl` contains + * our reusable components' (`src/common`) template HTML files, while + * `atpl` contains the same, but for our app's code. `html` is just our + * main HTML file, `less` is our main stylesheet, and `unit` contains our + * app's unit tests. + */ + app_files: { + js: [ 'src/**/*.js', '!src/**/*.spec.js', '!src/assets/**/*.js' ], + jsunit: [ 'src/**/*.spec.js' ], + + atpl: [ 'src/app/**/*.tpl.html' ], + ctpl: [ 'src/common/**/*.tpl.html' ], + + html: [ 'src/index.html' ], + less: 'src/less/main.less', + import_less: [ + 'vendor/bootstrap/less/bootstrap.less', + 'vendor/ambient/less/ambient.less', + 'vendor/angularjs-toaster/toaster.css', + 'src/app/**/*.less' + ] + }, + + /** + * This is a collection of files used during testing only. + */ + test_files: { + js: [ + 'vendor/angular-mocks/angular-mocks.js' + ] + }, + + /** + * This is the same as `app_files`, except it contains patterns that + * reference vendor code (`vendor/`) that we need to place into the build + * process somewhere. While the `app_files` property ensures all + * standardized files are collected for compilation, it is the user's job + * to ensure non-standardized (i.e. vendor-related) files are handled + * appropriately in `vendor_files.js`. + * + * The `vendor_files.js` property holds files to be automatically + * concatenated and minified with our project source files. + * + * The `vendor_files.css` property holds any CSS files to be automatically + * included in our app. + * + * The `vendor_files.assets` property holds any assets to be copied along + * with our app's assets. This structure is flattened, so it is not + * recommended that you use wildcards. + */ + vendor_files: { + js: [ + 'vendor/angular/angular.js', + 'vendor/angular-animate/angular-animate.min.js', + 'vendor/angular-resource/angular-resource.js', + 'vendor/angular-cookies/angular-cookies.js', + 'vendor/angular-bootstrap/ui-bootstrap-tpls.js', + 'vendor/angular-ui-router/release/angular-ui-router.js', + 'vendor/angularjs-toaster/toaster.js', + 'vendor/jquery/dist/jquery.min.js' + ], + css: [ + ], + assets: [ + ] + } +}; diff --git a/changelog.tpl b/changelog.tpl new file mode 100644 index 00000000..c0274e4a --- /dev/null +++ b/changelog.tpl @@ -0,0 +1,23 @@ + +# <%= version%> (<%= today%>) + +<% if (_(changelog.feat).size() > 0) { %> ## Features +<% _(changelog.feat).forEach(function(changes, scope) { %> +- **<%= scope%>:** + <% changes.forEach(function(change) { %> - <%= change.msg%> (<%= helpers.commitLink(change.sha1) %>) + <% }); %> +<% }); %> <% } %> + +<% if (_(changelog.fix).size() > 0) { %> ## Fixes +<% _(changelog.fix).forEach(function(changes, scope) { %> +- **<%= scope%>:** + <% changes.forEach(function(change) { %> - <%= change.msg%> (<%= helpers.commitLink(change.sha1) %>) + <% }); %> +<% }); %> <% } %> + +<% if (_(changelog.breaking).size() > 0) { %> ## Breaking Changes +<% _(changelog.breaking).forEach(function(changes, scope) { %> +- **<%= scope%>:** + <% changes.forEach(function(change) { %> <%= change.msg%> + <% }); %> +<% }); %> <% } %> diff --git a/karma/karma-unit.tpl.js b/karma/karma-unit.tpl.js new file mode 100644 index 00000000..efaf4149 --- /dev/null +++ b/karma/karma-unit.tpl.js @@ -0,0 +1,25 @@ +module.exports = function ( karma ) { + karma.set({ + basePath: "../", + files: [ + <% scripts.forEach( function ( file ) { %>"<%= file %>", + <% }); %>, + "src/**/*.js" + ], + exclude: [ + "src/assets/**/*.js" + ], + frameworks: [ 'jasmine' ], + plugins: [ 'karma-jasmine', 'karma-firefox-launcher'], + preprocessors: { }, + reporters: 'dots', + port: 9018, + runnerPort: 9100, + urlRoot: "/", + autoWatch: true, + browsers: [ + 'Firefox' + ] + }); +}; + diff --git a/module.prefix b/module.prefix new file mode 100644 index 00000000..c52d9b72 --- /dev/null +++ b/module.prefix @@ -0,0 +1 @@ +(function ( window, angular, undefined ) { diff --git a/module.suffix b/module.suffix new file mode 100644 index 00000000..f6354bac --- /dev/null +++ b/module.suffix @@ -0,0 +1 @@ +})( window, window.angular ); diff --git a/package.json b/package.json new file mode 100644 index 00000000..ef5ef29b --- /dev/null +++ b/package.json @@ -0,0 +1,35 @@ +{ + "author": "Four51, Inc.", + "name": "OrderCloud", + "version": "0.0.1", + "homepage": "https://github.com/Four51/OrderCloud", + "licenses": { + "type": "MIT", + "url": "https://raw.github.com/Four51/OrderCloud/master/LICENSE" + }, + "bugs": "https://github.com/Four51/OrderCloud/issues", + "repository": { + "type": "git", + "url": "git@github.com:Four51/OrderCloud.git" + }, + "dependencies": {}, + "devDependencies": { + "grunt": "~0.4.1", + "grunt-autoprefixer": "^2.2.0", + "grunt-bump": "0.0.6", + "grunt-contrib-clean": "^0.4.1", + "grunt-contrib-concat": "^0.3.0", + "grunt-contrib-copy": "^0.4.1", + "grunt-contrib-less": "^0.11.4", + "grunt-contrib-uglify": "^0.2.7", + "grunt-contrib-watch": "^0.4.4", + "grunt-conventional-changelog": "^0.1.2", + "grunt-html2js": "^0.1.9", + "grunt-karma": "^0.8.3", + "grunt-less-imports": "^1.1.0", + "grunt-ng-annotate": "^0.9.2", + "karma": "^0.12.31", + "karma-firefox-launcher": "^0.1.4", + "karma-jasmine": "^0.1.5" + } +} diff --git a/src/README.md b/src/README.md new file mode 100644 index 00000000..80c247f9 --- /dev/null +++ b/src/README.md @@ -0,0 +1,48 @@ +# The `src` Directory + +## Overview + +The `src/` directory contains all code used in the application along with all +tests of such code. + +``` +src/ + |- app/ + | |- about/ + | |- home/ + | |- app.js + | |- app.spec.js + |- assets/ + |- common/ + | |- plusOne/ + |- less/ + | |- main.less + | |- variables.less + |- index.html +``` + +- `src/app/` - application-specific code, i.e. code not likely to be reused in + another application. [Read more »](app/README.md) +- `src/assets/` - static files like fonts and images. + [Read more »](assets/README.md) +- `src/common/` - third-party libraries or components likely to be reused in + another application. [Read more »](common/README.md) +- `src/less/` - LESS CSS files. [Read more »](less/README.md) +- `src/index.html` - this is the HTML document of the single-page application. + See below. + +See each directory for a detailed explanation. + +## `index.html` + +The `index.html` file is the HTML document of the single-page application (SPA) +that should contain all markup that applies to everything in the app, such as +the header and footer. It declares with `ngApp` that this is `ngBoilerplate`, +specifies the main `AppCtrl` controller, and contains the `ngView` directive +into which route templates are placed. + +Unlike any other HTML document (e.g. the templates), `index.html` is compiled as +a Grunt template, so variables from `Gruntfile.js` and `package.json` can be +referenced from within it. Changing `name` in `package.json` from +"ng-boilerplate" will rename the resultant CSS and JavaScript placed in `build/`, +so this HTML references them by variable for convenience. diff --git a/src/app/README.md b/src/app/README.md new file mode 100644 index 00000000..4332035c --- /dev/null +++ b/src/app/README.md @@ -0,0 +1,94 @@ +# The `src/app` Directory + +## Overview + +``` +src/ + |- app/ + | |- home/ + | |- about/ + | |- app.js + | |- app.spec.js +``` + +The `src/app` directory contains all code specific to this application. Apart +from `app.js` and its accompanying tests (discussed below), this directory is +filled with subdirectories corresponding to high-level sections of the +application, often corresponding to top-level routes. Each directory can have as +many subdirectories as it needs, and the build system will understand what to +do. For example, a top-level route might be "products", which would be a folder +within the `src/app` directory that conceptually corresponds to the top-level +route `/products`, though this is in no way enforced. Products may then have +subdirectories for "create", "view", "search", etc. The "view" submodule may +then define a route of `/products/:id`, ad infinitum. + +As `ngBoilerplate` is quite minimal, take a look at the two provided submodules +to gain a better understanding of how these are used as well as to get a +glimpse of how powerful this simple construct can be. + +## `app.js` + +This is our main app configuration file. It kickstarts the whole process by +requiring all the modules from `src/app` that we need. We must load these now to +ensure the routes are loaded. If as in our "products" example there are +subroutes, we only require the top-level module, and allow the submodules to +require their own submodules. + +As a matter of course, we also require the template modules that are generated +during the build. + +However, the modules from `src/common` should be required by the app +submodules that need them to ensure proper dependency handling. These are +app-wide dependencies that are required to assemble your app. + +```js +angular.module( 'ngBoilerplate', [ + 'templates-app', + 'templates-common', + 'ngBoilerplate.home', + 'ngBoilerplate.about' + 'ui.router', + 'ui.route' +]) +``` + +With app modules broken down in this way, all routing is performed by the +submodules we include, as that is where our app's functionality is really +defined. So all we need to do in `app.js` is specify a default route to follow, +which route of course is defined in a submodule. In this case, our `home` module +is where we want to start, which has a defined route for `/home` in +`src/app/home/home.js`. + +```js +.config( function myAppConfig ( $stateProvider, $urlRouterProvider ) { + $urlRouterProvider.otherwise( '/home' ); +}) +``` + +Use the main applications run method to execute any code after services +have been instantiated. + +```js +.run( function run () { +}) +``` + +And then we define our main application controller. This is a good place for logic +not specific to the template or route, such as menu logic or page title wiring. + +```js +.controller( 'AppCtrl', function AppCtrl ( $scope, $location ) { + $scope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams){ + if ( angular.isDefined( toState.data.pageTitle ) ) { + $scope.pageTitle = toState.data.pageTitle + ' | ngBoilerplate' ; + } + }); +}) +``` + +### Testing + +One of the design philosophies of `ngBoilerplate` is that tests should exist +alongside the code they test and that the build system should be smart enough to +know the difference and react accordingly. As such, the unit test for `app.js` +is `app.spec.js`, though it is quite minimal. diff --git a/src/app/app.js b/src/app/app.js new file mode 100644 index 00000000..2ed5e805 --- /dev/null +++ b/src/app/app.js @@ -0,0 +1,47 @@ +angular.module( 'orderCloud', [ + 'templates-app', + 'templates-common', + 'orderCloud.home', + 'ui.router' +]) + + .config(Routing) + .config(ErrorHandling) + .constant('appname', 'oc') + .controller( 'AppCtrl', AppCtrl) + +; + +function AppCtrl($scope, $location) { + $scope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams){ + if ( angular.isDefined( toState.data.pageTitle ) ) { + $scope.pageTitle = 'OrderCloud | ' + toState.data.pageTitle; + } + }); +} + +function Routing($stateProvider, $urlRouterProvider) { + $urlRouterProvider.otherwise( '/home' ); +} + +function ErrorHandling($provide) { + $provide.decorator('$exceptionHandler', handler); + + function handler($delegate, $injector) { + return function $broadcastingExceptionHandler(ex, cause) { + ex.status != 500 ? + $delegate(ex, cause) : + (function() { + try { + //TODO: implement track js + console.log(JSON.stringify(ex)); + //trackJs.error("API: " + JSON.stringify(ex)); + } + catch (x) { + console.log(JSON.stringify(ex)); + } + })(); + $injector.get('$rootScope').$broadcast('exception', ex, cause); + } + } +} \ No newline at end of file diff --git a/src/app/app.spec.js b/src/app/app.spec.js new file mode 100644 index 00000000..8275aa13 --- /dev/null +++ b/src/app/app.spec.js @@ -0,0 +1,7 @@ +describe( 'AppCtrl', function() { + beforeEach( module( 'orderCloud' ) ); + + it( 'Our first test', function() { + expect(true).toBeTruthy(); + }); +}); diff --git a/src/app/home/README.md b/src/app/home/README.md new file mode 100644 index 00000000..8caf617d --- /dev/null +++ b/src/app/home/README.md @@ -0,0 +1,73 @@ +# The `src/app/home` Directory + +## Overview + +``` +src/ + |- app/ + | |- home/ + | | |- home.js + | | |- home.less + | | |- home.spec.js + | | |- home.tpl.html +``` + +- `home.js` - defines the module. +- `home.less` - module-specific styles; this file is imported into + `src/less/main.less` manually by the developer. +- `home.spec.js` - module unit tests. +- `home.tpl.html` - the route template. + +## `home.js` + +This boilerplate is too simple to demonstrate it, but `src/app/home` could have +several sub-folders representing additional modules that would then be listed +as dependencies of this one. For example, a `note` section could have the +submodules `note.create`, `note.delete`, `note.search`, etc. + +Regardless, so long as dependencies are managed correctly, the build process +will automatically take take of the rest. + +The dependencies block is also where component dependencies should be +specified, as shown below. + +```js +angular.module( 'ngBoilerplate.home', [ + 'ui.router', + 'titleService', + 'plusOne' +]) +``` + +Each section or module of the site can also have its own routes. AngularJS will +handle ensuring they are all available at run-time, but splitting it this way +makes each module more self-contained. We use [ui-router](https://github.com/angular-ui/ui-router) to create +a state for our 'home' page. We set the url we'd like to see in the address bar +as well as the controller and template file to load. Specifying "main" as our view +means the controller and template will be loaded into the
element +of the root template (aka index.html). Read more over at the [ui-router wiki](https://github.com/angular-ui/ui-router/wiki). +Finally we add a custom data property, pageTitle, which will be used to set the page's +title (see the app.js controller). + +```js +.config(function config( $stateProvider ) { + $stateProvider.state( 'home', { + url: '/home', + views: { + "main": { + controller: 'HomeCtrl', + templateUrl: 'home/home.tpl.html' + } + }, + data:{ pageTitle: 'Home' } + }); +}) +``` + +And of course we define a controller for our route, though in this case it does +nothing. + +```js +.controller( 'HomeCtrl', function HomeController( $scope ) { +}) +``` diff --git a/src/app/home/home.js b/src/app/home/home.js new file mode 100644 index 00000000..47a6e546 --- /dev/null +++ b/src/app/home/home.js @@ -0,0 +1,34 @@ +/** + * Each section of the site has its own module. It probably also has + * submodules, though this boilerplate is too simple to demonstrate it. Within + * `src/app/home`, however, could exist several additional folders representing + * additional modules that would then be listed as dependencies of this one. + * For example, a `note` section could have the submodules `note.create`, + * `note.delete`, `note.edit`, etc. + * + * Regardless, so long as dependencies are managed correctly, the build process + * will automatically take take of the rest. + * + * The dependencies block here is also where component dependencies should be + * specified, as shown below. + */ +angular.module( 'orderCloud.home', [ + 'ui.router' +]) + +.config(Config) + +.controller( 'HomeCtrl', HomeController) + +; + +function Config( $stateProvider ) { + $stateProvider.state( 'home', { + url: '/home', + controller: 'HomeCtrl', + templateUrl: 'home/home.tpl.html', + data:{ pageTitle: 'Home' } + }); +} + +function HomeController( $scope ) { } diff --git a/src/app/home/home.less b/src/app/home/home.less new file mode 100644 index 00000000..e69de29b diff --git a/src/app/home/home.spec.js b/src/app/home/home.spec.js new file mode 100644 index 00000000..00372a22 --- /dev/null +++ b/src/app/home/home.spec.js @@ -0,0 +1,14 @@ +/** + * Tests sit right alongside the file they are testing, which is more intuitive + * and portable than separating `src` and `test` directories. Additionally, the + * build process will exclude all `.spec.js` files from the build + * automatically. + */ +describe( 'home section', function() { + beforeEach( module( 'orderCloud.home' ) ); + + it( 'should have a dummy test', function() { + expect( true ).toBeTruthy(); + }); +}); + diff --git a/src/app/home/home.tpl.html b/src/app/home/home.tpl.html new file mode 100644 index 00000000..fe44db29 --- /dev/null +++ b/src/app/home/home.tpl.html @@ -0,0 +1,4 @@ +
+

OrderCloud Seed

+

Everything you need to kickstart AngularJS projects for OrderCloud: a best-practice directory structure, an intelligent build system, and the best web design libraries around.

+
diff --git a/src/app/variables.less b/src/app/variables.less new file mode 100644 index 00000000..e69bde85 --- /dev/null +++ b/src/app/variables.less @@ -0,0 +1,4 @@ +/** + * These are the variables used throughout the application. This is where + * overwrites that are not specific to components should be maintained. + */ \ No newline at end of file diff --git a/src/assets/README.md b/src/assets/README.md new file mode 100644 index 00000000..3040eacd --- /dev/null +++ b/src/assets/README.md @@ -0,0 +1,4 @@ +# The `src/assets` Directory + +There's really not much to say here. Every file in this directory is recursively transferred to `dist/assets/`. + diff --git a/src/common/README.md b/src/common/README.md new file mode 100644 index 00000000..2c68a757 --- /dev/null +++ b/src/common/README.md @@ -0,0 +1,24 @@ +# The `src/common/` Directory + +The `src/common/` directory houses internal and third-party re-usable +components. Essentially, this folder is for everything that isn't completely +specific to this application. + +Each component resides in its own directory that may then be structured any way +the developer desires. The build system will read all `*.js` files that do not +end in `.spec.js` as source files to be included in the final build, all +`*.spec.js` files as unit tests to be executed, and all `*.tpl.html` files as +templates to compiled into the `$templateCache`. There is currently no way to +handle components that do not meet this pattern. + +``` +src/ + |- common/ + | |- plusOne/ +``` + +- `plusOne` - a simple directive to load a Google +1 Button on an element. + +Every component contained here should be drag-and-drop reusable in any other +project; they should depend on no other components that aren't similarly +drag-and-drop reusable. diff --git a/src/index.html b/src/index.html new file mode 100644 index 00000000..1344d46f --- /dev/null +++ b/src/index.html @@ -0,0 +1,16 @@ + + + + + + + <% styles.forEach( function ( file ) { %> + <% }); %> + + + +
+ <% scripts.forEach( function ( file ) { %> + <% }); %> + + diff --git a/src/less/README.md b/src/less/README.md new file mode 100644 index 00000000..a7673152 --- /dev/null +++ b/src/less/README.md @@ -0,0 +1,28 @@ +# The `src/less` Directory + +This folder is actually fairly self-explanatory: it contains your LESS/CSS files to be compiled during the build. +The only important thing to note is that *only* `main.less` will be processed during the build, meaning that all +other stylesheets must be *imported* into that one. + +This should operate somewhat like the routing; the `main.less` file contains all of the site-wide styles, while +any styles that are route-specific should be imported into here from LESS files kept alongside the JavaScript +and HTML sources of that component. For example, the `home` section of the site has some custom styles, which +are imported like so: + +```css +@import '../app/home/home.less'; +``` + +The same principal, though not demonstrated in the code, would also apply to reusable components. CSS or LESS +files from external components would also be imported. If, for example, we had a Twitter feed directive with +an accompanying template and style, we would similarly import it: + +```css +@import '../common/twitterFeed/twitterFeedDirective.less'; +``` + +Using this decentralized approach for all our code (JavaScript, HTML, and CSS) creates a framework where a +component's directory can be dragged and dropped into *any other project* and it will "just work". + +I would like to eventually automate the importing during the build so that manually importing it here would no +longer be required, but more thought must be put in to whether this is the best approach. diff --git a/src/less/main.less b/src/less/main.less new file mode 100644 index 00000000..36a31687 --- /dev/null +++ b/src/less/main.less @@ -0,0 +1,246 @@ +// This file was generated by the grunt-less-imports task in the build process. Do not alter this file, any changes you make will be overwritten the next time you build. + +/* + * Toastr + * Version 2.0.1 + * Copyright 2012 John Papa and Hans Fjällemark. + * All Rights Reserved. + * Use, reproduction, distribution, and modification of this code is subject to the terms and + * conditions of the MIT license, available at http://www.opensource.org/licenses/mit-license.php + * + * Author: John Papa and Hans Fjällemark + * Project: https://github.com/CodeSeven/toastr + */ +.toast-title { + font-weight: bold; +} +.toast-message { + -ms-word-wrap: break-word; + word-wrap: break-word; +} +.toast-message a, +.toast-message label { + color: #ffffff; +} +.toast-message a:hover { + color: #cccccc; + text-decoration: none; +} + +.toast-close-button { + position: relative; + right: -0.3em; + top: -0.3em; + float: right; + font-size: 20px; + font-weight: bold; + color: #ffffff; + -webkit-text-shadow: 0 1px 0 #ffffff; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.8; + -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=80); + filter: alpha(opacity=80); +} +.toast-close-button:hover, +.toast-close-button:focus { + color: #000000; + text-decoration: none; + cursor: pointer; + opacity: 0.4; + -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=40); + filter: alpha(opacity=40); +} + +/*Additional properties for button version + iOS requires the button element instead of an anchor tag. + If you want the anchor version, it requires `href="#"`.*/ +button.toast-close-button { + padding: 0; + cursor: pointer; + background: transparent; + border: 0; + -webkit-appearance: none; +} +.toast-top-full-width { + top: 0; + right: 0; + width: 100%; +} +.toast-bottom-full-width { + bottom: 0; + right: 0; + width: 100%; +} +.toast-top-left { + top: 12px; + left: 12px; +} +.toast-top-center { + top: 12px; +} +.toast-top-right { + top: 12px; + right: 12px; +} +.toast-bottom-right { + right: 12px; + bottom: 12px; +} +.toast-bottom-center { + bottom: 12px; +} +.toast-bottom-left { + bottom: 12px; + left: 12px; +} +.toast-center { + top: 45%; +} +#toast-container { + position: fixed; + z-index: 999999; + /*overrides*/ + +} +#toast-container.toast-center, +#toast-container.toast-top-center, +#toast-container.toast-bottom-center{ + width: 100%; + pointer-events: none; +} +#toast-container.toast-center > div, +#toast-container.toast-top-center > div, +#toast-container.toast-bottom-center > div{ + margin: auto; + pointer-events: auto; +} +#toast-container.toast-center > button, +#toast-container.toast-top-cente > button, +#toast-container.toast-bottom-center > button{ + pointer-events: auto; +} +#toast-container * { + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} +#toast-container > div { + margin: 0 0 6px; + padding: 15px 15px 15px 50px; + width: 300px; + -moz-border-radius: 3px 3px 3px 3px; + -webkit-border-radius: 3px 3px 3px 3px; + border-radius: 3px 3px 3px 3px; + background-position: 15px center; + background-repeat: no-repeat; + -moz-box-shadow: 0 0 12px #999999; + -webkit-box-shadow: 0 0 12px #999999; + box-shadow: 0 0 12px #999999; + color: #ffffff; + opacity: 0.8; + -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=80); + filter: alpha(opacity=80); +} +#toast-container > :hover { + -moz-box-shadow: 0 0 12px #000000; + -webkit-box-shadow: 0 0 12px #000000; + box-shadow: 0 0 12px #000000; + opacity: 1; + -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100); + filter: alpha(opacity=100); + cursor: pointer; +} +#toast-container > .toast-info { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVEhLtZa9SgNBEMc9sUxxRcoUKSzSWIhXpFMhhYWFhaBg4yPYiWCXZxBLERsLRS3EQkEfwCKdjWJAwSKCgoKCcudv4O5YLrt7EzgXhiU3/4+b2ckmwVjJSpKkQ6wAi4gwhT+z3wRBcEz0yjSseUTrcRyfsHsXmD0AmbHOC9Ii8VImnuXBPglHpQ5wwSVM7sNnTG7Za4JwDdCjxyAiH3nyA2mtaTJufiDZ5dCaqlItILh1NHatfN5skvjx9Z38m69CgzuXmZgVrPIGE763Jx9qKsRozWYw6xOHdER+nn2KkO+Bb+UV5CBN6WC6QtBgbRVozrahAbmm6HtUsgtPC19tFdxXZYBOfkbmFJ1VaHA1VAHjd0pp70oTZzvR+EVrx2Ygfdsq6eu55BHYR8hlcki+n+kERUFG8BrA0BwjeAv2M8WLQBtcy+SD6fNsmnB3AlBLrgTtVW1c2QN4bVWLATaIS60J2Du5y1TiJgjSBvFVZgTmwCU+dAZFoPxGEEs8nyHC9Bwe2GvEJv2WXZb0vjdyFT4Cxk3e/kIqlOGoVLwwPevpYHT+00T+hWwXDf4AJAOUqWcDhbwAAAAASUVORK5CYII=") !important; +} +#toast-container > .toast-wait { + background-image: url("data:image/gif;base64,R0lGODlhIAAgAIQAAAQCBISGhMzKzERCROTm5CQiJKyurHx+fPz+/ExOTOzu7Dw+PIyOjCwqLFRWVAwKDIyKjMzOzOzq7CQmJLy6vFRSVPTy9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJCQAXACwAAAAAIAAgAAAF3eAljmRpnmh6VRSVqLDpIDTixOdUlFSNUDhSQUAT7ES9GnD0SFQAKWItMqr4bqKHVPDI+WiTkaOFFVlrFe83rDrT0qeIjwrT0iLdU0GOiBxhAA4VeSk6QYeIOAsQEAuJKgw+EI8nA18IA48JBAQvFxCXDI8SNAQikV+iiaQIpheWX5mJmxKeF6g0qpQmA4yOu8C7EwYWCgZswRcTFj4KyMAGlwYxDwcHhCXMXxYxBzQHKNo+3DDeCOAn0V/TddbYJA0K48gAEAFQicMWFsfwNA3JSgAIAAFfwIMIL4QAACH5BAkJABoALAAAAAAgACAAhAQCBIyKjERCRMzOzCQiJPTy9DQyNGRmZMTCxOTm5CwqLHx+fBQWFJyenNTW1Pz6/Dw6PGxubAwKDIyOjNTS1CQmJCwuLPz+/Dw+PHRydAAAAAAAAAAAAAAAAAAAAAAAAAXboCaOZGmeaKoxWcSosMkk15W8cZ7VdZaXkcEgQtrxfD9RhHchima1GwlCGUBSFCaFxMrgRtnLFhWujWHhs2nJc8KoVlWGQnEn7/i8XgOwWAB7JwoONQ4KgSQAZRcOgHgSCwsSIhZMNRZ5CzULIgaWF5h4mhecfIQ8jXmQkiODhYeIiRYGjrG2PxgBARi3IhNMAbcCnwI5BAQpAZ8TIwK6vCQVDwUVKL+WzAANTA210g/VJ8OWxQefByQE4dZMzBoInwh4zrtgn2p725YNthUFTNRuGYB3AYGBHCEAACH5BAkJAB0ALAAAAAAgACAAhAQCBISChFRWVMzKzCQiJOTm5GxqbCwuLJSWlPz6/NTW1AwODJSSlGRmZCwqLOzu7HR2dDQ2NAQGBISGhFxaXNTS1CQmJOzq7GxubDQyNKSmpPz+/Nza3AAAAAAAAAAAAAXfYCeOZGmeaKqurHBdAiuP17Zdc0lMAVHWt9yI8LA9fCPB4xEjARoNSWpis01kBpshFahurqzsZosiGpErScMAUO0maKF8Tq/bTQCIQgFp30cQXhB1BHEcXhx0FgkJFiOHVYlzi42AgoRxeRx8fn+en3UABwedKgsBAwMBCygOCjYKDisLFV4VrCUAtVUKpSZdXl8mB8EbByQWcQPFAyYZxccdB7sV0cvBzbmvvG0LBV4FrFTBYCWuNhyyHRTFFB20trh4BxmdYl4YIqepq0IRxRE+IfDCAFQHARo0NGERAgAh+QQJCQAgACwAAAAAIAAgAIUEAgSEgoRMTkzMyswcHhzk5uR0cnQUFhRcXlwsKiz09vQMCgyMiozU1tQkJiR8fnxkZmT8/vwEBgSEhoRcWlzU0tQkIiT08vR0dnQcGhxkYmQ0MjT8+vwMDgyMjozc2twAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG+UCQcEgsGo/IpHLJXDweC6Z0+IhEHlOjRGIMWLHZoUZx0RQlAajxkFFKFFYFl5m5KNpIySU+X2bIBEoQZBBZGQdMElFhjI2Oj5AgHQEDAw8dQxYeDBaNHRVWVhWYCXsRFwmMXqFWEyAerB6MA6xWA6+xs7URt6VWqIwTu64gDh4eDp6goaORQ5OVAZjO1EgEGhB4RwAYDQ0YAEwIcBEKFEgYrBhLBORxgUYfrB9LELuF8fNDAAaVBuEg7NXCVyRdqHVCGLBiIIQAB1Yc4BXh9uEbwAXuyi2iQI7DuSwHdiFqCEGDtizLRFUDsaGAlQIbVoJYIEDAIiZBAAAh+QQJCQAbACwAAAAAIAAgAIQEAgSMioxcWlz08vQcHhysqqwMDgx8enwsKiykoqRkZmT8+vzEwsQMCgyUlpQkJiS0srQEBgSMjoxcXlz09vQkIiSsrqwUEhQ0MjRsamz8/vwAAAAAAAAAAAAAAAAAAAAF7+AmjmRpnmiqruz2PG0sIssCj4CQJAIgj4/abRNJaI6agu9kCAQaphdJgEQKUIFjgGWsahJYLdf7RTWfLKr3+jsBClVlG5Xb9eb4fImgUBBKDVB4ExRHFGwbGRQLGXMEhUgUfw2QC4IyCmSNDQtHlm2ZXgoiGQsUjW0EnUgLfyKBeYSeiHojfH61uS0GBisVEgEVLRcWRxAXKAgDRwMILMVIECgSVRIrBmS9JtRI1iMVBweuGxerSNolyszOIhjLGs0jEFXSKA8SEkMbcEgWIxfzNBxrw6AKgxIGkM05UOWALhERHJhysOThBgAVWYQAACH5BAkJABkALAAAAAAgACAAhAQGBIyKjERCRMzOzCwuLGRiZPz6/OTm5AwODLSytFRSVNTW1Dw6PHx6fAwKDJSSlERGRNTS1DQyNGxqbPz+/BQSFLy6vFRWVNza3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAXqYCaO5FgFwxBUZeu61ULNFMa+eBvQdJD/owFvFhkBBAwHsBQZUooZyWF2YOQkBNJu6ANMaQeli0AxSEwymi0DcUJeEgPlbEJFAghRe/h+Eeg/Dl9UYks5DF9VhksOAgKFi5GSSwh5kzgVCXIJNxknD5aSCTwJIw8zD5MITpanFKmSCHI8NxUPoJejNKWXLZkznL0vCJ3CxsckDpA/ChYJFzkTBgYTSxc80C4OswbLLhY8Fi/bMwYAJVgl4DTiL9LUJADrFuci1zTZLwD1IwU8BSQuWLCQb1EDHg2QiSDALYvCDAISJLDy8FIIACH5BAkJAB4ALAAAAAAgACAAhAQGBISGhFRSVNTW1CQiJKyqrGRmZOzu7CwuLIyOjGxubPz6/BQSFGRiZOTi5CwqLLy6vDQ2NIyKjFRWVCQmJKyurGxqbPT29DQyNJSSlHRydPz+/BQWFOzq7AAAAAAAAAXhoCeOJElYClGubOs117YtjWuvxCLLi3qbhc6h4FPsdorfiNI5dige43GT9AAkHUcCwCpMNxVP7tgTJY4J1uF7EBl0M8Ooueuo2SOCIkVa11kVX2E2EmgsFH4yBz4uAAkdHVstBAUHQ4xKmZqbnJ2bAhAQAiURGJ4eE0cTIxgzpp0QRxCsrp6xO7MjpaepO6unKxOhv8DFxsfIJBwaChw2DAkZDEocDjIOzi0ZMhlKUjIaLtsb3T8aR+EtDBkJ0yQUBQVQI9XX2ZsDMgMlyxr3mzE2XEgmotCGAARFIHiQ0FMIACH5BAkJABgALAAAAAAgACAAhAQCBISGhDw+POTi5CwuLLS2tPTy9BQSFJyenGRiZDQ2NIyOjLy+vPz6/BweHIyKjFRSVOzq7DQyNLy6vBQWFHRydDw6PPz+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXXICaOZHkcZaquIjVd10SxtFrAcFGrVhBYIwoON9uNAsOA6DCEFTEKBEKxEjQvAtELNxkpGrAGNfW4Plpb2QgxRKjKzfPoVGLj3CnLNUv7hscpSDhKOxJSgDwPP0ZGAACMjAQFDQYFBJA0BAZDBpeYGBQVFUU3TV2YFAMwAzNgTQ2PkBVDFRiuQ7CYszi1pUOnkKmrM5qcnqiiTwQTDQ2Wn9DR0tPUfRKQEBEREDQSFw3XRhEwEd3f4TvjF+XWKgJ8JNnb0QkwCdUlCzAL+CQODAwc9BtIMAQAOw==") !important; +} +#toast-container > .toast-error { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHOSURBVEhLrZa/SgNBEMZzh0WKCClSCKaIYOED+AAKeQQLG8HWztLCImBrYadgIdY+gIKNYkBFSwu7CAoqCgkkoGBI/E28PdbLZmeDLgzZzcx83/zZ2SSXC1j9fr+I1Hq93g2yxH4iwM1vkoBWAdxCmpzTxfkN2RcyZNaHFIkSo10+8kgxkXIURV5HGxTmFuc75B2RfQkpxHG8aAgaAFa0tAHqYFfQ7Iwe2yhODk8+J4C7yAoRTWI3w/4klGRgR4lO7Rpn9+gvMyWp+uxFh8+H+ARlgN1nJuJuQAYvNkEnwGFck18Er4q3egEc/oO+mhLdKgRyhdNFiacC0rlOCbhNVz4H9FnAYgDBvU3QIioZlJFLJtsoHYRDfiZoUyIxqCtRpVlANq0EU4dApjrtgezPFad5S19Wgjkc0hNVnuF4HjVA6C7QrSIbylB+oZe3aHgBsqlNqKYH48jXyJKMuAbiyVJ8KzaB3eRc0pg9VwQ4niFryI68qiOi3AbjwdsfnAtk0bCjTLJKr6mrD9g8iq/S/B81hguOMlQTnVyG40wAcjnmgsCNESDrjme7wfftP4P7SP4N3CJZdvzoNyGq2c/HWOXJGsvVg+RA/k2MC/wN6I2YA2Pt8GkAAAAASUVORK5CYII=") !important; +} +#toast-container > .toast-success { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVEhLY2AYBfQMgf///3P8+/evAIgvA/FsIF+BavYDDWMBGroaSMMBiE8VC7AZDrIFaMFnii3AZTjUgsUUWUDA8OdAH6iQbQEhw4HyGsPEcKBXBIC4ARhex4G4BsjmweU1soIFaGg/WtoFZRIZdEvIMhxkCCjXIVsATV6gFGACs4Rsw0EGgIIH3QJYJgHSARQZDrWAB+jawzgs+Q2UO49D7jnRSRGoEFRILcdmEMWGI0cm0JJ2QpYA1RDvcmzJEWhABhD/pqrL0S0CWuABKgnRki9lLseS7g2AlqwHWQSKH4oKLrILpRGhEQCw2LiRUIa4lwAAAABJRU5ErkJggg==") !important; +} +#toast-container > .toast-warning { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGYSURBVEhL5ZSvTsNQFMbXZGICMYGYmJhAQIJAICYQPAACiSDB8AiICQQJT4CqQEwgJvYASAQCiZiYmJhAIBATCARJy+9rTsldd8sKu1M0+dLb057v6/lbq/2rK0mS/TRNj9cWNAKPYIJII7gIxCcQ51cvqID+GIEX8ASG4B1bK5gIZFeQfoJdEXOfgX4QAQg7kH2A65yQ87lyxb27sggkAzAuFhbbg1K2kgCkB1bVwyIR9m2L7PRPIhDUIXgGtyKw575yz3lTNs6X4JXnjV+LKM/m3MydnTbtOKIjtz6VhCBq4vSm3ncdrD2lk0VgUXSVKjVDJXJzijW1RQdsU7F77He8u68koNZTz8Oz5yGa6J3H3lZ0xYgXBK2QymlWWA+RWnYhskLBv2vmE+hBMCtbA7KX5drWyRT/2JsqZ2IvfB9Y4bWDNMFbJRFmC9E74SoS0CqulwjkC0+5bpcV1CZ8NMej4pjy0U+doDQsGyo1hzVJttIjhQ7GnBtRFN1UarUlH8F3xict+HY07rEzoUGPlWcjRFRr4/gChZgc3ZL2d8oAAAAASUVORK5CYII=") !important; +} +#toast-container.toast-top-full-width > div, +#toast-container.toast-bottom-full-width > div { + width: 96%; + margin: auto; +} +.toast { + background-color: #030303; +} +.toast-success { + background-color: #51a351; +} +.toast-error { + background-color: #bd362f; +} +.toast-info { + background-color: #2f96b4; +} +.toast-wait { + background-color: #2f96b4; +} +.toast-warning { + background-color: #f89406; +} +/*Responsive Design*/ +@media all and (max-width: 240px) { + #toast-container > div { + padding: 8px 8px 8px 50px; + width: 11em; + } + #toast-container .toast-close-button { + right: -0.2em; + top: -0.2em; +} + } +@media all and (min-width: 241px) and (max-width: 480px) { + #toast-container > div { + padding: 8px 8px 8px 50px; + width: 18em; + } + #toast-container .toast-close-button { + right: -0.2em; + top: -0.2em; +} +} +@media all and (min-width: 481px) and (max-width: 768px) { + #toast-container > div { + padding: 15px 15px 15px 50px; + width: 25em; + } +} + + /* + * AngularJS-Toaster + * Version 0.3 + */ +:not(.no-enter)#toast-container > div.ng-enter, +:not(.no-leave)#toast-container > div.ng-leave +{ + -webkit-transition: 1000ms cubic-bezier(0.250, 0.250, 0.750, 0.750) all; + -moz-transition: 1000ms cubic-bezier(0.250, 0.250, 0.750, 0.750) all; + -ms-transition: 1000ms cubic-bezier(0.250, 0.250, 0.750, 0.750) all; + -o-transition: 1000ms cubic-bezier(0.250, 0.250, 0.750, 0.750) all; + transition: 1000ms cubic-bezier(0.250, 0.250, 0.750, 0.750) all; +} + +:not(.no-enter)#toast-container > div.ng-enter.ng-enter-active, +:not(.no-leave)#toast-container > div.ng-leave { + opacity: 0.8; +} + +:not(.no-leave)#toast-container > div.ng-leave.ng-leave-active, +:not(.no-enter)#toast-container > div.ng-enter { + opacity: 0; +} + +@import (once) "..\..\vendor\bootstrap\less\bootstrap.less"; +@import (once) "..\..\vendor\ambient\less\ambient.less"; +@import (once) "..\app\home\home.less"; +@import (once) "..\app\variables.less"; diff --git a/tools.md b/tools.md new file mode 100644 index 00000000..140fb0c0 --- /dev/null +++ b/tools.md @@ -0,0 +1,213 @@ +# The Tools Used in `OrderCloud` + +## Introduction + +`OrderCloud` is standards-based, so it uses all the usual tools to manage +and develop client-side code. If you've developed modern, highly-organized +JavaScript projects before, you are probably already familiar with at least most +of these tools. What follows is a simple description of the tools of which this +project makes use and how they fit in to the `OrderCloud` picture. + +## Git + +[Git](http://git-scm.com/) is a distributed version control system. +`OrderCloud` uses git to manage its codebase. While in theory you don't have +to use Git once you download `OrderCloud`, this project makes the assumption +that you do. If you're on GitHub, I assume you already have a basic +understanding of Git, which is all you need to make effective use of this +project. You just need to be able to commit and push and junk - nothing funky. +If you're not familiar with it, check out the documentation linked to above. +GitHub also has a great [help section](https://help.github.com/). + +## Node.js & NPM + +[Node.js](http://nodejs.org) is a platform based on Chrome's JavaScript runtime, +called [V8](http://code.google.com/p/v8/). It allows you to develop all kinds of +software using the JavaScript you already know and love. + +A great feature of Node.js is its wide variety of existing libraries and tools. +As the developer community is absolutely massive and incredibly active, Node.js +has a basic package manager called NPM that you can use to install Node.js-based +software and libraries from the command line. + +While `OrderCloud` makes heavy use of Node.js behind the scenes, you as the +application developer don't need to really think about it much. Most of the +interaction with Node.js will occur through Grunt (see next section), so you +really only need to know how get the initial setup working. + +`package.json` is an NPM package description file written in JSON. It contains +basic metadata about your application, like its name, version, and dependencies. +By default, several packages are required for the build process to work; so when +you first start with `OrderCloud` you have to tell NPM to install the +packages; this is covered in detail in the [main README](README.md). Some of +the required packages are Grunt build tasks (see below), while others are +command-line tools either we (or the build system) need, like Karma, Grunt, and +Bower. + +Don't worry about knowing Node.js in order to use `OrderCloud`; Grunt is +where the magic happens. + +## Grunt.js + +[Grunt](http://gruntjs.com) is a JavaScript task runner that runs on top of +Node.js. Most importantly, Grunt brings us automation. There are lots of steps +that go into taking our manageable codebase and making it into a +production-ready website; we must gather, lint, test, annotate, and copy files +about. Instead of doing all of that manually, we write (and use others') Grunt +tasks to do things for us. + +When we want to build our site, we can just type: + +```sh +$ grunt +``` + +This will do everything needed and place our built code inside a folder called +`release/`. We can tell Grunt to watch for file changes we make +so it can re-build our site on-the-fly: + +```sh +$ grunt watch +``` + +The built files will be in `release/`. See the main [README](README.md) for more +info. + +The next time we change a source file, Grunt will re-build the changed parts of +the site. If you have a Live Reload plugin installed in your browser, it will +even auto-refresh your browser for you. + +Grunt is controlled through `Gruntfile.js`. This file is heavily documented in +the source, so I will only provide a high-altitude overview here. Also note that +unless you need to modify the build process, you don't need to know anything +else from this section. The two commands above really are all you need to know +to get started with `OrderCloud`. But for those curious or looking to go a +little more advanced, here's what you'll find. + +First, we tell Grunt which tasks we might want to use: + +```js +// ... +grunt.loadNpmTasks('grunt-recess'); +grunt.loadNpmTasks('grunt-contrib-clean'); +grunt.loadNpmTasks('grunt-contrib-copy'); +grunt.loadNpmTasks('grunt-contrib-jshint'); +// ... +``` + +Each of these tasks must already be installed. Remember the dependencies from +`package.json` that NPM installed for us? + +Then we get the opportunity to tell the tasks to behave like we want by +defining a configuration object. While we can (and do) define all sorts of +custom configuration values that we reference later on, tasks look for +configuration properties of their own name. For example, the `clean` task just +takes an array of files to delete when the task runs: + +```js +clean: [ '<%= build_dir %>', '<%= compile_dir %>' ], +``` + +In Grunt, the `<%= varName %>` is a way of re-using configuration variables. +In the `build.config.js`, we defined what `build_dir` meant: + +```js +build_dir: 'build', +``` + +When the clean task runs, it will delete the `build/` folder entirely so that +when our new build runs, we don't encounter any problems with stale or old +files. Most tasks, however, have considerably more complicated configuration +requirements, but I've tried to document what each one is doing and what the +configuration properties mean. + +After our configuration is complete, we can define some of our own tasks. For +example, we could do the build by running all of the separate tasks that we +installed from NPM and configured as above: + +```sh +$ grunt clean +$ grunt html2js +$ grunt jshint +$ grunt karma:continuous +$ grunt concat +$ grunt ngmin:dist +$ grunt uglify +$ grunt recess +$ grunt index +$ grunt copy +``` + +But how automated is that? So instead we define a composite task that executes +all that for us. The commands above make up the `default` tasks, which can be +run by typing *either* of these commands: + +```js +$ grunt +$ grunt default +``` + +We also define the `watch` task discussed earlier. This is covered in more +detail in the main (README)[README.md]. + +Grunt is the engine behind `OrderCloud`. It's the magic that makes it move. +Just getting started, you won't need to alter `Gruntfile.js` at all, but +as you get into more advanced application development, you will probably need to +add more tasks and change some steps around to make this build your own. +Hopefully, this readme and the documentation within `Gruntfile.js` (as well as +of course the documentation at gruntjs.com) will set you on the right path. + +## Bower + +[Bower](bower.io) is a package manager for the web. It's similar in many +respects to NPM, though it is significantly simpler and only contains code for +web projects, like Twitter Bootstrap and its AngularJS counterpart Angular +Bootstrap. Bower allows us to say that our app depends in some way on these +other libraries so that we can manage all of them in one simple place. + +`OrderCloud` comes with a `bower.json` file that looks something like this: + +```js +{ + "name": "OrderCloud", + "version": ".0.0.1-SNAPSHOT", + "devDependencies": { + "angular": "~1.0.7", + "angular-mocks": "~1.0.7", + "bootstrap": "~2.3.2", + "angular-bootstrap": "~0.3.0", + "angular-ui-router": "~0.0.1", + "angular-ui-utils": "~0.0.3" + }, + "dependencies": {} +} +``` + +This file is fairly self-explanatory; it gives the package name and version +(duplicated from `package.json`, but this is unavoidable) as well as a list of +dependencies our application needs in order to work. If we simply call + +```sh +$ bower install +``` + +it will read these three dependencies and install them into the `vendor/` folder +(along with any dependencies they have) so that we can use them in our app. If +we want to add a new package like AngularUI's +[ngGrid](http://angular-ui.github.io/ng-grid/), then we can tell Bower to +install that from the web, place it into the `vendor/` folder for us to use, and +then add it as a dependency to `bower.json`: + +```js +$ bower install angular-grid --save-dev +``` + +Bower can also update all of our packages for us at a later date, though that +and its many other awesome features are beyond the scope of this simple +overview. + +One last thing to note is that packages installed with Bower are not +standardized, so we cannot automatically add them to the build process; anything +installed with Bower (or placed in the `vendor/` directory manually) *must* be +added to your `build.config.js` file manually; look for the Bower libs included +in `OrderCloud` by default in there to see what I mean. From b7fcb020833e5c36c530e5c997bd7915a92e5a5f Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 16 Apr 2015 17:30:18 -0500 Subject: [PATCH 002/367] Finalizing seed requirements Part 1 --- .gitignore | 1 + Gruntfile.js | 184 ++++++++------- bower.json | 20 +- build.config.js | 31 ++- src/README.md | 17 +- src/app/README.md | 55 +++-- src/app/app.js | 45 ++-- src/app/global.less | 3 + src/app/home/README.md | 18 +- src/app/home/home.js | 26 +-- src/app/home/{ => less}/home.less | 0 src/app/home/less/variables.less | 0 src/app/home/{ => templates}/home.tpl.html | 4 +- src/app/variables.less | 5 +- src/assets/README.md | 1 + src/common/README.md | 24 -- src/index.html | 4 +- src/less/README.md | 28 --- src/less/main.less | 246 --------------------- 19 files changed, 206 insertions(+), 506 deletions(-) create mode 100644 src/app/global.less rename src/app/home/{ => less}/home.less (100%) create mode 100644 src/app/home/less/variables.less rename src/app/home/{ => templates}/home.tpl.html (67%) delete mode 100644 src/common/README.md delete mode 100644 src/less/README.md delete mode 100644 src/less/main.less diff --git a/.gitignore b/.gitignore index ee56217c..d8733b94 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ build/ compile/ node_modules/ vendor/ +temp/ \ No newline at end of file diff --git a/Gruntfile.js b/Gruntfile.js index 8575a1ba..b3891486 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1,6 +1,6 @@ module.exports = function ( grunt ) { - - /** + + /** * Load required Grunt tasks. These are installed based on the versions listed * in `package.json` when you do `npm install` in this directory. */ @@ -18,13 +18,13 @@ module.exports = function ( grunt ) { grunt.loadNpmTasks('grunt-autoprefixer'); - /** + /** * Load in our build configuration file. */ var userConfig = require( './build.config.js' ); /** - * This is the configuration object Grunt uses to give each plugin its + * This is the configuration object Grunt uses to give each plugin its * instructions. */ var taskConfig = { @@ -35,37 +35,38 @@ module.exports = function ( grunt ) { pkg: grunt.file.readJSON("package.json"), /** - * The banner is the comment that is placed at the top of our compiled + * The banner is the comment that is placed at the top of our compiled * source files. It is first processed as a Grunt template, where the `<%=` * pairs are evaluated based on this very configuration object. */ meta: { - banner: - '/**\n' + - ' * <%= pkg.name %> - v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %>\n' + - ' * <%= pkg.homepage %>\n' + - ' *\n' + - ' * Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' + - ' * Licensed <%= pkg.licenses.type %> <<%= pkg.licenses.url %>>\n' + - ' */\n' + banner: + '/**\n' + + ' * <%= pkg.name %> - v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %>\n' + + ' * <%= pkg.homepage %>\n' + + ' *\n' + + ' * Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' + + ' * Licensed <%= pkg.licenses.type %> <<%= pkg.licenses.url %>>\n' + + ' */\n' }, /** * Creates a changelog on a new version. */ - changelog: { - options: { - dest: 'CHANGELOG.md', - template: 'changelog.tpl' - } - }, + changelog: { + options: { + dest: 'CHANGELOG.md', + template: 'changelog.tpl' + } + }, /** * The directories to delete when `grunt clean` is executed. */ - clean: [ - '<%= build_dir %>', - '<%= compile_dir %>' + clean: [ + '<%= build_dir %>', + '<%= compile_dir %>', + '<%= temp_dir %>' ], /** @@ -76,24 +77,24 @@ module.exports = function ( grunt ) { copy: { build_app_assets: { files: [ - { + { src: [ '**' ], dest: '<%= build_dir %>/assets/', cwd: 'src/assets', expand: true } - ] + ] }, build_vendor_assets: { files: [ - { + { src: [ '<%= vendor_files.assets %>' ], dest: '<%= build_dir %>/assets/', cwd: '.', expand: true, flatten: true } - ] + ] }, build_appjs: { files: [ @@ -150,13 +151,12 @@ module.exports = function ( grunt ) { options: { banner: '<%= meta.banner %>' }, - src: [ - '<%= vendor_files.js %>', - 'module.prefix', - '<%= build_dir %>/src/**/*.js', - '<%= html2js.app.dest %>', - '<%= html2js.common.dest %>', - 'module.suffix' + src: [ + '<%= vendor_files.js %>', + 'module.prefix', + '<%= build_dir %>/src/**/*.js', + '<%= html2js.app.dest %>', + 'module.suffix' ], dest: '<%= compile_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.js' } @@ -193,20 +193,21 @@ module.exports = function ( grunt ) { } }, - /** - * `grunt-less-imports` handles importing of all LESS files into the src/less/main.less file. - * The app_files.import_less array in the build.config.js file drives where to look for these files. - */ - less_imports: { - build: { - options: { - banner: '// This file was generated by the grunt-less-imports task in the build process. Do not alter this file, any changes you make will be overwritten the next time you build.' - }, - files: { - 'src/less/main.less': '<%= app_files.import_less %>' - } - } - }, + /** + * `grunt-less-imports` handles importing of all LESS files into the src/less/main.less file. + * The app_files.import_less array in the build.config.js file drives where to look for these files. + */ + less_imports: { + build: { + options: { + import: 'less', + inlineCSS: false, + banner: '// This file was generated by the grunt-less-imports task in the build process. Do not alter this file, any changes you make will be overwritten the next time you build.' + }, + src: '<%= app_files.import_less %>', + dest: 'temp/imports.less' + } + }, /** * `grunt-contrib-less` handles our LESS compilation and uglification automatically. @@ -216,40 +217,45 @@ module.exports = function ( grunt ) { less: { build: { files: { - '<%= build_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.css': '<%= app_files.less %>' + '<%= build_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.css': '<%= less_imports.build.dest %>' + }, + options: { + strictImports:true } }, compile: { files: { - '<%= build_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.css': '<%= app_files.less %>' + '<%= build_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.css': '<%= less_imports.build.dest %>' }, options: { + strictImports:true, cleancss: true, compress: true } } }, - /** - * https://github.com/nDmitry/grunt-autoprefixer - * `autoprefixer` looks at the compiled CSS and adds any necessary - * browser-specific prefixes needed for newer CSS rules. The autoprefixer default - * options are set below and it is used in the build, compile, and watch tasks. - */ - autoprefixer: { - options: { - browsers: ['> 1%', 'last 2 versions', 'Firefox ESR', 'Opera 12.1'], - cascade: true, - remove: true, - diff: false, - map: false, - silent: false - }, - single_file: { - src: '<%= build_dir %>/assets/*.css', - dest: '<%= build_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.css' - } - }, + /** + * https://github.com/nDmitry/grunt-autoprefixer + * `autoprefixer` looks at the compiled CSS and adds any necessary + * browser-specific prefixes needed for newer CSS rules. The autoprefixer default + * options are set below and it is used in the build, compile, and watch tasks. + */ + //TODO:make sure this works in the compile task + autoprefixer: { + options: { + browsers: ['> 1%', 'last 2 versions', 'Safari 7'], + cascade: true, + remove: true, + diff: false, + map: false, + silent: false + }, + single_file: { + src: '<%= build_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.css', + dest: '<%= build_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.css' + } + }, /** * HTML2JS is a Grunt plugin that takes all of your template files and @@ -267,17 +273,6 @@ module.exports = function ( grunt ) { }, src: [ '<%= app_files.atpl %>' ], dest: '<%= build_dir %>/templates-app.js' - }, - - /** - * These are the templates from `src/common`. - */ - common: { - options: { - base: 'src/common' - }, - src: [ '<%= app_files.ctpl %>' ], - dest: '<%= build_dir %>/templates-common.js' } }, @@ -314,7 +309,6 @@ module.exports = function ( grunt ) { src: [ '<%= vendor_files.js %>', '<%= build_dir %>/src/**/*.js', - '<%= html2js.common.dest %>', '<%= html2js.app.dest %>', '<%= vendor_files.css %>', '<%= build_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.css' @@ -343,10 +337,9 @@ module.exports = function ( grunt ) { karmaconfig: { unit: { dir: '<%= build_dir %>', - src: [ + src: [ '<%= vendor_files.js %>', '<%= html2js.app.dest %>', - '<%= html2js.common.dest %>', '<%= test_files.js %>' ] } @@ -354,13 +347,13 @@ module.exports = function ( grunt ) { /** * And for rapid development, we have a watch set up that checks to see if - * any of the files listed below change, and then to execute the listed + * any of the files listed below change, and then to execute the listed * tasks when they do. This just saves us from having to type "grunt" into * the command-line every time we want to see what we're working on; we can * instead just leave "grunt watch" running in a background terminal. Set it * and forget it, as Ron Popeil used to tell us. * - * But we don't need the same thing to happen for all the files. + * But we don't need the same thing to happen for all the files. */ delta: { /** @@ -390,7 +383,7 @@ module.exports = function ( grunt ) { * run our unit tests. */ jssrc: { - files: [ + files: [ '<%= app_files.js %>' ], tasks: [ 'karma:unit:run', 'copy:build_appjs' ] @@ -401,7 +394,7 @@ module.exports = function ( grunt ) { * files, so this is probably not very useful. */ assets: { - files: [ + files: [ 'src/assets/**/*' ], tasks: [ 'copy:build_app_assets', 'copy:build_vendor_assets' ] @@ -419,9 +412,8 @@ module.exports = function ( grunt ) { * When our templates change, we only rewrite the template cache. */ tpls: { - files: [ - '<%= app_files.atpl %>', - '<%= app_files.ctpl %>' + files: [ + '<%= app_files.atpl %>' ], tasks: [ 'html2js' ] }, @@ -473,8 +465,8 @@ module.exports = function ( grunt ) { grunt.registerTask( 'build', [ 'clean', 'html2js', 'less_imports:build', 'less:build', 'concat:build_css', 'copy:build_app_assets', 'copy:build_vendor_assets', 'autoprefixer', - 'copy:build_appjs', 'copy:build_vendorjs', 'index:build', 'karmaconfig', - 'karma:continuous' + 'copy:build_appjs', 'copy:build_vendorjs', 'index:build', 'karmaconfig', + 'karma:continuous' ]); /** @@ -503,7 +495,7 @@ module.exports = function ( grunt ) { }); } - /** + /** * The index.html template includes the stylesheet and javascript sources * based on dynamic names calculated in this Gruntfile. This task assembles * the list into variables for the template to use and then runs the @@ -518,7 +510,7 @@ module.exports = function ( grunt ) { return file.replace( dirRE, '' ); }); - grunt.file.copy('src/index.html', this.data.dir + '/index.html', { + grunt.file.copy('src/index.html', this.data.dir + '/index.html', { process: function ( contents, path ) { return grunt.template.process( contents, { data: { @@ -538,8 +530,8 @@ module.exports = function ( grunt ) { */ grunt.registerMultiTask( 'karmaconfig', 'Process karma config templates', function () { var jsFiles = filterForJS( this.filesSrc ); - - grunt.file.copy( 'karma/karma-unit.tpl.js', grunt.config( 'build_dir' ) + '/karma-unit.js', { + + grunt.file.copy( 'karma/karma-unit.tpl.js', grunt.config( 'build_dir' ) + '/karma-unit.js', { process: function ( contents, path ) { return grunt.template.process( contents, { data: { diff --git a/bower.json b/bower.json index a2cbe82a..1aace247 100644 --- a/bower.json +++ b/bower.json @@ -1,16 +1,18 @@ { "name": "orderCloud", - "version": "2.1.0", + "version": "0.0.1", "devDependencies": { - "angular": "~1.3.0-rc.4", - "angular-mocks": "~1.3.0-rc.4", - "bootstrap": "~3.1", - "angular-bootstrap": "~0.10.0", + "angular": "~1.3.14", + "angular-mocks": "~1.3.14", + "angular-sanitize": "~1.3.14", "angular-ui-router": "~0.2", - "ambient": "~1.2.2", - "angular-animate": "~1.3.13", - "angular-cookies": "~1.3.13", - "angularjs-toaster": "~0.4.10" + "angular-messages": "~1.3.14", + "angular-animate": "~1.3.14", + "angular-touch": "~1.3.15", + "ambient": "~1.3.0", + "jquery": "~2.1.3", + "font-awesome": "~4.3.0", + "ordercloud-sdk": "~0.0.4" }, "dependencies": {} } diff --git a/build.config.js b/build.config.js index f688b1b3..3680ab7a 100644 --- a/build.config.js +++ b/build.config.js @@ -9,6 +9,7 @@ module.exports = { */ build_dir: 'build', compile_dir: 'compile', + temp_dir: 'temp', /** * This is a collection of file patterns that refer to our app code (the @@ -24,16 +25,14 @@ module.exports = { jsunit: [ 'src/**/*.spec.js' ], atpl: [ 'src/app/**/*.tpl.html' ], - ctpl: [ 'src/common/**/*.tpl.html' ], html: [ 'src/index.html' ], - less: 'src/less/main.less', - import_less: [ - 'vendor/bootstrap/less/bootstrap.less', - 'vendor/ambient/less/ambient.less', - 'vendor/angularjs-toaster/toaster.css', - 'src/app/**/*.less' - ] + import_less: [ + 'vendor/normalize-css/normalize.css', //ambient dependency + 'vendor/ambient/less/ambient.less', + 'vendor/font-awesome/less/font-awesome.less', + 'src/app/**/*.less' + ] }, /** @@ -65,14 +64,14 @@ module.exports = { */ vendor_files: { js: [ - 'vendor/angular/angular.js', - 'vendor/angular-animate/angular-animate.min.js', - 'vendor/angular-resource/angular-resource.js', - 'vendor/angular-cookies/angular-cookies.js', - 'vendor/angular-bootstrap/ui-bootstrap-tpls.js', - 'vendor/angular-ui-router/release/angular-ui-router.js', - 'vendor/angularjs-toaster/toaster.js', - 'vendor/jquery/dist/jquery.min.js' + 'vendor/angular/angular.js', + 'vendor/angular-sanitize/angular-sanitize.js', + 'vendor/angular-ui-router/release/angular-ui-router.js', + 'vendor/angular-messages/angular-messages.js', + 'vendor/angular-animate/angular-animate.js', + 'vendor/angular-touch/angular-touch.js', + 'vendor/jquery/dist/jquery.js', + 'vendor/ordercloud-sdk/dist/OrderCloudSDK.js' ], css: [ ], diff --git a/src/README.md b/src/README.md index 80c247f9..78fbf9aa 100644 --- a/src/README.md +++ b/src/README.md @@ -8,16 +8,12 @@ tests of such code. ``` src/ |- app/ - | |- about/ | |- home/ | |- app.js | |- app.spec.js - |- assets/ - |- common/ - | |- plusOne/ - |- less/ - | |- main.less + | |- global.less | |- variables.less + |- assets/ |- index.html ``` @@ -25,9 +21,6 @@ src/ another application. [Read more »](app/README.md) - `src/assets/` - static files like fonts and images. [Read more »](assets/README.md) -- `src/common/` - third-party libraries or components likely to be reused in - another application. [Read more »](common/README.md) -- `src/less/` - LESS CSS files. [Read more »](less/README.md) - `src/index.html` - this is the HTML document of the single-page application. See below. @@ -37,12 +30,12 @@ See each directory for a detailed explanation. The `index.html` file is the HTML document of the single-page application (SPA) that should contain all markup that applies to everything in the app, such as -the header and footer. It declares with `ngApp` that this is `ngBoilerplate`, -specifies the main `AppCtrl` controller, and contains the `ngView` directive +the header and footer. It declares with `ngApp` that this is `orderCloud`, +specifies the main `AppCtrl` controller, and contains the `uiView` directive into which route templates are placed. Unlike any other HTML document (e.g. the templates), `index.html` is compiled as a Grunt template, so variables from `Gruntfile.js` and `package.json` can be referenced from within it. Changing `name` in `package.json` from -"ng-boilerplate" will rename the resultant CSS and JavaScript placed in `build/`, +"orderCloud" will rename the resultant CSS and JavaScript placed in `build/`, so this HTML references them by variable for convenience. diff --git a/src/app/README.md b/src/app/README.md index 4332035c..b6e5bafb 100644 --- a/src/app/README.md +++ b/src/app/README.md @@ -22,33 +22,32 @@ route `/products`, though this is in no way enforced. Products may then have subdirectories for "create", "view", "search", etc. The "view" submodule may then define a route of `/products/:id`, ad infinitum. -As `ngBoilerplate` is quite minimal, take a look at the two provided submodules -to gain a better understanding of how these are used as well as to get a -glimpse of how powerful this simple construct can be. - ## `app.js` This is our main app configuration file. It kickstarts the whole process by -requiring all the modules from `src/app` that we need. We must load these now to -ensure the routes are loaded. If as in our "products" example there are -subroutes, we only require the top-level module, and allow the submodules to -require their own submodules. +requiring all the modules that we need. -As a matter of course, we also require the template modules that are generated -during the build. +By default, the OrderCloud AngularJS Seed includes a few useful modules written +by the AngularJS team. Along with one by the Angular-UI team called `ui.router`. +Lastly, we include the `orderCloud.sdk` module for connecting to the API. -However, the modules from `src/common` should be required by the app -submodules that need them to ensure proper dependency handling. These are -app-wide dependencies that are required to assemble your app. +We must load any modules from `src/app` now to ensure the routes are loaded. If +as in our "products" example there are subroutes, we only require the top-level +module, and allow the submodules to require their own submodules. + +As a matter of course, we also require the template module that is generated +during the build. ```js -angular.module( 'ngBoilerplate', [ - 'templates-app', - 'templates-common', - 'ngBoilerplate.home', - 'ngBoilerplate.about' - 'ui.router', - 'ui.route' +angular.module( 'orderCloud', [ + 'templates-app', + 'ngSanitize', + 'ngAnimate', + 'ui.router', + 'ngMessages', + 'ngTouch', + 'orderCloud.sdk', + 'orderCloud.home' ]) ``` @@ -80,7 +79,7 @@ not specific to the template or route, such as menu logic or page title wiring. .controller( 'AppCtrl', function AppCtrl ( $scope, $location ) { $scope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams){ if ( angular.isDefined( toState.data.pageTitle ) ) { - $scope.pageTitle = toState.data.pageTitle + ' | ngBoilerplate' ; + $scope.pageTitle = 'OrderCloud | ' + toState.data.pageTitle; } }); }) @@ -88,7 +87,19 @@ not specific to the template or route, such as menu logic or page title wiring. ### Testing -One of the design philosophies of `ngBoilerplate` is that tests should exist +One of the design philosophies of `OrderCloud-AngularJS-seed` is that tests should exist alongside the code they test and that the build system should be smart enough to know the difference and react accordingly. As such, the unit test for `app.js` is `app.spec.js`, though it is quite minimal. + +### Global application styles + +Within the `src/app/` directory we included a `global.less` and `variables.less` file. +These should be utilized for application wide LESS variables and mixins. Each component +within `src/app` will have a corresponding `less/` directory with a similar structure. +The build is smart enough to recognize any new `*.less` file types and roll them in +automatically. + +Also, because any LESS brought in from the `/vendor` (through the build.config) directory +gets rolled into the same intermediate `imports.less` file, you will be able to use +and alter those 3rd party variables/mixins. diff --git a/src/app/app.js b/src/app/app.js index 2ed5e805..82371979 100644 --- a/src/app/app.js +++ b/src/app/app.js @@ -1,47 +1,52 @@ angular.module( 'orderCloud', [ 'templates-app', - 'templates-common', - 'orderCloud.home', - 'ui.router' + 'ngSanitize', + 'ngAnimate', + 'ui.router', + 'ngMessages', + 'ngTouch', + 'orderCloud.sdk', + 'orderCloud.home' ]) - .config(Routing) - .config(ErrorHandling) - .constant('appname', 'oc') - .controller( 'AppCtrl', AppCtrl) + .config( Routing ) + .config( ErrorHandling ) + .controller( 'AppCtrl', AppCtrl ) ; -function AppCtrl($scope, $location) { - $scope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams){ +function AppCtrl( $scope ) { + $scope.$on('$stateChangeSuccess', function( event, toState, toParams, fromState, fromParams ){ if ( angular.isDefined( toState.data.pageTitle ) ) { $scope.pageTitle = 'OrderCloud | ' + toState.data.pageTitle; } }); } -function Routing($stateProvider, $urlRouterProvider) { +function Routing( $urlRouterProvider ) { $urlRouterProvider.otherwise( '/home' ); + //$locationProvider.html5Mode(true); + /*TODO: we will want html5Mode to be on; however, to do this, we also need to dynamically set a tag in the index.html*/ } -function ErrorHandling($provide) { - $provide.decorator('$exceptionHandler', handler); +function ErrorHandling( $provide ) { + $provide.decorator('$exceptionHandler', handler ); - function handler($delegate, $injector) { - return function $broadcastingExceptionHandler(ex, cause) { + function handler( $delegate, $injector ) { + return function $broadcastingExceptionHandler( ex, cause ) { ex.status != 500 ? - $delegate(ex, cause) : - (function() { + $delegate( ex, cause ) : + ( function() { try { //TODO: implement track js - console.log(JSON.stringify(ex)); + console.log(JSON.stringify( ex )); //trackJs.error("API: " + JSON.stringify(ex)); } - catch (x) { - console.log(JSON.stringify(ex)); + catch ( ex ) { + console.log(JSON.stringify( ex )); } })(); - $injector.get('$rootScope').$broadcast('exception', ex, cause); + $injector.get( '$rootScope' ).$broadcast( 'exception', ex, cause ); } } } \ No newline at end of file diff --git a/src/app/global.less b/src/app/global.less new file mode 100644 index 00000000..0726f102 --- /dev/null +++ b/src/app/global.less @@ -0,0 +1,3 @@ +[ui-sref] { + cursor: pointer; +} \ No newline at end of file diff --git a/src/app/home/README.md b/src/app/home/README.md index 8caf617d..27414a4b 100644 --- a/src/app/home/README.md +++ b/src/app/home/README.md @@ -6,17 +6,21 @@ src/ |- app/ | |- home/ + | | |- less/ + | | | |- home.less + | | | |- variables.less + | | |- templates/ + | | | |- home.tpl.html | | |- home.js - | | |- home.less | | |- home.spec.js - | | |- home.tpl.html ``` - `home.js` - defines the module. -- `home.less` - module-specific styles; this file is imported into - `src/less/main.less` manually by the developer. +- `home/less` - module-specific styles; these files are rolled into a + `[root]/temp/imports.less` by the build process and immediately compiled to + `build/assets/OrderCloud-X.X.X.css`. - `home.spec.js` - module unit tests. -- `home.tpl.html` - the route template. +- `home/templates/` - contains all the templates for the module. ## `home.js` @@ -32,10 +36,8 @@ The dependencies block is also where component dependencies should be specified, as shown below. ```js -angular.module( 'ngBoilerplate.home', [ +angular.module( 'orderCloud.home', [ 'ui.router', - 'titleService', - 'plusOne' ]) ``` diff --git a/src/app/home/home.js b/src/app/home/home.js index 47a6e546..eee3abcd 100644 --- a/src/app/home/home.js +++ b/src/app/home/home.js @@ -1,32 +1,18 @@ -/** - * Each section of the site has its own module. It probably also has - * submodules, though this boilerplate is too simple to demonstrate it. Within - * `src/app/home`, however, could exist several additional folders representing - * additional modules that would then be listed as dependencies of this one. - * For example, a `note` section could have the submodules `note.create`, - * `note.delete`, `note.edit`, etc. - * - * Regardless, so long as dependencies are managed correctly, the build process - * will automatically take take of the rest. - * - * The dependencies block here is also where component dependencies should be - * specified, as shown below. - */ angular.module( 'orderCloud.home', [ 'ui.router' ]) -.config(Config) - -.controller( 'HomeCtrl', HomeController) + .config( HomeConfig ) + .controller( 'HomeCtrl', HomeController ) ; -function Config( $stateProvider ) { +function HomeConfig( $stateProvider, $urlMatcherFactoryProvider ) { + $urlMatcherFactoryProvider.strictMode(false); $stateProvider.state( 'home', { url: '/home', - controller: 'HomeCtrl', - templateUrl: 'home/home.tpl.html', + templateUrl:'home/templates/home.tpl.html', + controller:'HomeCtrl', data:{ pageTitle: 'Home' } }); } diff --git a/src/app/home/home.less b/src/app/home/less/home.less similarity index 100% rename from src/app/home/home.less rename to src/app/home/less/home.less diff --git a/src/app/home/less/variables.less b/src/app/home/less/variables.less new file mode 100644 index 00000000..e69de29b diff --git a/src/app/home/home.tpl.html b/src/app/home/templates/home.tpl.html similarity index 67% rename from src/app/home/home.tpl.html rename to src/app/home/templates/home.tpl.html index fe44db29..8fbf4743 100644 --- a/src/app/home/home.tpl.html +++ b/src/app/home/templates/home.tpl.html @@ -1,4 +1,4 @@ -
-

OrderCloud Seed

+
+

OrderCloud AngularJS Seed

Everything you need to kickstart AngularJS projects for OrderCloud: a best-practice directory structure, an intelligent build system, and the best web design libraries around.

diff --git a/src/app/variables.less b/src/app/variables.less index e69bde85..04e3d689 100644 --- a/src/app/variables.less +++ b/src/app/variables.less @@ -1,4 +1,7 @@ /** * These are the variables used throughout the application. This is where * overwrites that are not specific to components should be maintained. - */ \ No newline at end of file + */ + +// Font-awesome var overwrite for referencing Bootstrap CDN font files directly +@fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.3.0/fonts"; \ No newline at end of file diff --git a/src/assets/README.md b/src/assets/README.md index 3040eacd..be4adb04 100644 --- a/src/assets/README.md +++ b/src/assets/README.md @@ -2,3 +2,4 @@ There's really not much to say here. Every file in this directory is recursively transferred to `dist/assets/`. +These can be images, PDFs, etc... any non-code resource essentially. diff --git a/src/common/README.md b/src/common/README.md deleted file mode 100644 index 2c68a757..00000000 --- a/src/common/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# The `src/common/` Directory - -The `src/common/` directory houses internal and third-party re-usable -components. Essentially, this folder is for everything that isn't completely -specific to this application. - -Each component resides in its own directory that may then be structured any way -the developer desires. The build system will read all `*.js` files that do not -end in `.spec.js` as source files to be included in the final build, all -`*.spec.js` files as unit tests to be executed, and all `*.tpl.html` files as -templates to compiled into the `$templateCache`. There is currently no way to -handle components that do not meet this pattern. - -``` -src/ - |- common/ - | |- plusOne/ -``` - -- `plusOne` - a simple directive to load a Google +1 Button on an element. - -Every component contained here should be drag-and-drop reusable in any other -project; they should depend on no other components that aren't similarly -drag-and-drop reusable. diff --git a/src/index.html b/src/index.html index 1344d46f..e5bd826f 100644 --- a/src/index.html +++ b/src/index.html @@ -2,14 +2,14 @@ - + <% styles.forEach( function ( file ) { %> <% }); %> -
+
<% scripts.forEach( function ( file ) { %> <% }); %> diff --git a/src/less/README.md b/src/less/README.md deleted file mode 100644 index a7673152..00000000 --- a/src/less/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# The `src/less` Directory - -This folder is actually fairly self-explanatory: it contains your LESS/CSS files to be compiled during the build. -The only important thing to note is that *only* `main.less` will be processed during the build, meaning that all -other stylesheets must be *imported* into that one. - -This should operate somewhat like the routing; the `main.less` file contains all of the site-wide styles, while -any styles that are route-specific should be imported into here from LESS files kept alongside the JavaScript -and HTML sources of that component. For example, the `home` section of the site has some custom styles, which -are imported like so: - -```css -@import '../app/home/home.less'; -``` - -The same principal, though not demonstrated in the code, would also apply to reusable components. CSS or LESS -files from external components would also be imported. If, for example, we had a Twitter feed directive with -an accompanying template and style, we would similarly import it: - -```css -@import '../common/twitterFeed/twitterFeedDirective.less'; -``` - -Using this decentralized approach for all our code (JavaScript, HTML, and CSS) creates a framework where a -component's directory can be dragged and dropped into *any other project* and it will "just work". - -I would like to eventually automate the importing during the build so that manually importing it here would no -longer be required, but more thought must be put in to whether this is the best approach. diff --git a/src/less/main.less b/src/less/main.less deleted file mode 100644 index 36a31687..00000000 --- a/src/less/main.less +++ /dev/null @@ -1,246 +0,0 @@ -// This file was generated by the grunt-less-imports task in the build process. Do not alter this file, any changes you make will be overwritten the next time you build. - -/* - * Toastr - * Version 2.0.1 - * Copyright 2012 John Papa and Hans Fjällemark. - * All Rights Reserved. - * Use, reproduction, distribution, and modification of this code is subject to the terms and - * conditions of the MIT license, available at http://www.opensource.org/licenses/mit-license.php - * - * Author: John Papa and Hans Fjällemark - * Project: https://github.com/CodeSeven/toastr - */ -.toast-title { - font-weight: bold; -} -.toast-message { - -ms-word-wrap: break-word; - word-wrap: break-word; -} -.toast-message a, -.toast-message label { - color: #ffffff; -} -.toast-message a:hover { - color: #cccccc; - text-decoration: none; -} - -.toast-close-button { - position: relative; - right: -0.3em; - top: -0.3em; - float: right; - font-size: 20px; - font-weight: bold; - color: #ffffff; - -webkit-text-shadow: 0 1px 0 #ffffff; - text-shadow: 0 1px 0 #ffffff; - opacity: 0.8; - -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=80); - filter: alpha(opacity=80); -} -.toast-close-button:hover, -.toast-close-button:focus { - color: #000000; - text-decoration: none; - cursor: pointer; - opacity: 0.4; - -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=40); - filter: alpha(opacity=40); -} - -/*Additional properties for button version - iOS requires the button element instead of an anchor tag. - If you want the anchor version, it requires `href="#"`.*/ -button.toast-close-button { - padding: 0; - cursor: pointer; - background: transparent; - border: 0; - -webkit-appearance: none; -} -.toast-top-full-width { - top: 0; - right: 0; - width: 100%; -} -.toast-bottom-full-width { - bottom: 0; - right: 0; - width: 100%; -} -.toast-top-left { - top: 12px; - left: 12px; -} -.toast-top-center { - top: 12px; -} -.toast-top-right { - top: 12px; - right: 12px; -} -.toast-bottom-right { - right: 12px; - bottom: 12px; -} -.toast-bottom-center { - bottom: 12px; -} -.toast-bottom-left { - bottom: 12px; - left: 12px; -} -.toast-center { - top: 45%; -} -#toast-container { - position: fixed; - z-index: 999999; - /*overrides*/ - -} -#toast-container.toast-center, -#toast-container.toast-top-center, -#toast-container.toast-bottom-center{ - width: 100%; - pointer-events: none; -} -#toast-container.toast-center > div, -#toast-container.toast-top-center > div, -#toast-container.toast-bottom-center > div{ - margin: auto; - pointer-events: auto; -} -#toast-container.toast-center > button, -#toast-container.toast-top-cente > button, -#toast-container.toast-bottom-center > button{ - pointer-events: auto; -} -#toast-container * { - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; -} -#toast-container > div { - margin: 0 0 6px; - padding: 15px 15px 15px 50px; - width: 300px; - -moz-border-radius: 3px 3px 3px 3px; - -webkit-border-radius: 3px 3px 3px 3px; - border-radius: 3px 3px 3px 3px; - background-position: 15px center; - background-repeat: no-repeat; - -moz-box-shadow: 0 0 12px #999999; - -webkit-box-shadow: 0 0 12px #999999; - box-shadow: 0 0 12px #999999; - color: #ffffff; - opacity: 0.8; - -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=80); - filter: alpha(opacity=80); -} -#toast-container > :hover { - -moz-box-shadow: 0 0 12px #000000; - -webkit-box-shadow: 0 0 12px #000000; - box-shadow: 0 0 12px #000000; - opacity: 1; - -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100); - filter: alpha(opacity=100); - cursor: pointer; -} -#toast-container > .toast-info { - background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVEhLtZa9SgNBEMc9sUxxRcoUKSzSWIhXpFMhhYWFhaBg4yPYiWCXZxBLERsLRS3EQkEfwCKdjWJAwSKCgoKCcudv4O5YLrt7EzgXhiU3/4+b2ckmwVjJSpKkQ6wAi4gwhT+z3wRBcEz0yjSseUTrcRyfsHsXmD0AmbHOC9Ii8VImnuXBPglHpQ5wwSVM7sNnTG7Za4JwDdCjxyAiH3nyA2mtaTJufiDZ5dCaqlItILh1NHatfN5skvjx9Z38m69CgzuXmZgVrPIGE763Jx9qKsRozWYw6xOHdER+nn2KkO+Bb+UV5CBN6WC6QtBgbRVozrahAbmm6HtUsgtPC19tFdxXZYBOfkbmFJ1VaHA1VAHjd0pp70oTZzvR+EVrx2Ygfdsq6eu55BHYR8hlcki+n+kERUFG8BrA0BwjeAv2M8WLQBtcy+SD6fNsmnB3AlBLrgTtVW1c2QN4bVWLATaIS60J2Du5y1TiJgjSBvFVZgTmwCU+dAZFoPxGEEs8nyHC9Bwe2GvEJv2WXZb0vjdyFT4Cxk3e/kIqlOGoVLwwPevpYHT+00T+hWwXDf4AJAOUqWcDhbwAAAAASUVORK5CYII=") !important; -} -#toast-container > .toast-wait { - background-image: url("data:image/gif;base64,R0lGODlhIAAgAIQAAAQCBISGhMzKzERCROTm5CQiJKyurHx+fPz+/ExOTOzu7Dw+PIyOjCwqLFRWVAwKDIyKjMzOzOzq7CQmJLy6vFRSVPTy9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJCQAXACwAAAAAIAAgAAAF3eAljmRpnmh6VRSVqLDpIDTixOdUlFSNUDhSQUAT7ES9GnD0SFQAKWItMqr4bqKHVPDI+WiTkaOFFVlrFe83rDrT0qeIjwrT0iLdU0GOiBxhAA4VeSk6QYeIOAsQEAuJKgw+EI8nA18IA48JBAQvFxCXDI8SNAQikV+iiaQIpheWX5mJmxKeF6g0qpQmA4yOu8C7EwYWCgZswRcTFj4KyMAGlwYxDwcHhCXMXxYxBzQHKNo+3DDeCOAn0V/TddbYJA0K48gAEAFQicMWFsfwNA3JSgAIAAFfwIMIL4QAACH5BAkJABoALAAAAAAgACAAhAQCBIyKjERCRMzOzCQiJPTy9DQyNGRmZMTCxOTm5CwqLHx+fBQWFJyenNTW1Pz6/Dw6PGxubAwKDIyOjNTS1CQmJCwuLPz+/Dw+PHRydAAAAAAAAAAAAAAAAAAAAAAAAAXboCaOZGmeaKoxWcSosMkk15W8cZ7VdZaXkcEgQtrxfD9RhHchima1GwlCGUBSFCaFxMrgRtnLFhWujWHhs2nJc8KoVlWGQnEn7/i8XgOwWAB7JwoONQ4KgSQAZRcOgHgSCwsSIhZMNRZ5CzULIgaWF5h4mhecfIQ8jXmQkiODhYeIiRYGjrG2PxgBARi3IhNMAbcCnwI5BAQpAZ8TIwK6vCQVDwUVKL+WzAANTA210g/VJ8OWxQefByQE4dZMzBoInwh4zrtgn2p725YNthUFTNRuGYB3AYGBHCEAACH5BAkJAB0ALAAAAAAgACAAhAQCBISChFRWVMzKzCQiJOTm5GxqbCwuLJSWlPz6/NTW1AwODJSSlGRmZCwqLOzu7HR2dDQ2NAQGBISGhFxaXNTS1CQmJOzq7GxubDQyNKSmpPz+/Nza3AAAAAAAAAAAAAXfYCeOZGmeaKqurHBdAiuP17Zdc0lMAVHWt9yI8LA9fCPB4xEjARoNSWpis01kBpshFahurqzsZosiGpErScMAUO0maKF8Tq/bTQCIQgFp30cQXhB1BHEcXhx0FgkJFiOHVYlzi42AgoRxeRx8fn+en3UABwedKgsBAwMBCygOCjYKDisLFV4VrCUAtVUKpSZdXl8mB8EbByQWcQPFAyYZxccdB7sV0cvBzbmvvG0LBV4FrFTBYCWuNhyyHRTFFB20trh4BxmdYl4YIqepq0IRxRE+IfDCAFQHARo0NGERAgAh+QQJCQAgACwAAAAAIAAgAIUEAgSEgoRMTkzMyswcHhzk5uR0cnQUFhRcXlwsKiz09vQMCgyMiozU1tQkJiR8fnxkZmT8/vwEBgSEhoRcWlzU0tQkIiT08vR0dnQcGhxkYmQ0MjT8+vwMDgyMjozc2twAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG+UCQcEgsGo/IpHLJXDweC6Z0+IhEHlOjRGIMWLHZoUZx0RQlAajxkFFKFFYFl5m5KNpIySU+X2bIBEoQZBBZGQdMElFhjI2Oj5AgHQEDAw8dQxYeDBaNHRVWVhWYCXsRFwmMXqFWEyAerB6MA6xWA6+xs7URt6VWqIwTu64gDh4eDp6goaORQ5OVAZjO1EgEGhB4RwAYDQ0YAEwIcBEKFEgYrBhLBORxgUYfrB9LELuF8fNDAAaVBuEg7NXCVyRdqHVCGLBiIIQAB1Yc4BXh9uEbwAXuyi2iQI7DuSwHdiFqCEGDtizLRFUDsaGAlQIbVoJYIEDAIiZBAAAh+QQJCQAbACwAAAAAIAAgAIQEAgSMioxcWlz08vQcHhysqqwMDgx8enwsKiykoqRkZmT8+vzEwsQMCgyUlpQkJiS0srQEBgSMjoxcXlz09vQkIiSsrqwUEhQ0MjRsamz8/vwAAAAAAAAAAAAAAAAAAAAF7+AmjmRpnmiqruz2PG0sIssCj4CQJAIgj4/abRNJaI6agu9kCAQaphdJgEQKUIFjgGWsahJYLdf7RTWfLKr3+jsBClVlG5Xb9eb4fImgUBBKDVB4ExRHFGwbGRQLGXMEhUgUfw2QC4IyCmSNDQtHlm2ZXgoiGQsUjW0EnUgLfyKBeYSeiHojfH61uS0GBisVEgEVLRcWRxAXKAgDRwMILMVIECgSVRIrBmS9JtRI1iMVBweuGxerSNolyszOIhjLGs0jEFXSKA8SEkMbcEgWIxfzNBxrw6AKgxIGkM05UOWALhERHJhysOThBgAVWYQAACH5BAkJABkALAAAAAAgACAAhAQGBIyKjERCRMzOzCwuLGRiZPz6/OTm5AwODLSytFRSVNTW1Dw6PHx6fAwKDJSSlERGRNTS1DQyNGxqbPz+/BQSFLy6vFRWVNza3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAXqYCaO5FgFwxBUZeu61ULNFMa+eBvQdJD/owFvFhkBBAwHsBQZUooZyWF2YOQkBNJu6ANMaQeli0AxSEwymi0DcUJeEgPlbEJFAghRe/h+Eeg/Dl9UYks5DF9VhksOAgKFi5GSSwh5kzgVCXIJNxknD5aSCTwJIw8zD5MITpanFKmSCHI8NxUPoJejNKWXLZkznL0vCJ3CxsckDpA/ChYJFzkTBgYTSxc80C4OswbLLhY8Fi/bMwYAJVgl4DTiL9LUJADrFuci1zTZLwD1IwU8BSQuWLCQb1EDHg2QiSDALYvCDAISJLDy8FIIACH5BAkJAB4ALAAAAAAgACAAhAQGBISGhFRSVNTW1CQiJKyqrGRmZOzu7CwuLIyOjGxubPz6/BQSFGRiZOTi5CwqLLy6vDQ2NIyKjFRWVCQmJKyurGxqbPT29DQyNJSSlHRydPz+/BQWFOzq7AAAAAAAAAXhoCeOJElYClGubOs117YtjWuvxCLLi3qbhc6h4FPsdorfiNI5dige43GT9AAkHUcCwCpMNxVP7tgTJY4J1uF7EBl0M8Ooueuo2SOCIkVa11kVX2E2EmgsFH4yBz4uAAkdHVstBAUHQ4xKmZqbnJ2bAhAQAiURGJ4eE0cTIxgzpp0QRxCsrp6xO7MjpaepO6unKxOhv8DFxsfIJBwaChw2DAkZDEocDjIOzi0ZMhlKUjIaLtsb3T8aR+EtDBkJ0yQUBQVQI9XX2ZsDMgMlyxr3mzE2XEgmotCGAARFIHiQ0FMIACH5BAkJABgALAAAAAAgACAAhAQCBISGhDw+POTi5CwuLLS2tPTy9BQSFJyenGRiZDQ2NIyOjLy+vPz6/BweHIyKjFRSVOzq7DQyNLy6vBQWFHRydDw6PPz+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXXICaOZHkcZaquIjVd10SxtFrAcFGrVhBYIwoON9uNAsOA6DCEFTEKBEKxEjQvAtELNxkpGrAGNfW4Plpb2QgxRKjKzfPoVGLj3CnLNUv7hscpSDhKOxJSgDwPP0ZGAACMjAQFDQYFBJA0BAZDBpeYGBQVFUU3TV2YFAMwAzNgTQ2PkBVDFRiuQ7CYszi1pUOnkKmrM5qcnqiiTwQTDQ2Wn9DR0tPUfRKQEBEREDQSFw3XRhEwEd3f4TvjF+XWKgJ8JNnb0QkwCdUlCzAL+CQODAwc9BtIMAQAOw==") !important; -} -#toast-container > .toast-error { - background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHOSURBVEhLrZa/SgNBEMZzh0WKCClSCKaIYOED+AAKeQQLG8HWztLCImBrYadgIdY+gIKNYkBFSwu7CAoqCgkkoGBI/E28PdbLZmeDLgzZzcx83/zZ2SSXC1j9fr+I1Hq93g2yxH4iwM1vkoBWAdxCmpzTxfkN2RcyZNaHFIkSo10+8kgxkXIURV5HGxTmFuc75B2RfQkpxHG8aAgaAFa0tAHqYFfQ7Iwe2yhODk8+J4C7yAoRTWI3w/4klGRgR4lO7Rpn9+gvMyWp+uxFh8+H+ARlgN1nJuJuQAYvNkEnwGFck18Er4q3egEc/oO+mhLdKgRyhdNFiacC0rlOCbhNVz4H9FnAYgDBvU3QIioZlJFLJtsoHYRDfiZoUyIxqCtRpVlANq0EU4dApjrtgezPFad5S19Wgjkc0hNVnuF4HjVA6C7QrSIbylB+oZe3aHgBsqlNqKYH48jXyJKMuAbiyVJ8KzaB3eRc0pg9VwQ4niFryI68qiOi3AbjwdsfnAtk0bCjTLJKr6mrD9g8iq/S/B81hguOMlQTnVyG40wAcjnmgsCNESDrjme7wfftP4P7SP4N3CJZdvzoNyGq2c/HWOXJGsvVg+RA/k2MC/wN6I2YA2Pt8GkAAAAASUVORK5CYII=") !important; -} -#toast-container > .toast-success { - background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVEhLY2AYBfQMgf///3P8+/evAIgvA/FsIF+BavYDDWMBGroaSMMBiE8VC7AZDrIFaMFnii3AZTjUgsUUWUDA8OdAH6iQbQEhw4HyGsPEcKBXBIC4ARhex4G4BsjmweU1soIFaGg/WtoFZRIZdEvIMhxkCCjXIVsATV6gFGACs4Rsw0EGgIIH3QJYJgHSARQZDrWAB+jawzgs+Q2UO49D7jnRSRGoEFRILcdmEMWGI0cm0JJ2QpYA1RDvcmzJEWhABhD/pqrL0S0CWuABKgnRki9lLseS7g2AlqwHWQSKH4oKLrILpRGhEQCw2LiRUIa4lwAAAABJRU5ErkJggg==") !important; -} -#toast-container > .toast-warning { - background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGYSURBVEhL5ZSvTsNQFMbXZGICMYGYmJhAQIJAICYQPAACiSDB8AiICQQJT4CqQEwgJvYASAQCiZiYmJhAIBATCARJy+9rTsldd8sKu1M0+dLb057v6/lbq/2rK0mS/TRNj9cWNAKPYIJII7gIxCcQ51cvqID+GIEX8ASG4B1bK5gIZFeQfoJdEXOfgX4QAQg7kH2A65yQ87lyxb27sggkAzAuFhbbg1K2kgCkB1bVwyIR9m2L7PRPIhDUIXgGtyKw575yz3lTNs6X4JXnjV+LKM/m3MydnTbtOKIjtz6VhCBq4vSm3ncdrD2lk0VgUXSVKjVDJXJzijW1RQdsU7F77He8u68koNZTz8Oz5yGa6J3H3lZ0xYgXBK2QymlWWA+RWnYhskLBv2vmE+hBMCtbA7KX5drWyRT/2JsqZ2IvfB9Y4bWDNMFbJRFmC9E74SoS0CqulwjkC0+5bpcV1CZ8NMej4pjy0U+doDQsGyo1hzVJttIjhQ7GnBtRFN1UarUlH8F3xict+HY07rEzoUGPlWcjRFRr4/gChZgc3ZL2d8oAAAAASUVORK5CYII=") !important; -} -#toast-container.toast-top-full-width > div, -#toast-container.toast-bottom-full-width > div { - width: 96%; - margin: auto; -} -.toast { - background-color: #030303; -} -.toast-success { - background-color: #51a351; -} -.toast-error { - background-color: #bd362f; -} -.toast-info { - background-color: #2f96b4; -} -.toast-wait { - background-color: #2f96b4; -} -.toast-warning { - background-color: #f89406; -} -/*Responsive Design*/ -@media all and (max-width: 240px) { - #toast-container > div { - padding: 8px 8px 8px 50px; - width: 11em; - } - #toast-container .toast-close-button { - right: -0.2em; - top: -0.2em; -} - } -@media all and (min-width: 241px) and (max-width: 480px) { - #toast-container > div { - padding: 8px 8px 8px 50px; - width: 18em; - } - #toast-container .toast-close-button { - right: -0.2em; - top: -0.2em; -} -} -@media all and (min-width: 481px) and (max-width: 768px) { - #toast-container > div { - padding: 15px 15px 15px 50px; - width: 25em; - } -} - - /* - * AngularJS-Toaster - * Version 0.3 - */ -:not(.no-enter)#toast-container > div.ng-enter, -:not(.no-leave)#toast-container > div.ng-leave -{ - -webkit-transition: 1000ms cubic-bezier(0.250, 0.250, 0.750, 0.750) all; - -moz-transition: 1000ms cubic-bezier(0.250, 0.250, 0.750, 0.750) all; - -ms-transition: 1000ms cubic-bezier(0.250, 0.250, 0.750, 0.750) all; - -o-transition: 1000ms cubic-bezier(0.250, 0.250, 0.750, 0.750) all; - transition: 1000ms cubic-bezier(0.250, 0.250, 0.750, 0.750) all; -} - -:not(.no-enter)#toast-container > div.ng-enter.ng-enter-active, -:not(.no-leave)#toast-container > div.ng-leave { - opacity: 0.8; -} - -:not(.no-leave)#toast-container > div.ng-leave.ng-leave-active, -:not(.no-enter)#toast-container > div.ng-enter { - opacity: 0; -} - -@import (once) "..\..\vendor\bootstrap\less\bootstrap.less"; -@import (once) "..\..\vendor\ambient\less\ambient.less"; -@import (once) "..\app\home\home.less"; -@import (once) "..\app\variables.less"; From 5e6d69a6e037ff10d376ba99d173d4cf8c491f9e Mon Sep 17 00:00:00 2001 From: Robert Watt Date: Fri, 17 Apr 2015 10:08:01 -0500 Subject: [PATCH 003/367] Update README.md --- README.md | 61 ++++++++++++++++--------------------------------------- 1 file changed, 18 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index a5e0d52b..fa703105 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A seed project for custom Four51 Solutions ## Get started -Install [node.js](http://nodejs.org/) and then: +Node.js is required for the following node package manager (npm) tasks. If you don't have node.js installed, you can download it [here](http://nodejs.org/). ```sh $ npm -g install grunt-cli karma bower @@ -23,7 +23,7 @@ OrderCloud/ ``` ## Configure WebStorm -WebStorm is our chosen development IDE. It provides an interface into the capabilities of the projects configuration. +WebStorm is our chosen development IDE. It provides an interface for the capabilities of the seed projects configuration. ### Karma Unit Testing Once you've installed the prerequisites and run your grunt build you can setup and run your Karma tests. @@ -43,21 +43,16 @@ At a high level, the structure looks roughly like this: ``` OrderCloud/ - |- grunt-tasks/ |- karma/ + |- node_modules/ |- src/ | |- app/ - | | |- + | | |- | |- assets/ | | |- - | |- common/ - | | |- - | |- less/ - | | |- main.less + | |- index.html |- vendor/ - | |- angular-bootstrap/ - | |- bootstrap/ - | |- placeholders/ + | |- |- .bowerrc |- bower.json |- build.config.js @@ -98,8 +93,8 @@ This will read the `dependencies` (empty by default) and the `devDependencies` (which contains our build requirements) from `package.json` and install everything needed into a folder called `node_modules/`. -There are many Bower packages used by `OrderCloud`, like Twitter Bootstrap -and Angular UI, which are listed in `bower.js`. To install them into the +There are many Bower packages used by `OrderCloud`, like AngularJS and the +OrderCloud-SDK, which are listed in `bower.js`. To install them into the `vendor/` directory, simply run: ```sh @@ -140,10 +135,6 @@ and concatenated, but when a test/spec file changes, only the tests are run. This allows the watch command to complete in a fraction of the time it would ordinarily take. -In addition, if you're running a Live Reload plugin in your browser (see below), -you won't even have to refresh to see the changes! When the `watch` task detects -a file change, it will reload the page for you. Sweet. - When you're ready to push your app into production, just run the `compile` command: @@ -152,11 +143,11 @@ $ grunt compile ``` This will concatenate and minify your sources and place them by default into the -`release/` directory. There will only be three files: `index.html`, +`compile/` directory. There will only be three files (excluding assets): `index.html`, `OrderCloud.js`, and `OrderCloud.css`. All of the vendor dependencies like -Bootstrap styles and AngularJS itself have been added to them for super-easy +AngularJS styles and the OrderCloud-SDK itself have been added to them for super-easy deploying. If you use any assets (`src/assets/`) then they will be copied to -`release/` as is. +`compile/` as is. Lastly, a complete build is always available by simply running the default task, which runs `build` and then `compile`: @@ -185,21 +176,19 @@ changes: template, so script names, etc., are dynamically replaced with the correct values configured dynamically by Grunt. * `delta:less` - When any `*.less` file within `src/` changes, the - `src/less/main.less` file is linted and copied into - `build/assets/OrderCloud.css`. + `temp/imports.less` file is regenerated by the `less_imports:build` task, + autoprefixed, and compiled into `build/assets/OrderCloud.css`. * `delta:jssrc` - When any JavaScript file within `src/` that does not end in `.spec.js` changes, all JavaScript sources are linted, all unit tests are run, and the all source files are re-copied to `build/src`. `build/src` in a structure mirroring where they were in `src/` so it's easy to locate problems. * `delta:tpls` - When any `*.tpl.html` file within `src/` changes, all templates - are put into strings in a JavaScript file (technically two, one for - `src/common/` and another for `src/app/`) that will add the template to + are put into strings in a JavaScript file that will add the template to AngularJS's [`$templateCache`](http://docs.angularjs.org/api/ng.$templateCache) so - template files are part of the initial JavaScript payload and do not require - any future XHR. The template cache files are `build/template-app.js` and - `build/template-common.js`. + template file is part of the initial JavaScript payload and do not require + any future XHR. The template cache file is `build/template-app.js`. * `delta:jsunit` - When any `*.spec.js` file in `src/` changes, the test files are linted and the unit tests are executed. @@ -231,19 +220,5 @@ To initiate a full compile, you simply run the default task: $ grunt ``` -This will perform a build and then a compile. The compiled site is located in `release/`, taking a cue from -traditional software development. To test that your full site works as -expected, open the `release/index.html` file in your browser. Voila! - -### Live Reload! - -`OrderCloud` also includes [Live Reload](http://livereload.com/), so you no -longer have to refresh your page after making changes! You need a Live Reload -browser plugin for this: - -- Chrome - [Chrome Webstore](https://chrome.google.com/webstore/detail/livereload/jnihajbhpnppcggbcgedagnkighmdlei) -- Firefox - [Download from Live Reload](http://download.livereload.com/2.0.8/LiveReload-2.0.8.xpi) -- Safari - [Download from Live Reload](http://download.livereload.com/2.0.9/LiveReload-2.0.9.safariextz) -- Internet Explorer - Not available. - -When you load your page, click the Live Reload icon in your toolbar. \ No newline at end of file +This will perform a build and then a compile. The compiled site is located in `compile/`. +To test that your full site works as expected, open the `compile/index.html` file in your browser. Voila! From 7459c7239a9390bc970a7d47cbce2dbbe5a3f1be Mon Sep 17 00:00:00 2001 From: Robert Watt Date: Fri, 17 Apr 2015 10:13:14 -0500 Subject: [PATCH 004/367] Update README.md --- src/app/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/app/README.md b/src/app/README.md index b6e5bafb..72457552 100644 --- a/src/app/README.md +++ b/src/app/README.md @@ -94,6 +94,8 @@ is `app.spec.js`, though it is quite minimal. ### Global application styles +By default, we include [Ambient](http://ionlyseespots.github.io/ambient-design/index.html) which is an internally developed design framework that makes use of HTML5 elements & CSS3 attributes to layout the document outline. + Within the `src/app/` directory we included a `global.less` and `variables.less` file. These should be utilized for application wide LESS variables and mixins. Each component within `src/app` will have a corresponding `less/` directory with a similar structure. From c412265b7db1ee4fb9329e64a750c39953f4d330 Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 17 Apr 2015 10:43:31 -0500 Subject: [PATCH 005/367] Preparing for update --- bower.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bower.json b/bower.json index 1aace247..cae2ba2d 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "orderCloud", - "version": "0.0.1", + "version": "0.0.2", "devDependencies": { "angular": "~1.3.14", "angular-mocks": "~1.3.14", diff --git a/package.json b/package.json index ef5ef29b..0dd3e7f2 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "author": "Four51, Inc.", "name": "OrderCloud", - "version": "0.0.1", + "version": "0.0.2", "homepage": "https://github.com/Four51/OrderCloud", "licenses": { "type": "MIT", From 9da30928b2276f4cfcd91e7c9a0b52b247b5ec59 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 23 Apr 2015 10:23:34 -0500 Subject: [PATCH 006/367] Use the new 3.0 SDK --- bower.json | 2 +- build.config.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bower.json b/bower.json index cae2ba2d..e07d51ff 100644 --- a/bower.json +++ b/bower.json @@ -12,7 +12,7 @@ "ambient": "~1.3.0", "jquery": "~2.1.3", "font-awesome": "~4.3.0", - "ordercloud-sdk": "~0.0.4" + "ordercloud-angular-sdk": "~0.0.3" }, "dependencies": {} } diff --git a/build.config.js b/build.config.js index 3680ab7a..b6d0caf2 100644 --- a/build.config.js +++ b/build.config.js @@ -71,7 +71,7 @@ module.exports = { 'vendor/angular-animate/angular-animate.js', 'vendor/angular-touch/angular-touch.js', 'vendor/jquery/dist/jquery.js', - 'vendor/ordercloud-sdk/dist/OrderCloudSDK.js' + 'vendor/ordercloud-angular-sdk/dist/ordercloud-angular-sdk.js' ], css: [ ], From 9c2e7f3d8a44557ac9d8155a1e774a539256d0a9 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 28 Apr 2015 14:47:31 -0500 Subject: [PATCH 007/367] Update Angular, Angular modules, Ambient and the SDK versions --- README.md | 4 ++-- bower.json | 18 +++++++++--------- package.json | 10 +++++----- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index fa703105..2a92909c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# OrderCloud -A seed project for custom Four51 Solutions +# OrderCloud Seed - AngularJS +A seed project for custom Four51 Solutions built on AngularJS *** ## Get started diff --git a/bower.json b/bower.json index e07d51ff..b572caa2 100644 --- a/bower.json +++ b/bower.json @@ -1,18 +1,18 @@ { "name": "orderCloud", - "version": "0.0.2", + "version": "0.0.3", "devDependencies": { - "angular": "~1.3.14", - "angular-mocks": "~1.3.14", - "angular-sanitize": "~1.3.14", - "angular-ui-router": "~0.2", - "angular-messages": "~1.3.14", - "angular-animate": "~1.3.14", + "angular": "~1.3.15", + "angular-mocks": "~1.3.15", + "angular-sanitize": "~1.3.15", + "angular-ui-router": "~0.2.14", + "angular-messages": "~1.3.15", + "angular-animate": "~1.3.15", "angular-touch": "~1.3.15", - "ambient": "~1.3.0", + "ambient": "~1.3.6", "jquery": "~2.1.3", "font-awesome": "~4.3.0", - "ordercloud-angular-sdk": "~0.0.3" + "ordercloud-angular-sdk": "~0.0.10" }, "dependencies": {} } diff --git a/package.json b/package.json index 0dd3e7f2..f98860f9 100644 --- a/package.json +++ b/package.json @@ -1,16 +1,16 @@ { "author": "Four51, Inc.", "name": "OrderCloud", - "version": "0.0.2", - "homepage": "https://github.com/Four51/OrderCloud", + "version": "0.0.3", + "homepage": "https://github.com/Four51/OrderCloud-Seed-AngularJS", "licenses": { "type": "MIT", - "url": "https://raw.github.com/Four51/OrderCloud/master/LICENSE" + "url": "https://raw.github.com/Four51/OrderCloud-Seed-AngularJS/master/LICENSE" }, - "bugs": "https://github.com/Four51/OrderCloud/issues", + "bugs": "https://github.com/Four51/OrderCloud-Seed-AngularJS/issues", "repository": { "type": "git", - "url": "git@github.com:Four51/OrderCloud.git" + "url": "git@github.com:Four51/OrderCloud-Seed-AngularJS.git" }, "dependencies": {}, "devDependencies": { From 9790a15e8a4696bde358af9e907e90e7e162ca5e Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 28 Apr 2015 16:11:22 -0500 Subject: [PATCH 008/367] Update to latest release of Angular Updated the SDK version Adopted the chaining pattern for the example home component Updates to the README.md --- bower.json | 14 +++++++------- build.config.js | 2 +- src/app/README.md | 7 +++---- src/app/app.js | 13 +++++++------ src/app/home/home.js | 7 ++----- src/app/home/home.spec.js | 3 ++- src/index.html | 4 ++-- 7 files changed, 24 insertions(+), 26 deletions(-) diff --git a/bower.json b/bower.json index b572caa2..bd370443 100644 --- a/bower.json +++ b/bower.json @@ -2,17 +2,17 @@ "name": "orderCloud", "version": "0.0.3", "devDependencies": { - "angular": "~1.3.15", - "angular-mocks": "~1.3.15", - "angular-sanitize": "~1.3.15", + "angular": "~1.4.0-rc.1", + "angular-mocks": "~1.4.0-rc.1", + "angular-sanitize": "~1.4.0-rc.1", "angular-ui-router": "~0.2.14", - "angular-messages": "~1.3.15", - "angular-animate": "~1.3.15", - "angular-touch": "~1.3.15", + "angular-messages": "~1.4.0-rc.1", + "angular-animate": "~1.4.0-rc.1", + "angular-touch": "~1.4.0-rc.1", "ambient": "~1.3.6", "jquery": "~2.1.3", "font-awesome": "~4.3.0", - "ordercloud-angular-sdk": "~0.0.10" + "ordercloud-angular-sdk": "~0.0.11" }, "dependencies": {} } diff --git a/build.config.js b/build.config.js index b6d0caf2..e2d3bce0 100644 --- a/build.config.js +++ b/build.config.js @@ -66,10 +66,10 @@ module.exports = { js: [ 'vendor/angular/angular.js', 'vendor/angular-sanitize/angular-sanitize.js', - 'vendor/angular-ui-router/release/angular-ui-router.js', 'vendor/angular-messages/angular-messages.js', 'vendor/angular-animate/angular-animate.js', 'vendor/angular-touch/angular-touch.js', + 'vendor/angular-ui-router/release/angular-ui-router.js', 'vendor/jquery/dist/jquery.js', 'vendor/ordercloud-angular-sdk/dist/ordercloud-angular-sdk.js' ], diff --git a/src/app/README.md b/src/app/README.md index 72457552..613cd9a5 100644 --- a/src/app/README.md +++ b/src/app/README.md @@ -46,9 +46,8 @@ angular.module( 'orderCloud', [ 'ui.router', 'ngMessages', 'ngTouch', - 'orderCloud.sdk', - 'orderCloud.home' -]) + 'orderCloud.sdk' + ]) ``` With app modules broken down in this way, all routing is performed by the @@ -87,7 +86,7 @@ not specific to the template or route, such as menu logic or page title wiring. ### Testing -One of the design philosophies of `OrderCloud-AngularJS-seed` is that tests should exist +One of the design philosophies of `OrderCloud-Seed-AngularJS` is that tests should exist alongside the code they test and that the build system should be smart enough to know the difference and react accordingly. As such, the unit test for `app.js` is `app.spec.js`, though it is quite minimal. diff --git a/src/app/app.js b/src/app/app.js index 82371979..9b2e69dc 100644 --- a/src/app/app.js +++ b/src/app/app.js @@ -2,11 +2,10 @@ angular.module( 'orderCloud', [ 'templates-app', 'ngSanitize', 'ngAnimate', - 'ui.router', 'ngMessages', 'ngTouch', - 'orderCloud.sdk', - 'orderCloud.home' + 'ui.router', + 'orderCloud.sdk' ]) .config( Routing ) @@ -16,17 +15,19 @@ angular.module( 'orderCloud', [ ; function AppCtrl( $scope ) { + var vm = this; $scope.$on('$stateChangeSuccess', function( event, toState, toParams, fromState, fromParams ){ if ( angular.isDefined( toState.data.pageTitle ) ) { - $scope.pageTitle = 'OrderCloud | ' + toState.data.pageTitle; + vm.pageTitle = 'OrderCloud | ' + toState.data.pageTitle; } }); } -function Routing( $urlRouterProvider ) { +function Routing( $urlRouterProvider, $urlMatcherFactoryProvider ) { + $urlMatcherFactoryProvider.strictMode(false); $urlRouterProvider.otherwise( '/home' ); //$locationProvider.html5Mode(true); - /*TODO: we will want html5Mode to be on; however, to do this, we also need to dynamically set a tag in the index.html*/ + //TODO: For HTML5 mode to work we need to always return index.html as the entry point on the serverside } function ErrorHandling( $provide ) { diff --git a/src/app/home/home.js b/src/app/home/home.js index eee3abcd..f594964f 100644 --- a/src/app/home/home.js +++ b/src/app/home/home.js @@ -1,14 +1,11 @@ -angular.module( 'orderCloud.home', [ - 'ui.router' -]) +angular.module( 'orderCloud' ) .config( HomeConfig ) .controller( 'HomeCtrl', HomeController ) ; -function HomeConfig( $stateProvider, $urlMatcherFactoryProvider ) { - $urlMatcherFactoryProvider.strictMode(false); +function HomeConfig( $stateProvider ) { $stateProvider.state( 'home', { url: '/home', templateUrl:'home/templates/home.tpl.html', diff --git a/src/app/home/home.spec.js b/src/app/home/home.spec.js index 00372a22..d529d881 100644 --- a/src/app/home/home.spec.js +++ b/src/app/home/home.spec.js @@ -5,7 +5,8 @@ * automatically. */ describe( 'home section', function() { - beforeEach( module( 'orderCloud.home' ) ); + beforeEach( module( 'orderCloud' ) ); + //TODO: this used to be orderCloud.home because it was it's own module but now it is just chained onto orderCloud... how would we write the test for 'home section' in this case? it( 'should have a dummy test', function() { expect( true ).toBeTruthy(); diff --git a/src/index.html b/src/index.html index e5bd826f..9d75e233 100644 --- a/src/index.html +++ b/src/index.html @@ -1,9 +1,9 @@ - + - + <% styles.forEach( function ( file ) { %> <% }); %> From afcf779a717e150ce4268976b5b54617fe8c92e0 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 28 Apr 2015 16:31:49 -0500 Subject: [PATCH 009/367] Reworked the example Home component to use ControllerAs I also temporarily commented the home.spec.js because it will break the $grunt watch task --- src/app/home/home.js | 6 +++++- src/app/home/home.spec.js | 3 +++ src/app/home/templates/home.tpl.html | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/app/home/home.js b/src/app/home/home.js index f594964f..4e2571a3 100644 --- a/src/app/home/home.js +++ b/src/app/home/home.js @@ -10,8 +10,12 @@ function HomeConfig( $stateProvider ) { url: '/home', templateUrl:'home/templates/home.tpl.html', controller:'HomeCtrl', + controllerAs: 'home', data:{ pageTitle: 'Home' } }); } -function HomeController( $scope ) { } +function HomeController( ) { + var vm = this; + vm.example = 'Example Data'; +} diff --git a/src/app/home/home.spec.js b/src/app/home/home.spec.js index d529d881..b6e5626d 100644 --- a/src/app/home/home.spec.js +++ b/src/app/home/home.spec.js @@ -4,6 +4,8 @@ * build process will exclude all `.spec.js` files from the build * automatically. */ +//TODO: this is all commented out because the way it is currently written will break the $ grunt watch task. +/* describe( 'home section', function() { beforeEach( module( 'orderCloud' ) ); //TODO: this used to be orderCloud.home because it was it's own module but now it is just chained onto orderCloud... how would we write the test for 'home section' in this case? @@ -12,4 +14,5 @@ describe( 'home section', function() { expect( true ).toBeTruthy(); }); }); +*/ diff --git a/src/app/home/templates/home.tpl.html b/src/app/home/templates/home.tpl.html index 8fbf4743..de44443e 100644 --- a/src/app/home/templates/home.tpl.html +++ b/src/app/home/templates/home.tpl.html @@ -1,4 +1,5 @@

OrderCloud AngularJS Seed

Everything you need to kickstart AngularJS projects for OrderCloud: a best-practice directory structure, an intelligent build system, and the best web design libraries around.

+

{{home.example}}

From 2ff3d20b2d9e676fe620e59d75e6d77db4a26ba2 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 29 Apr 2015 16:11:34 -0500 Subject: [PATCH 010/367] Update the version of Ambient to the latest release --- bower.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bower.json b/bower.json index bd370443..4723d77a 100644 --- a/bower.json +++ b/bower.json @@ -9,7 +9,7 @@ "angular-messages": "~1.4.0-rc.1", "angular-animate": "~1.4.0-rc.1", "angular-touch": "~1.4.0-rc.1", - "ambient": "~1.3.6", + "ambient": "~1.3.7", "jquery": "~2.1.3", "font-awesome": "~4.3.0", "ordercloud-angular-sdk": "~0.0.11" From 8ee863c0d8b4af37c05ad241eaae24d3ca260c43 Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 11 May 2015 16:02:29 -0500 Subject: [PATCH 011/367] Update to SDK version ~0.1.1 --- bower.json | 2 +- src/app/app.js | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/bower.json b/bower.json index 4723d77a..6bb346f2 100644 --- a/bower.json +++ b/bower.json @@ -12,7 +12,7 @@ "ambient": "~1.3.7", "jquery": "~2.1.3", "font-awesome": "~4.3.0", - "ordercloud-angular-sdk": "~0.0.11" + "ordercloud-angular-sdk": "~0.1.1" }, "dependencies": {} } diff --git a/src/app/app.js b/src/app/app.js index 9b2e69dc..59149efd 100644 --- a/src/app/app.js +++ b/src/app/app.js @@ -11,7 +11,19 @@ angular.module( 'orderCloud', [ .config( Routing ) .config( ErrorHandling ) .controller( 'AppCtrl', AppCtrl ) + .constant('appname', 'oc') + /* + Test + .constant('authurl', 'https://testauth.ordercloud.io/oauth/token') + .constant('apiurl', 'https://testapi.ordercloud.io/api') + .constant('clientid', '8ec8ecdb-ccef-4294-802e-2c863cf061df') + */ + + //Local + .constant('authurl', 'http://core.four51.com:11629/OAuth/token') + .constant('apiurl', 'http://core.four51.com:9002/api') + .constant('clientid', '5e841037-b21c-4784-8cbb-746c4f1468ed') ; function AppCtrl( $scope ) { From 7c7f693107e80471e33ee8db0d096821da77b83a Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 27 May 2015 09:42:06 -0500 Subject: [PATCH 012/367] Update to latest AngularJS release Also ordercloud-angular-sdk and Ambient updated to their latest versions --- bower.json | 16 ++++++++-------- src/app/app.js | 3 ++- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/bower.json b/bower.json index 6bb346f2..30060c0f 100644 --- a/bower.json +++ b/bower.json @@ -2,17 +2,17 @@ "name": "orderCloud", "version": "0.0.3", "devDependencies": { - "angular": "~1.4.0-rc.1", - "angular-mocks": "~1.4.0-rc.1", - "angular-sanitize": "~1.4.0-rc.1", + "angular": "~1.4.0", + "angular-mocks": "~1.4.0", + "angular-sanitize": "~1.4.0", "angular-ui-router": "~0.2.14", - "angular-messages": "~1.4.0-rc.1", - "angular-animate": "~1.4.0-rc.1", - "angular-touch": "~1.4.0-rc.1", - "ambient": "~1.3.7", + "angular-messages": "~1.4.0", + "angular-animate": "~1.4.0", + "angular-touch": "~1.4.0", + "ambient": "~1.4.1", "jquery": "~2.1.3", "font-awesome": "~4.3.0", - "ordercloud-angular-sdk": "~0.1.1" + "ordercloud-angular-sdk": "~0.2.8" }, "dependencies": {} } diff --git a/src/app/app.js b/src/app/app.js index 59149efd..29d953b5 100644 --- a/src/app/app.js +++ b/src/app/app.js @@ -11,7 +11,8 @@ angular.module( 'orderCloud', [ .config( Routing ) .config( ErrorHandling ) .controller( 'AppCtrl', AppCtrl ) - .constant('appname', 'oc') + .constant('ocscope', 'FullAccess') + .constant('appname', 'OrderCloud') /* Test From 6d655681a913f76e6cfb032f215bec34adfb007f Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 27 May 2015 12:06:56 -0500 Subject: [PATCH 013/367] Use postcss:autoprefixer because grunt-autoprefixer .process() will be deprecated --- Gruntfile.js | 31 ++++++++++++------------------- package.json | 2 ++ 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index b3891486..48539ab1 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -15,7 +15,7 @@ module.exports = function ( grunt ) { grunt.loadNpmTasks('grunt-karma'); grunt.loadNpmTasks('grunt-ng-annotate'); grunt.loadNpmTasks('grunt-html2js'); - grunt.loadNpmTasks('grunt-autoprefixer'); + grunt.loadNpmTasks('grunt-postcss'); /** @@ -234,29 +234,22 @@ module.exports = function ( grunt ) { } } }, - /** - * https://github.com/nDmitry/grunt-autoprefixer - * `autoprefixer` looks at the compiled CSS and adds any necessary - * browser-specific prefixes needed for newer CSS rules. The autoprefixer default - * options are set below and it is used in the build, compile, and watch tasks. + * Postcss is a plugin for using postcss processors, like autoprefixer. We only need to + * run autoprefixer during the build process because the compile task simply copies the + * already prefixed CSS into the compile directory and minifies it. */ - //TODO:make sure this works in the compile task - autoprefixer: { + postcss: { options: { - browsers: ['> 1%', 'last 2 versions', 'Safari 7'], - cascade: true, - remove: true, - diff: false, - map: false, - silent: false + processors: [ + require('autoprefixer-core')({browsers: ['> 1%', 'last 2 versions', 'Safari 7']}) + ] }, - single_file: { + build: { src: '<%= build_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.css', dest: '<%= build_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.css' } }, - /** * HTML2JS is a Grunt plugin that takes all of your template files and * places them into JavaScript files as strings that are added to @@ -423,7 +416,7 @@ module.exports = function ( grunt ) { */ less: { files: [ 'src/**/*.less' ], - tasks: [ 'less_imports:build', 'less:build', 'autoprefixer' ] + tasks: [ 'less_imports:build', 'less:build', 'postcss' ] }, /** @@ -464,7 +457,7 @@ module.exports = function ( grunt ) { */ grunt.registerTask( 'build', [ 'clean', 'html2js', 'less_imports:build', 'less:build', - 'concat:build_css', 'copy:build_app_assets', 'copy:build_vendor_assets', 'autoprefixer', + 'concat:build_css', 'copy:build_app_assets', 'copy:build_vendor_assets', 'postcss', 'copy:build_appjs', 'copy:build_vendorjs', 'index:build', 'karmaconfig', 'karma:continuous' ]); @@ -474,7 +467,7 @@ module.exports = function ( grunt ) { * minifying your code. */ grunt.registerTask( 'compile', [ - 'less:compile', 'copy:compile_assets', 'autoprefixer', 'ngAnnotate', 'concat:compile_js', 'uglify', 'index:compile' + 'less:compile', 'postcss', 'copy:compile_assets', 'ngAnnotate', 'concat:compile_js', 'uglify', 'index:compile' ]); /** diff --git a/package.json b/package.json index f98860f9..8dded564 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ }, "dependencies": {}, "devDependencies": { + "autoprefixer-core": "^5.2.0", "grunt": "~0.4.1", "grunt-autoprefixer": "^2.2.0", "grunt-bump": "0.0.6", @@ -28,6 +29,7 @@ "grunt-karma": "^0.8.3", "grunt-less-imports": "^1.1.0", "grunt-ng-annotate": "^0.9.2", + "grunt-postcss": "^0.4.0", "karma": "^0.12.31", "karma-firefox-launcher": "^0.1.4", "karma-jasmine": "^0.1.5" From 0db00ef498033c2719d7c7c62cdbb60e9f7ec9f5 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 27 May 2015 12:07:42 -0500 Subject: [PATCH 014/367] Remove grunt-autoprefixer from devDependencies --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 8dded564..dd058917 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,6 @@ "devDependencies": { "autoprefixer-core": "^5.2.0", "grunt": "~0.4.1", - "grunt-autoprefixer": "^2.2.0", "grunt-bump": "0.0.6", "grunt-contrib-clean": "^0.4.1", "grunt-contrib-concat": "^0.3.0", From e5fd18afd3a7c9fbdb0251eff0926a06d4867297 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 2 Jun 2015 14:49:34 -0500 Subject: [PATCH 015/367] Versioned API endpoint --- src/app/app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/app.js b/src/app/app.js index 29d953b5..49913a0d 100644 --- a/src/app/app.js +++ b/src/app/app.js @@ -17,13 +17,13 @@ angular.module( 'orderCloud', [ /* Test .constant('authurl', 'https://testauth.ordercloud.io/oauth/token') - .constant('apiurl', 'https://testapi.ordercloud.io/api') + .constant('apiurl', 'https://testapi.ordercloud.io/v1') .constant('clientid', '8ec8ecdb-ccef-4294-802e-2c863cf061df') */ //Local .constant('authurl', 'http://core.four51.com:11629/OAuth/token') - .constant('apiurl', 'http://core.four51.com:9002/api') + .constant('apiurl', 'http://core.four51.com:9002/v1') .constant('clientid', '5e841037-b21c-4784-8cbb-746c4f1468ed') ; From 2ca43fe07774a3215df0c5684198e6155bfd2ca4 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 4 Aug 2015 18:31:04 -0500 Subject: [PATCH 016/367] Gulp Component Setup --- Gruntfile.js | 538 ------------------------- Gulp/assetTasks.js | 125 ++++++ Gulp/generalTasks.js | 45 +++ Gulp/scriptTasks.js | 89 ++++ Gulp/testTasks.js | 0 Gulp/watchTasks.js | 65 +++ Gulpfile.js | 14 + bower.json | 12 +- build.config.js | 81 ---- gulpConfig.js | 71 ++++ karma.conf.js | 67 +++ package.json | 53 ++- src/app/app.js | 40 +- src/app/app.spec.js | 7 - src/app/base/base.js | 24 ++ src/app/base/templates/base.tpl.html | 37 ++ src/app/home/home.js | 18 +- src/app/home/templates/home.tpl.html | 7 +- src/app/login/less/login.less | 4 + src/app/login/login.js | 31 ++ src/app/login/templates/login.tpl.html | 15 + src/app/variables.less | 4 +- src/index.html | 29 +- 23 files changed, 685 insertions(+), 691 deletions(-) delete mode 100644 Gruntfile.js create mode 100644 Gulp/assetTasks.js create mode 100644 Gulp/generalTasks.js create mode 100644 Gulp/scriptTasks.js create mode 100644 Gulp/testTasks.js create mode 100644 Gulp/watchTasks.js create mode 100644 Gulpfile.js delete mode 100644 build.config.js create mode 100644 gulpConfig.js create mode 100644 karma.conf.js create mode 100644 src/app/base/base.js create mode 100644 src/app/base/templates/base.tpl.html create mode 100644 src/app/login/less/login.less create mode 100644 src/app/login/login.js create mode 100644 src/app/login/templates/login.tpl.html diff --git a/Gruntfile.js b/Gruntfile.js deleted file mode 100644 index 48539ab1..00000000 --- a/Gruntfile.js +++ /dev/null @@ -1,538 +0,0 @@ -module.exports = function ( grunt ) { - - /** - * Load required Grunt tasks. These are installed based on the versions listed - * in `package.json` when you do `npm install` in this directory. - */ - grunt.loadNpmTasks('grunt-contrib-clean'); - grunt.loadNpmTasks('grunt-contrib-copy'); - grunt.loadNpmTasks('grunt-contrib-concat'); - grunt.loadNpmTasks('grunt-contrib-watch'); - grunt.loadNpmTasks('grunt-contrib-uglify'); - grunt.loadNpmTasks('grunt-less-imports'); - grunt.loadNpmTasks('grunt-contrib-less'); - grunt.loadNpmTasks('grunt-conventional-changelog'); - grunt.loadNpmTasks('grunt-karma'); - grunt.loadNpmTasks('grunt-ng-annotate'); - grunt.loadNpmTasks('grunt-html2js'); - grunt.loadNpmTasks('grunt-postcss'); - - - /** - * Load in our build configuration file. - */ - var userConfig = require( './build.config.js' ); - - /** - * This is the configuration object Grunt uses to give each plugin its - * instructions. - */ - var taskConfig = { - /** - * We read in our `package.json` file so we can access the package name and - * version. It's already there, so we don't repeat ourselves here. - */ - pkg: grunt.file.readJSON("package.json"), - - /** - * The banner is the comment that is placed at the top of our compiled - * source files. It is first processed as a Grunt template, where the `<%=` - * pairs are evaluated based on this very configuration object. - */ - meta: { - banner: - '/**\n' + - ' * <%= pkg.name %> - v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %>\n' + - ' * <%= pkg.homepage %>\n' + - ' *\n' + - ' * Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' + - ' * Licensed <%= pkg.licenses.type %> <<%= pkg.licenses.url %>>\n' + - ' */\n' - }, - - /** - * Creates a changelog on a new version. - */ - changelog: { - options: { - dest: 'CHANGELOG.md', - template: 'changelog.tpl' - } - }, - - /** - * The directories to delete when `grunt clean` is executed. - */ - clean: [ - '<%= build_dir %>', - '<%= compile_dir %>', - '<%= temp_dir %>' - ], - - /** - * The `copy` task just copies files from A to B. We use it here to copy - * our project assets (images, fonts, etc.) and javascripts into - * `build_dir`, and then to copy the assets to `compile_dir`. - */ - copy: { - build_app_assets: { - files: [ - { - src: [ '**' ], - dest: '<%= build_dir %>/assets/', - cwd: 'src/assets', - expand: true - } - ] - }, - build_vendor_assets: { - files: [ - { - src: [ '<%= vendor_files.assets %>' ], - dest: '<%= build_dir %>/assets/', - cwd: '.', - expand: true, - flatten: true - } - ] - }, - build_appjs: { - files: [ - { - src: [ '<%= app_files.js %>' ], - dest: '<%= build_dir %>/', - cwd: '.', - expand: true - } - ] - }, - build_vendorjs: { - files: [ - { - src: [ '<%= vendor_files.js %>' ], - dest: '<%= build_dir %>/', - cwd: '.', - expand: true - } - ] - }, - compile_assets: { - files: [ - { - src: [ '**' ], - dest: '<%= compile_dir %>/assets', - cwd: '<%= build_dir %>/assets', - expand: true - } - ] - } - }, - - /** - * `grunt concat` concatenates multiple source files into a single file. - */ - concat: { - /** - * The `build_css` target concatenates compiled CSS and vendor CSS - * together. - */ - build_css: { - src: [ - '<%= vendor_files.css %>', - '<%= build_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.css' - ], - dest: '<%= build_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.css' - }, - /** - * The `compile_js` target is the concatenation of our application source - * code and all specified vendor source code into a single file. - */ - compile_js: { - options: { - banner: '<%= meta.banner %>' - }, - src: [ - '<%= vendor_files.js %>', - 'module.prefix', - '<%= build_dir %>/src/**/*.js', - '<%= html2js.app.dest %>', - 'module.suffix' - ], - dest: '<%= compile_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.js' - } - }, - - /** - * `ng-annotate` annotates the sources before minifying. That is, it allows us - * to code without the array syntax. - */ - ngAnnotate: { - compile: { - files: [ - { - src: [ '<%= app_files.js %>' ], - cwd: '<%= build_dir %>', - dest: '<%= build_dir %>', - expand: true - } - ] - } - }, - - /** - * Minify the sources! - */ - uglify: { - compile: { - options: { - banner: '<%= meta.banner %>' - }, - files: { - '<%= concat.compile_js.dest %>': '<%= concat.compile_js.dest %>' - } - } - }, - - /** - * `grunt-less-imports` handles importing of all LESS files into the src/less/main.less file. - * The app_files.import_less array in the build.config.js file drives where to look for these files. - */ - less_imports: { - build: { - options: { - import: 'less', - inlineCSS: false, - banner: '// This file was generated by the grunt-less-imports task in the build process. Do not alter this file, any changes you make will be overwritten the next time you build.' - }, - src: '<%= app_files.import_less %>', - dest: 'temp/imports.less' - } - }, - - /** - * `grunt-contrib-less` handles our LESS compilation and uglification automatically. - * Only our `main.less` file is included in compilation; all other files - * must be imported from this file. - */ - less: { - build: { - files: { - '<%= build_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.css': '<%= less_imports.build.dest %>' - }, - options: { - strictImports:true - } - }, - compile: { - files: { - '<%= build_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.css': '<%= less_imports.build.dest %>' - }, - options: { - strictImports:true, - cleancss: true, - compress: true - } - } - }, - /** - * Postcss is a plugin for using postcss processors, like autoprefixer. We only need to - * run autoprefixer during the build process because the compile task simply copies the - * already prefixed CSS into the compile directory and minifies it. - */ - postcss: { - options: { - processors: [ - require('autoprefixer-core')({browsers: ['> 1%', 'last 2 versions', 'Safari 7']}) - ] - }, - build: { - src: '<%= build_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.css', - dest: '<%= build_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.css' - } - }, - /** - * HTML2JS is a Grunt plugin that takes all of your template files and - * places them into JavaScript files as strings that are added to - * AngularJS's template cache. This means that the templates too become - * part of the initial payload as one JavaScript file. Neat! - */ - html2js: { - /** - * These are the templates from `src/app`. - */ - app: { - options: { - base: 'src/app' - }, - src: [ '<%= app_files.atpl %>' ], - dest: '<%= build_dir %>/templates-app.js' - } - }, - - /** - * The Karma configurations. - */ - karma: { - options: { - configFile: '<%= build_dir %>/karma-unit.js' - }, - unit: { - port: 9019, - background: true - }, - continuous: { - singleRun: true - } - }, - - /** - * The `index` task compiles the `index.html` file as a Grunt template. CSS - * and JS files co-exist here but they get split apart later. - */ - index: { - - /** - * During development, we don't want to have wait for compilation, - * concatenation, minification, etc. So to avoid these steps, we simply - * add all script files directly to the `` of `index.html`. The - * `src` property contains the list of included files. - */ - build: { - dir: '<%= build_dir %>', - src: [ - '<%= vendor_files.js %>', - '<%= build_dir %>/src/**/*.js', - '<%= html2js.app.dest %>', - '<%= vendor_files.css %>', - '<%= build_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.css' - ] - }, - - /** - * When it is time to have a completely compiled application, we can - * alter the above to include only a single JavaScript and a single CSS - * file. Now we're back! - */ - compile: { - dir: '<%= compile_dir %>', - src: [ - '<%= concat.compile_js.dest %>', - '<%= vendor_files.css %>', - '<%= build_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.css' - ] - } - }, - - /** - * This task compiles the karma template so that changes to its file array - * don't have to be managed manually. - */ - karmaconfig: { - unit: { - dir: '<%= build_dir %>', - src: [ - '<%= vendor_files.js %>', - '<%= html2js.app.dest %>', - '<%= test_files.js %>' - ] - } - }, - - /** - * And for rapid development, we have a watch set up that checks to see if - * any of the files listed below change, and then to execute the listed - * tasks when they do. This just saves us from having to type "grunt" into - * the command-line every time we want to see what we're working on; we can - * instead just leave "grunt watch" running in a background terminal. Set it - * and forget it, as Ron Popeil used to tell us. - * - * But we don't need the same thing to happen for all the files. - */ - delta: { - /** - * By default, we want the Live Reload to work for all tasks; this is - * overridden in some tasks (like this file) where browser resources are - * unaffected. It runs by default on port 35729, which your browser - * plugin should auto-detect. - */ - options: { - livereload: true - }, - - /** - * When the Gruntfile changes, we just want to lint it. In fact, when - * your Gruntfile changes, it will automatically be reloaded! - */ - gruntfile: { - files: 'Gruntfile.js', - tasks: [ ], - options: { - livereload: false - } - }, - - /** - * When our JavaScript source files change, we want to run lint them and - * run our unit tests. - */ - jssrc: { - files: [ - '<%= app_files.js %>' - ], - tasks: [ 'karma:unit:run', 'copy:build_appjs' ] - }, - - /** - * When assets are changed, copy them. Note that this will *not* copy new - * files, so this is probably not very useful. - */ - assets: { - files: [ - 'src/assets/**/*' - ], - tasks: [ 'copy:build_app_assets', 'copy:build_vendor_assets' ] - }, - - /** - * When index.html changes, we need to compile it. - */ - html: { - files: [ '<%= app_files.html %>' ], - tasks: [ 'index:build' ] - }, - - /** - * When our templates change, we only rewrite the template cache. - */ - tpls: { - files: [ - '<%= app_files.atpl %>' - ], - tasks: [ 'html2js' ] - }, - - /** - * When the CSS files change, we need to compile and minify them. - */ - less: { - files: [ 'src/**/*.less' ], - tasks: [ 'less_imports:build', 'less:build', 'postcss' ] - }, - - /** - * When a JavaScript unit test file changes, we only want to lint it and - * run the unit tests. We don't want to do any live reloading. - */ - jsunit: { - files: [ - '<%= app_files.jsunit %>' - ], - tasks: [ 'karma:unit:run' ], - options: { - livereload: false - } - } - } - }; - - grunt.initConfig( grunt.util._.extend( taskConfig, userConfig ) ); - - /** - * In order to make it safe to just compile or copy *only* what was changed, - * we need to ensure we are starting from a clean, fresh build. So we rename - * the `watch` task to `delta` (that's why the configuration var above is - * `delta`) and then add a new task called `watch` that does a clean build - * before watching for changes. - */ - grunt.renameTask( 'watch', 'delta' ); - grunt.registerTask( 'watch', [ 'build', 'karma:unit', 'delta' ] ); - - /** - * The default task is to build and compile. - */ - grunt.registerTask( 'default', [ 'build', 'compile' ] ); - - /** - * The `build` task gets your app ready to run for development and testing. - */ - grunt.registerTask( 'build', [ - 'clean', 'html2js', 'less_imports:build', 'less:build', - 'concat:build_css', 'copy:build_app_assets', 'copy:build_vendor_assets', 'postcss', - 'copy:build_appjs', 'copy:build_vendorjs', 'index:build', 'karmaconfig', - 'karma:continuous' - ]); - - /** - * The `compile` task gets your app ready for deployment by concatenating and - * minifying your code. - */ - grunt.registerTask( 'compile', [ - 'less:compile', 'postcss', 'copy:compile_assets', 'ngAnnotate', 'concat:compile_js', 'uglify', 'index:compile' - ]); - - /** - * A utility function to get all app JavaScript sources. - */ - function filterForJS ( files ) { - return files.filter( function ( file ) { - return file.match( /\.js$/ ); - }); - } - - /** - * A utility function to get all app CSS sources. - */ - function filterForCSS ( files ) { - return files.filter( function ( file ) { - return file.match( /\.css$/ ); - }); - } - - /** - * The index.html template includes the stylesheet and javascript sources - * based on dynamic names calculated in this Gruntfile. This task assembles - * the list into variables for the template to use and then runs the - * compilation. - */ - grunt.registerMultiTask( 'index', 'Process index.html template', function () { - var dirRE = new RegExp( '^('+grunt.config('build_dir')+'|'+grunt.config('compile_dir')+')\/', 'g' ); - var jsFiles = filterForJS( this.filesSrc ).map( function ( file ) { - return file.replace( dirRE, '' ); - }); - var cssFiles = filterForCSS( this.filesSrc ).map( function ( file ) { - return file.replace( dirRE, '' ); - }); - - grunt.file.copy('src/index.html', this.data.dir + '/index.html', { - process: function ( contents, path ) { - return grunt.template.process( contents, { - data: { - scripts: jsFiles, - styles: cssFiles, - version: grunt.config( 'pkg.version' ) - } - }); - } - }); - }); - - /** - * In order to avoid having to specify manually the files needed for karma to - * run, we use grunt to manage the list for us. The `karma/*` files are - * compiled as grunt templates for use by Karma. Yay! - */ - grunt.registerMultiTask( 'karmaconfig', 'Process karma config templates', function () { - var jsFiles = filterForJS( this.filesSrc ); - - grunt.file.copy( 'karma/karma-unit.tpl.js', grunt.config( 'build_dir' ) + '/karma-unit.js', { - process: function ( contents, path ) { - return grunt.template.process( contents, { - data: { - scripts: jsFiles - } - }); - } - }); - }); - -}; diff --git a/Gulp/assetTasks.js b/Gulp/assetTasks.js new file mode 100644 index 00000000..063946d0 --- /dev/null +++ b/Gulp/assetTasks.js @@ -0,0 +1,125 @@ +//GENERAL +var gulp = require('gulp'); +var less = require('gulp-less'); +var sass = require('gulp-sass'); +var filter = require('gulp-filter'); +var autoprefixer = require('gulp-autoprefixer'); +var minify = require('gulp-minify-css'); +var mainBowerFiles = require('main-bower-files'); +var concat = require('gulp-concat'); +var clean = require('gulp-clean'); +var plumber = require('gulp-plumber'); +var lessImport = require('gulp-less-import'); + +var pkg = require('../package.json'); +var currVersion = pkg.name + "-" + pkg.version; +/*var lessFilter = filter('**!/!*.less'); +var sassFilter = filter(['**!/!*.sass', '**!/!*.scss']); +var cssFilter = filter('**!/!*.css');*/ + + +/*BUILD*/ + +gulp.task('b_m:less', function() { + return gulp.src(mainBowerFiles({filter: '**/*.less'}) + .concat(config.import_less)) + .pipe(plumber()) + .pipe(lessImport('lessStyles.less')) + .pipe(less()) + .pipe(gulp.dest(config.temp)) +}); + +gulp.task('b_m:sass', function() { + return gulp.src(mainBowerFiles({filter: ['**/*.sass', '**/*.scss']}) + .concat([config.source + '**/*.scss', config.source + '**/*.sass'])) + .pipe(plumber()) + .pipe(sass()) + .pipe(concat(config.temp + 'sassStyles.css')) + .pipe(gulp.dest(config.temp)) +}); + +gulp.task('b_m:css', function() { + return gulp + .src(mainBowerFiles({filter: '**/*.css'})) + .pipe(plumber()) + .pipe(autoprefixer({browsers: ['last 2 versions']})) + .pipe(concat('bowerStyles.css')) + .pipe(gulp.dest(config.temp)) +}); + +gulp.task('b_m:appCss', function() { + return gulp + .src(config.source + '**/*.css') + .pipe(plumber()) + .pipe(autoprefixer({browsers: ['last 2 versions']})) + .pipe(concat('appCss.css')) + .pipe(gulp.dest(config.temp)) +}); + +gulp.task('b_m:styles', function() { + return gulp + .src([config.temp + 'bowerStyles.css', config.temp + 'lessStyles.css', config.temp + 'sassStyles.css', config.temp + 'appCss.css']) + .pipe(concat(currVersion + '.css')) + .pipe(gulp.dest(config.build + 'assets')) + .pipe(browserSync.stream()) +}); + +gulp.task('b_c:styles', function() { + return gulp.src([config.build + 'assets/**/*.css', config.temp + '**/*' ], {read:false}) + .pipe(clean()); +}); + +gulp.task('b_m:assets', function() { + return gulp.src([ + config.source + 'assets/**/*', + '!' + config.source + '**/*.css', + '!' + config.source + '**/*.less', + '!' + config.source + '**/*.scss', + '!' + config.source + '**/*.sass']) + .pipe(gulp.dest(config.build + 'assets')) +}); + +gulp.task('b_c:assets', function() { + return gulp.src([ + config.build + 'assets/**/*', + '!' + config.build + '**/*.css', + '!' + config.build + '**/*.less', + '!' + config.build + '**/*.scss', + '!' + config.build + '**/*.sass'], {read:false}) + .pipe(clean()) +}); + +/*COMPILE*/ +gulp.task('c_m:css', function() { + return gulp.src(config.build + 'assets/**/*.css') + .pipe(minify()) + .pipe(gulp.dest(config.compile + 'assets/')); +}); + +gulp.task('c_c:css', function() { + return gulp + .src(config.compile + '**/*.css', {read:false}) + .pipe(clean()); +}); + +gulp.task('c_m:assets', function() { + return gulp.src([ + config.build + 'assets/**/*', + '!' + config.build + '**/*.css', + '!' + config.build + '**/*.less', + '!' + config.build + '**/*.scss', + '!' + config.build + '**/*.sass']) + .pipe(gulp.dest(config.compile + 'assets')) +}); + +gulp.task('c_c:assets', function() { + return gulp + .src([config.compile + 'assets/**/*', '!' + config.compile + 'assets/**/*.css'], {read:false}) + .pipe(clean()); +}); + +//Master Asset Tasks +gulp.task('build:styles', gulp.series('b_c:styles', 'b_m:less', 'b_m:sass', 'b_m:css', 'b_m:appCss', 'b_m:styles')); +gulp.task('compile:css', gulp.series('c_c:css', 'build:styles', 'c_m:css')); +gulp.task('build:assets', gulp.series('b_c:assets', 'b_m:assets')); +gulp.task('compile:assets', gulp.series('c_c:assets', 'build:assets', 'c_m:assets')); \ No newline at end of file diff --git a/Gulp/generalTasks.js b/Gulp/generalTasks.js new file mode 100644 index 00000000..8ef3b358 --- /dev/null +++ b/Gulp/generalTasks.js @@ -0,0 +1,45 @@ +var gulp = require('gulp'); +var inject = require('gulp-inject'); +var clean = require('gulp-clean'); +var pkg = require('../package.json'); +var currVersion = pkg.name + "-" + pkg.version; + + +gulp.task('compile:inject', function() { + return gulp.src(config.source + 'index.html') + .pipe(inject(gulp.src(config.compile + '/**/*', {read:false}), {ignorePath: config.compile.replace('.', ''), addRootSlash: false})) + .pipe(gulp.dest(config.compile)); + +}); + +gulp.task('build:inject', function() { + //task injects dep into index.html + return gulp + .src(config.source + 'index.html') + .pipe(inject(gulp.src([config.build + 'vendor/**/angular.js', config.build + 'vendor/**/*.js'], {read:false}), {name: 'bower', ignorePath: config.build.replace('.', ''), addRootSlash: false})) + .pipe(inject(gulp.src([ + config.build + '**/*.js', + config.build + 'assets/**/*.css', + "!" + config.build + 'src/**/*.spec.js', + '!' + config.build + 'vendor/**/*'], {read:false}), {ignorePath: config.build.replace('.', ''), addRootSlash: false})) + .pipe(gulp.dest(config.build)); +}); + + +gulp.task('masterClean', function() { + return gulp + .src([config.build, config.compile, config.temp]) + .pipe(clean({read:false})); +}); + +//Major Project Build Tasks +gulp.task('build', gulp.series( + 'masterClean', + gulp.parallel('build:js_bower', 'build:js', 'build:templateCache', 'build:styles', 'build:assets'), + 'build:inject')); + +//Major Project Compile Tasks +gulp.task('compile', gulp.series( + 'build', + gulp.parallel('compile:js', 'compile:assets', 'compile:css'), + 'compile:inject')); \ No newline at end of file diff --git a/Gulp/scriptTasks.js b/Gulp/scriptTasks.js new file mode 100644 index 00000000..0d7b6cbc --- /dev/null +++ b/Gulp/scriptTasks.js @@ -0,0 +1,89 @@ +var gulp = require('gulp'); +var header = require('gulp-header'); +var concat = require('gulp-concat'); +var mainBowerFiles = require('main-bower-files'); +var uglify = require('gulp-uglify'); +var filter = require('gulp-filter'); +var wrap = require('gulp-wrapper'); +var templatecache = require('gulp-angular-templatecache'); +var clean = require('gulp-clean'); +var ngAnnotate = require('gulp-ng-annotate'); + + +var pkg = require('../package.json'); +var banner = config.banner; +var currVersion = pkg.name + "-" + pkg.version; +var appJS = config.app_files.js; + + + +gulp.task('b_m:js_bower', function() { + return gulp + .src(mainBowerFiles()) + .pipe(filter(['**/*.js', '!**/bootstrap.js'])) + .pipe(gulp.dest(config.build + 'vendor')); +}); + +gulp.task('b_c:js_bower', function() { + return gulp + .src(config.build + 'vendor', {read:false}) + .pipe(clean()); +}); + +gulp.task('b_m:js', function() { + return gulp + .src(['./src/**/*.js', '!./src/**/*spec.js']) + .pipe(ngAnnotate()) + .pipe(wrap({ + header: "(function ( window, angular, undefined ) {\n 'use strict';\n", + footer: "})( window, window.angular );\n" + })) + .pipe(gulp.dest(config.build + 'src')); +}); + +gulp.task('b_c:js', function() { + return gulp + .src([config.build + 'src/**/*.js', '!' + config.build + 'src/**/templates-app.js'], {read:false}) + .pipe(clean()); +}); + +gulp.task('b_m:templateCache', function() { + return gulp + .src('./src/app/**/*.tpl.html') + .pipe(templatecache('templates-app.js',{ + standalone: true, + module: 'templates-app', + moduleSystem: 'IIFE'})) + .pipe(gulp.dest(config.build + 'src/')); +}); + +gulp.task('b_c:templateCache', function() { + return gulp + .src(config.build + 'src/templates-app.js', {read:false}) + .pipe(clean()); +}); + +gulp.task('c_m:js', function() { + return gulp + .src([config.build + 'vendor/angular.js', config.build + 'vendor/**/*.js', config.build + 'src/templates-app.js', config.build + 'src/app/app.js', config.build + 'src/**/*.js', '!' + config.build + 'src/**/*.spec.js']) + .pipe(concat('app.js')) + .pipe(uglify({})) + //TODO: gulp-header doesn't work with gulp-4.0 + //.pipe(header(banner, {pkg: pkg})) + .pipe(gulp.dest(config.compile + 'assets')); +}); + +gulp.task('c_c:js', function(){ + return gulp.src(config.compile + '**/*.js', {read:false}) + .pipe(clean()); +}); + + + +//Master Script Build Tasks +gulp.task('build:js', gulp.series('b_c:js', 'b_m:js')); +gulp.task('build:js_bower', gulp.series('b_c:js_bower', 'b_m:js_bower')); +gulp.task('build:templateCache', gulp.series('b_c:templateCache', 'b_m:templateCache')); + +//Master Script Compile Tasks +gulp.task('compile:js', gulp.series(gulp.parallel('c_c:js', 'build:js_bower', 'build:js', 'build:templateCache'), 'c_m:js')); diff --git a/Gulp/testTasks.js b/Gulp/testTasks.js new file mode 100644 index 00000000..e69de29b diff --git a/Gulp/watchTasks.js b/Gulp/watchTasks.js new file mode 100644 index 00000000..9ac8c66d --- /dev/null +++ b/Gulp/watchTasks.js @@ -0,0 +1,65 @@ +gulp = require('gulp'); +jshint = require('gulp-jshint'); +mainBowerFiles = require('main-bower-files'); +var watch = require('gulp-watch'); +var karma = require('gulp-karma'); + +var server = 'server.js'; +var vendorJS = mainBowerFiles({filter:'**/*.js'}); +var vendorCSS = mainBowerFiles({filter:'**/*.css'}); + +var gulp = require('gulp'); +browserSync = require('browser-sync').create(); + +browserSync.emitter.on('init', function() { + console.log("Browsersync is running..."); +}); + +gulp.task('dev', function() { + browserSync.init({ + server: { + baseDir: config.build, + index: 'index.html', + routes: '' + }, + port: 8000, + ghostMode: { + clicks: false, + forms: false, + scroll: false + }, + logPrefix: 'OrderCloud 3.0' + }) +}); + +gulp.task('karma:unit', function() { + return gulp.src([config.build + '**/*.spec.js']) + .pipe(karma({ + configFile:'karma.conf.js', + action: 'watch' + })) +}); + + +gulp.task('watch:js', function() { + console.log("running 'watch:js' task"); + gulp.watch(config.app_files.js, gulp.series('build:js', 'build:inject', function() {browserSync.reload()})); + gulp.watch(vendorJS, gulp.series('build:js_bower', 'build:inject', function() {browserSync.reload()})); +}); + +gulp.task('watch:assets', function() { + console.log("running 'watch:assets' task"); + gulp.watch(config.app_files.assets, gulp.series('build:assets', 'build:inject', function() {browserSync.reload()})); + gulp.watch(config.supportedStyles, gulp.series('build:styles')); +}); + +gulp.task('watch:other', function() { + console.log("running 'watch:other' task"); + gulp.watch(config.app_files.atpl, gulp.series('build:templateCache', 'build:inject', function() {browserSync.reload()})); + gulp.watch(config.source + config.index, gulp.series( 'build:inject', function() {browserSync.reload()})); +}); + + //TODO: need to add new/deleted file watch if it ever comes available in gulp 4.0 + + +gulp.task('watch', gulp.parallel('dev','watch:js', 'watch:assets', 'watch:other', 'karma:unit')); diff --git a/Gulpfile.js b/Gulpfile.js new file mode 100644 index 00000000..e68f09e1 --- /dev/null +++ b/Gulpfile.js @@ -0,0 +1,14 @@ +//Global gulp variables +var gulp = require('gulp'); +var fs = require('fs'); +config = require('./gulpConfig'); +var path = require('path'); + + +//require gulpfiles in order... + +require('./Gulp/testTasks'); +require('./Gulp/scriptTasks'); +require('./Gulp/assetTasks'); +require('./Gulp/generalTasks'); +require('./Gulp/watchTasks'); \ No newline at end of file diff --git a/bower.json b/bower.json index 30060c0f..677dd6ac 100644 --- a/bower.json +++ b/bower.json @@ -2,17 +2,19 @@ "name": "orderCloud", "version": "0.0.3", "devDependencies": { + "angular-mocks": "~1.4.0" + }, + "dependencies": { "angular": "~1.4.0", - "angular-mocks": "~1.4.0", "angular-sanitize": "~1.4.0", "angular-ui-router": "~0.2.14", "angular-messages": "~1.4.0", "angular-animate": "~1.4.0", "angular-touch": "~1.4.0", - "ambient": "~1.4.1", "jquery": "~2.1.3", "font-awesome": "~4.3.0", - "ordercloud-angular-sdk": "~0.2.8" - }, - "dependencies": {} + "ordercloud-angular-sdk": "~0.6.6", + "bootstrap": "~3.3.5", + "angular-bootstrap": "~0.13.2" + } } diff --git a/build.config.js b/build.config.js deleted file mode 100644 index e2d3bce0..00000000 --- a/build.config.js +++ /dev/null @@ -1,81 +0,0 @@ -/** - * This file/module contains all configuration for the build process. - */ -module.exports = { - /** - * The `build_dir` folder is where our projects are compiled during - * development and the `compile_dir` folder is where our app resides once it's - * completely built. - */ - build_dir: 'build', - compile_dir: 'compile', - temp_dir: 'temp', - - /** - * This is a collection of file patterns that refer to our app code (the - * stuff in `src/`). These file paths are used in the configuration of - * build tasks. `js` is all project javascript, less tests. `ctpl` contains - * our reusable components' (`src/common`) template HTML files, while - * `atpl` contains the same, but for our app's code. `html` is just our - * main HTML file, `less` is our main stylesheet, and `unit` contains our - * app's unit tests. - */ - app_files: { - js: [ 'src/**/*.js', '!src/**/*.spec.js', '!src/assets/**/*.js' ], - jsunit: [ 'src/**/*.spec.js' ], - - atpl: [ 'src/app/**/*.tpl.html' ], - - html: [ 'src/index.html' ], - import_less: [ - 'vendor/normalize-css/normalize.css', //ambient dependency - 'vendor/ambient/less/ambient.less', - 'vendor/font-awesome/less/font-awesome.less', - 'src/app/**/*.less' - ] - }, - - /** - * This is a collection of files used during testing only. - */ - test_files: { - js: [ - 'vendor/angular-mocks/angular-mocks.js' - ] - }, - - /** - * This is the same as `app_files`, except it contains patterns that - * reference vendor code (`vendor/`) that we need to place into the build - * process somewhere. While the `app_files` property ensures all - * standardized files are collected for compilation, it is the user's job - * to ensure non-standardized (i.e. vendor-related) files are handled - * appropriately in `vendor_files.js`. - * - * The `vendor_files.js` property holds files to be automatically - * concatenated and minified with our project source files. - * - * The `vendor_files.css` property holds any CSS files to be automatically - * included in our app. - * - * The `vendor_files.assets` property holds any assets to be copied along - * with our app's assets. This structure is flattened, so it is not - * recommended that you use wildcards. - */ - vendor_files: { - js: [ - 'vendor/angular/angular.js', - 'vendor/angular-sanitize/angular-sanitize.js', - 'vendor/angular-messages/angular-messages.js', - 'vendor/angular-animate/angular-animate.js', - 'vendor/angular-touch/angular-touch.js', - 'vendor/angular-ui-router/release/angular-ui-router.js', - 'vendor/jquery/dist/jquery.js', - 'vendor/ordercloud-angular-sdk/dist/ordercloud-angular-sdk.js' - ], - css: [ - ], - assets: [ - ] - } -}; diff --git a/gulpConfig.js b/gulpConfig.js new file mode 100644 index 00000000..ac746a82 --- /dev/null +++ b/gulpConfig.js @@ -0,0 +1,71 @@ +var source = './src/'; +var build = './build/'; +var compile = './compile/'; +var root = './'; +var index = 'index.html'; +var temp = './temp/'; +var gulp_dir = './Gulp'; + +module.exports = { + source: source, + gulp_dir: gulp_dir, + banner: ['/**', + ' * <%= pkg.name %> - <%= pkg.description %>', + ' * @version v<%= pkg.version %>', + ' * @link <%= pkg.homepage %>', + ' * @license <%= pkg.licenses.url %>', + ' */', + ''].join('\n'), + allCSS: [ + source + '**/*.css', + source + '**/*.less', + source + '**/*.sass' + ], + allHTML: [ + source + '**/*.html' + ], + allJS: [ + source + '**/*.js', + './*.js', + './gulp/**/*.js' + ], + build: build, + compile: compile, + fonts: [ + source + 'assets/fonts/**.*' + ], + htmlTemplates: [ + source + '**/*.html', + '!' + source + index + ], + index: index, + npm_pkg: './package.json', + bower_pkg: './bower.json', + src: source, + supportedStyles: [ + source + '**/*.css', + source + '**/*.less', + source + '**/*.sass', + source + '**/*.scss' + ], + temp: temp, + root: root, + import_less: [ + 'vendor/font-awesome/less/font-awesome.less', + source + 'app/**/*.less' + ], + app_files: { + js: [ source + '**/*.js', '!' + source + '**/*.spec.js', '!' + source + 'assets/**/*.js' ], + assets: [source + 'assets/**'], + jsunit: [ source + '**/*.spec.js' ], + + atpl: [ source + 'app/**/*.tpl.html' ], + + html: [ source + 'index.html' ], + import_less: [ + 'vendor/font-awesome/less/font-awesome.less', + source + 'app/**/*.less' + ] + } + +}; \ No newline at end of file diff --git a/karma.conf.js b/karma.conf.js new file mode 100644 index 00000000..97961d64 --- /dev/null +++ b/karma.conf.js @@ -0,0 +1,67 @@ +// Karma configuration +// Generated on Mon Jul 27 2015 17:53:54 GMT-0500 (Central Daylight Time) +module.exports = function(config) { + var mainBowerFiles = require('main-bower-files'); + config.set({ + + // base path that will be used to resolve all patterns (eg. files, exclude) + basePath: '', + + + // frameworks to use + // available frameworks: https://npmjs.org/browse/keyword/karma-adapter + frameworks: ['jasmine'], + + + // list of files / patterns to load in the browser + files: [].concat( + mainBowerFiles({filter: '**/*.js'}), + './src/**/*.module.js', + './src/**/*.js' + ), + + + // list of files to exclude + exclude: [ + ], + + + // preprocess matching files before serving them to the browser + // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor + preprocessors: { + }, + + + // test results reporter to use + // possible values: 'dots', 'progress' + // available reporters: https://npmjs.org/browse/keyword/karma-reporter + reporters: ['progress'], + + + // web server port + port: 9876, + + + // enable / disable colors in the output (reporters and logs) + colors: true, + + + // level of logging + // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG + logLevel: config.LOG_INFO, + + + // enable / disable watching file and executing tests whenever any file changes + autoWatch: false, + + + // start these browsers + // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher + browsers: ['Chrome'], + + + // Continuous Integration mode + // if true, Karma captures browsers, runs the tests and exits + singleRun: false + }) +} diff --git a/package.json b/package.json index dd058917..3a598869 100644 --- a/package.json +++ b/package.json @@ -14,23 +14,42 @@ }, "dependencies": {}, "devDependencies": { - "autoprefixer-core": "^5.2.0", - "grunt": "~0.4.1", - "grunt-bump": "0.0.6", - "grunt-contrib-clean": "^0.4.1", - "grunt-contrib-concat": "^0.3.0", - "grunt-contrib-copy": "^0.4.1", - "grunt-contrib-less": "^0.11.4", - "grunt-contrib-uglify": "^0.2.7", - "grunt-contrib-watch": "^0.4.4", - "grunt-conventional-changelog": "^0.1.2", - "grunt-html2js": "^0.1.9", - "grunt-karma": "^0.8.3", - "grunt-less-imports": "^1.1.0", - "grunt-ng-annotate": "^0.9.2", - "grunt-postcss": "^0.4.0", + "browser-sync": "^2.8.0", + "browserify": "^11.0.0", + "fs": "0.0.2", + "gulp": "git://github.com/gulpjs/gulp.git#4.0", + "gulp-angular-templatecache": "^1.7.0", + "gulp-autoprefixer": "^2.3.1", + "gulp-clean": "^0.3.1", + "gulp-concat": "^2.6.0", + "gulp-copy": "0.0.2", + "gulp-filter": "^2.0.2", + "gulp-header": "^1.2.2", + "gulp-html2js": "^0.2.0", + "gulp-inject": "^1.5.0", + "gulp-jshint": "^1.11.2", + "gulp-karma": "0.0.4", + "gulp-less": "^3.0.3", + "gulp-less-import": "^1.0.0", + "gulp-minify-css": "^1.2.0", + "gulp-ng-annotate": "^1.0.0", + "gulp-plumber": "^1.0.1", + "gulp-sass": "^2.0.4", + "gulp-sourcemaps": "^1.5.2", + "gulp-uglify": "^1.2.0", + "gulp-util": "^3.0.6", + "gulp-watch": "^4.3.4", + "gulp-wrapper": "^1.0.0", + "json-file-plus": "^3.0.0", "karma": "^0.12.31", - "karma-firefox-launcher": "^0.1.4", - "karma-jasmine": "^0.1.5" + "karma-chrome-launcher": "^0.2.0", + "karma-firefox-launcher": "^0.1.6", + "karma-jasmine": "^0.1.5", + "main-bower-files": "^2.9.0", + "npm": "^2.13.0", + "path": "^0.11.14", + "synchro-prompt": "^1.1.0", + "vinyl-source-stream": "^1.1.0", + "watchify": "^3.3.0" } } diff --git a/src/app/app.js b/src/app/app.js index 49913a0d..24ed8397 100644 --- a/src/app/app.js +++ b/src/app/app.js @@ -5,35 +5,35 @@ angular.module( 'orderCloud', [ 'ngMessages', 'ngTouch', 'ui.router', + 'ui.bootstrap', 'orderCloud.sdk' ]) + .run( Security ) .config( Routing ) .config( ErrorHandling ) .controller( 'AppCtrl', AppCtrl ) .constant('ocscope', 'FullAccess') - .constant('appname', 'OrderCloud') + .constant('appname', 'OrderCloud AngularJS Seed') + .constant('clientid', '0e0450e6-27a0-4093-a6b3-d7cd9ebc2b8f') //DISTRIBUTOR + //.constant('clientid', 'f0976e5c-ed16-443a-98ad-d084c7010e05') //BUYER - /* - Test + + //Test .constant('authurl', 'https://testauth.ordercloud.io/oauth/token') .constant('apiurl', 'https://testapi.ordercloud.io/v1') - .constant('clientid', '8ec8ecdb-ccef-4294-802e-2c863cf061df') - */ - - //Local - .constant('authurl', 'http://core.four51.com:11629/OAuth/token') - .constant('apiurl', 'http://core.four51.com:9002/v1') - .constant('clientid', '5e841037-b21c-4784-8cbb-746c4f1468ed') ; -function AppCtrl( $scope ) { - var vm = this; - $scope.$on('$stateChangeSuccess', function( event, toState, toParams, fromState, fromParams ){ - if ( angular.isDefined( toState.data.pageTitle ) ) { - vm.pageTitle = 'OrderCloud | ' + toState.data.pageTitle; +function Security( $rootScope, $state, Auth ) { + $rootScope.$on('$stateChangeStart', function(e, to) { + if (!to.data.limitAccess) return; + Auth.IsAuthenticated() + .catch(sendToLogin); + + function sendToLogin() { + $state.go('login'); } - }); + }) } function Routing( $urlRouterProvider, $urlMatcherFactoryProvider ) { @@ -63,4 +63,12 @@ function ErrorHandling( $provide ) { $injector.get( '$rootScope' ).$broadcast( 'exception', ex, cause ); } } +} + +function AppCtrl( $state, Credentials ) { + var vm = this; + vm.logout = function() { + Credentials.Delete(); + $state.go('login'); + } } \ No newline at end of file diff --git a/src/app/app.spec.js b/src/app/app.spec.js index 8275aa13..e69de29b 100644 --- a/src/app/app.spec.js +++ b/src/app/app.spec.js @@ -1,7 +0,0 @@ -describe( 'AppCtrl', function() { - beforeEach( module( 'orderCloud' ) ); - - it( 'Our first test', function() { - expect(true).toBeTruthy(); - }); -}); diff --git a/src/app/base/base.js b/src/app/base/base.js new file mode 100644 index 00000000..9a936cb6 --- /dev/null +++ b/src/app/base/base.js @@ -0,0 +1,24 @@ +angular.module( 'orderCloud' ) + + .config( BaseConfig ) + .controller( 'BaseCtrl', BaseController ) + +; + +function BaseConfig( $stateProvider ) { + $stateProvider + .state( 'base', { + url: '', + abstract: true, + templateUrl:'base/templates/base.tpl.html', + controller:'BaseCtrl', + controllerAs: 'base', + data:{ + limitAccess: true + } + }) +} + +function BaseController( ) { + var vm = this; +} diff --git a/src/app/base/templates/base.tpl.html b/src/app/base/templates/base.tpl.html new file mode 100644 index 00000000..f84828c9 --- /dev/null +++ b/src/app/base/templates/base.tpl.html @@ -0,0 +1,37 @@ +
+ +
+
diff --git a/src/app/home/home.js b/src/app/home/home.js index 4e2571a3..06c85a1b 100644 --- a/src/app/home/home.js +++ b/src/app/home/home.js @@ -6,16 +6,16 @@ angular.module( 'orderCloud' ) ; function HomeConfig( $stateProvider ) { - $stateProvider.state( 'home', { - url: '/home', - templateUrl:'home/templates/home.tpl.html', - controller:'HomeCtrl', - controllerAs: 'home', - data:{ pageTitle: 'Home' } - }); + $stateProvider + .state( 'base.home', { + url: '/home', + templateUrl:'home/templates/home.tpl.html', + controller:'HomeCtrl', + controllerAs: 'home' + }) } -function HomeController( ) { +function HomeController( appname ) { var vm = this; - vm.example = 'Example Data'; + vm.appName = appname; } diff --git a/src/app/home/templates/home.tpl.html b/src/app/home/templates/home.tpl.html index de44443e..729a9575 100644 --- a/src/app/home/templates/home.tpl.html +++ b/src/app/home/templates/home.tpl.html @@ -1,5 +1,4 @@ -
-

OrderCloud AngularJS Seed

+
+

Everything you need to kickstart AngularJS projects for OrderCloud: a best-practice directory structure, an intelligent build system, and the best web design libraries around.

-

{{home.example}}

-
+ diff --git a/src/app/login/less/login.less b/src/app/login/less/login.less new file mode 100644 index 00000000..34333fad --- /dev/null +++ b/src/app/login/less/login.less @@ -0,0 +1,4 @@ +#Login { + max-width:300px; + margin:0 auto; +} \ No newline at end of file diff --git a/src/app/login/login.js b/src/app/login/login.js new file mode 100644 index 00000000..8d12feb6 --- /dev/null +++ b/src/app/login/login.js @@ -0,0 +1,31 @@ +angular.module( 'orderCloud' ) + + .config( LoginConfig ) + .controller( 'LoginCtrl', LoginController ) + +; + +function LoginConfig( $stateProvider ) { + $stateProvider.state( 'login', { + url: '/login', + templateUrl:'login/templates/login.tpl.html', + controller:'LoginCtrl', + controllerAs: 'login', + data:{ + limitAccess: false + } + }); +} + +function LoginController( $state, Credentials ) { + var vm = this; + + vm.submit = function( ) { + Credentials.Get( vm.credentials ).then( + function() { + $state.go( 'base.home' ); + }).catch(function( ex ) { + console.dir( ex ); + }); + }; +} diff --git a/src/app/login/templates/login.tpl.html b/src/app/login/templates/login.tpl.html new file mode 100644 index 00000000..4e42c474 --- /dev/null +++ b/src/app/login/templates/login.tpl.html @@ -0,0 +1,15 @@ +
+
+

Login

+
+ + +
+
+ + +
+ + Forgot Password? +
+
diff --git a/src/app/variables.less b/src/app/variables.less index 04e3d689..e47f2182 100644 --- a/src/app/variables.less +++ b/src/app/variables.less @@ -4,4 +4,6 @@ */ // Font-awesome var overwrite for referencing Bootstrap CDN font files directly -@fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.3.0/fonts"; \ No newline at end of file +@fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.3.0/fonts"; + +//Bootstrap Overwrites \ No newline at end of file diff --git a/src/index.html b/src/index.html index 9d75e233..f1b9a4fa 100644 --- a/src/index.html +++ b/src/index.html @@ -1,16 +1,19 @@ - - - - - <% styles.forEach( function ( file ) { %> - <% }); %> - + + + + OrderCloud + + + - -
- <% scripts.forEach( function ( file ) { %> - <% }); %> - - + + + + + + + + + \ No newline at end of file From e3edbbb67c716fc82a5f152572ba99bb44e86dd1 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 5 Aug 2015 12:48:13 -0500 Subject: [PATCH 017/367] Preparing to merge into the Master branch --- README.md | 17 +++++++++++++---- src/app/{app.js => _app.js} | 13 ++++++++----- src/app/{app.spec.js => _app.spec.js} | 0 src/app/base/base.js | 3 ++- src/app/base/base.spec.js | 0 src/app/base/less/base.less | 0 src/app/base/less/variables.less | 0 src/app/base/templates/base.tpl.html | 26 ++++++++------------------ src/app/global.less | 4 ++++ src/app/home/home.spec.js | 18 ------------------ src/app/login/less/login.less | 4 ++-- src/app/login/less/variables.less | 2 ++ src/app/login/login.js | 2 +- src/app/login/login.spec.js | 0 src/app/login/templates/login.tpl.html | 2 +- src/app/variables.less | 10 +++------- 16 files changed, 44 insertions(+), 57 deletions(-) rename src/app/{app.js => _app.js} (78%) rename src/app/{app.spec.js => _app.spec.js} (100%) create mode 100644 src/app/base/base.spec.js create mode 100644 src/app/base/less/base.less create mode 100644 src/app/base/less/variables.less create mode 100644 src/app/login/less/variables.less create mode 100644 src/app/login/login.spec.js diff --git a/README.md b/README.md index 2a92909c..381b11b2 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,11 @@ A seed project for custom Four51 Solutions built on AngularJS Node.js is required for the following node package manager (npm) tasks. If you don't have node.js installed, you can download it [here](http://nodejs.org/). ```sh -$ npm -g install grunt-cli karma bower +$ npm -g install karma bower +$ npm -g install "gulpjs/gulp-cli#4.0" $ npm install $ bower install -$ grunt build +$ gulp build ``` You should now have a few more directories in your project. @@ -43,6 +44,12 @@ At a high level, the structure looks roughly like this: ``` OrderCloud/ + |- Gulp/ + |- |- assetTasks.js + |- |- generalTasks.js + |- |- scriptTasks.js + |- |- testTasks.js + |- |- watchTasks.js |- karma/ |- node_modules/ |- src/ @@ -55,14 +62,16 @@ OrderCloud/ | |- |- .bowerrc |- bower.json - |- build.config.js - |- Gruntfile.js + |- gulpConfig.js + |- Gulpfile.js + |- karma.conf.js |- module.prefix |- module.suffix |- package.json ``` ### Detailed Installation +##Out dated - No longer using Grunt This section provides a little more detailed understanding of what goes into getting `OrderCloud` up and running. Though `OrderCloud` is really simple diff --git a/src/app/app.js b/src/app/_app.js similarity index 78% rename from src/app/app.js rename to src/app/_app.js index 24ed8397..c0dcccc9 100644 --- a/src/app/app.js +++ b/src/app/_app.js @@ -13,19 +13,22 @@ angular.module( 'orderCloud', [ .config( Routing ) .config( ErrorHandling ) .controller( 'AppCtrl', AppCtrl ) + + //Constants needed for the OrderCloud AngularJS SDK .constant('ocscope', 'FullAccess') .constant('appname', 'OrderCloud AngularJS Seed') - .constant('clientid', '0e0450e6-27a0-4093-a6b3-d7cd9ebc2b8f') //DISTRIBUTOR - //.constant('clientid', 'f0976e5c-ed16-443a-98ad-d084c7010e05') //BUYER + //Client ID for a Registered Distributor or Buyer Company + .constant('clientid', 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx') - //Test - .constant('authurl', 'https://testauth.ordercloud.io/oauth/token') - .constant('apiurl', 'https://testapi.ordercloud.io/v1') + //Test Environment + .constant('authurl', 'https://testauth.ordercloud.io/oauth/token') + .constant('apiurl', 'https://testapi.ordercloud.io/v1') ; function Security( $rootScope, $state, Auth ) { $rootScope.$on('$stateChangeStart', function(e, to) { + /*TODO: make the '$stateChangeStart event' accept a function so users can control the redirect from each state's declaration.*/ if (!to.data.limitAccess) return; Auth.IsAuthenticated() .catch(sendToLogin); diff --git a/src/app/app.spec.js b/src/app/_app.spec.js similarity index 100% rename from src/app/app.spec.js rename to src/app/_app.spec.js diff --git a/src/app/base/base.js b/src/app/base/base.js index 9a936cb6..ed8bb98b 100644 --- a/src/app/base/base.js +++ b/src/app/base/base.js @@ -14,7 +14,8 @@ function BaseConfig( $stateProvider ) { controller:'BaseCtrl', controllerAs: 'base', data:{ - limitAccess: true + limitAccess: true //Whether or not to require authentication on this state, this also affects any child states. + /*TODO: make the '$stateChangeStart event' in _app.js accept a function so users can control the redirect from here.*/ } }) } diff --git a/src/app/base/base.spec.js b/src/app/base/base.spec.js new file mode 100644 index 00000000..e69de29b diff --git a/src/app/base/less/base.less b/src/app/base/less/base.less new file mode 100644 index 00000000..e69de29b diff --git a/src/app/base/less/variables.less b/src/app/base/less/variables.less new file mode 100644 index 00000000..e69de29b diff --git a/src/app/base/templates/base.tpl.html b/src/app/base/templates/base.tpl.html index f84828c9..afacddbd 100644 --- a/src/app/base/templates/base.tpl.html +++ b/src/app/base/templates/base.tpl.html @@ -1,5 +1,5 @@ - + +
diff --git a/src/app/global.less b/src/app/global.less index 0726f102..42750a0f 100644 --- a/src/app/global.less +++ b/src/app/global.less @@ -1,3 +1,7 @@ +body { + padding-top:70px; // Source - http://getbootstrap.com/components/#callout-navbar-fixed-top-padding +} + [ui-sref] { cursor: pointer; } \ No newline at end of file diff --git a/src/app/home/home.spec.js b/src/app/home/home.spec.js index b6e5626d..e69de29b 100644 --- a/src/app/home/home.spec.js +++ b/src/app/home/home.spec.js @@ -1,18 +0,0 @@ -/** - * Tests sit right alongside the file they are testing, which is more intuitive - * and portable than separating `src` and `test` directories. Additionally, the - * build process will exclude all `.spec.js` files from the build - * automatically. - */ -//TODO: this is all commented out because the way it is currently written will break the $ grunt watch task. -/* -describe( 'home section', function() { - beforeEach( module( 'orderCloud' ) ); - //TODO: this used to be orderCloud.home because it was it's own module but now it is just chained onto orderCloud... how would we write the test for 'home section' in this case? - - it( 'should have a dummy test', function() { - expect( true ).toBeTruthy(); - }); -}); -*/ - diff --git a/src/app/login/less/login.less b/src/app/login/less/login.less index 34333fad..4ba4ca61 100644 --- a/src/app/login/less/login.less +++ b/src/app/login/less/login.less @@ -1,4 +1,4 @@ #Login { - max-width:300px; - margin:0 auto; + max-width: @login-form-width; + margin: 0 auto; } \ No newline at end of file diff --git a/src/app/login/less/variables.less b/src/app/login/less/variables.less new file mode 100644 index 00000000..6ecb95fd --- /dev/null +++ b/src/app/login/less/variables.less @@ -0,0 +1,2 @@ +// Variables specific to the Login Screen +@login-form-width: 300px; \ No newline at end of file diff --git a/src/app/login/login.js b/src/app/login/login.js index 8d12feb6..8376a333 100644 --- a/src/app/login/login.js +++ b/src/app/login/login.js @@ -12,7 +12,7 @@ function LoginConfig( $stateProvider ) { controller:'LoginCtrl', controllerAs: 'login', data:{ - limitAccess: false + limitAccess: false //Whether or not to require authentication on this state } }); } diff --git a/src/app/login/login.spec.js b/src/app/login/login.spec.js new file mode 100644 index 00000000..e69de29b diff --git a/src/app/login/templates/login.tpl.html b/src/app/login/templates/login.tpl.html index 4e42c474..f338d322 100644 --- a/src/app/login/templates/login.tpl.html +++ b/src/app/login/templates/login.tpl.html @@ -10,6 +10,6 @@

Login

- Forgot Password? + Forgot Password? diff --git a/src/app/variables.less b/src/app/variables.less index e47f2182..4c3ad302 100644 --- a/src/app/variables.less +++ b/src/app/variables.less @@ -1,9 +1,5 @@ -/** - * These are the variables used throughout the application. This is where - * overwrites that are not specific to components should be maintained. - */ +//These are the variables used throughout the application. This is where +//overwrites that are not specific to components should be maintained. // Font-awesome var overwrite for referencing Bootstrap CDN font files directly -@fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.3.0/fonts"; - -//Bootstrap Overwrites \ No newline at end of file +@fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.3.0/fonts"; \ No newline at end of file From faa089f3771a5ed3ffcb230cb714edf4e1fc2e90 Mon Sep 17 00:00:00 2001 From: Max Lund Date: Wed, 12 Aug 2015 16:25:14 -0500 Subject: [PATCH 018/367] added testServe task for external testing and updated asset tasks for font-awesome loading issues --- Gulp/assetTasks.js | 11 +++++++++-- Gulp/testTasks.js | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/Gulp/assetTasks.js b/Gulp/assetTasks.js index 063946d0..88605de2 100644 --- a/Gulp/assetTasks.js +++ b/Gulp/assetTasks.js @@ -40,7 +40,7 @@ gulp.task('b_m:sass', function() { gulp.task('b_m:css', function() { return gulp - .src(mainBowerFiles({filter: '**/*.css'})) + .src(mainBowerFiles({filter: '**/*.css'}).concat('!**/font-awesome.css')) .pipe(plumber()) .pipe(autoprefixer({browsers: ['last 2 versions']})) .pipe(concat('bowerStyles.css')) @@ -59,6 +59,7 @@ gulp.task('b_m:appCss', function() { gulp.task('b_m:styles', function() { return gulp .src([config.temp + 'bowerStyles.css', config.temp + 'lessStyles.css', config.temp + 'sassStyles.css', config.temp + 'appCss.css']) + .pipe(replace('../fonts/', 'fonts/')) .pipe(concat(currVersion + '.css')) .pipe(gulp.dest(config.build + 'assets')) .pipe(browserSync.stream()) @@ -79,6 +80,12 @@ gulp.task('b_m:assets', function() { .pipe(gulp.dest(config.build + 'assets')) }); +gulp.task('b_m:fonts', function() { + return gulp.src('vendor/**/fonts/*', '!vendor/**/dist') + .pipe(flatten()) + .pipe(gulp.dest(config.build + 'assets/fonts')) +}); + gulp.task('b_c:assets', function() { return gulp.src([ config.build + 'assets/**/*', @@ -121,5 +128,5 @@ gulp.task('c_c:assets', function() { //Master Asset Tasks gulp.task('build:styles', gulp.series('b_c:styles', 'b_m:less', 'b_m:sass', 'b_m:css', 'b_m:appCss', 'b_m:styles')); gulp.task('compile:css', gulp.series('c_c:css', 'build:styles', 'c_m:css')); -gulp.task('build:assets', gulp.series('b_c:assets', 'b_m:assets')); +gulp.task('build:assets', gulp.series('b_c:assets', 'b_m:assets', 'b_m:fonts')); gulp.task('compile:assets', gulp.series('c_c:assets', 'build:assets', 'c_m:assets')); \ No newline at end of file diff --git a/Gulp/testTasks.js b/Gulp/testTasks.js index e69de29b..07d32af6 100644 --- a/Gulp/testTasks.js +++ b/Gulp/testTasks.js @@ -0,0 +1,39 @@ +var gulp = require('gulp'); +var browserSync = require('browser-sync').create(); + +//Enter Server Info Here +var appName = null; //used for externally accessible site... must only include letters ('_', '-' not allowed) +var portNumber = 12000; //used for localhost + + + +if (appName) { + appName = appName.toLowerCase(); +} +if (portNumber) { + if (isNaN(portNumber)) { + portNumber = null; + console.log('portNumber must be numeric'); + } + if (portNumber < 10000 || portNumber > 65536) { + portNumber = null; + } +} + +gulp.task('testServe', function() { + browserSync.init({ + server: { + baseDir: config.build, + index: 'index.html', + routes: '' + }, + port: (portNumber || 8000), + ghostMode: { + clicks: false, + forms: false, + scroll: false + }, + logPrefix: 'OrderCloud 3.0', + tunnel: 'ordercloudapp' + (appName || '') + }) +}); \ No newline at end of file From c6c9b160a447088ab623bd59bf37c39e585d309e Mon Sep 17 00:00:00 2001 From: Max Lund Date: Wed, 12 Aug 2015 16:28:43 -0500 Subject: [PATCH 019/367] Updates to dependency requirements from last updates --- Gulp/assetTasks.js | 2 ++ package.json | 2 ++ 2 files changed, 4 insertions(+) diff --git a/Gulp/assetTasks.js b/Gulp/assetTasks.js index 88605de2..13d2f67d 100644 --- a/Gulp/assetTasks.js +++ b/Gulp/assetTasks.js @@ -10,6 +10,8 @@ var concat = require('gulp-concat'); var clean = require('gulp-clean'); var plumber = require('gulp-plumber'); var lessImport = require('gulp-less-import'); +var replace = require('gulp-replace'); +var flatten = require('gulp-flatten'); var pkg = require('../package.json'); var currVersion = pkg.name + "-" + pkg.version; diff --git a/package.json b/package.json index 3a598869..a8f39852 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "gulp-concat": "^2.6.0", "gulp-copy": "0.0.2", "gulp-filter": "^2.0.2", + "gulp-flatten": "^0.1.1", "gulp-header": "^1.2.2", "gulp-html2js": "^0.2.0", "gulp-inject": "^1.5.0", @@ -34,6 +35,7 @@ "gulp-minify-css": "^1.2.0", "gulp-ng-annotate": "^1.0.0", "gulp-plumber": "^1.0.1", + "gulp-replace": "^0.5.4", "gulp-sass": "^2.0.4", "gulp-sourcemaps": "^1.5.2", "gulp-uglify": "^1.2.0", From c7e71ab6703f7cd8119c8d62c21e8c34e68219ed Mon Sep 17 00:00:00 2001 From: Max Lund Date: Thu, 13 Aug 2015 09:06:02 -0500 Subject: [PATCH 020/367] Add option structure to javascript inject and compile --- Gulp/generalTasks.js | 6 ++++++ Gulp/scriptTasks.js | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Gulp/generalTasks.js b/Gulp/generalTasks.js index 8ef3b358..af79d887 100644 --- a/Gulp/generalTasks.js +++ b/Gulp/generalTasks.js @@ -18,6 +18,12 @@ gulp.task('build:inject', function() { .src(config.source + 'index.html') .pipe(inject(gulp.src([config.build + 'vendor/**/angular.js', config.build + 'vendor/**/*.js'], {read:false}), {name: 'bower', ignorePath: config.build.replace('.', ''), addRootSlash: false})) .pipe(inject(gulp.src([ + config.build + 'src/templates-app.js', + config.build + 'src/app/app.js', + config.build + '**/*.module.js', + config.build + '**/*.config.js', + config.build + '**/*.svc.js', + config.build + '**/*.ctrl.js', config.build + '**/*.js', config.build + 'assets/**/*.css', "!" + config.build + 'src/**/*.spec.js', diff --git a/Gulp/scriptTasks.js b/Gulp/scriptTasks.js index 0d7b6cbc..455b6b19 100644 --- a/Gulp/scriptTasks.js +++ b/Gulp/scriptTasks.js @@ -19,8 +19,8 @@ var appJS = config.app_files.js; gulp.task('b_m:js_bower', function() { return gulp - .src(mainBowerFiles()) - .pipe(filter(['**/*.js', '!**/bootstrap.js'])) + .src(mainBowerFiles({filter: ['**/*.js', '!**/bootstrap.js']})) + .pipe(filter('**/*.js')) .pipe(gulp.dest(config.build + 'vendor')); }); From 763e4217ea3d7859fa325f55e75d5f8bdb9f1152 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 13 Aug 2015 09:51:55 -0500 Subject: [PATCH 021/367] Remove font-awesome font path variable overwrite --- src/app/variables.less | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/app/variables.less b/src/app/variables.less index 4c3ad302..6c92855a 100644 --- a/src/app/variables.less +++ b/src/app/variables.less @@ -1,5 +1,2 @@ //These are the variables used throughout the application. This is where -//overwrites that are not specific to components should be maintained. - -// Font-awesome var overwrite for referencing Bootstrap CDN font files directly -@fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.3.0/fonts"; \ No newline at end of file +//overwrites that are not specific to components should be maintained. \ No newline at end of file From 1871e1e1c9b71944630285bcbcefe4f4b277f124 Mon Sep 17 00:00:00 2001 From: Max Lund Date: Tue, 18 Aug 2015 10:02:36 -0500 Subject: [PATCH 022/367] fix issue with font-compile, add 'default' task, and ensure '**/*.module.js' files get loaded before dependents --- Gulp/assetTasks.js | 3 ++- Gulp/generalTasks.js | 4 +++- Gulp/scriptTasks.js | 8 +++++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Gulp/assetTasks.js b/Gulp/assetTasks.js index 13d2f67d..54819ba7 100644 --- a/Gulp/assetTasks.js +++ b/Gulp/assetTasks.js @@ -94,7 +94,8 @@ gulp.task('b_c:assets', function() { '!' + config.build + '**/*.css', '!' + config.build + '**/*.less', '!' + config.build + '**/*.scss', - '!' + config.build + '**/*.sass'], {read:false}) + '!' + config.build + '**/*.sass', + '!' + config.build + 'assets/fonts/**/*'], {read:false}) .pipe(clean()) }); diff --git a/Gulp/generalTasks.js b/Gulp/generalTasks.js index af79d887..3eb0d720 100644 --- a/Gulp/generalTasks.js +++ b/Gulp/generalTasks.js @@ -48,4 +48,6 @@ gulp.task('build', gulp.series( gulp.task('compile', gulp.series( 'build', gulp.parallel('compile:js', 'compile:assets', 'compile:css'), - 'compile:inject')); \ No newline at end of file + 'compile:inject')); + +gulp.task('default', gulp.series('compile')); \ No newline at end of file diff --git a/Gulp/scriptTasks.js b/Gulp/scriptTasks.js index 455b6b19..edd3fb96 100644 --- a/Gulp/scriptTasks.js +++ b/Gulp/scriptTasks.js @@ -65,7 +65,13 @@ gulp.task('b_c:templateCache', function() { gulp.task('c_m:js', function() { return gulp - .src([config.build + 'vendor/angular.js', config.build + 'vendor/**/*.js', config.build + 'src/templates-app.js', config.build + 'src/app/app.js', config.build + 'src/**/*.js', '!' + config.build + 'src/**/*.spec.js']) + .src([config.build + 'vendor/angular.js', + config.build + 'vendor/**/*.js', + config.build + 'src/templates-app.js', + config.build + 'src/app/app.js', + config.build + 'src/app/**/*.module.js', + config.build + 'src/**/*.js', + '!' + config.build + 'src/**/*.spec.js']) .pipe(concat('app.js')) .pipe(uglify({})) //TODO: gulp-header doesn't work with gulp-4.0 From 3c0eba03d168423ba31164f1c092f5b593b161b6 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 20 Aug 2015 10:29:11 -0500 Subject: [PATCH 023/367] Split up Vendor LESS and App LESS --- Gulp/assetTasks.js | 2 +- gulpConfig.js | 13 ++++--------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/Gulp/assetTasks.js b/Gulp/assetTasks.js index 54819ba7..63628f1f 100644 --- a/Gulp/assetTasks.js +++ b/Gulp/assetTasks.js @@ -24,7 +24,7 @@ var cssFilter = filter('**!/!*.css');*/ gulp.task('b_m:less', function() { return gulp.src(mainBowerFiles({filter: '**/*.less'}) - .concat(config.import_less)) + .concat(config.vendor_files.import_less).concat(config.app_files.import_less)) .pipe(plumber()) .pipe(lessImport('lessStyles.less')) .pipe(less()) diff --git a/gulpConfig.js b/gulpConfig.js index ac746a82..c16522cd 100644 --- a/gulpConfig.js +++ b/gulpConfig.js @@ -50,10 +50,6 @@ module.exports = { ], temp: temp, root: root, - import_less: [ - 'vendor/font-awesome/less/font-awesome.less', - source + 'app/**/*.less' - ], app_files: { js: [ source + '**/*.js', '!' + source + '**/*.spec.js', '!' + source + 'assets/**/*.js' ], assets: [source + 'assets/**'], @@ -62,10 +58,9 @@ module.exports = { atpl: [ source + 'app/**/*.tpl.html' ], html: [ source + 'index.html' ], - import_less: [ - 'vendor/font-awesome/less/font-awesome.less', - source + 'app/**/*.less' - ] + import_less: [ source + 'app/**/*.less' ] + }, + vendor_files: { + import_less: ['vendor/font-awesome/less/font-awesome.less'] } - }; \ No newline at end of file From 66f2b2af222141119205b5e2e8bcdf5f83a374d1 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Tue, 22 Sep 2015 10:45:29 -0500 Subject: [PATCH 024/367] Update Seed Changes to the seed --- Gulp/assetTasks.js | 11 ++++++----- Gulp/generalTasks.js | 5 +++-- Gulp/scriptTasks.js | 13 +++++++------ Gulp/watchTasks.js | 4 +--- Gulpfile.js | 1 - bower.json | 15 ++++++++------- karma.conf.js | 4 ++-- module.prefix | 1 - module.suffix | 1 - package.json | 26 +++++--------------------- src/app/{_app.js => app.js} | 3 ++- src/app/{_app.spec.js => app.spec.js} | 0 12 files changed, 34 insertions(+), 50 deletions(-) delete mode 100644 module.prefix delete mode 100644 module.suffix rename src/app/{_app.js => app.js} (95%) rename src/app/{_app.spec.js => app.spec.js} (100%) diff --git a/Gulp/assetTasks.js b/Gulp/assetTasks.js index 63628f1f..9a9584eb 100644 --- a/Gulp/assetTasks.js +++ b/Gulp/assetTasks.js @@ -7,7 +7,8 @@ var autoprefixer = require('gulp-autoprefixer'); var minify = require('gulp-minify-css'); var mainBowerFiles = require('main-bower-files'); var concat = require('gulp-concat'); -var clean = require('gulp-clean'); +var del = require('del'); +var vinylPaths = require('vinyl-paths'); var plumber = require('gulp-plumber'); var lessImport = require('gulp-less-import'); var replace = require('gulp-replace'); @@ -69,7 +70,7 @@ gulp.task('b_m:styles', function() { gulp.task('b_c:styles', function() { return gulp.src([config.build + 'assets/**/*.css', config.temp + '**/*' ], {read:false}) - .pipe(clean()); + .pipe(vinylPaths(del)); }); gulp.task('b_m:assets', function() { @@ -96,7 +97,7 @@ gulp.task('b_c:assets', function() { '!' + config.build + '**/*.scss', '!' + config.build + '**/*.sass', '!' + config.build + 'assets/fonts/**/*'], {read:false}) - .pipe(clean()) + .pipe(vinylPaths(del)) }); /*COMPILE*/ @@ -109,7 +110,7 @@ gulp.task('c_m:css', function() { gulp.task('c_c:css', function() { return gulp .src(config.compile + '**/*.css', {read:false}) - .pipe(clean()); + .pipe(vinylPaths(del)); }); gulp.task('c_m:assets', function() { @@ -125,7 +126,7 @@ gulp.task('c_m:assets', function() { gulp.task('c_c:assets', function() { return gulp .src([config.compile + 'assets/**/*', '!' + config.compile + 'assets/**/*.css'], {read:false}) - .pipe(clean()); + .pipe(vinylPaths(del)); }); //Master Asset Tasks diff --git a/Gulp/generalTasks.js b/Gulp/generalTasks.js index 3eb0d720..ff7be64a 100644 --- a/Gulp/generalTasks.js +++ b/Gulp/generalTasks.js @@ -1,6 +1,7 @@ var gulp = require('gulp'); var inject = require('gulp-inject'); -var clean = require('gulp-clean'); +var del = require('del'); +var vinylPaths = require('vinyl-paths'); var pkg = require('../package.json'); var currVersion = pkg.name + "-" + pkg.version; @@ -35,7 +36,7 @@ gulp.task('build:inject', function() { gulp.task('masterClean', function() { return gulp .src([config.build, config.compile, config.temp]) - .pipe(clean({read:false})); + .pipe(vinylPaths(del)); }); //Major Project Build Tasks diff --git a/Gulp/scriptTasks.js b/Gulp/scriptTasks.js index edd3fb96..47ad6fe1 100644 --- a/Gulp/scriptTasks.js +++ b/Gulp/scriptTasks.js @@ -1,12 +1,13 @@ var gulp = require('gulp'); -var header = require('gulp-header'); +//var header = require('gulp-header'); var concat = require('gulp-concat'); var mainBowerFiles = require('main-bower-files'); var uglify = require('gulp-uglify'); var filter = require('gulp-filter'); var wrap = require('gulp-wrapper'); var templatecache = require('gulp-angular-templatecache'); -var clean = require('gulp-clean'); +var del = require('del'); +var vinylPaths = require('vinyl-paths'); var ngAnnotate = require('gulp-ng-annotate'); @@ -27,7 +28,7 @@ gulp.task('b_m:js_bower', function() { gulp.task('b_c:js_bower', function() { return gulp .src(config.build + 'vendor', {read:false}) - .pipe(clean()); + .pipe(gulp.dest('dist')); }); gulp.task('b_m:js', function() { @@ -44,7 +45,7 @@ gulp.task('b_m:js', function() { gulp.task('b_c:js', function() { return gulp .src([config.build + 'src/**/*.js', '!' + config.build + 'src/**/templates-app.js'], {read:false}) - .pipe(clean()); + .pipe(gulp.dest('dist')); }); gulp.task('b_m:templateCache', function() { @@ -60,7 +61,7 @@ gulp.task('b_m:templateCache', function() { gulp.task('b_c:templateCache', function() { return gulp .src(config.build + 'src/templates-app.js', {read:false}) - .pipe(clean()); + .pipe(gulp.dest('dist')); }); gulp.task('c_m:js', function() { @@ -81,7 +82,7 @@ gulp.task('c_m:js', function() { gulp.task('c_c:js', function(){ return gulp.src(config.compile + '**/*.js', {read:false}) - .pipe(clean()); + .pipe(gulp.dest('dist')); }); diff --git a/Gulp/watchTasks.js b/Gulp/watchTasks.js index 9ac8c66d..390bf97b 100644 --- a/Gulp/watchTasks.js +++ b/Gulp/watchTasks.js @@ -1,7 +1,5 @@ gulp = require('gulp'); -jshint = require('gulp-jshint'); mainBowerFiles = require('main-bower-files'); -var watch = require('gulp-watch'); var karma = require('gulp-karma'); var server = 'server.js'; @@ -43,7 +41,7 @@ gulp.task('karma:unit', function() { gulp.task('watch:js', function() { console.log("running 'watch:js' task"); - gulp.watch(config.app_files.js, gulp.series('build:js', 'build:inject', function() {browserSync.reload()})); + gulp.watch(config.app_files.js, gulp.series('build:js', 'build:styles', 'build:inject', function() {browserSync.reload()})); gulp.watch(vendorJS, gulp.series('build:js_bower', 'build:inject', function() {browserSync.reload()})); }); diff --git a/Gulpfile.js b/Gulpfile.js index e68f09e1..fc14aea2 100644 --- a/Gulpfile.js +++ b/Gulpfile.js @@ -1,6 +1,5 @@ //Global gulp variables var gulp = require('gulp'); -var fs = require('fs'); config = require('./gulpConfig'); var path = require('path'); diff --git a/bower.json b/bower.json index 677dd6ac..96c8f759 100644 --- a/bower.json +++ b/bower.json @@ -6,15 +6,16 @@ }, "dependencies": { "angular": "~1.4.0", - "angular-sanitize": "~1.4.0", - "angular-ui-router": "~0.2.14", - "angular-messages": "~1.4.0", "angular-animate": "~1.4.0", + "angular-auto-validate": "~1.18.17", + "angular-bootstrap": "~0.13.2", + "angular-messages": "~1.4.0", + "angular-sanitize": "~1.4.0", "angular-touch": "~1.4.0", - "jquery": "~2.1.3", - "font-awesome": "~4.3.0", - "ordercloud-angular-sdk": "~0.6.6", + "angular-ui-router": "~0.2.14", "bootstrap": "~3.3.5", - "angular-bootstrap": "~0.13.2" + "font-awesome": "~4.3.0", + "jquery": "~2.1.3", + "ordercloud-angular-sdk": "~0.6.6" } } diff --git a/karma.conf.js b/karma.conf.js index 97961d64..8f8fdc95 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -16,7 +16,7 @@ module.exports = function(config) { // list of files / patterns to load in the browser files: [].concat( mainBowerFiles({filter: '**/*.js'}), - './src/**/*.module.js', + './src/**/app.js', './src/**/*.js' ), @@ -57,7 +57,7 @@ module.exports = function(config) { // start these browsers // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher - browsers: ['Chrome'], + browsers: ['Firefox'], // Continuous Integration mode diff --git a/module.prefix b/module.prefix deleted file mode 100644 index c52d9b72..00000000 --- a/module.prefix +++ /dev/null @@ -1 +0,0 @@ -(function ( window, angular, undefined ) { diff --git a/module.suffix b/module.suffix deleted file mode 100644 index f6354bac..00000000 --- a/module.suffix +++ /dev/null @@ -1 +0,0 @@ -})( window, window.angular ); diff --git a/package.json b/package.json index a8f39852..51b9a2da 100644 --- a/package.json +++ b/package.json @@ -3,10 +3,7 @@ "name": "OrderCloud", "version": "0.0.3", "homepage": "https://github.com/Four51/OrderCloud-Seed-AngularJS", - "licenses": { - "type": "MIT", - "url": "https://raw.github.com/Four51/OrderCloud-Seed-AngularJS/master/LICENSE" - }, + "license": "MIT", "bugs": "https://github.com/Four51/OrderCloud-Seed-AngularJS/issues", "repository": { "type": "git", @@ -15,20 +12,15 @@ "dependencies": {}, "devDependencies": { "browser-sync": "^2.8.0", - "browserify": "^11.0.0", - "fs": "0.0.2", + "del": "^2.0.2", "gulp": "git://github.com/gulpjs/gulp.git#4.0", "gulp-angular-templatecache": "^1.7.0", "gulp-autoprefixer": "^2.3.1", - "gulp-clean": "^0.3.1", "gulp-concat": "^2.6.0", - "gulp-copy": "0.0.2", "gulp-filter": "^2.0.2", "gulp-flatten": "^0.1.1", - "gulp-header": "^1.2.2", - "gulp-html2js": "^0.2.0", + "gulp-header": "^1.7.1", "gulp-inject": "^1.5.0", - "gulp-jshint": "^1.11.2", "gulp-karma": "0.0.4", "gulp-less": "^3.0.3", "gulp-less-import": "^1.0.0", @@ -37,21 +29,13 @@ "gulp-plumber": "^1.0.1", "gulp-replace": "^0.5.4", "gulp-sass": "^2.0.4", - "gulp-sourcemaps": "^1.5.2", "gulp-uglify": "^1.2.0", "gulp-util": "^3.0.6", - "gulp-watch": "^4.3.4", "gulp-wrapper": "^1.0.0", - "json-file-plus": "^3.0.0", - "karma": "^0.12.31", - "karma-chrome-launcher": "^0.2.0", + "karma": "^0.13.10", "karma-firefox-launcher": "^0.1.6", "karma-jasmine": "^0.1.5", "main-bower-files": "^2.9.0", - "npm": "^2.13.0", - "path": "^0.11.14", - "synchro-prompt": "^1.1.0", - "vinyl-source-stream": "^1.1.0", - "watchify": "^3.3.0" + "vinyl-paths": "^2.0.0" } } diff --git a/src/app/_app.js b/src/app/app.js similarity index 95% rename from src/app/_app.js rename to src/app/app.js index c0dcccc9..d9a7955e 100644 --- a/src/app/_app.js +++ b/src/app/app.js @@ -20,10 +20,11 @@ angular.module( 'orderCloud', [ //Client ID for a Registered Distributor or Buyer Company .constant('clientid', 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx') + .constant('buyerid', 'xxxx') //Test Environment .constant('authurl', 'https://testauth.ordercloud.io/oauth/token') - .constant('apiurl', 'https://testapi.ordercloud.io/v1') + .constant('apiurl', 'https://testapi.ordercloud.io') ; function Security( $rootScope, $state, Auth ) { diff --git a/src/app/_app.spec.js b/src/app/app.spec.js similarity index 100% rename from src/app/_app.spec.js rename to src/app/app.spec.js From b8793a8743ffbe9907ecba0c165d5cdaed03258d Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Tue, 29 Sep 2015 10:02:08 -0500 Subject: [PATCH 025/367] I made a mistake and copied the wrong line when replacing the gulp-clean task. Also a task will fail if it cannot find a path given explicitly, so it is best to use a glob for these (see the change to the b_m:styles task for an example) --- Gulp/assetTasks.js | 14 ++++++++------ Gulp/generalTasks.js | 8 +++++--- Gulp/scriptTasks.js | 24 +++++++++++++----------- 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/Gulp/assetTasks.js b/Gulp/assetTasks.js index 9a9584eb..524087ea 100644 --- a/Gulp/assetTasks.js +++ b/Gulp/assetTasks.js @@ -61,7 +61,7 @@ gulp.task('b_m:appCss', function() { gulp.task('b_m:styles', function() { return gulp - .src([config.temp + 'bowerStyles.css', config.temp + 'lessStyles.css', config.temp + 'sassStyles.css', config.temp + 'appCss.css']) + .src(config.temp + '*.css') .pipe(replace('../fonts/', 'fonts/')) .pipe(concat(currVersion + '.css')) .pipe(gulp.dest(config.build + 'assets')) @@ -69,8 +69,10 @@ gulp.task('b_m:styles', function() { }); gulp.task('b_c:styles', function() { - return gulp.src([config.build + 'assets/**/*.css', config.temp + '**/*' ], {read:false}) - .pipe(vinylPaths(del)); + return del([ + config.build + 'assets/**/*.css', + config.temp + '**/*' + ]); }); gulp.task('b_m:assets', function() { @@ -90,14 +92,14 @@ gulp.task('b_m:fonts', function() { }); gulp.task('b_c:assets', function() { - return gulp.src([ + return del([ config.build + 'assets/**/*', '!' + config.build + '**/*.css', '!' + config.build + '**/*.less', '!' + config.build + '**/*.scss', '!' + config.build + '**/*.sass', - '!' + config.build + 'assets/fonts/**/*'], {read:false}) - .pipe(vinylPaths(del)) + '!' + config.build + 'assets/fonts/**/*' + ]); }); /*COMPILE*/ diff --git a/Gulp/generalTasks.js b/Gulp/generalTasks.js index ff7be64a..246c157f 100644 --- a/Gulp/generalTasks.js +++ b/Gulp/generalTasks.js @@ -34,9 +34,11 @@ gulp.task('build:inject', function() { gulp.task('masterClean', function() { - return gulp - .src([config.build, config.compile, config.temp]) - .pipe(vinylPaths(del)); + return del([ + config.build, + config.compile, + config.temp + ]); }); //Major Project Build Tasks diff --git a/Gulp/scriptTasks.js b/Gulp/scriptTasks.js index 47ad6fe1..b1edffa0 100644 --- a/Gulp/scriptTasks.js +++ b/Gulp/scriptTasks.js @@ -26,9 +26,9 @@ gulp.task('b_m:js_bower', function() { }); gulp.task('b_c:js_bower', function() { - return gulp - .src(config.build + 'vendor', {read:false}) - .pipe(gulp.dest('dist')); + return del([ + config.build + 'vendor' + ]); }); gulp.task('b_m:js', function() { @@ -43,9 +43,10 @@ gulp.task('b_m:js', function() { }); gulp.task('b_c:js', function() { - return gulp - .src([config.build + 'src/**/*.js', '!' + config.build + 'src/**/templates-app.js'], {read:false}) - .pipe(gulp.dest('dist')); + return del([ + config.build + 'src/**/*.js', + '!' + config.build + 'src/**/templates-app.js' + ]); }); gulp.task('b_m:templateCache', function() { @@ -59,9 +60,9 @@ gulp.task('b_m:templateCache', function() { }); gulp.task('b_c:templateCache', function() { - return gulp - .src(config.build + 'src/templates-app.js', {read:false}) - .pipe(gulp.dest('dist')); + return del([ + config.build + 'src/templates-app.js' + ]); }); gulp.task('c_m:js', function() { @@ -81,8 +82,9 @@ gulp.task('c_m:js', function() { }); gulp.task('c_c:js', function(){ - return gulp.src(config.compile + '**/*.js', {read:false}) - .pipe(gulp.dest('dist')); + return del([ + config.compile + '**/*.js' + ]); }); From d46e77584b7e767f1ef2e29ff51516dbf36180a8 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Fri, 23 Oct 2015 14:06:45 -0500 Subject: [PATCH 026/367] Updates to README files to reflect the change to the Gulp.js build system. --- README.md | 167 ++++++++++++++++++++++++++++++++++-------------------- tools.md | 117 +++----------------------------------- 2 files changed, 113 insertions(+), 171 deletions(-) diff --git a/README.md b/README.md index 381b11b2..975d7528 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ OrderCloud/ WebStorm is our chosen development IDE. It provides an interface for the capabilities of the seed projects configuration. ### Karma Unit Testing -Once you've installed the prerequisites and run your grunt build you can setup and run your Karma tests. +Once you've installed the prerequisites and run your gulp build you can setup and run your Karma tests. Create a Run configuration using the Karma plugin with the following settings: @@ -71,25 +71,23 @@ OrderCloud/ ``` ### Detailed Installation -##Out dated - No longer using Grunt This section provides a little more detailed understanding of what goes into getting `OrderCloud` up and running. Though `OrderCloud` is really simple to use, it might help to have an understanding of the tools involved here, like -Node.js and Grunt and Bower. If you're completely new to highly organized, +Node.js and Gulp and Bower. If you're completely new to highly organized, modern JavaScript development, take a few short minutes to read [this overview of the tools](tools.md) before continuing with this section. Here it is: -`OrderCloud` uses [Grunt](http://gruntjs.org) as its build system, so -[Node.js](http://nodejs.org) is required. Also, Grunt by default no longer comes -with a command-line utility and Karma and Bower must end up in your global path -for the build system to find it, so they must be installed independently. Once -you have Node.js installed, you can simply use `npm` to make it all happen: +`OrderCloud` uses [Gulp](http://gulpjs.com/) as its build system, so +[Node.js](http://nodejs.org) is required. Also, we are using Gulp 4.0 prior to +its official release date. You can install Gulp 4.0 on your machine globally by running +the following command: ```sh -$ npm -g install grunt-cli karma bower +$ npm -g install "gulpjs/gulp-cli#4.0" karma bower ``` And then install the remaining build dependencies locally: @@ -103,7 +101,7 @@ This will read the `dependencies` (empty by default) and the `devDependencies` everything needed into a folder called `node_modules/`. There are many Bower packages used by `OrderCloud`, like AngularJS and the -OrderCloud-SDK, which are listed in `bower.js`. To install them into the +OrderCloud-Angular-SDK, which are listed in `bower.js`. To install them into the `vendor/` directory, simply run: ```sh @@ -111,13 +109,13 @@ $ bower install ``` In the future, should you want to add a new Bower package to your app, run the -`install` command: +`install` command and add `--save` to save the dependency in your bower.json file: ```sh -$ bower install packagename --save-dev +$ bower install packagename --save ``` -The `--save-dev` flag tells Bower to add the package at its current version to +The `--save` flag tells Bower to add the package at its current version to our project's `bower.js` file so should another developer download our application (or we download it from a different computer), we can simply run the `bower install` command as above and all our dependencies will be installed for @@ -125,30 +123,29 @@ us. Neat! Technically, `OrderCloud` is now ready to go. -To ensure your setup works, launch grunt: +To ensure your setup works, build your application and then run it with the following +commands: ```sh -$ grunt watch +$ gulp build +$ gulp watch ``` -The built files are placed in the `build/` directory by default. Open the -`build/index.html` file in your browser and check it out! Because everything is -compiled, no XHR requests are needed to retrieve templates, so until this needs -to communicate with your backend there is no need to run it from a web server. +The built files are placed in the `build/` directory by default. And you application +should automatically open in the browser window on a localhost! -`watch` is actually an alias of the `grunt-contrib-watch` that will first run a -partial build before watching for file changes. With this setup, any file that -changes will trigger only those build tasks necessary to bring the app up to -date. For example, when a template file changes, the templates are recompiled -and concatenated, but when a test/spec file changes, only the tests are run. -This allows the watch command to complete in a fraction of the time it would -ordinarily take. +`watch` actually starts a few other processes in the background to help you develop your +application. Using `browser-sync` and some built in gulp functions the app is now watching +for changes in your source directory. Should you make any changes to your html or js files +the app should automatically reload your application with the appropriate changes. Also +if you make any changes to your style sheets (less or css) the app will rebuild those changes +and inject them directly into the application, without reloading the entire page! When you're ready to push your app into production, just run the `compile` command: ```sh -$ grunt compile +$ gulp compile ``` This will concatenate and minify your sources and place them by default into the @@ -162,52 +159,98 @@ Lastly, a complete build is always available by simply running the default task, which runs `build` and then `compile`: ```sh -$ grunt +$ gulp ``` ### The Build System The best way to learn about the build system is by familiarizing yourself with -Grunt and then reading through the heavily documented build script, -`Gruntfile.js`. But you don't need to do that to be very productive with +Gulp and then looking through the code, `Gulpfile.js` and the Gulp folder. + But you don't need to do that to be very productive with `OrderCloud`. What follows in this section is a quick introduction to the tasks provided and should be plenty to get you started. -The driver of the process is the `delta` multi-task, which watches for file -changes using `grunt-contrib-watch` and executes one of nine tasks when a file -changes: - -* `delta:gruntfile` - When `Gruntfile.js` changes, this task runs the linter - (`jshint`) on that one file and reloads the configuration. -* `delta:assets` - When any file within `src/assets/` changes, all asset files - are copied to `build/assets/`. -* `delta:html` - When `src/index.html` changes, it is compiled as a Grunt - template, so script names, etc., are dynamically replaced with the correct - values configured dynamically by Grunt. -* `delta:less` - When any `*.less` file within `src/` changes, the - `temp/imports.less` file is regenerated by the `less_imports:build` task, - autoprefixed, and compiled into `build/assets/OrderCloud.css`. -* `delta:jssrc` - When any JavaScript file within `src/` that does not end in - `.spec.js` changes, all JavaScript sources are linted, all unit tests are run, - and the all source files are re-copied to `build/src`. - `build/src` in a structure mirroring where they were in `src/` so it's easy to - locate problems. -* `delta:tpls` - When any `*.tpl.html` file within `src/` changes, all templates - are put into strings in a JavaScript file that will add the template to - AngularJS's - [`$templateCache`](http://docs.angularjs.org/api/ng.$templateCache) so - template file is part of the initial JavaScript payload and do not require - any future XHR. The template cache file is `build/template-app.js`. -* `delta:jsunit` - When any `*.spec.js` file in `src/` changes, the test files - are linted and the unit tests are executed. - -As covered in the previous section, `grunt watch` will execute a full build -up-front and then run any of the aforementioned `delta:*` tasks as needed to +Below is a description of the gulp tasks in the project, sorted by their general purpose +and location within the Gulp directory. + +####Asset Tasks +* `b_m:less` - Compiles all of the app and bower less files into css and moves the compiled file into the temp folder +* `b_m:sass` - Compiles all of the app and bower sass files into css and moves the compiled file into the temp folder +* `b_m:css` - Compiles all of the bower css files (with the exception of the font awesome file as it was already compiled +in `b_m:less`) into one file and autoprefixes the css to run for the last to versions of all the major browsers +* `b_m:appCss` - Compiles all of the app css files into one file and autoprefixes the css to run for the last to versions +of all the major browsers +* `b_m:styles` - Compiles all of the css files in the temp directory into one file, replaces the path to fonts to be correct +for the build directory and renames the file with the version of the app. Places the file in the build folder and injects the +change into browser-sync if it is currently running +* `b_c:styles` - Deletes all of the assets that have been moved over to the build folder and all of the files in the temp folder +* `b_m:assets` - Moves over all asset files (fonts and images) saved in the src/assets directory to the build/assets directory +* `b_m:fonts` - Moves over all fonts saved within the bower dependencies to the build/assets directory +* `b_c:assets` - Deletes all assets files from the build directory +* `c_m:css` - Minifies all css files in the build directory and moves them to the compile folder +* `c_c:css` - Deletes all css files from the compile directory +* `c_m:assets` - Moves over all asset files (fonts and images) from the build folder to the compile folder +* `c_c:assets` - Delete all asset and css files from the compile directory +* `build:styles` - Runs `b_c:styles`, `b_m:less`, `b_m:sass`, `b_m:css`, `b_m:appCss`, `b_m:styles` in order +* `compile:css` - Runs `c_c:css`, `build:styles`, `c_m:css` in order +* `build:assets` - Runs `b_c:assets`, `b_m:assets`, `b_m:fonts` in order +* `compile:assets` - Runs `c_c:assets`, `build:assets`, `c_m:assets` in order + +####General Tasks +* `compile:inject` - Injects the app dependencies into the index.html file for the compiled build +Note: Theere should only be two: `OrderCloud-[Version#].css` and `app.js` +* `build:inject` - Injects the app dependencies into the index.html file for the unminified build +* `masterClean` - Deletes the build, compile, and temp directories. Basically anything built by the gulp +tasks will be removed by this task +* `build` - First runs `master clean`, then runs `build:js_bower`, `build:js`, `build:templateCache`, `build:styles`, `build:assets`, +and lastly runs `build:inject` to create an unminified build of the project +* `compile` - First runs `build`, then runs `compile:js`, `compile:assets`, `compile:css` +and lastly runs `compile:inject` to create a minified build of the project +* `default` - Runs the `compile` task when only `gulp` is typed into the command prompt + +####Script Tasks +* `b_m:js_bower` - Moves the bower dependencies over to the build folder +* `b_c:js_bower` - Deletes bower dependencies form the build folder +* `b_m:js` - Moves over all of the app js files need to run the application (not the ones for unit testing) and +annotates them and wraps each file in an IIFE call. +* `b_c:js` - Deletes all of the javascript files moved over to the build folder except for the templateCache file +* `b_m:templateCache` - Creates an angular templateCache of all the html files (except the index) that +allows for the application to run faster. +* `b_c:templateCache` - Cleans out the compiled template file generated by `b_m:templateCache` +* `c_c:js` - Deletes all js files from the compile directory +* `build:js` - Runs `b_c:js`, and `b_m:js` in order +* `build:js_bower` - Runs `b_c:js_bower`, and `b_m:js_bower` in order +* `build:templateCache` - Runs `b_c:templateCache`, and `b_m:templateCache` in order +* `compile:js` - Runs `c_c:js`, `build:js_bower`, `build:js`, and `build:templateCache` at the same time, then runs +`c_m:js` + +####Test Tasks +* `testServe` - Starts the browser-sync server on localhost:12000 +Note: this task does not build the application first so you must run `gulp build` first for it to work. +This task differs from `dev` in that it opens a tunnel that allows the app to be viewed on other computers +not on the same network. + +####Watch Tasks +* `dev` - Starts the browser-sync server on localhost:8000 +* `karma:unit` - Starts the karma unit tests +* `watch:js` - Starts a process that watches for changes in the javascript files in the src directory +* `watch:assets` - Starts a process that watches for changes in the style sheet files (less and css) +* `watch:other` - Starts a process the watches for changes in the html files +* `watch` - Starts all of the previously mentioned tasks in parallel + +As covered in the previous section, `gulp build` and `gulp watch` will execute a full build +up-front and then run any of the aforementioned `watch` tasks as needed to ensure the fastest possible build. So whenever you're working on your project, start with: ```sh -$ grunt watch +$ gulp build +``` + +then: + +```sh +$ gulp watch ``` And everything will be done automatically! @@ -226,7 +269,7 @@ automatically during build or watch. To initiate a full compile, you simply run the default task: ```sh -$ grunt +$ gulp ``` This will perform a build and then a compile. The compiled site is located in `compile/`. diff --git a/tools.md b/tools.md index 140fb0c0..ac5f6758 100644 --- a/tools.md +++ b/tools.md @@ -32,7 +32,7 @@ software and libraries from the command line. While `OrderCloud` makes heavy use of Node.js behind the scenes, you as the application developer don't need to really think about it much. Most of the -interaction with Node.js will occur through Grunt (see next section), so you +interaction with Node.js will occur through Gulp (see next section), so you really only need to know how get the initial setup working. `package.json` is an NPM package description file written in JSON. It contains @@ -40,123 +40,22 @@ basic metadata about your application, like its name, version, and dependencies. By default, several packages are required for the build process to work; so when you first start with `OrderCloud` you have to tell NPM to install the packages; this is covered in detail in the [main README](README.md). Some of -the required packages are Grunt build tasks (see below), while others are -command-line tools either we (or the build system) need, like Karma, Grunt, and +the required packages are Gulp build tasks, while others are +command-line tools either we (or the build system) need, like Karma, Gulp, and Bower. -Don't worry about knowing Node.js in order to use `OrderCloud`; Grunt is +Don't worry about knowing Node.js in order to use `OrderCloud`; Gulp is where the magic happens. -## Grunt.js +## Gulp.js -[Grunt](http://gruntjs.com) is a JavaScript task runner that runs on top of -Node.js. Most importantly, Grunt brings us automation. There are lots of steps +[Gulp](http://gulpjs.com/) is a JavaScript task runner that runs on top of +Node.js. Most importantly, Gulp brings us automation. There are lots of steps that go into taking our manageable codebase and making it into a production-ready website; we must gather, lint, test, annotate, and copy files -about. Instead of doing all of that manually, we write (and use others') Grunt +about. Instead of doing all of that manually, we write (and use others') Gulp tasks to do things for us. -When we want to build our site, we can just type: - -```sh -$ grunt -``` - -This will do everything needed and place our built code inside a folder called -`release/`. We can tell Grunt to watch for file changes we make -so it can re-build our site on-the-fly: - -```sh -$ grunt watch -``` - -The built files will be in `release/`. See the main [README](README.md) for more -info. - -The next time we change a source file, Grunt will re-build the changed parts of -the site. If you have a Live Reload plugin installed in your browser, it will -even auto-refresh your browser for you. - -Grunt is controlled through `Gruntfile.js`. This file is heavily documented in -the source, so I will only provide a high-altitude overview here. Also note that -unless you need to modify the build process, you don't need to know anything -else from this section. The two commands above really are all you need to know -to get started with `OrderCloud`. But for those curious or looking to go a -little more advanced, here's what you'll find. - -First, we tell Grunt which tasks we might want to use: - -```js -// ... -grunt.loadNpmTasks('grunt-recess'); -grunt.loadNpmTasks('grunt-contrib-clean'); -grunt.loadNpmTasks('grunt-contrib-copy'); -grunt.loadNpmTasks('grunt-contrib-jshint'); -// ... -``` - -Each of these tasks must already be installed. Remember the dependencies from -`package.json` that NPM installed for us? - -Then we get the opportunity to tell the tasks to behave like we want by -defining a configuration object. While we can (and do) define all sorts of -custom configuration values that we reference later on, tasks look for -configuration properties of their own name. For example, the `clean` task just -takes an array of files to delete when the task runs: - -```js -clean: [ '<%= build_dir %>', '<%= compile_dir %>' ], -``` - -In Grunt, the `<%= varName %>` is a way of re-using configuration variables. -In the `build.config.js`, we defined what `build_dir` meant: - -```js -build_dir: 'build', -``` - -When the clean task runs, it will delete the `build/` folder entirely so that -when our new build runs, we don't encounter any problems with stale or old -files. Most tasks, however, have considerably more complicated configuration -requirements, but I've tried to document what each one is doing and what the -configuration properties mean. - -After our configuration is complete, we can define some of our own tasks. For -example, we could do the build by running all of the separate tasks that we -installed from NPM and configured as above: - -```sh -$ grunt clean -$ grunt html2js -$ grunt jshint -$ grunt karma:continuous -$ grunt concat -$ grunt ngmin:dist -$ grunt uglify -$ grunt recess -$ grunt index -$ grunt copy -``` - -But how automated is that? So instead we define a composite task that executes -all that for us. The commands above make up the `default` tasks, which can be -run by typing *either* of these commands: - -```js -$ grunt -$ grunt default -``` - -We also define the `watch` task discussed earlier. This is covered in more -detail in the main (README)[README.md]. - -Grunt is the engine behind `OrderCloud`. It's the magic that makes it move. -Just getting started, you won't need to alter `Gruntfile.js` at all, but -as you get into more advanced application development, you will probably need to -add more tasks and change some steps around to make this build your own. -Hopefully, this readme and the documentation within `Gruntfile.js` (as well as -of course the documentation at gruntjs.com) will set you on the right path. - ## Bower [Bower](bower.io) is a package manager for the web. It's similar in many From c062d56fd46df2df4068610488e498fd0bdabb10 Mon Sep 17 00:00:00 2001 From: Kyle Olson Date: Mon, 26 Oct 2015 10:04:22 -0500 Subject: [PATCH 027/367] Fixes/Updates to ErrorHandler Implementation of Angular-Toastr --- bower.json | 3 ++- src/app/app.js | 63 ++++++++++++++++++++++++++++++-------------------- 2 files changed, 40 insertions(+), 26 deletions(-) diff --git a/bower.json b/bower.json index 96c8f759..3f52ab7f 100644 --- a/bower.json +++ b/bower.json @@ -16,6 +16,7 @@ "bootstrap": "~3.3.5", "font-awesome": "~4.3.0", "jquery": "~2.1.3", - "ordercloud-angular-sdk": "~0.6.6" + "ordercloud-angular-sdk": "~0.8.4", + "angular-toastr": "~1.5.0" } } diff --git a/src/app/app.js b/src/app/app.js index d9a7955e..af66886b 100644 --- a/src/app/app.js +++ b/src/app/app.js @@ -6,12 +6,16 @@ angular.module( 'orderCloud', [ 'ngTouch', 'ui.router', 'ui.bootstrap', - 'orderCloud.sdk' + 'orderCloud.sdk', + 'toastr' ]) + .run( SetBuyerID ) .run( Security ) .config( Routing ) - .config( ErrorHandling ) + //.config( ErrorHandling ) + .factory('$exceptionHandler', ExceptionHandler) + .factory('toast', toast) .controller( 'AppCtrl', AppCtrl ) //Constants needed for the OrderCloud AngularJS SDK @@ -19,14 +23,21 @@ angular.module( 'orderCloud', [ .constant('appname', 'OrderCloud AngularJS Seed') //Client ID for a Registered Distributor or Buyer Company - .constant('clientid', 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx') - .constant('buyerid', 'xxxx') + .constant('clientid', '6d60154e-8a55-4bd2-93aa-494444e69996') //Test Environment - .constant('authurl', 'https://testauth.ordercloud.io/oauth/token') - .constant('apiurl', 'https://testapi.ordercloud.io') + //.constant('authurl', 'https://testauth.ordercloud.io/oauth/token') + //.constant('apiurl', 'https://testapi.ordercloud.io') + + .constant('authurl', 'http://core.four51.com:11629/OAuth/Token') + .constant('apiurl', 'http://core.four51.com:9002') + .constant('devcenterClientID', '6d60154e-8a55-4bd2-93aa-494444e69996') //Local ; +function SetBuyerID( BuyerID ) { + BuyerID.Set('xxxx'); +} + function Security( $rootScope, $state, Auth ) { $rootScope.$on('$stateChangeStart', function(e, to) { /*TODO: make the '$stateChangeStart event' accept a function so users can control the redirect from each state's declaration.*/ @@ -47,32 +58,34 @@ function Routing( $urlRouterProvider, $urlMatcherFactoryProvider ) { //TODO: For HTML5 mode to work we need to always return index.html as the entry point on the serverside } -function ErrorHandling( $provide ) { - $provide.decorator('$exceptionHandler', handler ); +ExceptionHandler.$inject = ['$injector']; - function handler( $delegate, $injector ) { - return function $broadcastingExceptionHandler( ex, cause ) { - ex.status != 500 ? - $delegate( ex, cause ) : - ( function() { - try { - //TODO: implement track js - console.log(JSON.stringify( ex )); - //trackJs.error("API: " + JSON.stringify(ex)); - } - catch ( ex ) { - console.log(JSON.stringify( ex )); - } - })(); - $injector.get( '$rootScope' ).$broadcast( 'exception', ex, cause ); +function ExceptionHandler($injector) { + return function $broadcastingExceptionHandler( ex, cause ) { + if (ex.data) { + var toast = $injector.get('toast'); + var msg = ex.data.Errors[0].Message; + toast.error(msg); } } } -function AppCtrl( $state, Credentials ) { +function toast(toastr) { + var service = { + error: _error + }; + + function _error(msg) { + toastr.error(msg, 'Error'); + } + + return service; +} + +function AppCtrl( $state, Credentials, Users ) { var vm = this; vm.logout = function() { Credentials.Delete(); $state.go('login'); - } + }; } \ No newline at end of file From 4c2eaa0893aa4ec8a49619bdb92463d71f93dd1e Mon Sep 17 00:00:00 2001 From: Kyle Olson Date: Mon, 26 Oct 2015 15:06:42 -0500 Subject: [PATCH 028/367] ordercloud-angular-sdk update --- bower.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bower.json b/bower.json index 3f52ab7f..837ff6bc 100644 --- a/bower.json +++ b/bower.json @@ -16,7 +16,7 @@ "bootstrap": "~3.3.5", "font-awesome": "~4.3.0", "jquery": "~2.1.3", - "ordercloud-angular-sdk": "~0.8.4", + "ordercloud-angular-sdk": "~0.8.5", "angular-toastr": "~1.5.0" } } From 3816e455b9386e147857a0b9c2b31541b7de08a5 Mon Sep 17 00:00:00 2001 From: Kyle Olson Date: Tue, 3 Nov 2015 15:45:24 -0600 Subject: [PATCH 029/367] Reset Password on Login --- src/app/login/login.js | 92 ++++++++++++++++++++++++-- src/app/login/templates/login.tpl.html | 44 ++++++++++-- 2 files changed, 127 insertions(+), 9 deletions(-) diff --git a/src/app/login/login.js b/src/app/login/login.js index 8376a333..4dfc4e73 100644 --- a/src/app/login/login.js +++ b/src/app/login/login.js @@ -1,13 +1,14 @@ angular.module( 'orderCloud' ) .config( LoginConfig ) + .factory( 'LoginService', LoginService ) .controller( 'LoginCtrl', LoginController ) ; function LoginConfig( $stateProvider ) { $stateProvider.state( 'login', { - url: '/login', + url: '/login/:token', templateUrl:'login/templates/login.tpl.html', controller:'LoginCtrl', controllerAs: 'login', @@ -17,15 +18,98 @@ function LoginConfig( $stateProvider ) { }); } -function LoginController( $state, Credentials ) { +function LoginService( $q, PasswordResets, clientid ) { + var service = { + SendVerificationCode: _sendVerificationCode, + ResetPassword: _resetPassword + }; + + function _sendVerificationCode(email) { + var deferred = $q.defer(); + + var passwordResetRequest = { + Email: email, + ClientID: clientid, + URL: encodeURIComponent($window.location.href) + '{0}' + }; + + PasswordResets.SendVerificationCode(passwordResetRequest) + .then(function() { + deferred.resolve(); + }) + .catch(function(ex) { + deferred.reject(ex); + }); + + return deferred.promise; + } + + function _resetPassword(resetPasswordCredentials, verificationCode) { + var deferred = $q.defer(); + + var passwordReset = { + ClientID: clientid, + Username: resetPasswordCredentials.ResetUsername, + Password: resetPasswordCredentials.NewPassword + }; + + PasswordResets.ResetPassword(verificationCode, passwordReset). + then(function() { + deferred.resolve(); + }) + .catch(function(ex) { + deferred.reject(ex); + }); + + return deferred.promise; + } + + return service; +} + +function LoginController( $state, $stateParams, $exceptionHandler, LoginService, Credentials ) { var vm = this; + vm.token = $stateParams.token; + vm.form = vm.token ? 'reset' : 'login'; + vm.setForm = function(form) { + vm.form = form; + }; + vm.submit = function( ) { Credentials.Get( vm.credentials ).then( function() { $state.go( 'base.home' ); - }).catch(function( ex ) { - console.dir( ex ); + }).catch(function(ex) { + $exceptionHandler(ex); + }); + }; + + vm.forgotPassword = function() { + LoginService.SendVerificationCode(vm.credentials.Email) + .then(function() { + vm.setForm('verificationCodeSuccess'); + vm.credentials.Email = null; + }) + .catch(function(ex) { + $exceptionHandler(ex); + }); + }; + + vm.resetPassword = function() { + LoginService.ResetPassword(vm.credentials, vm.token) + .then(function() { + vm.setForm('resetSuccess'); + vm.token = null; + vm.credentials.ResetUsername = null; + vm.credentials.NewPassword = null; + vm.credentials.ConfirmPassword = null; + }) + .catch(function(ex) { + $exceptionHandler(ex); + vm.credentials.ResetUsername = null; + vm.credentials.NewPassword = null; + vm.credentials.ConfirmPassword = null; }); }; } diff --git a/src/app/login/templates/login.tpl.html b/src/app/login/templates/login.tpl.html index f338d322..bbc698fc 100644 --- a/src/app/login/templates/login.tpl.html +++ b/src/app/login/templates/login.tpl.html @@ -1,15 +1,49 @@ -
-
+
+

Login

- +
- +
- Forgot Password? + Forgot Password? + +
+

Forgot Password

+
+ + +
+ + Back to Login +
+
+

Reset Password

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

Forgot Password

+
Forgot Password email has been sent. Please check your email in order to reset your password.
+
+
+

Reset Password

+
Your password has been reset.
+ Back to Login
From 0fcc62b84325452056838e93d585f2caa0a245af Mon Sep 17 00:00:00 2001 From: Kyle Olson Date: Tue, 3 Nov 2015 15:47:02 -0600 Subject: [PATCH 030/367] Refactor ExceptionHandler --- src/app/app.js | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/src/app/app.js b/src/app/app.js index af66886b..cb9955ae 100644 --- a/src/app/app.js +++ b/src/app/app.js @@ -58,30 +58,18 @@ function Routing( $urlRouterProvider, $urlMatcherFactoryProvider ) { //TODO: For HTML5 mode to work we need to always return index.html as the entry point on the serverside } -ExceptionHandler.$inject = ['$injector']; - function ExceptionHandler($injector) { - return function $broadcastingExceptionHandler( ex, cause ) { + return function( ex, cause ) { + var toastr = $injector.get('toastr'); if (ex.data) { - var toast = $injector.get('toast'); - var msg = ex.data.Errors[0].Message; - toast.error(msg); + var msg = ex.data.error || ex.data.Errors[0].Message; + toastr.error(msg, 'Error'); + } else if (ex.message) { + toastr.error(ex.message, 'Error'); } } } -function toast(toastr) { - var service = { - error: _error - }; - - function _error(msg) { - toastr.error(msg, 'Error'); - } - - return service; -} - function AppCtrl( $state, Credentials, Users ) { var vm = this; vm.logout = function() { From 7080684e245abcc0d8968caf3118fcb476de9f60 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 4 Nov 2015 16:00:21 -0600 Subject: [PATCH 031/367] Preparation for Components --- bower.json | 2 +- src/app/account/account.js | 161 ++++++++++++++++++ src/app/account/templates/account.tpl.html | 34 ++++ .../account/templates/changePassword.tpl.html | 19 +++ .../templates/confirmPassword.modal.tpl.html | 10 ++ src/app/app.js | 50 +++--- src/app/base/base.js | 69 +++++++- src/app/base/less/base.less | 110 ++++++++++++ src/app/base/less/variables.less | 3 + src/app/base/templates/base.left.tpl.html | 26 +++ src/app/base/templates/base.top.tpl.html | 23 +++ src/app/base/templates/base.tpl.html | 32 +--- src/app/common/auto-id/auto-id.js | 52 ++++++ src/app/common/buyer-select/buyer-select.less | 22 +++ .../common/buyer-select/buyer-select.tpl.html | 39 +++++ .../buyer-select/ordercloud-buyer-selected.js | 49 ++++++ src/app/common/files/files.js | 133 +++++++++++++++ src/app/common/files/templates/files.tpl.html | 4 + .../helper-factories/assignment-helpers.js | 59 +++++++ .../common/infinite-scroll/infinite-scroll.js | 128 ++++++++++++++ .../ordercloud-logo/ordercloud-logo.tpl.html | 133 +++++++++++++++ .../common/ordercloud-logo/ordercloud_logo.js | 19 +++ src/app/common/search/search.js | 63 +++++++ .../common/search/templates/search.tpl.html | 5 + src/app/global.less | 91 +++++++++- src/app/home/home.js | 3 +- src/app/home/templates/home.tpl.html | 10 +- src/app/login/login.js | 2 +- src/app/login/templates/login.tpl.html | 2 +- src/app/variables.less | 17 +- 30 files changed, 1304 insertions(+), 66 deletions(-) create mode 100644 src/app/account/account.js create mode 100644 src/app/account/templates/account.tpl.html create mode 100644 src/app/account/templates/changePassword.tpl.html create mode 100644 src/app/account/templates/confirmPassword.modal.tpl.html create mode 100644 src/app/base/templates/base.left.tpl.html create mode 100644 src/app/base/templates/base.top.tpl.html create mode 100644 src/app/common/auto-id/auto-id.js create mode 100644 src/app/common/buyer-select/buyer-select.less create mode 100644 src/app/common/buyer-select/buyer-select.tpl.html create mode 100644 src/app/common/buyer-select/ordercloud-buyer-selected.js create mode 100644 src/app/common/files/files.js create mode 100644 src/app/common/files/templates/files.tpl.html create mode 100644 src/app/common/helper-factories/assignment-helpers.js create mode 100644 src/app/common/infinite-scroll/infinite-scroll.js create mode 100644 src/app/common/ordercloud-logo/ordercloud-logo.tpl.html create mode 100644 src/app/common/ordercloud-logo/ordercloud_logo.js create mode 100644 src/app/common/search/search.js create mode 100644 src/app/common/search/templates/search.tpl.html diff --git a/bower.json b/bower.json index 837ff6bc..81f37640 100644 --- a/bower.json +++ b/bower.json @@ -8,7 +8,7 @@ "angular": "~1.4.0", "angular-animate": "~1.4.0", "angular-auto-validate": "~1.18.17", - "angular-bootstrap": "~0.13.2", + "angular-bootstrap": "~0.14.3", "angular-messages": "~1.4.0", "angular-sanitize": "~1.4.0", "angular-touch": "~1.4.0", diff --git a/src/app/account/account.js b/src/app/account/account.js new file mode 100644 index 00000000..d55a6dfb --- /dev/null +++ b/src/app/account/account.js @@ -0,0 +1,161 @@ +angular.module( 'orderCloud' ) + + .config( AccountConfig ) + .controller( 'AccountCtrl', AccountController ) + .factory( 'AccountService', AccountService ) + .controller( 'ConfirmPasswordCtrl', ConfirmPasswordController ) + .controller( 'ChangePasswordCtrl', ChangePasswordController ) + +; + +function AccountConfig( $stateProvider ) { + $stateProvider + .state( 'base.account', { + url: '/account', + templateUrl:'account/templates/account.tpl.html', + controller:'AccountCtrl', + controllerAs: 'account', + resolve: { + Profile: function(Me) { + return Me.Get(); + } + } + }) + .state( 'base.changePassword', { + url: '/account/changepassword', + templateUrl: 'account/templates/changePassword.tpl.html', + controller: 'ChangePasswordCtrl', + controllerAs: 'changePassword', + resolve: { + CurrentUser: function(Me) { + return Me.Get(); + } + } + }) +} + +function AccountService( $q, $uibModal, Credentials, AdminUsers ) { + var service = { + Update: _update, + ChangePassword: _changePassword + }; + + function _update(currentProfile, newProfile) { + var deferred = $q.defer(); + + function updateUser() { + AdminUsers.Update(currentProfile.ID, newProfile) + .then(function(data) { + deferred.resolve(data); + }) + .catch(function(ex) { + deferred.reject(ex); + }) + } + + var modalInstance = $uibModal.open({ + animation: true, + templateUrl: 'account/templates/confirmPassword.modal.tpl.html', + controller: 'ConfirmPasswordCtrl', + controllerAs: 'confirmPassword', + size: 'sm' + }); + + modalInstance.result.then(function(password) { + var checkPasswordCredentials = { + Username: currentProfile.Username, + Password: password + }; + Credentials.Get(checkPasswordCredentials).then( + function() { + updateUser(); + }).catch(function( ex ) { + deferred.reject(ex); + }); + }, function() { + angular.noop(); + }); + + return deferred.promise; + } + + function _changePassword(currentUser) { + var deferred = $q.defer(); + + var checkPasswordCredentials = { + Username: currentUser.Username, + Password: currentUser.CurrentPassword + }; + + function changePassword() { + currentUser.Password = currentUser.NewPassword; + AdminUsers.Update(currentUser.ID, currentUser) + .then(function() { + deferred.resolve(); + }); + } + + Credentials.Get(checkPasswordCredentials).then( + function() { + changePassword(); + }).catch(function( ex ) { + deferred.reject(ex); + }); + + return deferred.promise; + } + + return service; +} + +function AccountController( $exceptionHandler, toastr, Profile, AccountService ) { + var vm = this; + vm.profile = angular.copy(Profile); + var currentProfile = Profile; + + vm.update = function() { + AccountService.Update(currentProfile, vm.profile) + .then(function(data) { + vm.profile = angular.copy(data); + currentProfile = data; + toastr.success('Account changes were saved.', 'Success!'); + }) + .catch(function(ex) { + vm.profile = currentProfile; + $exceptionHandler(ex) + }) + }; + + vm.resetForm = function(form) { + vm.profile = currentProfile; + form.$setPristine(true); + }; +} + +function ConfirmPasswordController( $uibModalInstance ) { + var vm = this; + + vm.submit = function() { + $uibModalInstance.close(vm.password); + }; + + vm.cancel = function() { + $uibModalInstance.dismiss('cancel'); + }; +} + +function ChangePasswordController( $state, $exceptionHandler, toastr, AccountService, CurrentUser ) { + var vm = this; + vm.currentUser = CurrentUser; + + vm.changePassword = function() { + AccountService.ChangePassword(vm.currentUser) + .then(function() { + toastr.success('Password successfully changed', 'Success!'); + $state.go('base.account'); + }) + .catch(function(ex) { + $exceptionHandler(ex) + }); + }; +} diff --git a/src/app/account/templates/account.tpl.html b/src/app/account/templates/account.tpl.html new file mode 100644 index 00000000..7c1137be --- /dev/null +++ b/src/app/account/templates/account.tpl.html @@ -0,0 +1,34 @@ +
+ +
+
+
+ + +
+
+ + +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ + + +
+
\ No newline at end of file diff --git a/src/app/account/templates/changePassword.tpl.html b/src/app/account/templates/changePassword.tpl.html new file mode 100644 index 00000000..654e3415 --- /dev/null +++ b/src/app/account/templates/changePassword.tpl.html @@ -0,0 +1,19 @@ +
+ +
+
+ + +
+
+ + +
+
+ + +
+ + +
+
\ No newline at end of file diff --git a/src/app/account/templates/confirmPassword.modal.tpl.html b/src/app/account/templates/confirmPassword.modal.tpl.html new file mode 100644 index 00000000..c3791fad --- /dev/null +++ b/src/app/account/templates/confirmPassword.modal.tpl.html @@ -0,0 +1,10 @@ + \ No newline at end of file diff --git a/src/app/app.js b/src/app/app.js index cb9955ae..200df057 100644 --- a/src/app/app.js +++ b/src/app/app.js @@ -7,15 +7,17 @@ angular.module( 'orderCloud', [ 'ui.router', 'ui.bootstrap', 'orderCloud.sdk', - 'toastr' + 'toastr', + 'ordercloud-infinite-scroll', + 'ordercloud-buyer-select', + 'ordercloud-search', + 'ordercloud-assignment-helpers' ]) .run( SetBuyerID ) .run( Security ) .config( Routing ) - //.config( ErrorHandling ) - .factory('$exceptionHandler', ExceptionHandler) - .factory('toast', toast) + .config( ErrorHandling ) .controller( 'AppCtrl', AppCtrl ) //Constants needed for the OrderCloud AngularJS SDK @@ -23,19 +25,19 @@ angular.module( 'orderCloud', [ .constant('appname', 'OrderCloud AngularJS Seed') //Client ID for a Registered Distributor or Buyer Company - .constant('clientid', '6d60154e-8a55-4bd2-93aa-494444e69996') + .constant('clientid', '0e0450e6-27a0-4093-a6b3-d7cd9ebc2b8f') //Test Environment - //.constant('authurl', 'https://testauth.ordercloud.io/oauth/token') - //.constant('apiurl', 'https://testapi.ordercloud.io') + .constant('authurl', 'https://testauth.ordercloud.io/oauth/token') + .constant('apiurl', 'https://testapi.ordercloud.io') - .constant('authurl', 'http://core.four51.com:11629/OAuth/Token') - .constant('apiurl', 'http://core.four51.com:9002') - .constant('devcenterClientID', '6d60154e-8a55-4bd2-93aa-494444e69996') //Local + //Local Environment + //.constant('authurl', 'http://core.four51.com:11629/OAuth/Token') + //.constant('apiurl', 'http://core.four51.com:9002') ; function SetBuyerID( BuyerID ) { - BuyerID.Set('xxxx'); + BuyerID.Set('451ORDERCLOUD'); } function Security( $rootScope, $state, Auth ) { @@ -58,20 +60,24 @@ function Routing( $urlRouterProvider, $urlMatcherFactoryProvider ) { //TODO: For HTML5 mode to work we need to always return index.html as the entry point on the serverside } -function ExceptionHandler($injector) { - return function( ex, cause ) { - var toastr = $injector.get('toastr'); - if (ex.data) { - var msg = ex.data.error || ex.data.Errors[0].Message; - toastr.error(msg, 'Error'); - } else if (ex.message) { - toastr.error(ex.message, 'Error'); - } - } +function ErrorHandling( $provide ) { + $provide.decorator('$exceptionHandler', handler); + + function handler( $delegate, $injector ) { + return function( ex, cause ) { + $delegate(ex, cause); + $injector.get('toastr').error(ex.data ? (ex.data.error || ex.data.Errors[0].Message) : ex.message, 'Error'); + }; + }; } -function AppCtrl( $state, Credentials, Users ) { +function AppCtrl( $state, appname, Credentials ) { var vm = this; + vm.name = appname; + vm.showLeftNav = true; + vm.toggleLeftNav = function() { + vm.showLeftNav = !vm.showLeftNav; + }; vm.logout = function() { Credentials.Delete(); $state.go('login'); diff --git a/src/app/base/base.js b/src/app/base/base.js index ed8bb98b..5b6c3560 100644 --- a/src/app/base/base.js +++ b/src/app/base/base.js @@ -2,6 +2,8 @@ angular.module( 'orderCloud' ) .config( BaseConfig ) .controller( 'BaseCtrl', BaseController ) + .controller( 'BaseLeftCtrl', BaseLeftController ) + .controller( 'BaseTopCtrl', BaseTopController ) ; @@ -11,15 +13,70 @@ function BaseConfig( $stateProvider ) { url: '', abstract: true, templateUrl:'base/templates/base.tpl.html', - controller:'BaseCtrl', - controllerAs: 'base', data:{ - limitAccess: true //Whether or not to require authentication on this state, this also affects any child states. - /*TODO: make the '$stateChangeStart event' in _app.js accept a function so users can control the redirect from here.*/ + limitAccess: true + }, + views: { + '': { + templateUrl: 'base/templates/base.tpl.html', + controller: 'BaseCtrl', + controllerAs: 'base' + }, + 'top@base': { + templateUrl: 'base/templates/base.top.tpl.html', + controller: 'BaseTopCtrl', + controllerAs: 'baseTop' + }, + 'left@base': { + templateUrl: 'base/templates/base.left.tpl.html', + controller: 'BaseLeftCtrl', + controllerAs: 'baseLeft' + } + }, + resolve: { + CurrentUser: function(Me) { + return Me.Get(); + }, + ComponentList: function($state, $q) { + var deferred = $q.defer(); + var nonSpecific = ['Products', 'Specs', 'Price Schedules']; + var components = { + nonSpecific: [], + buyerSpecific: [] + }; + angular.forEach($state.get(), function(state) { + if (!state.data || !state.data.componentName) return; + if (nonSpecific.indexOf(state.data.componentName) > -1) { + components.nonSpecific.push({ + Display: state.data.componentName, + StateRef: state.name + }) + } else { + components.buyerSpecific.push({ + Display: state.data.componentName, + StateRef: state.name + }) + } + }); + deferred.resolve(components); + return deferred.promise; + } } - }) + }); } -function BaseController( ) { +function BaseController( CurrentUser ) { var vm = this; + vm.currentUser = CurrentUser; } + +function BaseLeftController(ComponentList) { + var vm = this; + vm.catalogItems = ComponentList.nonSpecific; + vm.organizationItems = ComponentList.buyerSpecific; + vm.isCollapsed = true; +} + +function BaseTopController() { + var vm = this; +} \ No newline at end of file diff --git a/src/app/base/less/base.less b/src/app/base/less/base.less index e69de29b..09850fd4 100644 --- a/src/app/base/less/base.less +++ b/src/app/base/less/base.less @@ -0,0 +1,110 @@ +#DashboardWrapper { + padding-left: 0; + transition: all 0.5s ease; + &.toggled { + padding-left: @dashboard-leftnav-width; + #DashboardLeftNav { + width: @dashboard-leftnav-width; + } + #DashboardContent { + position: absolute; + margin-right: -@dashboard-leftnav-width; + } + } +} + +#DashboardLeftNav { + z-index: 1000; + position: fixed; + left: @dashboard-leftnav-width; + width: 0; + height: 100%; + margin-left: -@dashboard-leftnav-width; + overflow-y: auto; + overflow-x:hidden; + background-color:@dashboard-leftnav-bg; + border-right:1px solid @dashboard-leftnav-border; + -webkit-transition: all 0.5s ease; + -moz-transition: all 0.5s ease; + -o-transition: all 0.5s ease; + transition: all 0.5s ease; +} + + +#DashboardContent { + width: 100%; + position: absolute; +} + +@media(min-width:768px) { + #DashboardWrapper { + padding-left: @dashboard-leftnav-width; + &.toggled { + padding-left: 0; + #DashboardLeftNav { + width: 0; + } + #DashboardContent { + position: relative; + margin-right: 0; + } + } + } + + #DashboardLeftNav { + width: @dashboard-leftnav-width; + } + + #DashboardContent { + position: relative; + } +} + +#BaseLeft { + padding: @padding-base-horizontal; + width: @dashboard-leftnav-width; + white-space: nowrap; + h4 { + margin-left:-@padding-base-horizontal; + margin-right:-@padding-base-horizontal; + background-color:@navbar-default-bg; + padding:@padding-base-horizontal; + } +} + +.navbar-flex { + #BaseTop { + background-color:@navbar-default-bg; + border-bottom:1px solid @navbar-default-border; + display: flex; + flex-flow: row nowrap; + justify-content: flex-start; + align-items:center; + margin-bottom:@navbar-margin-bottom; + > div { + max-height:@navbar-height; + &.link { + flex:0 1 auto; + > a { + display:block; + line-height:@navbar-height - 20px; + padding:@nav-link-padding; + color:@navbar-default-link-color; + &:hover { + background-color:@navbar-default-link-hover-bg; + color:@navbar-default-link-hover-color; + } + &.active, + &:active, + &:focus { + background-color:@navbar-default-link-active-bg; + color:@navbar-default-link-active-color; + } + } + } + &.logo { + flex:1 0 auto; + } + } + } +} \ No newline at end of file diff --git a/src/app/base/less/variables.less b/src/app/base/less/variables.less index e69de29b..33c1ea14 100644 --- a/src/app/base/less/variables.less +++ b/src/app/base/less/variables.less @@ -0,0 +1,3 @@ +@dashboard-leftnav-width: 250px; +@dashboard-leftnav-bg: darken(@navbar-default-bg, 5); +@dashboard-leftnav-border:darken(@dashboard-leftnav-bg, 5); \ No newline at end of file diff --git a/src/app/base/templates/base.left.tpl.html b/src/app/base/templates/base.left.tpl.html new file mode 100644 index 00000000..88d9017f --- /dev/null +++ b/src/app/base/templates/base.left.tpl.html @@ -0,0 +1,26 @@ + diff --git a/src/app/base/templates/base.top.tpl.html b/src/app/base/templates/base.top.tpl.html new file mode 100644 index 00000000..f1b3173a --- /dev/null +++ b/src/app/base/templates/base.top.tpl.html @@ -0,0 +1,23 @@ +
+ + + +
\ No newline at end of file diff --git a/src/app/base/templates/base.tpl.html b/src/app/base/templates/base.tpl.html index afacddbd..52aaeb61 100644 --- a/src/app/base/templates/base.tpl.html +++ b/src/app/base/templates/base.tpl.html @@ -1,27 +1,7 @@ - -
-
-
+ \ No newline at end of file diff --git a/src/app/common/auto-id/auto-id.js b/src/app/common/auto-id/auto-id.js new file mode 100644 index 00000000..6e439741 --- /dev/null +++ b/src/app/common/auto-id/auto-id.js @@ -0,0 +1,52 @@ +angular.module('ordercloud-auto-id', []); + +angular.module('ordercloud-auto-id') + + .directive('ordercloudAutoId', ordercloudAutoIdDirective) + +; + +function ordercloudAutoIdDirective($compile) { + return { + restrict: 'A', + require: 'ngModel', + scope: { + boxtext: '@' + }, + link: function(scope, element, attrs, ngModel) { + scope.boxtext = scope.boxtext || 'Auto-Gen. ID'; + var autoID_element = angular.element(" {{boxtext}} "); + //var initCheckbox = true; + //if (scope.defaultvalue != undefined) { + // initCheckbox = scope.defaultvalue; + //} + //console.log(initCheckbox); + if(element.parent().hasClass('input-group') == false) { + element.wrap("
"); + } + autoID_element.attr('checked', true); + if (autoID_element.prop('checked')) { + element.attr('disabled', true); + } + autoID_element.bind('click', function() { + autoID_element.attr('checked', !autoID_element.prop('checked')); + if (autoID_element.prop('checked')) { + element.attr('disabled', true); + element.attr('required', false); + element.attr('ng-required', false); + element.removeClass('ng-invalid'); + element.removeClass('ng-invalid-required'); + ngModel.$setViewValue(null); + ngModel.$render(); + } + else { + element.attr('disabled', false); + element.attr('required', true); + element.attr('ng-required', true); + } + }); + element.after(autoID_element); + $compile(autoID_element)(scope); + } + } +} diff --git a/src/app/common/buyer-select/buyer-select.less b/src/app/common/buyer-select/buyer-select.less new file mode 100644 index 00000000..1e6b8d1e --- /dev/null +++ b/src/app/common/buyer-select/buyer-select.less @@ -0,0 +1,22 @@ +.btn-select-buyer { + text-align:left; + margin-bottom:10px; + span { + display:block; + white-space: normal; + } +} + +.buyer-list-menu{ + padding:0; + border:0; + background:none; + min-width:400px; + max-width:100%; + .table-fixed-header { + margin-bottom:0; + } + .table-container { + max-height:calc(50vh); + } +} \ No newline at end of file diff --git a/src/app/common/buyer-select/buyer-select.tpl.html b/src/app/common/buyer-select/buyer-select.tpl.html new file mode 100644 index 00000000..e61ec767 --- /dev/null +++ b/src/app/common/buyer-select/buyer-select.tpl.html @@ -0,0 +1,39 @@ +
+
+ + +
+ +
diff --git a/src/app/common/buyer-select/ordercloud-buyer-selected.js b/src/app/common/buyer-select/ordercloud-buyer-selected.js new file mode 100644 index 00000000..080b41a0 --- /dev/null +++ b/src/app/common/buyer-select/ordercloud-buyer-selected.js @@ -0,0 +1,49 @@ +angular.module('ordercloud-buyer-select', []) + + .directive('ordercloudSelectBuyer', SelectBuyerDirective) + .controller('SelectBuyerCtrl', SelectBuyerController) + +; + +function SelectBuyerDirective() { + return { + scope: {}, + restrict: 'E', + templateUrl: 'common/buyer-select/buyer-select.tpl.html', + controller: 'SelectBuyerCtrl', + controllerAs: 'selectBuyer' + } +} + +function SelectBuyerController($state, Buyers, BuyerID) { + var vm = this, + page = 1; + + Buyers.List().then(function(data) { + vm.BuyerList = data; + }); + + Buyers.Get(BuyerID.Get()).then(function(data) { + vm.selectedBuyer = data; + }); + + vm.ChangeBuyer = function(buyer) { + Buyers.Get(buyer.ID).then(function(data) { + vm.selectedBuyer = data; + BuyerID.Set(data.ID); + //console.dir($state.current); + $state.reload($state.current); + }); + }; + + vm.PagingFunction = function() { + page += 1; + if (page <= vm.BuyerList.Meta.TotalPages) { + Buyers.List(null, page, vm.BuyerList.Meta.PageSize) + .then(function(data) { + vm.BuyerList.Meta = data.Meta; + vm.BuyerList.Items = [].concat(vm.BuyerList.Items, data.Items); + }); + } + } +} diff --git a/src/app/common/files/files.js b/src/app/common/files/files.js new file mode 100644 index 00000000..87d9ecea --- /dev/null +++ b/src/app/common/files/files.js @@ -0,0 +1,133 @@ +angular.module( 'orderCloud' ) + + .factory('FileReader', fileReader) + .factory( 'FilesService', FilesService ) + .directive( 'ordercloudFileUpload', ordercloudFileUpload) +; + +function fileReader( $q ) { + var service = { + readAsDataUrl: readAsDataURL + }; + + function onLoad(reader, deferred, scope) { + return function () { + scope.$apply(function () { + deferred.resolve(reader); + }); + }; + } + + function onError(reader, deferred, scope) { + return function () { + scope.$apply(function () { + deferred.reject(reader); + }); + }; + } + + function onProgress(reader, scope) { + return function (event) { + scope.$broadcast("fileProgress", + { + total: event.total, + loaded: event.loaded + }); + }; + } + + function getReader(deferred, scope) { + var reader = new FileReader(); + reader.onload = onLoad(reader, deferred, scope); + reader.onerror = onError(reader, deferred, scope); + reader.onprogress = onProgress(reader, scope); + return reader; + } + + function readAsDataURL(file, scope) { + var deferred = $q.defer(); + + var reader = getReader(deferred, scope); + reader.readAsDataURL(file); + + return deferred.promise; + } + + return service; +} + +function FilesService( $q, $http, apiurl ) { + var service = { + Upload: _upload + }; + + var fileURL = apiurl + '/v1/files'; + + function _upload(file, fileName) { + var deferred = $q.defer(); + + var fd = new FormData(); + fd.append('file', file); + + $http.post(fileURL + '?filename=' + fileName, fd, {transformRequest: angular.identity, headers: {'Content-Type': undefined}}) + .success(function(data){ + deferred.resolve(data); + }) + .error(function(error){ + deferred.reject(error) + }); + + return deferred.promise; + } + + return service; +} + +function ordercloudFileUpload( $parse, FileReader, FilesService ) { + var directive = { + scope: { + model: '=', + keyname: '@', + label: '@' + }, + restrict: 'E', + templateUrl: 'common/files/templates/files.tpl.html', + replace: true, + link: link + }; + + function link(scope, element, attrs) { + var file_input = $parse("file"); + var file_control = angular.element(element.find('input'))[0]; + + function afterSelection(fileName) { + FilesService.Upload(file_control.files[0], fileName) + .then(function(fileData) { + if (!scope.model.xp) scope.model.xp = {}; + scope.model.xp[scope.keyname] = fileData; + scope.model.FileUpdated = true; + }); + } + + function updateModel(event) { + switch (event.target.name) { + case 'upload': + if (event.target.files[0] == null) return; + var fileName = event.target.files[0].name; + scope.$apply(function() { + FileReader.readAsDataUrl(event.target.files[0], scope) + .then(function(f) { + afterSelection(fileName); + }); + file_input.assign(scope, event.target.files[0]); + }); + break; + } + } + + element.bind('change', updateModel); + } + + return directive; +} + diff --git a/src/app/common/files/templates/files.tpl.html b/src/app/common/files/templates/files.tpl.html new file mode 100644 index 00000000..6d1ab633 --- /dev/null +++ b/src/app/common/files/templates/files.tpl.html @@ -0,0 +1,4 @@ +
+ + +
diff --git a/src/app/common/helper-factories/assignment-helpers.js b/src/app/common/helper-factories/assignment-helpers.js new file mode 100644 index 00000000..e8799248 --- /dev/null +++ b/src/app/common/helper-factories/assignment-helpers.js @@ -0,0 +1,59 @@ +angular.module('ordercloud-assignment-helpers', []) + + .factory('Assignments', AssignmentHelpers) + +; + +function AssignmentHelpers($q, Underscore, $state) { + return { + //getAssigned: getAssigned, + //getSelected: getSelected, + //getUnselected: getUnselected, + //getToAssign: getToAssign, + //getToDelete: getToDelete, + saveAssignments: saveAssignments + }; + + function getAssigned(AssignmentsArray, ID_Name) { + //TODO: Save this result in temp variable so I don't do this operation twice every time. + return Underscore.pluck(AssignmentsArray, ID_Name); + } + + function getSelected(ListArray) { + return Underscore.pluck(Underscore.where(ListArray, {selected: true}), 'ID'); + } + + function getUnselected(ListArray) { + return Underscore.pluck(Underscore.filter(ListArray, function(item) { + return !item.selected; + }), 'ID'); + } + + function getToAssign(ListArray, AssignmentsArray, ID_Name) { + return Underscore.difference(getSelected(ListArray), getAssigned(AssignmentsArray, ID_Name)); + } + + function getToDelete(ListArray, AssignmentsArray, ID_Name) { + return Underscore.intersection(getUnselected(ListArray), getAssigned(AssignmentsArray, ID_Name)); + } + + function saveAssignments(ListArray, AssignmentsArray, SaveFunc, DeleteFunc, ID_Name) { + var id_name = ID_Name ? ID_Name : 'UserGroupID'; + var toAssign = getToAssign(ListArray, AssignmentsArray, id_name); + var toDelete = getToDelete(ListArray, AssignmentsArray, id_name); + var queue = []; + var dfd = $q.defer(); + angular.forEach(toAssign, function(ItemID) { + console.log(ItemID); + queue.push(SaveFunc(ItemID)); + }); + angular.forEach(toDelete, function(ItemID) { + queue.push(DeleteFunc(ItemID)); + }); + $q.all(queue).then(function() { + dfd.resolve(); + $state.reload($state.current); + }); + return dfd.promise; + } +} \ No newline at end of file diff --git a/src/app/common/infinite-scroll/infinite-scroll.js b/src/app/common/infinite-scroll/infinite-scroll.js new file mode 100644 index 00000000..8e7e79a5 --- /dev/null +++ b/src/app/common/infinite-scroll/infinite-scroll.js @@ -0,0 +1,128 @@ +angular.module('ordercloud-infinite-scroll', ['ordercloud-search']); +angular.module('ordercloud-infinite-scroll') + + .directive( 'ordercloudInfiniteScroll', InfiniteScrollDirective ) + .controller( 'InfiniteScrollCtrl', InfiniteScrollController ) + .factory( 'PagingFunctions', PagingFunctionsFactory ) +; + +function InfiniteScrollDirective(PagingFunctions) { + return { + restrict: 'A', + scope: { + pagingfunction: '&', + servicename: '@', + listobject: '=', + threshold: '@', + usergrouplist: '=', + selectedid: '@' + }, + controller: 'InfiniteScrollCtrl', + controllerAs: 'InfiniteScroll', + link: function(scope, element, attrs) { + var threshold = scope.threshold || 0; + var ele = element[0]; + element.bind('scroll', function () { + if (ele.scrollTop + ele.offsetHeight + threshold >= ele.scrollHeight) { + if (scope.servicename && scope.listobject && scope.usergrouplist && scope.selectedid) { + PagingFunctions.assignmentsPaging(scope.servicename, scope.listobject, scope.usergrouplist, scope.selectedid); + } + /* Use preset factory */ + else if (scope.servicename && scope.listobject) { + PagingFunctions.componentPaging(scope.servicename, scope.listobject); + } + /* Check if paging function is defined */ + else if (scope.pagingfunction != undefined && typeof(scope.pagingfunction) == 'function') { + scope.pagingfunction(); + } + /* Else display a console error */ + else { + console.log('Error: Infinite scroll directive not fully defined.'); + } + } + }); + } + } +} + +function InfiniteScrollController($scope, PagingFunctions) { + PagingFunctions.reset(); + if ($scope.usergrouplist) { + PagingFunctions.setSelected($scope.listobject, $scope.usergrouplist); + } +} + +function PagingFunctionsFactory($injector, UserGroups, TrackSearch) { + var page = 1, + pageSize = 20, + nonBuyerSpecific = [ + 'Buyers', + 'Products', + 'PriceSchedules', + 'Specs' + ], + service = { + reset: initPaging, + setSelected: setSelected, + componentPaging: componentPaging, + assignmentsPaging: assignmentsPaging + }; + return service; + + function initPaging() { + TrackSearch.SetTerm(null); + } + + function componentPaging(component, componentObject) { + var componentService = $injector.get(component); + //page += 1; + if (componentObject.Meta.Page + 1 <= componentObject.Meta.TotalPages && componentService) { + var args = []; + if (component === 'Orders') { + args = ['incoming', TrackSearch.GetTerm(), null, null, componentObject.Meta.Page + 1, componentObject.Meta.PageSize]; + } + else { + args = [ TrackSearch.GetTerm(), componentObject.Meta.Page + 1, componentObject.Meta.PageSize]; + } + componentService.List.apply(this, args) + .then(function(data) { + componentObject.Meta = data.Meta; + componentObject.Items = [].concat(componentObject.Items, data.Items); + }); + } + } + + function assignmentsPaging(component, componentObject, UserGroupList, selectedID) { + var componentService = $injector.get(component); + page += 1; + if (page <= UserGroupList.Meta.TotalPages && componentService) { + UserGroups.List(null, page, UserGroupList.Meta.PageSize) + .then(function(data) { + UserGroupList.Meta = data.Meta; + UserGroupList.Items = [].concat(UserGroupList.Items, data.Items); + if (page <= componentObject.Meta.TotalPages) { + var args = [selectedID, null, null, page, UserGroupList.Meta.PageSize]; + componentService.ListAssignments.apply(this, args) + .then(function(data) { + componentObject.Meta = data.Meta; + componentObject.Items = [].concat(componentObject.Items, data.Items); + setSelected(componentObject, UserGroupList); + }); + } + else { + setSelected(componentObject, UserGroupList); + } + }); + } + } + + function setSelected(assignedUserGroups, userGroups) { + angular.forEach(userGroups.Items, function(group) { + angular.forEach(assignedUserGroups.Items, function(assignedGroup) { + if (assignedGroup.UserGroupID === group.ID) { + group.selected = true; + } + }); + }); + } +} \ No newline at end of file diff --git a/src/app/common/ordercloud-logo/ordercloud-logo.tpl.html b/src/app/common/ordercloud-logo/ordercloud-logo.tpl.html new file mode 100644 index 00000000..475605f0 --- /dev/null +++ b/src/app/common/ordercloud-logo/ordercloud-logo.tpl.html @@ -0,0 +1,133 @@ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/app/common/ordercloud-logo/ordercloud_logo.js b/src/app/common/ordercloud-logo/ordercloud_logo.js new file mode 100644 index 00000000..c8068847 --- /dev/null +++ b/src/app/common/ordercloud-logo/ordercloud_logo.js @@ -0,0 +1,19 @@ +angular.module('orderCloud') + .directive('ordercloudLogo', ordercloudLogo) +; + +function ordercloudLogo() { + var obj = { + templateUrl: 'common/ordercloud-logo/ordercloud-logo.tpl.html', + replace:true, + link: function(scope, element, attrs) { + scope.OrderCloudLogo = { + 'Icon': attrs.icon ? true : false, + 'maxHeight':attrs.height, + 'fillColor': attrs.color, + 'width': attrs.width + }; + } + }; + return obj; +} \ No newline at end of file diff --git a/src/app/common/search/search.js b/src/app/common/search/search.js new file mode 100644 index 00000000..3dd3728b --- /dev/null +++ b/src/app/common/search/search.js @@ -0,0 +1,63 @@ +angular.module('ordercloud-search', []); +angular.module('ordercloud-search') + + .directive( 'ordercloudSearch', ordercloudSearch) + .controller( 'ordercloudSearchCtrl', ordercloudSearchCtrl) + .factory( 'TrackSearch', trackSearchService ) +; + +function ordercloudSearch () { + return { + scope: { + servicename: "@", + controlleras: "=" + }, + restrict: 'E', + templateUrl: 'common/search/templates/search.tpl.html', + controller: 'ordercloudSearchCtrl', + controllerAs: 'ocSearch', + replace: true + } +} + +function ordercloudSearchCtrl($timeout, $scope, $injector, TrackSearch) { + $scope.searchTerm = null; + $scope.placeholder = "Search " + $scope.servicename + '...'; + var Service = $injector.get($scope.servicename); + var searching; + $scope.$watch('searchTerm', function(n,o) { + if (n == o) { + if (searching) $timeout.cancel(searching); + } else { + if (searching) $timeout.cancel(searching); + searching = $timeout(function() { + n == '' ? n = null : angular.noop(); + TrackSearch.SetTerm(n); + Service.List(n) + .then(function (data){ + $scope.controlleras.list = data; + }); + }, 300); + } + }); +} + +function trackSearchService() { + var service = { + SetTerm: _setTerm, + GetTerm: _getTerm + }; + + var term = null; + + function _setTerm(value) { + term = value; + } + + function _getTerm() { + return term; + } + + return service; +} + diff --git a/src/app/common/search/templates/search.tpl.html b/src/app/common/search/templates/search.tpl.html new file mode 100644 index 00000000..8d471449 --- /dev/null +++ b/src/app/common/search/templates/search.tpl.html @@ -0,0 +1,5 @@ +
+
+ +
+
\ No newline at end of file diff --git a/src/app/global.less b/src/app/global.less index 42750a0f..09670ae0 100644 --- a/src/app/global.less +++ b/src/app/global.less @@ -1,7 +1,94 @@ body { - padding-top:70px; // Source - http://getbootstrap.com/components/#callout-navbar-fixed-top-padding + overflow-x:hidden; } -[ui-sref] { +[ui-sref], +[ng-click]{ cursor: pointer; +} + +//TABLES WITH FIXED HEADERS +.table-fixed-header { + position:relative; + padding-top:@table-header-height; + margin-bottom:@line-height-computed; + overflow:hidden; + .table-header-bg { + position:absolute; + left:0; right:0; top:0; + height:@table-header-height; + background:@table-header-bg; + border:1px solid @table-header-border-color; + border-bottom-width:2px; + .border-top-radius(@table-border-radius); + } + .table-container { + background-color:@table-bg; + overflow-y:auto; + overflow-x:hidden; + max-height:@infinite-scroll-size; + border: 1px solid @table-border-color; + border-top-width:0; + .border-bottom-radius(@table-border-radius); + table { + border-spacing:0; + margin-bottom:0; + } + td { + border:1px solid @table-border-color; + vertical-align:middle; + &:first-child { + border-left:none; + } + &:last-child { + border-left:none; + } + } + th { + height: 0; + line-height: 0; + padding: 0 25px; + color: transparent; + border: none; + white-space: nowrap; + span { + max-height:0; + height:0; + line-height:0; + margin:0; + padding:0; + } + div{ + position: absolute; + background: transparent; + padding:@table-cell-padding; + color:@table-header-color; + top: 0; + margin-left: -25px; + line-height: @line-height-base; + vertical-align: bottom; + border-left:1px solid @table-header-border-color; + } + &:first-child div{ + border: none; + } + } + tbody tr { + &:first-child { + td { + border-top:none; + } + } + &:last-child { + td { + border-bottom:none; + } + } + } + } +} +colgroup { + > col.action-column { + width:70px; + } } \ No newline at end of file diff --git a/src/app/home/home.js b/src/app/home/home.js index 06c85a1b..e1a302fa 100644 --- a/src/app/home/home.js +++ b/src/app/home/home.js @@ -15,7 +15,6 @@ function HomeConfig( $stateProvider ) { }) } -function HomeController( appname ) { +function HomeController( ) { var vm = this; - vm.appName = appname; } diff --git a/src/app/home/templates/home.tpl.html b/src/app/home/templates/home.tpl.html index 729a9575..efa9af0a 100644 --- a/src/app/home/templates/home.tpl.html +++ b/src/app/home/templates/home.tpl.html @@ -1,4 +1,6 @@ -
-

-

Everything you need to kickstart AngularJS projects for OrderCloud: a best-practice directory structure, an intelligent build system, and the best web design libraries around.

-
+
+
+

+
+
+ diff --git a/src/app/login/login.js b/src/app/login/login.js index 4dfc4e73..f0d73f6f 100644 --- a/src/app/login/login.js +++ b/src/app/login/login.js @@ -13,7 +13,7 @@ function LoginConfig( $stateProvider ) { controller:'LoginCtrl', controllerAs: 'login', data:{ - limitAccess: false //Whether or not to require authentication on this state + limitAccess: false } }); } diff --git a/src/app/login/templates/login.tpl.html b/src/app/login/templates/login.tpl.html index bbc698fc..7744d94d 100644 --- a/src/app/login/templates/login.tpl.html +++ b/src/app/login/templates/login.tpl.html @@ -10,7 +10,7 @@

Login

- Forgot Password? + Forgot Password?

Forgot Password

diff --git a/src/app/variables.less b/src/app/variables.less index 6c92855a..fb958272 100644 --- a/src/app/variables.less +++ b/src/app/variables.less @@ -1,2 +1,17 @@ //These are the variables used throughout the application. This is where -//overwrites that are not specific to components should be maintained. \ No newline at end of file +//overwrites that are not specific to components should be maintained. +//Interconnected table color styles +@table-bg:white; +@table-bg-accent:darken(@table-bg, 5); +@table-bg-hover:darken(@table-bg-accent, 5); + +@table-border-color:darken(@table-bg, 15); +@table-border-radius:@border-radius-base; + +@table-header-bg:white; +@table-header-border-color:darken(@table-header-bg, 15); +@table-header-color:@text-color; +@table-header-height:@table-cell-padding*2 + @line-height-computed; + +//Infinite Scroll +@infinite-scroll-size: 600px; \ No newline at end of file From d3d2b4772df9e33056127f95065a53b3998ea1ea Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 4 Nov 2015 16:14:30 -0600 Subject: [PATCH 032/367] Error handling for errors where ex.data is the message --- src/app/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/app.js b/src/app/app.js index 200df057..fb02472b 100644 --- a/src/app/app.js +++ b/src/app/app.js @@ -66,7 +66,7 @@ function ErrorHandling( $provide ) { function handler( $delegate, $injector ) { return function( ex, cause ) { $delegate(ex, cause); - $injector.get('toastr').error(ex.data ? (ex.data.error || ex.data.Errors[0].Message) : ex.message, 'Error'); + $injector.get('toastr').error(ex.data ? (ex.data.error || (ex.data.Errors ? ex.data.Errors[0].Message : ex.data)) : ex.message, 'Error'); }; }; } From f2d3e1b283f719d27ace6dd3632efaca94a7360c Mon Sep 17 00:00:00 2001 From: mlund01 Date: Wed, 9 Dec 2015 15:43:50 -0600 Subject: [PATCH 033/367] remove clientid and set env to prod from test clientid should not be set in repo, and environment needs to be set to prod (not test) --- src/app/app.js | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/app/app.js b/src/app/app.js index fb02472b..767eab60 100644 --- a/src/app/app.js +++ b/src/app/app.js @@ -25,15 +25,9 @@ angular.module( 'orderCloud', [ .constant('appname', 'OrderCloud AngularJS Seed') //Client ID for a Registered Distributor or Buyer Company - .constant('clientid', '0e0450e6-27a0-4093-a6b3-d7cd9ebc2b8f') - - //Test Environment - .constant('authurl', 'https://testauth.ordercloud.io/oauth/token') - .constant('apiurl', 'https://testapi.ordercloud.io') - - //Local Environment - //.constant('authurl', 'http://core.four51.com:11629/OAuth/Token') - //.constant('apiurl', 'http://core.four51.com:9002') + .constant('clientid', '') + .constant('authurl', 'https://auth.ordercloud.io/oauth/token') + .constant('apiurl', 'https://api.ordercloud.io') ; function SetBuyerID( BuyerID ) { @@ -82,4 +76,4 @@ function AppCtrl( $state, appname, Credentials ) { Credentials.Delete(); $state.go('login'); }; -} \ No newline at end of file +} From e8bee785caffee698be00da4d3cd2fe225d33a6d Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Thu, 10 Dec 2015 13:30:22 -0600 Subject: [PATCH 034/367] Updates to the seed --- .bowerrc | 5 + .gitignore | 7 + .gitmodules | 0 .travis.yml | 13 + Gulp/assetTasks.js | 138 +++++++++ Gulp/generalTasks.js | 56 ++++ Gulp/scriptTasks.js | 98 +++++++ Gulp/testTasks.js | 39 +++ Gulp/watchTasks.js | 63 ++++ Gulpfile.js | 13 + LICENSE | 19 ++ README.md | 276 ++++++++++++++++++ bower.json | 22 ++ changelog.tpl | 23 ++ gulpConfig.js | 66 +++++ karma.conf.js | 67 +++++ karma/karma-unit.tpl.js | 25 ++ package.json | 41 +++ src/README.md | 41 +++ src/app/README.md | 106 +++++++ src/app/account/account.js | 161 ++++++++++ src/app/account/templates/account.tpl.html | 34 +++ .../account/templates/changePassword.tpl.html | 19 ++ .../templates/confirmPassword.modal.tpl.html | 10 + src/app/app.js | 79 +++++ src/app/app.spec.js | 0 src/app/base/base.js | 82 ++++++ src/app/base/base.spec.js | 0 src/app/base/less/base.less | 110 +++++++ src/app/base/less/variables.less | 3 + src/app/base/templates/base.left.tpl.html | 26 ++ src/app/base/templates/base.top.tpl.html | 23 ++ src/app/base/templates/base.tpl.html | 7 + src/app/common/auto-id/auto-id.js | 52 ++++ src/app/common/buyer-select/buyer-select.less | 22 ++ .../common/buyer-select/buyer-select.tpl.html | 39 +++ .../buyer-select/ordercloud-buyer-selected.js | 49 ++++ src/app/common/files/files.js | 133 +++++++++ src/app/common/files/templates/files.tpl.html | 4 + .../helper-factories/assignment-helpers.js | 59 ++++ .../common/infinite-scroll/infinite-scroll.js | 128 ++++++++ .../ordercloud-logo/ordercloud-logo.tpl.html | 133 +++++++++ .../common/ordercloud-logo/ordercloud_logo.js | 19 ++ src/app/common/search/search.js | 63 ++++ .../common/search/templates/search.tpl.html | 5 + src/app/global.less | 94 ++++++ src/app/home/README.md | 75 +++++ src/app/home/home.js | 20 ++ src/app/home/home.spec.js | 0 src/app/home/less/home.less | 0 src/app/home/less/variables.less | 0 src/app/home/templates/home.tpl.html | 6 + src/app/login/less/login.less | 4 + src/app/login/less/variables.less | 2 + src/app/login/login.js | 115 ++++++++ src/app/login/login.spec.js | 0 src/app/login/templates/login.tpl.html | 49 ++++ src/app/variables.less | 17 ++ src/assets/README.md | 5 + src/index.html | 19 ++ tools.md | 112 +++++++ 61 files changed, 2896 insertions(+) create mode 100644 .bowerrc create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 .travis.yml create mode 100644 Gulp/assetTasks.js create mode 100644 Gulp/generalTasks.js create mode 100644 Gulp/scriptTasks.js create mode 100644 Gulp/testTasks.js create mode 100644 Gulp/watchTasks.js create mode 100644 Gulpfile.js create mode 100644 LICENSE create mode 100644 README.md create mode 100644 bower.json create mode 100644 changelog.tpl create mode 100644 gulpConfig.js create mode 100644 karma.conf.js create mode 100644 karma/karma-unit.tpl.js create mode 100644 package.json create mode 100644 src/README.md create mode 100644 src/app/README.md create mode 100644 src/app/account/account.js create mode 100644 src/app/account/templates/account.tpl.html create mode 100644 src/app/account/templates/changePassword.tpl.html create mode 100644 src/app/account/templates/confirmPassword.modal.tpl.html create mode 100644 src/app/app.js create mode 100644 src/app/app.spec.js create mode 100644 src/app/base/base.js create mode 100644 src/app/base/base.spec.js create mode 100644 src/app/base/less/base.less create mode 100644 src/app/base/less/variables.less create mode 100644 src/app/base/templates/base.left.tpl.html create mode 100644 src/app/base/templates/base.top.tpl.html create mode 100644 src/app/base/templates/base.tpl.html create mode 100644 src/app/common/auto-id/auto-id.js create mode 100644 src/app/common/buyer-select/buyer-select.less create mode 100644 src/app/common/buyer-select/buyer-select.tpl.html create mode 100644 src/app/common/buyer-select/ordercloud-buyer-selected.js create mode 100644 src/app/common/files/files.js create mode 100644 src/app/common/files/templates/files.tpl.html create mode 100644 src/app/common/helper-factories/assignment-helpers.js create mode 100644 src/app/common/infinite-scroll/infinite-scroll.js create mode 100644 src/app/common/ordercloud-logo/ordercloud-logo.tpl.html create mode 100644 src/app/common/ordercloud-logo/ordercloud_logo.js create mode 100644 src/app/common/search/search.js create mode 100644 src/app/common/search/templates/search.tpl.html create mode 100644 src/app/global.less create mode 100644 src/app/home/README.md create mode 100644 src/app/home/home.js create mode 100644 src/app/home/home.spec.js create mode 100644 src/app/home/less/home.less create mode 100644 src/app/home/less/variables.less create mode 100644 src/app/home/templates/home.tpl.html create mode 100644 src/app/login/less/login.less create mode 100644 src/app/login/less/variables.less create mode 100644 src/app/login/login.js create mode 100644 src/app/login/login.spec.js create mode 100644 src/app/login/templates/login.tpl.html create mode 100644 src/app/variables.less create mode 100644 src/assets/README.md create mode 100644 src/index.html create mode 100644 tools.md diff --git a/.bowerrc b/.bowerrc new file mode 100644 index 00000000..1f984984 --- /dev/null +++ b/.bowerrc @@ -0,0 +1,5 @@ +{ + "directory": "vendor", + "json": "bower.json" +} + diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..d8733b94 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +*.sw* +*~ +build/ +compile/ +node_modules/ +vendor/ +temp/ \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..e69de29b diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..29f56d66 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,13 @@ +language: node_js +node_js: + - "0.10" + +before_script: + - export DISPLAY=:99.0 + - sh -e /etc/init.d/xvfb start + - npm install --quiet -g grunt-cli karma bower + - npm install + - bower install + +script: grunt + diff --git a/Gulp/assetTasks.js b/Gulp/assetTasks.js new file mode 100644 index 00000000..524087ea --- /dev/null +++ b/Gulp/assetTasks.js @@ -0,0 +1,138 @@ +//GENERAL +var gulp = require('gulp'); +var less = require('gulp-less'); +var sass = require('gulp-sass'); +var filter = require('gulp-filter'); +var autoprefixer = require('gulp-autoprefixer'); +var minify = require('gulp-minify-css'); +var mainBowerFiles = require('main-bower-files'); +var concat = require('gulp-concat'); +var del = require('del'); +var vinylPaths = require('vinyl-paths'); +var plumber = require('gulp-plumber'); +var lessImport = require('gulp-less-import'); +var replace = require('gulp-replace'); +var flatten = require('gulp-flatten'); + +var pkg = require('../package.json'); +var currVersion = pkg.name + "-" + pkg.version; +/*var lessFilter = filter('**!/!*.less'); +var sassFilter = filter(['**!/!*.sass', '**!/!*.scss']); +var cssFilter = filter('**!/!*.css');*/ + + +/*BUILD*/ + +gulp.task('b_m:less', function() { + return gulp.src(mainBowerFiles({filter: '**/*.less'}) + .concat(config.vendor_files.import_less).concat(config.app_files.import_less)) + .pipe(plumber()) + .pipe(lessImport('lessStyles.less')) + .pipe(less()) + .pipe(gulp.dest(config.temp)) +}); + +gulp.task('b_m:sass', function() { + return gulp.src(mainBowerFiles({filter: ['**/*.sass', '**/*.scss']}) + .concat([config.source + '**/*.scss', config.source + '**/*.sass'])) + .pipe(plumber()) + .pipe(sass()) + .pipe(concat(config.temp + 'sassStyles.css')) + .pipe(gulp.dest(config.temp)) +}); + +gulp.task('b_m:css', function() { + return gulp + .src(mainBowerFiles({filter: '**/*.css'}).concat('!**/font-awesome.css')) + .pipe(plumber()) + .pipe(autoprefixer({browsers: ['last 2 versions']})) + .pipe(concat('bowerStyles.css')) + .pipe(gulp.dest(config.temp)) +}); + +gulp.task('b_m:appCss', function() { + return gulp + .src(config.source + '**/*.css') + .pipe(plumber()) + .pipe(autoprefixer({browsers: ['last 2 versions']})) + .pipe(concat('appCss.css')) + .pipe(gulp.dest(config.temp)) +}); + +gulp.task('b_m:styles', function() { + return gulp + .src(config.temp + '*.css') + .pipe(replace('../fonts/', 'fonts/')) + .pipe(concat(currVersion + '.css')) + .pipe(gulp.dest(config.build + 'assets')) + .pipe(browserSync.stream()) +}); + +gulp.task('b_c:styles', function() { + return del([ + config.build + 'assets/**/*.css', + config.temp + '**/*' + ]); +}); + +gulp.task('b_m:assets', function() { + return gulp.src([ + config.source + 'assets/**/*', + '!' + config.source + '**/*.css', + '!' + config.source + '**/*.less', + '!' + config.source + '**/*.scss', + '!' + config.source + '**/*.sass']) + .pipe(gulp.dest(config.build + 'assets')) +}); + +gulp.task('b_m:fonts', function() { + return gulp.src('vendor/**/fonts/*', '!vendor/**/dist') + .pipe(flatten()) + .pipe(gulp.dest(config.build + 'assets/fonts')) +}); + +gulp.task('b_c:assets', function() { + return del([ + config.build + 'assets/**/*', + '!' + config.build + '**/*.css', + '!' + config.build + '**/*.less', + '!' + config.build + '**/*.scss', + '!' + config.build + '**/*.sass', + '!' + config.build + 'assets/fonts/**/*' + ]); +}); + +/*COMPILE*/ +gulp.task('c_m:css', function() { + return gulp.src(config.build + 'assets/**/*.css') + .pipe(minify()) + .pipe(gulp.dest(config.compile + 'assets/')); +}); + +gulp.task('c_c:css', function() { + return gulp + .src(config.compile + '**/*.css', {read:false}) + .pipe(vinylPaths(del)); +}); + +gulp.task('c_m:assets', function() { + return gulp.src([ + config.build + 'assets/**/*', + '!' + config.build + '**/*.css', + '!' + config.build + '**/*.less', + '!' + config.build + '**/*.scss', + '!' + config.build + '**/*.sass']) + .pipe(gulp.dest(config.compile + 'assets')) +}); + +gulp.task('c_c:assets', function() { + return gulp + .src([config.compile + 'assets/**/*', '!' + config.compile + 'assets/**/*.css'], {read:false}) + .pipe(vinylPaths(del)); +}); + +//Master Asset Tasks +gulp.task('build:styles', gulp.series('b_c:styles', 'b_m:less', 'b_m:sass', 'b_m:css', 'b_m:appCss', 'b_m:styles')); +gulp.task('compile:css', gulp.series('c_c:css', 'build:styles', 'c_m:css')); +gulp.task('build:assets', gulp.series('b_c:assets', 'b_m:assets', 'b_m:fonts')); +gulp.task('compile:assets', gulp.series('c_c:assets', 'build:assets', 'c_m:assets')); \ No newline at end of file diff --git a/Gulp/generalTasks.js b/Gulp/generalTasks.js new file mode 100644 index 00000000..246c157f --- /dev/null +++ b/Gulp/generalTasks.js @@ -0,0 +1,56 @@ +var gulp = require('gulp'); +var inject = require('gulp-inject'); +var del = require('del'); +var vinylPaths = require('vinyl-paths'); +var pkg = require('../package.json'); +var currVersion = pkg.name + "-" + pkg.version; + + +gulp.task('compile:inject', function() { + return gulp.src(config.source + 'index.html') + .pipe(inject(gulp.src(config.compile + '/**/*', {read:false}), {ignorePath: config.compile.replace('.', ''), addRootSlash: false})) + .pipe(gulp.dest(config.compile)); + +}); + +gulp.task('build:inject', function() { + //task injects dep into index.html + return gulp + .src(config.source + 'index.html') + .pipe(inject(gulp.src([config.build + 'vendor/**/angular.js', config.build + 'vendor/**/*.js'], {read:false}), {name: 'bower', ignorePath: config.build.replace('.', ''), addRootSlash: false})) + .pipe(inject(gulp.src([ + config.build + 'src/templates-app.js', + config.build + 'src/app/app.js', + config.build + '**/*.module.js', + config.build + '**/*.config.js', + config.build + '**/*.svc.js', + config.build + '**/*.ctrl.js', + config.build + '**/*.js', + config.build + 'assets/**/*.css', + "!" + config.build + 'src/**/*.spec.js', + '!' + config.build + 'vendor/**/*'], {read:false}), {ignorePath: config.build.replace('.', ''), addRootSlash: false})) + .pipe(gulp.dest(config.build)); +}); + + +gulp.task('masterClean', function() { + return del([ + config.build, + config.compile, + config.temp + ]); +}); + +//Major Project Build Tasks +gulp.task('build', gulp.series( + 'masterClean', + gulp.parallel('build:js_bower', 'build:js', 'build:templateCache', 'build:styles', 'build:assets'), + 'build:inject')); + +//Major Project Compile Tasks +gulp.task('compile', gulp.series( + 'build', + gulp.parallel('compile:js', 'compile:assets', 'compile:css'), + 'compile:inject')); + +gulp.task('default', gulp.series('compile')); \ No newline at end of file diff --git a/Gulp/scriptTasks.js b/Gulp/scriptTasks.js new file mode 100644 index 00000000..b1edffa0 --- /dev/null +++ b/Gulp/scriptTasks.js @@ -0,0 +1,98 @@ +var gulp = require('gulp'); +//var header = require('gulp-header'); +var concat = require('gulp-concat'); +var mainBowerFiles = require('main-bower-files'); +var uglify = require('gulp-uglify'); +var filter = require('gulp-filter'); +var wrap = require('gulp-wrapper'); +var templatecache = require('gulp-angular-templatecache'); +var del = require('del'); +var vinylPaths = require('vinyl-paths'); +var ngAnnotate = require('gulp-ng-annotate'); + + +var pkg = require('../package.json'); +var banner = config.banner; +var currVersion = pkg.name + "-" + pkg.version; +var appJS = config.app_files.js; + + + +gulp.task('b_m:js_bower', function() { + return gulp + .src(mainBowerFiles({filter: ['**/*.js', '!**/bootstrap.js']})) + .pipe(filter('**/*.js')) + .pipe(gulp.dest(config.build + 'vendor')); +}); + +gulp.task('b_c:js_bower', function() { + return del([ + config.build + 'vendor' + ]); +}); + +gulp.task('b_m:js', function() { + return gulp + .src(['./src/**/*.js', '!./src/**/*spec.js']) + .pipe(ngAnnotate()) + .pipe(wrap({ + header: "(function ( window, angular, undefined ) {\n 'use strict';\n", + footer: "})( window, window.angular );\n" + })) + .pipe(gulp.dest(config.build + 'src')); +}); + +gulp.task('b_c:js', function() { + return del([ + config.build + 'src/**/*.js', + '!' + config.build + 'src/**/templates-app.js' + ]); +}); + +gulp.task('b_m:templateCache', function() { + return gulp + .src('./src/app/**/*.tpl.html') + .pipe(templatecache('templates-app.js',{ + standalone: true, + module: 'templates-app', + moduleSystem: 'IIFE'})) + .pipe(gulp.dest(config.build + 'src/')); +}); + +gulp.task('b_c:templateCache', function() { + return del([ + config.build + 'src/templates-app.js' + ]); +}); + +gulp.task('c_m:js', function() { + return gulp + .src([config.build + 'vendor/angular.js', + config.build + 'vendor/**/*.js', + config.build + 'src/templates-app.js', + config.build + 'src/app/app.js', + config.build + 'src/app/**/*.module.js', + config.build + 'src/**/*.js', + '!' + config.build + 'src/**/*.spec.js']) + .pipe(concat('app.js')) + .pipe(uglify({})) + //TODO: gulp-header doesn't work with gulp-4.0 + //.pipe(header(banner, {pkg: pkg})) + .pipe(gulp.dest(config.compile + 'assets')); +}); + +gulp.task('c_c:js', function(){ + return del([ + config.compile + '**/*.js' + ]); +}); + + + +//Master Script Build Tasks +gulp.task('build:js', gulp.series('b_c:js', 'b_m:js')); +gulp.task('build:js_bower', gulp.series('b_c:js_bower', 'b_m:js_bower')); +gulp.task('build:templateCache', gulp.series('b_c:templateCache', 'b_m:templateCache')); + +//Master Script Compile Tasks +gulp.task('compile:js', gulp.series(gulp.parallel('c_c:js', 'build:js_bower', 'build:js', 'build:templateCache'), 'c_m:js')); diff --git a/Gulp/testTasks.js b/Gulp/testTasks.js new file mode 100644 index 00000000..07d32af6 --- /dev/null +++ b/Gulp/testTasks.js @@ -0,0 +1,39 @@ +var gulp = require('gulp'); +var browserSync = require('browser-sync').create(); + +//Enter Server Info Here +var appName = null; //used for externally accessible site... must only include letters ('_', '-' not allowed) +var portNumber = 12000; //used for localhost + + + +if (appName) { + appName = appName.toLowerCase(); +} +if (portNumber) { + if (isNaN(portNumber)) { + portNumber = null; + console.log('portNumber must be numeric'); + } + if (portNumber < 10000 || portNumber > 65536) { + portNumber = null; + } +} + +gulp.task('testServe', function() { + browserSync.init({ + server: { + baseDir: config.build, + index: 'index.html', + routes: '' + }, + port: (portNumber || 8000), + ghostMode: { + clicks: false, + forms: false, + scroll: false + }, + logPrefix: 'OrderCloud 3.0', + tunnel: 'ordercloudapp' + (appName || '') + }) +}); \ No newline at end of file diff --git a/Gulp/watchTasks.js b/Gulp/watchTasks.js new file mode 100644 index 00000000..390bf97b --- /dev/null +++ b/Gulp/watchTasks.js @@ -0,0 +1,63 @@ +gulp = require('gulp'); +mainBowerFiles = require('main-bower-files'); +var karma = require('gulp-karma'); + +var server = 'server.js'; +var vendorJS = mainBowerFiles({filter:'**/*.js'}); +var vendorCSS = mainBowerFiles({filter:'**/*.css'}); + +var gulp = require('gulp'); +browserSync = require('browser-sync').create(); + +browserSync.emitter.on('init', function() { + console.log("Browsersync is running..."); +}); + +gulp.task('dev', function() { + browserSync.init({ + server: { + baseDir: config.build, + index: 'index.html', + routes: '' + }, + port: 8000, + ghostMode: { + clicks: false, + forms: false, + scroll: false + }, + logPrefix: 'OrderCloud 3.0' + }) +}); + +gulp.task('karma:unit', function() { + return gulp.src([config.build + '**/*.spec.js']) + .pipe(karma({ + configFile:'karma.conf.js', + action: 'watch' + })) +}); + + +gulp.task('watch:js', function() { + console.log("running 'watch:js' task"); + gulp.watch(config.app_files.js, gulp.series('build:js', 'build:styles', 'build:inject', function() {browserSync.reload()})); + gulp.watch(vendorJS, gulp.series('build:js_bower', 'build:inject', function() {browserSync.reload()})); +}); + +gulp.task('watch:assets', function() { + console.log("running 'watch:assets' task"); + gulp.watch(config.app_files.assets, gulp.series('build:assets', 'build:inject', function() {browserSync.reload()})); + gulp.watch(config.supportedStyles, gulp.series('build:styles')); +}); + +gulp.task('watch:other', function() { + console.log("running 'watch:other' task"); + gulp.watch(config.app_files.atpl, gulp.series('build:templateCache', 'build:inject', function() {browserSync.reload()})); + gulp.watch(config.source + config.index, gulp.series( 'build:inject', function() {browserSync.reload()})); +}); + + //TODO: need to add new/deleted file watch if it ever comes available in gulp 4.0 + + +gulp.task('watch', gulp.parallel('dev','watch:js', 'watch:assets', 'watch:other', 'karma:unit')); diff --git a/Gulpfile.js b/Gulpfile.js new file mode 100644 index 00000000..fc14aea2 --- /dev/null +++ b/Gulpfile.js @@ -0,0 +1,13 @@ +//Global gulp variables +var gulp = require('gulp'); +config = require('./gulpConfig'); +var path = require('path'); + + +//require gulpfiles in order... + +require('./Gulp/testTasks'); +require('./Gulp/scriptTasks'); +require('./Gulp/assetTasks'); +require('./Gulp/generalTasks'); +require('./Gulp/watchTasks'); \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..3ccb9103 --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) Four51, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 00000000..975d7528 --- /dev/null +++ b/README.md @@ -0,0 +1,276 @@ +# OrderCloud Seed - AngularJS +A seed project for custom Four51 Solutions built on AngularJS +*** + +## Get started + +Node.js is required for the following node package manager (npm) tasks. If you don't have node.js installed, you can download it [here](http://nodejs.org/). + +```sh +$ npm -g install karma bower +$ npm -g install "gulpjs/gulp-cli#4.0" +$ npm install +$ bower install +$ gulp build +``` + +You should now have a few more directories in your project. + +``` +OrderCloud/ + |- build/ + |- node_modules/ + |- vendor/ +``` + +## Configure WebStorm +WebStorm is our chosen development IDE. It provides an interface for the capabilities of the seed projects configuration. + +### Karma Unit Testing +Once you've installed the prerequisites and run your gulp build you can setup and run your Karma tests. + +Create a Run configuration using the Karma plugin with the following settings: + +Node interpreter: C:\Program Files (x86)\nodejs\node.exe + +Karma package: C:\Four51\WebFiles\SPASites\defaults\OrderCloud\node_modules\karma + +Configuration file: C:\Four51\WebFiles\SPASites\defaults\OrderCloud\build\karma-unit.js + + +### Overall Directory Structure + +At a high level, the structure looks roughly like this: + +``` +OrderCloud/ + |- Gulp/ + |- |- assetTasks.js + |- |- generalTasks.js + |- |- scriptTasks.js + |- |- testTasks.js + |- |- watchTasks.js + |- karma/ + |- node_modules/ + |- src/ + | |- app/ + | | |- + | |- assets/ + | | |- + | |- index.html + |- vendor/ + | |- + |- .bowerrc + |- bower.json + |- gulpConfig.js + |- Gulpfile.js + |- karma.conf.js + |- module.prefix + |- module.suffix + |- package.json +``` + +### Detailed Installation + +This section provides a little more detailed understanding of what goes into +getting `OrderCloud` up and running. Though `OrderCloud` is really simple +to use, it might help to have an understanding of the tools involved here, like +Node.js and Gulp and Bower. If you're completely new to highly organized, +modern JavaScript development, take a few short minutes to read [this overview +of the tools](tools.md) before continuing with this section. + +Here it is: + +`OrderCloud` uses [Gulp](http://gulpjs.com/) as its build system, so +[Node.js](http://nodejs.org) is required. Also, we are using Gulp 4.0 prior to +its official release date. You can install Gulp 4.0 on your machine globally by running +the following command: + +```sh +$ npm -g install "gulpjs/gulp-cli#4.0" karma bower +``` + +And then install the remaining build dependencies locally: + +```sh +$ npm install +``` + +This will read the `dependencies` (empty by default) and the `devDependencies` +(which contains our build requirements) from `package.json` and install +everything needed into a folder called `node_modules/`. + +There are many Bower packages used by `OrderCloud`, like AngularJS and the +OrderCloud-Angular-SDK, which are listed in `bower.js`. To install them into the +`vendor/` directory, simply run: + +```sh +$ bower install +``` + +In the future, should you want to add a new Bower package to your app, run the +`install` command and add `--save` to save the dependency in your bower.json file: + +```sh +$ bower install packagename --save +``` + +The `--save` flag tells Bower to add the package at its current version to +our project's `bower.js` file so should another developer download our +application (or we download it from a different computer), we can simply run the +`bower install` command as above and all our dependencies will be installed for +us. Neat! + +Technically, `OrderCloud` is now ready to go. + +To ensure your setup works, build your application and then run it with the following +commands: + +```sh +$ gulp build +$ gulp watch +``` + +The built files are placed in the `build/` directory by default. And you application +should automatically open in the browser window on a localhost! + +`watch` actually starts a few other processes in the background to help you develop your +application. Using `browser-sync` and some built in gulp functions the app is now watching +for changes in your source directory. Should you make any changes to your html or js files +the app should automatically reload your application with the appropriate changes. Also +if you make any changes to your style sheets (less or css) the app will rebuild those changes +and inject them directly into the application, without reloading the entire page! + +When you're ready to push your app into production, just run the `compile` +command: + +```sh +$ gulp compile +``` + +This will concatenate and minify your sources and place them by default into the +`compile/` directory. There will only be three files (excluding assets): `index.html`, +`OrderCloud.js`, and `OrderCloud.css`. All of the vendor dependencies like +AngularJS styles and the OrderCloud-SDK itself have been added to them for super-easy +deploying. If you use any assets (`src/assets/`) then they will be copied to +`compile/` as is. + +Lastly, a complete build is always available by simply running the default +task, which runs `build` and then `compile`: + +```sh +$ gulp +``` + +### The Build System + +The best way to learn about the build system is by familiarizing yourself with +Gulp and then looking through the code, `Gulpfile.js` and the Gulp folder. + But you don't need to do that to be very productive with +`OrderCloud`. What follows in this section is a quick introduction to the +tasks provided and should be plenty to get you started. + +Below is a description of the gulp tasks in the project, sorted by their general purpose +and location within the Gulp directory. + +####Asset Tasks +* `b_m:less` - Compiles all of the app and bower less files into css and moves the compiled file into the temp folder +* `b_m:sass` - Compiles all of the app and bower sass files into css and moves the compiled file into the temp folder +* `b_m:css` - Compiles all of the bower css files (with the exception of the font awesome file as it was already compiled +in `b_m:less`) into one file and autoprefixes the css to run for the last to versions of all the major browsers +* `b_m:appCss` - Compiles all of the app css files into one file and autoprefixes the css to run for the last to versions +of all the major browsers +* `b_m:styles` - Compiles all of the css files in the temp directory into one file, replaces the path to fonts to be correct +for the build directory and renames the file with the version of the app. Places the file in the build folder and injects the +change into browser-sync if it is currently running +* `b_c:styles` - Deletes all of the assets that have been moved over to the build folder and all of the files in the temp folder +* `b_m:assets` - Moves over all asset files (fonts and images) saved in the src/assets directory to the build/assets directory +* `b_m:fonts` - Moves over all fonts saved within the bower dependencies to the build/assets directory +* `b_c:assets` - Deletes all assets files from the build directory +* `c_m:css` - Minifies all css files in the build directory and moves them to the compile folder +* `c_c:css` - Deletes all css files from the compile directory +* `c_m:assets` - Moves over all asset files (fonts and images) from the build folder to the compile folder +* `c_c:assets` - Delete all asset and css files from the compile directory +* `build:styles` - Runs `b_c:styles`, `b_m:less`, `b_m:sass`, `b_m:css`, `b_m:appCss`, `b_m:styles` in order +* `compile:css` - Runs `c_c:css`, `build:styles`, `c_m:css` in order +* `build:assets` - Runs `b_c:assets`, `b_m:assets`, `b_m:fonts` in order +* `compile:assets` - Runs `c_c:assets`, `build:assets`, `c_m:assets` in order + +####General Tasks +* `compile:inject` - Injects the app dependencies into the index.html file for the compiled build +Note: Theere should only be two: `OrderCloud-[Version#].css` and `app.js` +* `build:inject` - Injects the app dependencies into the index.html file for the unminified build +* `masterClean` - Deletes the build, compile, and temp directories. Basically anything built by the gulp +tasks will be removed by this task +* `build` - First runs `master clean`, then runs `build:js_bower`, `build:js`, `build:templateCache`, `build:styles`, `build:assets`, +and lastly runs `build:inject` to create an unminified build of the project +* `compile` - First runs `build`, then runs `compile:js`, `compile:assets`, `compile:css` +and lastly runs `compile:inject` to create a minified build of the project +* `default` - Runs the `compile` task when only `gulp` is typed into the command prompt + +####Script Tasks +* `b_m:js_bower` - Moves the bower dependencies over to the build folder +* `b_c:js_bower` - Deletes bower dependencies form the build folder +* `b_m:js` - Moves over all of the app js files need to run the application (not the ones for unit testing) and +annotates them and wraps each file in an IIFE call. +* `b_c:js` - Deletes all of the javascript files moved over to the build folder except for the templateCache file +* `b_m:templateCache` - Creates an angular templateCache of all the html files (except the index) that +allows for the application to run faster. +* `b_c:templateCache` - Cleans out the compiled template file generated by `b_m:templateCache` +* `c_c:js` - Deletes all js files from the compile directory +* `build:js` - Runs `b_c:js`, and `b_m:js` in order +* `build:js_bower` - Runs `b_c:js_bower`, and `b_m:js_bower` in order +* `build:templateCache` - Runs `b_c:templateCache`, and `b_m:templateCache` in order +* `compile:js` - Runs `c_c:js`, `build:js_bower`, `build:js`, and `build:templateCache` at the same time, then runs +`c_m:js` + +####Test Tasks +* `testServe` - Starts the browser-sync server on localhost:12000 +Note: this task does not build the application first so you must run `gulp build` first for it to work. +This task differs from `dev` in that it opens a tunnel that allows the app to be viewed on other computers +not on the same network. + +####Watch Tasks +* `dev` - Starts the browser-sync server on localhost:8000 +* `karma:unit` - Starts the karma unit tests +* `watch:js` - Starts a process that watches for changes in the javascript files in the src directory +* `watch:assets` - Starts a process that watches for changes in the style sheet files (less and css) +* `watch:other` - Starts a process the watches for changes in the html files +* `watch` - Starts all of the previously mentioned tasks in parallel + +As covered in the previous section, `gulp build` and `gulp watch` will execute a full build +up-front and then run any of the aforementioned `watch` tasks as needed to +ensure the fastest possible build. So whenever you're working on your project, +start with: + +```sh +$ gulp build +``` + +then: + +```sh +$ gulp watch +``` + +And everything will be done automatically! + +### Build vs. Compile + +To make the build even faster, tasks are placed into two categories: build and +compile. The build tasks (like those we've been discussing) are the minimal +tasks required to run your app during development. + +Compile tasks, however, get your app ready for production. The compile tasks +include concatenation, minification, compression, etc. These tasks take a little +bit longer to run and are not at all necessary for development so are not called +automatically during build or watch. + +To initiate a full compile, you simply run the default task: + +```sh +$ gulp +``` + +This will perform a build and then a compile. The compiled site is located in `compile/`. +To test that your full site works as expected, open the `compile/index.html` file in your browser. Voila! diff --git a/bower.json b/bower.json new file mode 100644 index 00000000..81f37640 --- /dev/null +++ b/bower.json @@ -0,0 +1,22 @@ +{ + "name": "orderCloud", + "version": "0.0.3", + "devDependencies": { + "angular-mocks": "~1.4.0" + }, + "dependencies": { + "angular": "~1.4.0", + "angular-animate": "~1.4.0", + "angular-auto-validate": "~1.18.17", + "angular-bootstrap": "~0.14.3", + "angular-messages": "~1.4.0", + "angular-sanitize": "~1.4.0", + "angular-touch": "~1.4.0", + "angular-ui-router": "~0.2.14", + "bootstrap": "~3.3.5", + "font-awesome": "~4.3.0", + "jquery": "~2.1.3", + "ordercloud-angular-sdk": "~0.8.5", + "angular-toastr": "~1.5.0" + } +} diff --git a/changelog.tpl b/changelog.tpl new file mode 100644 index 00000000..c0274e4a --- /dev/null +++ b/changelog.tpl @@ -0,0 +1,23 @@ + +# <%= version%> (<%= today%>) + +<% if (_(changelog.feat).size() > 0) { %> ## Features +<% _(changelog.feat).forEach(function(changes, scope) { %> +- **<%= scope%>:** + <% changes.forEach(function(change) { %> - <%= change.msg%> (<%= helpers.commitLink(change.sha1) %>) + <% }); %> +<% }); %> <% } %> + +<% if (_(changelog.fix).size() > 0) { %> ## Fixes +<% _(changelog.fix).forEach(function(changes, scope) { %> +- **<%= scope%>:** + <% changes.forEach(function(change) { %> - <%= change.msg%> (<%= helpers.commitLink(change.sha1) %>) + <% }); %> +<% }); %> <% } %> + +<% if (_(changelog.breaking).size() > 0) { %> ## Breaking Changes +<% _(changelog.breaking).forEach(function(changes, scope) { %> +- **<%= scope%>:** + <% changes.forEach(function(change) { %> <%= change.msg%> + <% }); %> +<% }); %> <% } %> diff --git a/gulpConfig.js b/gulpConfig.js new file mode 100644 index 00000000..c16522cd --- /dev/null +++ b/gulpConfig.js @@ -0,0 +1,66 @@ +var source = './src/'; +var build = './build/'; +var compile = './compile/'; +var root = './'; +var index = 'index.html'; +var temp = './temp/'; +var gulp_dir = './Gulp'; + +module.exports = { + source: source, + gulp_dir: gulp_dir, + banner: ['/**', + ' * <%= pkg.name %> - <%= pkg.description %>', + ' * @version v<%= pkg.version %>', + ' * @link <%= pkg.homepage %>', + ' * @license <%= pkg.licenses.url %>', + ' */', + ''].join('\n'), + allCSS: [ + source + '**/*.css', + source + '**/*.less', + source + '**/*.sass' + ], + allHTML: [ + source + '**/*.html' + ], + allJS: [ + source + '**/*.js', + './*.js', + './gulp/**/*.js' + ], + build: build, + compile: compile, + fonts: [ + source + 'assets/fonts/**.*' + ], + htmlTemplates: [ + source + '**/*.html', + '!' + source + index + ], + index: index, + npm_pkg: './package.json', + bower_pkg: './bower.json', + src: source, + supportedStyles: [ + source + '**/*.css', + source + '**/*.less', + source + '**/*.sass', + source + '**/*.scss' + ], + temp: temp, + root: root, + app_files: { + js: [ source + '**/*.js', '!' + source + '**/*.spec.js', '!' + source + 'assets/**/*.js' ], + assets: [source + 'assets/**'], + jsunit: [ source + '**/*.spec.js' ], + + atpl: [ source + 'app/**/*.tpl.html' ], + + html: [ source + 'index.html' ], + import_less: [ source + 'app/**/*.less' ] + }, + vendor_files: { + import_less: ['vendor/font-awesome/less/font-awesome.less'] + } +}; \ No newline at end of file diff --git a/karma.conf.js b/karma.conf.js new file mode 100644 index 00000000..8f8fdc95 --- /dev/null +++ b/karma.conf.js @@ -0,0 +1,67 @@ +// Karma configuration +// Generated on Mon Jul 27 2015 17:53:54 GMT-0500 (Central Daylight Time) +module.exports = function(config) { + var mainBowerFiles = require('main-bower-files'); + config.set({ + + // base path that will be used to resolve all patterns (eg. files, exclude) + basePath: '', + + + // frameworks to use + // available frameworks: https://npmjs.org/browse/keyword/karma-adapter + frameworks: ['jasmine'], + + + // list of files / patterns to load in the browser + files: [].concat( + mainBowerFiles({filter: '**/*.js'}), + './src/**/app.js', + './src/**/*.js' + ), + + + // list of files to exclude + exclude: [ + ], + + + // preprocess matching files before serving them to the browser + // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor + preprocessors: { + }, + + + // test results reporter to use + // possible values: 'dots', 'progress' + // available reporters: https://npmjs.org/browse/keyword/karma-reporter + reporters: ['progress'], + + + // web server port + port: 9876, + + + // enable / disable colors in the output (reporters and logs) + colors: true, + + + // level of logging + // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG + logLevel: config.LOG_INFO, + + + // enable / disable watching file and executing tests whenever any file changes + autoWatch: false, + + + // start these browsers + // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher + browsers: ['Firefox'], + + + // Continuous Integration mode + // if true, Karma captures browsers, runs the tests and exits + singleRun: false + }) +} diff --git a/karma/karma-unit.tpl.js b/karma/karma-unit.tpl.js new file mode 100644 index 00000000..efaf4149 --- /dev/null +++ b/karma/karma-unit.tpl.js @@ -0,0 +1,25 @@ +module.exports = function ( karma ) { + karma.set({ + basePath: "../", + files: [ + <% scripts.forEach( function ( file ) { %>"<%= file %>", + <% }); %>, + "src/**/*.js" + ], + exclude: [ + "src/assets/**/*.js" + ], + frameworks: [ 'jasmine' ], + plugins: [ 'karma-jasmine', 'karma-firefox-launcher'], + preprocessors: { }, + reporters: 'dots', + port: 9018, + runnerPort: 9100, + urlRoot: "/", + autoWatch: true, + browsers: [ + 'Firefox' + ] + }); +}; + diff --git a/package.json b/package.json new file mode 100644 index 00000000..51b9a2da --- /dev/null +++ b/package.json @@ -0,0 +1,41 @@ +{ + "author": "Four51, Inc.", + "name": "OrderCloud", + "version": "0.0.3", + "homepage": "https://github.com/Four51/OrderCloud-Seed-AngularJS", + "license": "MIT", + "bugs": "https://github.com/Four51/OrderCloud-Seed-AngularJS/issues", + "repository": { + "type": "git", + "url": "git@github.com:Four51/OrderCloud-Seed-AngularJS.git" + }, + "dependencies": {}, + "devDependencies": { + "browser-sync": "^2.8.0", + "del": "^2.0.2", + "gulp": "git://github.com/gulpjs/gulp.git#4.0", + "gulp-angular-templatecache": "^1.7.0", + "gulp-autoprefixer": "^2.3.1", + "gulp-concat": "^2.6.0", + "gulp-filter": "^2.0.2", + "gulp-flatten": "^0.1.1", + "gulp-header": "^1.7.1", + "gulp-inject": "^1.5.0", + "gulp-karma": "0.0.4", + "gulp-less": "^3.0.3", + "gulp-less-import": "^1.0.0", + "gulp-minify-css": "^1.2.0", + "gulp-ng-annotate": "^1.0.0", + "gulp-plumber": "^1.0.1", + "gulp-replace": "^0.5.4", + "gulp-sass": "^2.0.4", + "gulp-uglify": "^1.2.0", + "gulp-util": "^3.0.6", + "gulp-wrapper": "^1.0.0", + "karma": "^0.13.10", + "karma-firefox-launcher": "^0.1.6", + "karma-jasmine": "^0.1.5", + "main-bower-files": "^2.9.0", + "vinyl-paths": "^2.0.0" + } +} diff --git a/src/README.md b/src/README.md new file mode 100644 index 00000000..78fbf9aa --- /dev/null +++ b/src/README.md @@ -0,0 +1,41 @@ +# The `src` Directory + +## Overview + +The `src/` directory contains all code used in the application along with all +tests of such code. + +``` +src/ + |- app/ + | |- home/ + | |- app.js + | |- app.spec.js + | |- global.less + | |- variables.less + |- assets/ + |- index.html +``` + +- `src/app/` - application-specific code, i.e. code not likely to be reused in + another application. [Read more »](app/README.md) +- `src/assets/` - static files like fonts and images. + [Read more »](assets/README.md) +- `src/index.html` - this is the HTML document of the single-page application. + See below. + +See each directory for a detailed explanation. + +## `index.html` + +The `index.html` file is the HTML document of the single-page application (SPA) +that should contain all markup that applies to everything in the app, such as +the header and footer. It declares with `ngApp` that this is `orderCloud`, +specifies the main `AppCtrl` controller, and contains the `uiView` directive +into which route templates are placed. + +Unlike any other HTML document (e.g. the templates), `index.html` is compiled as +a Grunt template, so variables from `Gruntfile.js` and `package.json` can be +referenced from within it. Changing `name` in `package.json` from +"orderCloud" will rename the resultant CSS and JavaScript placed in `build/`, +so this HTML references them by variable for convenience. diff --git a/src/app/README.md b/src/app/README.md new file mode 100644 index 00000000..613cd9a5 --- /dev/null +++ b/src/app/README.md @@ -0,0 +1,106 @@ +# The `src/app` Directory + +## Overview + +``` +src/ + |- app/ + | |- home/ + | |- about/ + | |- app.js + | |- app.spec.js +``` + +The `src/app` directory contains all code specific to this application. Apart +from `app.js` and its accompanying tests (discussed below), this directory is +filled with subdirectories corresponding to high-level sections of the +application, often corresponding to top-level routes. Each directory can have as +many subdirectories as it needs, and the build system will understand what to +do. For example, a top-level route might be "products", which would be a folder +within the `src/app` directory that conceptually corresponds to the top-level +route `/products`, though this is in no way enforced. Products may then have +subdirectories for "create", "view", "search", etc. The "view" submodule may +then define a route of `/products/:id`, ad infinitum. + +## `app.js` + +This is our main app configuration file. It kickstarts the whole process by +requiring all the modules that we need. + +By default, the OrderCloud AngularJS Seed includes a few useful modules written +by the AngularJS team. Along with one by the Angular-UI team called `ui.router`. +Lastly, we include the `orderCloud.sdk` module for connecting to the API. + +We must load any modules from `src/app` now to ensure the routes are loaded. If +as in our "products" example there are subroutes, we only require the top-level +module, and allow the submodules to require their own submodules. + +As a matter of course, we also require the template module that is generated +during the build. + +```js +angular.module( 'orderCloud', [ + 'templates-app', + 'ngSanitize', + 'ngAnimate', + 'ui.router', + 'ngMessages', + 'ngTouch', + 'orderCloud.sdk' + ]) +``` + +With app modules broken down in this way, all routing is performed by the +submodules we include, as that is where our app's functionality is really +defined. So all we need to do in `app.js` is specify a default route to follow, +which route of course is defined in a submodule. In this case, our `home` module +is where we want to start, which has a defined route for `/home` in +`src/app/home/home.js`. + +```js +.config( function myAppConfig ( $stateProvider, $urlRouterProvider ) { + $urlRouterProvider.otherwise( '/home' ); +}) +``` + +Use the main applications run method to execute any code after services +have been instantiated. + +```js +.run( function run () { +}) +``` + +And then we define our main application controller. This is a good place for logic +not specific to the template or route, such as menu logic or page title wiring. + +```js +.controller( 'AppCtrl', function AppCtrl ( $scope, $location ) { + $scope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams){ + if ( angular.isDefined( toState.data.pageTitle ) ) { + $scope.pageTitle = 'OrderCloud | ' + toState.data.pageTitle; + } + }); +}) +``` + +### Testing + +One of the design philosophies of `OrderCloud-Seed-AngularJS` is that tests should exist +alongside the code they test and that the build system should be smart enough to +know the difference and react accordingly. As such, the unit test for `app.js` +is `app.spec.js`, though it is quite minimal. + +### Global application styles + +By default, we include [Ambient](http://ionlyseespots.github.io/ambient-design/index.html) which is an internally developed design framework that makes use of HTML5 elements & CSS3 attributes to layout the document outline. + +Within the `src/app/` directory we included a `global.less` and `variables.less` file. +These should be utilized for application wide LESS variables and mixins. Each component +within `src/app` will have a corresponding `less/` directory with a similar structure. +The build is smart enough to recognize any new `*.less` file types and roll them in +automatically. + +Also, because any LESS brought in from the `/vendor` (through the build.config) directory +gets rolled into the same intermediate `imports.less` file, you will be able to use +and alter those 3rd party variables/mixins. diff --git a/src/app/account/account.js b/src/app/account/account.js new file mode 100644 index 00000000..d55a6dfb --- /dev/null +++ b/src/app/account/account.js @@ -0,0 +1,161 @@ +angular.module( 'orderCloud' ) + + .config( AccountConfig ) + .controller( 'AccountCtrl', AccountController ) + .factory( 'AccountService', AccountService ) + .controller( 'ConfirmPasswordCtrl', ConfirmPasswordController ) + .controller( 'ChangePasswordCtrl', ChangePasswordController ) + +; + +function AccountConfig( $stateProvider ) { + $stateProvider + .state( 'base.account', { + url: '/account', + templateUrl:'account/templates/account.tpl.html', + controller:'AccountCtrl', + controllerAs: 'account', + resolve: { + Profile: function(Me) { + return Me.Get(); + } + } + }) + .state( 'base.changePassword', { + url: '/account/changepassword', + templateUrl: 'account/templates/changePassword.tpl.html', + controller: 'ChangePasswordCtrl', + controllerAs: 'changePassword', + resolve: { + CurrentUser: function(Me) { + return Me.Get(); + } + } + }) +} + +function AccountService( $q, $uibModal, Credentials, AdminUsers ) { + var service = { + Update: _update, + ChangePassword: _changePassword + }; + + function _update(currentProfile, newProfile) { + var deferred = $q.defer(); + + function updateUser() { + AdminUsers.Update(currentProfile.ID, newProfile) + .then(function(data) { + deferred.resolve(data); + }) + .catch(function(ex) { + deferred.reject(ex); + }) + } + + var modalInstance = $uibModal.open({ + animation: true, + templateUrl: 'account/templates/confirmPassword.modal.tpl.html', + controller: 'ConfirmPasswordCtrl', + controllerAs: 'confirmPassword', + size: 'sm' + }); + + modalInstance.result.then(function(password) { + var checkPasswordCredentials = { + Username: currentProfile.Username, + Password: password + }; + Credentials.Get(checkPasswordCredentials).then( + function() { + updateUser(); + }).catch(function( ex ) { + deferred.reject(ex); + }); + }, function() { + angular.noop(); + }); + + return deferred.promise; + } + + function _changePassword(currentUser) { + var deferred = $q.defer(); + + var checkPasswordCredentials = { + Username: currentUser.Username, + Password: currentUser.CurrentPassword + }; + + function changePassword() { + currentUser.Password = currentUser.NewPassword; + AdminUsers.Update(currentUser.ID, currentUser) + .then(function() { + deferred.resolve(); + }); + } + + Credentials.Get(checkPasswordCredentials).then( + function() { + changePassword(); + }).catch(function( ex ) { + deferred.reject(ex); + }); + + return deferred.promise; + } + + return service; +} + +function AccountController( $exceptionHandler, toastr, Profile, AccountService ) { + var vm = this; + vm.profile = angular.copy(Profile); + var currentProfile = Profile; + + vm.update = function() { + AccountService.Update(currentProfile, vm.profile) + .then(function(data) { + vm.profile = angular.copy(data); + currentProfile = data; + toastr.success('Account changes were saved.', 'Success!'); + }) + .catch(function(ex) { + vm.profile = currentProfile; + $exceptionHandler(ex) + }) + }; + + vm.resetForm = function(form) { + vm.profile = currentProfile; + form.$setPristine(true); + }; +} + +function ConfirmPasswordController( $uibModalInstance ) { + var vm = this; + + vm.submit = function() { + $uibModalInstance.close(vm.password); + }; + + vm.cancel = function() { + $uibModalInstance.dismiss('cancel'); + }; +} + +function ChangePasswordController( $state, $exceptionHandler, toastr, AccountService, CurrentUser ) { + var vm = this; + vm.currentUser = CurrentUser; + + vm.changePassword = function() { + AccountService.ChangePassword(vm.currentUser) + .then(function() { + toastr.success('Password successfully changed', 'Success!'); + $state.go('base.account'); + }) + .catch(function(ex) { + $exceptionHandler(ex) + }); + }; +} diff --git a/src/app/account/templates/account.tpl.html b/src/app/account/templates/account.tpl.html new file mode 100644 index 00000000..7c1137be --- /dev/null +++ b/src/app/account/templates/account.tpl.html @@ -0,0 +1,34 @@ +
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ + + + +
\ No newline at end of file diff --git a/src/app/account/templates/changePassword.tpl.html b/src/app/account/templates/changePassword.tpl.html new file mode 100644 index 00000000..654e3415 --- /dev/null +++ b/src/app/account/templates/changePassword.tpl.html @@ -0,0 +1,19 @@ +
+ +
+
+ + +
+
+ + +
+
+ + +
+ + +
+
\ No newline at end of file diff --git a/src/app/account/templates/confirmPassword.modal.tpl.html b/src/app/account/templates/confirmPassword.modal.tpl.html new file mode 100644 index 00000000..c3791fad --- /dev/null +++ b/src/app/account/templates/confirmPassword.modal.tpl.html @@ -0,0 +1,10 @@ + \ No newline at end of file diff --git a/src/app/app.js b/src/app/app.js new file mode 100644 index 00000000..767eab60 --- /dev/null +++ b/src/app/app.js @@ -0,0 +1,79 @@ +angular.module( 'orderCloud', [ + 'templates-app', + 'ngSanitize', + 'ngAnimate', + 'ngMessages', + 'ngTouch', + 'ui.router', + 'ui.bootstrap', + 'orderCloud.sdk', + 'toastr', + 'ordercloud-infinite-scroll', + 'ordercloud-buyer-select', + 'ordercloud-search', + 'ordercloud-assignment-helpers' +]) + + .run( SetBuyerID ) + .run( Security ) + .config( Routing ) + .config( ErrorHandling ) + .controller( 'AppCtrl', AppCtrl ) + + //Constants needed for the OrderCloud AngularJS SDK + .constant('ocscope', 'FullAccess') + .constant('appname', 'OrderCloud AngularJS Seed') + + //Client ID for a Registered Distributor or Buyer Company + .constant('clientid', '') + .constant('authurl', 'https://auth.ordercloud.io/oauth/token') + .constant('apiurl', 'https://api.ordercloud.io') +; + +function SetBuyerID( BuyerID ) { + BuyerID.Set('451ORDERCLOUD'); +} + +function Security( $rootScope, $state, Auth ) { + $rootScope.$on('$stateChangeStart', function(e, to) { + /*TODO: make the '$stateChangeStart event' accept a function so users can control the redirect from each state's declaration.*/ + if (!to.data.limitAccess) return; + Auth.IsAuthenticated() + .catch(sendToLogin); + + function sendToLogin() { + $state.go('login'); + } + }) +} + +function Routing( $urlRouterProvider, $urlMatcherFactoryProvider ) { + $urlMatcherFactoryProvider.strictMode(false); + $urlRouterProvider.otherwise( '/home' ); + //$locationProvider.html5Mode(true); + //TODO: For HTML5 mode to work we need to always return index.html as the entry point on the serverside +} + +function ErrorHandling( $provide ) { + $provide.decorator('$exceptionHandler', handler); + + function handler( $delegate, $injector ) { + return function( ex, cause ) { + $delegate(ex, cause); + $injector.get('toastr').error(ex.data ? (ex.data.error || (ex.data.Errors ? ex.data.Errors[0].Message : ex.data)) : ex.message, 'Error'); + }; + }; +} + +function AppCtrl( $state, appname, Credentials ) { + var vm = this; + vm.name = appname; + vm.showLeftNav = true; + vm.toggleLeftNav = function() { + vm.showLeftNav = !vm.showLeftNav; + }; + vm.logout = function() { + Credentials.Delete(); + $state.go('login'); + }; +} diff --git a/src/app/app.spec.js b/src/app/app.spec.js new file mode 100644 index 00000000..e69de29b diff --git a/src/app/base/base.js b/src/app/base/base.js new file mode 100644 index 00000000..5b6c3560 --- /dev/null +++ b/src/app/base/base.js @@ -0,0 +1,82 @@ +angular.module( 'orderCloud' ) + + .config( BaseConfig ) + .controller( 'BaseCtrl', BaseController ) + .controller( 'BaseLeftCtrl', BaseLeftController ) + .controller( 'BaseTopCtrl', BaseTopController ) + +; + +function BaseConfig( $stateProvider ) { + $stateProvider + .state( 'base', { + url: '', + abstract: true, + templateUrl:'base/templates/base.tpl.html', + data:{ + limitAccess: true + }, + views: { + '': { + templateUrl: 'base/templates/base.tpl.html', + controller: 'BaseCtrl', + controllerAs: 'base' + }, + 'top@base': { + templateUrl: 'base/templates/base.top.tpl.html', + controller: 'BaseTopCtrl', + controllerAs: 'baseTop' + }, + 'left@base': { + templateUrl: 'base/templates/base.left.tpl.html', + controller: 'BaseLeftCtrl', + controllerAs: 'baseLeft' + } + }, + resolve: { + CurrentUser: function(Me) { + return Me.Get(); + }, + ComponentList: function($state, $q) { + var deferred = $q.defer(); + var nonSpecific = ['Products', 'Specs', 'Price Schedules']; + var components = { + nonSpecific: [], + buyerSpecific: [] + }; + angular.forEach($state.get(), function(state) { + if (!state.data || !state.data.componentName) return; + if (nonSpecific.indexOf(state.data.componentName) > -1) { + components.nonSpecific.push({ + Display: state.data.componentName, + StateRef: state.name + }) + } else { + components.buyerSpecific.push({ + Display: state.data.componentName, + StateRef: state.name + }) + } + }); + deferred.resolve(components); + return deferred.promise; + } + } + }); +} + +function BaseController( CurrentUser ) { + var vm = this; + vm.currentUser = CurrentUser; +} + +function BaseLeftController(ComponentList) { + var vm = this; + vm.catalogItems = ComponentList.nonSpecific; + vm.organizationItems = ComponentList.buyerSpecific; + vm.isCollapsed = true; +} + +function BaseTopController() { + var vm = this; +} \ No newline at end of file diff --git a/src/app/base/base.spec.js b/src/app/base/base.spec.js new file mode 100644 index 00000000..e69de29b diff --git a/src/app/base/less/base.less b/src/app/base/less/base.less new file mode 100644 index 00000000..09850fd4 --- /dev/null +++ b/src/app/base/less/base.less @@ -0,0 +1,110 @@ +#DashboardWrapper { + padding-left: 0; + transition: all 0.5s ease; + &.toggled { + padding-left: @dashboard-leftnav-width; + #DashboardLeftNav { + width: @dashboard-leftnav-width; + } + #DashboardContent { + position: absolute; + margin-right: -@dashboard-leftnav-width; + } + } +} + +#DashboardLeftNav { + z-index: 1000; + position: fixed; + left: @dashboard-leftnav-width; + width: 0; + height: 100%; + margin-left: -@dashboard-leftnav-width; + overflow-y: auto; + overflow-x:hidden; + background-color:@dashboard-leftnav-bg; + border-right:1px solid @dashboard-leftnav-border; + -webkit-transition: all 0.5s ease; + -moz-transition: all 0.5s ease; + -o-transition: all 0.5s ease; + transition: all 0.5s ease; +} + + +#DashboardContent { + width: 100%; + position: absolute; +} + +@media(min-width:768px) { + #DashboardWrapper { + padding-left: @dashboard-leftnav-width; + &.toggled { + padding-left: 0; + #DashboardLeftNav { + width: 0; + } + #DashboardContent { + position: relative; + margin-right: 0; + } + } + } + + #DashboardLeftNav { + width: @dashboard-leftnav-width; + } + + #DashboardContent { + position: relative; + } +} + +#BaseLeft { + padding: @padding-base-horizontal; + width: @dashboard-leftnav-width; + white-space: nowrap; + h4 { + margin-left:-@padding-base-horizontal; + margin-right:-@padding-base-horizontal; + background-color:@navbar-default-bg; + padding:@padding-base-horizontal; + } +} + +.navbar-flex { + #BaseTop { + background-color:@navbar-default-bg; + border-bottom:1px solid @navbar-default-border; + display: flex; + flex-flow: row nowrap; + justify-content: flex-start; + align-items:center; + margin-bottom:@navbar-margin-bottom; + > div { + max-height:@navbar-height; + &.link { + flex:0 1 auto; + > a { + display:block; + line-height:@navbar-height - 20px; + padding:@nav-link-padding; + color:@navbar-default-link-color; + &:hover { + background-color:@navbar-default-link-hover-bg; + color:@navbar-default-link-hover-color; + } + &.active, + &:active, + &:focus { + background-color:@navbar-default-link-active-bg; + color:@navbar-default-link-active-color; + } + } + } + &.logo { + flex:1 0 auto; + } + } + } +} \ No newline at end of file diff --git a/src/app/base/less/variables.less b/src/app/base/less/variables.less new file mode 100644 index 00000000..33c1ea14 --- /dev/null +++ b/src/app/base/less/variables.less @@ -0,0 +1,3 @@ +@dashboard-leftnav-width: 250px; +@dashboard-leftnav-bg: darken(@navbar-default-bg, 5); +@dashboard-leftnav-border:darken(@dashboard-leftnav-bg, 5); \ No newline at end of file diff --git a/src/app/base/templates/base.left.tpl.html b/src/app/base/templates/base.left.tpl.html new file mode 100644 index 00000000..88d9017f --- /dev/null +++ b/src/app/base/templates/base.left.tpl.html @@ -0,0 +1,26 @@ + diff --git a/src/app/base/templates/base.top.tpl.html b/src/app/base/templates/base.top.tpl.html new file mode 100644 index 00000000..f1b3173a --- /dev/null +++ b/src/app/base/templates/base.top.tpl.html @@ -0,0 +1,23 @@ +
+ + + +
\ No newline at end of file diff --git a/src/app/base/templates/base.tpl.html b/src/app/base/templates/base.tpl.html new file mode 100644 index 00000000..52aaeb61 --- /dev/null +++ b/src/app/base/templates/base.tpl.html @@ -0,0 +1,7 @@ +
+
+
+ + +
+
\ No newline at end of file diff --git a/src/app/common/auto-id/auto-id.js b/src/app/common/auto-id/auto-id.js new file mode 100644 index 00000000..6e439741 --- /dev/null +++ b/src/app/common/auto-id/auto-id.js @@ -0,0 +1,52 @@ +angular.module('ordercloud-auto-id', []); + +angular.module('ordercloud-auto-id') + + .directive('ordercloudAutoId', ordercloudAutoIdDirective) + +; + +function ordercloudAutoIdDirective($compile) { + return { + restrict: 'A', + require: 'ngModel', + scope: { + boxtext: '@' + }, + link: function(scope, element, attrs, ngModel) { + scope.boxtext = scope.boxtext || 'Auto-Gen. ID'; + var autoID_element = angular.element(" {{boxtext}} "); + //var initCheckbox = true; + //if (scope.defaultvalue != undefined) { + // initCheckbox = scope.defaultvalue; + //} + //console.log(initCheckbox); + if(element.parent().hasClass('input-group') == false) { + element.wrap("
"); + } + autoID_element.attr('checked', true); + if (autoID_element.prop('checked')) { + element.attr('disabled', true); + } + autoID_element.bind('click', function() { + autoID_element.attr('checked', !autoID_element.prop('checked')); + if (autoID_element.prop('checked')) { + element.attr('disabled', true); + element.attr('required', false); + element.attr('ng-required', false); + element.removeClass('ng-invalid'); + element.removeClass('ng-invalid-required'); + ngModel.$setViewValue(null); + ngModel.$render(); + } + else { + element.attr('disabled', false); + element.attr('required', true); + element.attr('ng-required', true); + } + }); + element.after(autoID_element); + $compile(autoID_element)(scope); + } + } +} diff --git a/src/app/common/buyer-select/buyer-select.less b/src/app/common/buyer-select/buyer-select.less new file mode 100644 index 00000000..1e6b8d1e --- /dev/null +++ b/src/app/common/buyer-select/buyer-select.less @@ -0,0 +1,22 @@ +.btn-select-buyer { + text-align:left; + margin-bottom:10px; + span { + display:block; + white-space: normal; + } +} + +.buyer-list-menu{ + padding:0; + border:0; + background:none; + min-width:400px; + max-width:100%; + .table-fixed-header { + margin-bottom:0; + } + .table-container { + max-height:calc(50vh); + } +} \ No newline at end of file diff --git a/src/app/common/buyer-select/buyer-select.tpl.html b/src/app/common/buyer-select/buyer-select.tpl.html new file mode 100644 index 00000000..e61ec767 --- /dev/null +++ b/src/app/common/buyer-select/buyer-select.tpl.html @@ -0,0 +1,39 @@ +
+
+ + +
+ +
diff --git a/src/app/common/buyer-select/ordercloud-buyer-selected.js b/src/app/common/buyer-select/ordercloud-buyer-selected.js new file mode 100644 index 00000000..080b41a0 --- /dev/null +++ b/src/app/common/buyer-select/ordercloud-buyer-selected.js @@ -0,0 +1,49 @@ +angular.module('ordercloud-buyer-select', []) + + .directive('ordercloudSelectBuyer', SelectBuyerDirective) + .controller('SelectBuyerCtrl', SelectBuyerController) + +; + +function SelectBuyerDirective() { + return { + scope: {}, + restrict: 'E', + templateUrl: 'common/buyer-select/buyer-select.tpl.html', + controller: 'SelectBuyerCtrl', + controllerAs: 'selectBuyer' + } +} + +function SelectBuyerController($state, Buyers, BuyerID) { + var vm = this, + page = 1; + + Buyers.List().then(function(data) { + vm.BuyerList = data; + }); + + Buyers.Get(BuyerID.Get()).then(function(data) { + vm.selectedBuyer = data; + }); + + vm.ChangeBuyer = function(buyer) { + Buyers.Get(buyer.ID).then(function(data) { + vm.selectedBuyer = data; + BuyerID.Set(data.ID); + //console.dir($state.current); + $state.reload($state.current); + }); + }; + + vm.PagingFunction = function() { + page += 1; + if (page <= vm.BuyerList.Meta.TotalPages) { + Buyers.List(null, page, vm.BuyerList.Meta.PageSize) + .then(function(data) { + vm.BuyerList.Meta = data.Meta; + vm.BuyerList.Items = [].concat(vm.BuyerList.Items, data.Items); + }); + } + } +} diff --git a/src/app/common/files/files.js b/src/app/common/files/files.js new file mode 100644 index 00000000..87d9ecea --- /dev/null +++ b/src/app/common/files/files.js @@ -0,0 +1,133 @@ +angular.module( 'orderCloud' ) + + .factory('FileReader', fileReader) + .factory( 'FilesService', FilesService ) + .directive( 'ordercloudFileUpload', ordercloudFileUpload) +; + +function fileReader( $q ) { + var service = { + readAsDataUrl: readAsDataURL + }; + + function onLoad(reader, deferred, scope) { + return function () { + scope.$apply(function () { + deferred.resolve(reader); + }); + }; + } + + function onError(reader, deferred, scope) { + return function () { + scope.$apply(function () { + deferred.reject(reader); + }); + }; + } + + function onProgress(reader, scope) { + return function (event) { + scope.$broadcast("fileProgress", + { + total: event.total, + loaded: event.loaded + }); + }; + } + + function getReader(deferred, scope) { + var reader = new FileReader(); + reader.onload = onLoad(reader, deferred, scope); + reader.onerror = onError(reader, deferred, scope); + reader.onprogress = onProgress(reader, scope); + return reader; + } + + function readAsDataURL(file, scope) { + var deferred = $q.defer(); + + var reader = getReader(deferred, scope); + reader.readAsDataURL(file); + + return deferred.promise; + } + + return service; +} + +function FilesService( $q, $http, apiurl ) { + var service = { + Upload: _upload + }; + + var fileURL = apiurl + '/v1/files'; + + function _upload(file, fileName) { + var deferred = $q.defer(); + + var fd = new FormData(); + fd.append('file', file); + + $http.post(fileURL + '?filename=' + fileName, fd, {transformRequest: angular.identity, headers: {'Content-Type': undefined}}) + .success(function(data){ + deferred.resolve(data); + }) + .error(function(error){ + deferred.reject(error) + }); + + return deferred.promise; + } + + return service; +} + +function ordercloudFileUpload( $parse, FileReader, FilesService ) { + var directive = { + scope: { + model: '=', + keyname: '@', + label: '@' + }, + restrict: 'E', + templateUrl: 'common/files/templates/files.tpl.html', + replace: true, + link: link + }; + + function link(scope, element, attrs) { + var file_input = $parse("file"); + var file_control = angular.element(element.find('input'))[0]; + + function afterSelection(fileName) { + FilesService.Upload(file_control.files[0], fileName) + .then(function(fileData) { + if (!scope.model.xp) scope.model.xp = {}; + scope.model.xp[scope.keyname] = fileData; + scope.model.FileUpdated = true; + }); + } + + function updateModel(event) { + switch (event.target.name) { + case 'upload': + if (event.target.files[0] == null) return; + var fileName = event.target.files[0].name; + scope.$apply(function() { + FileReader.readAsDataUrl(event.target.files[0], scope) + .then(function(f) { + afterSelection(fileName); + }); + file_input.assign(scope, event.target.files[0]); + }); + break; + } + } + + element.bind('change', updateModel); + } + + return directive; +} + diff --git a/src/app/common/files/templates/files.tpl.html b/src/app/common/files/templates/files.tpl.html new file mode 100644 index 00000000..6d1ab633 --- /dev/null +++ b/src/app/common/files/templates/files.tpl.html @@ -0,0 +1,4 @@ +
+ + +
diff --git a/src/app/common/helper-factories/assignment-helpers.js b/src/app/common/helper-factories/assignment-helpers.js new file mode 100644 index 00000000..e8799248 --- /dev/null +++ b/src/app/common/helper-factories/assignment-helpers.js @@ -0,0 +1,59 @@ +angular.module('ordercloud-assignment-helpers', []) + + .factory('Assignments', AssignmentHelpers) + +; + +function AssignmentHelpers($q, Underscore, $state) { + return { + //getAssigned: getAssigned, + //getSelected: getSelected, + //getUnselected: getUnselected, + //getToAssign: getToAssign, + //getToDelete: getToDelete, + saveAssignments: saveAssignments + }; + + function getAssigned(AssignmentsArray, ID_Name) { + //TODO: Save this result in temp variable so I don't do this operation twice every time. + return Underscore.pluck(AssignmentsArray, ID_Name); + } + + function getSelected(ListArray) { + return Underscore.pluck(Underscore.where(ListArray, {selected: true}), 'ID'); + } + + function getUnselected(ListArray) { + return Underscore.pluck(Underscore.filter(ListArray, function(item) { + return !item.selected; + }), 'ID'); + } + + function getToAssign(ListArray, AssignmentsArray, ID_Name) { + return Underscore.difference(getSelected(ListArray), getAssigned(AssignmentsArray, ID_Name)); + } + + function getToDelete(ListArray, AssignmentsArray, ID_Name) { + return Underscore.intersection(getUnselected(ListArray), getAssigned(AssignmentsArray, ID_Name)); + } + + function saveAssignments(ListArray, AssignmentsArray, SaveFunc, DeleteFunc, ID_Name) { + var id_name = ID_Name ? ID_Name : 'UserGroupID'; + var toAssign = getToAssign(ListArray, AssignmentsArray, id_name); + var toDelete = getToDelete(ListArray, AssignmentsArray, id_name); + var queue = []; + var dfd = $q.defer(); + angular.forEach(toAssign, function(ItemID) { + console.log(ItemID); + queue.push(SaveFunc(ItemID)); + }); + angular.forEach(toDelete, function(ItemID) { + queue.push(DeleteFunc(ItemID)); + }); + $q.all(queue).then(function() { + dfd.resolve(); + $state.reload($state.current); + }); + return dfd.promise; + } +} \ No newline at end of file diff --git a/src/app/common/infinite-scroll/infinite-scroll.js b/src/app/common/infinite-scroll/infinite-scroll.js new file mode 100644 index 00000000..8e7e79a5 --- /dev/null +++ b/src/app/common/infinite-scroll/infinite-scroll.js @@ -0,0 +1,128 @@ +angular.module('ordercloud-infinite-scroll', ['ordercloud-search']); +angular.module('ordercloud-infinite-scroll') + + .directive( 'ordercloudInfiniteScroll', InfiniteScrollDirective ) + .controller( 'InfiniteScrollCtrl', InfiniteScrollController ) + .factory( 'PagingFunctions', PagingFunctionsFactory ) +; + +function InfiniteScrollDirective(PagingFunctions) { + return { + restrict: 'A', + scope: { + pagingfunction: '&', + servicename: '@', + listobject: '=', + threshold: '@', + usergrouplist: '=', + selectedid: '@' + }, + controller: 'InfiniteScrollCtrl', + controllerAs: 'InfiniteScroll', + link: function(scope, element, attrs) { + var threshold = scope.threshold || 0; + var ele = element[0]; + element.bind('scroll', function () { + if (ele.scrollTop + ele.offsetHeight + threshold >= ele.scrollHeight) { + if (scope.servicename && scope.listobject && scope.usergrouplist && scope.selectedid) { + PagingFunctions.assignmentsPaging(scope.servicename, scope.listobject, scope.usergrouplist, scope.selectedid); + } + /* Use preset factory */ + else if (scope.servicename && scope.listobject) { + PagingFunctions.componentPaging(scope.servicename, scope.listobject); + } + /* Check if paging function is defined */ + else if (scope.pagingfunction != undefined && typeof(scope.pagingfunction) == 'function') { + scope.pagingfunction(); + } + /* Else display a console error */ + else { + console.log('Error: Infinite scroll directive not fully defined.'); + } + } + }); + } + } +} + +function InfiniteScrollController($scope, PagingFunctions) { + PagingFunctions.reset(); + if ($scope.usergrouplist) { + PagingFunctions.setSelected($scope.listobject, $scope.usergrouplist); + } +} + +function PagingFunctionsFactory($injector, UserGroups, TrackSearch) { + var page = 1, + pageSize = 20, + nonBuyerSpecific = [ + 'Buyers', + 'Products', + 'PriceSchedules', + 'Specs' + ], + service = { + reset: initPaging, + setSelected: setSelected, + componentPaging: componentPaging, + assignmentsPaging: assignmentsPaging + }; + return service; + + function initPaging() { + TrackSearch.SetTerm(null); + } + + function componentPaging(component, componentObject) { + var componentService = $injector.get(component); + //page += 1; + if (componentObject.Meta.Page + 1 <= componentObject.Meta.TotalPages && componentService) { + var args = []; + if (component === 'Orders') { + args = ['incoming', TrackSearch.GetTerm(), null, null, componentObject.Meta.Page + 1, componentObject.Meta.PageSize]; + } + else { + args = [ TrackSearch.GetTerm(), componentObject.Meta.Page + 1, componentObject.Meta.PageSize]; + } + componentService.List.apply(this, args) + .then(function(data) { + componentObject.Meta = data.Meta; + componentObject.Items = [].concat(componentObject.Items, data.Items); + }); + } + } + + function assignmentsPaging(component, componentObject, UserGroupList, selectedID) { + var componentService = $injector.get(component); + page += 1; + if (page <= UserGroupList.Meta.TotalPages && componentService) { + UserGroups.List(null, page, UserGroupList.Meta.PageSize) + .then(function(data) { + UserGroupList.Meta = data.Meta; + UserGroupList.Items = [].concat(UserGroupList.Items, data.Items); + if (page <= componentObject.Meta.TotalPages) { + var args = [selectedID, null, null, page, UserGroupList.Meta.PageSize]; + componentService.ListAssignments.apply(this, args) + .then(function(data) { + componentObject.Meta = data.Meta; + componentObject.Items = [].concat(componentObject.Items, data.Items); + setSelected(componentObject, UserGroupList); + }); + } + else { + setSelected(componentObject, UserGroupList); + } + }); + } + } + + function setSelected(assignedUserGroups, userGroups) { + angular.forEach(userGroups.Items, function(group) { + angular.forEach(assignedUserGroups.Items, function(assignedGroup) { + if (assignedGroup.UserGroupID === group.ID) { + group.selected = true; + } + }); + }); + } +} \ No newline at end of file diff --git a/src/app/common/ordercloud-logo/ordercloud-logo.tpl.html b/src/app/common/ordercloud-logo/ordercloud-logo.tpl.html new file mode 100644 index 00000000..475605f0 --- /dev/null +++ b/src/app/common/ordercloud-logo/ordercloud-logo.tpl.html @@ -0,0 +1,133 @@ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/app/common/ordercloud-logo/ordercloud_logo.js b/src/app/common/ordercloud-logo/ordercloud_logo.js new file mode 100644 index 00000000..c8068847 --- /dev/null +++ b/src/app/common/ordercloud-logo/ordercloud_logo.js @@ -0,0 +1,19 @@ +angular.module('orderCloud') + .directive('ordercloudLogo', ordercloudLogo) +; + +function ordercloudLogo() { + var obj = { + templateUrl: 'common/ordercloud-logo/ordercloud-logo.tpl.html', + replace:true, + link: function(scope, element, attrs) { + scope.OrderCloudLogo = { + 'Icon': attrs.icon ? true : false, + 'maxHeight':attrs.height, + 'fillColor': attrs.color, + 'width': attrs.width + }; + } + }; + return obj; +} \ No newline at end of file diff --git a/src/app/common/search/search.js b/src/app/common/search/search.js new file mode 100644 index 00000000..3dd3728b --- /dev/null +++ b/src/app/common/search/search.js @@ -0,0 +1,63 @@ +angular.module('ordercloud-search', []); +angular.module('ordercloud-search') + + .directive( 'ordercloudSearch', ordercloudSearch) + .controller( 'ordercloudSearchCtrl', ordercloudSearchCtrl) + .factory( 'TrackSearch', trackSearchService ) +; + +function ordercloudSearch () { + return { + scope: { + servicename: "@", + controlleras: "=" + }, + restrict: 'E', + templateUrl: 'common/search/templates/search.tpl.html', + controller: 'ordercloudSearchCtrl', + controllerAs: 'ocSearch', + replace: true + } +} + +function ordercloudSearchCtrl($timeout, $scope, $injector, TrackSearch) { + $scope.searchTerm = null; + $scope.placeholder = "Search " + $scope.servicename + '...'; + var Service = $injector.get($scope.servicename); + var searching; + $scope.$watch('searchTerm', function(n,o) { + if (n == o) { + if (searching) $timeout.cancel(searching); + } else { + if (searching) $timeout.cancel(searching); + searching = $timeout(function() { + n == '' ? n = null : angular.noop(); + TrackSearch.SetTerm(n); + Service.List(n) + .then(function (data){ + $scope.controlleras.list = data; + }); + }, 300); + } + }); +} + +function trackSearchService() { + var service = { + SetTerm: _setTerm, + GetTerm: _getTerm + }; + + var term = null; + + function _setTerm(value) { + term = value; + } + + function _getTerm() { + return term; + } + + return service; +} + diff --git a/src/app/common/search/templates/search.tpl.html b/src/app/common/search/templates/search.tpl.html new file mode 100644 index 00000000..8d471449 --- /dev/null +++ b/src/app/common/search/templates/search.tpl.html @@ -0,0 +1,5 @@ +
+
+ +
+
\ No newline at end of file diff --git a/src/app/global.less b/src/app/global.less new file mode 100644 index 00000000..09670ae0 --- /dev/null +++ b/src/app/global.less @@ -0,0 +1,94 @@ +body { + overflow-x:hidden; +} + +[ui-sref], +[ng-click]{ + cursor: pointer; +} + +//TABLES WITH FIXED HEADERS +.table-fixed-header { + position:relative; + padding-top:@table-header-height; + margin-bottom:@line-height-computed; + overflow:hidden; + .table-header-bg { + position:absolute; + left:0; right:0; top:0; + height:@table-header-height; + background:@table-header-bg; + border:1px solid @table-header-border-color; + border-bottom-width:2px; + .border-top-radius(@table-border-radius); + } + .table-container { + background-color:@table-bg; + overflow-y:auto; + overflow-x:hidden; + max-height:@infinite-scroll-size; + border: 1px solid @table-border-color; + border-top-width:0; + .border-bottom-radius(@table-border-radius); + table { + border-spacing:0; + margin-bottom:0; + } + td { + border:1px solid @table-border-color; + vertical-align:middle; + &:first-child { + border-left:none; + } + &:last-child { + border-left:none; + } + } + th { + height: 0; + line-height: 0; + padding: 0 25px; + color: transparent; + border: none; + white-space: nowrap; + span { + max-height:0; + height:0; + line-height:0; + margin:0; + padding:0; + } + div{ + position: absolute; + background: transparent; + padding:@table-cell-padding; + color:@table-header-color; + top: 0; + margin-left: -25px; + line-height: @line-height-base; + vertical-align: bottom; + border-left:1px solid @table-header-border-color; + } + &:first-child div{ + border: none; + } + } + tbody tr { + &:first-child { + td { + border-top:none; + } + } + &:last-child { + td { + border-bottom:none; + } + } + } + } +} +colgroup { + > col.action-column { + width:70px; + } +} \ No newline at end of file diff --git a/src/app/home/README.md b/src/app/home/README.md new file mode 100644 index 00000000..27414a4b --- /dev/null +++ b/src/app/home/README.md @@ -0,0 +1,75 @@ +# The `src/app/home` Directory + +## Overview + +``` +src/ + |- app/ + | |- home/ + | | |- less/ + | | | |- home.less + | | | |- variables.less + | | |- templates/ + | | | |- home.tpl.html + | | |- home.js + | | |- home.spec.js +``` + +- `home.js` - defines the module. +- `home/less` - module-specific styles; these files are rolled into a + `[root]/temp/imports.less` by the build process and immediately compiled to + `build/assets/OrderCloud-X.X.X.css`. +- `home.spec.js` - module unit tests. +- `home/templates/` - contains all the templates for the module. + +## `home.js` + +This boilerplate is too simple to demonstrate it, but `src/app/home` could have +several sub-folders representing additional modules that would then be listed +as dependencies of this one. For example, a `note` section could have the +submodules `note.create`, `note.delete`, `note.search`, etc. + +Regardless, so long as dependencies are managed correctly, the build process +will automatically take take of the rest. + +The dependencies block is also where component dependencies should be +specified, as shown below. + +```js +angular.module( 'orderCloud.home', [ + 'ui.router', +]) +``` + +Each section or module of the site can also have its own routes. AngularJS will +handle ensuring they are all available at run-time, but splitting it this way +makes each module more self-contained. We use [ui-router](https://github.com/angular-ui/ui-router) to create +a state for our 'home' page. We set the url we'd like to see in the address bar +as well as the controller and template file to load. Specifying "main" as our view +means the controller and template will be loaded into the
element +of the root template (aka index.html). Read more over at the [ui-router wiki](https://github.com/angular-ui/ui-router/wiki). +Finally we add a custom data property, pageTitle, which will be used to set the page's +title (see the app.js controller). + +```js +.config(function config( $stateProvider ) { + $stateProvider.state( 'home', { + url: '/home', + views: { + "main": { + controller: 'HomeCtrl', + templateUrl: 'home/home.tpl.html' + } + }, + data:{ pageTitle: 'Home' } + }); +}) +``` + +And of course we define a controller for our route, though in this case it does +nothing. + +```js +.controller( 'HomeCtrl', function HomeController( $scope ) { +}) +``` diff --git a/src/app/home/home.js b/src/app/home/home.js new file mode 100644 index 00000000..e1a302fa --- /dev/null +++ b/src/app/home/home.js @@ -0,0 +1,20 @@ +angular.module( 'orderCloud' ) + + .config( HomeConfig ) + .controller( 'HomeCtrl', HomeController ) + +; + +function HomeConfig( $stateProvider ) { + $stateProvider + .state( 'base.home', { + url: '/home', + templateUrl:'home/templates/home.tpl.html', + controller:'HomeCtrl', + controllerAs: 'home' + }) +} + +function HomeController( ) { + var vm = this; +} diff --git a/src/app/home/home.spec.js b/src/app/home/home.spec.js new file mode 100644 index 00000000..e69de29b diff --git a/src/app/home/less/home.less b/src/app/home/less/home.less new file mode 100644 index 00000000..e69de29b diff --git a/src/app/home/less/variables.less b/src/app/home/less/variables.less new file mode 100644 index 00000000..e69de29b diff --git a/src/app/home/templates/home.tpl.html b/src/app/home/templates/home.tpl.html new file mode 100644 index 00000000..efa9af0a --- /dev/null +++ b/src/app/home/templates/home.tpl.html @@ -0,0 +1,6 @@ +
+
+

+
+
+ diff --git a/src/app/login/less/login.less b/src/app/login/less/login.less new file mode 100644 index 00000000..4ba4ca61 --- /dev/null +++ b/src/app/login/less/login.less @@ -0,0 +1,4 @@ +#Login { + max-width: @login-form-width; + margin: 0 auto; +} \ No newline at end of file diff --git a/src/app/login/less/variables.less b/src/app/login/less/variables.less new file mode 100644 index 00000000..6ecb95fd --- /dev/null +++ b/src/app/login/less/variables.less @@ -0,0 +1,2 @@ +// Variables specific to the Login Screen +@login-form-width: 300px; \ No newline at end of file diff --git a/src/app/login/login.js b/src/app/login/login.js new file mode 100644 index 00000000..f0d73f6f --- /dev/null +++ b/src/app/login/login.js @@ -0,0 +1,115 @@ +angular.module( 'orderCloud' ) + + .config( LoginConfig ) + .factory( 'LoginService', LoginService ) + .controller( 'LoginCtrl', LoginController ) + +; + +function LoginConfig( $stateProvider ) { + $stateProvider.state( 'login', { + url: '/login/:token', + templateUrl:'login/templates/login.tpl.html', + controller:'LoginCtrl', + controllerAs: 'login', + data:{ + limitAccess: false + } + }); +} + +function LoginService( $q, PasswordResets, clientid ) { + var service = { + SendVerificationCode: _sendVerificationCode, + ResetPassword: _resetPassword + }; + + function _sendVerificationCode(email) { + var deferred = $q.defer(); + + var passwordResetRequest = { + Email: email, + ClientID: clientid, + URL: encodeURIComponent($window.location.href) + '{0}' + }; + + PasswordResets.SendVerificationCode(passwordResetRequest) + .then(function() { + deferred.resolve(); + }) + .catch(function(ex) { + deferred.reject(ex); + }); + + return deferred.promise; + } + + function _resetPassword(resetPasswordCredentials, verificationCode) { + var deferred = $q.defer(); + + var passwordReset = { + ClientID: clientid, + Username: resetPasswordCredentials.ResetUsername, + Password: resetPasswordCredentials.NewPassword + }; + + PasswordResets.ResetPassword(verificationCode, passwordReset). + then(function() { + deferred.resolve(); + }) + .catch(function(ex) { + deferred.reject(ex); + }); + + return deferred.promise; + } + + return service; +} + +function LoginController( $state, $stateParams, $exceptionHandler, LoginService, Credentials ) { + var vm = this; + + vm.token = $stateParams.token; + vm.form = vm.token ? 'reset' : 'login'; + vm.setForm = function(form) { + vm.form = form; + }; + + vm.submit = function( ) { + Credentials.Get( vm.credentials ).then( + function() { + $state.go( 'base.home' ); + }).catch(function(ex) { + $exceptionHandler(ex); + }); + }; + + vm.forgotPassword = function() { + LoginService.SendVerificationCode(vm.credentials.Email) + .then(function() { + vm.setForm('verificationCodeSuccess'); + vm.credentials.Email = null; + }) + .catch(function(ex) { + $exceptionHandler(ex); + }); + }; + + vm.resetPassword = function() { + LoginService.ResetPassword(vm.credentials, vm.token) + .then(function() { + vm.setForm('resetSuccess'); + vm.token = null; + vm.credentials.ResetUsername = null; + vm.credentials.NewPassword = null; + vm.credentials.ConfirmPassword = null; + }) + .catch(function(ex) { + $exceptionHandler(ex); + vm.credentials.ResetUsername = null; + vm.credentials.NewPassword = null; + vm.credentials.ConfirmPassword = null; + }); + }; +} diff --git a/src/app/login/login.spec.js b/src/app/login/login.spec.js new file mode 100644 index 00000000..e69de29b diff --git a/src/app/login/templates/login.tpl.html b/src/app/login/templates/login.tpl.html new file mode 100644 index 00000000..7744d94d --- /dev/null +++ b/src/app/login/templates/login.tpl.html @@ -0,0 +1,49 @@ +
+
+

Login

+
+ + +
+
+ + +
+ + Forgot Password? +
+
+

Forgot Password

+
+ + +
+ + Back to Login +
+
+

Reset Password

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

Forgot Password

+
Forgot Password email has been sent. Please check your email in order to reset your password.
+
+
+

Reset Password

+
Your password has been reset.
+ Back to Login +
+
diff --git a/src/app/variables.less b/src/app/variables.less new file mode 100644 index 00000000..fb958272 --- /dev/null +++ b/src/app/variables.less @@ -0,0 +1,17 @@ +//These are the variables used throughout the application. This is where +//overwrites that are not specific to components should be maintained. +//Interconnected table color styles +@table-bg:white; +@table-bg-accent:darken(@table-bg, 5); +@table-bg-hover:darken(@table-bg-accent, 5); + +@table-border-color:darken(@table-bg, 15); +@table-border-radius:@border-radius-base; + +@table-header-bg:white; +@table-header-border-color:darken(@table-header-bg, 15); +@table-header-color:@text-color; +@table-header-height:@table-cell-padding*2 + @line-height-computed; + +//Infinite Scroll +@infinite-scroll-size: 600px; \ No newline at end of file diff --git a/src/assets/README.md b/src/assets/README.md new file mode 100644 index 00000000..be4adb04 --- /dev/null +++ b/src/assets/README.md @@ -0,0 +1,5 @@ +# The `src/assets` Directory + +There's really not much to say here. Every file in this directory is recursively transferred to `dist/assets/`. + +These can be images, PDFs, etc... any non-code resource essentially. diff --git a/src/index.html b/src/index.html new file mode 100644 index 00000000..f1b9a4fa --- /dev/null +++ b/src/index.html @@ -0,0 +1,19 @@ + + + + + + OrderCloud + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools.md b/tools.md new file mode 100644 index 00000000..ac5f6758 --- /dev/null +++ b/tools.md @@ -0,0 +1,112 @@ +# The Tools Used in `OrderCloud` + +## Introduction + +`OrderCloud` is standards-based, so it uses all the usual tools to manage +and develop client-side code. If you've developed modern, highly-organized +JavaScript projects before, you are probably already familiar with at least most +of these tools. What follows is a simple description of the tools of which this +project makes use and how they fit in to the `OrderCloud` picture. + +## Git + +[Git](http://git-scm.com/) is a distributed version control system. +`OrderCloud` uses git to manage its codebase. While in theory you don't have +to use Git once you download `OrderCloud`, this project makes the assumption +that you do. If you're on GitHub, I assume you already have a basic +understanding of Git, which is all you need to make effective use of this +project. You just need to be able to commit and push and junk - nothing funky. +If you're not familiar with it, check out the documentation linked to above. +GitHub also has a great [help section](https://help.github.com/). + +## Node.js & NPM + +[Node.js](http://nodejs.org) is a platform based on Chrome's JavaScript runtime, +called [V8](http://code.google.com/p/v8/). It allows you to develop all kinds of +software using the JavaScript you already know and love. + +A great feature of Node.js is its wide variety of existing libraries and tools. +As the developer community is absolutely massive and incredibly active, Node.js +has a basic package manager called NPM that you can use to install Node.js-based +software and libraries from the command line. + +While `OrderCloud` makes heavy use of Node.js behind the scenes, you as the +application developer don't need to really think about it much. Most of the +interaction with Node.js will occur through Gulp (see next section), so you +really only need to know how get the initial setup working. + +`package.json` is an NPM package description file written in JSON. It contains +basic metadata about your application, like its name, version, and dependencies. +By default, several packages are required for the build process to work; so when +you first start with `OrderCloud` you have to tell NPM to install the +packages; this is covered in detail in the [main README](README.md). Some of +the required packages are Gulp build tasks, while others are +command-line tools either we (or the build system) need, like Karma, Gulp, and +Bower. + +Don't worry about knowing Node.js in order to use `OrderCloud`; Gulp is +where the magic happens. + +## Gulp.js + +[Gulp](http://gulpjs.com/) is a JavaScript task runner that runs on top of +Node.js. Most importantly, Gulp brings us automation. There are lots of steps +that go into taking our manageable codebase and making it into a +production-ready website; we must gather, lint, test, annotate, and copy files +about. Instead of doing all of that manually, we write (and use others') Gulp +tasks to do things for us. + +## Bower + +[Bower](bower.io) is a package manager for the web. It's similar in many +respects to NPM, though it is significantly simpler and only contains code for +web projects, like Twitter Bootstrap and its AngularJS counterpart Angular +Bootstrap. Bower allows us to say that our app depends in some way on these +other libraries so that we can manage all of them in one simple place. + +`OrderCloud` comes with a `bower.json` file that looks something like this: + +```js +{ + "name": "OrderCloud", + "version": ".0.0.1-SNAPSHOT", + "devDependencies": { + "angular": "~1.0.7", + "angular-mocks": "~1.0.7", + "bootstrap": "~2.3.2", + "angular-bootstrap": "~0.3.0", + "angular-ui-router": "~0.0.1", + "angular-ui-utils": "~0.0.3" + }, + "dependencies": {} +} +``` + +This file is fairly self-explanatory; it gives the package name and version +(duplicated from `package.json`, but this is unavoidable) as well as a list of +dependencies our application needs in order to work. If we simply call + +```sh +$ bower install +``` + +it will read these three dependencies and install them into the `vendor/` folder +(along with any dependencies they have) so that we can use them in our app. If +we want to add a new package like AngularUI's +[ngGrid](http://angular-ui.github.io/ng-grid/), then we can tell Bower to +install that from the web, place it into the `vendor/` folder for us to use, and +then add it as a dependency to `bower.json`: + +```js +$ bower install angular-grid --save-dev +``` + +Bower can also update all of our packages for us at a later date, though that +and its many other awesome features are beyond the scope of this simple +overview. + +One last thing to note is that packages installed with Bower are not +standardized, so we cannot automatically add them to the build process; anything +installed with Bower (or placed in the `vendor/` directory manually) *must* be +added to your `build.config.js` file manually; look for the Bower libs included +in `OrderCloud` by default in there to see what I mean. From 0599ecdbd6ec9b98a58597bfe1be78fbc9b1ad14 Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 11 Dec 2015 10:29:27 -0600 Subject: [PATCH 035/367] DEVCTR-16156 Base now resolves the current user after it checks for authentication Any state under base requires the user to be authenticated Scrollbar no longer overlaps the left nav --- src/app/account/account.js | 20 +--- src/app/app.js | 14 --- src/app/base/base.js | 27 +++++- src/app/base/less/base.less | 179 ++++++++++++++++++------------------ 4 files changed, 119 insertions(+), 121 deletions(-) diff --git a/src/app/account/account.js b/src/app/account/account.js index d55a6dfb..546b9ff5 100644 --- a/src/app/account/account.js +++ b/src/app/account/account.js @@ -14,23 +14,13 @@ function AccountConfig( $stateProvider ) { url: '/account', templateUrl:'account/templates/account.tpl.html', controller:'AccountCtrl', - controllerAs: 'account', - resolve: { - Profile: function(Me) { - return Me.Get(); - } - } + controllerAs: 'account' }) .state( 'base.changePassword', { url: '/account/changepassword', templateUrl: 'account/templates/changePassword.tpl.html', controller: 'ChangePasswordCtrl', - controllerAs: 'changePassword', - resolve: { - CurrentUser: function(Me) { - return Me.Get(); - } - } + controllerAs: 'changePassword' }) } @@ -108,10 +98,10 @@ function AccountService( $q, $uibModal, Credentials, AdminUsers ) { return service; } -function AccountController( $exceptionHandler, toastr, Profile, AccountService ) { +function AccountController( $exceptionHandler, toastr, CurrentUser, AccountService ) { var vm = this; - vm.profile = angular.copy(Profile); - var currentProfile = Profile; + vm.profile = angular.copy(CurrentUser); + var currentProfile = CurrentUser; vm.update = function() { AccountService.Update(currentProfile, vm.profile) diff --git a/src/app/app.js b/src/app/app.js index 767eab60..73bccf37 100644 --- a/src/app/app.js +++ b/src/app/app.js @@ -15,7 +15,6 @@ angular.module( 'orderCloud', [ ]) .run( SetBuyerID ) - .run( Security ) .config( Routing ) .config( ErrorHandling ) .controller( 'AppCtrl', AppCtrl ) @@ -34,19 +33,6 @@ function SetBuyerID( BuyerID ) { BuyerID.Set('451ORDERCLOUD'); } -function Security( $rootScope, $state, Auth ) { - $rootScope.$on('$stateChangeStart', function(e, to) { - /*TODO: make the '$stateChangeStart event' accept a function so users can control the redirect from each state's declaration.*/ - if (!to.data.limitAccess) return; - Auth.IsAuthenticated() - .catch(sendToLogin); - - function sendToLogin() { - $state.go('login'); - } - }) -} - function Routing( $urlRouterProvider, $urlMatcherFactoryProvider ) { $urlMatcherFactoryProvider.strictMode(false); $urlRouterProvider.otherwise( '/home' ); diff --git a/src/app/base/base.js b/src/app/base/base.js index 5b6c3560..14626d58 100644 --- a/src/app/base/base.js +++ b/src/app/base/base.js @@ -13,9 +13,6 @@ function BaseConfig( $stateProvider ) { url: '', abstract: true, templateUrl:'base/templates/base.tpl.html', - data:{ - limitAccess: true - }, views: { '': { templateUrl: 'base/templates/base.tpl.html', @@ -34,8 +31,28 @@ function BaseConfig( $stateProvider ) { } }, resolve: { - CurrentUser: function(Me) { - return Me.Get(); + CurrentUser: function($q, $state, Auth, BuyerID, Me) { + var dfd = $q.defer(); + Auth.IsAuthenticated() + .then(function() { + Me.Get() + .then(function(data) { + dfd.resolve(data); + }) + .catch(function(){ + Auth.RemoveToken(); + BuyerID.Set(null); + $state.go('login'); + dfd.resolve(); + }) + }) + .catch(function() { + BuyerID.Set(null); + $state.go('login'); + dfd.resolve(); + }) + ; + return dfd.promise; }, ComponentList: function($state, $q) { var deferred = $q.defer(); diff --git a/src/app/base/less/base.less b/src/app/base/less/base.less index 09850fd4..59b240b9 100644 --- a/src/app/base/less/base.less +++ b/src/app/base/less/base.less @@ -1,110 +1,115 @@ +/*! + * Start Bootstrap - Simple Sidebar HTML Template (http://startbootstrap.com) + * Code licensed under the Apache License v2.0. + * For details, see http://www.apache.org/licenses/LICENSE-2.0. + */ #DashboardWrapper { - padding-left: 0; - transition: all 0.5s ease; - &.toggled { - padding-left: @dashboard-leftnav-width; - #DashboardLeftNav { - width: @dashboard-leftnav-width; - } - #DashboardContent { - position: absolute; - margin-right: -@dashboard-leftnav-width; + padding-left: 0; + transition: all 0.5s ease; + &.toggled { + padding-left: @dashboard-leftnav-width; + #DashboardLeftNav { + width: @dashboard-leftnav-width; + } + #DashboardContent { + position: absolute; + margin-right: -@dashboard-leftnav-width; + } } - } } #DashboardLeftNav { - z-index: 1000; - position: fixed; - left: @dashboard-leftnav-width; - width: 0; - height: 100%; - margin-left: -@dashboard-leftnav-width; - overflow-y: auto; - overflow-x:hidden; - background-color:@dashboard-leftnav-bg; - border-right:1px solid @dashboard-leftnav-border; - -webkit-transition: all 0.5s ease; - -moz-transition: all 0.5s ease; - -o-transition: all 0.5s ease; - transition: all 0.5s ease; + z-index: 1000; + position: fixed; + left: @dashboard-leftnav-width; + width: 0; + height: 100%; + margin-left: -@dashboard-leftnav-width; + overflow:hidden; + background-color:@dashboard-leftnav-bg; + border-right:1px solid @dashboard-leftnav-border; + -webkit-transition: all 0.5s ease; + -moz-transition: all 0.5s ease; + -o-transition: all 0.5s ease; + transition: all 0.5s ease; } - #DashboardContent { - width: 100%; - position: absolute; + width: 100%; + position: absolute; } @media(min-width:768px) { - #DashboardWrapper { - padding-left: @dashboard-leftnav-width; - &.toggled { - padding-left: 0; - #DashboardLeftNav { - width: 0; - } - #DashboardContent { - position: relative; - margin-right: 0; - } + #DashboardWrapper { + padding-left: @dashboard-leftnav-width; + &.toggled { + padding-left: 0; + #DashboardLeftNav { + width: 0; + } + #DashboardContent { + position: relative; + margin-right: 0; + } + } } - } - #DashboardLeftNav { - width: @dashboard-leftnav-width; - } + #DashboardLeftNav { + width: @dashboard-leftnav-width; + } - #DashboardContent { - position: relative; - } + #DashboardContent { + position: relative; + } } #BaseLeft { - padding: @padding-base-horizontal; - width: @dashboard-leftnav-width; - white-space: nowrap; - h4 { - margin-left:-@padding-base-horizontal; - margin-right:-@padding-base-horizontal; - background-color:@navbar-default-bg; - padding:@padding-base-horizontal; - } + height:100%; + overflow-y:auto; + padding: @padding-base-horizontal; + width: @dashboard-leftnav-width; + white-space: nowrap; + h4 { + margin-left:-@padding-base-horizontal; + margin-right:-@padding-base-horizontal; + background-color:@navbar-default-bg; + padding:@padding-base-horizontal; + } } .navbar-flex { - #BaseTop { - background-color:@navbar-default-bg; - border-bottom:1px solid @navbar-default-border; - display: flex; - flex-flow: row nowrap; - justify-content: flex-start; - align-items:center; - margin-bottom:@navbar-margin-bottom; - > div { - max-height:@navbar-height; - &.link { - flex:0 1 auto; - > a { - display:block; - line-height:@navbar-height - 20px; - padding:@nav-link-padding; - color:@navbar-default-link-color; - &:hover { - background-color:@navbar-default-link-hover-bg; - color:@navbar-default-link-hover-color; - } - &.active, - &:active, - &:focus { - background-color:@navbar-default-link-active-bg; - color:@navbar-default-link-active-color; - } + #BaseTop { + background-color:@navbar-default-bg; + border-bottom:1px solid @navbar-default-border; + display: flex; + flex-flow: row nowrap; + justify-content: flex-start; + align-items:center; + margin-bottom:@navbar-margin-bottom; + > div { + max-height:@navbar-height; + &.link { + flex:0 1 auto; + > a { + display:block; + line-height:@navbar-height - 20px; + padding:@nav-link-padding; + color:@navbar-default-link-color; + &:hover { + background-color:@navbar-default-link-hover-bg; + color:@navbar-default-link-hover-color; + } + &.active, + &:active, + &:focus { + background-color:@navbar-default-link-active-bg; + color:@navbar-default-link-active-color; + } + } + } + &.logo { + flex:1 0 auto; + } } - } - &.logo { - flex:1 0 auto; - } } - } } \ No newline at end of file From b13b17ac0acd0576f0785df8e04309489560ea5b Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Wed, 20 Jan 2016 20:02:15 -0600 Subject: [PATCH 036/367] Updates from OrderCloud-Components --- .idea/vcs.xml | 6 + Gulp/assetTasks.js | 13 +- Gulp/generalTasks.js | 2 +- Gulp/scriptTasks.js | 19 +- Gulp/testTasks.js | 20 +- Gulp/watchTasks.js | 21 +- Gulpfile.js | 4 +- bower.json | 8 +- gulpConfig.js | 7 +- karma.conf.js | 15 +- package.json | 21 +- protractor.config.js | 36 +++ server.js | 25 +++ src/app/account/account.js | 10 +- src/app/account/templates/account.tpl.html | 66 +++--- .../account/templates/changePassword.tpl.html | 2 +- src/app/account/tests/account.spec.js | 123 +++++++++++ .../tests/account.test.js} | 0 src/app/app.js | 146 +++++++----- src/app/base/base.js | 154 ++++++------- src/app/base/less/base.less | 182 +++++++-------- src/app/base/less/variables.less | 2 +- src/app/base/templates/base.left.tpl.html | 2 +- src/app/base/templates/base.top.tpl.html | 7 +- src/app/base/templates/base.tpl.html | 12 +- src/app/base/tests/base.spec.js | 89 ++++++++ src/app/base/tests/base.test.js | 23 ++ src/app/common/address/address.js | 52 +++++ .../address/templates/address.form.tpl.html | 54 +++++ src/app/common/auto-id/auto-id.js | 2 +- src/app/common/auto-id/tests/auto-id.spec.js | 35 +++ .../auto-id/tests/auto-id.test.js} | 0 .../buyer-select/{ => less}/buyer-select.less | 0 .../buyer-select/ordercloud-buyer-selected.js | 13 +- .../{ => templates}/buyer-select.tpl.html | 12 +- .../buyer-select/tests/buyer-select.spec.js | 106 +++++++++ .../buyer-select/tests/buyer_select.test.js} | 0 src/app/common/current-order/current-order.js | 92 ++++++++ src/app/common/files/files.js | 67 +++++- src/app/common/files/templates/files.tpl.html | 6 +- src/app/common/files/tests/files.spec.js | 33 +++ src/app/common/files/tests/files.test.js | 5 + .../helper-factories/assignment-helpers.js | 12 +- .../common/helper-factories/paging-helpers.js | 50 +++++ .../tests/assignment-helpers.spec.js | 66 ++++++ .../tests/assignment-helpers.test.js | 0 .../tests/paging-helpers.spec.js | 79 +++++++ .../tests/paging-helpers.test.js | 0 .../impersonation/ordercloud-impersonation.js | 98 +++++++++ .../templates/buyer-user-modal.tpl.html | 37 ++++ .../common/infinite-scroll/infinite-scroll.js | 117 ++-------- .../tests/infinite-scroll.spec.js | 33 +++ .../tests/infinite-scroll.test.js | 0 src/app/common/lineitems/less/lineitems.less | 3 + src/app/common/lineitems/lineitems.js | 118 ++++++++++ .../lineitems/templates/shipping.tpl.html | 11 + .../common/ordercloud-logo/ordercloud_logo.js | 5 +- .../{ => templates}/ordercloud-logo.tpl.html | 0 .../tests/ordercloud-logo.test.js | 0 .../tests/ordercloud_logo.spec.js | 28 +++ src/app/common/search/search.js | 41 +++- src/app/common/search/tests/search.spec.js | 58 +++++ src/app/common/search/tests/search.test.js | 0 src/app/common/token-refresh/token-refresh.js | 44 ++++ src/app/home/home.js | 7 +- src/app/home/templates/home.tpl.html | 4 +- src/app/login/less/login.less | 2 +- src/app/login/login.js | 208 +++++++++--------- src/app/login/templates/login.dev.tpl.html | 14 ++ src/app/login/templates/login.tpl.html | 104 +++++---- src/app/login/tests/login.spec.js | 159 +++++++++++++ src/app/login/tests/login.test.js | 22 ++ src/app/login/tests/logout.test.js | 1 + 73 files changed, 2197 insertions(+), 616 deletions(-) create mode 100644 .idea/vcs.xml create mode 100644 protractor.config.js create mode 100644 server.js create mode 100644 src/app/account/tests/account.spec.js rename src/app/{base/base.spec.js => account/tests/account.test.js} (100%) create mode 100644 src/app/base/tests/base.spec.js create mode 100644 src/app/base/tests/base.test.js create mode 100644 src/app/common/address/address.js create mode 100644 src/app/common/address/templates/address.form.tpl.html create mode 100644 src/app/common/auto-id/tests/auto-id.spec.js rename src/app/{home/home.spec.js => common/auto-id/tests/auto-id.test.js} (100%) rename src/app/common/buyer-select/{ => less}/buyer-select.less (100%) rename src/app/common/buyer-select/{ => templates}/buyer-select.tpl.html (77%) create mode 100644 src/app/common/buyer-select/tests/buyer-select.spec.js rename src/app/{login/login.spec.js => common/buyer-select/tests/buyer_select.test.js} (100%) create mode 100644 src/app/common/current-order/current-order.js create mode 100644 src/app/common/files/tests/files.spec.js create mode 100644 src/app/common/files/tests/files.test.js create mode 100644 src/app/common/helper-factories/paging-helpers.js create mode 100644 src/app/common/helper-factories/tests/assignment-helpers.spec.js create mode 100644 src/app/common/helper-factories/tests/assignment-helpers.test.js create mode 100644 src/app/common/helper-factories/tests/paging-helpers.spec.js create mode 100644 src/app/common/helper-factories/tests/paging-helpers.test.js create mode 100644 src/app/common/impersonation/ordercloud-impersonation.js create mode 100644 src/app/common/impersonation/templates/buyer-user-modal.tpl.html create mode 100644 src/app/common/infinite-scroll/tests/infinite-scroll.spec.js create mode 100644 src/app/common/infinite-scroll/tests/infinite-scroll.test.js create mode 100644 src/app/common/lineitems/less/lineitems.less create mode 100644 src/app/common/lineitems/lineitems.js create mode 100644 src/app/common/lineitems/templates/shipping.tpl.html rename src/app/common/ordercloud-logo/{ => templates}/ordercloud-logo.tpl.html (100%) create mode 100644 src/app/common/ordercloud-logo/tests/ordercloud-logo.test.js create mode 100644 src/app/common/ordercloud-logo/tests/ordercloud_logo.spec.js create mode 100644 src/app/common/search/tests/search.spec.js create mode 100644 src/app/common/search/tests/search.test.js create mode 100644 src/app/common/token-refresh/token-refresh.js create mode 100644 src/app/login/templates/login.dev.tpl.html create mode 100644 src/app/login/tests/login.spec.js create mode 100644 src/app/login/tests/login.test.js create mode 100644 src/app/login/tests/logout.test.js diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000..94a25f7f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Gulp/assetTasks.js b/Gulp/assetTasks.js index 524087ea..f0f53282 100644 --- a/Gulp/assetTasks.js +++ b/Gulp/assetTasks.js @@ -8,7 +8,6 @@ var minify = require('gulp-minify-css'); var mainBowerFiles = require('main-bower-files'); var concat = require('gulp-concat'); var del = require('del'); -var vinylPaths = require('vinyl-paths'); var plumber = require('gulp-plumber'); var lessImport = require('gulp-less-import'); var replace = require('gulp-replace'); @@ -110,9 +109,7 @@ gulp.task('c_m:css', function() { }); gulp.task('c_c:css', function() { - return gulp - .src(config.compile + '**/*.css', {read:false}) - .pipe(vinylPaths(del)); + return del([config.compile + '**/*.css']); }); gulp.task('c_m:assets', function() { @@ -126,13 +123,11 @@ gulp.task('c_m:assets', function() { }); gulp.task('c_c:assets', function() { - return gulp - .src([config.compile + 'assets/**/*', '!' + config.compile + 'assets/**/*.css'], {read:false}) - .pipe(vinylPaths(del)); + return del([config.compile + 'assets/**/*', '!' + config.compile + 'assets/**/*.css']); }); //Master Asset Tasks gulp.task('build:styles', gulp.series('b_c:styles', 'b_m:less', 'b_m:sass', 'b_m:css', 'b_m:appCss', 'b_m:styles')); -gulp.task('compile:css', gulp.series('c_c:css', 'build:styles', 'c_m:css')); +gulp.task('compile:css', gulp.series('c_c:css', 'c_m:css')); gulp.task('build:assets', gulp.series('b_c:assets', 'b_m:assets', 'b_m:fonts')); -gulp.task('compile:assets', gulp.series('c_c:assets', 'build:assets', 'c_m:assets')); \ No newline at end of file +gulp.task('compile:assets', gulp.series('c_c:assets', 'c_m:assets')); \ No newline at end of file diff --git a/Gulp/generalTasks.js b/Gulp/generalTasks.js index 246c157f..d152fd7e 100644 --- a/Gulp/generalTasks.js +++ b/Gulp/generalTasks.js @@ -1,7 +1,6 @@ var gulp = require('gulp'); var inject = require('gulp-inject'); var del = require('del'); -var vinylPaths = require('vinyl-paths'); var pkg = require('../package.json'); var currVersion = pkg.name + "-" + pkg.version; @@ -28,6 +27,7 @@ gulp.task('build:inject', function() { config.build + '**/*.js', config.build + 'assets/**/*.css', "!" + config.build + 'src/**/*.spec.js', + "!" + config.build + 'src/**/*.test.js', '!' + config.build + 'vendor/**/*'], {read:false}), {ignorePath: config.build.replace('.', ''), addRootSlash: false})) .pipe(gulp.dest(config.build)); }); diff --git a/Gulp/scriptTasks.js b/Gulp/scriptTasks.js index b1edffa0..6e92a2ab 100644 --- a/Gulp/scriptTasks.js +++ b/Gulp/scriptTasks.js @@ -1,4 +1,5 @@ var gulp = require('gulp'); +var ngConstant = require('gulp-ng-constant'); //var header = require('gulp-header'); var concat = require('gulp-concat'); var mainBowerFiles = require('main-bower-files'); @@ -7,7 +8,6 @@ var filter = require('gulp-filter'); var wrap = require('gulp-wrapper'); var templatecache = require('gulp-angular-templatecache'); var del = require('del'); -var vinylPaths = require('vinyl-paths'); var ngAnnotate = require('gulp-ng-annotate'); @@ -33,7 +33,7 @@ gulp.task('b_c:js_bower', function() { gulp.task('b_m:js', function() { return gulp - .src(['./src/**/*.js', '!./src/**/*spec.js']) + .src(['./src/**/*.js', '!**/*spec.js', '!**/*.test.js']) .pipe(ngAnnotate()) .pipe(wrap({ header: "(function ( window, angular, undefined ) {\n 'use strict';\n", @@ -67,17 +67,16 @@ gulp.task('b_c:templateCache', function() { gulp.task('c_m:js', function() { return gulp - .src([config.build + 'vendor/angular.js', + .src([ + config.build + 'vendor/angular.js', config.build + 'vendor/**/*.js', config.build + 'src/templates-app.js', config.build + 'src/app/app.js', - config.build + 'src/app/**/*.module.js', - config.build + 'src/**/*.js', - '!' + config.build + 'src/**/*.spec.js']) + config.build + 'src/app/app.config.js', + config.build + 'src/**/*.js' + ]) .pipe(concat('app.js')) - .pipe(uglify({})) - //TODO: gulp-header doesn't work with gulp-4.0 - //.pipe(header(banner, {pkg: pkg})) + .pipe(uglify({mangle: false})) .pipe(gulp.dest(config.compile + 'assets')); }); @@ -95,4 +94,4 @@ gulp.task('build:js_bower', gulp.series('b_c:js_bower', 'b_m:js_bower')); gulp.task('build:templateCache', gulp.series('b_c:templateCache', 'b_m:templateCache')); //Master Script Compile Tasks -gulp.task('compile:js', gulp.series(gulp.parallel('c_c:js', 'build:js_bower', 'build:js', 'build:templateCache'), 'c_m:js')); +gulp.task('compile:js', gulp.series('c_c:js', 'c_m:js')); diff --git a/Gulp/testTasks.js b/Gulp/testTasks.js index 07d32af6..c6f3130c 100644 --- a/Gulp/testTasks.js +++ b/Gulp/testTasks.js @@ -4,12 +4,12 @@ var browserSync = require('browser-sync').create(); //Enter Server Info Here var appName = null; //used for externally accessible site... must only include letters ('_', '-' not allowed) var portNumber = 12000; //used for localhost - - +var protractor = require('gulp-angular-protractor'); if (appName) { appName = appName.toLowerCase(); } + if (portNumber) { if (isNaN(portNumber)) { portNumber = null; @@ -36,4 +36,18 @@ gulp.task('testServe', function() { logPrefix: 'OrderCloud 3.0', tunnel: 'ordercloudapp' + (appName || '') }) -}); \ No newline at end of file +}); + +gulp.task('protractor', function () { + return gulp + .src(config.src + '**/login.test.js', config.src + '**/*.test.js') + .pipe(protractor({ + configFile: './protractor.config.js', + args: ['--baseUrl', 'http://localhost:8000'], + autoStartStopServer: true, + debug: true + })) + .on('error', function(e) { + throw e; + }); +}); diff --git a/Gulp/watchTasks.js b/Gulp/watchTasks.js index 390bf97b..62f76696 100644 --- a/Gulp/watchTasks.js +++ b/Gulp/watchTasks.js @@ -1,10 +1,9 @@ gulp = require('gulp'); mainBowerFiles = require('main-bower-files'); -var karma = require('gulp-karma'); var server = 'server.js'; var vendorJS = mainBowerFiles({filter:'**/*.js'}); -var vendorCSS = mainBowerFiles({filter:'**/*.css'}); +var Server = require('karma').Server; var gulp = require('gulp'); browserSync = require('browser-sync').create(); @@ -30,18 +29,16 @@ gulp.task('dev', function() { }) }); -gulp.task('karma:unit', function() { - return gulp.src([config.build + '**/*.spec.js']) - .pipe(karma({ - configFile:'karma.conf.js', - action: 'watch' - })) +gulp.task('test', function(done) { + new Server({ + configFile: __dirname + '/../karma.conf.js', + singleRun: true + }, done).start(); }); - gulp.task('watch:js', function() { console.log("running 'watch:js' task"); - gulp.watch(config.app_files.js, gulp.series('build:js', 'build:styles', 'build:inject', function() {browserSync.reload()})); + gulp.watch(config.app_files.js, gulp.parallel(gulp.series('build:js', 'build:assets', 'build:styles', 'build:inject', function() {browserSync.reload()}))); gulp.watch(vendorJS, gulp.series('build:js_bower', 'build:inject', function() {browserSync.reload()})); }); @@ -53,11 +50,11 @@ gulp.task('watch:assets', function() { gulp.task('watch:other', function() { console.log("running 'watch:other' task"); - gulp.watch(config.app_files.atpl, gulp.series('build:templateCache', 'build:inject', function() {browserSync.reload()})); + gulp.watch(config.app_files.atpl, gulp.series('build:templateCache', 'build:assets', 'build:inject', function() {browserSync.reload()})); gulp.watch(config.source + config.index, gulp.series( 'build:inject', function() {browserSync.reload()})); }); //TODO: need to add new/deleted file watch if it ever comes available in gulp 4.0 -gulp.task('watch', gulp.parallel('dev','watch:js', 'watch:assets', 'watch:other', 'karma:unit')); +gulp.task('watch', gulp.parallel('dev', 'watch:js', 'watch:assets', 'watch:other')); diff --git a/Gulpfile.js b/Gulpfile.js index fc14aea2..9420eb12 100644 --- a/Gulpfile.js +++ b/Gulpfile.js @@ -6,8 +6,8 @@ var path = require('path'); //require gulpfiles in order... -require('./Gulp/testTasks'); require('./Gulp/scriptTasks'); require('./Gulp/assetTasks'); require('./Gulp/generalTasks'); -require('./Gulp/watchTasks'); \ No newline at end of file +require('./Gulp/watchTasks'); +require('./Gulp/testTasks'); \ No newline at end of file diff --git a/bower.json b/bower.json index 81f37640..525c6585 100644 --- a/bower.json +++ b/bower.json @@ -8,7 +8,6 @@ "angular": "~1.4.0", "angular-animate": "~1.4.0", "angular-auto-validate": "~1.18.17", - "angular-bootstrap": "~0.14.3", "angular-messages": "~1.4.0", "angular-sanitize": "~1.4.0", "angular-touch": "~1.4.0", @@ -16,7 +15,10 @@ "bootstrap": "~3.3.5", "font-awesome": "~4.3.0", "jquery": "~2.1.3", - "ordercloud-angular-sdk": "~0.8.5", - "angular-toastr": "~1.5.0" + "angular-toastr": "~1.5.0", + "angular-bootstrap": "~0.14.3", + "angular-ui-tree": "~2.10.0", + "ordercloud-angular-sdk": "~1.0.3", + "angular-ui-grid": "~3.0.7" } } diff --git a/gulpConfig.js b/gulpConfig.js index c16522cd..414b26b5 100644 --- a/gulpConfig.js +++ b/gulpConfig.js @@ -51,7 +51,12 @@ module.exports = { temp: temp, root: root, app_files: { - js: [ source + '**/*.js', '!' + source + '**/*.spec.js', '!' + source + 'assets/**/*.js' ], + js: [ + source + '**/*.js', + '!' + source + '**/*.spec.js', + '!' + source + '**/*.test.js', + '!' + source + 'assets/**/*.js' + ], assets: [source + 'assets/**'], jsunit: [ source + '**/*.spec.js' ], diff --git a/karma.conf.js b/karma.conf.js index 8f8fdc95..e50b9a2d 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -1,7 +1,6 @@ // Karma configuration // Generated on Mon Jul 27 2015 17:53:54 GMT-0500 (Central Daylight Time) module.exports = function(config) { - var mainBowerFiles = require('main-bower-files'); config.set({ // base path that will be used to resolve all patterns (eg. files, exclude) @@ -15,14 +14,18 @@ module.exports = function(config) { // list of files / patterns to load in the browser files: [].concat( - mainBowerFiles({filter: '**/*.js'}), - './src/**/app.js', - './src/**/*.js' + './build/vendor/angular.js', + './build/vendor/**/*.js', + './vendor/angular-mocks/angular-mocks.js', + './build/src/app/app.js', + './build/src/**/*.js', + './src/**/*.spec.js' ), // list of files to exclude exclude: [ + './src/**/*.test.js' ], @@ -57,11 +60,11 @@ module.exports = function(config) { // start these browsers // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher - browsers: ['Firefox'], + browsers: ['PhantomJS'], // Continuous Integration mode // if true, Karma captures browsers, runs the tests and exits singleRun: false }) -} +}; diff --git a/package.json b/package.json index 51b9a2da..6cca5e45 100644 --- a/package.json +++ b/package.json @@ -9,11 +9,13 @@ "type": "git", "url": "git@github.com:Four51/OrderCloud-Seed-AngularJS.git" }, - "dependencies": {}, - "devDependencies": { + "dependencies": { + "bower": "^1.6.8", "browser-sync": "^2.8.0", "del": "^2.0.2", + "express": "^4.13.3", "gulp": "git://github.com/gulpjs/gulp.git#4.0", + "gulp-angular-protractor": "0.0.5", "gulp-angular-templatecache": "^1.7.0", "gulp-autoprefixer": "^2.3.1", "gulp-concat": "^2.6.0", @@ -21,21 +23,24 @@ "gulp-flatten": "^0.1.1", "gulp-header": "^1.7.1", "gulp-inject": "^1.5.0", - "gulp-karma": "0.0.4", "gulp-less": "^3.0.3", "gulp-less-import": "^1.0.0", "gulp-minify-css": "^1.2.0", "gulp-ng-annotate": "^1.0.0", + "gulp-ng-constant": "^1.1.0", "gulp-plumber": "^1.0.1", "gulp-replace": "^0.5.4", "gulp-sass": "^2.0.4", "gulp-uglify": "^1.2.0", "gulp-util": "^3.0.6", "gulp-wrapper": "^1.0.0", - "karma": "^0.13.10", - "karma-firefox-launcher": "^0.1.6", - "karma-jasmine": "^0.1.5", + "jasmine": "^2.3.2", + "karma": "^0.13.15", + "karma-jasmine": "^0.3.6", + "karma-phantomjs-launcher": "^0.2.1", "main-bower-files": "^2.9.0", - "vinyl-paths": "^2.0.0" - } + "phantomjs": "^1.9.18", + "protractor": "^2.5.1" + }, + "devDependencies": {} } diff --git a/protractor.config.js b/protractor.config.js new file mode 100644 index 00000000..42e78e3f --- /dev/null +++ b/protractor.config.js @@ -0,0 +1,36 @@ +var browsers = { + firefox: { + name: 'Firefox', + browserName: 'firefox' + }, + chrome: { + name: 'Chrome', + browserName: 'chrome' + } +}; + + +// An example configuration file. +exports.config = { + baseUrl: 'http://localhost:8000', + + // The address of a running selenium server. + seleniumAddress: 'http://localhost:4444/wd/hub', + + // Capabilities to be passed to the webdriver instance. + capabilities: browsers.chrome, + + // Spec patterns are relative to the configuration file location passed + // to protractor (in this example conf.js). + // They may include glob patterns. + specs: [ + './src/**/login.test.js', + './src/**/*.test.js', + './src/**/logout.test.js' + ], + + // Options to be passed to Jasmine-node. + jasmineNodeOpts: { + showColors: true // Use colors in the command line report. + } +}; \ No newline at end of file diff --git a/server.js b/server.js new file mode 100644 index 00000000..6171c82b --- /dev/null +++ b/server.js @@ -0,0 +1,25 @@ +var express = require('express'); +var app = express(); + +if (process.env.authurl) { + app.use(express.static(__dirname + '/compile')); +} else { + app.use(express.static(__dirname + '/build')); +} + +app.get('*', function(req, res) { + res.sendFile('index.html'); +}); + +if (!process.env.PORT) { + var server = app.listen(4451, function () { + var port = server.address().port; + console.log('Example app listening on port: ', port); + + }); +} else { + var server = app.listen(process.env.PORT, function () { + var port = server.address().port; + console.log('Example app listening on port: ', port); + }); +} diff --git a/src/app/account/account.js b/src/app/account/account.js index 546b9ff5..3ce7cecf 100644 --- a/src/app/account/account.js +++ b/src/app/account/account.js @@ -10,13 +10,14 @@ angular.module( 'orderCloud' ) function AccountConfig( $stateProvider ) { $stateProvider - .state( 'base.account', { + .state( 'account', { + parent: 'base', url: '/account', templateUrl:'account/templates/account.tpl.html', controller:'AccountCtrl', controllerAs: 'account' }) - .state( 'base.changePassword', { + .state( 'account.changePassword', { url: '/account/changepassword', templateUrl: 'account/templates/changePassword.tpl.html', controller: 'ChangePasswordCtrl', @@ -142,7 +143,10 @@ function ChangePasswordController( $state, $exceptionHandler, toastr, AccountSer AccountService.ChangePassword(vm.currentUser) .then(function() { toastr.success('Password successfully changed', 'Success!'); - $state.go('base.account'); + vm.currentUser.CurrentPassword = null; + vm.currentUser.NewPassword = null; + vm.currentUser.ConfirmPassword = null; + $state.go('account'); }) .catch(function(ex) { $exceptionHandler(ex) diff --git a/src/app/account/templates/account.tpl.html b/src/app/account/templates/account.tpl.html index 7c1137be..a5155e7c 100644 --- a/src/app/account/templates/account.tpl.html +++ b/src/app/account/templates/account.tpl.html @@ -1,34 +1,36 @@ -
- -
-
-
- - + +
+ + +
+
+ + +
+
+ + +
-
- - +
+ +
-
-
- - -
-
- - -
-
- - -
-
- - -
- - - - -
\ No newline at end of file +
+ + +
+
+ + +
+
+ + +
+ + + + +
+ \ No newline at end of file diff --git a/src/app/account/templates/changePassword.tpl.html b/src/app/account/templates/changePassword.tpl.html index 654e3415..5cfffece 100644 --- a/src/app/account/templates/changePassword.tpl.html +++ b/src/app/account/templates/changePassword.tpl.html @@ -14,6 +14,6 @@
- + \ No newline at end of file diff --git a/src/app/account/tests/account.spec.js b/src/app/account/tests/account.spec.js new file mode 100644 index 00000000..f5f16798 --- /dev/null +++ b/src/app/account/tests/account.spec.js @@ -0,0 +1,123 @@ +describe('Component: Account', function() { + var scope, + q, + account; + beforeEach(module('orderCloud')); + beforeEach(module('orderCloud.sdk')); + beforeEach(inject(function($q, $rootScope) { + q = $q; + scope = $rootScope.$new(); + account = { + ID: "TestAccount123456789", + Username: "TestAccount", + Password: "Fails345", + FirstName: "Test", + LastName: "Test", + Email: "test@test.com", + TermsAccepted: true, + Active: true + }; + })); + + describe('Controller: AccountCtrl', function() { + var accountCtrl, currentProfile; + beforeEach(inject(function($state, $controller) { + accountCtrl = $controller('AccountCtrl', { + $scope: scope, + CurrentUser: {} + }); + spyOn($state, 'go').and.returnValue(true); + })); + + describe('update', function() { + beforeEach(inject(function(AccountService) { + accountCtrl.profile = account; + currentProfile = {}; + var defer = q.defer(); + defer.resolve(account); + spyOn(AccountService, 'Update').and.returnValue(defer.promise); + accountCtrl.update(); + })); + it ('should call the Accounts Update method', inject(function(AccountService) { + expect(AccountService.Update).toHaveBeenCalledWith(currentProfile, account); + })); + }); + + //describe('resetForm', function() { + // beforeEach(inject(function(form) { + // accountCtrl.profile = account; + // spyOn(form, '$setPristine').and.returnValue(null); + // accountCtrl.resetForm(form); + // })); + // it ('should set accountCtrl.profile to currentProfile', inject(function() { + // expect(accountCtrl.profile).toEqual({}); + // })); + // it ('should call form.$setPristine method', inject(function(form) { + // expect(form.$setPristine).toHaveBeenCalledWith(true); + // })); + //}); + }); + + //describe('Controller: ConfirmPasswordCtrl', function() { + // var confirmPasswordCtrl; + // beforeEach(inject(function($state, $controller) { + // confirmPasswordCtrl = $controller('ConfirmPasswordCtrl', { + // $scope: scope + // }); + // spyOn($state, 'go').and.returnValue(true); + // })); + // + // describe('submit', function() { + // beforeEach(inject(function($uibModalInstance) { + // confirmPasswordCtrl.password = account.password; + // var defer = q.defer(); + // defer.resolve(account); + // spyOn($uibModalInstance, 'close').and.returnValue(defer.promise); + // confirmPasswordCtrl.submit(); + // scope.$digest(); + // })); + // it ('should call the $uibModalInstance close method', inject(function($uibModalInstance) { + // expect($uibModalInstance.close).toHaveBeenCalledWith(confirmPasswordCtrl.password); + // })); + // }); + // + // describe('cancel', function() { + // beforeEach(inject(function($uibModalInstance) { + // confirmPasswordCtrl.password = account.password; + // var defer = q.defer(); + // defer.resolve(account); + // spyOn($uibModalInstance, 'dismiss').and.returnValue(defer.promise); + // confirmPasswordCtrl.cancel(); + // scope.$digest(); + // })); + // it ('should call the $uibModalInstance close method', inject(function($uibModalInstance) { + // expect($uibModalInstance.dismiss).toHaveBeenCalledWith('cancel'); + // })); + // }); + //}); + + describe('Controller: ChangePasswordCtrl', function () { + var changePasswordCtrl; + beforeEach(inject(function($state, $controller) { + changePasswordCtrl = $controller('ChangePasswordCtrl', { + $scope: scope, + CurrentUser: {} + }); + spyOn($state, 'go').and.returnValue(true); + })); + describe('changePassword', function() { + beforeEach(inject(function(AccountService) { + changePasswordCtrl.currentUser = account; + var defer = q.defer(); + defer.resolve(account); + spyOn(AccountService, 'ChangePassword').and.returnValue(defer.promise); + changePasswordCtrl.changePassword(); + })); + it ('should call the Accounts ChangePassword method', inject(function(AccountService) { + expect(AccountService.ChangePassword).toHaveBeenCalledWith(changePasswordCtrl.currentUser); + })); + }); + + }); +}); + diff --git a/src/app/base/base.spec.js b/src/app/account/tests/account.test.js similarity index 100% rename from src/app/base/base.spec.js rename to src/app/account/tests/account.test.js diff --git a/src/app/app.js b/src/app/app.js index 73bccf37..05709cd8 100644 --- a/src/app/app.js +++ b/src/app/app.js @@ -1,65 +1,97 @@ -angular.module( 'orderCloud', [ - 'templates-app', - 'ngSanitize', - 'ngAnimate', - 'ngMessages', - 'ngTouch', - 'ui.router', - 'ui.bootstrap', - 'orderCloud.sdk', - 'toastr', - 'ordercloud-infinite-scroll', - 'ordercloud-buyer-select', - 'ordercloud-search', - 'ordercloud-assignment-helpers' -]) +(function ( window, angular, undefined ) { + 'use strict'; - .run( SetBuyerID ) - .config( Routing ) - .config( ErrorHandling ) - .controller( 'AppCtrl', AppCtrl ) + SetBuyerID.$inject = ["BuyerID", "buyerid"]; + Routing.$inject = ["$urlRouterProvider", "$urlMatcherFactoryProvider"]; + ErrorHandling.$inject = ["$provide"]; + AppCtrl.$inject = ["$rootScope", "$state", "appname", "Auth", "BuyerID", "ImpersonationService"];angular.module( 'orderCloud', [ + 'templates-app', + 'ngSanitize', + 'ngAnimate', + 'ngMessages', + 'ngTouch', + 'ui.tree', + 'ui.router', + 'ui.bootstrap', + 'orderCloud.sdk', + 'toastr', + 'jcs-autoValidate', + 'ordercloud-infinite-scroll', + 'ordercloud-buyer-select', + 'ordercloud-search', + 'ordercloud-assignment-helpers', + 'ordercloud-paging-helpers', + 'ordercloud-auto-id', + 'ordercloud-impersonation', + 'ordercloud-current-order', + 'ordercloud-address', + 'ordercloud-lineitems', + 'ui.grid', + 'ui.grid.infiniteScroll' + ]) - //Constants needed for the OrderCloud AngularJS SDK - .constant('ocscope', 'FullAccess') - .constant('appname', 'OrderCloud AngularJS Seed') + .constant("appname", "DevCenter") + .constant("ocscope", "FullAccess") + .constant("clientid", "0e0450e6-27a0-4093-a6b3-d7cd9ebc2b8f") + .constant("buyerid", "451ORDERCLOUD") + .constant("authurl", "https://testauth.ordercloud.io/oauth/token") + .constant("apiurl", "https://testapi.ordercloud.io") - //Client ID for a Registered Distributor or Buyer Company - .constant('clientid', '') - .constant('authurl', 'https://auth.ordercloud.io/oauth/token') - .constant('apiurl', 'https://api.ordercloud.io') -; + .run( SetBuyerID ) + .config( Routing ) + .config( ErrorHandling ) + .controller( 'AppCtrl', AppCtrl ) + ; -function SetBuyerID( BuyerID ) { - BuyerID.Set('451ORDERCLOUD'); -} + function SetBuyerID( BuyerID, buyerid ) { + BuyerID.Get() ? angular.noop() : BuyerID.Set(buyerid); + } -function Routing( $urlRouterProvider, $urlMatcherFactoryProvider ) { - $urlMatcherFactoryProvider.strictMode(false); - $urlRouterProvider.otherwise( '/home' ); - //$locationProvider.html5Mode(true); - //TODO: For HTML5 mode to work we need to always return index.html as the entry point on the serverside -} + function Routing( $urlRouterProvider, $urlMatcherFactoryProvider ) { + $urlMatcherFactoryProvider.strictMode(false); + $urlRouterProvider.otherwise( '/home' ); + //$locationProvider.html5Mode(true); + } -function ErrorHandling( $provide ) { - $provide.decorator('$exceptionHandler', handler); + function ErrorHandling( $provide ) { + handler.$inject = ["$delegate", "$injector"]; + $provide.decorator('$exceptionHandler', handler); - function handler( $delegate, $injector ) { - return function( ex, cause ) { - $delegate(ex, cause); - $injector.get('toastr').error(ex.data ? (ex.data.error || (ex.data.Errors ? ex.data.Errors[0].Message : ex.data)) : ex.message, 'Error'); - }; - }; -} + function handler( $delegate, $injector ) { + return function( ex, cause ) { + $delegate(ex, cause); + $injector.get('toastr').error(ex.data ? (ex.data.error || (ex.data.Errors ? ex.data.Errors[0].Message : ex.data)) : ex.message, 'Error'); + }; + } + } -function AppCtrl( $state, appname, Credentials ) { - var vm = this; - vm.name = appname; - vm.showLeftNav = true; - vm.toggleLeftNav = function() { - vm.showLeftNav = !vm.showLeftNav; - }; - vm.logout = function() { - Credentials.Delete(); - $state.go('login'); - }; -} + function AppCtrl( $rootScope, $state, appname, Auth, BuyerID, ImpersonationService ) { + var vm = this; + vm.name = appname; + vm.title = appname; + vm.showLeftNav = true; + vm.toggleLeftNav = function() { + vm.showLeftNav = !vm.showLeftNav; + }; + vm.logout = function() { + Auth.RemoveToken(); + BuyerID.Set(null); + ImpersonationService.StopImpersonating(); + $state.go('login'); + }; + vm.EndImpersonation = ImpersonationService.StopImpersonating; + vm.isImpersonating = !!Auth.GetImpersonating(); + $rootScope.$on('ImpersonationStarted', function() { + vm.isImpersonating = true; + }); + $rootScope.$on('ImpersonationStopped', function() { + vm.isImpersonating = false; + }); + $rootScope.$on('$stateChangeSuccess', function(e, toState) { + if (toState.data && toState.data.componentName) { + vm.title = appname + ' - ' + toState.data.componentName + } else { + vm.title = appname; + } + }); + }})( window, window.angular ); diff --git a/src/app/base/base.js b/src/app/base/base.js index 14626d58..ef3ae2da 100644 --- a/src/app/base/base.js +++ b/src/app/base/base.js @@ -2,8 +2,8 @@ angular.module( 'orderCloud' ) .config( BaseConfig ) .controller( 'BaseCtrl', BaseController ) - .controller( 'BaseLeftCtrl', BaseLeftController ) - .controller( 'BaseTopCtrl', BaseTopController ) + .controller( 'BaseLeftCtrl', BaseLeftController ) + .controller( 'BaseTopCtrl', BaseTopController ) ; @@ -13,87 +13,91 @@ function BaseConfig( $stateProvider ) { url: '', abstract: true, templateUrl:'base/templates/base.tpl.html', - views: { - '': { - templateUrl: 'base/templates/base.tpl.html', - controller: 'BaseCtrl', - controllerAs: 'base' - }, - 'top@base': { - templateUrl: 'base/templates/base.top.tpl.html', - controller: 'BaseTopCtrl', - controllerAs: 'baseTop' - }, - 'left@base': { - templateUrl: 'base/templates/base.left.tpl.html', - controller: 'BaseLeftCtrl', - controllerAs: 'baseLeft' - } - }, - resolve: { - CurrentUser: function($q, $state, Auth, BuyerID, Me) { - var dfd = $q.defer(); - Auth.IsAuthenticated() - .then(function() { - Me.Get() - .then(function(data) { - dfd.resolve(data); - }) - .catch(function(){ - Auth.RemoveToken(); - BuyerID.Set(null); - $state.go('login'); - dfd.resolve(); - }) - }) - .catch(function() { - BuyerID.Set(null); - $state.go('login'); - dfd.resolve(); - }) - ; - return dfd.promise; - }, - ComponentList: function($state, $q) { - var deferred = $q.defer(); - var nonSpecific = ['Products', 'Specs', 'Price Schedules']; - var components = { - nonSpecific: [], - buyerSpecific: [] - }; - angular.forEach($state.get(), function(state) { - if (!state.data || !state.data.componentName) return; - if (nonSpecific.indexOf(state.data.componentName) > -1) { - components.nonSpecific.push({ - Display: state.data.componentName, - StateRef: state.name - }) - } else { - components.buyerSpecific.push({ - Display: state.data.componentName, - StateRef: state.name - }) - } - }); - deferred.resolve(components); - return deferred.promise; - } - } + views: { + '': { + templateUrl: 'base/templates/base.tpl.html', + controller: 'BaseCtrl', + controllerAs: 'base' + }, + 'top@base': { + templateUrl: 'base/templates/base.top.tpl.html', + controller: 'BaseTopCtrl', + controllerAs: 'baseTop' + }, + 'left@base': { + templateUrl: 'base/templates/base.left.tpl.html', + controller: 'BaseLeftCtrl', + controllerAs: 'baseLeft' + } + }, + resolve: { + CurrentUser: function($q, $state, Auth, BuyerID, Me) { + var dfd = $q.defer(); + Auth.IsAuthenticated() + .then(function() { + Me.Get() + .then(function(data) { + dfd.resolve(data); + }) + .catch(function(){ + Auth.RemoveToken(); + BuyerID.Set(null); + $state.go('login'); + dfd.resolve(); + }) + }) + .catch(function() { + BuyerID.Set(null); + $state.go('login'); + dfd.resolve(); + }) + ; + return dfd.promise; + }, + ComponentList: function($state, $q, Underscore) { + var deferred = $q.defer(); + var nonSpecific = ['Products', 'Specs', 'Price Schedules', 'Admin Users']; + var components = { + nonSpecific: [], + buyerSpecific: [] + }; + angular.forEach($state.get(), function(state) { + if (!state.data || !state.data.componentName) return; + if (nonSpecific.indexOf(state.data.componentName) > -1) { + if (Underscore.findWhere(components.nonSpecific, {Display: state.data.componentName}) == undefined) { + components.nonSpecific.push({ + Display: state.data.componentName, + StateRef: state.name + }); + } + } else { + if (Underscore.findWhere(components.buyerSpecific, {Display: state.data.componentName}) == undefined) { + components.buyerSpecific.push({ + Display: state.data.componentName, + StateRef: state.name + }); + } + } + }); + deferred.resolve(components); + return deferred.promise; + } + } }); } function BaseController( CurrentUser ) { var vm = this; - vm.currentUser = CurrentUser; + vm.currentUser = CurrentUser; } function BaseLeftController(ComponentList) { - var vm = this; - vm.catalogItems = ComponentList.nonSpecific; - vm.organizationItems = ComponentList.buyerSpecific; - vm.isCollapsed = true; + var vm = this; + vm.catalogItems = ComponentList.nonSpecific; + vm.organizationItems = ComponentList.buyerSpecific; + vm.isCollapsed = true; } function BaseTopController() { - var vm = this; -} \ No newline at end of file + var vm = this; +} diff --git a/src/app/base/less/base.less b/src/app/base/less/base.less index 59b240b9..2ae2db96 100644 --- a/src/app/base/less/base.less +++ b/src/app/base/less/base.less @@ -4,112 +4,112 @@ * For details, see http://www.apache.org/licenses/LICENSE-2.0. */ #DashboardWrapper { - padding-left: 0; - transition: all 0.5s ease; - &.toggled { - padding-left: @dashboard-leftnav-width; - #DashboardLeftNav { - width: @dashboard-leftnav-width; - } - #DashboardContent { - position: absolute; - margin-right: -@dashboard-leftnav-width; - } - } + padding-left: 0; + transition: all 0.5s ease; + &.toggled { + padding-left: @dashboard-leftnav-width; + #DashboardLeftNav { + width: @dashboard-leftnav-width; + } + #DashboardContent { + position: absolute; + margin-right: -@dashboard-leftnav-width; + } + } } #DashboardLeftNav { - z-index: 1000; - position: fixed; - left: @dashboard-leftnav-width; - width: 0; - height: 100%; - margin-left: -@dashboard-leftnav-width; - overflow:hidden; - background-color:@dashboard-leftnav-bg; - border-right:1px solid @dashboard-leftnav-border; - -webkit-transition: all 0.5s ease; - -moz-transition: all 0.5s ease; - -o-transition: all 0.5s ease; - transition: all 0.5s ease; + z-index: 1000; + position: fixed; + left: @dashboard-leftnav-width; + width: 0; + height: 100%; + margin-left: -@dashboard-leftnav-width; + overflow:hidden; + background-color:@dashboard-leftnav-bg; + border-right:1px solid @dashboard-leftnav-border; + -webkit-transition: all 0.5s ease; + -moz-transition: all 0.5s ease; + -o-transition: all 0.5s ease; + transition: all 0.5s ease; } #DashboardContent { - width: 100%; - position: absolute; + width: 100%; + position: absolute; } @media(min-width:768px) { - #DashboardWrapper { - padding-left: @dashboard-leftnav-width; - &.toggled { - padding-left: 0; - #DashboardLeftNav { - width: 0; - } - #DashboardContent { - position: relative; - margin-right: 0; - } - } - } + #DashboardWrapper { + padding-left: @dashboard-leftnav-width; + &.toggled { + padding-left: 0; + #DashboardLeftNav { + width: 0; + } + #DashboardContent { + position: relative; + margin-right: 0; + } + } + } - #DashboardLeftNav { - width: @dashboard-leftnav-width; - } + #DashboardLeftNav { + width: @dashboard-leftnav-width; + } - #DashboardContent { - position: relative; - } + #DashboardContent { + position: relative; + } } #BaseLeft { - height:100%; - overflow-y:auto; - padding: @padding-base-horizontal; - width: @dashboard-leftnav-width; - white-space: nowrap; - h4 { - margin-left:-@padding-base-horizontal; - margin-right:-@padding-base-horizontal; - background-color:@navbar-default-bg; - padding:@padding-base-horizontal; - } + height:100%; + overflow-y:auto; + padding: @padding-base-horizontal; + width: @dashboard-leftnav-width; + white-space: nowrap; + h4 { + margin-left:-@padding-base-horizontal; + margin-right:-@padding-base-horizontal; + background-color:@navbar-default-bg; + padding:@padding-base-horizontal; + } } .navbar-flex { - #BaseTop { - background-color:@navbar-default-bg; - border-bottom:1px solid @navbar-default-border; - display: flex; - flex-flow: row nowrap; - justify-content: flex-start; - align-items:center; - margin-bottom:@navbar-margin-bottom; - > div { - max-height:@navbar-height; - &.link { - flex:0 1 auto; - > a { - display:block; - line-height:@navbar-height - 20px; - padding:@nav-link-padding; - color:@navbar-default-link-color; - &:hover { - background-color:@navbar-default-link-hover-bg; - color:@navbar-default-link-hover-color; - } - &.active, - &:active, - &:focus { - background-color:@navbar-default-link-active-bg; - color:@navbar-default-link-active-color; - } - } - } - &.logo { - flex:1 0 auto; - } - } - } + #BaseTop { + background-color:@navbar-default-bg; + border-bottom:1px solid @navbar-default-border; + display: flex; + flex-flow: row nowrap; + justify-content: flex-start; + align-items:center; + margin-bottom:@navbar-margin-bottom; + > div { + max-height:@navbar-height; + &.link { + flex:0 1 auto; + > a { + display:block; + line-height:@navbar-height - 20px; + padding:@nav-link-padding; + color:@navbar-default-link-color; + &:hover { + background-color:@navbar-default-link-hover-bg; + color:@navbar-default-link-hover-color; + } + &.active, + &:active, + &:focus { + background-color:@navbar-default-link-active-bg; + color:@navbar-default-link-active-color; + } + } + } + &.logo { + flex:1 0 auto; + } + } + } } \ No newline at end of file diff --git a/src/app/base/less/variables.less b/src/app/base/less/variables.less index 33c1ea14..f1a59b1f 100644 --- a/src/app/base/less/variables.less +++ b/src/app/base/less/variables.less @@ -1,3 +1,3 @@ @dashboard-leftnav-width: 250px; @dashboard-leftnav-bg: darken(@navbar-default-bg, 5); -@dashboard-leftnav-border:darken(@dashboard-leftnav-bg, 5); \ No newline at end of file +@dashboard-leftnav-border:darken(@dashboard-leftnav-bg, 5); diff --git a/src/app/base/templates/base.left.tpl.html b/src/app/base/templates/base.left.tpl.html index 88d9017f..8d1cf88c 100644 --- a/src/app/base/templates/base.left.tpl.html +++ b/src/app/base/templates/base.left.tpl.html @@ -2,7 +2,7 @@ diff --git a/src/app/base/templates/base.top.tpl.html b/src/app/base/templates/base.top.tpl.html index f1b3173a..dca18b79 100644 --- a/src/app/base/templates/base.top.tpl.html +++ b/src/app/base/templates/base.top.tpl.html @@ -3,7 +3,7 @@ \ No newline at end of file diff --git a/src/app/base/templates/base.tpl.html b/src/app/base/templates/base.tpl.html index 52aaeb61..2eab6ca8 100644 --- a/src/app/base/templates/base.tpl.html +++ b/src/app/base/templates/base.tpl.html @@ -1,7 +1,7 @@
-
-
- - -
-
\ No newline at end of file +
+
+ +
+
+ diff --git a/src/app/base/tests/base.spec.js b/src/app/base/tests/base.spec.js new file mode 100644 index 00000000..a2cbdb2a --- /dev/null +++ b/src/app/base/tests/base.spec.js @@ -0,0 +1,89 @@ +describe('Component: Base', function() { + var q, + scope; + beforeEach(module('orderCloud')); + beforeEach(module('orderCloud.sdk')); + beforeEach(module('ui.router')); + beforeEach(inject(function($q, $rootScope) { + q = $q; + scope = $rootScope.$new(); + })); + describe('State: Base', function() { + var state; + beforeEach(inject(function($state, Me, BuyerID) { + state = $state.get('base'); + var dfd = q.defer(); + dfd.resolve(true); + spyOn(Me, 'Get').and.returnValue(dfd.promise); + spyOn(BuyerID, 'Set').and.callThrough(); + spyOn($state, 'go').and.returnValue(true); + })); + //Skipped this test because Base now resolves with Auth.IsAuthenticated and THEN do a Me.Get() to confirm the token will work + it('should resolve CurrentUser', inject(function ($injector, Me, Auth) { + var dfd = q.defer(); + dfd.resolve(true); + spyOn(Auth, 'IsAuthenticated').and.returnValue(dfd.promise); + $injector.invoke(state.resolve.CurrentUser); + scope.$digest(); + expect(Me.Get).toHaveBeenCalled(); + })); + it('should return to login if unauthenticated', inject(function($injector, Auth, BuyerID, $state) { + var dfd = q.defer(); + dfd.reject(true); + spyOn(Auth, 'IsAuthenticated').and.returnValue(dfd.promise); + $injector.invoke(state.resolve.CurrentUser); + scope.$digest(); + expect(BuyerID.Set).toHaveBeenCalledWith(null); + expect($state.go).toHaveBeenCalledWith('login'); + })); + it ('should resolve ComponentsList', inject(function($injector) { + var components = $injector.invoke(state.resolve.ComponentList); + expect(components.nonSpecific).not.toBe(null); + expect(components.buyerSpecific).not.toBe(null); + })); + }); + + describe('Controller: BaseCtrl', function(){ + var baseCtrl, + fake_user = { + Username: 'notarealusername', + Password: 'notarealpassword' + }; + beforeEach(inject(function($controller) { + baseCtrl = $controller('BaseCtrl', { + CurrentUser: fake_user + }); + })); + it ('should initialize the currentUser into its scope', function() { + expect(baseCtrl.currentUser).toBe(fake_user); + }); + }); + + describe('Controller: BaseLeftCtrl', function(){ + var baseLeftCtrl, + fake_components = { + nonSpecific: ['test1', 'test2', 'test3'], + buyerSpecific: ['test4', 'test5', 'test6'] + }; + beforeEach(inject(function($controller) { + baseLeftCtrl = $controller('BaseLeftCtrl', { + ComponentList: fake_components + }); + })); + it ('should initialize the components lists', function() { + expect(baseLeftCtrl.catalogItems).toBe(fake_components.nonSpecific); + expect(baseLeftCtrl.organizationItems).toBe(fake_components.buyerSpecific); + }); + it ('should initialize isCollapsed to true', function() { + expect(baseLeftCtrl.isCollapsed).toBe(true); + }); + }); + + describe('Controller: BaseTopCtrl', function(){ + var baseTopCtrl; + beforeEach(inject(function($controller) { + baseTopCtrl = $controller('BaseTopCtrl', {}); + })); + /* No tests needed */ + }); +}); diff --git a/src/app/base/tests/base.test.js b/src/app/base/tests/base.test.js new file mode 100644 index 00000000..a31d445d --- /dev/null +++ b/src/app/base/tests/base.test.js @@ -0,0 +1,23 @@ +function BasePage() { + this.get = function() { + browser.get('/#'); + }; + + this.getTitle = function() { + return browser.getTitle(); + }; +} + +describe('Base', function() { + var page = new BasePage(); + + beforeEach(function() { + page.get(); + }); + + describe('base', function() { + it ("should display the correct title", function() { + expect(page.getTitle()).toBe('OrderCloud'); + }); + }) +}); \ No newline at end of file diff --git a/src/app/common/address/address.js b/src/app/common/address/address.js new file mode 100644 index 00000000..2e0f8309 --- /dev/null +++ b/src/app/common/address/address.js @@ -0,0 +1,52 @@ +angular.module('ordercloud-address', []) + + .directive('ordercloudAddressForm', AddressFormDirective) + .directive('ordercloudAddressInfo', AddressInfoDirective) + .filter('address', AddressFilter) + +; + +function AddressFormDirective() { + return { + restrict: 'E', + scope: { + address: '=', + isbilling: '=' + }, + templateUrl: 'common/address/templates/address.form.tpl.html' + }; +} + +function AddressInfoDirective() { + return { + restrict: 'E', + scope: { + addressid: '@' + }, + templateUrl: 'common/address/templates/address.info.tpl.html', + controller: 'AddressInfoCtrl', + controllerAs: 'addressInfo' + }; +} + +function AddressFilter() { + return function(address, option) { + if (!address) return null; + if (option === 'full') { + var result = []; + if (address.AddressName) { + result.push(address.AddressName); + } + result.push((address.FirstName ? address.FirstName + ' ' : '') + address.LastName); + result.push(address.Street1); + if (address.Street2) { + result.push(address.Street2); + } + result.push(address.City + ', ' + address.State + ' ' + address.Zip); + return result.join('\n'); + } + else { + return address.Street1 + (address.Street2 ? ', ' + address.Street2 : ''); + } + } +} diff --git a/src/app/common/address/templates/address.form.tpl.html b/src/app/common/address/templates/address.form.tpl.html new file mode 100644 index 00000000..54da9f5b --- /dev/null +++ b/src/app/common/address/templates/address.form.tpl.html @@ -0,0 +1,54 @@ +
+
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+
+ + +
+
+ + +
+
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+
\ No newline at end of file diff --git a/src/app/common/auto-id/auto-id.js b/src/app/common/auto-id/auto-id.js index 6e439741..2bbffd3c 100644 --- a/src/app/common/auto-id/auto-id.js +++ b/src/app/common/auto-id/auto-id.js @@ -28,7 +28,7 @@ function ordercloudAutoIdDirective($compile) { if (autoID_element.prop('checked')) { element.attr('disabled', true); } - autoID_element.bind('click', function() { + autoID_element.find('input').bind('click', function() { autoID_element.attr('checked', !autoID_element.prop('checked')); if (autoID_element.prop('checked')) { element.attr('disabled', true); diff --git a/src/app/common/auto-id/tests/auto-id.spec.js b/src/app/common/auto-id/tests/auto-id.spec.js new file mode 100644 index 00000000..c4b2cdf3 --- /dev/null +++ b/src/app/common/auto-id/tests/auto-id.spec.js @@ -0,0 +1,35 @@ +describe('Directive: ordercloudAutoId', function() { + var scope, + element, + modelValue; + beforeEach(module('orderCloud')); + beforeEach(module('orderCloud.sdk')); + beforeEach(module('ordercloud-auto-id')); + beforeEach(inject(function($rootScope, $compile) { + scope = $rootScope.$new(); + element = $compile('
')(scope); + scope.$digest(); + })); + it('should set boxtext to the value passed in', inject(function($compile) { + var potato_element = $compile('')(scope); + scope.$digest(); + expect(potato_element.isolateScope().boxtext).toBe('potato'); + })); + it('should wrap the input in an input group div', function() { + var result = element[0].querySelectorAll('.input-group'); + expect(angular.element(result).hasClass('input-group')).toBe(true); + }); + it('should have property checked set to checked', function() { + var result = element[0].querySelectorAll('.input-group-addon'); + expect(angular.element(result).attr('checked')).toBe('checked'); + }); + it('should have attribute disabled set to disabled', function() { + var result = element[0].querySelectorAll('.element_for_testing'); + expect(angular.element(result).attr('disabled')).toBe('disabled'); + }); + it('should init boxtext if no value is passed in', inject(function($compile) { + var blank_element = $compile('')(scope); + scope.$digest(); + expect(blank_element.isolateScope().boxtext).toBe('Auto-Gen. ID'); + })); +}); diff --git a/src/app/home/home.spec.js b/src/app/common/auto-id/tests/auto-id.test.js similarity index 100% rename from src/app/home/home.spec.js rename to src/app/common/auto-id/tests/auto-id.test.js diff --git a/src/app/common/buyer-select/buyer-select.less b/src/app/common/buyer-select/less/buyer-select.less similarity index 100% rename from src/app/common/buyer-select/buyer-select.less rename to src/app/common/buyer-select/less/buyer-select.less diff --git a/src/app/common/buyer-select/ordercloud-buyer-selected.js b/src/app/common/buyer-select/ordercloud-buyer-selected.js index 080b41a0..685c9445 100644 --- a/src/app/common/buyer-select/ordercloud-buyer-selected.js +++ b/src/app/common/buyer-select/ordercloud-buyer-selected.js @@ -9,15 +9,14 @@ function SelectBuyerDirective() { return { scope: {}, restrict: 'E', - templateUrl: 'common/buyer-select/buyer-select.tpl.html', + templateUrl: 'common/buyer-select/templates/buyer-select.tpl.html', controller: 'SelectBuyerCtrl', controllerAs: 'selectBuyer' } } function SelectBuyerController($state, Buyers, BuyerID) { - var vm = this, - page = 1; + var vm = this; Buyers.List().then(function(data) { vm.BuyerList = data; @@ -31,15 +30,13 @@ function SelectBuyerController($state, Buyers, BuyerID) { Buyers.Get(buyer.ID).then(function(data) { vm.selectedBuyer = data; BuyerID.Set(data.ID); - //console.dir($state.current); $state.reload($state.current); }); }; - vm.PagingFunction = function() { - page += 1; - if (page <= vm.BuyerList.Meta.TotalPages) { - Buyers.List(null, page, vm.BuyerList.Meta.PageSize) + vm.pagingfunction = function() { + if (vm.BuyerList.Meta.Page <= vm.BuyerList.Meta.TotalPages) { + Buyers.List(null, vm.BuyerList.Meta.Page + 1, vm.BuyerList.Meta.PageSize) .then(function(data) { vm.BuyerList.Meta = data.Meta; vm.BuyerList.Items = [].concat(vm.BuyerList.Items, data.Items); diff --git a/src/app/common/buyer-select/buyer-select.tpl.html b/src/app/common/buyer-select/templates/buyer-select.tpl.html similarity index 77% rename from src/app/common/buyer-select/buyer-select.tpl.html rename to src/app/common/buyer-select/templates/buyer-select.tpl.html index e61ec767..17069025 100644 --- a/src/app/common/buyer-select/buyer-select.tpl.html +++ b/src/app/common/buyer-select/templates/buyer-select.tpl.html @@ -7,7 +7,7 @@ + diff --git a/src/app/common/infinite-scroll/infinite-scroll.js b/src/app/common/infinite-scroll/infinite-scroll.js index 8e7e79a5..53c812d5 100644 --- a/src/app/common/infinite-scroll/infinite-scroll.js +++ b/src/app/common/infinite-scroll/infinite-scroll.js @@ -1,39 +1,31 @@ -angular.module('ordercloud-infinite-scroll', ['ordercloud-search']); +angular.module('ordercloud-infinite-scroll', ['ordercloud-search', 'ordercloud-paging-helpers']); angular.module('ordercloud-infinite-scroll') .directive( 'ordercloudInfiniteScroll', InfiniteScrollDirective ) .controller( 'InfiniteScrollCtrl', InfiniteScrollController ) - .factory( 'PagingFunctions', PagingFunctionsFactory ) ; -function InfiniteScrollDirective(PagingFunctions) { +function InfiniteScrollDirective(Paging) { return { restrict: 'A', scope: { - pagingfunction: '&', servicename: '@', - listobject: '=', - threshold: '@', - usergrouplist: '=', - selectedid: '@' + controlleras: '=', + idname: '@', + threshold: '@' }, controller: 'InfiniteScrollCtrl', controllerAs: 'InfiniteScroll', - link: function(scope, element, attrs) { + link: function(scope, element) { var threshold = scope.threshold || 0; var ele = element[0]; element.bind('scroll', function () { if (ele.scrollTop + ele.offsetHeight + threshold >= ele.scrollHeight) { - if (scope.servicename && scope.listobject && scope.usergrouplist && scope.selectedid) { - PagingFunctions.assignmentsPaging(scope.servicename, scope.listobject, scope.usergrouplist, scope.selectedid); + if (scope.controlleras && scope.controlleras.pagingfunction !== undefined) { + scope.controlleras.pagingfunction(); } - /* Use preset factory */ - else if (scope.servicename && scope.listobject) { - PagingFunctions.componentPaging(scope.servicename, scope.listobject); - } - /* Check if paging function is defined */ - else if (scope.pagingfunction != undefined && typeof(scope.pagingfunction) == 'function') { - scope.pagingfunction(); + else if (scope.servicename && scope.controlleras && scope.controlleras.list) { + Paging.paging(scope.controlleras.list, scope.servicename); } /* Else display a console error */ else { @@ -45,84 +37,15 @@ function InfiniteScrollDirective(PagingFunctions) { } } -function InfiniteScrollController($scope, PagingFunctions) { - PagingFunctions.reset(); - if ($scope.usergrouplist) { - PagingFunctions.setSelected($scope.listobject, $scope.usergrouplist); - } -} - -function PagingFunctionsFactory($injector, UserGroups, TrackSearch) { - var page = 1, - pageSize = 20, - nonBuyerSpecific = [ - 'Buyers', - 'Products', - 'PriceSchedules', - 'Specs' - ], - service = { - reset: initPaging, - setSelected: setSelected, - componentPaging: componentPaging, - assignmentsPaging: assignmentsPaging - }; - return service; - - function initPaging() { - TrackSearch.SetTerm(null); - } - - function componentPaging(component, componentObject) { - var componentService = $injector.get(component); - //page += 1; - if (componentObject.Meta.Page + 1 <= componentObject.Meta.TotalPages && componentService) { - var args = []; - if (component === 'Orders') { - args = ['incoming', TrackSearch.GetTerm(), null, null, componentObject.Meta.Page + 1, componentObject.Meta.PageSize]; - } - else { - args = [ TrackSearch.GetTerm(), componentObject.Meta.Page + 1, componentObject.Meta.PageSize]; - } - componentService.List.apply(this, args) - .then(function(data) { - componentObject.Meta = data.Meta; - componentObject.Items = [].concat(componentObject.Items, data.Items); - }); +function InfiniteScrollController($scope, Paging, TrackSearch) { + TrackSearch.SetTerm(null); + $scope.$watchCollection(function() { + if ($scope.controlleras && $scope.controlleras.assignments) { + return $scope.controlleras.assignments; } - } - - function assignmentsPaging(component, componentObject, UserGroupList, selectedID) { - var componentService = $injector.get(component); - page += 1; - if (page <= UserGroupList.Meta.TotalPages && componentService) { - UserGroups.List(null, page, UserGroupList.Meta.PageSize) - .then(function(data) { - UserGroupList.Meta = data.Meta; - UserGroupList.Items = [].concat(UserGroupList.Items, data.Items); - if (page <= componentObject.Meta.TotalPages) { - var args = [selectedID, null, null, page, UserGroupList.Meta.PageSize]; - componentService.ListAssignments.apply(this, args) - .then(function(data) { - componentObject.Meta = data.Meta; - componentObject.Items = [].concat(componentObject.Items, data.Items); - setSelected(componentObject, UserGroupList); - }); - } - else { - setSelected(componentObject, UserGroupList); - } - }); + }, function() { + if ($scope.controlleras && $scope.controlleras.assignments && $scope.controlleras.list && $scope.idname) { + Paging.setSelected($scope.controlleras.list.Items, $scope.controlleras.assignments.Items, $scope.idname); } - } - - function setSelected(assignedUserGroups, userGroups) { - angular.forEach(userGroups.Items, function(group) { - angular.forEach(assignedUserGroups.Items, function(assignedGroup) { - if (assignedGroup.UserGroupID === group.ID) { - group.selected = true; - } - }); - }); - } -} \ No newline at end of file + }); +} diff --git a/src/app/common/infinite-scroll/tests/infinite-scroll.spec.js b/src/app/common/infinite-scroll/tests/infinite-scroll.spec.js new file mode 100644 index 00000000..1b9b61ad --- /dev/null +++ b/src/app/common/infinite-scroll/tests/infinite-scroll.spec.js @@ -0,0 +1,33 @@ +describe('Component: Infinite Scroll', function() { + var scope; + beforeEach(module('orderCloud')); + beforeEach(module('orderCloud.sdk')); + beforeEach(module('ordercloud-infinite-scroll')) + beforeEach(inject(function($rootScope) { + scope = $rootScope.$new(); + })); + describe('Directive: ordercloudInfiniteScroll', function() { + var element; + beforeEach(inject(function($compile, Paging) { + scope.ctrl = {}; + element = $compile('
')(scope); + spyOn(Paging, 'paging').and.returnValue(true); + })); + it ('should initialize the directive', function() { + expect(element.isolateScope().controlleras).toEqual({}); + expect(element.isolateScope().servicename).toBe('Products'); + }); + }); + describe('Controller: InfiniteScrollCtrl', function() { + var infiniteScrollCtrl; + beforeEach(inject(function($controller, TrackSearch) { + spyOn(TrackSearch, 'SetTerm').and.callThrough(); + infiniteScrollCtrl = $controller('InfiniteScrollCtrl', { + $scope: scope + }); + })); + it('should initialize the search term to null', inject(function(TrackSearch) { + expect(TrackSearch.SetTerm).toHaveBeenCalledWith(null); + })); + }); +}); \ No newline at end of file diff --git a/src/app/common/infinite-scroll/tests/infinite-scroll.test.js b/src/app/common/infinite-scroll/tests/infinite-scroll.test.js new file mode 100644 index 00000000..e69de29b diff --git a/src/app/common/lineitems/less/lineitems.less b/src/app/common/lineitems/less/lineitems.less new file mode 100644 index 00000000..0212a303 --- /dev/null +++ b/src/app/common/lineitems/less/lineitems.less @@ -0,0 +1,3 @@ +.modal_buttons { + margin-bottom: 50px; +} \ No newline at end of file diff --git a/src/app/common/lineitems/lineitems.js b/src/app/common/lineitems/lineitems.js new file mode 100644 index 00000000..93670358 --- /dev/null +++ b/src/app/common/lineitems/lineitems.js @@ -0,0 +1,118 @@ +angular.module('ordercloud-lineitems', []) + + .factory('LineItemHelpers', LineItemFactory) + .controller('LineItemModalCtrl', LineItemModalController) + +; + +function LineItemFactory($q, $state, CurrentOrder, Orders, LineItems, $uibModal, $rootScope, Products, Underscore) { + return { + SpecConvert: SpecConverter, + RemoveItem: DeleteLineItem, + UpdateQuantity: UpdateQuantity, + GetProductInfo: GetProductInformation, + ClearShipper: ClearShipping, + CustomShipper: CustomShipping + }; + + function DeleteLineItem(Order, LineItem) { + LineItems.Delete(Order.ID, LineItem.ID) + .then(function() { + // If all line items are removed delete the order. + LineItems.List(Order.ID) + .then(function(data) { + if (!data.Items.length) { + Orders.Delete(Order.ID); + CurrentOrder.Remove(); + } + $state.reload(); + }); + }); + } + + function UpdateQuantity(Order, LineItem) { + if (LineItem.Quantity > 0) { + LineItems.Patch(Order.ID, LineItem.ID, {Quantity: LineItem.Quantity}) + .then(function() { + $rootScope.$broadcast('LineItemQuantityUpdated', LineItem.ID); + }); + } + } + + function ClearShipping(Order, LineItem) { + + } + + function GetProductInformation(LineItems) { + var li = LineItems.Items || LineItems; + var productIDs = Underscore.uniq(Underscore.pluck(li, 'ProductID')); + var dfd = $q.defer(); + var queue = []; + angular.forEach(productIDs, function(productid) { + queue.push(Products.Get(productid)); + }); + $q.all(queue) + .then(function(results) { + angular.forEach(li, function(item) { + item.Product = angular.copy(Underscore.where(results, {ID: item.ProductID})[0]); + }); + dfd.resolve(li); + }); + return dfd.promise; + } + + function CustomShipping(Order, LineItem) { + var modalInstance = $uibModal.open({ + animation: true, + templateUrl: 'common/lineitems/templates/shipping.tpl.html', + controller: 'LineItemModalCtrl', + controllerAs: 'liModal', + size: 'lg' + }); + + modalInstance.result + .then(function(address) { + LineItems.SetShippingAddress(Order.ID, LineItem.ID, address) + .then(function() { + $rootScope.$broadcast('LineItemShippingUpdated', LineItem.ID); + }); + }); + } + + function SpecConverter(specs) { + var results = []; + angular.forEach(specs, function(spec) { + var spec_to_push = {SpecID: spec.ID}; + if (spec.Options.length > 0) { + if (spec.DefaultOptionID) { + spec_to_push.OptionID = spec.DefaultOptionID; + } + if (spec.Value) { + spec_to_push.Value = spec.Value; + } + else if (spec.OptionID) { + spec_to_push.OptionID = spec.OptionID; + } + } + else { + spec_to_push.Value = spec.Value || spec.DefaultValue || null; + } + results.push(spec_to_push); + }); + return results; + } +} + +function LineItemModalController($uibModalInstance) { + var vm = this; + vm.address = {}; + + vm.submit = function() { + $uibModalInstance.close(vm.address); + }; + + vm.cancel = function() { + vm.address = {}; + $uibModalInstance.dismiss('cancel'); + }; +} diff --git a/src/app/common/lineitems/templates/shipping.tpl.html b/src/app/common/lineitems/templates/shipping.tpl.html new file mode 100644 index 00000000..2c155a49 --- /dev/null +++ b/src/app/common/lineitems/templates/shipping.tpl.html @@ -0,0 +1,11 @@ + \ No newline at end of file diff --git a/src/app/common/ordercloud-logo/ordercloud_logo.js b/src/app/common/ordercloud-logo/ordercloud_logo.js index c8068847..da775284 100644 --- a/src/app/common/ordercloud-logo/ordercloud_logo.js +++ b/src/app/common/ordercloud-logo/ordercloud_logo.js @@ -3,8 +3,8 @@ angular.module('orderCloud') ; function ordercloudLogo() { - var obj = { - templateUrl: 'common/ordercloud-logo/ordercloud-logo.tpl.html', + return { + templateUrl: 'common/ordercloud-logo/templates/ordercloud-logo.tpl.html', replace:true, link: function(scope, element, attrs) { scope.OrderCloudLogo = { @@ -15,5 +15,4 @@ function ordercloudLogo() { }; } }; - return obj; } \ No newline at end of file diff --git a/src/app/common/ordercloud-logo/ordercloud-logo.tpl.html b/src/app/common/ordercloud-logo/templates/ordercloud-logo.tpl.html similarity index 100% rename from src/app/common/ordercloud-logo/ordercloud-logo.tpl.html rename to src/app/common/ordercloud-logo/templates/ordercloud-logo.tpl.html diff --git a/src/app/common/ordercloud-logo/tests/ordercloud-logo.test.js b/src/app/common/ordercloud-logo/tests/ordercloud-logo.test.js new file mode 100644 index 00000000..e69de29b diff --git a/src/app/common/ordercloud-logo/tests/ordercloud_logo.spec.js b/src/app/common/ordercloud-logo/tests/ordercloud_logo.spec.js new file mode 100644 index 00000000..3f0313b2 --- /dev/null +++ b/src/app/common/ordercloud-logo/tests/ordercloud_logo.spec.js @@ -0,0 +1,28 @@ +describe('Directive: ordercloudLogo', function() { + var scope, + element, + blank_element; + beforeEach(module('orderCloud')); + beforeEach(module('orderCloud.sdk')); + beforeEach(inject(function($rootScope) { + scope = $rootScope.$new(); + })); + it ('should initialize all values passed in as attributes', inject(function($compile) { + element = $compile('')(scope); + scope.$digest(); + expect(element.scope().OrderCloudLogo).not.toBe(undefined); + expect(element.scope().OrderCloudLogo.Icon).toBe(true); + expect(element.scope().OrderCloudLogo.maxHeight).toBe('30'); + expect(element.scope().OrderCloudLogo.width).toBe('31'); + expect(element.scope().OrderCloudLogo.fillColor).toBe('blue'); + })); + it ('should set logo to false if not passed in and all other values to undefined', inject(function($compile) { + blank_element = $compile('')(scope); + scope.$digest(); + expect(blank_element.scope().OrderCloudLogo).not.toBe(undefined); + expect(blank_element.scope().OrderCloudLogo.Icon).toBe(false); + expect(blank_element.scope().OrderCloudLogo.maxHeight).toBe(undefined); + expect(blank_element.scope().OrderCloudLogo.width).toBe(undefined); + expect(blank_element.scope().OrderCloudLogo.fillColor).toBe(undefined); + })); +}); \ No newline at end of file diff --git a/src/app/common/search/search.js b/src/app/common/search/search.js index 3dd3728b..4ca36a05 100644 --- a/src/app/common/search/search.js +++ b/src/app/common/search/search.js @@ -9,6 +9,7 @@ angular.module('ordercloud-search') function ordercloudSearch () { return { scope: { + placeholder: '@', servicename: "@", controlleras: "=" }, @@ -22,8 +23,11 @@ function ordercloudSearch () { function ordercloudSearchCtrl($timeout, $scope, $injector, TrackSearch) { $scope.searchTerm = null; - $scope.placeholder = "Search " + $scope.servicename + '...'; - var Service = $injector.get($scope.servicename); + if ($scope.servicename) { + var var_name = $scope.servicename.replace(/([a-z])([A-Z])/g, '$1 $2'); + $scope.placeholder = "Search " + var_name + '...'; + var Service = $injector.get($scope.servicename); + } var searching; $scope.$watch('searchTerm', function(n,o) { if (n == o) { @@ -33,10 +37,35 @@ function ordercloudSearchCtrl($timeout, $scope, $injector, TrackSearch) { searching = $timeout(function() { n == '' ? n = null : angular.noop(); TrackSearch.SetTerm(n); - Service.List(n) - .then(function (data){ - $scope.controlleras.list = data; - }); + if($scope.servicename === 'Orders') { + if (!$scope.controlleras.searchfunction) { + Service.List('incoming',null, null, n) + .then(function (data){ + $scope.controlleras.list = data; + }); + } + else { + $scope.controlleras.searchfunction($scope.searchTerm) + .then(function (data){ + $scope.controlleras.list = data; + }); + } + } + else { + if (!$scope.controlleras.searchfunction) { + Service.List(n) + .then(function (data){ + $scope.controlleras.list = data; + }); + } + else { + $scope.controlleras.searchfunction($scope.searchTerm) + .then(function (data){ + $scope.controlleras.list = data; + }); + } + } + }, 300); } }); diff --git a/src/app/common/search/tests/search.spec.js b/src/app/common/search/tests/search.spec.js new file mode 100644 index 00000000..084d9550 --- /dev/null +++ b/src/app/common/search/tests/search.spec.js @@ -0,0 +1,58 @@ +describe('Component: Search', function() { + var scope; + beforeEach(module('orderCloud')); + beforeEach(module('orderCloud.sdk')); + beforeEach(module('ordercloud-search')); + beforeEach(inject(function($rootScope) { + scope = $rootScope.$new(); + })); + describe('Directive: ordercloudSearch', function() { + var element; + beforeEach(inject(function($compile) { + scope.ctrl = { + searchTerm: '' + }; + element = $compile('')(scope); + scope.$digest(); + })); + it('should initialize the isolate scope', function() { + expect(element.isolateScope().servicename).toBe('Products'); + expect(element.isolateScope().controlleras).toEqual({searchTerm: ''}); + }); + }); + describe('Controller: ordercloudSearchCtrl', function() { + var searchCtrl; + beforeEach(inject(function($controller, $injector, Products) { + scope.servicename = 'Products'; + spyOn(scope, '$watch').and.callThrough(); + searchCtrl = $controller('ordercloudSearchCtrl', { + $scope: scope + }); + scope.$digest(); + })); + it('should initialize the placeholder for the search', function() { + expect(scope.placeholder).toBe('Search Products...') + }); + it('should initialize the search term to null', function() { + expect(scope.searchTerm).toBe(null); + }); + it('should trigger the watch function when searchTerm is changed', function() { + scope.searchTerm = 'potato'; + scope.$digest(); + expect(scope.$watch).toHaveBeenCalled(); + }); + }); + describe('Factory: TrackSearch', function() { + var trackSearch; + beforeEach(inject(function(TrackSearch) { + trackSearch = TrackSearch; + })); + it('should initialize term to null', function() { + expect(trackSearch.GetTerm()).toBe(null); + }); + it('SetTerm should change the value of term', function() { + trackSearch.SetTerm('testing'); + expect(trackSearch.GetTerm()).toBe('testing'); + }); + }); +}); \ No newline at end of file diff --git a/src/app/common/search/tests/search.test.js b/src/app/common/search/tests/search.test.js new file mode 100644 index 00000000..e69de29b diff --git a/src/app/common/token-refresh/token-refresh.js b/src/app/common/token-refresh/token-refresh.js new file mode 100644 index 00000000..42e87945 --- /dev/null +++ b/src/app/common/token-refresh/token-refresh.js @@ -0,0 +1,44 @@ +angular.module('orderCloud') + .factory('TokenRefresh', TokenRefresh) +; + +function TokenRefresh($resource, $cookieStore, ocscope, clientid) { + var service = { + Set: _set, + Get: _get, + SetToken: _setToken, + GetToken: _getToken, + Refresh: _refresh + }; + var remember; + + return service; + //// + + function _set(value) { + remember = value; + } + + function _get() { + return remember; + } + + function _setToken(token) { + $cookieStore.put(appname + '.refresh_token', token); + } + + function _getToken() { + $cookieStore.get(appname + '.refresh_token'); + } + + function _refresh(token) { + var data = $.param({ + grant_type: 'refresh_token', + scope: ocscope, + client_id: clientid, + refresh_token: token + }); + return $resource(authurl, {}, { refresh: { method: 'POST'}}).refresh(data).$promise; + } + +} \ No newline at end of file diff --git a/src/app/home/home.js b/src/app/home/home.js index e1a302fa..2b953845 100644 --- a/src/app/home/home.js +++ b/src/app/home/home.js @@ -7,10 +7,11 @@ angular.module( 'orderCloud' ) function HomeConfig( $stateProvider ) { $stateProvider - .state( 'base.home', { + .state( 'home', { + parent: 'base', url: '/home', - templateUrl:'home/templates/home.tpl.html', - controller:'HomeCtrl', + templateUrl: 'home/templates/home.tpl.html', + controller: 'HomeCtrl', controllerAs: 'home' }) } diff --git a/src/app/home/templates/home.tpl.html b/src/app/home/templates/home.tpl.html index efa9af0a..62a58fb4 100644 --- a/src/app/home/templates/home.tpl.html +++ b/src/app/home/templates/home.tpl.html @@ -1,6 +1,6 @@ -
+

-
+ diff --git a/src/app/login/less/login.less b/src/app/login/less/login.less index 4ba4ca61..b5b204ba 100644 --- a/src/app/login/less/login.less +++ b/src/app/login/less/login.less @@ -1,4 +1,4 @@ -#Login { +#Login, #DevLogin { max-width: @login-form-width; margin: 0 auto; } \ No newline at end of file diff --git a/src/app/login/login.js b/src/app/login/login.js index f0d73f6f..6008f2f8 100644 --- a/src/app/login/login.js +++ b/src/app/login/login.js @@ -1,115 +1,113 @@ angular.module( 'orderCloud' ) - .config( LoginConfig ) - .factory( 'LoginService', LoginService ) - .controller( 'LoginCtrl', LoginController ) + .config( LoginConfig ) + .factory( 'LoginService', LoginService ) + .controller( 'LoginCtrl', LoginController ) ; function LoginConfig( $stateProvider ) { - $stateProvider.state( 'login', { - url: '/login/:token', - templateUrl:'login/templates/login.tpl.html', - controller:'LoginCtrl', - controllerAs: 'login', - data:{ - limitAccess: false - } - }); + $stateProvider + .state( 'login', { + url: '/login/:token', + templateUrl:'login/templates/login.tpl.html', + controller:'LoginCtrl', + controllerAs: 'login' + }) } -function LoginService( $q, PasswordResets, clientid ) { - var service = { - SendVerificationCode: _sendVerificationCode, - ResetPassword: _resetPassword - }; - - function _sendVerificationCode(email) { - var deferred = $q.defer(); - - var passwordResetRequest = { - Email: email, - ClientID: clientid, - URL: encodeURIComponent($window.location.href) + '{0}' - }; - - PasswordResets.SendVerificationCode(passwordResetRequest) - .then(function() { - deferred.resolve(); - }) - .catch(function(ex) { - deferred.reject(ex); - }); - - return deferred.promise; - } - - function _resetPassword(resetPasswordCredentials, verificationCode) { - var deferred = $q.defer(); - - var passwordReset = { - ClientID: clientid, - Username: resetPasswordCredentials.ResetUsername, - Password: resetPasswordCredentials.NewPassword - }; - - PasswordResets.ResetPassword(verificationCode, passwordReset). - then(function() { - deferred.resolve(); - }) - .catch(function(ex) { - deferred.reject(ex); - }); - - return deferred.promise; - } - - return service; +function LoginService( $q, $window, PasswordResets, clientid ) { + return { + SendVerificationCode: _sendVerificationCode, + ResetPassword: _resetPassword + }; + + function _sendVerificationCode(email) { + var deferred = $q.defer(); + + var passwordResetRequest = { + Email: email, + ClientID: clientid, + URL: encodeURIComponent($window.location.href) + '{0}' + }; + + PasswordResets.SendVerificationCode(passwordResetRequest) + .then(function() { + deferred.resolve(); + }) + .catch(function(ex) { + deferred.reject(ex); + }); + + return deferred.promise; + } + + function _resetPassword(resetPasswordCredentials, verificationCode) { + var deferred = $q.defer(); + + var passwordReset = { + ClientID: clientid, + Username: resetPasswordCredentials.ResetUsername, + Password: resetPasswordCredentials.NewPassword + }; + + PasswordResets.ResetPassword(verificationCode, passwordReset). + then(function() { + deferred.resolve(); + }) + .catch(function(ex) { + deferred.reject(ex); + }); + + return deferred.promise; + } } -function LoginController( $state, $stateParams, $exceptionHandler, LoginService, Credentials ) { - var vm = this; - - vm.token = $stateParams.token; - vm.form = vm.token ? 'reset' : 'login'; - vm.setForm = function(form) { - vm.form = form; - }; - - vm.submit = function( ) { - Credentials.Get( vm.credentials ).then( - function() { - $state.go( 'base.home' ); - }).catch(function(ex) { - $exceptionHandler(ex); - }); - }; - - vm.forgotPassword = function() { - LoginService.SendVerificationCode(vm.credentials.Email) - .then(function() { - vm.setForm('verificationCodeSuccess'); - vm.credentials.Email = null; - }) - .catch(function(ex) { - $exceptionHandler(ex); - }); - }; - - vm.resetPassword = function() { - LoginService.ResetPassword(vm.credentials, vm.token) - .then(function() { - vm.setForm('resetSuccess'); - vm.token = null; - vm.credentials.ResetUsername = null; - vm.credentials.NewPassword = null; - vm.credentials.ConfirmPassword = null; - }) - .catch(function(ex) { - $exceptionHandler(ex); - vm.credentials.ResetUsername = null; - vm.credentials.NewPassword = null; - vm.credentials.ConfirmPassword = null; - }); - }; -} +function LoginController( $state, $stateParams, $exceptionHandler, LoginService, Credentials, BuyerID, buyerid, ImpersonationService ) { + var vm = this; + vm.token = $stateParams.token; + vm.form = vm.token ? 'reset' : 'login'; + vm.setForm = function(form) { + vm.form = form; + }; + + vm.submit = function() { + Credentials.Get( vm.credentials ) + .then(function() { + BuyerID.Get() ? angular.noop() : BuyerID.Set(buyerid); + ImpersonationService.StopImpersonating(); + $state.go('home'); + }) + .catch(function(ex) { + $exceptionHandler(ex); + }) + }; + + vm.forgotPassword = function() { + LoginService.SendVerificationCode(vm.credentials.Email) + .then(function() { + vm.setForm('verificationCodeSuccess'); + vm.credentials.Email = null; + }) + .catch(function(ex) { + $exceptionHandler(ex); + }); + }; + + vm.resetPassword = function() { + LoginService.ResetPassword(vm.credentials, vm.token) + .then(function() { + vm.setForm('resetSuccess'); + vm.token = null; + vm.credentials.ResetUsername = null; + vm.credentials.NewPassword = null; + vm.credentials.ConfirmPassword = null; + }) + .catch(function(ex) { + $exceptionHandler(ex); + vm.credentials.ResetUsername = null; + vm.credentials.NewPassword = null; + vm.credentials.ConfirmPassword = null; + }); + }; +} \ No newline at end of file diff --git a/src/app/login/templates/login.dev.tpl.html b/src/app/login/templates/login.dev.tpl.html new file mode 100644 index 00000000..bb88e2da --- /dev/null +++ b/src/app/login/templates/login.dev.tpl.html @@ -0,0 +1,14 @@ +
+
+

Login

+
+ + +
+
+ + +
+ +
+
diff --git a/src/app/login/templates/login.tpl.html b/src/app/login/templates/login.tpl.html index 7744d94d..e8e22544 100644 --- a/src/app/login/templates/login.tpl.html +++ b/src/app/login/templates/login.tpl.html @@ -1,49 +1,59 @@
-
-

Login

-
- - -
-
- - -
- - Forgot Password? -
-
-

Forgot Password

-
- - -
- - Back to Login -
-
-

Reset Password

-
- - -
-
- - -
-
- - -
- -
-
-

Forgot Password

-
Forgot Password email has been sent. Please check your email in order to reset your password.
-
-
-

Reset Password

-
Your password has been reset.
- Back to Login -
+
+
+

Login

+
+ + +
+
+ + +
+ + Forgot Password? +
+
+
+
+

Forgot Password

+
+ + +
+ + Back to Login +
+
+
+
+

Reset Password

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

Forgot Password

+
Forgot Password email has been sent. Please check your email in order to reset your password.
+
+
+
+
+

Reset Password

+
Your password has been reset.
+ Back to Login +
+
diff --git a/src/app/login/tests/login.spec.js b/src/app/login/tests/login.spec.js new file mode 100644 index 00000000..7cb55eb3 --- /dev/null +++ b/src/app/login/tests/login.spec.js @@ -0,0 +1,159 @@ +describe('Component: Login', function() { + var scope, + q, + loginFactory, + credentials = { + Username: 'notarealusername', + Password: 'notarealpassword' + }; + beforeEach(module('orderCloud')); + beforeEach(module('orderCloud.sdk')); + beforeEach(inject(function($q, $rootScope, LoginService) { + q = $q; + scope = $rootScope.$new(); + loginFactory = LoginService + })); + + describe('Factory: LoginService', function() { + var PasswordResetsFactory, + client_id; + beforeEach(inject(function(PasswordResets, clientid) { + PasswordResetsFactory = PasswordResets; + client_id = clientid; + })); + describe('SendVerificationCode', function() { + var passwordResetRequest; + beforeEach(inject(function($window) { + var email = 'test@test.com'; + passwordResetRequest = { + Email: email, + ClientID: client_id, + URL: encodeURIComponent($window.location.href) + '{0}' + }; + var deferred = q.defer(); + deferred.resolve(true); + spyOn(PasswordResetsFactory, 'SendVerificationCode').and.returnValue(deferred.promise); + loginFactory.SendVerificationCode(email); + })); + it ('should call the SendVerificationCode method of PasswordResets with the reset request object', function(){ + expect(PasswordResetsFactory.SendVerificationCode).toHaveBeenCalledWith(passwordResetRequest); + }); + }); + + describe('ResetPassword', function() { + var creds = { + ResetUsername: credentials.Username, + NewPassword: credentials.Password, + ConfirmPassword: credentials.Password + }; + beforeEach(inject(function() { + var deferred = q.defer(); + deferred.resolve(true); + spyOn(PasswordResetsFactory, 'ResetPassword').and.returnValue(deferred.promise); + loginFactory.ResetPassword(creds, 'code'); + })); + it ('should call the ResetPassword method of the PasswordResets Service with a code and credentials', function() { + expect(PasswordResetsFactory.ResetPassword).toHaveBeenCalledWith('code', {ClientID: client_id, Username: creds.ResetUsername, Password: creds.NewPassword}); + }); + }); + }); + + describe('Controller: LoginCtrl', function() { + var loginCtrl; + beforeEach(inject(function($controller, $state, Credentials, LoginService) { + spyOn($state, 'go').and.callThrough(); + var dfd = q.defer(); + dfd.resolve(true); + spyOn(Credentials, 'Get').and.returnValue(dfd.promise); + loginCtrl = $controller('LoginCtrl', { + $scope: scope, + LoginService: LoginService, + Credentials: Credentials + }); + })); + + describe('form', function() { + it ('should initialize to login', function() { + expect(loginCtrl.form).toBe('login'); + }); + }); + + describe('setForm', function() { + it ('should change the value of form to the passed in value', function() { + loginCtrl.setForm('reset'); + expect(loginCtrl.form).toBe('reset'); + }); + }); + + describe('submit', function() { + beforeEach(function() { + loginCtrl.credentials = credentials; + loginCtrl.submit(); + }); + it ('should call the Credentials Get method with credentials', inject(function(Credentials) { + expect(Credentials.Get).toHaveBeenCalledWith(credentials); + })); + it ('should enter the home state', inject(function($state) { + scope.$digest(); + expect($state.go).toHaveBeenCalledWith('home'); + })); + }); + + describe('forgotPassword', function() { + var email = 'test@test.com'; + beforeEach(function() { + loginCtrl.credentials = { + Email: email + }; + var deferred = q.defer(); + deferred.resolve(true); + spyOn(loginFactory, 'SendVerificationCode').and.returnValue(deferred.promise); + loginCtrl.forgotPassword(); + scope.$digest(); + }); + it ('should call the LoginService SendVerificationCode with the email', function() { + expect(loginFactory.SendVerificationCode).toHaveBeenCalledWith(email); + }); + it ('should set the form to verificationCodeSuccess', function() { + expect(loginCtrl.form).toBe('verificationCodeSuccess'); + }); + it ('should set credentials.Email back to null', function() { + expect(loginCtrl.credentials.Email).toBe(null); + }); + }); + + describe('resetPassword', function() { + var creds = { + ResetUsername: credentials.Username, + NewPassword: credentials.Password, + ConfirmPassword: credentials.Password + }; + var token = 'reset'; + beforeEach(function() { + loginCtrl.credentials = creds; + loginCtrl.token = token; + var deferred = q.defer(); + deferred.resolve(true); + spyOn(loginFactory, 'ResetPassword').and.returnValue(deferred.promise); + loginCtrl.resetPassword(); + scope.$digest(); + }); + it ('should call the ResetPassword method of the LoginService with credentials and token', function() { + expect(loginFactory.ResetPassword).toHaveBeenCalledWith(creds, token); + }); + it ('should set the form to resetSuccess', function() { + expect(loginCtrl.form).toBe('resetSuccess'); + }); + it ('should set the token to null', function() { + expect(loginCtrl.token).toBe(null); + }); + it ('should set the credentials values to null', function() { + for (key in loginCtrl.credentials) { + if (loginCtrl.credentials.hasOwnProperty(key)) { + expect(loginCtrl.credentials[key]).toBe(null); + } + } + }); + }); + }); +}); diff --git a/src/app/login/tests/login.test.js b/src/app/login/tests/login.test.js new file mode 100644 index 00000000..ca3a8ec1 --- /dev/null +++ b/src/app/login/tests/login.test.js @@ -0,0 +1,22 @@ +/* This test will have to be run first so the user is logged in */ +function LoginPage() { + this.get = function() { + browser.get('#/login'); + }; +} + +describe('login page', function() { + var page = new LoginPage(); + + beforeEach(function() { + page.get(); + }); + + describe('forgot password', function() { + + }); + + describe('login', function() { + + }); +}); \ No newline at end of file diff --git a/src/app/login/tests/logout.test.js b/src/app/login/tests/logout.test.js new file mode 100644 index 00000000..a81f1770 --- /dev/null +++ b/src/app/login/tests/logout.test.js @@ -0,0 +1 @@ +/* This test will have to be run last so user isn't left logged in */ \ No newline at end of file From 280be174631576416a9afcdb408a79d60888bd5f Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Thu, 21 Jan 2016 08:47:43 -0600 Subject: [PATCH 037/367] Making the app config data more generic --- src/app/app.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/app/app.js b/src/app/app.js index 05709cd8..644598a9 100644 --- a/src/app/app.js +++ b/src/app/app.js @@ -30,12 +30,12 @@ 'ui.grid.infiniteScroll' ]) - .constant("appname", "DevCenter") + .constant("appname", "OrderCloud AngularJS Seed") .constant("ocscope", "FullAccess") - .constant("clientid", "0e0450e6-27a0-4093-a6b3-d7cd9ebc2b8f") - .constant("buyerid", "451ORDERCLOUD") - .constant("authurl", "https://testauth.ordercloud.io/oauth/token") - .constant("apiurl", "https://testapi.ordercloud.io") + .constant("clientid", "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX") + .constant("buyerid", "XXXXXXXXXXXXX") + .constant("authurl", "https://auth.ordercloud.io/oauth/token") + .constant("apiurl", "https://api.ordercloud.io") .run( SetBuyerID ) .config( Routing ) From f7552b715a2fe407fdc44e74287338441f45a7e0 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 21 Jan 2016 09:55:27 -0600 Subject: [PATCH 038/367] Fixed the app.js file Removed reference to app.config.js from gulp/scriptTasks.js --- Gulp/scriptTasks.js | 2 +- src/app/app.js | 173 ++++++++++++++++++++++---------------------- 2 files changed, 86 insertions(+), 89 deletions(-) diff --git a/Gulp/scriptTasks.js b/Gulp/scriptTasks.js index 6e92a2ab..f4977c0b 100644 --- a/Gulp/scriptTasks.js +++ b/Gulp/scriptTasks.js @@ -72,7 +72,7 @@ gulp.task('c_m:js', function() { config.build + 'vendor/**/*.js', config.build + 'src/templates-app.js', config.build + 'src/app/app.js', - config.build + 'src/app/app.config.js', + //config.build + 'src/app/app.config.js', config.build + 'src/**/*.js' ]) .pipe(concat('app.js')) diff --git a/src/app/app.js b/src/app/app.js index 644598a9..9f4f644c 100644 --- a/src/app/app.js +++ b/src/app/app.js @@ -1,97 +1,94 @@ -(function ( window, angular, undefined ) { - 'use strict'; +angular.module( 'orderCloud', [ + 'templates-app', + 'ngSanitize', + 'ngAnimate', + 'ngMessages', + 'ngTouch', + 'ui.tree', + 'ui.router', + 'ui.bootstrap', + 'orderCloud.sdk', + 'toastr', + 'jcs-autoValidate', + 'ordercloud-infinite-scroll', + 'ordercloud-buyer-select', + 'ordercloud-search', + 'ordercloud-assignment-helpers', + 'ordercloud-paging-helpers', + 'ordercloud-auto-id', + 'ordercloud-impersonation', + 'ordercloud-current-order', + 'ordercloud-address', + 'ordercloud-lineitems', + 'ui.grid', + 'ui.grid.infiniteScroll' + ]) - SetBuyerID.$inject = ["BuyerID", "buyerid"]; - Routing.$inject = ["$urlRouterProvider", "$urlMatcherFactoryProvider"]; - ErrorHandling.$inject = ["$provide"]; - AppCtrl.$inject = ["$rootScope", "$state", "appname", "Auth", "BuyerID", "ImpersonationService"];angular.module( 'orderCloud', [ - 'templates-app', - 'ngSanitize', - 'ngAnimate', - 'ngMessages', - 'ngTouch', - 'ui.tree', - 'ui.router', - 'ui.bootstrap', - 'orderCloud.sdk', - 'toastr', - 'jcs-autoValidate', - 'ordercloud-infinite-scroll', - 'ordercloud-buyer-select', - 'ordercloud-search', - 'ordercloud-assignment-helpers', - 'ordercloud-paging-helpers', - 'ordercloud-auto-id', - 'ordercloud-impersonation', - 'ordercloud-current-order', - 'ordercloud-address', - 'ordercloud-lineitems', - 'ui.grid', - 'ui.grid.infiniteScroll' - ]) + .run( SetBuyerID ) + .config( Routing ) + .config( ErrorHandling ) + .controller( 'AppCtrl', AppCtrl ) + .constant("appname", "OrderCloud AngularJS Seed") - .constant("appname", "OrderCloud AngularJS Seed") - .constant("ocscope", "FullAccess") - .constant("clientid", "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX") - .constant("buyerid", "XXXXXXXXXXXXX") - .constant("authurl", "https://auth.ordercloud.io/oauth/token") - .constant("apiurl", "https://api.ordercloud.io") + //App Constants used by the OrderCloud SDK + .constant("ocscope", "FullAccess") + .constant("clientid", "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX") + .constant("buyerid", "XXXXXXXXXX") - .run( SetBuyerID ) - .config( Routing ) - .config( ErrorHandling ) - .controller( 'AppCtrl', AppCtrl ) - ; + //OrderCloud Base URLs + .constant("authurl", "https://auth.ordercloud.io/oauth/token") + .constant("apiurl", "https://api.ordercloud.io") - function SetBuyerID( BuyerID, buyerid ) { - BuyerID.Get() ? angular.noop() : BuyerID.Set(buyerid); - } +; - function Routing( $urlRouterProvider, $urlMatcherFactoryProvider ) { - $urlMatcherFactoryProvider.strictMode(false); - $urlRouterProvider.otherwise( '/home' ); - //$locationProvider.html5Mode(true); - } +function SetBuyerID( BuyerID, buyerid ) { + BuyerID.Get() ? angular.noop() : BuyerID.Set(buyerid); +} - function ErrorHandling( $provide ) { - handler.$inject = ["$delegate", "$injector"]; - $provide.decorator('$exceptionHandler', handler); +function Routing( $urlRouterProvider, $urlMatcherFactoryProvider ) { + $urlMatcherFactoryProvider.strictMode(false); + $urlRouterProvider.otherwise( '/home' ); + //$locationProvider.html5Mode(true); +} - function handler( $delegate, $injector ) { - return function( ex, cause ) { - $delegate(ex, cause); - $injector.get('toastr').error(ex.data ? (ex.data.error || (ex.data.Errors ? ex.data.Errors[0].Message : ex.data)) : ex.message, 'Error'); - }; - } - } +function ErrorHandling( $provide ) { + $provide.decorator('$exceptionHandler', handler); - function AppCtrl( $rootScope, $state, appname, Auth, BuyerID, ImpersonationService ) { - var vm = this; - vm.name = appname; - vm.title = appname; - vm.showLeftNav = true; - vm.toggleLeftNav = function() { - vm.showLeftNav = !vm.showLeftNav; + function handler( $delegate, $injector ) { + return function( ex, cause ) { + $delegate(ex, cause); + $injector.get('toastr').error(ex.data ? (ex.data.error || (ex.data.Errors ? ex.data.Errors[0].Message : ex.data)) : ex.message, 'Error'); }; - vm.logout = function() { - Auth.RemoveToken(); - BuyerID.Set(null); - ImpersonationService.StopImpersonating(); - $state.go('login'); - }; - vm.EndImpersonation = ImpersonationService.StopImpersonating; - vm.isImpersonating = !!Auth.GetImpersonating(); - $rootScope.$on('ImpersonationStarted', function() { - vm.isImpersonating = true; - }); - $rootScope.$on('ImpersonationStopped', function() { - vm.isImpersonating = false; - }); - $rootScope.$on('$stateChangeSuccess', function(e, toState) { - if (toState.data && toState.data.componentName) { - vm.title = appname + ' - ' + toState.data.componentName - } else { - vm.title = appname; - } - }); - }})( window, window.angular ); + } +} + +function AppCtrl( $rootScope, $state, appname, Auth, BuyerID, ImpersonationService ) { + var vm = this; + vm.name = appname; + vm.title = appname; + vm.showLeftNav = true; + vm.toggleLeftNav = function() { + vm.showLeftNav = !vm.showLeftNav; + }; + vm.logout = function() { + Auth.RemoveToken(); + BuyerID.Set(null); + ImpersonationService.StopImpersonating(); + $state.go('login'); + }; + vm.EndImpersonation = ImpersonationService.StopImpersonating; + vm.isImpersonating = !!Auth.GetImpersonating(); + $rootScope.$on('ImpersonationStarted', function() { + vm.isImpersonating = true; + }); + $rootScope.$on('ImpersonationStopped', function() { + vm.isImpersonating = false; + }); + $rootScope.$on('$stateChangeSuccess', function(e, toState) { + if (toState.data && toState.data.componentName) { + vm.title = appname + ' - ' + toState.data.componentName + } else { + vm.title = appname; + } + }); +} \ No newline at end of file From 49fd3e1cb03fba58c9cb3e01efef3e73b81de0fb Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 21 Jan 2016 16:29:37 -0600 Subject: [PATCH 039/367] Updated default Seed components to use the new SDK pattern IMPORTANT NOTE: You must change the module name of the ordercloud-ng-sdk vendor file to orderCloud.newsdk Login, Base, Account are all updated and tested --- bower.json | 3 +- src/app/account/account.js | 16 +++--- src/app/account/tests/account.spec.js | 71 +++++++++++++++++++++++---- src/app/app.js | 32 ++++++------ src/app/base/base.js | 28 ++++------- src/app/base/tests/base.spec.js | 32 ++++++------ src/app/login/login.js | 19 ++++--- src/app/login/tests/login.spec.js | 49 +++++++++--------- 8 files changed, 151 insertions(+), 99 deletions(-) diff --git a/bower.json b/bower.json index 525c6585..f76f5caf 100644 --- a/bower.json +++ b/bower.json @@ -19,6 +19,7 @@ "angular-bootstrap": "~0.14.3", "angular-ui-tree": "~2.10.0", "ordercloud-angular-sdk": "~1.0.3", - "angular-ui-grid": "~3.0.7" + "angular-ui-grid": "~3.0.7", + "ordercloud-ng-sdk": "~1.0.0" } } diff --git a/src/app/account/account.js b/src/app/account/account.js index 3ce7cecf..62e2f044 100644 --- a/src/app/account/account.js +++ b/src/app/account/account.js @@ -25,7 +25,7 @@ function AccountConfig( $stateProvider ) { }) } -function AccountService( $q, $uibModal, Credentials, AdminUsers ) { +function AccountService( $q, $uibModal, OrderCloud ) { var service = { Update: _update, ChangePassword: _changePassword @@ -35,7 +35,7 @@ function AccountService( $q, $uibModal, Credentials, AdminUsers ) { var deferred = $q.defer(); function updateUser() { - AdminUsers.Update(currentProfile.ID, newProfile) + OrderCloud.AdminUsers.Update(currentProfile.ID, newProfile) .then(function(data) { deferred.resolve(data); }) @@ -44,20 +44,18 @@ function AccountService( $q, $uibModal, Credentials, AdminUsers ) { }) } - var modalInstance = $uibModal.open({ + $uibModal.open({ animation: true, templateUrl: 'account/templates/confirmPassword.modal.tpl.html', controller: 'ConfirmPasswordCtrl', controllerAs: 'confirmPassword', size: 'sm' - }); - - modalInstance.result.then(function(password) { + }).result.then(function(password) { var checkPasswordCredentials = { Username: currentProfile.Username, Password: password }; - Credentials.Get(checkPasswordCredentials).then( + OrderCloud.Auth.GetToken(checkPasswordCredentials).then( function() { updateUser(); }).catch(function( ex ) { @@ -80,13 +78,13 @@ function AccountService( $q, $uibModal, Credentials, AdminUsers ) { function changePassword() { currentUser.Password = currentUser.NewPassword; - AdminUsers.Update(currentUser.ID, currentUser) + OrderCloud.AdminUsers.Update(currentUser.ID, currentUser) .then(function() { deferred.resolve(); }); } - Credentials.Get(checkPasswordCredentials).then( + OrderCloud.Auth.GetToken(checkPasswordCredentials).then( function() { changePassword(); }).catch(function( ex ) { diff --git a/src/app/account/tests/account.spec.js b/src/app/account/tests/account.spec.js index f5f16798..b5e9f9dc 100644 --- a/src/app/account/tests/account.spec.js +++ b/src/app/account/tests/account.spec.js @@ -1,10 +1,11 @@ describe('Component: Account', function() { var scope, q, - account; + account, + accountFactory; beforeEach(module('orderCloud')); - beforeEach(module('orderCloud.sdk')); - beforeEach(inject(function($q, $rootScope) { + beforeEach(module('orderCloud.newsdk')); + beforeEach(inject(function($q, $rootScope, AccountService) { q = $q; scope = $rootScope.$new(); account = { @@ -17,8 +18,60 @@ describe('Component: Account', function() { TermsAccepted: true, Active: true }; + accountFactory = AccountService; })); + describe('Factory: AccountService', function() { + var oc; + beforeEach(inject(function(OrderCloud) { + oc = OrderCloud; + var defer = q.defer(); + defer.resolve(); + spyOn(oc.Auth, 'GetToken').and.returnValue(defer.promise); + spyOn(oc.AdminUsers, 'Update').and.returnValue(defer.promise); + })); + + describe('Update', function() { + var uibModal, + currentProfile = { + ID: 'FAKEID', + Username: 'FAKEUSERNAME' + }, + newProfile = { + Username: 'FAKENEWPROFILE' + }; + beforeEach(inject(function($uibModal) { + uibModal = $uibModal; + })); + it ('should open a uibModal, confirm their password, and update the user', function() { + var defer = q.defer(); + defer.resolve('FAKEPASSWORD'); + spyOn(uibModal, 'open').and.returnValue({result: defer.promise}); + accountFactory.Update(currentProfile, newProfile); + expect(uibModal.open).toHaveBeenCalled(); + scope.$digest(); + expect(oc.Auth.GetToken).toHaveBeenCalledWith({Username: 'FAKEUSERNAME', Password: 'FAKEPASSWORD'}); + expect(oc.AdminUsers.Update).toHaveBeenCalledWith(currentProfile.ID, newProfile); + }) + }); + + describe('ChangePassword', function() { + var currentUser = { + ID: 'FAKEID', + Username: 'FAKEUSERNAME', + CurrentPassword: 'FAKECURRENTPASSWORD', + NewPassword: 'FAKENEWPASSWORD' + }; + it ('should check their password and update the user', function() { + accountFactory.ChangePassword(currentUser); + expect(oc.Auth.GetToken).toHaveBeenCalledWith({Username:currentUser.Username, Password:currentUser.CurrentPassword}); + scope.$digest(); + currentUser.Password = currentUser.NewPassword; + expect(oc.AdminUsers.Update).toHaveBeenCalledWith(currentUser.ID, currentUser); + }) + }); + }); + describe('Controller: AccountCtrl', function() { var accountCtrl, currentProfile; beforeEach(inject(function($state, $controller) { @@ -30,16 +83,16 @@ describe('Component: Account', function() { })); describe('update', function() { - beforeEach(inject(function(AccountService) { + beforeEach(inject(function() { accountCtrl.profile = account; currentProfile = {}; var defer = q.defer(); defer.resolve(account); - spyOn(AccountService, 'Update').and.returnValue(defer.promise); + spyOn(accountFactory, 'Update').and.returnValue(defer.promise); accountCtrl.update(); })); it ('should call the Accounts Update method', inject(function(AccountService) { - expect(AccountService.Update).toHaveBeenCalledWith(currentProfile, account); + expect(accountFactory.Update).toHaveBeenCalledWith(currentProfile, account); })); }); @@ -106,15 +159,15 @@ describe('Component: Account', function() { spyOn($state, 'go').and.returnValue(true); })); describe('changePassword', function() { - beforeEach(inject(function(AccountService) { + beforeEach(inject(function() { changePasswordCtrl.currentUser = account; var defer = q.defer(); defer.resolve(account); - spyOn(AccountService, 'ChangePassword').and.returnValue(defer.promise); + spyOn(accountFactory, 'ChangePassword').and.returnValue(defer.promise); changePasswordCtrl.changePassword(); })); it ('should call the Accounts ChangePassword method', inject(function(AccountService) { - expect(AccountService.ChangePassword).toHaveBeenCalledWith(changePasswordCtrl.currentUser); + expect(accountFactory.ChangePassword).toHaveBeenCalledWith(changePasswordCtrl.currentUser); })); }); diff --git a/src/app/app.js b/src/app/app.js index 9f4f644c..49d60864 100644 --- a/src/app/app.js +++ b/src/app/app.js @@ -8,6 +8,7 @@ angular.module( 'orderCloud', [ 'ui.router', 'ui.bootstrap', 'orderCloud.sdk', + 'orderCloud.newsdk', 'toastr', 'jcs-autoValidate', 'ordercloud-infinite-scroll', @@ -32,17 +33,17 @@ angular.module( 'orderCloud', [ //App Constants used by the OrderCloud SDK .constant("ocscope", "FullAccess") - .constant("clientid", "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX") - .constant("buyerid", "XXXXXXXXXX") + .constant("clientid", "0854871D-1492-42CD-AC95-C31139ACC916") + .constant("buyerid", "Buyer001") //OrderCloud Base URLs - .constant("authurl", "https://auth.ordercloud.io/oauth/token") - .constant("apiurl", "https://api.ordercloud.io") + .constant("authurl", "http://core.four51.com:11629/oauth/token") + .constant("apiurl", "http://core.four51.com:9002") ; -function SetBuyerID( BuyerID, buyerid ) { - BuyerID.Get() ? angular.noop() : BuyerID.Set(buyerid); +function SetBuyerID( OrderCloud, buyerid ) { + OrderCloud.BuyerID.Get() ? angular.noop() : OrderCloud.BuyerID.Set(buyerid); } function Routing( $urlRouterProvider, $urlMatcherFactoryProvider ) { @@ -62,28 +63,23 @@ function ErrorHandling( $provide ) { } } -function AppCtrl( $rootScope, $state, appname, Auth, BuyerID, ImpersonationService ) { +function AppCtrl( $rootScope, $state, appname, OrderCloud ) { var vm = this; vm.name = appname; vm.title = appname; vm.showLeftNav = true; + vm.toggleLeftNav = function() { vm.showLeftNav = !vm.showLeftNav; }; + vm.logout = function() { - Auth.RemoveToken(); - BuyerID.Set(null); - ImpersonationService.StopImpersonating(); + OrderCloud.Auth.RemoveToken(); + OrderCloud.Auth.RemoveImpersonationToken(); + OrderCloud.BuyerID.Set(null); $state.go('login'); }; - vm.EndImpersonation = ImpersonationService.StopImpersonating; - vm.isImpersonating = !!Auth.GetImpersonating(); - $rootScope.$on('ImpersonationStarted', function() { - vm.isImpersonating = true; - }); - $rootScope.$on('ImpersonationStopped', function() { - vm.isImpersonating = false; - }); + $rootScope.$on('$stateChangeSuccess', function(e, toState) { if (toState.data && toState.data.componentName) { vm.title = appname + ' - ' + toState.data.componentName diff --git a/src/app/base/base.js b/src/app/base/base.js index ef3ae2da..817ec3cb 100644 --- a/src/app/base/base.js +++ b/src/app/base/base.js @@ -31,27 +31,19 @@ function BaseConfig( $stateProvider ) { } }, resolve: { - CurrentUser: function($q, $state, Auth, BuyerID, Me) { + CurrentUser: function($q, $state, OrderCloud) { var dfd = $q.defer(); - Auth.IsAuthenticated() - .then(function() { - Me.Get() - .then(function(data) { - dfd.resolve(data); - }) - .catch(function(){ - Auth.RemoveToken(); - BuyerID.Set(null); - $state.go('login'); - dfd.resolve(); - }) + OrderCloud.Me.Get() + .then(function(data) { + dfd.resolve(data); }) - .catch(function() { - BuyerID.Set(null); + .catch(function(){ + OrderCloud.Auth.RemoveToken(); + OrderCloud.Auth.RemoveImpersonationToken(); + OrderCloud.BuyerID.Set(null); $state.go('login'); dfd.resolve(); - }) - ; + }); return dfd.promise; }, ComponentList: function($state, $q, Underscore) { @@ -86,7 +78,7 @@ function BaseConfig( $stateProvider ) { }); } -function BaseController( CurrentUser ) { +function BaseController(CurrentUser) { var vm = this; vm.currentUser = CurrentUser; } diff --git a/src/app/base/tests/base.spec.js b/src/app/base/tests/base.spec.js index a2cbdb2a..018006ab 100644 --- a/src/app/base/tests/base.spec.js +++ b/src/app/base/tests/base.spec.js @@ -1,39 +1,43 @@ describe('Component: Base', function() { var q, - scope; + scope, + oc; beforeEach(module('orderCloud')); - beforeEach(module('orderCloud.sdk')); + beforeEach(module('orderCloud.newsdk')); beforeEach(module('ui.router')); - beforeEach(inject(function($q, $rootScope) { + beforeEach(inject(function($q, $rootScope, OrderCloud) { q = $q; scope = $rootScope.$new(); + oc = OrderCloud; })); describe('State: Base', function() { var state; - beforeEach(inject(function($state, Me, BuyerID) { + beforeEach(inject(function($state) { state = $state.get('base'); var dfd = q.defer(); dfd.resolve(true); - spyOn(Me, 'Get').and.returnValue(dfd.promise); - spyOn(BuyerID, 'Set').and.callThrough(); + spyOn(oc.BuyerID, 'Set').and.callThrough(); + spyOn(oc.Auth, 'RemoveToken').and.callThrough(); + spyOn(oc.Auth, 'RemoveImpersonationToken').and.callThrough(); spyOn($state, 'go').and.returnValue(true); })); //Skipped this test because Base now resolves with Auth.IsAuthenticated and THEN do a Me.Get() to confirm the token will work - it('should resolve CurrentUser', inject(function ($injector, Me, Auth) { + it('should resolve CurrentUser', inject(function ($injector) { var dfd = q.defer(); - dfd.resolve(true); - spyOn(Auth, 'IsAuthenticated').and.returnValue(dfd.promise); + dfd.resolve('TEST USER'); + spyOn(oc.Me, 'Get').and.returnValue(dfd.promise); $injector.invoke(state.resolve.CurrentUser); - scope.$digest(); - expect(Me.Get).toHaveBeenCalled(); + expect(oc.Me.Get).toHaveBeenCalled(); })); - it('should return to login if unauthenticated', inject(function($injector, Auth, BuyerID, $state) { + it('should remove Auth tokens, set BuyerID to null, and return to login if unauthenticated', inject(function($injector, $state) { var dfd = q.defer(); dfd.reject(true); - spyOn(Auth, 'IsAuthenticated').and.returnValue(dfd.promise); + spyOn(oc.Me, 'Get').and.returnValue(dfd.promise); $injector.invoke(state.resolve.CurrentUser); scope.$digest(); - expect(BuyerID.Set).toHaveBeenCalledWith(null); + expect(oc.Auth.RemoveToken).toHaveBeenCalled(); + expect(oc.Auth.RemoveImpersonationToken).toHaveBeenCalled(); + expect(oc.BuyerID.Set).toHaveBeenCalledWith(null); expect($state.go).toHaveBeenCalledWith('login'); })); it ('should resolve ComponentsList', inject(function($injector) { diff --git a/src/app/login/login.js b/src/app/login/login.js index 6008f2f8..29bbf54c 100644 --- a/src/app/login/login.js +++ b/src/app/login/login.js @@ -16,7 +16,7 @@ function LoginConfig( $stateProvider ) { }) } -function LoginService( $q, $window, PasswordResets, clientid ) { +function LoginService( $q, $window, OrderCloud, clientid ) { return { SendVerificationCode: _sendVerificationCode, ResetPassword: _resetPassword @@ -31,7 +31,7 @@ function LoginService( $q, $window, PasswordResets, clientid ) { URL: encodeURIComponent($window.location.href) + '{0}' }; - PasswordResets.SendVerificationCode(passwordResetRequest) + OrderCloud.PasswordResets.SendVerificationCode(passwordResetRequest) .then(function() { deferred.resolve(); }) @@ -51,7 +51,7 @@ function LoginService( $q, $window, PasswordResets, clientid ) { Password: resetPasswordCredentials.NewPassword }; - PasswordResets.ResetPassword(verificationCode, passwordReset). + OrderCloud.PasswordResets.ResetPassword(verificationCode, passwordReset). then(function() { deferred.resolve(); }) @@ -63,8 +63,12 @@ function LoginService( $q, $window, PasswordResets, clientid ) { } } -function LoginController( $state, $stateParams, $exceptionHandler, LoginService, Credentials, BuyerID, buyerid, ImpersonationService ) { +function LoginController( $state, $stateParams, $exceptionHandler, OrderCloud, LoginService, buyerid ) { var vm = this; + vm.credentials = { + Username: null, + Password: null + }; vm.token = $stateParams.token; vm.form = vm.token ? 'reset' : 'login'; vm.setForm = function(form) { @@ -72,10 +76,9 @@ function LoginController( $state, $stateParams, $exceptionHandler, LoginService, }; vm.submit = function() { - Credentials.Get( vm.credentials ) - .then(function() { - BuyerID.Get() ? angular.noop() : BuyerID.Set(buyerid); - ImpersonationService.StopImpersonating(); + OrderCloud.Auth.GetToken(vm.credentials) + .then(function(data) { + OrderCloud.Auth.SetToken(data['access_token']); $state.go('home'); }) .catch(function(ex) { diff --git a/src/app/login/tests/login.spec.js b/src/app/login/tests/login.spec.js index 7cb55eb3..9ab8fac6 100644 --- a/src/app/login/tests/login.spec.js +++ b/src/app/login/tests/login.spec.js @@ -2,23 +2,23 @@ describe('Component: Login', function() { var scope, q, loginFactory, + oc, credentials = { Username: 'notarealusername', Password: 'notarealpassword' }; beforeEach(module('orderCloud')); - beforeEach(module('orderCloud.sdk')); - beforeEach(inject(function($q, $rootScope, LoginService) { + beforeEach(module('orderCloud.newsdk')); + beforeEach(inject(function($q, $rootScope, OrderCloud, LoginService) { q = $q; scope = $rootScope.$new(); - loginFactory = LoginService + loginFactory = LoginService; + oc = OrderCloud; })); describe('Factory: LoginService', function() { - var PasswordResetsFactory, - client_id; - beforeEach(inject(function(PasswordResets, clientid) { - PasswordResetsFactory = PasswordResets; + var client_id; + beforeEach(inject(function(clientid) { client_id = clientid; })); describe('SendVerificationCode', function() { @@ -32,11 +32,11 @@ describe('Component: Login', function() { }; var deferred = q.defer(); deferred.resolve(true); - spyOn(PasswordResetsFactory, 'SendVerificationCode').and.returnValue(deferred.promise); + spyOn(oc.PasswordResets, 'SendVerificationCode').and.returnValue(deferred.promise); loginFactory.SendVerificationCode(email); })); it ('should call the SendVerificationCode method of PasswordResets with the reset request object', function(){ - expect(PasswordResetsFactory.SendVerificationCode).toHaveBeenCalledWith(passwordResetRequest); + expect(oc.PasswordResets.SendVerificationCode).toHaveBeenCalledWith(passwordResetRequest); }); }); @@ -49,26 +49,28 @@ describe('Component: Login', function() { beforeEach(inject(function() { var deferred = q.defer(); deferred.resolve(true); - spyOn(PasswordResetsFactory, 'ResetPassword').and.returnValue(deferred.promise); + spyOn(oc.PasswordResets, 'ResetPassword').and.returnValue(deferred.promise); loginFactory.ResetPassword(creds, 'code'); })); it ('should call the ResetPassword method of the PasswordResets Service with a code and credentials', function() { - expect(PasswordResetsFactory.ResetPassword).toHaveBeenCalledWith('code', {ClientID: client_id, Username: creds.ResetUsername, Password: creds.NewPassword}); + expect(oc.PasswordResets.ResetPassword).toHaveBeenCalledWith('code', {ClientID: client_id, Username: creds.ResetUsername, Password: creds.NewPassword}); }); }); }); describe('Controller: LoginCtrl', function() { - var loginCtrl; - beforeEach(inject(function($controller, $state, Credentials, LoginService) { - spyOn($state, 'go').and.callThrough(); + var loginCtrl, + fakeToken = 'XXXX-XXXX-XXXX'; + beforeEach(inject(function($controller, $state) { + spyOn($state, 'go').and.returnValue(true); var dfd = q.defer(); - dfd.resolve(true); - spyOn(Credentials, 'Get').and.returnValue(dfd.promise); + dfd.resolve({access_token: fakeToken}); + spyOn(oc.Auth, 'GetToken').and.returnValue(dfd.promise); + spyOn(oc.Auth, 'SetToken').and.returnValue(dfd.promise); loginCtrl = $controller('LoginCtrl', { $scope: scope, - LoginService: LoginService, - Credentials: Credentials + LoginService: loginFactory, + oc: oc }); })); @@ -89,12 +91,15 @@ describe('Component: Login', function() { beforeEach(function() { loginCtrl.credentials = credentials; loginCtrl.submit(); + scope.$digest(); + }); + it ('should call the GetToken method from the Auth Service with credentials', function() { + expect(oc.Auth.GetToken).toHaveBeenCalledWith(credentials); + }); + it ('should call the SetToken method from the Auth Service', function() { + expect(oc.Auth.SetToken).toHaveBeenCalledWith(fakeToken); }); - it ('should call the Credentials Get method with credentials', inject(function(Credentials) { - expect(Credentials.Get).toHaveBeenCalledWith(credentials); - })); it ('should enter the home state', inject(function($state) { - scope.$digest(); expect($state.go).toHaveBeenCalledWith('home'); })); }); From 102470f4254cf27e351b5b3900ebbcd9b4bf6f97 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 21 Jan 2016 16:37:48 -0600 Subject: [PATCH 040/367] Common Directory Update: buyer-select Using new sdk --- .../buyer-select/ordercloud-buyer-selected.js | 12 +++--- .../buyer-select/tests/buyer-select.spec.js | 38 +++++++++---------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/app/common/buyer-select/ordercloud-buyer-selected.js b/src/app/common/buyer-select/ordercloud-buyer-selected.js index 685c9445..2177fdc6 100644 --- a/src/app/common/buyer-select/ordercloud-buyer-selected.js +++ b/src/app/common/buyer-select/ordercloud-buyer-selected.js @@ -15,28 +15,28 @@ function SelectBuyerDirective() { } } -function SelectBuyerController($state, Buyers, BuyerID) { +function SelectBuyerController($state, OrderCloud) { var vm = this; - Buyers.List().then(function(data) { + OrderCloud.Buyers.List().then(function(data) { vm.BuyerList = data; }); - Buyers.Get(BuyerID.Get()).then(function(data) { + OrderCloud.Buyers.Get(OrderCloud.BuyerID.Get()).then(function(data) { vm.selectedBuyer = data; }); vm.ChangeBuyer = function(buyer) { - Buyers.Get(buyer.ID).then(function(data) { + OrderCloud.Buyers.Get(buyer.ID).then(function(data) { vm.selectedBuyer = data; - BuyerID.Set(data.ID); + OrderCloud.BuyerID.Set(data.ID); $state.reload($state.current); }); }; vm.pagingfunction = function() { if (vm.BuyerList.Meta.Page <= vm.BuyerList.Meta.TotalPages) { - Buyers.List(null, vm.BuyerList.Meta.Page + 1, vm.BuyerList.Meta.PageSize) + OrderCloud.Buyers.List(null, vm.BuyerList.Meta.Page + 1, vm.BuyerList.Meta.PageSize) .then(function(data) { vm.BuyerList.Meta = data.Meta; vm.BuyerList.Items = [].concat(vm.BuyerList.Items, data.Items); diff --git a/src/app/common/buyer-select/tests/buyer-select.spec.js b/src/app/common/buyer-select/tests/buyer-select.spec.js index 7299ffdc..00593b0a 100644 --- a/src/app/common/buyer-select/tests/buyer-select.spec.js +++ b/src/app/common/buyer-select/tests/buyer-select.spec.js @@ -1,32 +1,32 @@ describe('Buyer-Select:', function() { var q, scope, - buyers; + oc; beforeEach(module('orderCloud')); - beforeEach(module('orderCloud.sdk')); - beforeEach(inject(function($q, $rootScope, Buyers){ + beforeEach(module('orderCloud.newsdk')); + beforeEach(inject(function($q, $rootScope, OrderCloud){ q = $q; scope = $rootScope.$new(); - buyers = Buyers; + oc = OrderCloud; })); describe('Directive: ordercloudSelectBuyer', function() { var element; - beforeEach(inject(function($compile, Buyers) { + beforeEach(inject(function($compile) { var deferred1 = q.defer(); var deferred2 = q.defer(); deferred1.resolve('Buyer'); deferred2.resolve('Buyers'); - spyOn(Buyers, 'Get').and.returnValue(deferred1.promise); - spyOn(Buyers, 'List').and.returnValue(deferred2.promise); + spyOn(oc.Buyers, 'Get').and.returnValue(deferred1.promise); + spyOn(oc.Buyers, 'List').and.returnValue(deferred2.promise); element = $compile('')(scope); scope.$digest(); })); - it('should initialize the controller', inject(function(BuyerID) { - expect(buyers.List).toHaveBeenCalled(); - expect(buyers.Get).toHaveBeenCalledWith(BuyerID.Get()); + it('should initialize the controller', function() { + expect(oc.Buyers.List).toHaveBeenCalled(); + expect(oc.Buyers.Get).toHaveBeenCalledWith(oc.BuyerID.Get()); expect(element.isolateScope().selectBuyer).not.toBe(undefined); - })); + }); it('should initialize a list of buyers', function() { expect(element.isolateScope().selectBuyer.BuyerList).toBe('Buyers'); }); @@ -55,15 +55,15 @@ describe('Buyer-Select:', function() { 'buyer2' ] }; - beforeEach(inject(function($controller, $state, Buyers, BuyerID) { + beforeEach(inject(function($controller, $state) { var deferred1 = q.defer(); var deferred2 = q.defer(); deferred1.resolve(mock_buyer); deferred2.resolve(mock_list); - spyOn(Buyers, 'Get').and.returnValue(deferred1.promise); - spyOn(Buyers, 'List').and.returnValue(deferred2.promise); + spyOn(oc.Buyers, 'Get').and.returnValue(deferred1.promise); + spyOn(oc.Buyers, 'List').and.returnValue(deferred2.promise); spyOn($state, 'reload').and.returnValue(true); - spyOn(BuyerID, 'Set').and.returnValue(true); + spyOn(oc.BuyerID, 'Set').and.returnValue(true); buyerSelectCtrl = $controller('SelectBuyerCtrl', { $scope: scope }); @@ -74,13 +74,13 @@ describe('Buyer-Select:', function() { scope.$digest(); }); it('should called the Get method of the Buyers service', function() { - expect(buyers.Get).toHaveBeenCalledWith(mock_buyer.ID); + expect(oc.Buyers.Get).toHaveBeenCalledWith(mock_buyer.ID); }); it('should change the selected buyer to the one passed in', function() { expect(buyerSelectCtrl.selectedBuyer).toBe(mock_buyer); }); it('should call the Set method of BuyerID to change the saved buyer ID value stored in the cookies', inject(function(BuyerID) { - expect(BuyerID.Set).toHaveBeenCalledWith(mock_buyer.ID); + expect(oc.BuyerID.Set).toHaveBeenCalledWith(mock_buyer.ID); })); it('should reload the state', inject(function($state) { expect($state.reload).toHaveBeenCalledWith($state.current); @@ -93,13 +93,13 @@ describe('Buyer-Select:', function() { }); it('should call the List method of Buyers when there are more pages to get', function() { scope.$digest(); - expect(buyers.List).toHaveBeenCalledWith(null, mock_list.Meta.Page + 1, mock_list.Meta.PageSize); + expect(oc.Buyers.List).toHaveBeenCalledWith(null, mock_list.Meta.Page + 1, mock_list.Meta.PageSize); expect(buyerSelectCtrl.BuyerList.Items.length).toBe(4); }); it('should not call the List method when there are no more pages to get', function() { buyerSelectCtrl.BuyerList.Meta.Page = 2; scope.$digest(); - expect(buyers.List).not.toHaveBeenCalledWith(null, mock_list.Meta.Page + 1, mock_list.Meta.PageSize); + expect(oc.Buyers.List).not.toHaveBeenCalledWith(null, mock_list.Meta.Page + 1, mock_list.Meta.PageSize); }); }); }); From eb8941653c1ebaf85f2ce6f75bf664b7cb766dc8 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 21 Jan 2016 17:00:26 -0600 Subject: [PATCH 041/367] Common Directory Update: helper-factories/paging-helpers.js Updated and tested TODOs on current-order and files --- src/app/common/current-order/current-order.js | 2 +- src/app/common/files/files.js | 2 +- .../common/helper-factories/paging-helpers.js | 4 ++-- .../tests/paging-helpers.spec.js | 20 ++++++++----------- 4 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/app/common/current-order/current-order.js b/src/app/common/current-order/current-order.js index 73948564..7cdccbbd 100644 --- a/src/app/common/current-order/current-order.js +++ b/src/app/common/current-order/current-order.js @@ -3,7 +3,7 @@ angular.module('ordercloud-current-order', []) .factory('CurrentOrder', CurrentOrderService) ; - +//TODO: CurrentOrderService needs to be updated to NEW SDK / remove the need for ImpersonationService function CurrentOrderService($q, appname, ImpersonationService, $localForage, Auth, Orders, Me) { var StorageName = appname + '.CurrentOrderID'; return { diff --git a/src/app/common/files/files.js b/src/app/common/files/files.js index 860281d9..e1cac304 100644 --- a/src/app/common/files/files.js +++ b/src/app/common/files/files.js @@ -4,7 +4,7 @@ angular.module( 'orderCloud' ) .factory( 'FilesService', FilesService ) .directive( 'ordercloudFileUpload', ordercloudFileUpload) ; - +//TODO: update the New SDK to have a file Upload method similar to how this works. Minus attaching the file info to any XP function fileReader( $q ) { var service = { readAsDataUrl: readAsDataURL diff --git a/src/app/common/helper-factories/paging-helpers.js b/src/app/common/helper-factories/paging-helpers.js index 1b3ccbe0..56a00803 100644 --- a/src/app/common/helper-factories/paging-helpers.js +++ b/src/app/common/helper-factories/paging-helpers.js @@ -4,7 +4,7 @@ angular.module('ordercloud-paging-helpers', ['ordercloud-assignment-helpers']) ; -function PagingHelpers($q, $injector, Assignments) { +function PagingHelpers($q, OrderCloud, Assignments) { return { setSelected: setSelected, paging: pagingFunction @@ -21,7 +21,7 @@ function PagingHelpers($q, $injector, Assignments) { } function pagingFunction(ListObject, ServiceName, AssignmentObjects, AssignmentFunc) { - var Service = $injector.get(ServiceName); + var Service = OrderCloud[ServiceName]; if (Service && ListObject.Meta.Page < ListObject.Meta.TotalPages) { var queue = []; var dfd = $q.defer(); diff --git a/src/app/common/helper-factories/tests/paging-helpers.spec.js b/src/app/common/helper-factories/tests/paging-helpers.spec.js index db2e4bba..72576bb9 100644 --- a/src/app/common/helper-factories/tests/paging-helpers.spec.js +++ b/src/app/common/helper-factories/tests/paging-helpers.spec.js @@ -2,15 +2,17 @@ describe('Factory: Paging', function() { var scope, paging, listArray, - assignmentsArray; + assignmentsArray, + oc; beforeEach(module('orderCloud')); - beforeEach(module('orderCloud.sdk')); + beforeEach(module('orderCloud.newsdk')); beforeEach(module('ordercloud-paging-helpers')); - beforeEach(inject(function($rootScope, Paging) { + beforeEach(inject(function($rootScope, Paging, OrderCloud) { listArray = [{ID: 1}, {ID: 2}, {ID: 3}]; assignmentsArray = [{ID: 2}, {ID: 3}]; scope = $rootScope.$new(); paging= Paging; + oc = OrderCloud; })); it('setSelected should create or update a selected property on the first array if it also exists in the second assignments array', function() { paging.setSelected(listArray, assignmentsArray, 'ID'); @@ -21,7 +23,7 @@ describe('Factory: Paging', function() { objectList, objectAssignmentsList, assignFunc; - beforeEach(inject(function($injector) { + beforeEach(function() { serviceName = 'Products'; objectList = { Meta: { @@ -42,16 +44,10 @@ describe('Factory: Paging', function() { assignFunc = function() { return service.ListAssignments(); }; - service = $injector.get(serviceName); + service = oc[serviceName]; spyOn(service, 'List').and.returnValue(objectList); spyOn(service, 'ListAssignments').and.returnValue(objectAssignmentsList); - spyOn($injector, 'get').and.callThrough(); - })); - it('should be the list service for the service name passed in', inject(function($injector) { - paging.paging(objectList, serviceName); - scope.$digest(); - expect($injector.get).toHaveBeenCalledWith(serviceName) - })); + }); it('should call the List method of the service passed in if page is less than total pages', function() { paging.paging(objectList, serviceName); scope.$digest(); From 0f9ad786ce4e4f67bafba349601ea2ae21b41163 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 21 Jan 2016 17:10:37 -0600 Subject: [PATCH 042/367] Common Directory Update: LineItems and Search now using new SDK Only Search is tested -TODO added to ordercloud-impersonation.js for it's removal --- .../impersonation/ordercloud-impersonation.js | 2 +- src/app/common/lineitems/lineitems.js | 14 +++++++------- src/app/common/search/search.js | 4 ++-- src/app/common/search/tests/search.spec.js | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/app/common/impersonation/ordercloud-impersonation.js b/src/app/common/impersonation/ordercloud-impersonation.js index be849bf6..af9be22e 100644 --- a/src/app/common/impersonation/ordercloud-impersonation.js +++ b/src/app/common/impersonation/ordercloud-impersonation.js @@ -4,7 +4,7 @@ angular.module('ordercloud-impersonation', []) .controller('BuyerUserSelectModalCtrl', ModalController) ; - +//TODO: Consider removing function ImpersonationService(ApiClients, $q, $rootScope, $uibModal, $state, Users, Auth, toastr) { return { DecryptToken: DecryptToken, diff --git a/src/app/common/lineitems/lineitems.js b/src/app/common/lineitems/lineitems.js index 93670358..d3b79ba3 100644 --- a/src/app/common/lineitems/lineitems.js +++ b/src/app/common/lineitems/lineitems.js @@ -5,7 +5,7 @@ angular.module('ordercloud-lineitems', []) ; -function LineItemFactory($q, $state, CurrentOrder, Orders, LineItems, $uibModal, $rootScope, Products, Underscore) { +function LineItemFactory($q, $state, CurrentOrder, OrderCloud, $uibModal, $rootScope, Underscore) { return { SpecConvert: SpecConverter, RemoveItem: DeleteLineItem, @@ -16,13 +16,13 @@ function LineItemFactory($q, $state, CurrentOrder, Orders, LineItems, $uibModal, }; function DeleteLineItem(Order, LineItem) { - LineItems.Delete(Order.ID, LineItem.ID) + OrderCloud.LineItems.Delete(Order.ID, LineItem.ID) .then(function() { // If all line items are removed delete the order. - LineItems.List(Order.ID) + OrderCloud.List(Order.ID) .then(function(data) { if (!data.Items.length) { - Orders.Delete(Order.ID); + OrderCloud.Orders.Delete(Order.ID); CurrentOrder.Remove(); } $state.reload(); @@ -32,7 +32,7 @@ function LineItemFactory($q, $state, CurrentOrder, Orders, LineItems, $uibModal, function UpdateQuantity(Order, LineItem) { if (LineItem.Quantity > 0) { - LineItems.Patch(Order.ID, LineItem.ID, {Quantity: LineItem.Quantity}) + OrderCloud.LineItems.Patch(Order.ID, LineItem.ID, {Quantity: LineItem.Quantity}) .then(function() { $rootScope.$broadcast('LineItemQuantityUpdated', LineItem.ID); }); @@ -49,7 +49,7 @@ function LineItemFactory($q, $state, CurrentOrder, Orders, LineItems, $uibModal, var dfd = $q.defer(); var queue = []; angular.forEach(productIDs, function(productid) { - queue.push(Products.Get(productid)); + queue.push(OrderCloud.Products.Get(productid)); }); $q.all(queue) .then(function(results) { @@ -72,7 +72,7 @@ function LineItemFactory($q, $state, CurrentOrder, Orders, LineItems, $uibModal, modalInstance.result .then(function(address) { - LineItems.SetShippingAddress(Order.ID, LineItem.ID, address) + OrderCloud.LineItems.SetShippingAddress(Order.ID, LineItem.ID, address) .then(function() { $rootScope.$broadcast('LineItemShippingUpdated', LineItem.ID); }); diff --git a/src/app/common/search/search.js b/src/app/common/search/search.js index 4ca36a05..b79200b8 100644 --- a/src/app/common/search/search.js +++ b/src/app/common/search/search.js @@ -21,12 +21,12 @@ function ordercloudSearch () { } } -function ordercloudSearchCtrl($timeout, $scope, $injector, TrackSearch) { +function ordercloudSearchCtrl($timeout, $scope, OrderCloud, TrackSearch) { $scope.searchTerm = null; if ($scope.servicename) { var var_name = $scope.servicename.replace(/([a-z])([A-Z])/g, '$1 $2'); $scope.placeholder = "Search " + var_name + '...'; - var Service = $injector.get($scope.servicename); + var Service = OrderCloud[$scope.servicename]; } var searching; $scope.$watch('searchTerm', function(n,o) { diff --git a/src/app/common/search/tests/search.spec.js b/src/app/common/search/tests/search.spec.js index 084d9550..c5b9ff5d 100644 --- a/src/app/common/search/tests/search.spec.js +++ b/src/app/common/search/tests/search.spec.js @@ -22,7 +22,7 @@ describe('Component: Search', function() { }); describe('Controller: ordercloudSearchCtrl', function() { var searchCtrl; - beforeEach(inject(function($controller, $injector, Products) { + beforeEach(inject(function($controller) { scope.servicename = 'Products'; spyOn(scope, '$watch').and.callThrough(); searchCtrl = $controller('ordercloudSearchCtrl', { From 0947c3a6f429e9183ad5b7e95cbe448b489c26b9 Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 25 Jan 2016 14:01:13 -0600 Subject: [PATCH 043/367] Split out build system section of README.md into it's own file in the Gulp directory --- Gulp/README.md | 112 +++++++++++++++++++++++++++++++++++++++++++++++ README.md | 115 +------------------------------------------------ 2 files changed, 113 insertions(+), 114 deletions(-) create mode 100644 Gulp/README.md diff --git a/Gulp/README.md b/Gulp/README.md new file mode 100644 index 00000000..64e5e96e --- /dev/null +++ b/Gulp/README.md @@ -0,0 +1,112 @@ +### The Build System + +The best way to learn about the build system is by familiarizing yourself with +Gulp and then looking through the code, `Gulpfile.js` and the Gulp folder. + But you don't need to do that to be very productive with +`OrderCloud`. What follows in this section is a quick introduction to the +tasks provided and should be plenty to get you started. + +Below is a description of the gulp tasks in the project, sorted by their general purpose +and location within the Gulp directory. + +####Asset Tasks +* `b_m:less` - Compiles all of the app and bower less files into css and moves the compiled file into the temp folder +* `b_m:sass` - Compiles all of the app and bower sass files into css and moves the compiled file into the temp folder +* `b_m:css` - Compiles all of the bower css files (with the exception of the font awesome file as it was already compiled +in `b_m:less`) into one file and autoprefixes the css to run for the last to versions of all the major browsers +* `b_m:appCss` - Compiles all of the app css files into one file and autoprefixes the css to run for the last to versions +of all the major browsers +* `b_m:styles` - Compiles all of the css files in the temp directory into one file, replaces the path to fonts to be correct +for the build directory and renames the file with the version of the app. Places the file in the build folder and injects the +change into browser-sync if it is currently running +* `b_c:styles` - Deletes all of the assets that have been moved over to the build folder and all of the files in the temp folder +* `b_m:assets` - Moves over all asset files (fonts and images) saved in the src/assets directory to the build/assets directory +* `b_m:fonts` - Moves over all fonts saved within the bower dependencies to the build/assets directory +* `b_c:assets` - Deletes all assets files from the build directory +* `c_m:css` - Minifies all css files in the build directory and moves them to the compile folder +* `c_c:css` - Deletes all css files from the compile directory +* `c_m:assets` - Moves over all asset files (fonts and images) from the build folder to the compile folder +* `c_c:assets` - Delete all asset and css files from the compile directory +* `build:styles` - Runs `b_c:styles`, `b_m:less`, `b_m:sass`, `b_m:css`, `b_m:appCss`, `b_m:styles` in order +* `compile:css` - Runs `c_c:css`, `build:styles`, `c_m:css` in order +* `build:assets` - Runs `b_c:assets`, `b_m:assets`, `b_m:fonts` in order +* `compile:assets` - Runs `c_c:assets`, `build:assets`, `c_m:assets` in order + +####General Tasks +* `compile:inject` - Injects the app dependencies into the index.html file for the compiled build +Note: Theere should only be two: `OrderCloud-[Version#].css` and `app.js` +* `build:inject` - Injects the app dependencies into the index.html file for the unminified build +* `masterClean` - Deletes the build, compile, and temp directories. Basically anything built by the gulp +tasks will be removed by this task +* `build` - First runs `master clean`, then runs `build:js_bower`, `build:js`, `build:templateCache`, `build:styles`, `build:assets`, +and lastly runs `build:inject` to create an unminified build of the project +* `compile` - First runs `build`, then runs `compile:js`, `compile:assets`, `compile:css` +and lastly runs `compile:inject` to create a minified build of the project +* `default` - Runs the `compile` task when only `gulp` is typed into the command prompt + +####Script Tasks +* `b_m:js_bower` - Moves the bower dependencies over to the build folder +* `b_c:js_bower` - Deletes bower dependencies form the build folder +* `b_m:js` - Moves over all of the app js files need to run the application (not the ones for unit testing) and +annotates them and wraps each file in an IIFE call. +* `b_c:js` - Deletes all of the javascript files moved over to the build folder except for the templateCache file +* `b_m:templateCache` - Creates an angular templateCache of all the html files (except the index) that +allows for the application to run faster. +* `b_c:templateCache` - Cleans out the compiled template file generated by `b_m:templateCache` +* `c_c:js` - Deletes all js files from the compile directory +* `build:js` - Runs `b_c:js`, and `b_m:js` in order +* `build:js_bower` - Runs `b_c:js_bower`, and `b_m:js_bower` in order +* `build:templateCache` - Runs `b_c:templateCache`, and `b_m:templateCache` in order +* `compile:js` - Runs `c_c:js`, `build:js_bower`, `build:js`, and `build:templateCache` at the same time, then runs +`c_m:js` + +####Test Tasks +* `testServe` - Starts the browser-sync server on localhost:12000 +Note: this task does not build the application first so you must run `gulp build` first for it to work. +This task differs from `dev` in that it opens a tunnel that allows the app to be viewed on other computers +not on the same network. + +####Watch Tasks +* `dev` - Starts the browser-sync server on localhost:8000 +* `karma:unit` - Starts the karma unit tests +* `watch:js` - Starts a process that watches for changes in the javascript files in the src directory +* `watch:assets` - Starts a process that watches for changes in the style sheet files (less and css) +* `watch:other` - Starts a process the watches for changes in the html files +* `watch` - Starts all of the previously mentioned tasks in parallel + +As covered in the previous section, `gulp build` and `gulp watch` will execute a full build +up-front and then run any of the aforementioned `watch` tasks as needed to +ensure the fastest possible build. So whenever you're working on your project, +start with: + +```sh +$ gulp build +``` + +then: + +```sh +$ gulp watch +``` + +And everything will be done automatically! + +### Build vs. Compile + +To make the build even faster, tasks are placed into two categories: build and +compile. The build tasks (like those we've been discussing) are the minimal +tasks required to run your app during development. + +Compile tasks, however, get your app ready for production. The compile tasks +include concatenation, minification, compression, etc. These tasks take a little +bit longer to run and are not at all necessary for development so are not called +automatically during build or watch. + +To initiate a full compile, you simply run the default task: + +```sh +$ gulp +``` + +This will perform a build and then a compile. The compiled site is located in `compile/`. +To test that your full site works as expected, open the `compile/index.html` file in your browser. Voila! diff --git a/README.md b/README.md index 975d7528..ced74a11 100644 --- a/README.md +++ b/README.md @@ -160,117 +160,4 @@ task, which runs `build` and then `compile`: ```sh $ gulp -``` - -### The Build System - -The best way to learn about the build system is by familiarizing yourself with -Gulp and then looking through the code, `Gulpfile.js` and the Gulp folder. - But you don't need to do that to be very productive with -`OrderCloud`. What follows in this section is a quick introduction to the -tasks provided and should be plenty to get you started. - -Below is a description of the gulp tasks in the project, sorted by their general purpose -and location within the Gulp directory. - -####Asset Tasks -* `b_m:less` - Compiles all of the app and bower less files into css and moves the compiled file into the temp folder -* `b_m:sass` - Compiles all of the app and bower sass files into css and moves the compiled file into the temp folder -* `b_m:css` - Compiles all of the bower css files (with the exception of the font awesome file as it was already compiled -in `b_m:less`) into one file and autoprefixes the css to run for the last to versions of all the major browsers -* `b_m:appCss` - Compiles all of the app css files into one file and autoprefixes the css to run for the last to versions -of all the major browsers -* `b_m:styles` - Compiles all of the css files in the temp directory into one file, replaces the path to fonts to be correct -for the build directory and renames the file with the version of the app. Places the file in the build folder and injects the -change into browser-sync if it is currently running -* `b_c:styles` - Deletes all of the assets that have been moved over to the build folder and all of the files in the temp folder -* `b_m:assets` - Moves over all asset files (fonts and images) saved in the src/assets directory to the build/assets directory -* `b_m:fonts` - Moves over all fonts saved within the bower dependencies to the build/assets directory -* `b_c:assets` - Deletes all assets files from the build directory -* `c_m:css` - Minifies all css files in the build directory and moves them to the compile folder -* `c_c:css` - Deletes all css files from the compile directory -* `c_m:assets` - Moves over all asset files (fonts and images) from the build folder to the compile folder -* `c_c:assets` - Delete all asset and css files from the compile directory -* `build:styles` - Runs `b_c:styles`, `b_m:less`, `b_m:sass`, `b_m:css`, `b_m:appCss`, `b_m:styles` in order -* `compile:css` - Runs `c_c:css`, `build:styles`, `c_m:css` in order -* `build:assets` - Runs `b_c:assets`, `b_m:assets`, `b_m:fonts` in order -* `compile:assets` - Runs `c_c:assets`, `build:assets`, `c_m:assets` in order - -####General Tasks -* `compile:inject` - Injects the app dependencies into the index.html file for the compiled build -Note: Theere should only be two: `OrderCloud-[Version#].css` and `app.js` -* `build:inject` - Injects the app dependencies into the index.html file for the unminified build -* `masterClean` - Deletes the build, compile, and temp directories. Basically anything built by the gulp -tasks will be removed by this task -* `build` - First runs `master clean`, then runs `build:js_bower`, `build:js`, `build:templateCache`, `build:styles`, `build:assets`, -and lastly runs `build:inject` to create an unminified build of the project -* `compile` - First runs `build`, then runs `compile:js`, `compile:assets`, `compile:css` -and lastly runs `compile:inject` to create a minified build of the project -* `default` - Runs the `compile` task when only `gulp` is typed into the command prompt - -####Script Tasks -* `b_m:js_bower` - Moves the bower dependencies over to the build folder -* `b_c:js_bower` - Deletes bower dependencies form the build folder -* `b_m:js` - Moves over all of the app js files need to run the application (not the ones for unit testing) and -annotates them and wraps each file in an IIFE call. -* `b_c:js` - Deletes all of the javascript files moved over to the build folder except for the templateCache file -* `b_m:templateCache` - Creates an angular templateCache of all the html files (except the index) that -allows for the application to run faster. -* `b_c:templateCache` - Cleans out the compiled template file generated by `b_m:templateCache` -* `c_c:js` - Deletes all js files from the compile directory -* `build:js` - Runs `b_c:js`, and `b_m:js` in order -* `build:js_bower` - Runs `b_c:js_bower`, and `b_m:js_bower` in order -* `build:templateCache` - Runs `b_c:templateCache`, and `b_m:templateCache` in order -* `compile:js` - Runs `c_c:js`, `build:js_bower`, `build:js`, and `build:templateCache` at the same time, then runs -`c_m:js` - -####Test Tasks -* `testServe` - Starts the browser-sync server on localhost:12000 -Note: this task does not build the application first so you must run `gulp build` first for it to work. -This task differs from `dev` in that it opens a tunnel that allows the app to be viewed on other computers -not on the same network. - -####Watch Tasks -* `dev` - Starts the browser-sync server on localhost:8000 -* `karma:unit` - Starts the karma unit tests -* `watch:js` - Starts a process that watches for changes in the javascript files in the src directory -* `watch:assets` - Starts a process that watches for changes in the style sheet files (less and css) -* `watch:other` - Starts a process the watches for changes in the html files -* `watch` - Starts all of the previously mentioned tasks in parallel - -As covered in the previous section, `gulp build` and `gulp watch` will execute a full build -up-front and then run any of the aforementioned `watch` tasks as needed to -ensure the fastest possible build. So whenever you're working on your project, -start with: - -```sh -$ gulp build -``` - -then: - -```sh -$ gulp watch -``` - -And everything will be done automatically! - -### Build vs. Compile - -To make the build even faster, tasks are placed into two categories: build and -compile. The build tasks (like those we've been discussing) are the minimal -tasks required to run your app during development. - -Compile tasks, however, get your app ready for production. The compile tasks -include concatenation, minification, compression, etc. These tasks take a little -bit longer to run and are not at all necessary for development so are not called -automatically during build or watch. - -To initiate a full compile, you simply run the default task: - -```sh -$ gulp -``` - -This will perform a build and then a compile. The compiled site is located in `compile/`. -To test that your full site works as expected, open the `compile/index.html` file in your browser. Voila! +``` \ No newline at end of file From 783854c623f42c2010e3ad321dbc9e072f042d40 Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 25 Jan 2016 14:01:56 -0600 Subject: [PATCH 044/367] Ensure the cookie is legitimate during SetBuyerID() at runtime --- src/app/app.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/app.js b/src/app/app.js index 49d60864..39064644 100644 --- a/src/app/app.js +++ b/src/app/app.js @@ -43,7 +43,8 @@ angular.module( 'orderCloud', [ ; function SetBuyerID( OrderCloud, buyerid ) { - OrderCloud.BuyerID.Get() ? angular.noop() : OrderCloud.BuyerID.Set(buyerid); + var cookie = OrderCloud.BuyerID.Get(); + (cookie && cookie.length && cookie != null) ? angular.noop() : OrderCloud.BuyerID.Set(buyerid); } function Routing( $urlRouterProvider, $urlMatcherFactoryProvider ) { From 147538c7a535344831a20e23b60b275bce2bfcbc Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 17 Feb 2016 12:28:21 -0600 Subject: [PATCH 045/367] Update common/ directory to match Components --- .../address/templates/address.form.tpl.html | 6 +- src/app/common/current-order/current-order.js | 85 +++++++------- src/app/common/files/tests/files.spec.js | 2 +- src/app/common/lineitems/lineitems.js | 107 ++++++++++-------- 4 files changed, 104 insertions(+), 96 deletions(-) diff --git a/src/app/common/address/templates/address.form.tpl.html b/src/app/common/address/templates/address.form.tpl.html index 54da9f5b..4eeb9250 100644 --- a/src/app/common/address/templates/address.form.tpl.html +++ b/src/app/common/address/templates/address.form.tpl.html @@ -34,17 +34,17 @@
- +
- +
- +
diff --git a/src/app/common/current-order/current-order.js b/src/app/common/current-order/current-order.js index 7cdccbbd..02ac9667 100644 --- a/src/app/common/current-order/current-order.js +++ b/src/app/common/current-order/current-order.js @@ -4,69 +4,43 @@ angular.module('ordercloud-current-order', []) ; //TODO: CurrentOrderService needs to be updated to NEW SDK / remove the need for ImpersonationService -function CurrentOrderService($q, appname, ImpersonationService, $localForage, Auth, Orders, Me) { +function CurrentOrderService($q, appname, $localForage, OrderCloud) { var StorageName = appname + '.CurrentOrderID'; return { - Get: getOrder, - GetID: getOrderID, - Set: setOrderID, - Remove: removeOrder + Get: Get, + GetID: GetID, + Set: Set, + Remove: Remove, + GetLineItems: GetLineItems }; - function getOrder() { + function Get() { var dfd = $q.defer(); - getOrderID() + GetID() .then(function(OrderID) { - Orders.Get(OrderID) + OrderCloud.Orders.Get(OrderID) .then(function(order) { - if (order.Status === 'Unsubmitted' && Auth.GetImpersonating()) { - dfd.resolve(order); - } - else { - /* remove order if it has been submitted */ - removeOrder(); - dfd.reject(); - } + dfd.resolve(order); }) .catch(function() { - // If method fails clear out saved order - removeOrder(); + Remove(); dfd.reject(); }); }) .catch(function() { - // Double check for an open order - ImpersonationService.Impersonation(Me.Get) - .then(function(me) { - ImpersonationService.Impersonation(function() { - return Orders.List('outgoing', null, null, null, null, null, null, null, {'FromUserID': me.ID, 'Status': 'Unsubmitted'}) - .then(function(orders) { - if (orders.Items.length >= 1) { - $localForage.setItem(StorageName, orders.Items[0].ID); - dfd.resolve(orders.Items[0]); - } - else dfd.reject(); - }) - .catch(function() { - dfd.reject(); - }); - }); - }) - .catch(function(error) { - dfd.reject(error); - }); + dfd.reject(); }); return dfd.promise; } - function getOrderID() { + function GetID() { var dfd = $q.defer(); $localForage.getItem(StorageName) .then(function(orderID) { - if (orderID && Auth.GetImpersonating()) + if (orderID) dfd.resolve(orderID); else { - removeOrder(); + Remove(); dfd.reject(); } }) @@ -76,7 +50,7 @@ function CurrentOrderService($q, appname, ImpersonationService, $localForage, Au return dfd.promise; } - function setOrderID(OrderID) { + function Set(OrderID) { $localForage.setItem(StorageName, OrderID) .then(function(data) { return data; @@ -86,7 +60,32 @@ function CurrentOrderService($q, appname, ImpersonationService, $localForage, Au }); } - function removeOrder() { + function Remove() { return $localForage.removeItem(StorageName); } + + function GetLineItems(orderID) { + var deferred = $q.defer(); + var lineItems = []; + var queue = []; + + GetID() + .then(function(OrderID) { + OrderCloud.LineItems.List(OrderID, 1, 100) + .then(function(data) { + lineItems = lineItems.concat(data.Items); + for (var i = 2; i <= data.Meta.TotalPages; i++) { + queue.push(OrderCloud.LineItems.List(OrderID, i, 100)); + } + $q.all(queue).then(function(results) { + angular.forEach(results, function(result) { + lineItems = lineItems.concat(result.Items); + }); + deferred.resolve(lineItems); + }); + }); + }); + + return deferred.promise; + } } \ No newline at end of file diff --git a/src/app/common/files/tests/files.spec.js b/src/app/common/files/tests/files.spec.js index 13c5cebd..6cabbd13 100644 --- a/src/app/common/files/tests/files.spec.js +++ b/src/app/common/files/tests/files.spec.js @@ -17,7 +17,7 @@ describe('Component: Files', function() { fileService = FileService; })); }); - describe('Directive: ordercloudFileUpload', function() { + xdescribe('Directive: ordercloudFileUpload', function() { var element; beforeEach(inject(function($compile) { scope.model = {}; diff --git a/src/app/common/lineitems/lineitems.js b/src/app/common/lineitems/lineitems.js index d3b79ba3..a84ba683 100644 --- a/src/app/common/lineitems/lineitems.js +++ b/src/app/common/lineitems/lineitems.js @@ -5,27 +5,54 @@ angular.module('ordercloud-lineitems', []) ; -function LineItemFactory($q, $state, CurrentOrder, OrderCloud, $uibModal, $rootScope, Underscore) { +function LineItemFactory($rootScope, $q, $state, $uibModal, Underscore, OrderCloud, CurrentOrder) { return { - SpecConvert: SpecConverter, - RemoveItem: DeleteLineItem, + SpecConvert: SpecConvert, + RemoveItem: RemoveItem, UpdateQuantity: UpdateQuantity, - GetProductInfo: GetProductInformation, - ClearShipper: ClearShipping, - CustomShipper: CustomShipping + GetProductInfo: GetProductInfo, + CustomShipping: CustomShipping, + UpdateShipping: UpdateShipping }; - function DeleteLineItem(Order, LineItem) { + function SpecConvert(specs) { + var results = []; + angular.forEach(specs, function (spec) { + var spec_to_push = {SpecID: spec.ID}; + if (spec.Options.length > 0) { + if (spec.DefaultOptionID) { + spec_to_push.OptionID = spec.DefaultOptionID; + } + if (spec.OptionID) { + spec_to_push.OptionID = spec.OptionID; + } + if (spec.Value) { + spec_to_push.Value = spec.Value; + } + } + else { + spec_to_push.Value = spec.Value || spec.DefaultValue || null; + } + results.push(spec_to_push); + }); + return results; + } + + function RemoveItem(Order, LineItem) { OrderCloud.LineItems.Delete(Order.ID, LineItem.ID) - .then(function() { + .then(function () { // If all line items are removed delete the order. - OrderCloud.List(Order.ID) - .then(function(data) { + OrderCloud.LineItems.List(Order.ID) + .then(function (data) { if (!data.Items.length) { - OrderCloud.Orders.Delete(Order.ID); CurrentOrder.Remove(); + OrderCloud.Orders.Delete(Order.ID).then(function () { + $state.reload(); + }); + } + else { + $state.reload(); } - $state.reload(); }); }); } @@ -33,27 +60,23 @@ function LineItemFactory($q, $state, CurrentOrder, OrderCloud, $uibModal, $rootS function UpdateQuantity(Order, LineItem) { if (LineItem.Quantity > 0) { OrderCloud.LineItems.Patch(Order.ID, LineItem.ID, {Quantity: LineItem.Quantity}) - .then(function() { - $rootScope.$broadcast('LineItemQuantityUpdated', LineItem.ID); + .then(function () { + $rootScope.$broadcast('OC:UpdateOrder', Order.ID); }); } } - function ClearShipping(Order, LineItem) { - - } - - function GetProductInformation(LineItems) { + function GetProductInfo(LineItems) { var li = LineItems.Items || LineItems; var productIDs = Underscore.uniq(Underscore.pluck(li, 'ProductID')); var dfd = $q.defer(); var queue = []; - angular.forEach(productIDs, function(productid) { - queue.push(OrderCloud.Products.Get(productid)); + angular.forEach(productIDs, function (productid) { + queue.push(OrderCloud.Me.GetProduct(productid)); }); $q.all(queue) - .then(function(results) { - angular.forEach(li, function(item) { + .then(function (results) { + angular.forEach(li, function (item) { item.Product = angular.copy(Underscore.where(results, {ID: item.ProductID})[0]); }); dfd.resolve(li); @@ -71,35 +94,21 @@ function LineItemFactory($q, $state, CurrentOrder, OrderCloud, $uibModal, $rootS }); modalInstance.result - .then(function(address) { + .then(function (address) { + address.ID = Math.floor(Math.random() * 1000000).toString(); OrderCloud.LineItems.SetShippingAddress(Order.ID, LineItem.ID, address) - .then(function() { - $rootScope.$broadcast('LineItemShippingUpdated', LineItem.ID); + .then(function () { + $rootScope.$broadcast('LineItemAddressUpdated', LineItem.ID, address); }); }); } - function SpecConverter(specs) { - var results = []; - angular.forEach(specs, function(spec) { - var spec_to_push = {SpecID: spec.ID}; - if (spec.Options.length > 0) { - if (spec.DefaultOptionID) { - spec_to_push.OptionID = spec.DefaultOptionID; - } - if (spec.Value) { - spec_to_push.Value = spec.Value; - } - else if (spec.OptionID) { - spec_to_push.OptionID = spec.OptionID; - } - } - else { - spec_to_push.Value = spec.Value || spec.DefaultValue || null; - } - results.push(spec_to_push); - }); - return results; + function UpdateShipping(Order, LineItem, AddressID) { + OrderCloud.Addresses.Get(AddressID) + .then(function (address) { + OrderCloud.LineItems.SetShippingAddress(Order.ID, LineItem.ID, address); + $rootScope.$broadcast('LineItemAddressUpdated', LineItem.ID, address); + }); } } @@ -107,11 +116,11 @@ function LineItemModalController($uibModalInstance) { var vm = this; vm.address = {}; - vm.submit = function() { + vm.submit = function () { $uibModalInstance.close(vm.address); }; - vm.cancel = function() { + vm.cancel = function () { vm.address = {}; $uibModalInstance.dismiss('cancel'); }; From d4058ff105b26257a3cb207f06d734cb6f29c198 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 17 Feb 2016 13:09:10 -0600 Subject: [PATCH 046/367] Prep for merging #newsdk branch --- Gulp/generalTasks.js | 2 +- Gulp/scriptTasks.js | 3 +- bower.json | 5 +- src/app/account/tests/account.spec.js | 2 +- src/app/app.js | 10 +- src/app/base/tests/base.spec.js | 2 +- .../buyer-select/tests/buyer-select.spec.js | 2 +- .../tests/paging-helpers.spec.js | 2 +- .../common/localforage/localforage.config.js | 12 ++ src/app/common/media/ordercloud.media.js | 121 ++++++++++++++++++ .../common/underscore/underscore.factory.js | 7 + src/app/login/tests/login.spec.js | 2 +- 12 files changed, 156 insertions(+), 14 deletions(-) create mode 100644 src/app/common/localforage/localforage.config.js create mode 100644 src/app/common/media/ordercloud.media.js create mode 100644 src/app/common/underscore/underscore.factory.js diff --git a/Gulp/generalTasks.js b/Gulp/generalTasks.js index d152fd7e..f1fd82ff 100644 --- a/Gulp/generalTasks.js +++ b/Gulp/generalTasks.js @@ -16,7 +16,7 @@ gulp.task('build:inject', function() { //task injects dep into index.html return gulp .src(config.source + 'index.html') - .pipe(inject(gulp.src([config.build + 'vendor/**/angular.js', config.build + 'vendor/**/*.js'], {read:false}), {name: 'bower', ignorePath: config.build.replace('.', ''), addRootSlash: false})) + .pipe(inject(gulp.src([config.build + 'vendor/jquery.js', config.build + 'vendor/localforage.js', config.build + 'vendor/**/angular.js', config.build + 'vendor/**/*.js'], {read:false}), {name: 'bower', ignorePath: config.build.replace('.', ''), addRootSlash: false})) .pipe(inject(gulp.src([ config.build + 'src/templates-app.js', config.build + 'src/app/app.js', diff --git a/Gulp/scriptTasks.js b/Gulp/scriptTasks.js index f4977c0b..06487201 100644 --- a/Gulp/scriptTasks.js +++ b/Gulp/scriptTasks.js @@ -67,7 +67,8 @@ gulp.task('b_c:templateCache', function() { gulp.task('c_m:js', function() { return gulp - .src([ + .src([config.build + 'vendor/jquery.js', + config.build + 'vendor/localforage.js', config.build + 'vendor/angular.js', config.build + 'vendor/**/*.js', config.build + 'src/templates-app.js', diff --git a/bower.json b/bower.json index f76f5caf..89d926bc 100644 --- a/bower.json +++ b/bower.json @@ -18,8 +18,9 @@ "angular-toastr": "~1.5.0", "angular-bootstrap": "~0.14.3", "angular-ui-tree": "~2.10.0", - "ordercloud-angular-sdk": "~1.0.3", "angular-ui-grid": "~3.0.7", - "ordercloud-ng-sdk": "~1.0.0" + "ordercloud-ng-sdk": "~1.0.5", + "underscore": "^1.8.3", + "angular-localforage": "^1.2.5" } } diff --git a/src/app/account/tests/account.spec.js b/src/app/account/tests/account.spec.js index b5e9f9dc..184cffd1 100644 --- a/src/app/account/tests/account.spec.js +++ b/src/app/account/tests/account.spec.js @@ -4,7 +4,7 @@ describe('Component: Account', function() { account, accountFactory; beforeEach(module('orderCloud')); - beforeEach(module('orderCloud.newsdk')); + beforeEach(module('orderCloud.sdk')); beforeEach(inject(function($q, $rootScope, AccountService) { q = $q; scope = $rootScope.$new(); diff --git a/src/app/app.js b/src/app/app.js index 39064644..894be82a 100644 --- a/src/app/app.js +++ b/src/app/app.js @@ -8,7 +8,7 @@ angular.module( 'orderCloud', [ 'ui.router', 'ui.bootstrap', 'orderCloud.sdk', - 'orderCloud.newsdk', + 'LocalForageModule', 'toastr', 'jcs-autoValidate', 'ordercloud-infinite-scroll', @@ -33,12 +33,12 @@ angular.module( 'orderCloud', [ //App Constants used by the OrderCloud SDK .constant("ocscope", "FullAccess") - .constant("clientid", "0854871D-1492-42CD-AC95-C31139ACC916") - .constant("buyerid", "Buyer001") + .constant("clientid", "f567ce46-3c24-46be-a9c9-327fabadebb3") + .constant("buyerid", "component_1") //OrderCloud Base URLs - .constant("authurl", "http://core.four51.com:11629/oauth/token") - .constant("apiurl", "http://core.four51.com:9002") + .constant("authurl", "https://auth.ordercloud.io/oauth/token") + .constant("apiurl", "https://api.ordercloud.io") ; diff --git a/src/app/base/tests/base.spec.js b/src/app/base/tests/base.spec.js index 018006ab..896f0214 100644 --- a/src/app/base/tests/base.spec.js +++ b/src/app/base/tests/base.spec.js @@ -3,7 +3,7 @@ describe('Component: Base', function() { scope, oc; beforeEach(module('orderCloud')); - beforeEach(module('orderCloud.newsdk')); + beforeEach(module('orderCloud.sdk')); beforeEach(module('ui.router')); beforeEach(inject(function($q, $rootScope, OrderCloud) { q = $q; diff --git a/src/app/common/buyer-select/tests/buyer-select.spec.js b/src/app/common/buyer-select/tests/buyer-select.spec.js index 00593b0a..f893afc5 100644 --- a/src/app/common/buyer-select/tests/buyer-select.spec.js +++ b/src/app/common/buyer-select/tests/buyer-select.spec.js @@ -3,7 +3,7 @@ describe('Buyer-Select:', function() { scope, oc; beforeEach(module('orderCloud')); - beforeEach(module('orderCloud.newsdk')); + beforeEach(module('orderCloud.sdk')); beforeEach(inject(function($q, $rootScope, OrderCloud){ q = $q; scope = $rootScope.$new(); diff --git a/src/app/common/helper-factories/tests/paging-helpers.spec.js b/src/app/common/helper-factories/tests/paging-helpers.spec.js index 72576bb9..75690a96 100644 --- a/src/app/common/helper-factories/tests/paging-helpers.spec.js +++ b/src/app/common/helper-factories/tests/paging-helpers.spec.js @@ -5,7 +5,7 @@ describe('Factory: Paging', function() { assignmentsArray, oc; beforeEach(module('orderCloud')); - beforeEach(module('orderCloud.newsdk')); + beforeEach(module('orderCloud.sdk')); beforeEach(module('ordercloud-paging-helpers')); beforeEach(inject(function($rootScope, Paging, OrderCloud) { listArray = [{ID: 1}, {ID: 2}, {ID: 3}]; diff --git a/src/app/common/localforage/localforage.config.js b/src/app/common/localforage/localforage.config.js new file mode 100644 index 00000000..1f49ed07 --- /dev/null +++ b/src/app/common/localforage/localforage.config.js @@ -0,0 +1,12 @@ +angular.module('orderCloud') + .config(LocalForage) +; + +function LocalForage($localForageProvider) { + $localForageProvider.config({ + version: 1.0, + name: 'OrderCloud', + storeName: 'four51', + description: 'Four51 OrderCloud Local Storage' + }); +} \ No newline at end of file diff --git a/src/app/common/media/ordercloud.media.js b/src/app/common/media/ordercloud.media.js new file mode 100644 index 00000000..f5789bc3 --- /dev/null +++ b/src/app/common/media/ordercloud.media.js @@ -0,0 +1,121 @@ +angular.module('orderCloud') + .factory('$ocMedia', ocMediaFactory) + .constant('MEDIA', MEDIA_CONSTANT) + .constant('MEDIA_PRIORITY', MEDIA_PRIORITY_CONSTANT); + +function MEDIA_CONSTANT() { + return { + 'sm': '(max-width: 600px)', + 'gt-sm': '(min-width: 600px)', + 'md': '(min-width: 600px) and (max-width: 960px)', + 'gt-md': '(min-width: 960px)', + 'lg': '(min-width: 960px) and (max-width: 1200px)', + 'gt-lg': '(min-width: 1200px)' + } +} + +function MEDIA_PRIORITY_CONSTANT() { + return [ + 'gt-lg', + 'lg', + 'gt-md', + 'md', + 'gt-sm', + 'sm' + ] +} + +function ocMediaFactory(MEDIA, MEDIA_PRIORITY, $rootScope, $window) { + var queries = {}; + var mqls = {}; + var results = {}; + var normalizeCache = {}; + + $ocMedia.getResponsiveAttribute = getResponsiveAttribute; + $ocMedia.getQuery = getQuery; + $ocMedia.watchResponsiveAttributes = watchResponsiveAttributes; + + return $ocMedia; + + function $ocMedia(query) { + var validated = queries[query]; + if (angular.isUndefined(validated)) { + validated = queries[query] = validate(query); + } + + var result = results[validated]; + if (angular.isUndefined(result)) { + result = add(validated); + } + + return result; + } + + function validate(query) { + return MEDIA[query] || + ((query.charAt(0) !== '(') ? ('(' + query + ')') : query); + } + + function add(query) { + var result = mqls[query] = $window.matchMedia(query); + result.addListener(onQueryChange); + return (results[result.media] = !!result.matches); + } + + function onQueryChange(query) { + $rootScope.$evalAsync(function() { + results[query.media] = !!query.matches; + }); + } + + function getQuery(name) { + return mqls[name]; + } + + function getResponsiveAttribute(attrs, attrName) { + for (var i = 0; i < MEDIA_PRIORITY.length; i++) { + var mediaName = MEDIA_PRIORITY[i]; + if (!mqls[queries[mediaName]].matches) { + continue; + } + + var normalizedName = getNormalizedName(attrs, attrName + '-' + mediaName); + if (attrs[normalizedName]) { + return attrs[normalizedName]; + } + } + + // fallback on unprefixed + return attrs[getNormalizedName(attrs, attrName)]; + } + + function watchResponsiveAttributes(attrNames, attrs, watchFn) { + var unwatchFns = []; + attrNames.forEach(function(attrName) { + var normalizedName = getNormalizedName(attrs, attrName); + if (attrs[normalizedName]) { + unwatchFns.push( + attrs.$observe(normalizedName, angular.bind(void 0, watchFn, null))); + } + + for (var mediaName in MEDIA) { + normalizedName = getNormalizedName(attrs, attrName + '-' + mediaName); + if (!attrs[normalizedName]) { + return; + } + + unwatchFns.push(attrs.$observe(normalizedName, angular.bind(void 0, watchFn, mediaName))); + } + }); + + return function unwatch() { + unwatchFns.forEach(function(fn) { fn(); }) + }; + } + + // Improves performance dramatically + function getNormalizedName(attrs, attrName) { + return normalizeCache[attrName] || + (normalizeCache[attrName] = attrs.$normalize(attrName)); + } +} diff --git a/src/app/common/underscore/underscore.factory.js b/src/app/common/underscore/underscore.factory.js new file mode 100644 index 00000000..ce517190 --- /dev/null +++ b/src/app/common/underscore/underscore.factory.js @@ -0,0 +1,7 @@ +angular.module('orderCloud') + .factory('Underscore', UnderscoreFactory) +; + +function UnderscoreFactory($window) { + return $window._; +} \ No newline at end of file diff --git a/src/app/login/tests/login.spec.js b/src/app/login/tests/login.spec.js index 9ab8fac6..1068c5e6 100644 --- a/src/app/login/tests/login.spec.js +++ b/src/app/login/tests/login.spec.js @@ -8,7 +8,7 @@ describe('Component: Login', function() { Password: 'notarealpassword' }; beforeEach(module('orderCloud')); - beforeEach(module('orderCloud.newsdk')); + beforeEach(module('orderCloud.sdk')); beforeEach(inject(function($q, $rootScope, OrderCloud, LoginService) { q = $q; scope = $rootScope.$new(); From 61a610f6553d380c916cce1de32fe11d9ab6e268 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 17 Feb 2016 15:13:10 -0600 Subject: [PATCH 047/367] Set buyerID at login Sync up common/ directory with Components repo --- src/app/common/buyer-select/tests/buyer-select.spec.js | 4 ++-- src/app/common/lineitems/lineitems.js | 1 + src/app/login/login.js | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/app/common/buyer-select/tests/buyer-select.spec.js b/src/app/common/buyer-select/tests/buyer-select.spec.js index f893afc5..f931e916 100644 --- a/src/app/common/buyer-select/tests/buyer-select.spec.js +++ b/src/app/common/buyer-select/tests/buyer-select.spec.js @@ -79,9 +79,9 @@ describe('Buyer-Select:', function() { it('should change the selected buyer to the one passed in', function() { expect(buyerSelectCtrl.selectedBuyer).toBe(mock_buyer); }); - it('should call the Set method of BuyerID to change the saved buyer ID value stored in the cookies', inject(function(BuyerID) { + it('should call the Set method of BuyerID to change the saved buyer ID value stored in the cookies', function() { expect(oc.BuyerID.Set).toHaveBeenCalledWith(mock_buyer.ID); - })); + }); it('should reload the state', inject(function($state) { expect($state.reload).toHaveBeenCalledWith($state.current); })); diff --git a/src/app/common/lineitems/lineitems.js b/src/app/common/lineitems/lineitems.js index a84ba683..36335aa1 100644 --- a/src/app/common/lineitems/lineitems.js +++ b/src/app/common/lineitems/lineitems.js @@ -48,6 +48,7 @@ function LineItemFactory($rootScope, $q, $state, $uibModal, Underscore, OrderClo CurrentOrder.Remove(); OrderCloud.Orders.Delete(Order.ID).then(function () { $state.reload(); + $rootScope.$broadcast('OC:OrderDeleted'); }); } else { diff --git a/src/app/login/login.js b/src/app/login/login.js index 29bbf54c..86044343 100644 --- a/src/app/login/login.js +++ b/src/app/login/login.js @@ -78,6 +78,7 @@ function LoginController( $state, $stateParams, $exceptionHandler, OrderCloud, L vm.submit = function() { OrderCloud.Auth.GetToken(vm.credentials) .then(function(data) { + OrderCloud.BuyerID.Set(buyerid); OrderCloud.Auth.SetToken(data['access_token']); $state.go('home'); }) From 1c182f41c7d134be2941790c5b915094e2a27063 Mon Sep 17 00:00:00 2001 From: Robert Watt Date: Wed, 17 Feb 2016 15:25:29 -0600 Subject: [PATCH 048/367] Remove development constant values --- src/app/app.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/app.js b/src/app/app.js index 894be82a..ae169df0 100644 --- a/src/app/app.js +++ b/src/app/app.js @@ -8,7 +8,7 @@ angular.module( 'orderCloud', [ 'ui.router', 'ui.bootstrap', 'orderCloud.sdk', - 'LocalForageModule', + 'LocalForageModule', 'toastr', 'jcs-autoValidate', 'ordercloud-infinite-scroll', @@ -33,8 +33,8 @@ angular.module( 'orderCloud', [ //App Constants used by the OrderCloud SDK .constant("ocscope", "FullAccess") - .constant("clientid", "f567ce46-3c24-46be-a9c9-327fabadebb3") - .constant("buyerid", "component_1") + .constant("clientid", "XXXXXXXX-XXXX-XXXX-XXXXXXXXXX") + .constant("buyerid", "XXXXX") //OrderCloud Base URLs .constant("authurl", "https://auth.ordercloud.io/oauth/token") @@ -88,4 +88,4 @@ function AppCtrl( $rootScope, $state, appname, OrderCloud ) { vm.title = appname; } }); -} \ No newline at end of file +} From 96f7be7e9fb111db5af7c2aa28156542d258d113 Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 11 Mar 2016 14:12:09 -0600 Subject: [PATCH 049/367] Sync the seed up with Components repository --- bower.json | 1 - src/app/app.js | 28 ++++-- src/app/base/base.js | 38 ++++--- src/app/base/less/base.less | 25 +++++ src/app/base/templates/base.left.tpl.html | 11 ++- src/app/base/templates/base.top.tpl.html | 4 +- src/app/base/tests/base.spec.js | 5 +- .../impersonation/ordercloud-impersonation.js | 98 ------------------- .../templates/buyer-user-modal.tpl.html | 37 ------- 9 files changed, 86 insertions(+), 161 deletions(-) delete mode 100644 src/app/common/impersonation/ordercloud-impersonation.js delete mode 100644 src/app/common/impersonation/templates/buyer-user-modal.tpl.html diff --git a/bower.json b/bower.json index 89d926bc..9fe0b47e 100644 --- a/bower.json +++ b/bower.json @@ -18,7 +18,6 @@ "angular-toastr": "~1.5.0", "angular-bootstrap": "~0.14.3", "angular-ui-tree": "~2.10.0", - "angular-ui-grid": "~3.0.7", "ordercloud-ng-sdk": "~1.0.5", "underscore": "^1.8.3", "angular-localforage": "^1.2.5" diff --git a/src/app/app.js b/src/app/app.js index ae169df0..90087b96 100644 --- a/src/app/app.js +++ b/src/app/app.js @@ -8,7 +8,7 @@ angular.module( 'orderCloud', [ 'ui.router', 'ui.bootstrap', 'orderCloud.sdk', - 'LocalForageModule', + 'LocalForageModule', 'toastr', 'jcs-autoValidate', 'ordercloud-infinite-scroll', @@ -17,17 +17,15 @@ angular.module( 'orderCloud', [ 'ordercloud-assignment-helpers', 'ordercloud-paging-helpers', 'ordercloud-auto-id', - 'ordercloud-impersonation', 'ordercloud-current-order', 'ordercloud-address', - 'ordercloud-lineitems', - 'ui.grid', - 'ui.grid.infiniteScroll' + 'ordercloud-lineitems' ]) .run( SetBuyerID ) .config( Routing ) .config( ErrorHandling ) + .config( Interceptor ) .controller( 'AppCtrl', AppCtrl ) .constant("appname", "OrderCloud AngularJS Seed") @@ -43,8 +41,7 @@ angular.module( 'orderCloud', [ ; function SetBuyerID( OrderCloud, buyerid ) { - var cookie = OrderCloud.BuyerID.Get(); - (cookie && cookie.length && cookie != null) ? angular.noop() : OrderCloud.BuyerID.Set(buyerid); + OrderCloud.BuyerID.Get() ? angular.noop() : OrderCloud.BuyerID.Set(buyerid); } function Routing( $urlRouterProvider, $urlMatcherFactoryProvider ) { @@ -88,4 +85,21 @@ function AppCtrl( $rootScope, $state, appname, OrderCloud ) { vm.title = appname; } }); + + $rootScope.$on('OC:AccessInvalidOrExpired', function() { + vm.logout(); + }); } + +function Interceptor( $httpProvider ) { + $httpProvider.interceptors.push(function($q, $rootScope) { + return { + 'responseError': function(rejection) { + if (rejection.config.url.indexOf('ordercloud.io') > -1 && rejection.status == 401) { + $rootScope.$broadcast('OC:AccessInvalidOrExpired'); + } + return $q.reject(rejection); + } + }; + }); +} \ No newline at end of file diff --git a/src/app/base/base.js b/src/app/base/base.js index 817ec3cb..9f99cd30 100644 --- a/src/app/base/base.js +++ b/src/app/base/base.js @@ -1,18 +1,17 @@ angular.module( 'orderCloud' ) - .config( BaseConfig ) - .controller( 'BaseCtrl', BaseController ) + .config( BaseConfig ) + .controller( 'BaseCtrl', BaseController ) .controller( 'BaseLeftCtrl', BaseLeftController ) .controller( 'BaseTopCtrl', BaseTopController ) - ; function BaseConfig( $stateProvider ) { - $stateProvider - .state( 'base', { - url: '', - abstract: true, - templateUrl:'base/templates/base.tpl.html', + $stateProvider + .state( 'base', { + url: '', + abstract: true, + templateUrl:'base/templates/base.tpl.html', views: { '': { templateUrl: 'base/templates/base.tpl.html', @@ -46,7 +45,7 @@ function BaseConfig( $stateProvider ) { }); return dfd.promise; }, - ComponentList: function($state, $q, Underscore) { + ComponentList: function($state, $q, Underscore, CurrentUser) { var deferred = $q.defer(); var nonSpecific = ['Products', 'Specs', 'Price Schedules', 'Admin Users']; var components = { @@ -73,18 +72,33 @@ function BaseConfig( $stateProvider ) { }); deferred.resolve(components); return deferred.promise; + }, + Tree: function(CatalogTreeService, OrderCloud, CurrentUser) { + if (OrderCloud.Auth.ReadToken) { + var tokenInfo = atob(OrderCloud.Auth.ReadToken().split('.')[1]); + if (tokenInfo.usrtype === "buyer") { + return CatalogTreeService.GetCatalogTree(); + } + else { + return null; + } + } + else { + return null; + } } } - }); + }); } function BaseController(CurrentUser) { - var vm = this; + var vm = this; vm.currentUser = CurrentUser; } -function BaseLeftController(ComponentList) { +function BaseLeftController(ComponentList, Tree) { var vm = this; + vm.tree = Tree; vm.catalogItems = ComponentList.nonSpecific; vm.organizationItems = ComponentList.buyerSpecific; vm.isCollapsed = true; diff --git a/src/app/base/less/base.less b/src/app/base/less/base.less index 2ae2db96..f686c75b 100644 --- a/src/app/base/less/base.less +++ b/src/app/base/less/base.less @@ -75,6 +75,31 @@ background-color:@navbar-default-bg; padding:@padding-base-horizontal; } + ul li ul { + background-color: #ffffff; + border-radius: 0 0 4px 4px; + border-left:2px solid #ebebeb; + padding-top: 5px; + li { + margin-left:10px !important; + margin-right: 5px !important; + &:last-child { + margin-bottom: 5px; + } + a { + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + } + &.active { + > a { + background-color:@brand-primary; + } + } + } + } + + } .navbar-flex { diff --git a/src/app/base/templates/base.left.tpl.html b/src/app/base/templates/base.left.tpl.html index 8d1cf88c..d8b89a47 100644 --- a/src/app/base/templates/base.left.tpl.html +++ b/src/app/base/templates/base.left.tpl.html @@ -6,6 +6,8 @@ + + + + + diff --git a/src/app/base/templates/base.top.tpl.html b/src/app/base/templates/base.top.tpl.html index dca18b79..0dabc69c 100644 --- a/src/app/base/templates/base.top.tpl.html +++ b/src/app/base/templates/base.top.tpl.html @@ -5,6 +5,7 @@ +
\ No newline at end of file diff --git a/src/app/base/tests/base.spec.js b/src/app/base/tests/base.spec.js index 896f0214..96abcf5d 100644 --- a/src/app/base/tests/base.spec.js +++ b/src/app/base/tests/base.spec.js @@ -1,4 +1,4 @@ -describe('Component: Base', function() { +xdescribe('Component: Base', function() { var q, scope, oc; @@ -71,7 +71,8 @@ describe('Component: Base', function() { }; beforeEach(inject(function($controller) { baseLeftCtrl = $controller('BaseLeftCtrl', { - ComponentList: fake_components + ComponentList: fake_components, + Order: null }); })); it ('should initialize the components lists', function() { diff --git a/src/app/common/impersonation/ordercloud-impersonation.js b/src/app/common/impersonation/ordercloud-impersonation.js deleted file mode 100644 index af9be22e..00000000 --- a/src/app/common/impersonation/ordercloud-impersonation.js +++ /dev/null @@ -1,98 +0,0 @@ -angular.module('ordercloud-impersonation', []) - - .factory('ImpersonationService', ImpersonationService) - .controller('BuyerUserSelectModalCtrl', ModalController) - -; -//TODO: Consider removing -function ImpersonationService(ApiClients, $q, $rootScope, $uibModal, $state, Users, Auth, toastr) { - return { - DecryptToken: DecryptToken, - Impersonation: Impersonation, - StopImpersonating: StopImpersonating - }; - - function DecryptToken() { - Auth.SetImpersonating(false); - var token = Auth.GetToken().split('.'); - return JSON.parse(atob(token[1])); - } - - function Impersonation(FunctionCall) { - var dfd = $q.defer(), - jwt = DecryptToken(); - if (jwt.type === 'Buyer') { - dfd.resolve(FunctionCall()); - } - else { - if (jwt.role === 'FullAccess') { - if (!Auth.GetImpersonating()) { - var modalInstance = $uibModal.open({ - animation: true, - templateUrl: 'common/impersonation/templates/buyer-user-modal.tpl.html', - controller: 'BuyerUserSelectModalCtrl', - controllerAs: 'modalSelect', - size: 'lg', - resolve: { - UserList: function( Users) { - return Users.List(); - } - } - }); - modalInstance.result - .then(function(selectedUser) { - ApiClients.List() - .then(function(apiList) { - Users.GetAccessToken(selectedUser.ID, {ClientID: apiList.Items[0].ID, Claims: ['FullAccess']}) - .then(function(token) { - Auth.SetImpersonationToken(selectedUser.ID, token["access_token"]); - Auth.SetImpersonating(true); - $rootScope.$broadcast('ImpersonationStarted'); - dfd.resolve(FunctionCall()); - }) - .catch(function() { - toastr.error('Could not set an impersonation token for the selected user.', 'Error:'); - }); - }) - .catch(function() { - toastr.error("No buyer client ids found.", 'Error:'); - }); - }) - .catch(function() { - $state.go('home'); - }); - } - else { - Auth.SetImpersonating(true); - dfd.resolve(FunctionCall()); - } - } - else { - toastr.error("You do not have permission to impersonate a buyer user.", 'Error:'); - } - } - return dfd.promise; - } - - function StopImpersonating() { - Auth.ClearImpersonationToken(); - Auth.SetImpersonating(false); - $rootScope.$broadcast('ImpersonationStopped'); - $state.go('home'); - } -} - -function ModalController($uibModalInstance, $state, UserList) { - var vm = this; - vm.list = UserList; - vm.selected = vm.list[0]; - - vm.selectUser = function(index) { - $uibModalInstance.close(vm.list.Items[index]); - }; - - vm.cancel = function() { - $uibModalInstance.dismiss('cancel'); - $state.go('home'); - }; -} diff --git a/src/app/common/impersonation/templates/buyer-user-modal.tpl.html b/src/app/common/impersonation/templates/buyer-user-modal.tpl.html deleted file mode 100644 index 9cd11591..00000000 --- a/src/app/common/impersonation/templates/buyer-user-modal.tpl.html +++ /dev/null @@ -1,37 +0,0 @@ -
- - -
- The selected buyer does not have any modalSelect. - No users match your search. -
-
-
-
- - - - - - - - - - - - - - - - -
-
ID
-
-
Name
-
{{user.ID}}{{user.Username}}
-
-
- -
From 2d262ff25a20f4c5e3423c86396bbc85703d7e0b Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 11 Mar 2016 15:07:44 -0600 Subject: [PATCH 050/367] Fix the files directive --- src/app/common/files/files.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/common/files/files.js b/src/app/common/files/files.js index e1cac304..811f02e7 100644 --- a/src/app/common/files/files.js +++ b/src/app/common/files/files.js @@ -90,7 +90,7 @@ function ordercloudFileUpload( $parse, Underscore, FileReader, FilesService ) { keyname: '@', label: '@', extensions: '@', - invalidExtension: '=' + invalidExtension: '@' }, restrict: 'E', templateUrl: 'common/files/templates/files.tpl.html', From beeaaf63d1e05a40438b06864fdae2f9c65d4485 Mon Sep 17 00:00:00 2001 From: Robert Watt Date: Mon, 14 Mar 2016 13:57:05 -0500 Subject: [PATCH 051/367] Delete vcs.xml --- .idea/vcs.xml | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 .idea/vcs.xml diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7f..00000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file From 01918bdddf91118985e230a471e53069ac25ab42 Mon Sep 17 00:00:00 2001 From: Robert Watt Date: Mon, 14 Mar 2016 13:57:24 -0500 Subject: [PATCH 052/367] Update .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index d8733b94..d2da6701 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ build/ compile/ node_modules/ vendor/ -temp/ \ No newline at end of file +temp/ +.idea From fa2a6a00df5233621f8f16e308702f4772c9bd0e Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 16 Mar 2016 12:25:08 -0500 Subject: [PATCH 053/367] Do not attempt to use component services in the Base This change is also reflected in components repo --- src/app/app.js | 1 + src/app/base/base.js | 18 +----------------- src/app/base/templates/base.left.tpl.html | 7 +++---- src/app/global.less | 4 ++++ 4 files changed, 9 insertions(+), 21 deletions(-) diff --git a/src/app/app.js b/src/app/app.js index 90087b96..d1ce22c6 100644 --- a/src/app/app.js +++ b/src/app/app.js @@ -66,6 +66,7 @@ function AppCtrl( $rootScope, $state, appname, OrderCloud ) { vm.name = appname; vm.title = appname; vm.showLeftNav = true; + vm.$state = $state; vm.toggleLeftNav = function() { vm.showLeftNav = !vm.showLeftNav; diff --git a/src/app/base/base.js b/src/app/base/base.js index 9f99cd30..42a81e1f 100644 --- a/src/app/base/base.js +++ b/src/app/base/base.js @@ -72,20 +72,6 @@ function BaseConfig( $stateProvider ) { }); deferred.resolve(components); return deferred.promise; - }, - Tree: function(CatalogTreeService, OrderCloud, CurrentUser) { - if (OrderCloud.Auth.ReadToken) { - var tokenInfo = atob(OrderCloud.Auth.ReadToken().split('.')[1]); - if (tokenInfo.usrtype === "buyer") { - return CatalogTreeService.GetCatalogTree(); - } - else { - return null; - } - } - else { - return null; - } } } }); @@ -96,12 +82,10 @@ function BaseController(CurrentUser) { vm.currentUser = CurrentUser; } -function BaseLeftController(ComponentList, Tree) { +function BaseLeftController(ComponentList) { var vm = this; - vm.tree = Tree; vm.catalogItems = ComponentList.nonSpecific; vm.organizationItems = ComponentList.buyerSpecific; - vm.isCollapsed = true; } function BaseTopController() { diff --git a/src/app/base/templates/base.left.tpl.html b/src/app/base/templates/base.left.tpl.html index d8b89a47..6606daf5 100644 --- a/src/app/base/templates/base.left.tpl.html +++ b/src/app/base/templates/base.left.tpl.html @@ -21,10 +21,9 @@

Organization

diff --git a/src/app/global.less b/src/app/global.less index 09670ae0..c24807f1 100644 --- a/src/app/global.less +++ b/src/app/global.less @@ -7,6 +7,10 @@ body { cursor: pointer; } +.container { + max-width:100%; +} + //TABLES WITH FIXED HEADERS .table-fixed-header { position:relative; From a009ef64e5144c59a256f541a429a530a8c26ee2 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 16 Mar 2016 13:34:16 -0500 Subject: [PATCH 054/367] Missing service method for the Repeat Order directive --- src/app/common/lineitems/lineitems.js | 29 ++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/app/common/lineitems/lineitems.js b/src/app/common/lineitems/lineitems.js index 36335aa1..35e116e7 100644 --- a/src/app/common/lineitems/lineitems.js +++ b/src/app/common/lineitems/lineitems.js @@ -12,7 +12,8 @@ function LineItemFactory($rootScope, $q, $state, $uibModal, Underscore, OrderClo UpdateQuantity: UpdateQuantity, GetProductInfo: GetProductInfo, CustomShipping: CustomShipping, - UpdateShipping: UpdateShipping + UpdateShipping: UpdateShipping, + ListAll: ListAll }; function SpecConvert(specs) { @@ -111,6 +112,32 @@ function LineItemFactory($rootScope, $q, $state, $uibModal, Underscore, OrderClo $rootScope.$broadcast('LineItemAddressUpdated', LineItem.ID, address); }); } + + function ListAll(orderID) { + var li; + var dfd = $q.defer(); + var queue = []; + OrderCloud.LineItems.List(orderID, 1, 100) + .then(function (data) { + li = data; + if (data.Meta.TotalPages > data.Meta.Page) { + var page = data.Meta.Page; + while (page < data.Meta.TotalPages) { + page += 1; + queue.push(OrderCloud.LineItems.List(orderID, page, 100)); + } + } + $q.all(queue) + .then(function (results) { + angular.forEach(results, function (result) { + li.Items = [].concat(li.Items, result.Items); + li.Meta = result.Meta; + }); + dfd.resolve(li.Items); + }); + }); + return dfd.promise; + } } function LineItemModalController($uibModalInstance) { From 6952c78de19dc054e369c2900b2bf4919ac60ca8 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Thu, 17 Mar 2016 10:27:16 -0500 Subject: [PATCH 055/367] initial commit for new gulp files --- .bowerrc | 5 -- .gitignore | 5 +- Gulp/README.md | 112 ---------------------------- Gulp/assetTasks.js | 133 ---------------------------------- Gulp/generalTasks.js | 56 -------------- Gulp/scriptTasks.js | 98 ------------------------- Gulp/testTasks.js | 53 -------------- Gulp/watchTasks.js | 60 --------------- Gulpfile.js | 13 ---- bower.json | 60 +++++++++------ changelog.tpl | 23 ------ gulp.config.js | 56 ++++++++++++++ gulp/build/inject.js | 20 +++++ gulp/build/scripts.js | 32 ++++++++ gulp/build/serve-build.js | 26 +++++++ gulp/build/styles.js | 31 ++++++++ gulp/compile/app-css.js | 36 +++++++++ gulp/compile/app-js.js | 37 ++++++++++ gulp/compile/fonts.js | 18 +++++ gulp/compile/images.js | 15 ++++ gulp/compile/index.js | 30 ++++++++ gulp/compile/lib-js.js | 22 ++++++ gulp/compile/serve-compile.js | 6 ++ gulp/serve.js | 62 ++++++++++++++++ gulp/test/SpecRunner.html | 128 ++++++++++++++++++++++++++++++++ gulp/test/e2e.js | 58 +++++++++++++++ gulp/test/plato.js | 57 +++++++++++++++ gulp/test/unit.js | 55 ++++++++++++++ gulpConfig.js | 71 ------------------ gulpfile.js | 6 ++ karma.conf.js | 70 ------------------ karma/karma-unit.tpl.js | 25 ------- package.json | 89 ++++++++++++++--------- protractor.config.js | 62 ++++++++++------ server.js | 48 ++++++------ 35 files changed, 857 insertions(+), 821 deletions(-) delete mode 100644 .bowerrc delete mode 100644 Gulp/README.md delete mode 100644 Gulp/assetTasks.js delete mode 100644 Gulp/generalTasks.js delete mode 100644 Gulp/scriptTasks.js delete mode 100644 Gulp/testTasks.js delete mode 100644 Gulp/watchTasks.js delete mode 100644 Gulpfile.js delete mode 100644 changelog.tpl create mode 100644 gulp.config.js create mode 100644 gulp/build/inject.js create mode 100644 gulp/build/scripts.js create mode 100644 gulp/build/serve-build.js create mode 100644 gulp/build/styles.js create mode 100644 gulp/compile/app-css.js create mode 100644 gulp/compile/app-js.js create mode 100644 gulp/compile/fonts.js create mode 100644 gulp/compile/images.js create mode 100644 gulp/compile/index.js create mode 100644 gulp/compile/lib-js.js create mode 100644 gulp/compile/serve-compile.js create mode 100644 gulp/serve.js create mode 100644 gulp/test/SpecRunner.html create mode 100644 gulp/test/e2e.js create mode 100644 gulp/test/plato.js create mode 100644 gulp/test/unit.js delete mode 100644 gulpConfig.js create mode 100644 gulpfile.js delete mode 100644 karma.conf.js delete mode 100644 karma/karma-unit.tpl.js diff --git a/.bowerrc b/.bowerrc deleted file mode 100644 index 1f984984..00000000 --- a/.bowerrc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "directory": "vendor", - "json": "bower.json" -} - diff --git a/.gitignore b/.gitignore index d2da6701..d4df87d5 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ build/ compile/ node_modules/ -vendor/ -temp/ +bower_components/ +errorShots/ .idea +plato/ \ No newline at end of file diff --git a/Gulp/README.md b/Gulp/README.md deleted file mode 100644 index 64e5e96e..00000000 --- a/Gulp/README.md +++ /dev/null @@ -1,112 +0,0 @@ -### The Build System - -The best way to learn about the build system is by familiarizing yourself with -Gulp and then looking through the code, `Gulpfile.js` and the Gulp folder. - But you don't need to do that to be very productive with -`OrderCloud`. What follows in this section is a quick introduction to the -tasks provided and should be plenty to get you started. - -Below is a description of the gulp tasks in the project, sorted by their general purpose -and location within the Gulp directory. - -####Asset Tasks -* `b_m:less` - Compiles all of the app and bower less files into css and moves the compiled file into the temp folder -* `b_m:sass` - Compiles all of the app and bower sass files into css and moves the compiled file into the temp folder -* `b_m:css` - Compiles all of the bower css files (with the exception of the font awesome file as it was already compiled -in `b_m:less`) into one file and autoprefixes the css to run for the last to versions of all the major browsers -* `b_m:appCss` - Compiles all of the app css files into one file and autoprefixes the css to run for the last to versions -of all the major browsers -* `b_m:styles` - Compiles all of the css files in the temp directory into one file, replaces the path to fonts to be correct -for the build directory and renames the file with the version of the app. Places the file in the build folder and injects the -change into browser-sync if it is currently running -* `b_c:styles` - Deletes all of the assets that have been moved over to the build folder and all of the files in the temp folder -* `b_m:assets` - Moves over all asset files (fonts and images) saved in the src/assets directory to the build/assets directory -* `b_m:fonts` - Moves over all fonts saved within the bower dependencies to the build/assets directory -* `b_c:assets` - Deletes all assets files from the build directory -* `c_m:css` - Minifies all css files in the build directory and moves them to the compile folder -* `c_c:css` - Deletes all css files from the compile directory -* `c_m:assets` - Moves over all asset files (fonts and images) from the build folder to the compile folder -* `c_c:assets` - Delete all asset and css files from the compile directory -* `build:styles` - Runs `b_c:styles`, `b_m:less`, `b_m:sass`, `b_m:css`, `b_m:appCss`, `b_m:styles` in order -* `compile:css` - Runs `c_c:css`, `build:styles`, `c_m:css` in order -* `build:assets` - Runs `b_c:assets`, `b_m:assets`, `b_m:fonts` in order -* `compile:assets` - Runs `c_c:assets`, `build:assets`, `c_m:assets` in order - -####General Tasks -* `compile:inject` - Injects the app dependencies into the index.html file for the compiled build -Note: Theere should only be two: `OrderCloud-[Version#].css` and `app.js` -* `build:inject` - Injects the app dependencies into the index.html file for the unminified build -* `masterClean` - Deletes the build, compile, and temp directories. Basically anything built by the gulp -tasks will be removed by this task -* `build` - First runs `master clean`, then runs `build:js_bower`, `build:js`, `build:templateCache`, `build:styles`, `build:assets`, -and lastly runs `build:inject` to create an unminified build of the project -* `compile` - First runs `build`, then runs `compile:js`, `compile:assets`, `compile:css` -and lastly runs `compile:inject` to create a minified build of the project -* `default` - Runs the `compile` task when only `gulp` is typed into the command prompt - -####Script Tasks -* `b_m:js_bower` - Moves the bower dependencies over to the build folder -* `b_c:js_bower` - Deletes bower dependencies form the build folder -* `b_m:js` - Moves over all of the app js files need to run the application (not the ones for unit testing) and -annotates them and wraps each file in an IIFE call. -* `b_c:js` - Deletes all of the javascript files moved over to the build folder except for the templateCache file -* `b_m:templateCache` - Creates an angular templateCache of all the html files (except the index) that -allows for the application to run faster. -* `b_c:templateCache` - Cleans out the compiled template file generated by `b_m:templateCache` -* `c_c:js` - Deletes all js files from the compile directory -* `build:js` - Runs `b_c:js`, and `b_m:js` in order -* `build:js_bower` - Runs `b_c:js_bower`, and `b_m:js_bower` in order -* `build:templateCache` - Runs `b_c:templateCache`, and `b_m:templateCache` in order -* `compile:js` - Runs `c_c:js`, `build:js_bower`, `build:js`, and `build:templateCache` at the same time, then runs -`c_m:js` - -####Test Tasks -* `testServe` - Starts the browser-sync server on localhost:12000 -Note: this task does not build the application first so you must run `gulp build` first for it to work. -This task differs from `dev` in that it opens a tunnel that allows the app to be viewed on other computers -not on the same network. - -####Watch Tasks -* `dev` - Starts the browser-sync server on localhost:8000 -* `karma:unit` - Starts the karma unit tests -* `watch:js` - Starts a process that watches for changes in the javascript files in the src directory -* `watch:assets` - Starts a process that watches for changes in the style sheet files (less and css) -* `watch:other` - Starts a process the watches for changes in the html files -* `watch` - Starts all of the previously mentioned tasks in parallel - -As covered in the previous section, `gulp build` and `gulp watch` will execute a full build -up-front and then run any of the aforementioned `watch` tasks as needed to -ensure the fastest possible build. So whenever you're working on your project, -start with: - -```sh -$ gulp build -``` - -then: - -```sh -$ gulp watch -``` - -And everything will be done automatically! - -### Build vs. Compile - -To make the build even faster, tasks are placed into two categories: build and -compile. The build tasks (like those we've been discussing) are the minimal -tasks required to run your app during development. - -Compile tasks, however, get your app ready for production. The compile tasks -include concatenation, minification, compression, etc. These tasks take a little -bit longer to run and are not at all necessary for development so are not called -automatically during build or watch. - -To initiate a full compile, you simply run the default task: - -```sh -$ gulp -``` - -This will perform a build and then a compile. The compiled site is located in `compile/`. -To test that your full site works as expected, open the `compile/index.html` file in your browser. Voila! diff --git a/Gulp/assetTasks.js b/Gulp/assetTasks.js deleted file mode 100644 index f0f53282..00000000 --- a/Gulp/assetTasks.js +++ /dev/null @@ -1,133 +0,0 @@ -//GENERAL -var gulp = require('gulp'); -var less = require('gulp-less'); -var sass = require('gulp-sass'); -var filter = require('gulp-filter'); -var autoprefixer = require('gulp-autoprefixer'); -var minify = require('gulp-minify-css'); -var mainBowerFiles = require('main-bower-files'); -var concat = require('gulp-concat'); -var del = require('del'); -var plumber = require('gulp-plumber'); -var lessImport = require('gulp-less-import'); -var replace = require('gulp-replace'); -var flatten = require('gulp-flatten'); - -var pkg = require('../package.json'); -var currVersion = pkg.name + "-" + pkg.version; -/*var lessFilter = filter('**!/!*.less'); -var sassFilter = filter(['**!/!*.sass', '**!/!*.scss']); -var cssFilter = filter('**!/!*.css');*/ - - -/*BUILD*/ - -gulp.task('b_m:less', function() { - return gulp.src(mainBowerFiles({filter: '**/*.less'}) - .concat(config.vendor_files.import_less).concat(config.app_files.import_less)) - .pipe(plumber()) - .pipe(lessImport('lessStyles.less')) - .pipe(less()) - .pipe(gulp.dest(config.temp)) -}); - -gulp.task('b_m:sass', function() { - return gulp.src(mainBowerFiles({filter: ['**/*.sass', '**/*.scss']}) - .concat([config.source + '**/*.scss', config.source + '**/*.sass'])) - .pipe(plumber()) - .pipe(sass()) - .pipe(concat(config.temp + 'sassStyles.css')) - .pipe(gulp.dest(config.temp)) -}); - -gulp.task('b_m:css', function() { - return gulp - .src(mainBowerFiles({filter: '**/*.css'}).concat('!**/font-awesome.css')) - .pipe(plumber()) - .pipe(autoprefixer({browsers: ['last 2 versions']})) - .pipe(concat('bowerStyles.css')) - .pipe(gulp.dest(config.temp)) -}); - -gulp.task('b_m:appCss', function() { - return gulp - .src(config.source + '**/*.css') - .pipe(plumber()) - .pipe(autoprefixer({browsers: ['last 2 versions']})) - .pipe(concat('appCss.css')) - .pipe(gulp.dest(config.temp)) -}); - -gulp.task('b_m:styles', function() { - return gulp - .src(config.temp + '*.css') - .pipe(replace('../fonts/', 'fonts/')) - .pipe(concat(currVersion + '.css')) - .pipe(gulp.dest(config.build + 'assets')) - .pipe(browserSync.stream()) -}); - -gulp.task('b_c:styles', function() { - return del([ - config.build + 'assets/**/*.css', - config.temp + '**/*' - ]); -}); - -gulp.task('b_m:assets', function() { - return gulp.src([ - config.source + 'assets/**/*', - '!' + config.source + '**/*.css', - '!' + config.source + '**/*.less', - '!' + config.source + '**/*.scss', - '!' + config.source + '**/*.sass']) - .pipe(gulp.dest(config.build + 'assets')) -}); - -gulp.task('b_m:fonts', function() { - return gulp.src('vendor/**/fonts/*', '!vendor/**/dist') - .pipe(flatten()) - .pipe(gulp.dest(config.build + 'assets/fonts')) -}); - -gulp.task('b_c:assets', function() { - return del([ - config.build + 'assets/**/*', - '!' + config.build + '**/*.css', - '!' + config.build + '**/*.less', - '!' + config.build + '**/*.scss', - '!' + config.build + '**/*.sass', - '!' + config.build + 'assets/fonts/**/*' - ]); -}); - -/*COMPILE*/ -gulp.task('c_m:css', function() { - return gulp.src(config.build + 'assets/**/*.css') - .pipe(minify()) - .pipe(gulp.dest(config.compile + 'assets/')); -}); - -gulp.task('c_c:css', function() { - return del([config.compile + '**/*.css']); -}); - -gulp.task('c_m:assets', function() { - return gulp.src([ - config.build + 'assets/**/*', - '!' + config.build + '**/*.css', - '!' + config.build + '**/*.less', - '!' + config.build + '**/*.scss', - '!' + config.build + '**/*.sass']) - .pipe(gulp.dest(config.compile + 'assets')) -}); - -gulp.task('c_c:assets', function() { - return del([config.compile + 'assets/**/*', '!' + config.compile + 'assets/**/*.css']); -}); - -//Master Asset Tasks -gulp.task('build:styles', gulp.series('b_c:styles', 'b_m:less', 'b_m:sass', 'b_m:css', 'b_m:appCss', 'b_m:styles')); -gulp.task('compile:css', gulp.series('c_c:css', 'c_m:css')); -gulp.task('build:assets', gulp.series('b_c:assets', 'b_m:assets', 'b_m:fonts')); -gulp.task('compile:assets', gulp.series('c_c:assets', 'c_m:assets')); \ No newline at end of file diff --git a/Gulp/generalTasks.js b/Gulp/generalTasks.js deleted file mode 100644 index f1fd82ff..00000000 --- a/Gulp/generalTasks.js +++ /dev/null @@ -1,56 +0,0 @@ -var gulp = require('gulp'); -var inject = require('gulp-inject'); -var del = require('del'); -var pkg = require('../package.json'); -var currVersion = pkg.name + "-" + pkg.version; - - -gulp.task('compile:inject', function() { - return gulp.src(config.source + 'index.html') - .pipe(inject(gulp.src(config.compile + '/**/*', {read:false}), {ignorePath: config.compile.replace('.', ''), addRootSlash: false})) - .pipe(gulp.dest(config.compile)); - -}); - -gulp.task('build:inject', function() { - //task injects dep into index.html - return gulp - .src(config.source + 'index.html') - .pipe(inject(gulp.src([config.build + 'vendor/jquery.js', config.build + 'vendor/localforage.js', config.build + 'vendor/**/angular.js', config.build + 'vendor/**/*.js'], {read:false}), {name: 'bower', ignorePath: config.build.replace('.', ''), addRootSlash: false})) - .pipe(inject(gulp.src([ - config.build + 'src/templates-app.js', - config.build + 'src/app/app.js', - config.build + '**/*.module.js', - config.build + '**/*.config.js', - config.build + '**/*.svc.js', - config.build + '**/*.ctrl.js', - config.build + '**/*.js', - config.build + 'assets/**/*.css', - "!" + config.build + 'src/**/*.spec.js', - "!" + config.build + 'src/**/*.test.js', - '!' + config.build + 'vendor/**/*'], {read:false}), {ignorePath: config.build.replace('.', ''), addRootSlash: false})) - .pipe(gulp.dest(config.build)); -}); - - -gulp.task('masterClean', function() { - return del([ - config.build, - config.compile, - config.temp - ]); -}); - -//Major Project Build Tasks -gulp.task('build', gulp.series( - 'masterClean', - gulp.parallel('build:js_bower', 'build:js', 'build:templateCache', 'build:styles', 'build:assets'), - 'build:inject')); - -//Major Project Compile Tasks -gulp.task('compile', gulp.series( - 'build', - gulp.parallel('compile:js', 'compile:assets', 'compile:css'), - 'compile:inject')); - -gulp.task('default', gulp.series('compile')); \ No newline at end of file diff --git a/Gulp/scriptTasks.js b/Gulp/scriptTasks.js deleted file mode 100644 index 06487201..00000000 --- a/Gulp/scriptTasks.js +++ /dev/null @@ -1,98 +0,0 @@ -var gulp = require('gulp'); -var ngConstant = require('gulp-ng-constant'); -//var header = require('gulp-header'); -var concat = require('gulp-concat'); -var mainBowerFiles = require('main-bower-files'); -var uglify = require('gulp-uglify'); -var filter = require('gulp-filter'); -var wrap = require('gulp-wrapper'); -var templatecache = require('gulp-angular-templatecache'); -var del = require('del'); -var ngAnnotate = require('gulp-ng-annotate'); - - -var pkg = require('../package.json'); -var banner = config.banner; -var currVersion = pkg.name + "-" + pkg.version; -var appJS = config.app_files.js; - - - -gulp.task('b_m:js_bower', function() { - return gulp - .src(mainBowerFiles({filter: ['**/*.js', '!**/bootstrap.js']})) - .pipe(filter('**/*.js')) - .pipe(gulp.dest(config.build + 'vendor')); -}); - -gulp.task('b_c:js_bower', function() { - return del([ - config.build + 'vendor' - ]); -}); - -gulp.task('b_m:js', function() { - return gulp - .src(['./src/**/*.js', '!**/*spec.js', '!**/*.test.js']) - .pipe(ngAnnotate()) - .pipe(wrap({ - header: "(function ( window, angular, undefined ) {\n 'use strict';\n", - footer: "})( window, window.angular );\n" - })) - .pipe(gulp.dest(config.build + 'src')); -}); - -gulp.task('b_c:js', function() { - return del([ - config.build + 'src/**/*.js', - '!' + config.build + 'src/**/templates-app.js' - ]); -}); - -gulp.task('b_m:templateCache', function() { - return gulp - .src('./src/app/**/*.tpl.html') - .pipe(templatecache('templates-app.js',{ - standalone: true, - module: 'templates-app', - moduleSystem: 'IIFE'})) - .pipe(gulp.dest(config.build + 'src/')); -}); - -gulp.task('b_c:templateCache', function() { - return del([ - config.build + 'src/templates-app.js' - ]); -}); - -gulp.task('c_m:js', function() { - return gulp - .src([config.build + 'vendor/jquery.js', - config.build + 'vendor/localforage.js', - config.build + 'vendor/angular.js', - config.build + 'vendor/**/*.js', - config.build + 'src/templates-app.js', - config.build + 'src/app/app.js', - //config.build + 'src/app/app.config.js', - config.build + 'src/**/*.js' - ]) - .pipe(concat('app.js')) - .pipe(uglify({mangle: false})) - .pipe(gulp.dest(config.compile + 'assets')); -}); - -gulp.task('c_c:js', function(){ - return del([ - config.compile + '**/*.js' - ]); -}); - - - -//Master Script Build Tasks -gulp.task('build:js', gulp.series('b_c:js', 'b_m:js')); -gulp.task('build:js_bower', gulp.series('b_c:js_bower', 'b_m:js_bower')); -gulp.task('build:templateCache', gulp.series('b_c:templateCache', 'b_m:templateCache')); - -//Master Script Compile Tasks -gulp.task('compile:js', gulp.series('c_c:js', 'c_m:js')); diff --git a/Gulp/testTasks.js b/Gulp/testTasks.js deleted file mode 100644 index c6f3130c..00000000 --- a/Gulp/testTasks.js +++ /dev/null @@ -1,53 +0,0 @@ -var gulp = require('gulp'); -var browserSync = require('browser-sync').create(); - -//Enter Server Info Here -var appName = null; //used for externally accessible site... must only include letters ('_', '-' not allowed) -var portNumber = 12000; //used for localhost -var protractor = require('gulp-angular-protractor'); - -if (appName) { - appName = appName.toLowerCase(); -} - -if (portNumber) { - if (isNaN(portNumber)) { - portNumber = null; - console.log('portNumber must be numeric'); - } - if (portNumber < 10000 || portNumber > 65536) { - portNumber = null; - } -} - -gulp.task('testServe', function() { - browserSync.init({ - server: { - baseDir: config.build, - index: 'index.html', - routes: '' - }, - port: (portNumber || 8000), - ghostMode: { - clicks: false, - forms: false, - scroll: false - }, - logPrefix: 'OrderCloud 3.0', - tunnel: 'ordercloudapp' + (appName || '') - }) -}); - -gulp.task('protractor', function () { - return gulp - .src(config.src + '**/login.test.js', config.src + '**/*.test.js') - .pipe(protractor({ - configFile: './protractor.config.js', - args: ['--baseUrl', 'http://localhost:8000'], - autoStartStopServer: true, - debug: true - })) - .on('error', function(e) { - throw e; - }); -}); diff --git a/Gulp/watchTasks.js b/Gulp/watchTasks.js deleted file mode 100644 index 62f76696..00000000 --- a/Gulp/watchTasks.js +++ /dev/null @@ -1,60 +0,0 @@ -gulp = require('gulp'); -mainBowerFiles = require('main-bower-files'); - -var server = 'server.js'; -var vendorJS = mainBowerFiles({filter:'**/*.js'}); -var Server = require('karma').Server; - -var gulp = require('gulp'); -browserSync = require('browser-sync').create(); - -browserSync.emitter.on('init', function() { - console.log("Browsersync is running..."); -}); - -gulp.task('dev', function() { - browserSync.init({ - server: { - baseDir: config.build, - index: 'index.html', - routes: '' - }, - port: 8000, - ghostMode: { - clicks: false, - forms: false, - scroll: false - }, - logPrefix: 'OrderCloud 3.0' - }) -}); - -gulp.task('test', function(done) { - new Server({ - configFile: __dirname + '/../karma.conf.js', - singleRun: true - }, done).start(); -}); - -gulp.task('watch:js', function() { - console.log("running 'watch:js' task"); - gulp.watch(config.app_files.js, gulp.parallel(gulp.series('build:js', 'build:assets', 'build:styles', 'build:inject', function() {browserSync.reload()}))); - gulp.watch(vendorJS, gulp.series('build:js_bower', 'build:inject', function() {browserSync.reload()})); -}); - -gulp.task('watch:assets', function() { - console.log("running 'watch:assets' task"); - gulp.watch(config.app_files.assets, gulp.series('build:assets', 'build:inject', function() {browserSync.reload()})); - gulp.watch(config.supportedStyles, gulp.series('build:styles')); -}); - -gulp.task('watch:other', function() { - console.log("running 'watch:other' task"); - gulp.watch(config.app_files.atpl, gulp.series('build:templateCache', 'build:assets', 'build:inject', function() {browserSync.reload()})); - gulp.watch(config.source + config.index, gulp.series( 'build:inject', function() {browserSync.reload()})); -}); - - //TODO: need to add new/deleted file watch if it ever comes available in gulp 4.0 - - -gulp.task('watch', gulp.parallel('dev', 'watch:js', 'watch:assets', 'watch:other')); diff --git a/Gulpfile.js b/Gulpfile.js deleted file mode 100644 index 9420eb12..00000000 --- a/Gulpfile.js +++ /dev/null @@ -1,13 +0,0 @@ -//Global gulp variables -var gulp = require('gulp'); -config = require('./gulpConfig'); -var path = require('path'); - - -//require gulpfiles in order... - -require('./Gulp/scriptTasks'); -require('./Gulp/assetTasks'); -require('./Gulp/generalTasks'); -require('./Gulp/watchTasks'); -require('./Gulp/testTasks'); \ No newline at end of file diff --git a/bower.json b/bower.json index 9fe0b47e..7a9c96cc 100644 --- a/bower.json +++ b/bower.json @@ -1,25 +1,43 @@ { - "name": "orderCloud", - "version": "0.0.3", - "devDependencies": { - "angular-mocks": "~1.4.0" - }, + "name": "OrderCloud-Components", + "authors": [ + "Four51" + ], + "description": "repo for managing ordercloud components that serve as a starting point for creating B2B applications on the Four51 OrderCloud platform.", + "main": "index", + "moduleType": [], + "keywords": [ + "OrderCloud", + "Four51", + "AngularJS", + "Angular", + "B2B" + ], + "license": "MIT", + "homepage": "https://devcenter.ordercloud.io/home", + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ], "dependencies": { - "angular": "~1.4.0", - "angular-animate": "~1.4.0", - "angular-auto-validate": "~1.18.17", - "angular-messages": "~1.4.0", - "angular-sanitize": "~1.4.0", - "angular-touch": "~1.4.0", - "angular-ui-router": "~0.2.14", - "bootstrap": "~3.3.5", - "font-awesome": "~4.3.0", - "jquery": "~2.1.3", - "angular-toastr": "~1.5.0", - "angular-bootstrap": "~0.14.3", - "angular-ui-tree": "~2.10.0", - "ordercloud-ng-sdk": "~1.0.5", - "underscore": "^1.8.3", - "angular-localforage": "^1.2.5" + "bootstrap": "^3.3.6", + "angular-sanitize": "^1.5.0", + "angular-touch": "^1.5.0", + "angular-ui-router": "^0.2.17", + "angular-toastr": "^1.7.0", + "angular-ui-tree": "^2.15.0", + "angular-animate": "^1.5.0", + "angular-messages": "^1.5.0", + "angular-bootstrap": "^1.1.2", + "ordercloud-ng-sdk": "^1.0.1", + "OrderCloud-Angular-SDK": "ordercloud-angular-sdk#^1.0.9", + "angular-auto-validate": "^1.19.3", + "font-awesome": "^4.5.0" + }, + "devDependencies": { + "angular-mocks": "^1.5.0" } } diff --git a/changelog.tpl b/changelog.tpl deleted file mode 100644 index c0274e4a..00000000 --- a/changelog.tpl +++ /dev/null @@ -1,23 +0,0 @@ - -# <%= version%> (<%= today%>) - -<% if (_(changelog.feat).size() > 0) { %> ## Features -<% _(changelog.feat).forEach(function(changes, scope) { %> -- **<%= scope%>:** - <% changes.forEach(function(change) { %> - <%= change.msg%> (<%= helpers.commitLink(change.sha1) %>) - <% }); %> -<% }); %> <% } %> - -<% if (_(changelog.fix).size() > 0) { %> ## Fixes -<% _(changelog.fix).forEach(function(changes, scope) { %> -- **<%= scope%>:** - <% changes.forEach(function(change) { %> - <%= change.msg%> (<%= helpers.commitLink(change.sha1) %>) - <% }); %> -<% }); %> <% } %> - -<% if (_(changelog.breaking).size() > 0) { %> ## Breaking Changes -<% _(changelog.breaking).forEach(function(changes, scope) { %> -- **<%= scope%>:** - <% changes.forEach(function(change) { %> <%= change.msg%> - <% }); %> -<% }); %> <% } %> diff --git a/gulp.config.js b/gulp.config.js new file mode 100644 index 00000000..c98bcd9c --- /dev/null +++ b/gulp.config.js @@ -0,0 +1,56 @@ +var source = './src/', + assets = 'assets/', + build = './build/', + bowerFiles = './bower_components/', + npmFiles = './node_modules', + compile = './compile/', + index = 'index.html', + gulp_dir = './gulp/'; + +module.exports = { + bowerFiles: bowerFiles, + npmFiles: npmFiles, + src: source, + build: build, + compile: compile, + assets: assets, + appCss: assets + 'styles/', + appFonts: assets + 'fonts/', + appImages: assets + 'images', + root: __dirname, + gulp: gulp_dir, + index: source + index, + styles: [ + source + '**/*.css', + source + '**/*.less' + ], + templates: [ + '!' + source + index, + source + 'app/**/*.html' + ], + scripts: [ + source + '**/*.js', + '!' + source + '**/*.spec.js', + '!' + source + '**/*.test.js' + ], + appFiles: [ + build + '**/*.js', + build + '**/*.css', + source + '**/*.css' + ], + wrapper: { + header: '(function() {\n"use strict";\n', + footer: '}());' + }, + templateCacheSettings: { + standalone: false, + moduleSystem: 'IIFE', + module: 'orderCloud' + }, + autoprefixerSettings: { + browsers: ['last 2 versions'], + cascade: true + }, + jsCache: 'jsscripts', + indentSize: 4 +}; diff --git a/gulp/build/inject.js b/gulp/build/inject.js new file mode 100644 index 00000000..6ba7bd63 --- /dev/null +++ b/gulp/build/inject.js @@ -0,0 +1,20 @@ +var gulp = require('gulp'), + config = require('../../gulp.config'), + del = require('del'), + inject = require('gulp-inject'), + mainBowerFiles = require('main-bower-files'); + +gulp.task('clean:inject', function() { + return del(config.build + '*.html'); +}); + +gulp.task('inject', ['clean:inject', 'scripts', 'styles'], function() { + var target = gulp.src(config.index), + bowerFiles = gulp.src(mainBowerFiles({filter: ['**/*.js', '**/*.css']}), {read: false}), + appFiles = gulp.src(config.appFiles, {read: false}); + + return target + .pipe(inject(bowerFiles, {name: 'bower'})) + .pipe(inject(appFiles)) + .pipe(gulp.dest(config.build)); +}); diff --git a/gulp/build/scripts.js b/gulp/build/scripts.js new file mode 100644 index 00000000..20982f8d --- /dev/null +++ b/gulp/build/scripts.js @@ -0,0 +1,32 @@ +var gulp = require('gulp'), + config = require('../../gulp.config'), + cache = require('gulp-cached'), + del = require('del'), + inject = require('gulp-inject'), + wrapper = require('gulp-wrapper'), + beautify = require('gulp-beautify'), + ngAnnotate = require('gulp-ng-annotate'); + +gulp.task('clean:scripts', function() { + return del(config.build + '**/*.js'); +}); + +gulp.task('scripts', ['clean:scripts'], function() { + return gulp + .src(config.scripts) + .pipe(cache(config.jsCache)) + .pipe(ngAnnotate()) + .pipe(wrapper(config.wrapper)) + .pipe(beautify({indentSize: config.indentSize})) + .pipe(gulp.dest(config.build)); +}); + +gulp.task('rebuild-scripts', function() { + return gulp + .src(config.scripts) + .pipe(cache('jsscripts')) + .pipe(ngAnnotate()) + .pipe(wrapper(config.wrapper)) + .pipe(beautify({indentSize: config.indentSize})) + .pipe(gulp.dest(config.build)); +}); diff --git a/gulp/build/serve-build.js b/gulp/build/serve-build.js new file mode 100644 index 00000000..3e9654b1 --- /dev/null +++ b/gulp/build/serve-build.js @@ -0,0 +1,26 @@ +var gulp = require('gulp'), + config = require('../../gulp.config'), + browserSync = require('browser-sync'), + argv = require('yargs') + .count('debug') + .alias('d', 'debug') + .argv, + serve = require('../serve'), + unit = require('../test/unit'), + plato = require('../test/plato'); + +gulp.task('serve-build', ['inject'], function() { + gulp.watch(config.src + '**/*.html') + .on('change', browserSync.reload); + gulp.watch(config.scripts, ['rebuild-scripts', 'report']) + .on('change', browserSync.reload); + gulp.watch(config.styles, ['styles']); + if (argv.debug) { + unit.RunUnitTests(); + unit.ServeTests(); + plato.GenerateReport(function () { + plato.OpenReport(); + }); + } + serve(true /*isDev*/); +}); diff --git a/gulp/build/styles.js b/gulp/build/styles.js new file mode 100644 index 00000000..c2970890 --- /dev/null +++ b/gulp/build/styles.js @@ -0,0 +1,31 @@ +var gulp = require('gulp'), + config = require('../../gulp.config'), + browserSync = require('browser-sync'), + del = require('del'), + less = require('gulp-less'), + autoprefixer = require('gulp-autoprefixer'), + lessImport = require('gulp-less-import'), + sourcemaps = require('gulp-sourcemaps'), + filter = require('gulp-filter'), + concat = require('gulp-concat'), + mainBowerFiles = require('main-bower-files'); + +gulp.task('clean:styles', function() { + return del(config.build + '**/*.css'); +}); + +gulp.task('styles', ['clean:styles'], function() { + return gulp + .src([].concat( + mainBowerFiles({filter: '**/*.less'}), + config.src + '**/*.less' + )) + .pipe(sourcemaps.init()) + .pipe(lessImport('oc-import.less')) + .pipe(less()) + .pipe(autoprefixer(config.autoprefixerSettings)) + .pipe(concat('app.css')) + .pipe(sourcemaps.write('../maps')) + .pipe(gulp.dest(config.build + config.appCss)) + .pipe(browserSync.stream()); +}); diff --git a/gulp/compile/app-css.js b/gulp/compile/app-css.js new file mode 100644 index 00000000..e688f050 --- /dev/null +++ b/gulp/compile/app-css.js @@ -0,0 +1,36 @@ +var gulp = require('gulp'), + config = require('../../gulp.config'), + del = require('del'), + rev = require('gulp-rev'), + concat = require('gulp-concat'), + filter = require('gulp-filter'), + less = require('gulp-less'), + lessImport = require('gulp-less-import'), + autoprefixer = require('gulp-autoprefixer'), + mainBowerFiles = require('main-bower-files'), + csso = require('gulp-csso'); + +gulp.task('clean:app-css', function() { + return del(config.compile + '**/*.css'); +}); + +gulp.task('app-css', ['clean:app-css'], function() { + var lessFilter = filter('**/*.less', {restore: true}), + cssFilter = filter('**/*.css'); + + return gulp + .src([].concat( + mainBowerFiles({filter: ['**/*.css', '**/*.less']}), + config.styles + )) + .pipe(lessFilter) + .pipe(lessImport('app.less')) + .pipe(less()) + .pipe(lessFilter.restore) + .pipe(cssFilter) + .pipe(autoprefixer(config.autoprefixerSettings)) + .pipe(csso()) + .pipe(concat('app.css')) + .pipe(rev()) + .pipe(gulp.dest(config.compile + config.appCss)); +}); diff --git a/gulp/compile/app-js.js b/gulp/compile/app-js.js new file mode 100644 index 00000000..21497199 --- /dev/null +++ b/gulp/compile/app-js.js @@ -0,0 +1,37 @@ +var gulp = require('gulp'), + config = require('../../gulp.config'), + del = require('del'), + ngAnnotate = require('gulp-ng-annotate'), + rev = require('gulp-rev'), + concat = require('gulp-concat'), + filter = require('gulp-filter'), + templateCache = require('gulp-angular-templatecache'), + htmlmin = require('gulp-htmlmin'), + uglify = require('gulp-uglify'), + wrapper = require('gulp-wrapper'); + +gulp.task('clean:app-js', function() { + return del(config.compile + 'js/app*.js'); +}); + +gulp.task('app-js', ['clean:app-js'], function() { + var htmlFilter = filter('**/*.html', {restore: true}), + jsFilter = filter('**/*.js'); + + return gulp + .src([].concat( + config.scripts, + config.templates + )) + .pipe(htmlFilter) + .pipe(htmlmin({collapseWhitespace: true, removeComments: true})) + .pipe(templateCache(config.templateCacheSettings)) + .pipe(htmlFilter.restore) + .pipe(jsFilter) + .pipe(wrapper(config.wrapper)) + .pipe(ngAnnotate()) + .pipe(concat('app.js')) + .pipe(rev()) + .pipe(uglify()) + .pipe(gulp.dest(config.compile + 'js/')) +}); diff --git a/gulp/compile/fonts.js b/gulp/compile/fonts.js new file mode 100644 index 00000000..3f83e194 --- /dev/null +++ b/gulp/compile/fonts.js @@ -0,0 +1,18 @@ +var gulp = require('gulp'), + config = require('../../gulp.config'), + flatten = require('gulp-flatten'), + del = require('del'); + +gulp.task('clean:fonts', function() { + return del(config.compile + config.appFonts); +}); + +gulp.task('fonts', ['clean:fonts'], function() { + return gulp + .src([].concat( + config.bowerFiles + '*/fonts/**/*', + config.src + config.appFonts + '**/*' + )) + .pipe(flatten()) + .pipe(gulp.dest(config.compile + config.appFonts)) +}); diff --git a/gulp/compile/images.js b/gulp/compile/images.js new file mode 100644 index 00000000..570ba12e --- /dev/null +++ b/gulp/compile/images.js @@ -0,0 +1,15 @@ +var gulp = require('gulp'), + config = require('../../gulp.config'), + imagemin = require('gulp-imagemin'), + del = require('del'); + +gulp.task('clean:images', function() { + return del(config.compile + config.appImages); +}); + +gulp.task('images', ['clean:images'], function() { + return gulp + .src(config.src + config.appImages + '**/*') + .pipe(imagemin()) + .pipe(gulp.dest(config.compile + config.appImages)); +}); diff --git a/gulp/compile/index.js b/gulp/compile/index.js new file mode 100644 index 00000000..c27b7298 --- /dev/null +++ b/gulp/compile/index.js @@ -0,0 +1,30 @@ +var gulp = require('gulp'), + config = require('../../gulp.config'), + del = require('del'), + inject = require('gulp-inject'); + +gulp.task('clean-index', function() { + return del(config.compile + '**/*.html'); +}); + +gulp.task('index', ['clean-index', 'app-js', 'lib-js', 'app-css', 'fonts', 'images'], function() { + var target = gulp.src(config.index), + libFiles = gulp.src(config.compile + '**/lib*.js', {read: false}), + appFiles = gulp.src([config.compile + '**/app*.js', config.compile + '**/*.css'], {read: false}); + + return target + .pipe(inject(libFiles, { + removeTags: true, + empty: true, + ignorePath: config.compile.replace('./', '').replace('/', ''), + addRootSlash: false, + name: 'bower' + })) + .pipe(inject(appFiles, { + removeTags: true, + empty: true, + ignorePath: config.compile.replace('./', '').replace('/', ''), + addRootSlash: false + })) + .pipe(gulp.dest(config.compile)); +}); diff --git a/gulp/compile/lib-js.js b/gulp/compile/lib-js.js new file mode 100644 index 00000000..a07493c8 --- /dev/null +++ b/gulp/compile/lib-js.js @@ -0,0 +1,22 @@ +var gulp = require('gulp'), + config = require('../../gulp.config'), + del = require('del'), + rev = require('gulp-rev'), + mainBowerFiles = require('main-bower-files'), + concat = require('gulp-concat'), + uglify = require('gulp-uglify'), + ngAnnotate = require('gulp-ng-annotate'); + +gulp.task('clean:lib-js', function() { + return del(config.compile + 'js/lib*.js'); +}); + +gulp.task('lib-js', ['clean:lib-js'], function() { + return gulp + .src(mainBowerFiles({filter: '**/*.js'})) + .pipe(ngAnnotate()) + .pipe(uglify()) + .pipe(concat('lib.js')) + .pipe(rev()) + .pipe(gulp.dest(config.compile + 'js')) +}); diff --git a/gulp/compile/serve-compile.js b/gulp/compile/serve-compile.js new file mode 100644 index 00000000..71fb9fab --- /dev/null +++ b/gulp/compile/serve-compile.js @@ -0,0 +1,6 @@ +var gulp = require('gulp'), + serve = require('../serve'); + +gulp.task('serve-compile', ['index'], function() { + serve(false /*isDev*/); +}); diff --git a/gulp/serve.js b/gulp/serve.js new file mode 100644 index 00000000..69df4640 --- /dev/null +++ b/gulp/serve.js @@ -0,0 +1,62 @@ +(function () { + 'use strict'; + + var nodemon = require('gulp-nodemon'), + config = require('../gulp.config'), + cache = require('gulp-cached'), + browserSync = require('browser-sync').create(), + port = process.env.PORT || 7203; + + function startBrowerSync () { + if (browserSync.active) { + return; + } + + browserSync.init({ + proxy: 'localhost:' + port, + port: 3000, + ghostMode: { + clicks: true, + forms: true, + scroll: true + }, + injectChanges: true, + logFileChanges: true, + logPrefix: 'OrderCloud-Components' + }); + } + + module.exports = function (isDev) { + return nodemon ({ + script: './server.js', + delayTime: 1, + env: { + 'PORT': port, + 'NODE_ENV': isDev ? 'dev' : 'prod' + }, + watch: ['./server.js'] + }) + .on('start', function () { + console.log('*** NODEMON STARTED ***'); + startBrowerSync(); + }) + .on('restart', ['vet'], function (env) { + console.log('*** NODEMON RESTARTED ***'); + console.log('*** FILES CHANGED ON RESTART: ***\n' + env); + console.log('FILES CHANGED:\n' + env); + setTimeout(function () { + browserSync.notify('*** RELOADING NOW ***'); + browserSync.reload({ stream: false }); + }, 1000); + }) + .on('crash', function () { + delete cache.caches['jsscripts']; + console.log('*** NODEMON CRASHED ***'); + }) + .on('exit', function () { + delete cache.caches['jsscripts']; + console.log('*** NODEMON EXITED ***'); + }); + }; + +}()); diff --git a/gulp/test/SpecRunner.html b/gulp/test/SpecRunner.html new file mode 100644 index 00000000..2f274552 --- /dev/null +++ b/gulp/test/SpecRunner.html @@ -0,0 +1,128 @@ + + + + + Jasmine Spec Runner v2.4.1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gulp/test/e2e.js b/gulp/test/e2e.js new file mode 100644 index 00000000..9483fc81 --- /dev/null +++ b/gulp/test/e2e.js @@ -0,0 +1,58 @@ +var gulp = require('gulp'), + argv = require('yargs').argv, + selenium = require('selenium-standalone'), + browserSync = require('browser-sync'), + protractor = require("gulp-protractor").protractor; + +gulp.task('selenium', function (done) { + selenium.install({ + drivers: { + chrome: { + version: '2.9', + arch: process.arch, + baseURL: 'https://chromedriver.storage.googleapis.com' + } + }, + logger: function(message) { + console.log(message); + } + }, function (err) { + if (err) return done(err); + + selenium.start(function (err, child) { + if (err) return done(err); + selenium.child = child; + done(); + }); + }); +}); + +gulp.task('http', ['inject'], function(done) { + browserSync({ + logLevel: 'silent', + notify: false, + open: false, + port: 9000, + server: { + baseDir: ['./src/app/', './dev', './'] + }, + ui: false + }, done); +}); + +gulp.task('test:e2e', ['http'/*, 'selenium'*/], function() { + return gulp + .src('./src/**/*.test.js') + .pipe(protractor({ + configFile: 'protractor.config.js', + args: [ + '--baseUrl', argv.baseUrl || 'http://localhost:9000', + '--suite', argv.suite || 'all' + ] + })) + .on('error', function(e) { throw e }) + .once('end', function() { + browserSync.exit(); + selenium.child.kill(); + }); +}); diff --git a/gulp/test/plato.js b/gulp/test/plato.js new file mode 100644 index 00000000..75e4d5d7 --- /dev/null +++ b/gulp/test/plato.js @@ -0,0 +1,57 @@ +var gulp = require('gulp'), + browserSync = require('browser-sync').create(), + plato = require('plato'); + +gulp.task('report', function(done) { + generateReport(done); +}); + +gulp.task('plato', ['report'], function() { + openReport(); +}); + +function generateReport(done) { + var files = [ + './dev/**/*.js', + '!./dev/**/*.test.js', + '!./dev/**/*.spec.js' + ]; + + var outputDir = './plato/dir'; + var options = { + title: 'Components Code Analysis' + }; + + var callback = function(report) { + plato.getOverviewReport(report); + if (done) { + done(); + } + }; + + plato.inspect(files, outputDir, options, callback); +} + +function openReport() { + browserSync.init({ + logLevel: 'silent', + notify: false, + open: true, + port: 453, + files: [ + './plato/dir/files/**/*' + ], + server: { + index: 'index.html', + baseDir: [ + './plato/dir/' + ] + }, + ui: false + }); +} + +module.exports = { + GenerateReport: generateReport, + OpenReport: openReport +} diff --git a/gulp/test/unit.js b/gulp/test/unit.js new file mode 100644 index 00000000..65dc216b --- /dev/null +++ b/gulp/test/unit.js @@ -0,0 +1,55 @@ +var gulp = require('gulp'), + inject = require('gulp-inject'), + browserSync = require('browser-sync').create(), + mainBowerFiles = require('main-bower-files'); + +gulp.task('test:unit', ['scripts'], function() { + runUnitTests(); + serveTests(); +}); + +function runUnitTests() { + var target = gulp.src('./gulp/test/SpecRunner.html'), + bowerFiles = gulp.src(mainBowerFiles({includeDev: true, filter: '**/*.js'}), {read: false}), + appFiles = gulp.src(['./dev/**/*.js'], {read: false}), + specFiles = gulp.src('./src/**/*.spec.js', {read: false}), + jasmineFiles = gulp.src([ + './node_modules/jasmine-core/lib/jasmine-core/jasmine.css', + './node_modules/jasmine-core/lib/jasmine-core/jasmine.js', + './node_modules/jasmine-core/lib/jasmine-core/jasmine-html.js', + './node_modules/jasmine-core/lib/jasmine-core/boot.js' + ], {read:false}); + + return target + .pipe(inject(jasmineFiles, {name: 'jasmine', relative: true})) + .pipe(inject(bowerFiles, {name: 'bower', relative: true})) + .pipe(inject(appFiles, {relative: true})) + .pipe(inject(specFiles, {name: 'spec', relative: true})) + .pipe(gulp.dest('./gulp/test/')); +} + +function serveTests() { + browserSync.init({ + logLevel: 'silent', + notify: false, + open: true, + port: 452, + files: [ + './dev/**/*.js' + ], + server: { + index: 'SpecRunner.html', + baseDir: [ + __dirname, + __dirname + '/../../' + ] + }, + ui: false + }); +} + +module.exports = { + RunUnitTests: runUnitTests, + ServeTests: serveTests +}; + diff --git a/gulpConfig.js b/gulpConfig.js deleted file mode 100644 index 414b26b5..00000000 --- a/gulpConfig.js +++ /dev/null @@ -1,71 +0,0 @@ -var source = './src/'; -var build = './build/'; -var compile = './compile/'; -var root = './'; -var index = 'index.html'; -var temp = './temp/'; -var gulp_dir = './Gulp'; - -module.exports = { - source: source, - gulp_dir: gulp_dir, - banner: ['/**', - ' * <%= pkg.name %> - <%= pkg.description %>', - ' * @version v<%= pkg.version %>', - ' * @link <%= pkg.homepage %>', - ' * @license <%= pkg.licenses.url %>', - ' */', - ''].join('\n'), - allCSS: [ - source + '**/*.css', - source + '**/*.less', - source + '**/*.sass' - ], - allHTML: [ - source + '**/*.html' - ], - allJS: [ - source + '**/*.js', - './*.js', - './gulp/**/*.js' - ], - build: build, - compile: compile, - fonts: [ - source + 'assets/fonts/**.*' - ], - htmlTemplates: [ - source + '**/*.html', - '!' + source + index - ], - index: index, - npm_pkg: './package.json', - bower_pkg: './bower.json', - src: source, - supportedStyles: [ - source + '**/*.css', - source + '**/*.less', - source + '**/*.sass', - source + '**/*.scss' - ], - temp: temp, - root: root, - app_files: { - js: [ - source + '**/*.js', - '!' + source + '**/*.spec.js', - '!' + source + '**/*.test.js', - '!' + source + 'assets/**/*.js' - ], - assets: [source + 'assets/**'], - jsunit: [ source + '**/*.spec.js' ], - - atpl: [ source + 'app/**/*.tpl.html' ], - - html: [ source + 'index.html' ], - import_less: [ source + 'app/**/*.less' ] - }, - vendor_files: { - import_less: ['vendor/font-awesome/less/font-awesome.less'] - } -}; \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 00000000..21407c6e --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,6 @@ +'use strict'; + +var requireDir = require('require-dir'), + gulp = require('gulp'); + +requireDir('./gulp', {recurse: true}); diff --git a/karma.conf.js b/karma.conf.js deleted file mode 100644 index e50b9a2d..00000000 --- a/karma.conf.js +++ /dev/null @@ -1,70 +0,0 @@ -// Karma configuration -// Generated on Mon Jul 27 2015 17:53:54 GMT-0500 (Central Daylight Time) -module.exports = function(config) { - config.set({ - - // base path that will be used to resolve all patterns (eg. files, exclude) - basePath: '', - - - // frameworks to use - // available frameworks: https://npmjs.org/browse/keyword/karma-adapter - frameworks: ['jasmine'], - - - // list of files / patterns to load in the browser - files: [].concat( - './build/vendor/angular.js', - './build/vendor/**/*.js', - './vendor/angular-mocks/angular-mocks.js', - './build/src/app/app.js', - './build/src/**/*.js', - './src/**/*.spec.js' - ), - - - // list of files to exclude - exclude: [ - './src/**/*.test.js' - ], - - - // preprocess matching files before serving them to the browser - // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor - preprocessors: { - }, - - - // test results reporter to use - // possible values: 'dots', 'progress' - // available reporters: https://npmjs.org/browse/keyword/karma-reporter - reporters: ['progress'], - - - // web server port - port: 9876, - - - // enable / disable colors in the output (reporters and logs) - colors: true, - - - // level of logging - // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG - logLevel: config.LOG_INFO, - - - // enable / disable watching file and executing tests whenever any file changes - autoWatch: false, - - - // start these browsers - // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher - browsers: ['PhantomJS'], - - - // Continuous Integration mode - // if true, Karma captures browsers, runs the tests and exits - singleRun: false - }) -}; diff --git a/karma/karma-unit.tpl.js b/karma/karma-unit.tpl.js deleted file mode 100644 index efaf4149..00000000 --- a/karma/karma-unit.tpl.js +++ /dev/null @@ -1,25 +0,0 @@ -module.exports = function ( karma ) { - karma.set({ - basePath: "../", - files: [ - <% scripts.forEach( function ( file ) { %>"<%= file %>", - <% }); %>, - "src/**/*.js" - ], - exclude: [ - "src/assets/**/*.js" - ], - frameworks: [ 'jasmine' ], - plugins: [ 'karma-jasmine', 'karma-firefox-launcher'], - preprocessors: { }, - reporters: 'dots', - port: 9018, - runnerPort: 9100, - urlRoot: "/", - autoWatch: true, - browsers: [ - 'Firefox' - ] - }); -}; - diff --git a/package.json b/package.json index 6cca5e45..5df8fb67 100644 --- a/package.json +++ b/package.json @@ -1,46 +1,63 @@ { - "author": "Four51, Inc.", - "name": "OrderCloud", - "version": "0.0.3", - "homepage": "https://github.com/Four51/OrderCloud-Seed-AngularJS", - "license": "MIT", - "bugs": "https://github.com/Four51/OrderCloud-Seed-AngularJS/issues", + "name": "ordercloud-components", + "version": "1.0.0", + "description": "repo for managing ordercloud components that serve as a starting point for creating B2B applications on the Four51 OrderCloud platform", + "main": "app.js", + "scripts": { + "test": "test" + }, "repository": { "type": "git", - "url": "git@github.com:Four51/OrderCloud-Seed-AngularJS.git" + "url": "git+https://github.com/Four51/OrderCloud-Components.git" + }, + "keywords": [ + "OrderCloud", + "Four51", + "AngularJS", + "Angular", + "B2B" + ], + "author": "Four51 Inc.", + "license": "MIT", + "bugs": { + "url": "https://github.com/Four51/OrderCloud-Components/issues" }, + "homepage": "https://github.com/Four51/OrderCloud-Components#readme", "dependencies": { - "bower": "^1.6.8", - "browser-sync": "^2.8.0", - "del": "^2.0.2", - "express": "^4.13.3", - "gulp": "git://github.com/gulpjs/gulp.git#4.0", - "gulp-angular-protractor": "0.0.5", - "gulp-angular-templatecache": "^1.7.0", - "gulp-autoprefixer": "^2.3.1", + "browser-sync": "^2.11.1", + "del": "^2.2.0", + "gulp": "^3.9.0", + "gulp-angular-templatecache": "^1.8.0", + "gulp-autoprefixer": "^3.1.0", + "gulp-beautify": "^2.0.0", + "gulp-cached": "^1.1.0", "gulp-concat": "^2.6.0", - "gulp-filter": "^2.0.2", - "gulp-flatten": "^0.1.1", - "gulp-header": "^1.7.1", - "gulp-inject": "^1.5.0", - "gulp-less": "^3.0.3", + "gulp-csso": "^1.0.1", + "gulp-filter": "^3.0.1", + "gulp-flatten": "^0.2.0", + "gulp-htmlmin": "^1.3.0", + "gulp-imagemin": "^2.4.0", + "gulp-inject": "^3.0.0", + "gulp-less": "^3.0.5", "gulp-less-import": "^1.0.0", - "gulp-minify-css": "^1.2.0", - "gulp-ng-annotate": "^1.0.0", - "gulp-ng-constant": "^1.1.0", - "gulp-plumber": "^1.0.1", - "gulp-replace": "^0.5.4", - "gulp-sass": "^2.0.4", - "gulp-uglify": "^1.2.0", - "gulp-util": "^3.0.6", + "gulp-ng-annotate": "^1.1.0", + "gulp-nodemon": "^2.0.6", + "gulp-open": "^1.0.0", + "gulp-rev": "^6.0.1", + "gulp-sourcemaps": "^1.6.0", + "gulp-uglify": "^1.5.1", "gulp-wrapper": "^1.0.0", - "jasmine": "^2.3.2", - "karma": "^0.13.15", - "karma-jasmine": "^0.3.6", - "karma-phantomjs-launcher": "^0.2.1", - "main-bower-files": "^2.9.0", - "phantomjs": "^1.9.18", - "protractor": "^2.5.1" + "main-bower-files": "^2.11.1", + "require-dir": "^0.3.0", + "yargs": "^3.32.0" }, - "devDependencies": {} + "devDependencies": { + "express": "^4.13.4", + "gulp-protractor": "^2.1.0", + "jasmine": "^2.4.1", + "plato": "^1.5.0", + "protractor": "^3.1.1", + "selenium-standalone": "^4.9.1", + "selenium-webdriver": "^2.52.0" + } } diff --git a/protractor.config.js b/protractor.config.js index 42e78e3f..8bc7f712 100644 --- a/protractor.config.js +++ b/protractor.config.js @@ -1,33 +1,53 @@ -var browsers = { - firefox: { - name: 'Firefox', - browserName: 'firefox' - }, - chrome: { - name: 'Chrome', - browserName: 'chrome' - } -}; - - -// An example configuration file. +// An example configuration file exports.config = { - baseUrl: 'http://localhost:8000', - // The address of a running selenium server. seleniumAddress: 'http://localhost:4444/wd/hub', // Capabilities to be passed to the webdriver instance. - capabilities: browsers.chrome, + capabilities: { + browserName: 'chrome' + }, // Spec patterns are relative to the configuration file location passed // to protractor (in this example conf.js). // They may include glob patterns. - specs: [ - './src/**/login.test.js', - './src/**/*.test.js', - './src/**/logout.test.js' - ], + specs: ['./src/**/*.test.js'], + + suites: { + all: './src/**/*.test.js', + buyer: [ + './src/cart/**/*.test.js', + './src/catalog/**/*.test.js', + './src/checkout/**/*.test.js', + './src/orderHistory/**/*.test.js' + ], + admin: [ + './src/addresses/**/*.test.js', + './src/adminUsers/**/*.test.js', + './src/approvalRules/**/*.test.js', + './src/buyers/**/*.test.js', + './src/categories/**/*.test.js', + './src/costCenters/**/*.test.js', + './src/coupons/**/*.test.js', + './src/creditCards/**/*.test.js', + './src/giftCards/**/*.test.js', + './src/orders/**/*.test.js', + './src/priceSchedules/**/*.test.js', + './src/products/**/*.test.js', + './src/shipments/**/*.test.js', + './src/specs/**/*.test.js', + './src/spendingAccounts/**/*.test.js', + './src/userGroups/**/*.test.js', + './src/users/**/*.test.js' + ], + common: [ + './src/common/**/*.test.js', + './src/account/**/*.test.js', + './src/base/**/*.test.js', + './src/home/**/*.test.js', + './src/login/**/*.test.js' + ] + }, // Options to be passed to Jasmine-node. jasmineNodeOpts: { diff --git a/server.js b/server.js index 6171c82b..c6ac317b 100644 --- a/server.js +++ b/server.js @@ -1,25 +1,29 @@ -var express = require('express'); -var app = express(); +'use strict'; +var config = require('./gulp.config'); -if (process.env.authurl) { - app.use(express.static(__dirname + '/compile')); -} else { - app.use(express.static(__dirname + '/build')); -} - -app.get('*', function(req, res) { - res.sendFile('index.html'); -}); +var express = require('express'), + env = process.env.NODE_ENV = process.env.NODE_ENV || config.build, + app = express(), + port = process.env.PORT || 451; -if (!process.env.PORT) { - var server = app.listen(4451, function () { - var port = server.address().port; - console.log('Example app listening on port: ', port); - - }); -} else { - var server = app.listen(process.env.PORT, function () { - var port = server.address().port; - console.log('Example app listening on port: ', port); - }); +switch(env) { + case 'prod': + console.log('*** PROD ***'); + app.use(express.static(config.root + config.compile.replace('.', ''))); + app.get('/*', function(req, res) { + res.sendFile(config.root + config.compile.replace('.', '') + config.index); + }); + break; + default: + console.log('*** DEV ***'); + app.use(express.static(config.root + config.build.replace('.', ''))); + app.use(express.static(config.root + config.src.replace('.', '') + 'app/')); + app.use(express.static(config.root)); + app.get('/*', function(req, res) { + res.sendFile(config.root + config.build.replace('.', '') + config.index); + }); + break; } + +app.listen(port); +console.log('Listening on port ' + port + '...'); From 9c6920d1de37566720bdf9d56be6cdb6b52de862 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Thu, 17 Mar 2016 14:24:23 -0500 Subject: [PATCH 056/367] Updates to gulp processes --- gulp.config.js | 42 ++++++++++++++++++++++++++++++++++++++- gulp/build/inject.js | 2 +- gulp/build/serve-build.js | 7 +------ gulp/serve.js | 8 ++++++++ gulp/test/plato.js | 6 +++--- package.json | 15 +++++++++++++- server.js | 4 ++-- src/app/app.config.json | 6 ++++++ src/app/app.js | 16 +++------------ src/index.html | 4 ++++ 10 files changed, 83 insertions(+), 27 deletions(-) create mode 100644 src/app/app.config.json diff --git a/gulp.config.js b/gulp.config.js index c98bcd9c..f1863bbd 100644 --- a/gulp.config.js +++ b/gulp.config.js @@ -5,7 +5,8 @@ var source = './src/', npmFiles = './node_modules', compile = './compile/', index = 'index.html', - gulp_dir = './gulp/'; + gulp_dir = './gulp/', + fs = require('fs'); module.exports = { bowerFiles: bowerFiles, @@ -34,6 +35,7 @@ module.exports = { '!' + source + '**/*.test.js' ], appFiles: [ + build + '**/app.js', build + '**/*.js', build + '**/*.css', source + '**/*.css' @@ -47,6 +49,11 @@ module.exports = { moduleSystem: 'IIFE', module: 'orderCloud' }, + ngConstantSettings: { + name: 'orderCloud', + deps: false, + constants: getConstants() + }, autoprefixerSettings: { browsers: ['last 2 versions'], cascade: true @@ -54,3 +61,36 @@ module.exports = { jsCache: 'jsscripts', indentSize: 4 }; + +function getConstants() { + var result = {}; + var constants = JSON.parse(fs.readFileSync(source + 'app/app.config.json')); + var environment = process.env.environment || constants.environment; + switch (environment) { + case 'local': + result.authurl = 'http://core.four51.com:11629/oauth/token'; + result.apiurl = 'http://core.four51.com:9002'; + break; + case 'test': + result.authurl = 'https://testauth.ordercloud.io/oauth/token'; + result.apiurl = 'https://testapi.ordercloud.io'; + break; + case 'qa': + result.authurl = 'https://qaauth.ordercloud.io/oauth/token'; + result.apiurl = 'https://qaapi.ordercloud.io'; + break; + default: + result.authurl = 'https://auth.ordercloud.io/oauth/token'; + result.apiurl = 'https://api.ordercloud.io'; + break; + } + if (!environment && (process.env.apiurl && process.env.authurl)) { + result.authurl = process.env.authurl; + result.apiurl = process.env.apiurl; + } + else if (!environment && !process.env.apiurl && !process.env.authurl) { + result.authurl = 'https://auth.ordercloud.io/oauth/token'; + result.apiurl = 'https://api.ordercloud.io'; + } + return result; +} diff --git a/gulp/build/inject.js b/gulp/build/inject.js index 6ba7bd63..fb778c3d 100644 --- a/gulp/build/inject.js +++ b/gulp/build/inject.js @@ -8,7 +8,7 @@ gulp.task('clean:inject', function() { return del(config.build + '*.html'); }); -gulp.task('inject', ['clean:inject', 'scripts', 'styles'], function() { +gulp.task('inject', ['clean:inject', 'scripts', 'app-config', 'bower-fonts', 'styles'], function() { var target = gulp.src(config.index), bowerFiles = gulp.src(mainBowerFiles({filter: ['**/*.js', '**/*.css']}), {read: false}), appFiles = gulp.src(config.appFiles, {read: false}); diff --git a/gulp/build/serve-build.js b/gulp/build/serve-build.js index 3e9654b1..6aa9133e 100644 --- a/gulp/build/serve-build.js +++ b/gulp/build/serve-build.js @@ -10,11 +10,7 @@ var gulp = require('gulp'), plato = require('../test/plato'); gulp.task('serve-build', ['inject'], function() { - gulp.watch(config.src + '**/*.html') - .on('change', browserSync.reload); - gulp.watch(config.scripts, ['rebuild-scripts', 'report']) - .on('change', browserSync.reload); - gulp.watch(config.styles, ['styles']); + serve(true /*isDev*/); if (argv.debug) { unit.RunUnitTests(); unit.ServeTests(); @@ -22,5 +18,4 @@ gulp.task('serve-build', ['inject'], function() { plato.OpenReport(); }); } - serve(true /*isDev*/); }); diff --git a/gulp/serve.js b/gulp/serve.js index 69df4640..98c1a39e 100644 --- a/gulp/serve.js +++ b/gulp/serve.js @@ -2,6 +2,7 @@ 'use strict'; var nodemon = require('gulp-nodemon'), + gulp = require('gulp'), config = require('../gulp.config'), cache = require('gulp-cached'), browserSync = require('browser-sync').create(), @@ -27,6 +28,13 @@ } module.exports = function (isDev) { + if (isDev) { + gulp.watch(config.src + '**/*.html') + .on('change', browserSync.reload); + gulp.watch(config.scripts, ['rebuild-scripts']) + .on('change', browserSync.reload); + gulp.watch(config.styles, ['styles']); + } return nodemon ({ script: './server.js', delayTime: 1, diff --git a/gulp/test/plato.js b/gulp/test/plato.js index 75e4d5d7..9d782011 100644 --- a/gulp/test/plato.js +++ b/gulp/test/plato.js @@ -7,7 +7,7 @@ gulp.task('report', function(done) { }); gulp.task('plato', ['report'], function() { - openReport(); + return openReport(); }); function generateReport(done) { @@ -19,7 +19,7 @@ function generateReport(done) { var outputDir = './plato/dir'; var options = { - title: 'Components Code Analysis' + title: 'OrderCloud Code Analysis' }; var callback = function(report) { @@ -54,4 +54,4 @@ function openReport() { module.exports = { GenerateReport: generateReport, OpenReport: openReport -} +}; diff --git a/package.json b/package.json index 5df8fb67..4ec92f76 100644 --- a/package.json +++ b/package.json @@ -3,8 +3,19 @@ "version": "1.0.0", "description": "repo for managing ordercloud components that serve as a starting point for creating B2B applications on the Four51 OrderCloud platform", "main": "app.js", + "engines": { + "node": "4.1.0", + "npm": "2.14.3" + }, + "cacheDirectories": [ + "node_modules", + "bower_components" + ], "scripts": { - "test": "test" + "postinstall": "bower install && gulp inject index", + "start": "node server.js", + "test": "gulp test:unit", + "test-e2e": "gulp test:e2e" }, "repository": { "type": "git", @@ -26,6 +37,7 @@ "dependencies": { "browser-sync": "^2.11.1", "del": "^2.2.0", + "fs": "0.0.2", "gulp": "^3.9.0", "gulp-angular-templatecache": "^1.8.0", "gulp-autoprefixer": "^3.1.0", @@ -41,6 +53,7 @@ "gulp-less": "^3.0.5", "gulp-less-import": "^1.0.0", "gulp-ng-annotate": "^1.1.0", + "gulp-ng-constant": "^1.1.0", "gulp-nodemon": "^2.0.6", "gulp-open": "^1.0.0", "gulp-rev": "^6.0.1", diff --git a/server.js b/server.js index c6ac317b..22915e4d 100644 --- a/server.js +++ b/server.js @@ -11,7 +11,7 @@ switch(env) { console.log('*** PROD ***'); app.use(express.static(config.root + config.compile.replace('.', ''))); app.get('/*', function(req, res) { - res.sendFile(config.root + config.compile.replace('.', '') + config.index); + res.sendFile(config.root + config.compile.replace('.', '') + 'index.html'); }); break; default: @@ -20,7 +20,7 @@ switch(env) { app.use(express.static(config.root + config.src.replace('.', '') + 'app/')); app.use(express.static(config.root)); app.get('/*', function(req, res) { - res.sendFile(config.root + config.build.replace('.', '') + config.index); + res.sendFile(config.root + config.build.replace('.', '') + 'index.html'); }); break; } diff --git a/src/app/app.config.json b/src/app/app.config.json new file mode 100644 index 00000000..17501daa --- /dev/null +++ b/src/app/app.config.json @@ -0,0 +1,6 @@ +{ + "appname": "Components", + "ocscope": "FullAccess", + "clientid": "F567CE46-3C24-46BE-A9C9-327FABADEBB3", + "buyerid": "component_1" +} \ No newline at end of file diff --git a/src/app/app.js b/src/app/app.js index d1ce22c6..6a516689 100644 --- a/src/app/app.js +++ b/src/app/app.js @@ -1,5 +1,4 @@ angular.module( 'orderCloud', [ - 'templates-app', 'ngSanitize', 'ngAnimate', 'ngMessages', @@ -27,16 +26,7 @@ angular.module( 'orderCloud', [ .config( ErrorHandling ) .config( Interceptor ) .controller( 'AppCtrl', AppCtrl ) - .constant("appname", "OrderCloud AngularJS Seed") - - //App Constants used by the OrderCloud SDK - .constant("ocscope", "FullAccess") - .constant("clientid", "XXXXXXXX-XXXX-XXXX-XXXXXXXXXX") - .constant("buyerid", "XXXXX") - - //OrderCloud Base URLs - .constant("authurl", "https://auth.ordercloud.io/oauth/token") - .constant("apiurl", "https://api.ordercloud.io") +//TEST ; @@ -44,10 +34,10 @@ function SetBuyerID( OrderCloud, buyerid ) { OrderCloud.BuyerID.Get() ? angular.noop() : OrderCloud.BuyerID.Set(buyerid); } -function Routing( $urlRouterProvider, $urlMatcherFactoryProvider ) { +function Routing( $urlRouterProvider, $urlMatcherFactoryProvider, $locationProvider ) { $urlMatcherFactoryProvider.strictMode(false); $urlRouterProvider.otherwise( '/home' ); - //$locationProvider.html5Mode(true); + $locationProvider.html5Mode(true); } function ErrorHandling( $provide ) { diff --git a/src/index.html b/src/index.html index f1b9a4fa..15d4e46a 100644 --- a/src/index.html +++ b/src/index.html @@ -4,6 +4,10 @@ OrderCloud + + + + From 78ed47930e522e3915981f4687020d71b935980b Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Thu, 17 Mar 2016 14:33:26 -0500 Subject: [PATCH 057/367] trying to add bower as a build engine for heroku deployment --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 4ec92f76..9a9fb462 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,8 @@ "main": "app.js", "engines": { "node": "4.1.0", - "npm": "2.14.3" + "npm": "2.14.3", + "bower": "1.7.7" }, "cacheDirectories": [ "node_modules", From 2855a21dcb35cd1cfe3e466a4e3e1d7cdddb6b76 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Thu, 17 Mar 2016 14:38:01 -0500 Subject: [PATCH 058/367] That didn't work, so I am trying this instead --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 9a9fb462..fa802cad 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,7 @@ "main": "app.js", "engines": { "node": "4.1.0", - "npm": "2.14.3", - "bower": "1.7.7" + "npm": "2.14.3" }, "cacheDirectories": [ "node_modules", @@ -36,6 +35,8 @@ }, "homepage": "https://github.com/Four51/OrderCloud-Components#readme", "dependencies": { + "bower": "1.7.7", + "express": "^4.13.4", "browser-sync": "^2.11.1", "del": "^2.2.0", "fs": "0.0.2", @@ -66,7 +67,6 @@ "yargs": "^3.32.0" }, "devDependencies": { - "express": "^4.13.4", "gulp-protractor": "^2.1.0", "jasmine": "^2.4.1", "plato": "^1.5.0", From cf6ebe38cc4f2686efeb1ec33649c887dfb9b96f Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Thu, 17 Mar 2016 14:42:03 -0500 Subject: [PATCH 059/367] Missing version of angular to install --- bower.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bower.json b/bower.json index 7a9c96cc..846c97ff 100644 --- a/bower.json +++ b/bower.json @@ -35,7 +35,8 @@ "ordercloud-ng-sdk": "^1.0.1", "OrderCloud-Angular-SDK": "ordercloud-angular-sdk#^1.0.9", "angular-auto-validate": "^1.19.3", - "font-awesome": "^4.5.0" + "font-awesome": "^4.5.0", + "angular": "^1.5.1" }, "devDependencies": { "angular-mocks": "^1.5.0" From 4cf7c2952faac548b68331d14fd058de08ff1673 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Thu, 17 Mar 2016 14:47:50 -0500 Subject: [PATCH 060/367] This should fix the broken resolution --- bower.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bower.json b/bower.json index 846c97ff..9e027906 100644 --- a/bower.json +++ b/bower.json @@ -35,10 +35,12 @@ "ordercloud-ng-sdk": "^1.0.1", "OrderCloud-Angular-SDK": "ordercloud-angular-sdk#^1.0.9", "angular-auto-validate": "^1.19.3", - "font-awesome": "^4.5.0", - "angular": "^1.5.1" + "font-awesome": "^4.5.0" }, "devDependencies": { "angular-mocks": "^1.5.0" + }, + "resolutions": { + "angular": "1.5.1" } } From dd0d49febb505a4c4c667d962abfeea018c0b3be Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Thu, 17 Mar 2016 14:59:08 -0500 Subject: [PATCH 061/367] updating the engines. No idea why heroku deploy isn't working now --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index fa802cad..c520f524 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,8 @@ "description": "repo for managing ordercloud components that serve as a starting point for creating B2B applications on the Four51 OrderCloud platform", "main": "app.js", "engines": { - "node": "4.1.0", - "npm": "2.14.3" + "node": "5.6.0", + "npm": "3.7.1" }, "cacheDirectories": [ "node_modules", From 8e55b94703d19758c29f1b175826f86654bfbaaa Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Thu, 17 Mar 2016 15:07:38 -0500 Subject: [PATCH 062/367] Does this work? --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c520f524..a496fd7f 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "bower_components" ], "scripts": { - "postinstall": "bower install && gulp inject index", + "postinstall": "bower install", "start": "node server.js", "test": "gulp test:unit", "test-e2e": "gulp test:e2e" From d8b88727c6edf5f9c4556ece6866e2b96e87e208 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Thu, 17 Mar 2016 15:18:17 -0500 Subject: [PATCH 063/367] Discovered bug is in running gulp inject index. Trying work around --- package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index a496fd7f..6e32a23a 100644 --- a/package.json +++ b/package.json @@ -5,15 +5,16 @@ "main": "app.js", "engines": { "node": "5.6.0", - "npm": "3.7.1" + "npm": "3.6.0" }, "cacheDirectories": [ "node_modules", "bower_components" ], "scripts": { - "postinstall": "bower install", + "postinstall": "bower install && npm run build-all", "start": "node server.js", + "build-all": "gulp inject index", "test": "gulp test:unit", "test-e2e": "gulp test:e2e" }, From 11dfe0d0f6f93055c93624ccedacdc36f625219a Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Thu, 17 Mar 2016 15:24:48 -0500 Subject: [PATCH 064/367] Adding devDependencies to dependencies --- package.json | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 6e32a23a..33554a4f 100644 --- a/package.json +++ b/package.json @@ -65,14 +65,13 @@ "gulp-wrapper": "^1.0.0", "main-bower-files": "^2.11.1", "require-dir": "^0.3.0", - "yargs": "^3.32.0" - }, - "devDependencies": { + "yargs": "^3.32.0", "gulp-protractor": "^2.1.0", "jasmine": "^2.4.1", "plato": "^1.5.0", "protractor": "^3.1.1", "selenium-standalone": "^4.9.1", "selenium-webdriver": "^2.52.0" - } + }, + "devDependencies": {} } From 91b777d7ff8191a52701bcd1b712cd02b3a96f3d Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Thu, 17 Mar 2016 15:57:28 -0500 Subject: [PATCH 065/367] These were not added to source control --- gulp/build/app-config.js | 15 +++++++++++++++ gulp/build/bower-fonts.js | 15 +++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 gulp/build/app-config.js create mode 100644 gulp/build/bower-fonts.js diff --git a/gulp/build/app-config.js b/gulp/build/app-config.js new file mode 100644 index 00000000..68160ff7 --- /dev/null +++ b/gulp/build/app-config.js @@ -0,0 +1,15 @@ +var gulp = require('gulp'), + del = require('del'), + config = require('../../gulp.config'), + ngConstant = require('gulp-ng-constant'); + +gulp.task('clean:app-config', function() { + return del(config.build + '**/app.config.js'); +}); + +gulp.task('app-config', ['clean:app-config'], function() { + return gulp + .src(config.src + '**/app.config.json') + .pipe(ngConstant(config.ngConstantSettings)) + .pipe(gulp.dest(config.build)); +}); diff --git a/gulp/build/bower-fonts.js b/gulp/build/bower-fonts.js new file mode 100644 index 00000000..37abdbe4 --- /dev/null +++ b/gulp/build/bower-fonts.js @@ -0,0 +1,15 @@ +var gulp = require('gulp'), + config = require('../../gulp.config'), + flatten = require('gulp-flatten'), + del = require('del'); + +gulp.task('clean:bower-fonts', function() { + return del(config.build + config.appFonts); +}); + +gulp.task('bower-fonts', ['clean:bower-fonts'], function() { + return gulp + .src(config.bowerFiles + '*/fonts/**/*') + .pipe(flatten()) + .pipe(gulp.dest(config.build + config.appFonts)) +}); From 07387a0aedc059231d388e3cb2458a4451b314a3 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Thu, 17 Mar 2016 16:07:22 -0500 Subject: [PATCH 066/367] Setting environment variables --- .gitignore | 1 + server.js | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index d4df87d5..865596c8 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *~ build/ compile/ +!gulp/ node_modules/ bower_components/ errorShots/ diff --git a/server.js b/server.js index 22915e4d..4b34b21b 100644 --- a/server.js +++ b/server.js @@ -2,12 +2,12 @@ var config = require('./gulp.config'); var express = require('express'), - env = process.env.NODE_ENV = process.env.NODE_ENV || config.build, + env = process.env.NODE_ENV = process.env.NODE_ENV || 'dev', app = express(), port = process.env.PORT || 451; switch(env) { - case 'prod': + case 'production': console.log('*** PROD ***'); app.use(express.static(config.root + config.compile.replace('.', ''))); app.get('/*', function(req, res) { From 5d89ebb413ea17f779f34e4260ffc29e9aa0767a Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Thu, 17 Mar 2016 16:15:40 -0500 Subject: [PATCH 067/367] Fixing compile --- gulp/compile/app-js.js | 8 +++++++- gulp/serve.js | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/gulp/compile/app-js.js b/gulp/compile/app-js.js index 21497199..eeb95e96 100644 --- a/gulp/compile/app-js.js +++ b/gulp/compile/app-js.js @@ -2,6 +2,7 @@ var gulp = require('gulp'), config = require('../../gulp.config'), del = require('del'), ngAnnotate = require('gulp-ng-annotate'), + ngConstant = require('gulp-ng-constant'), rev = require('gulp-rev'), concat = require('gulp-concat'), filter = require('gulp-filter'), @@ -16,13 +17,18 @@ gulp.task('clean:app-js', function() { gulp.task('app-js', ['clean:app-js'], function() { var htmlFilter = filter('**/*.html', {restore: true}), + jsonFilter = filter('**/*.json', {restore: true}), jsFilter = filter('**/*.js'); return gulp .src([].concat( config.scripts, - config.templates + config.templates, + config.src + '**/app.config.json' )) + .pipe(jsonFilter) + .pipe(ngConstant(config.ngConstantSettings)) + .pipe(jsonFilter.restore) .pipe(htmlFilter) .pipe(htmlmin({collapseWhitespace: true, removeComments: true})) .pipe(templateCache(config.templateCacheSettings)) diff --git a/gulp/serve.js b/gulp/serve.js index 98c1a39e..00ea50b1 100644 --- a/gulp/serve.js +++ b/gulp/serve.js @@ -40,7 +40,7 @@ delayTime: 1, env: { 'PORT': port, - 'NODE_ENV': isDev ? 'dev' : 'prod' + 'NODE_ENV': isDev ? 'dev' : 'production' }, watch: ['./server.js'] }) From b12cb7b8f578f1ce7a76ac7fa6c1e16e13eb963e Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Thu, 17 Mar 2016 16:28:44 -0500 Subject: [PATCH 068/367] making apiurl and authurl have priority over environment --- gulp.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gulp.config.js b/gulp.config.js index f1863bbd..bca36d3c 100644 --- a/gulp.config.js +++ b/gulp.config.js @@ -84,7 +84,7 @@ function getConstants() { result.apiurl = 'https://api.ordercloud.io'; break; } - if (!environment && (process.env.apiurl && process.env.authurl)) { + if (process.env.apiurl && process.env.authurl) { result.authurl = process.env.authurl; result.apiurl = process.env.apiurl; } From e76019c2707f78ecbb420880e81ce1cd0e7fc176 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Thu, 17 Mar 2016 16:40:45 -0500 Subject: [PATCH 069/367] Adding clientid, appname, ocscope, and buyerid to the process.env overwrite variables --- gulp.config.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gulp.config.js b/gulp.config.js index bca36d3c..b8ab234b 100644 --- a/gulp.config.js +++ b/gulp.config.js @@ -92,5 +92,9 @@ function getConstants() { result.authurl = 'https://auth.ordercloud.io/oauth/token'; result.apiurl = 'https://api.ordercloud.io'; } + if (process.env.clientid) result.clientid = process.env.clientid; + if (process.env.appname) result.appname = process.env.appname; + if (process.env.ocscope) result.ocscope = process.env.ocscope; + if (process.env.buyerid) result.buyerid = process.env.buyerid; return result; } From 2b6212ad9a872382f63296e463231eacdc17e8a3 Mon Sep 17 00:00:00 2001 From: Robert Watt Date: Thu, 17 Mar 2016 16:46:14 -0500 Subject: [PATCH 070/367] Update app.js --- src/app/app.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/app/app.js b/src/app/app.js index 6a516689..8cf85836 100644 --- a/src/app/app.js +++ b/src/app/app.js @@ -26,8 +26,6 @@ angular.module( 'orderCloud', [ .config( ErrorHandling ) .config( Interceptor ) .controller( 'AppCtrl', AppCtrl ) -//TEST - ; function SetBuyerID( OrderCloud, buyerid ) { @@ -93,4 +91,4 @@ function Interceptor( $httpProvider ) { } }; }); -} \ No newline at end of file +} From e72278dbfe2dcb3ec817c0ce6bb4c5c02466e84e Mon Sep 17 00:00:00 2001 From: Robert Watt Date: Thu, 17 Mar 2016 16:47:32 -0500 Subject: [PATCH 071/367] Update app.config.json --- src/app/app.config.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/app/app.config.json b/src/app/app.config.json index 17501daa..71604744 100644 --- a/src/app/app.config.json +++ b/src/app/app.config.json @@ -1,6 +1,6 @@ { - "appname": "Components", - "ocscope": "FullAccess", - "clientid": "F567CE46-3C24-46BE-A9C9-327FABADEBB3", - "buyerid": "component_1" -} \ No newline at end of file + "appname": "XXXXX", + "ocscope": "BuyerReader", + "clientid": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX", + "buyerid": "XXXXX" +} From 0fdeff8267a212a36c119168601b7a9a5f6abfc5 Mon Sep 17 00:00:00 2001 From: Robert Watt Date: Thu, 17 Mar 2016 16:48:20 -0500 Subject: [PATCH 072/367] Update app.js --- src/app/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/app.js b/src/app/app.js index 8cf85836..9940165f 100644 --- a/src/app/app.js +++ b/src/app/app.js @@ -7,7 +7,7 @@ angular.module( 'orderCloud', [ 'ui.router', 'ui.bootstrap', 'orderCloud.sdk', - 'LocalForageModule', + 'LocalForageModule', 'toastr', 'jcs-autoValidate', 'ordercloud-infinite-scroll', From 1c8c69226563f42a624a299be17adb9c77913ce0 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Fri, 18 Mar 2016 17:56:27 -0500 Subject: [PATCH 073/367] Gulp updates for working with developer submodule setup. --- gulp.config.js | 15 ++++++++++++++- gulp/build/inject.js | 2 +- gulp/build/scripts.js | 15 +++++++++++---- gulp/build/styles.js | 3 ++- gulp/compile/app-css.js | 2 ++ gulp/compile/app-js.js | 2 ++ gulp/serve.js | 12 ++++++++++-- server.js | 1 + 8 files changed, 43 insertions(+), 9 deletions(-) diff --git a/gulp.config.js b/gulp.config.js index b8ab234b..08bad15e 100644 --- a/gulp.config.js +++ b/gulp.config.js @@ -1,5 +1,6 @@ var source = './src/', assets = 'assets/', + components = './../ordercloud-components/', build = './build/', bowerFiles = './bower_components/', npmFiles = './node_modules', @@ -30,10 +31,22 @@ module.exports = { source + 'app/**/*.html' ], scripts: [ - source + '**/*.js', + source + 'app/**/*.js', '!' + source + '**/*.spec.js', '!' + source + '**/*.test.js' ], + components: { + scripts: [ + components + '**/*.js', + '!' + components + '**/*.spec.js', + '!' + components + '**/*.test.js' + ], + templates: components + '**/*.html', + styles: { + less: components + '**/*.less', + css: components + '**/*.css' + } + }, appFiles: [ build + '**/app.js', build + '**/*.js', diff --git a/gulp/build/inject.js b/gulp/build/inject.js index fb778c3d..9177558c 100644 --- a/gulp/build/inject.js +++ b/gulp/build/inject.js @@ -11,7 +11,7 @@ gulp.task('clean:inject', function() { gulp.task('inject', ['clean:inject', 'scripts', 'app-config', 'bower-fonts', 'styles'], function() { var target = gulp.src(config.index), bowerFiles = gulp.src(mainBowerFiles({filter: ['**/*.js', '**/*.css']}), {read: false}), - appFiles = gulp.src(config.appFiles, {read: false}); + appFiles = gulp.src([].concat(config.appFiles, config.components.styles.css), {read: false}); return target .pipe(inject(bowerFiles, {name: 'bower'})) diff --git a/gulp/build/scripts.js b/gulp/build/scripts.js index 20982f8d..86fdfbd3 100644 --- a/gulp/build/scripts.js +++ b/gulp/build/scripts.js @@ -2,6 +2,7 @@ var gulp = require('gulp'), config = require('../../gulp.config'), cache = require('gulp-cached'), del = require('del'), + filter = require('gulp-filter'), inject = require('gulp-inject'), wrapper = require('gulp-wrapper'), beautify = require('gulp-beautify'), @@ -13,20 +14,26 @@ gulp.task('clean:scripts', function() { gulp.task('scripts', ['clean:scripts'], function() { return gulp - .src(config.scripts) + .src([].concat( + config.scripts, + config.components.scripts + )) .pipe(cache(config.jsCache)) .pipe(ngAnnotate()) .pipe(wrapper(config.wrapper)) .pipe(beautify({indentSize: config.indentSize})) - .pipe(gulp.dest(config.build)); + .pipe(gulp.dest(config.build + 'app/')); }); gulp.task('rebuild-scripts', function() { return gulp - .src(config.scripts) + .src([].concat( + config.scripts, + config.components.scripts + )) .pipe(cache('jsscripts')) .pipe(ngAnnotate()) .pipe(wrapper(config.wrapper)) .pipe(beautify({indentSize: config.indentSize})) - .pipe(gulp.dest(config.build)); + .pipe(gulp.dest(config.build + 'app/')); }); diff --git a/gulp/build/styles.js b/gulp/build/styles.js index c2970890..ea71a843 100644 --- a/gulp/build/styles.js +++ b/gulp/build/styles.js @@ -18,7 +18,8 @@ gulp.task('styles', ['clean:styles'], function() { return gulp .src([].concat( mainBowerFiles({filter: '**/*.less'}), - config.src + '**/*.less' + config.src + '**/*.less', + config.components.styles.less )) .pipe(sourcemaps.init()) .pipe(lessImport('oc-import.less')) diff --git a/gulp/compile/app-css.js b/gulp/compile/app-css.js index e688f050..830c8efd 100644 --- a/gulp/compile/app-css.js +++ b/gulp/compile/app-css.js @@ -21,6 +21,8 @@ gulp.task('app-css', ['clean:app-css'], function() { return gulp .src([].concat( mainBowerFiles({filter: ['**/*.css', '**/*.less']}), + config.components.styles.less, + config.components.styles.css, config.styles )) .pipe(lessFilter) diff --git a/gulp/compile/app-js.js b/gulp/compile/app-js.js index eeb95e96..1b2dd022 100644 --- a/gulp/compile/app-js.js +++ b/gulp/compile/app-js.js @@ -23,7 +23,9 @@ gulp.task('app-js', ['clean:app-js'], function() { return gulp .src([].concat( config.scripts, + config.components.scripts, config.templates, + config.components.templates, config.src + '**/app.config.json' )) .pipe(jsonFilter) diff --git a/gulp/serve.js b/gulp/serve.js index 00ea50b1..8bc80390 100644 --- a/gulp/serve.js +++ b/gulp/serve.js @@ -29,11 +29,19 @@ module.exports = function (isDev) { if (isDev) { - gulp.watch(config.src + '**/*.html') + gulp.watch([].concat( + config.src + '**/*.html', + config.components.templates + )) .on('change', browserSync.reload); - gulp.watch(config.scripts, ['rebuild-scripts']) + gulp.watch([].concat( + config.scripts, + config.components.scripts + ), ['rebuild-scripts']) .on('change', browserSync.reload); gulp.watch(config.styles, ['styles']); + gulp.watch(config.src + '**/app.config.json', ['app-config']) + .on('change', browserSync.reload); } return nodemon ({ script: './server.js', diff --git a/server.js b/server.js index 4b34b21b..d7309ac1 100644 --- a/server.js +++ b/server.js @@ -19,6 +19,7 @@ switch(env) { app.use(express.static(config.root + config.build.replace('.', ''))); app.use(express.static(config.root + config.src.replace('.', '') + 'app/')); app.use(express.static(config.root)); + app.use(express.static(config.root + '/../ordercloud-components')); app.get('/*', function(req, res) { res.sendFile(config.root + config.build.replace('.', '') + 'index.html'); }); From 1754a1de970bcb3dbc668682bf33568d2d27cccc Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 21 Mar 2016 13:04:46 -0500 Subject: [PATCH 074/367] Connor's changes while attempting to debug the test:unit task --- bower.json | 2 +- gulp/build/scripts.js | 5 +- gulp/test/SpecRunner.html | 154 +++++++------------ gulp/test/plato.js | 7 +- gulp/test/unit.js | 9 +- src/app/common/auto-id/tests/auto-id.spec.js | 2 +- 6 files changed, 69 insertions(+), 110 deletions(-) diff --git a/bower.json b/bower.json index 9e027906..ec5ed325 100644 --- a/bower.json +++ b/bower.json @@ -41,6 +41,6 @@ "angular-mocks": "^1.5.0" }, "resolutions": { - "angular": "1.5.1" + "angular": "1.5.2" } } diff --git a/gulp/build/scripts.js b/gulp/build/scripts.js index 86fdfbd3..fd646e9d 100644 --- a/gulp/build/scripts.js +++ b/gulp/build/scripts.js @@ -9,7 +9,10 @@ var gulp = require('gulp'), ngAnnotate = require('gulp-ng-annotate'); gulp.task('clean:scripts', function() { - return del(config.build + '**/*.js'); + return del([ + config.build + '**/*.js', + '!' + config.build + '**/app.config.js' + ]); }); gulp.task('scripts', ['clean:scripts'], function() { diff --git a/gulp/test/SpecRunner.html b/gulp/test/SpecRunner.html index 2f274552..4f686a1f 100644 --- a/gulp/test/SpecRunner.html +++ b/gulp/test/SpecRunner.html @@ -5,121 +5,75 @@ Jasmine Spec Runner v2.4.1 - + - - - + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/gulp/test/plato.js b/gulp/test/plato.js index 9d782011..bb794c46 100644 --- a/gulp/test/plato.js +++ b/gulp/test/plato.js @@ -1,5 +1,6 @@ var gulp = require('gulp'), browserSync = require('browser-sync').create(), + config = require('../../gulp.config'), plato = require('plato'); gulp.task('report', function(done) { @@ -12,9 +13,9 @@ gulp.task('plato', ['report'], function() { function generateReport(done) { var files = [ - './dev/**/*.js', - '!./dev/**/*.test.js', - '!./dev/**/*.spec.js' + config.build + '**/*.js', + '!' + config.build + '**/*.test.js', + '!' + config.build + '**/*.spec.js' ]; var outputDir = './plato/dir'; diff --git a/gulp/test/unit.js b/gulp/test/unit.js index 65dc216b..bc3c7ef3 100644 --- a/gulp/test/unit.js +++ b/gulp/test/unit.js @@ -1,9 +1,10 @@ var gulp = require('gulp'), inject = require('gulp-inject'), browserSync = require('browser-sync').create(), + config = require('../../gulp.config'), mainBowerFiles = require('main-bower-files'); -gulp.task('test:unit', ['scripts'], function() { +gulp.task('test:unit', ['scripts', 'app-config'], function() { runUnitTests(); serveTests(); }); @@ -11,8 +12,8 @@ gulp.task('test:unit', ['scripts'], function() { function runUnitTests() { var target = gulp.src('./gulp/test/SpecRunner.html'), bowerFiles = gulp.src(mainBowerFiles({includeDev: true, filter: '**/*.js'}), {read: false}), - appFiles = gulp.src(['./dev/**/*.js'], {read: false}), - specFiles = gulp.src('./src/**/*.spec.js', {read: false}), + appFiles = gulp.src([config.build + '**/app.js', config.build + '**/*.js'], {read: false}), + specFiles = gulp.src(config.src + '**/*.spec.js', {read: false}), jasmineFiles = gulp.src([ './node_modules/jasmine-core/lib/jasmine-core/jasmine.css', './node_modules/jasmine-core/lib/jasmine-core/jasmine.js', @@ -35,7 +36,7 @@ function serveTests() { open: true, port: 452, files: [ - './dev/**/*.js' + config.build + '**/*.js' ], server: { index: 'SpecRunner.html', diff --git a/src/app/common/auto-id/tests/auto-id.spec.js b/src/app/common/auto-id/tests/auto-id.spec.js index c4b2cdf3..92d36464 100644 --- a/src/app/common/auto-id/tests/auto-id.spec.js +++ b/src/app/common/auto-id/tests/auto-id.spec.js @@ -24,7 +24,7 @@ describe('Directive: ordercloudAutoId', function() { expect(angular.element(result).attr('checked')).toBe('checked'); }); it('should have attribute disabled set to disabled', function() { - var result = element[0].querySelectorAll('.element_for_testing'); + var result = element[0].querySelectorAll('.form-control'); expect(angular.element(result).attr('disabled')).toBe('disabled'); }); it('should init boxtext if no value is passed in', inject(function($compile) { From 3bd45120d981283a5006cc17b594ef7994dde52f Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 21 Mar 2016 16:59:38 -0500 Subject: [PATCH 075/367] Fix errors when serving up templates from components submodule --- gulp.config.js | 3 ++- server.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/gulp.config.js b/gulp.config.js index 08bad15e..e7497d1c 100644 --- a/gulp.config.js +++ b/gulp.config.js @@ -1,6 +1,6 @@ var source = './src/', assets = 'assets/', - components = './../ordercloud-components/', + components = './../components-development-submodule/', build = './build/', bowerFiles = './bower_components/', npmFiles = './node_modules', @@ -36,6 +36,7 @@ module.exports = { '!' + source + '**/*.test.js' ], components: { + dir: components, scripts: [ components + '**/*.js', '!' + components + '**/*.spec.js', diff --git a/server.js b/server.js index d7309ac1..13d84feb 100644 --- a/server.js +++ b/server.js @@ -19,7 +19,7 @@ switch(env) { app.use(express.static(config.root + config.build.replace('.', ''))); app.use(express.static(config.root + config.src.replace('.', '') + 'app/')); app.use(express.static(config.root)); - app.use(express.static(config.root + '/../ordercloud-components')); + app.use(express.static(config.root + config.components.dir)); app.get('/*', function(req, res) { res.sendFile(config.root + config.build.replace('.', '') + 'index.html'); }); From 63b439c3afe85a332dabcb3db33227141d54f19e Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 21 Mar 2016 16:59:54 -0500 Subject: [PATCH 076/367] Alias tasks for build and compile --- gulpfile.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gulpfile.js b/gulpfile.js index 21407c6e..6b1cf237 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -4,3 +4,6 @@ var requireDir = require('require-dir'), gulp = require('gulp'); requireDir('./gulp', {recurse: true}); + +gulp.task('build', ['serve-build']); +gulp.task('compile', ['serve-compile']); From 8b3be3cbf11b815736fcf6779e5376382fe66b2d Mon Sep 17 00:00:00 2001 From: Crhistian Date: Wed, 23 Mar 2016 15:34:02 -0500 Subject: [PATCH 077/367] add 'remember me' functionality to log-in. still have to add tests --- src/app/app.js | 9 ++-- src/app/common/token-refresh/token-refresh.js | 13 ++++-- src/app/login/login.js | 41 +++++++++++++++++-- src/app/login/templates/login.tpl.html | 4 ++ 4 files changed, 54 insertions(+), 13 deletions(-) diff --git a/src/app/app.js b/src/app/app.js index 9940165f..3de8cc1b 100644 --- a/src/app/app.js +++ b/src/app/app.js @@ -49,7 +49,7 @@ function ErrorHandling( $provide ) { } } -function AppCtrl( $rootScope, $state, appname, OrderCloud ) { +function AppCtrl( $rootScope, $state, appname, LoginService ) { var vm = this; vm.name = appname; vm.title = appname; @@ -61,10 +61,7 @@ function AppCtrl( $rootScope, $state, appname, OrderCloud ) { }; vm.logout = function() { - OrderCloud.Auth.RemoveToken(); - OrderCloud.Auth.RemoveImpersonationToken(); - OrderCloud.BuyerID.Set(null); - $state.go('login'); + LoginService.Logout(); }; $rootScope.$on('$stateChangeSuccess', function(e, toState) { @@ -76,7 +73,7 @@ function AppCtrl( $rootScope, $state, appname, OrderCloud ) { }); $rootScope.$on('OC:AccessInvalidOrExpired', function() { - vm.logout(); + LoginService.RememberMe(); }); } diff --git a/src/app/common/token-refresh/token-refresh.js b/src/app/common/token-refresh/token-refresh.js index 42e87945..5f578574 100644 --- a/src/app/common/token-refresh/token-refresh.js +++ b/src/app/common/token-refresh/token-refresh.js @@ -2,13 +2,14 @@ angular.module('orderCloud') .factory('TokenRefresh', TokenRefresh) ; -function TokenRefresh($resource, $cookieStore, ocscope, clientid) { +function TokenRefresh($resource, $localForage, ocscope, clientid, appname, authurl) { var service = { Set: _set, Get: _get, SetToken: _setToken, GetToken: _getToken, - Refresh: _refresh + Refresh: _refresh, + RemoveToken: _removeToken }; var remember; @@ -24,11 +25,15 @@ function TokenRefresh($resource, $cookieStore, ocscope, clientid) { } function _setToken(token) { - $cookieStore.put(appname + '.refresh_token', token); + return $localForage.setItem(appname + '.refresh_token', token); } function _getToken() { - $cookieStore.get(appname + '.refresh_token'); + return $localForage.getItem(appname + '.refresh_token'); + } + + function _removeToken(){ + $localForage.removeItem(appname + '.refresh_token'); } function _refresh(token) { diff --git a/src/app/login/login.js b/src/app/login/login.js index 86044343..fc302f1f 100644 --- a/src/app/login/login.js +++ b/src/app/login/login.js @@ -16,10 +16,12 @@ function LoginConfig( $stateProvider ) { }) } -function LoginService( $q, $window, OrderCloud, clientid ) { +function LoginService( $q, $window, toastr, $state,OrderCloud, clientid, buyerid, TokenRefresh ) { return { SendVerificationCode: _sendVerificationCode, - ResetPassword: _resetPassword + ResetPassword: _resetPassword, + RememberMe: _rememberMe, + Logout: _logout }; function _sendVerificationCode(email) { @@ -61,9 +63,40 @@ function LoginService( $q, $window, OrderCloud, clientid ) { return deferred.promise; } + + function _logout(){ + OrderCloud.Auth.RemoveToken(); + OrderCloud.Auth.RemoveImpersonationToken(); + OrderCloud.BuyerID.Set(null); + TokenRefresh.RemoveToken(); + $state.go('login'); + } + + function _rememberMe() { + TokenRefresh.GetToken() + .then(function (refreshToken) { + if (refreshToken) { + TokenRefresh.Refresh(refreshToken) + .then(function (token) { + OrderCloud.BuyerID.Set(buyerid); + OrderCloud.Auth.SetToken(token.access_token); + $state.go('home') + }) + .catch(function () { + toastr.error("Your token has expired, please log in again.") + }); + }else{ + OrderCloud.Auth.RemoveToken(); + OrderCloud.Auth.RemoveImpersonationToken(); + OrderCloud.BuyerID.Set(null); + TokenRefresh.RemoveToken(); + $state.go('login'); + } + }) + } } -function LoginController( $state, $stateParams, $exceptionHandler, OrderCloud, LoginService, buyerid ) { +function LoginController( $state, $stateParams, $exceptionHandler, OrderCloud, LoginService, buyerid, TokenRefresh ) { var vm = this; vm.credentials = { Username: null, @@ -74,10 +107,12 @@ function LoginController( $state, $stateParams, $exceptionHandler, OrderCloud, L vm.setForm = function(form) { vm.form = form; }; + vm.rememberStatus = false; vm.submit = function() { OrderCloud.Auth.GetToken(vm.credentials) .then(function(data) { + vm.rememberStatus ? TokenRefresh.SetToken(data['refresh_token']) : angular.noop(); OrderCloud.BuyerID.Set(buyerid); OrderCloud.Auth.SetToken(data['access_token']); $state.go('home'); diff --git a/src/app/login/templates/login.tpl.html b/src/app/login/templates/login.tpl.html index e8e22544..233fe800 100644 --- a/src/app/login/templates/login.tpl.html +++ b/src/app/login/templates/login.tpl.html @@ -10,6 +10,10 @@

Login

+
+ Remember Me
+
+ Forgot Password? From daef6b495b670605d1af515f99087344c9de153b Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Thu, 24 Mar 2016 08:39:06 -0500 Subject: [PATCH 078/367] Updates to unit tests and plato for gulp. Fixing an issue present on mac computers. --- gulp.config.js | 3 ++- gulp/serve.js | 6 ++++- gulp/test/SpecRunner.html | 49 +++++++++++++++++++++++++++++++++++++++ gulp/test/e2e.js | 7 +++++- gulp/test/plato.js | 2 +- gulp/test/unit.js | 25 +++++++++++++------- 6 files changed, 80 insertions(+), 12 deletions(-) diff --git a/gulp.config.js b/gulp.config.js index e7497d1c..f36cc39d 100644 --- a/gulp.config.js +++ b/gulp.config.js @@ -6,6 +6,7 @@ var source = './src/', npmFiles = './node_modules', compile = './compile/', index = 'index.html', + root = __dirname, gulp_dir = './gulp/', fs = require('fs'); @@ -19,7 +20,7 @@ module.exports = { appCss: assets + 'styles/', appFonts: assets + 'fonts/', appImages: assets + 'images', - root: __dirname, + root: root, gulp: gulp_dir, index: source + index, styles: [ diff --git a/gulp/serve.js b/gulp/serve.js index 8bc80390..b553db7a 100644 --- a/gulp/serve.js +++ b/gulp/serve.js @@ -39,7 +39,11 @@ config.components.scripts ), ['rebuild-scripts']) .on('change', browserSync.reload); - gulp.watch(config.styles, ['styles']); + gulp.watch([].concat( + config.styles, + config.components.styles.less, + config.components.styles.css + ), ['styles']); gulp.watch(config.src + '**/app.config.json', ['app-config']) .on('change', browserSync.reload); } diff --git a/gulp/test/SpecRunner.html b/gulp/test/SpecRunner.html index 4f686a1f..e719e2f0 100644 --- a/gulp/test/SpecRunner.html +++ b/gulp/test/SpecRunner.html @@ -40,9 +40,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -74,6 +103,26 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/gulp/test/e2e.js b/gulp/test/e2e.js index 9483fc81..2ae9e302 100644 --- a/gulp/test/e2e.js +++ b/gulp/test/e2e.js @@ -1,6 +1,7 @@ var gulp = require('gulp'), argv = require('yargs').argv, selenium = require('selenium-standalone'), + config = require('../../gulp.config'), browserSync = require('browser-sync'), protractor = require("gulp-protractor").protractor; @@ -34,7 +35,11 @@ gulp.task('http', ['inject'], function(done) { open: false, port: 9000, server: { - baseDir: ['./src/app/', './dev', './'] + baseDir: [ + config.src + 'app/', + config.build, + config.root + ] }, ui: false }, done); diff --git a/gulp/test/plato.js b/gulp/test/plato.js index bb794c46..62817e5e 100644 --- a/gulp/test/plato.js +++ b/gulp/test/plato.js @@ -38,7 +38,7 @@ function openReport() { logLevel: 'silent', notify: false, open: true, - port: 453, + port: 4530, files: [ './plato/dir/files/**/*' ], diff --git a/gulp/test/unit.js b/gulp/test/unit.js index bc3c7ef3..bff79e46 100644 --- a/gulp/test/unit.js +++ b/gulp/test/unit.js @@ -12,8 +12,14 @@ gulp.task('test:unit', ['scripts', 'app-config'], function() { function runUnitTests() { var target = gulp.src('./gulp/test/SpecRunner.html'), bowerFiles = gulp.src(mainBowerFiles({includeDev: true, filter: '**/*.js'}), {read: false}), - appFiles = gulp.src([config.build + '**/app.js', config.build + '**/*.js'], {read: false}), - specFiles = gulp.src(config.src + '**/*.spec.js', {read: false}), + appFiles = gulp.src([].concat( + config.build + '**/app.js', + config.build + '**/*.js' + ), {read: false}), + specFiles = gulp.src([].concat( + config.src + '**/*.spec.js', + config.components.dir + '**/*.spec.js' + ), {read: false}), jasmineFiles = gulp.src([ './node_modules/jasmine-core/lib/jasmine-core/jasmine.css', './node_modules/jasmine-core/lib/jasmine-core/jasmine.js', @@ -22,27 +28,30 @@ function runUnitTests() { ], {read:false}); return target - .pipe(inject(jasmineFiles, {name: 'jasmine', relative: true})) - .pipe(inject(bowerFiles, {name: 'bower', relative: true})) - .pipe(inject(appFiles, {relative: true})) - .pipe(inject(specFiles, {name: 'spec', relative: true})) + .pipe(inject(jasmineFiles, {name: 'jasmine'})) + .pipe(inject(bowerFiles, {name: 'bower'})) + .pipe(inject(appFiles)) + .pipe(inject(specFiles, {name: 'spec'})) .pipe(gulp.dest('./gulp/test/')); } function serveTests() { + console.log(config.root + config.src.replace('.', '') + 'app/'); browserSync.init({ logLevel: 'silent', notify: false, open: true, - port: 452, + port: 4520, files: [ config.build + '**/*.js' ], server: { index: 'SpecRunner.html', baseDir: [ + config.root, + config.components.dir + '/../', __dirname, - __dirname + '/../../' + config.root + config.src.replace('.', '') + 'app/' ] }, ui: false From 2f1c95e3cb048afb7f315a958aec9f3f8134981e Mon Sep 17 00:00:00 2001 From: Miranda Posthumus Date: Fri, 25 Mar 2016 10:39:30 -0500 Subject: [PATCH 079/367] OC-316 fixing auto ID input disabling --- src/app/common/auto-id/auto-id.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/common/auto-id/auto-id.js b/src/app/common/auto-id/auto-id.js index 2bbffd3c..ceb990eb 100644 --- a/src/app/common/auto-id/auto-id.js +++ b/src/app/common/auto-id/auto-id.js @@ -25,12 +25,12 @@ function ordercloudAutoIdDirective($compile) { element.wrap("
"); } autoID_element.attr('checked', true); - if (autoID_element.prop('checked')) { + if (autoID_element.find('input').prop('checked')) { element.attr('disabled', true); } autoID_element.find('input').bind('click', function() { autoID_element.attr('checked', !autoID_element.prop('checked')); - if (autoID_element.prop('checked')) { + if (autoID_element.find('input').prop('checked')) { element.attr('disabled', true); element.attr('required', false); element.attr('ng-required', false); From 3a5d88c3bfacef59b9feb303fc3a0c82531de4c4 Mon Sep 17 00:00:00 2001 From: Crhistian Ramirez Date: Fri, 25 Mar 2016 17:30:01 -0500 Subject: [PATCH 080/367] add unit tests for rememberMe login --- src/app/login/login.js | 6 +----- src/app/login/tests/login.spec.js | 21 +++++++++++++++++++-- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/app/login/login.js b/src/app/login/login.js index fc302f1f..5ba14713 100644 --- a/src/app/login/login.js +++ b/src/app/login/login.js @@ -86,11 +86,7 @@ function LoginService( $q, $window, toastr, $state,OrderCloud, clientid, buyerid toastr.error("Your token has expired, please log in again.") }); }else{ - OrderCloud.Auth.RemoveToken(); - OrderCloud.Auth.RemoveImpersonationToken(); - OrderCloud.BuyerID.Set(null); - TokenRefresh.RemoveToken(); - $state.go('login'); + _logout(); } }) } diff --git a/src/app/login/tests/login.spec.js b/src/app/login/tests/login.spec.js index 1068c5e6..7b4c2367 100644 --- a/src/app/login/tests/login.spec.js +++ b/src/app/login/tests/login.spec.js @@ -2,6 +2,7 @@ describe('Component: Login', function() { var scope, q, loginFactory, + Token_Refresh, oc, credentials = { Username: 'notarealusername', @@ -9,16 +10,17 @@ describe('Component: Login', function() { }; beforeEach(module('orderCloud')); beforeEach(module('orderCloud.sdk')); - beforeEach(inject(function($q, $rootScope, OrderCloud, LoginService) { + beforeEach(inject(function($q, $rootScope, OrderCloud, LoginService, TokenRefresh) { q = $q; scope = $rootScope.$new(); loginFactory = LoginService; oc = OrderCloud; + Token_Refresh = TokenRefresh; })); describe('Factory: LoginService', function() { var client_id; - beforeEach(inject(function(clientid) { + beforeEach(inject(function(clientid, TokenRefresh) { client_id = clientid; })); describe('SendVerificationCode', function() { @@ -56,6 +58,21 @@ describe('Component: Login', function() { expect(oc.PasswordResets.ResetPassword).toHaveBeenCalledWith('code', {ClientID: client_id, Username: creds.ResetUsername, Password: creds.NewPassword}); }); }); + + describe('RememberMe', function(){ + beforeEach(inject(function(){ + var deferred = q.defer(); + deferred.resolve(true); + spyOn(Token_Refresh, 'GetToken').and.returnValue(deferred.promise); + loginFactory.RememberMe(); + + })); + + it('should call the TokenRefresh.GetToken method', function(){ + expect(Token_Refresh.GetToken).toHaveBeenCalled(); + }) + + }); }); describe('Controller: LoginCtrl', function() { From 42629a0f98802b331762a7e8100a5274e7e22747 Mon Sep 17 00:00:00 2001 From: Crhistian Ramirez Date: Fri, 25 Mar 2016 23:04:56 -0500 Subject: [PATCH 081/367] OC-319 add toastr message when user clicks component link they don't have access to --- src/app/app.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/app/app.js b/src/app/app.js index 9940165f..ee37fd87 100644 --- a/src/app/app.js +++ b/src/app/app.js @@ -49,7 +49,7 @@ function ErrorHandling( $provide ) { } } -function AppCtrl( $rootScope, $state, appname, OrderCloud ) { +function AppCtrl( $rootScope, $state, appname, OrderCloud, toastr ) { var vm = this; vm.name = appname; vm.title = appname; @@ -78,6 +78,9 @@ function AppCtrl( $rootScope, $state, appname, OrderCloud ) { $rootScope.$on('OC:AccessInvalidOrExpired', function() { vm.logout(); }); + $rootScope.$on('OC:AccessForbidden', function(){ + toastr.warning("I'm sorry, it doesn't look like you have permission to access this page.", 'Warning:'); + }) } function Interceptor( $httpProvider ) { @@ -87,6 +90,9 @@ function Interceptor( $httpProvider ) { if (rejection.config.url.indexOf('ordercloud.io') > -1 && rejection.status == 401) { $rootScope.$broadcast('OC:AccessInvalidOrExpired'); } + if (rejection.config.url.indexOf('ordercloud.io') > -1 && rejection.status == 403){ + $rootScope.$broadcast('OC:AccessForbidden'); + } return $q.reject(rejection); } }; From 0e3466035338ff8fabfb1267d766617c2e03821c Mon Sep 17 00:00:00 2001 From: Crhistian Ramirez Date: Mon, 28 Mar 2016 14:03:05 -0500 Subject: [PATCH 082/367] add custom error messages for invalid input on forms --- src/app/base/base.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/app/base/base.js b/src/app/base/base.js index 42a81e1f..2412565d 100644 --- a/src/app/base/base.js +++ b/src/app/base/base.js @@ -77,9 +77,16 @@ function BaseConfig( $stateProvider ) { }); } -function BaseController(CurrentUser) { +function BaseController(CurrentUser, defaultErrorMessageResolver) { var vm = this; vm.currentUser = CurrentUser; + + defaultErrorMessageResolver.getErrorMessages().then(function (errorMessages) { + errorMessages['customPassword'] = 'Password must be at least eight characters long and include at least one letter and one number'; + //regex for customPassword = ^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$ + errorMessages['positiveInteger'] = 'Please enter a positive integer'; + //regex positiveInteger = ^[0-9]*[1-9][0-9]*$ + }); } function BaseLeftController(ComponentList) { From 1fa729675adc3ed0888b63af354f235a2b79feef Mon Sep 17 00:00:00 2001 From: Miranda Posthumus Date: Mon, 4 Apr 2016 13:07:30 -0500 Subject: [PATCH 083/367] OC-393 fix infinite scroll for categories - depth was added before page/page-size so the call needed to be updated --- src/app/common/helper-factories/paging-helpers.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/app/common/helper-factories/paging-helpers.js b/src/app/common/helper-factories/paging-helpers.js index 56a00803..5f1e0fb1 100644 --- a/src/app/common/helper-factories/paging-helpers.js +++ b/src/app/common/helper-factories/paging-helpers.js @@ -25,12 +25,15 @@ function PagingHelpers($q, OrderCloud, Assignments) { if (Service && ListObject.Meta.Page < ListObject.Meta.TotalPages) { var queue = []; var dfd = $q.defer(); - if (ServiceName !== 'Orders') { + if (ServiceName !== 'Orders' && ServiceName !== 'Categories') { queue.push(Service.List(null, ListObject.Meta.Page + 1, ListObject.Meta.PageSize)); } - else { + if (ServiceName === 'Orders') { queue.push(Service.List('incoming', null, null, null, ListObject.Meta.Page + 1, ListObject.Meta.PageSize)); } + if (ServiceName === 'Categories') { + queue.push(Service.List(null, 'all', ListObject.Meta.Page + 1, ListObject.Meta.PageSize)); + } if (AssignmentFunc !== undefined && (AssignmentObjects.Meta.Page < AssignmentObjects.Meta.TotalPages)) { queue.push(AssignmentFunc()); } From 6fba85d5b896d391a3a3676b9e4668f126bca6b9 Mon Sep 17 00:00:00 2001 From: Crhistian Ramirez Date: Mon, 4 Apr 2016 13:48:59 -0500 Subject: [PATCH 084/367] add error message for ID/Name fields --- src/app/base/base.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/app/base/base.js b/src/app/base/base.js index 2412565d..d021f27f 100644 --- a/src/app/base/base.js +++ b/src/app/base/base.js @@ -86,6 +86,8 @@ function BaseController(CurrentUser, defaultErrorMessageResolver) { //regex for customPassword = ^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$ errorMessages['positiveInteger'] = 'Please enter a positive integer'; //regex positiveInteger = ^[0-9]*[1-9][0-9]*$ + errorMessages['ID_Name'] = 'Only Alphanumeric characters, hyphens and underscores are allowed'; + //regex ID_Name = ([A-Za-z0-9\-\_]+) }); } From 0f6f92027c409d546e1c1329d8e34e9d5fe48128 Mon Sep 17 00:00:00 2001 From: Crhistian Ramirez Date: Tue, 5 Apr 2016 13:54:13 -0500 Subject: [PATCH 085/367] add confirm password directive. OC-407 --- src/app/base/base.js | 3 +- .../common/confirmPassword/confirmPassword.js | 33 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 src/app/common/confirmPassword/confirmPassword.js diff --git a/src/app/base/base.js b/src/app/base/base.js index d021f27f..7955b993 100644 --- a/src/app/base/base.js +++ b/src/app/base/base.js @@ -83,11 +83,12 @@ function BaseController(CurrentUser, defaultErrorMessageResolver) { defaultErrorMessageResolver.getErrorMessages().then(function (errorMessages) { errorMessages['customPassword'] = 'Password must be at least eight characters long and include at least one letter and one number'; - //regex for customPassword = ^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$ + //regex for customPassword = ^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d!$%@#£€*?&]{8,}$ errorMessages['positiveInteger'] = 'Please enter a positive integer'; //regex positiveInteger = ^[0-9]*[1-9][0-9]*$ errorMessages['ID_Name'] = 'Only Alphanumeric characters, hyphens and underscores are allowed'; //regex ID_Name = ([A-Za-z0-9\-\_]+) + errorMessages['confirmpassword'] = 'Your passwords do not match' }); } diff --git a/src/app/common/confirmPassword/confirmPassword.js b/src/app/common/confirmPassword/confirmPassword.js new file mode 100644 index 00000000..9ccb41e8 --- /dev/null +++ b/src/app/common/confirmPassword/confirmPassword.js @@ -0,0 +1,33 @@ +angular.module( 'orderCloud' ) + .directive('confirmpassword', confirmpassword) +; + +function confirmpassword() { + return { + restrict: 'A', + require: 'ngModel', + link: function (scope, element, attrs, ngModel) { + if (!ngModel) return; + + //watch own value and re-validate on change + scope.$watch(attrs.ngModel, function () { + validate(); + }); + + //watch other value and re-validate on change + attrs.$observe('confirmpassword', function (val) { + validate(); + }); + + var validate = function() { + var val1 = ngModel.$viewValue; + var val2 = attrs.confirmpassword; + + (!val1 || !val2 || val1 === val2) ? ngModel.$setValidity('confirmpassword', true) : ngModel.$setValidity('confirmpassword', false); + + } + } + } +} + + From 8806ae5c1ad81144b0ca1731fd5faa754d5949ff Mon Sep 17 00:00:00 2001 From: Crhistian Ramirez Date: Thu, 7 Apr 2016 14:31:55 -0500 Subject: [PATCH 086/367] OC-315 fix file upload bug. was returning a 401 because of missing auth headers --- src/app/common/files/files.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/common/files/files.js b/src/app/common/files/files.js index 811f02e7..a3391c6b 100644 --- a/src/app/common/files/files.js +++ b/src/app/common/files/files.js @@ -56,7 +56,7 @@ function fileReader( $q ) { return service; } -function FilesService( $q, $http, apiurl ) { +function FilesService( $q, $http, apiurl, OrderCloud ) { var service = { Upload: _upload }; @@ -69,7 +69,7 @@ function FilesService( $q, $http, apiurl ) { var fd = new FormData(); fd.append('file', file); - $http.post(fileURL + '?filename=' + fileName, fd, {transformRequest: angular.identity, headers: {'Content-Type': undefined}}) + $http.post(fileURL + '?filename=' + fileName, fd, {transformRequest: angular.identity, headers: {'Content-Type': undefined, 'Authorization': 'Bearer ' + OrderCloud.Auth.ReadToken()} }) .success(function(data){ deferred.resolve(data); }) From d6984d82c9c8d9421afa3ee0fe34571106f0d503 Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 8 Apr 2016 18:21:49 -0600 Subject: [PATCH 087/367] Working prototype --- bower.json | 3 +- src/app/account/templates/account.tpl.html | 2 +- src/app/app.config.json | 9 +-- src/app/app.js | 75 ++++++++++++++-------- src/app/base/less/base.less | 61 +----------------- src/app/base/templates/base.left.tpl.html | 2 - src/app/base/templates/base.top.tpl.html | 4 +- src/app/base/templates/base.tpl.html | 15 +++-- src/app/global.less | 11 ++++ src/app/home/templates/home.tpl.html | 8 +-- src/index.html | 2 +- 11 files changed, 83 insertions(+), 109 deletions(-) diff --git a/bower.json b/bower.json index ec5ed325..a4d65fde 100644 --- a/bower.json +++ b/bower.json @@ -35,7 +35,8 @@ "ordercloud-ng-sdk": "^1.0.1", "OrderCloud-Angular-SDK": "ordercloud-angular-sdk#^1.0.9", "angular-auto-validate": "^1.19.3", - "font-awesome": "^4.5.0" + "font-awesome": "^4.5.0", + "angular-snap": "^1.8.5" }, "devDependencies": { "angular-mocks": "^1.5.0" diff --git a/src/app/account/templates/account.tpl.html b/src/app/account/templates/account.tpl.html index a5155e7c..63f8e0f5 100644 --- a/src/app/account/templates/account.tpl.html +++ b/src/app/account/templates/account.tpl.html @@ -1,5 +1,5 @@ -
+
diff --git a/src/app/app.config.json b/src/app/app.config.json index 71604744..3b8d122b 100644 --- a/src/app/app.config.json +++ b/src/app/app.config.json @@ -1,6 +1,7 @@ { - "appname": "XXXXX", - "ocscope": "BuyerReader", - "clientid": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX", - "buyerid": "XXXXX" + "appname": "Angular-Snap Prototype", + "ocscope": "FullAccess", + "clientid": "FA2E05CB-40DE-4210-AF48-AB7BF02B8F0B", + "buyerid": "component_1", + "environment": "prod" } diff --git a/src/app/app.js b/src/app/app.js index c8f0dad2..915cbf26 100644 --- a/src/app/app.js +++ b/src/app/app.js @@ -1,30 +1,32 @@ angular.module( 'orderCloud', [ - 'ngSanitize', - 'ngAnimate', - 'ngMessages', - 'ngTouch', - 'ui.tree', - 'ui.router', - 'ui.bootstrap', - 'orderCloud.sdk', - 'LocalForageModule', - 'toastr', - 'jcs-autoValidate', - 'ordercloud-infinite-scroll', - 'ordercloud-buyer-select', - 'ordercloud-search', - 'ordercloud-assignment-helpers', - 'ordercloud-paging-helpers', - 'ordercloud-auto-id', - 'ordercloud-current-order', - 'ordercloud-address', - 'ordercloud-lineitems' - ]) + 'ngSanitize', + 'ngAnimate', + 'ngMessages', + 'ngTouch', + 'ui.tree', + 'ui.router', + 'ui.bootstrap', + 'orderCloud.sdk', + 'LocalForageModule', + 'snap', + 'toastr', + 'jcs-autoValidate', + 'ordercloud-infinite-scroll', + 'ordercloud-buyer-select', + 'ordercloud-search', + 'ordercloud-assignment-helpers', + 'ordercloud-paging-helpers', + 'ordercloud-auto-id', + 'ordercloud-current-order', + 'ordercloud-address', + 'ordercloud-lineitems' +]) .run( SetBuyerID ) .config( Routing ) .config( ErrorHandling ) .config( Interceptor ) + .config( Drawers ) .controller( 'AppCtrl', AppCtrl ) ; @@ -49,21 +51,38 @@ function ErrorHandling( $provide ) { } } -function AppCtrl( $rootScope, $state, appname, LoginService, toastr ) { +function AppCtrl( $rootScope, $ocMedia, $state, snapRemote, appname, LoginService, toastr ) { var vm = this; vm.name = appname; vm.title = appname; - vm.showLeftNav = true; vm.$state = $state; + vm.$ocMedia = $ocMedia; - vm.toggleLeftNav = function() { - vm.showLeftNav = !vm.showLeftNav; - }; + function _isMobile() { + return $ocMedia('max-width:767px'); + } + + function initDrawers(isMobile) { + if (isMobile) { + snapRemote.close('MAIN'); + vm.showMenuToggle = true; + } else { + snapRemote.open('left', 'MAIN'); + vm.showMenuToggle = false; + } + } + + initDrawers(_isMobile()); vm.logout = function() { LoginService.Logout(); }; + $rootScope.$watch(_isMobile, function(n, o) { + if (n === o) return; + initDrawers(n); + }); + $rootScope.$on('$stateChangeSuccess', function(e, toState) { if (toState.data && toState.data.componentName) { vm.title = appname + ' - ' + toState.data.componentName @@ -95,3 +114,7 @@ function Interceptor( $httpProvider ) { }; }); } + +function Drawers(snapRemoteProvider) { + snapRemoteProvider.globalOptions.disable = 'right'; +} diff --git a/src/app/base/less/base.less b/src/app/base/less/base.less index f686c75b..f89e5314 100644 --- a/src/app/base/less/base.less +++ b/src/app/base/less/base.less @@ -3,71 +3,12 @@ * Code licensed under the Apache License v2.0. * For details, see http://www.apache.org/licenses/LICENSE-2.0. */ -#DashboardWrapper { - padding-left: 0; - transition: all 0.5s ease; - &.toggled { - padding-left: @dashboard-leftnav-width; - #DashboardLeftNav { - width: @dashboard-leftnav-width; - } - #DashboardContent { - position: absolute; - margin-right: -@dashboard-leftnav-width; - } - } -} - -#DashboardLeftNav { - z-index: 1000; - position: fixed; - left: @dashboard-leftnav-width; - width: 0; - height: 100%; - margin-left: -@dashboard-leftnav-width; - overflow:hidden; +#MAIN_LEFT { background-color:@dashboard-leftnav-bg; - border-right:1px solid @dashboard-leftnav-border; - -webkit-transition: all 0.5s ease; - -moz-transition: all 0.5s ease; - -o-transition: all 0.5s ease; - transition: all 0.5s ease; -} - -#DashboardContent { - width: 100%; - position: absolute; -} - -@media(min-width:768px) { - #DashboardWrapper { - padding-left: @dashboard-leftnav-width; - &.toggled { - padding-left: 0; - #DashboardLeftNav { - width: 0; - } - #DashboardContent { - position: relative; - margin-right: 0; - } - } - } - - #DashboardLeftNav { - width: @dashboard-leftnav-width; - } - - #DashboardContent { - position: relative; - } } #BaseLeft { - height:100%; - overflow-y:auto; padding: @padding-base-horizontal; - width: @dashboard-leftnav-width; white-space: nowrap; h4 { margin-left:-@padding-base-horizontal; diff --git a/src/app/base/templates/base.left.tpl.html b/src/app/base/templates/base.left.tpl.html index 6606daf5..e3c2554d 100644 --- a/src/app/base/templates/base.left.tpl.html +++ b/src/app/base/templates/base.left.tpl.html @@ -6,8 +6,6 @@ - -
From 3323ac51274be315bf3a2c503c40ba505019376b Mon Sep 17 00:00:00 2001 From: Aisha Ragheb Date: Tue, 10 May 2016 16:13:50 -0500 Subject: [PATCH 109/367] OC-583 adding a geography service to le seed --- src/app/app.js | 3 +- src/app/common/geoService/geoService2.js | 0 src/app/common/georgraphy/geography.js | 349 +++++++++++++++++++++++ 3 files changed, 351 insertions(+), 1 deletion(-) create mode 100644 src/app/common/geoService/geoService2.js create mode 100644 src/app/common/georgraphy/geography.js diff --git a/src/app/app.js b/src/app/app.js index 02929138..4edacbd3 100644 --- a/src/app/app.js +++ b/src/app/app.js @@ -18,7 +18,8 @@ angular.module( 'orderCloud', [ 'ordercloud-auto-id', 'ordercloud-current-order', 'ordercloud-address', - 'ordercloud-lineitems' + 'ordercloud-lineitems', + 'ordercloud-geography' ]) .run( SetBuyerID ) diff --git a/src/app/common/geoService/geoService2.js b/src/app/common/geoService/geoService2.js new file mode 100644 index 00000000..e69de29b diff --git a/src/app/common/georgraphy/geography.js b/src/app/common/georgraphy/geography.js new file mode 100644 index 00000000..c80fa25a --- /dev/null +++ b/src/app/common/georgraphy/geography.js @@ -0,0 +1,349 @@ +angular.module('ordercloud-geography', []) + + .factory('OCGeography', OCGeography) + +; + +function OCGeography() { + var countries = [ + { "label": "United States of America", "value": "US"}, + { "label": "Afghanistan", "value": "AF"}, + { "label": "Åland Islands", "value": "AX"}, + { "label": "Albania", "value": "AL"}, + { "label": "Algeria", "value": "DZ"}, + { "label": "American Samoa", "value": "AS"}, + { "label": "Andorra", "value": "AD"}, + { "label": "Angola", "value": "AO"}, + { "label": "Anguilla", "value": "AI"}, + { "label": "Antarctica", "value": "AQ"}, + { "label": "Antigua and Barbuda", "value": "AG"}, + { "label": "Argentina", "value": "AR"}, + { "label": "Armenia", "value": "AM"}, + { "label": "Aruba", "value": "AW"}, + { "label": "Australia", "value": "AU"}, + { "label": "Austria", "value": "AT"}, + { "label": "Azerbaijan", "value": "AZ"}, + { "label": "Bahamas", "value": "BS"}, + { "label": "Bahrain", "value": "BH"}, + { "label": "Bangladesh", "value": "BD"}, + { "label": "Barbados", "value": "BB"}, + { "label": "Belarus", "value": "BY"}, + { "label": "Belgium", "value": "BE"}, + { "label": "Belize", "value": "BZ"}, + { "label": "Benin", "value": "BJ"}, + { "label": "Bermuda", "value": "BM"}, + { "label": "Bhutan", "value": "BT"}, + { "label": "Bolivia", "value": "BO"}, + { "label": "Bosnia and Herzegovina", "value": "BA"}, + { "label": "Botswana", "value": "BW"}, + { "label": "Bouvet Island", "value": "BV"}, + { "label": "Brazil", "value": "BR"}, + { "label": "British Indian Ocean Territory", "value": "IO"}, + { "label": "Brunei Darussalam", "value": "BN"}, + { "label": "Bulgaria", "value": "BG"}, + { "label": "Burkina Faso", "value": "BF"}, + { "label": "Burundi", "value": "BI"}, + { "label": "Cambodia", "value": "KH"}, + { "label": "Cameroon", "value": "CM"}, + { "label": "Canada", "value": "CA"}, + { "label": "Cape Verde", "value": "CV"}, + { "label": "Cayman Islands", "value": "KY"}, + { "label": "Central African Republic", "value": "CF"}, + { "label": "Chad", "value": "TD"}, + { "label": "Chile", "value": "CL"}, + { "label": "China", "value": "CN"}, + { "label": "Christmas Island Australia", "value": "CX"}, + { "label": "Cocos Keeling Islands", "value": "CC"}, + { "label": "Colombia", "value": "CO"}, + { "label": "Comoros", "value": "KM"}, + { "label": "Congo", "value": "CG"}, + { "label": "Congo, D.R.", "value": "CD"}, + { "label": "Cook Islands", "value": "CK"}, + { "label": "Costa Rica", "value": "CR"}, + { "label": "Cote D'Ivoire Ivory Coast", "value": "CI"}, + { "label": "Croatia Hrvatska", "value": "HR"}, + { "label": "Cuba", "value": "CU"}, + { "label": "Cyprus", "value": "CY"}, + { "label": "Czech Republic", "value": "CZ"}, + { "label": "Denmark", "value": "DK"}, + { "label": "Djibouti", "value": "DJ"}, + { "label": "Dominica", "value": "DM"}, + { "label": "Dominican Republic", "value": "DO"}, + { "label": "Ecuador", "value": "EC"}, + { "label": "Egypt", "value": "EG"}, + { "label": "El Salvador", "value": "SV"}, + { "label": "Equatorial Guinea", "value": "GQ"}, + { "label": "Eritrea", "value": "ER"}, + { "label": "Estonia", "value": "EE"}, + { "label": "Ethiopia", "value": "ET"}, + { "label": "Faeroe Islands", "value": "FO"}, + { "label": "Falkland Islands Malvinas", "value": "FK"}, + { "label": "Fiji", "value": "FJ"}, + { "label": "Finland", "value": "FI"}, + { "label": "France", "value": "FR"}, + { "label": "France, Metropolitan", "value": "FX"}, + { "label": "French Guiana", "value": "GF"}, + { "label": "French Polynesia", "value": "PF"}, + { "label": "French Southern Territories", "value": "TF"}, + { "label": "Gabon", "value": "GA"}, + { "label": "Gambia", "value": "GM"}, + { "label": "Georgia", "value": "GE"}, + { "label": "Germany", "value": "DE"}, + { "label": "Ghana", "value": "GH"}, + { "label": "Gibraltar", "value": "GI"}, + { "label": "Greece", "value": "GR"}, + { "label": "Greenland", "value": "GL"}, + { "label": "Grenada", "value": "GD"}, + { "label": "Guadeloupe", "value": "GP"}, + { "label": "Guam", "value": "GU"}, + { "label": "Guatemala", "value": "GT"}, + { "label": "Guinea", "value": "GN"}, + { "label": "Guinea Bissau", "value": "GW"}, + { "label": "Guyana", "value": "GY"}, + { "label": "Haiti", "value": "HT"}, + { "label": "Heard and McDonald Is.", "value": "HM"}, + { "label": "Honduras", "value": "HN"}, + { "label": "Hong Kong", "value": "HK"}, + { "label": "Hungary", "value": "HU"}, + { "label": "Iceland", "value": "IS"}, + { "label": "India", "value": "IN"}, + { "label": "Indonesia", "value": "ID"}, + { "label": "Iran", "value": "IR"}, + { "label": "Iraq", "value": "IQ"}, + { "label": "Isle of Man", "value": "IM"}, + { "label": "Ireland", "value": "IE"}, + { "label": "Israel", "value": "IL"}, + { "label": "Italy", "value": "IT"}, + { "label": "Jamaica", "value": "JM"}, + { "label": "Japan", "value": "JP"}, + { "label": "Jersey", "value": "JE"}, + { "label": "Jordan", "value": "JO"}, + { "label": "Kazakhstan", "value": "KZ"}, + { "label": "Kenya", "value": "KE"}, + { "label": "Kiribati", "value": "KI"}, + { "label": "Korea North", "value": "KP"}, + { "label": "Korea South", "value": "KR"}, + { "label": "Kuwait", "value": "KW"}, + { "label": "Kyrgyzstan", "value": "KG"}, + { "label": "Lao P.Dem.R.", "value": "LA"}, + { "label": "Latvia", "value": "LV"}, + { "label": "Lebanon", "value": "LB"}, + { "label": "Lesotho", "value": "LS"}, + { "label": "Liberia", "value": "LR"}, + { "label": "Libyan Arab Jamahiriya", "value": "LY"}, + { "label": "Liechtenstein", "value": "LI"}, + { "label": "Lithuania", "value": "LT"}, + { "label": "Luxembourg", "value": "LU"}, + { "label": "Macau", "value": "MO"}, + { "label": "Macedonia", "value": "MK"}, + { "label": "Madagascar", "value": "MG"}, + { "label": "Malawi", "value": "MW"}, + { "label": "Malaysia", "value": "MY"}, + { "label": "Maldives", "value": "MV"}, + { "label": "Mali", "value": "ML"}, + { "label": "Malta", "value": "MT"}, + { "label": "Marshall Islands", "value": "MH"}, + { "label": "Martinique", "value": "MQ"}, + { "label": "Mauritania", "value": "MR"}, + { "label": "Mauritius", "value": "MU"}, + { "label": "Mayotte", "value": "YT"}, + { "label": "Mexico", "value": "MX"}, + { "label": "Micronesia", "value": "FM"}, + { "label": "Moldova", "value": "MD"}, + { "label": "Monaco", "value": "MC"}, + { "label": "Mongolia", "value": "MN"}, + { "label": "Montenegro", "value": "ME"}, + { "label": "Montserrat", "value": "MS"}, + { "label": "Morocco", "value": "MA"}, + { "label": "Mozambique", "value": "MZ"}, + { "label": "Myanmar", "value": "MM"}, + { "label": "Namibia", "value": "NA"}, + { "label": "Nauru", "value": "NR"}, + { "label": "Nepal", "value": "NP"}, + { "label": "Netherlands", "value": "NL"}, + { "label": "Netherlands Antilles", "value": "AN"}, + { "label": "New Caledonia", "value": "NC"}, + { "label": "New Zealand", "value": "NZ"}, + { "label": "Nicaragua", "value": "NI"}, + { "label": "Niger", "value": "NE"}, + { "label": "Nigeria", "value": "NG"}, + { "label": "Niue", "value": "NU"}, + { "label": "Norfolk Island", "value": "NF"}, + { "label": "Northern Mariana Islands", "value": "MP"}, + { "label": "Norway", "value": "NO"}, + { "label": "Oman", "value": "OM"}, + { "label": "Pakistan", "value": "PK"}, + { "label": "Palau", "value": "PW"}, + { "label": "Palestinian Territory, Occupied", "value": "PS"}, + { "label": "Panama", "value": "PA"}, + { "label": "Papua New Guinea", "value": "PG"}, + { "label": "Paraguay", "value": "PY"}, + { "label": "Peru", "value": "PE"}, + { "label": "Philippines", "value": "PH"}, + { "label": "Pitcairn", "value": "PN"}, + { "label": "Poland", "value": "PL"}, + { "label": "Portugal", "value": "PT"}, + { "label": "Puerto Rico", "value": "PR"}, + { "label": "Qatar", "value": "QA"}, + { "label": "Reunion", "value": "RE"}, + { "label": "Romania", "value": "RO"}, + { "label": "Russian Federation", "value": "RU"}, + { "label": "Rwanda", "value": "RW"}, + { "label": "Saint Helena", "value": "SH"}, + { "label": "Saint Kitts and Nevis", "value": "KN"}, + { "label": "Saint Lucia", "value": "LC"}, + { "label": "Saint Pierre and Miquelon", "value": "PM"}, + { "label": "Saint Vincent and the Grenadines", "value": "VC"}, + { "label": "Samoa", "value": "WS"}, + { "label": "San Marino", "value": "SM"}, + { "label": "Sao Tome and Principe", "value": "ST"}, + { "label": "Saudi Arabia", "value": "SA"}, + { "label": "Senegal", "value": "SN"}, + { "label": "Serbia", "value": "RS"}, + { "label": "Seychelles", "value": "SC"}, + { "label": "Sierra Leone", "value": "SL"}, + { "label": "Singapore", "value": "SG"}, + { "label": "Slovakia", "value": "SK"}, + { "label": "Slovenia", "value": "SI"}, + { "label": "Solomon Islands", "value": "SB"}, + { "label": "Somalia", "value": "SO"}, + { "label": "South Africa", "value": "ZA"}, + { "label": "S. Georgia & S. Sandwich Is.", "value": "GS"}, + { "label": "Spain", "value": "ES"}, + { "label": "Sri Lanka", "value": "LK"}, + { "label": "Sudan", "value": "SD"}, + { "label": "Suriname", "value": "SR"}, + { "label": "Svalbard & Jan Mayen Is.", "value": "SJ"}, + { "label": "Swaziland", "value": "SZ"}, + { "label": "Sweden", "value": "SE"}, + { "label": "Switzerland", "value": "CH"}, + { "label": "Syrian Arab Rep.", "value": "SY"}, + { "label": "Taiwan", "value": "TW"}, + { "label": "Tajikistan", "value": "TJ"}, + { "label": "Tanzania", "value": "TZ"}, + { "label": "Thailand", "value": "TH"}, + { "label": "Timor-Leste", "value": "TG"}, + { "label": "Togo", "value": "TG"}, + { "label": "Tokelau", "value": "TK"}, + { "label": "Tonga", "value": "TO"}, + { "label": "Trinidad and Tobago", "value": "TT"}, + { "label": "Tunisia", "value": "TN"}, + { "label": "Turkey", "value": "TR"}, + { "label": "Turkmenistan", "value": "TM"}, + { "label": "Turks and Caicos Islands", "value": "TC"}, + { "label": "Tuvalu", "value": "TU"}, + { "label": "Uganda", "value": "UG"}, + { "label": "Ukraine", "value": "UA"}, + { "label": "United Kingdom", "value": "GB"}, + { "label": "United Arab Emirates", "value": "AE"}, + { "label": "US Minor Outlying Is.", "value": "UM"}, + { "label": "Uruguay", "value": "UY"}, + { "label": "Uzbekistan", "value": "UZ"}, + { "label": "Vanuatu", "value": "VU"}, + { "label": "Vatican City State", "value": "VC"}, + { "label": "Venezuela", "value": "VE"}, + { "label": "Viet Nam", "value": "VN"}, + { "label": "Virgin Islands British", "value": "VG"}, + { "label": "Virgin Islands US", "value": "VI"}, + { "label": "Wallis and Futuna Islnds", "value": "WF"}, + { "label": "Western Sahara", "value": "EH"}, + { "label": "Yemen", "value": "YE"}, + { "label": "Yugoslavia", "value": "YU"}, + { "label": "Zambia", "value": "ZM"}, + { "label": "Zimbabwe", "value": "ZW"} + ]; + var states = [ + { "label": "Alabama", "value": "AL", "country": "US" }, + { "label": "Alaska", "value": "AK", "country": "US" }, + { "label": "Arizona", "value": "AZ", "country": "US" }, + { "label": "Arkansas", "value": "AR", "country": "US" }, + { "label": "California", "value": "CA", "country": "US" }, + { "label": "Colorado", "value": "CO", "country": "US" }, + { "label": "Connecticut", "value": "CT", "country": "US" }, + { "label": "Delaware", "value": "DE", "country": "US" }, + { "label": "District of Columbia", "value": "DC", "country": "US" }, + { "label": "Florida", "value": "FL", "country": "US" }, + { "label": "Georgia", "value": "GA", "country": "US" }, + { "label": "Hawaii", "value": "HI", "country": "US" }, + { "label": "Idaho", "value": "ID", "country": "US" }, + { "label": "Illinois", "value": "IL", "country": "US" }, + { "label": "Indiana", "value": "IN", "country": "US" }, + { "label": "Iowa", "value": "IA", "country": "US" }, + { "label": "Kansas", "value": "KS", "country": "US" }, + { "label": "Kentucky", "value": "KY", "country": "US" }, + { "label": "Louisiana", "value": "LA", "country": "US" }, + { "label": "Maine", "value": "ME", "country": "US" }, + { "label": "Maryland", "value": "MD", "country": "US" }, + { "label": "Massachusetts", "value": "MA", "country": "US" }, + { "label": "Michigan", "value": "MI", "country": "US" }, + { "label": "Minnesota", "value": "MN", "country": "US" }, + { "label": "Mississippi", "value": "MS", "country": "US" }, + { "label": "Missouri", "value": "MO", "country": "US" }, + { "label": "Montana", "value": "MT", "country": "US" }, + { "label": "Nebraska", "value": "NE", "country": "US" }, + { "label": "Nevada", "value": "NV", "country": "US" }, + { "label": "New Hampshire", "value": "NH", "country": "US" }, + { "label": "New Jersey", "value": "NJ", "country": "US" }, + { "label": "New Mexico", "value": "NM", "country": "US" }, + { "label": "New York", "value": "NY", "country": "US" }, + { "label": "North Carolina", "value": "NC", "country": "US" }, + { "label": "North Dakota", "value": "ND", "country": "US" }, + { "label": "Ohio", "value": "OH", "country": "US" }, + { "label": "Oklahoma", "value": "OK", "country": "US" }, + { "label": "Oregon", "value": "OR", "country": "US" }, + { "label": "Pennsylvania", "value": "PA", "country": "US" }, + { "label": "Rhode Island", "value": "RI", "country": "US" }, + { "label": "South Carolina", "value": "SC", "country": "US" }, + { "label": "South Dakota", "value": "SD", "country": "US" }, + { "label": "Tennessee", "value": "TN", "country": "US" }, + { "label": "Texas", "value": "TX", "country": "US" }, + { "label": "Utah", "value": "UT", "country": "US" }, + { "label": "Vermont", "value": "VT", "country": "US" }, + { "label": "Virginia", "value": "VA", "country": "US" }, + { "label": "Washington", "value": "WA", "country": "US" }, + { "label": "West Virginia", "value": "WV", "country": "US" }, + { "label": "Wisconsin", "value": "WI", "country": "US" }, + { "label": "Wyoming", "value": "WY", "country": "US" }, + { "label": "Armed Forces Americas (AA)", "value": "AA", "country": "US" }, + { "label": "Armed Forces Africa/Canada/Europe/Middle East (AE)", "value": "AE", "country": "US" }, + { "label": "Armed Forces Pacific (AP)", "value": "AP", "country": "US" }, + { "label": "American Samoa", "value": "AS", "country": "US" }, + { "label": "Federated States of Micronesia", "value": "FM", "country": "US" }, + { "label": "Guam", "value": "GU", "country": "US" }, + { "label": "Marshall Islands", "value": "MH", "country": "US" }, + { "label": "Northern Mariana Islands", "value": "MP", "country": "US" }, + { "label": "Palau", "value": "PW", "country": "US" }, + { "label": "Puerto Rico", "value": "PR", "country": "US" }, + { "label": "Virgin Islands", "value": "VI", "country": "US" }, + { "label": "Drenthe", "value": "Drenthe", "country": "NL" }, + { "label": "Flevoland", "value": "Flevoland", "country": "NL" }, + { "label": "Friesland", "value": "Friesland", "country": "NL" }, + { "label": "Gelderland", "value": "Gelderland", "country": "NL" }, + { "label": "Groningen", "value": "Groningen", "country": "NL" }, + { "label": "Limburg", "value": "Limburg", "country": "NL" }, + { "label": "Noord-Brabant", "value": "Noord-Brabant", "country": "NL" }, + { "label": "Noord-Holland", "value": "Noord-Holland", "country": "NL" }, + { "label": "Overijssel", "value": "Overijssel", "country": "NL" }, + { "label": "Utrecht", "value": "Utrecht", "country": "NL" }, + { "label": "Zeeland", "value": "Zeeland", "country": "NL" }, + { "label": "Zuid-Holland", "value": "Zuid-Holland", "country": "NL" }, + { "label": "Alberta", "value": "AB", "country": "CA" }, + { "label": "British Columbia", "value": "BC", "country": "CA" }, + { "label": "Manitoba", "value": "MB", "country": "CA" }, + { "label": "New Brunswick", "value": "NB", "country": "CA" }, + { "label": "Newfoundland and Labrador", "value": "NL", "country": "CA" }, + { "label": "Northwest Territories", "value": "NT", "country": "CA" }, + { "label": "Nova Scotia", "value": "NS", "country": "CA" }, + { "label": "Nunavut", "value": "NU", "country": "CA" }, + { "label": "Ontario", "value": "ON", "country": "CA" }, + { "label": "Prince Edward Island", "value": "PE", "country": "CA" }, + { "label": "Quebec", "value": "QC", "country": "CA" }, + { "label": "Saskatchewan", "value": "SK", "country": "CA" }, + { "label": "Yukon", "value": "YT", "country": "CA" } + ]; + + return { + countries: countries, + states: states + }; +}; \ No newline at end of file From 850422a0e59c1c7baac4bcb3c0434b3657033f68 Mon Sep 17 00:00:00 2001 From: Crhistian Ramirez Date: Tue, 10 May 2016 19:52:50 -0500 Subject: [PATCH 110/367] OC-59 update Account component to use Me.Update --- src/app/account/account.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/account/account.js b/src/app/account/account.js index 62e2f044..248126bd 100644 --- a/src/app/account/account.js +++ b/src/app/account/account.js @@ -35,7 +35,7 @@ function AccountService( $q, $uibModal, OrderCloud ) { var deferred = $q.defer(); function updateUser() { - OrderCloud.AdminUsers.Update(currentProfile.ID, newProfile) + OrderCloud.Me.Update(newProfile) .then(function(data) { deferred.resolve(data); }) @@ -78,7 +78,7 @@ function AccountService( $q, $uibModal, OrderCloud ) { function changePassword() { currentUser.Password = currentUser.NewPassword; - OrderCloud.AdminUsers.Update(currentUser.ID, currentUser) + OrderCloud.Me.Update(currentUser) .then(function() { deferred.resolve(); }); From d09d031bf6e281b7561d011bb72d29d378807530 Mon Sep 17 00:00:00 2001 From: Crhistian Ramirez Date: Tue, 10 May 2016 19:57:25 -0500 Subject: [PATCH 111/367] OC-59 fix tests to work with new update --- src/app/account/tests/account.spec.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/account/tests/account.spec.js b/src/app/account/tests/account.spec.js index 184cffd1..7d0a210f 100644 --- a/src/app/account/tests/account.spec.js +++ b/src/app/account/tests/account.spec.js @@ -28,7 +28,7 @@ describe('Component: Account', function() { var defer = q.defer(); defer.resolve(); spyOn(oc.Auth, 'GetToken').and.returnValue(defer.promise); - spyOn(oc.AdminUsers, 'Update').and.returnValue(defer.promise); + spyOn(oc.Me, 'Update').and.returnValue(defer.promise); })); describe('Update', function() { @@ -51,7 +51,7 @@ describe('Component: Account', function() { expect(uibModal.open).toHaveBeenCalled(); scope.$digest(); expect(oc.Auth.GetToken).toHaveBeenCalledWith({Username: 'FAKEUSERNAME', Password: 'FAKEPASSWORD'}); - expect(oc.AdminUsers.Update).toHaveBeenCalledWith(currentProfile.ID, newProfile); + expect(oc.Me.Update).toHaveBeenCalledWith(newProfile); }) }); @@ -67,7 +67,7 @@ describe('Component: Account', function() { expect(oc.Auth.GetToken).toHaveBeenCalledWith({Username:currentUser.Username, Password:currentUser.CurrentPassword}); scope.$digest(); currentUser.Password = currentUser.NewPassword; - expect(oc.AdminUsers.Update).toHaveBeenCalledWith(currentUser.ID, currentUser); + expect(oc.Me.Update).toHaveBeenCalledWith(currentUser); }) }); }); From 2f445c9d5a3eff8cd63cb86dac6bbda0d333004e Mon Sep 17 00:00:00 2001 From: Crhistian Date: Wed, 11 May 2016 10:24:29 -0500 Subject: [PATCH 112/367] Update app.config.json adding environment property for accelerators --- src/app/app.config.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/app.config.json b/src/app/app.config.json index 71604744..175ad45e 100644 --- a/src/app/app.config.json +++ b/src/app/app.config.json @@ -2,5 +2,6 @@ "appname": "XXXXX", "ocscope": "BuyerReader", "clientid": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX", - "buyerid": "XXXXX" + "buyerid": "XXXXX", + "environment": "prod" } From 60247dee5a2ffe244a1d4f6a65ddd65ad2401459 Mon Sep 17 00:00:00 2001 From: Aisha Ragheb Date: Wed, 11 May 2016 15:59:57 -0500 Subject: [PATCH 113/367] added to address inputs for OC-584-5 --- src/app/common/address/address.js | 8 ++++++-- src/app/common/address/templates/address.form.tpl.html | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/app/common/address/address.js b/src/app/common/address/address.js index 2e0f8309..4e91674b 100644 --- a/src/app/common/address/address.js +++ b/src/app/common/address/address.js @@ -6,14 +6,18 @@ angular.module('ordercloud-address', []) ; -function AddressFormDirective() { +function AddressFormDirective(OCGeography) { return { restrict: 'E', scope: { address: '=', isbilling: '=' }, - templateUrl: 'common/address/templates/address.form.tpl.html' + templateUrl: 'common/address/templates/address.form.tpl.html', + link: function(scope) { + scope.countries = OCGeography.countries; + scope.states = OCGeography.states; + } }; } diff --git a/src/app/common/address/templates/address.form.tpl.html b/src/app/common/address/templates/address.form.tpl.html index 4eeb9250..50e8b91b 100644 --- a/src/app/common/address/templates/address.form.tpl.html +++ b/src/app/common/address/templates/address.form.tpl.html @@ -34,7 +34,7 @@
- + + +
+ + + + + + + diff --git a/src/app/base/templates/base.left.tpl.html b/src/app/base/templates/base.left.tpl.html index c0f44046..c958d95c 100644 --- a/src/app/base/templates/base.left.tpl.html +++ b/src/app/base/templates/base.left.tpl.html @@ -1,4 +1,4 @@ -