├── app
├── styles
│ ├── menu
│ │ └── menu.scss
│ ├── _variables.scss
│ ├── views
│ │ └── home.scss
│ ├── layout
│ │ └── layout.scss
│ ├── main.scss
│ └── _fonts.scss
├── fonts
│ ├── Roboto-Bold.ttf
│ ├── Roboto-Light.ttf
│ └── Roboto-Thin.ttf
├── scripts
│ ├── controllers
│ │ ├── settingsController.js
│ │ ├── mainController.js
│ │ └── homeController.js
│ ├── utils
│ │ └── lodash.js
│ ├── config
│ │ └── apiEndpoint.js
│ ├── services
│ │ ├── ApiService.js
│ │ └── ExampleService.js
│ └── app.js
├── templates
│ ├── views
│ │ ├── home.html
│ │ └── settings.html
│ └── main.html
└── index.html
├── .bowerrc
├── resources
├── icon.png
└── splash.png
├── ionic.project
├── test
├── e2e
│ └── homepage.spec.js
└── unit
│ └── controllers
│ └── homeController.test.js
├── .gitignore
├── protractor.conf.js
├── vendor.json
├── bower.json
├── .jshintrc
├── hooks
├── before_platform_add
│ └── init_directories.js
├── after_plugin_rm
│ └── 010_deregister_plugin.js
├── after_platform_add
│ └── 010_install_plugins.js
├── after_prepare
│ ├── 020_remove_sass_from_platforms.js
│ └── 010_add_platform_class.js
├── after_plugin_add
│ └── 010_register_plugin.js
└── README.md
├── emulateios
├── package.json
├── karma.conf.js
├── config.xml
├── README.md
└── gulpfile.js
/app/styles/menu/menu.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.bowerrc:
--------------------------------------------------------------------------------
1 | {
2 | "directory": "bower_components"
3 | }
4 |
--------------------------------------------------------------------------------
/app/styles/_variables.scss:
--------------------------------------------------------------------------------
1 | /**
2 | * Define variables here
3 | */
4 |
5 | $textColor: #ccc;
--------------------------------------------------------------------------------
/app/styles/views/home.scss:
--------------------------------------------------------------------------------
1 | .header {
2 |
3 | }
4 |
5 | .content {
6 | padding: 1rem;
7 | }
--------------------------------------------------------------------------------
/resources/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tmaximini/ionic-gulp-seed/HEAD/resources/icon.png
--------------------------------------------------------------------------------
/ionic.project:
--------------------------------------------------------------------------------
1 | {
2 | "name": "IonicGulpSeed",
3 | "app_id": "de.thomasmaximini.ionicgulpseed"
4 | }
--------------------------------------------------------------------------------
/resources/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tmaximini/ionic-gulp-seed/HEAD/resources/splash.png
--------------------------------------------------------------------------------
/app/fonts/Roboto-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tmaximini/ionic-gulp-seed/HEAD/app/fonts/Roboto-Bold.ttf
--------------------------------------------------------------------------------
/app/fonts/Roboto-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tmaximini/ionic-gulp-seed/HEAD/app/fonts/Roboto-Light.ttf
--------------------------------------------------------------------------------
/app/fonts/Roboto-Thin.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tmaximini/ionic-gulp-seed/HEAD/app/fonts/Roboto-Thin.ttf
--------------------------------------------------------------------------------
/app/styles/layout/layout.scss:
--------------------------------------------------------------------------------
1 | .loader {
2 | text-align: center;
3 | width: 100%;
4 | padding: 20px 0;
5 | }
--------------------------------------------------------------------------------
/test/e2e/homepage.spec.js:
--------------------------------------------------------------------------------
1 | describe('HomePage', function(){
2 | it('can render the homepage', function(){
3 | browser.get('/');
4 | var headerElem = element(by.css('h1.title'));
5 |
6 | expect(headerElem).not.to.be.null;
7 |
8 | });
9 | });
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Specifies intentionally untracked files to ignore when using Git
2 | # http://git-scm.com/docs/gitignore
3 |
4 | node_modules/
5 | platforms/
6 | plugins/
7 | bower_components/
8 |
9 | .tmp/
10 | www/
11 | .sass-cache
12 | *.DS_Store
13 | *.log
14 | tmp.run.file
15 |
16 | coverage
17 |
--------------------------------------------------------------------------------
/app/scripts/controllers/settingsController.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @ngdoc function
5 | * @name IonicGulpSeed.controller:SettingsController
6 | * @description
7 | * # SettingsController
8 | */
9 | angular.module('IonicGulpSeed')
10 | .controller('SettingsController', function($scope) {
11 |
12 | // do something with $scope
13 |
14 | });
15 |
--------------------------------------------------------------------------------
/app/scripts/controllers/mainController.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @ngdoc function
5 | * @name IonicGulpSeed.controller:MainController
6 | * @description
7 | * # MainController
8 | * This controller handles the side menu
9 | */
10 | angular.module('IonicGulpSeed')
11 | .controller('MainController', function($scope) {
12 |
13 | // do something with $scope
14 |
15 | });
16 |
--------------------------------------------------------------------------------
/app/scripts/utils/lodash.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @ngdoc function
5 | * @name IonicGulpSeed.util:lodash
6 | * @description
7 | * # Lo-Dash
8 | * Expose Lo-Dash through injectable factory, so we don't pollute / rely on global namespace
9 | * just inject lodash as _
10 | */
11 |
12 | angular.module('IonicGulpSeed')
13 | .factory('_', function($window) {
14 | return $window._;
15 | });
--------------------------------------------------------------------------------
/protractor.conf.js:
--------------------------------------------------------------------------------
1 | exports.config = {
2 | framework: 'mocha',
3 |
4 | seleniumAddress: 'http://localhost:4444/wd/hub',
5 | baseUrl: 'http://localhost:9000',
6 |
7 | multiCapabilities: [{
8 | browserName: 'chrome'
9 | }],
10 |
11 | mochaOpts: {
12 | timeout: 4000
13 | },
14 |
15 | onPrepare: function(){
16 | global.expect = require('chai').expect;
17 | }
18 | }
--------------------------------------------------------------------------------
/app/styles/main.scss:
--------------------------------------------------------------------------------
1 | /************************************
2 | *
3 | * Main Styles to compile. Here only @imports!
4 | *
5 | ************************************/
6 |
7 | @import "_variables";
8 | @import "_fonts";
9 |
10 | /**
11 | * LAYOUT
12 | */
13 |
14 | @import "layout/layout";
15 |
16 |
17 | /**
18 | * MENU
19 | */
20 |
21 | @import "menu/menu";
22 |
23 | /**
24 | * VIEWS
25 | */
26 |
27 | @import "views/home";
--------------------------------------------------------------------------------
/vendor.json:
--------------------------------------------------------------------------------
1 | [
2 | "bower_components/angular/angular.js",
3 | "bower_components/angular-resource/angular-resource.js",
4 | "bower_components/angular-animate/angular-animate.js",
5 | "bower_components/angular-sanitize/angular-sanitize.js",
6 | "bower_components/angular-ui-router/release/angular-ui-router.js",
7 | "bower_components/ionic/js/ionic.js",
8 | "bower_components/ionic/js/ionic-angular.js",
9 | "bower_components/lodash/lodash.js",
10 | "bower_components/ngCordova/dist/ng-cordova.js"
11 | ]
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "IonicGulpSeed",
3 | "private": "true",
4 | "devDependencies": {
5 | "ionic": "driftyco/ionic-bower#1.0.0-rc.1",
6 | "angular": "~1.3.11",
7 | "angular-mocks": "~1.4.7"
8 | },
9 | "dependencies": {
10 | "ngCordova": "~0.1.12-alpha",
11 | "angular-resource": "1.3.13",
12 | "lodash": "~3.0.1",
13 | "angular-animate": "1.3.13"
14 | },
15 | "resolutions": {
16 | "angular-animate": "1.3.13",
17 | "angular-sanitize": "1.3.13",
18 | "angular": "1.3.13"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "node": true,
3 | "browser": true,
4 | "esnext": true,
5 | "bitwise": true,
6 | "camelcase": true,
7 | "curly": true,
8 | "eqeqeq": true,
9 | "immed": true,
10 | "indent": false,
11 | "latedef": true,
12 | "newcap": true,
13 | "noarg": true,
14 | "quotmark": "single",
15 | "regexp": true,
16 | "undef": true,
17 | "unused": true,
18 | "strict": true,
19 | "trailing": true,
20 | "smarttabs": true,
21 | "globals": {
22 | "angular": false,
23 | "cordova": false,
24 | "StatusBar": false
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/templates/views/home.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Gulp Ionic Seed
5 |
6 |
7 |
8 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/hooks/before_platform_add/init_directories.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | /**
4 | * On a fresh clone, the local platforms/ and plugins/ directories will be
5 | * missing, so ensure they get created before the first platform is added.
6 | */
7 | var fs = require('fs');
8 | var path = require('path');
9 |
10 | var platformsDir = path.resolve(__dirname, '../../platforms');
11 | var pluginsDir = path.resolve(__dirname, '../../plugins');
12 |
13 | try {
14 | fs.mkdirSync(platformsDir, function (err) {
15 | if (err) { console.error(err); }
16 | });
17 | } catch(ex) {}
18 |
19 | try {
20 | fs.mkdirSync(pluginsDir, function (err) {
21 | if (err) { console.error(err); }
22 | });
23 | } catch(ex) {}
24 |
--------------------------------------------------------------------------------
/app/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | IonicGulpSeed
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/emulateios:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | export DEVICES=`ios-sim showdevicetypes 2>&1`
3 | export DEVICES=\"`echo $DEVICES | sed -e 's/ com./" "com./g' | sed -e 's/, /,~/g'`\"
4 | PS3='Please enter your choice: '
5 | options=($DEVICES)
6 | curpath="$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
7 | app="`find $curpath/platforms/ios/build/emulator -name *.app -print`"
8 | escaped_app="\"$app\""
9 |
10 | echo $app
11 | select opt in "${options[@]}"
12 | do
13 | case $opt in
14 | *) echo ios-sim launch "$escaped_app" --devicetypeid "`echo $opt | sed -e "s/~/ /g"`" --stderr ./platforms/ios/cordova/console.log --stdout ./platforms/ios/cordova/console.log > tmp.run.file;chmod +x tmp.run.file;./tmp.run.file;rm tmp.run.file;exit;
15 | esac
16 | done
17 |
--------------------------------------------------------------------------------
/test/unit/controllers/homeController.test.js:
--------------------------------------------------------------------------------
1 | describe('HomeController', function(){
2 | var controller, scope, ExampleService;
3 |
4 | beforeEach(module('IonicGulpSeed'));
5 | beforeEach(module('AppTemplate'));
6 |
7 | beforeEach(inject(function($rootScope, _$controller_, _ExampleService_){
8 | scope = $rootScope.$new();
9 | controller = _$controller_('HomeController', {
10 | $scope: scope,
11 | ExampleService: _ExampleService_
12 | });
13 | ExampleService = _ExampleService_;
14 |
15 | sinon.stub(ExampleService, 'doSomethingAsync', ExampleService.doSomethingAsync);
16 | }));
17 |
18 | it('calls the method doSomethingAsync()', function(){
19 | scope.fetchRandomText();
20 | expect(ExampleService.doSomethingAsync.called).to.eq(true);
21 |
22 | });
23 |
24 | });
--------------------------------------------------------------------------------
/app/styles/_fonts.scss:
--------------------------------------------------------------------------------
1 | /**
2 | * Import fonts either via @import url (e.g. from Googlee Fonts)
3 | * or via @font-face when font files are stored locally in /app/fonts
4 | */
5 |
6 |
7 | // @import url(http://fonts.googleapis.com/css?family=Roboto:700,400,300);
8 |
9 | @font-face {
10 | font-family: 'Roboto';
11 | src: url(../fonts/Roboto-Light.ttf) format("truetype");
12 | font-weight: 300;
13 | font-style: normal;
14 | }
15 |
16 | @font-face {
17 | font-family: 'Roboto';
18 | src: url(../fonts/Roboto-Regular.ttf) format("truetype");
19 | font-weight: 400;
20 | font-style: normal;
21 | }
22 |
23 | @font-face {
24 | font-family: 'Roboto';
25 | src: url(../fonts/Roboto-Bold.ttf) format("truetype");
26 | font-weight: 700;
27 | font-style: normal;
28 | }
--------------------------------------------------------------------------------
/app/scripts/controllers/homeController.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @ngdoc function
5 | * @name IonicGulpSeed.controller:HomeController
6 | * @description
7 | * # HomeController
8 | */
9 | angular.module('IonicGulpSeed')
10 | .controller('HomeController', function($scope, ExampleService) {
11 |
12 | $scope.myHTML = null;
13 |
14 | $scope.fetchRandomText = function() {
15 | ExampleService.doSomethingAsync()
16 | .then(ExampleService.fetchSomethingFromServer)
17 | .then(function(response) {
18 | $scope.myHTML = response.data.text;
19 | // close pull to refresh loader
20 | $scope.$broadcast('scroll.refreshComplete');
21 | });
22 | };
23 |
24 | $scope.fetchRandomText();
25 | });
26 |
--------------------------------------------------------------------------------
/app/templates/views/settings.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Settings
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | Allow Push Notifications
15 |
16 |
17 |
18 |
19 |
20 | Allow cookies
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/scripts/config/apiEndpoint.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @ngdoc constant
5 | * @name IonicGulpSeed.API_ENDPOINT
6 | * @description
7 | * # API_ENDPOINT
8 | * Defines the API endpoint where our resources will make requests against.
9 | * Is used inside /services/ApiService.js to generate correct endpoint dynamically
10 | */
11 |
12 |
13 | angular.module('IonicGulpSeed')
14 |
15 | // development
16 | .constant('API_ENDPOINT', {
17 | host: 'http://localhost',
18 | port: 3000,
19 | path: '',
20 | needsAuth: false
21 | });
22 |
23 |
24 | // live example with HTTP Basic Auth
25 | /*
26 | .constant('API_ENDPOINT', {
27 | host: 'http://myserver.com',
28 | path: '/api/v2',
29 | needsAuth: true,
30 | username: 'whatever',
31 | password: 'foobar'
32 | });
33 | */
34 |
35 |
--------------------------------------------------------------------------------
/hooks/after_plugin_rm/010_deregister_plugin.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | /**
4 | * Remove plugins from cordovaPlugins array after_plugin_rm
5 | */
6 | var fs = require('fs');
7 | var packageJSON = require('../../package.json');
8 |
9 | packageJSON.cordovaPlugins = packageJSON.cordovaPlugins || [];
10 |
11 | process.env.CORDOVA_PLUGINS.split(',').forEach(function (plugin) {
12 | var index = packageJSON.cordovaPlugins.indexOf(plugin);
13 | if (index > -1) {
14 | packageJSON.cordovaPlugins.splice(index, 1);
15 | } else {
16 | //If it didnt find a match, it may be listed as {id,locator}
17 | for(var i = 0, j = packageJSON.cordovaPlugins.length; i < j; i++) {
18 | var packagePlugin = packageJSON.cordovaPlugins[i];
19 | if(typeof packagePlugin == 'object' && packagePlugin.id == plugin) {
20 | packageJSON.cordovaPlugins.splice(index, 1);
21 | break;
22 | }
23 | }
24 | }
25 | });
26 |
27 | fs.writeFile('package.json', JSON.stringify(packageJSON, null, 2));
28 |
--------------------------------------------------------------------------------
/app/templates/main.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
30 |
31 |
--------------------------------------------------------------------------------
/hooks/after_platform_add/010_install_plugins.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | /**
4 | * Install all plugins listed in package.json
5 | * https://raw.githubusercontent.com/diegonetto/generator-ionic/master/templates/hooks/after_platform_add/install_plugins.js
6 | */
7 | var exec = require('child_process').exec;
8 | var path = require('path');
9 | var sys = require('sys');
10 |
11 | var packageJSON = null;
12 |
13 | try {
14 | packageJSON = require('../../package.json');
15 | } catch(ex) {
16 | console.log('\nThere was an error fetching your package.json file.')
17 | console.log('\nPlease ensure a valid package.json is in the root of this project\n')
18 | return;
19 | }
20 |
21 | var cmd = process.platform === 'win32' ? 'cordova.cmd' : 'cordova';
22 | // var script = path.resolve(__dirname, '../../node_modules/cordova/bin', cmd);
23 |
24 | packageJSON.cordovaPlugins = packageJSON.cordovaPlugins || [];
25 | packageJSON.cordovaPlugins.forEach(function (plugin) {
26 | exec('cordova plugin add ' + plugin, function (error, stdout, stderr) {
27 | sys.puts(stdout);
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/hooks/after_prepare/020_remove_sass_from_platforms.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | /**
4 | * After prepare, files are copied to the platforms/ios and platforms/android folders.
5 | * Lets clean up some of those files that arent needed with this hook.
6 | */
7 | var fs = require('fs');
8 | var path = require('path');
9 |
10 | var deleteFolderRecursive = function(removePath) {
11 | if( fs.existsSync(removePath) ) {
12 | fs.readdirSync(removePath).forEach(function(file,index){
13 | var curPath = path.join(removePath, file);
14 | if(fs.lstatSync(curPath).isDirectory()) { // recurse
15 | deleteFolderRecursive(curPath);
16 | } else { // delete file
17 | fs.unlinkSync(curPath);
18 | }
19 | });
20 | fs.rmdirSync(removePath);
21 | }
22 | };
23 |
24 | var iosPlatformsDir = path.resolve(__dirname, '../../platforms/ios/www/lib/ionic/scss');
25 | var androidPlatformsDir = path.resolve(__dirname, '../../platforms/android/assets/www/lib/ionic/scss');
26 |
27 | deleteFolderRecursive(iosPlatformsDir);
28 | deleteFolderRecursive(androidPlatformsDir);
29 |
--------------------------------------------------------------------------------
/app/scripts/services/ApiService.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @ngdoc service
5 | * @name IonicGulpSeed.ApiService
6 | * @description
7 | * # ApiService
8 | * Retrieves correct api to make requests against.
9 | * Uses settings from API_ENDPOINT defined in /config/apiEndpoint.js
10 | *
11 | * Usage example: $http({
12 | * url: ApiService.getEndPoint() + '/things',
13 | * method: 'GET'
14 | * })
15 | *
16 | */
17 | angular.module('IonicGulpSeed')
18 | .factory('ApiService', function($window, $http, API_ENDPOINT) {
19 |
20 | var _api = API_ENDPOINT;
21 | var endpoint = _api.port ? (_api.host + ':' + _api.port + _api.path) : (_api.host + _api.path);
22 |
23 | // activate for basic auth
24 | if (_api.needsAuth) {
25 | $http.defaults.headers.common.Authorization = 'Basic ' + $window.btoa(_api.username + ':' + _api.password);
26 | }
27 |
28 | // public api
29 | return {
30 | getEndpoint: function() { return endpoint; }
31 | };
32 |
33 | });
34 |
35 |
--------------------------------------------------------------------------------
/app/scripts/services/ExampleService.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @ngdoc function
5 | * @name IonicGulpSeed.serive:ExampleService
6 | * @description
7 | * # ExampleService
8 | */
9 | angular.module('IonicGulpSeed')
10 | // use factory for services
11 | .factory('ExampleService', function($http, $timeout, $q) {
12 |
13 | var kindOfPrivateVariable = 42;
14 |
15 | var doSomethingAsync = function() {
16 | var deferred = $q.defer();
17 | $timeout(deferred.resolve.bind(null, kindOfPrivateVariable), 1000);
18 | return deferred.promise;
19 | };
20 |
21 | var fetchSomethingFromServer = function() {
22 | return $http({
23 | url: 'http://hipsterjesus.com/api',
24 | params: {
25 | paras: 2
26 | },
27 | method: 'GET'
28 | })
29 | .success(function(data) {
30 | console.log('fetched this stuff from server:', data);
31 | })
32 | .error(function(error) {
33 | console.log('an error occured', error);
34 | });
35 | };
36 |
37 | // public api
38 | return {
39 | doSomethingAsync: doSomethingAsync,
40 | fetchSomethingFromServer: fetchSomethingFromServer
41 | };
42 |
43 | });
44 |
--------------------------------------------------------------------------------
/app/scripts/app.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @ngdoc overview
5 | * @name IonicGulpSeed
6 | * @description
7 | * # Initializes main application and routing
8 | *
9 | * Main module of the application.
10 | */
11 |
12 |
13 | angular.module('IonicGulpSeed', ['ionic', 'ngCordova', 'ngResource', 'ngSanitize'])
14 |
15 | .run(function($ionicPlatform) {
16 |
17 | $ionicPlatform.ready(function() {
18 | // save to use plugins here
19 | });
20 |
21 | // add possible global event handlers here
22 |
23 | })
24 |
25 | .config(function($httpProvider, $stateProvider, $urlRouterProvider) {
26 | // register $http interceptors, if any. e.g.
27 | // $httpProvider.interceptors.push('interceptor-name');
28 |
29 | // Application routing
30 | $stateProvider
31 | .state('app', {
32 | url: '/app',
33 | abstract: true,
34 | templateUrl: 'templates/main.html',
35 | controller: 'MainController'
36 | })
37 | .state('app.home', {
38 | url: '/home',
39 | cache: true,
40 | views: {
41 | 'viewContent': {
42 | templateUrl: 'templates/views/home.html',
43 | controller: 'HomeController'
44 | }
45 | }
46 | })
47 | .state('app.settings', {
48 | url: '/settings',
49 | cache: true,
50 | views: {
51 | 'viewContent': {
52 | templateUrl: 'templates/views/settings.html',
53 | controller: 'SettingsController'
54 | }
55 | }
56 | });
57 |
58 |
59 | // redirects to default route for undefined routes
60 | $urlRouterProvider.otherwise('/app/home');
61 | });
62 |
63 |
64 |
--------------------------------------------------------------------------------
/hooks/after_plugin_add/010_register_plugin.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | /**
4 | * Push plugins to cordovaPlugins array after_plugin_add
5 | */
6 | var fs = require('fs'),
7 | packageJSON = require('../../package.json'),
8 | path = require('path');
9 |
10 | packageJSON.cordovaPlugins = packageJSON.cordovaPlugins || [];
11 | process.env.CORDOVA_PLUGINS.split(',').forEach(function (plugin) {
12 | var configString,
13 | idRegEx,
14 | id,
15 | pluginXmlPath,
16 | pluginToAdd;
17 |
18 | if(plugin.indexOf('https') != -1 || plugin.indexOf('git') != -1) {
19 | console.log('Installing plugin from url');
20 | }
21 |
22 | if(plugin.indexOf('/') != -1) {
23 | try {
24 | pluginXmlPath = path.resolve(plugin, 'plugin.xml');
25 | console.log('got pluginXmlPath:', pluginXmlPath);
26 | if (!fs.existsSync(pluginXmlPath)) {
27 | var errorMessage = ['There was no plugin.xml file found for path: ', pluginXmlPath].join('');
28 | return;
29 | }
30 |
31 | configString = fs.readFileSync(pluginXmlPath,{encoding: 'utf8'});
32 | idRegEx = new RegExp(']*id="(.*)"', 'i');
33 | id = idRegEx.exec(configString)[1]
34 | pluginToAdd = {id: id, locator: plugin};
35 | } catch(ex) {
36 | console.log('There was an error retrieving the plugin.xml filr from the 010_register_plugin.js hook', ex);
37 | }
38 | } else {
39 | pluginToAdd = plugin;
40 | }
41 |
42 | if(typeof pluginToAdd == 'string' && packageJSON.cordovaPlugins.indexOf(pluginToAdd) == -1) {
43 | packageJSON.cordovaPlugins.push(pluginToAdd);
44 | } else if (typeof pluginToAdd == 'object') {
45 | var pluginExists = false;
46 | packageJSON.cordovaPlugins.forEach(function(checkPlugin) {
47 | if(typeof checkPlugin == 'object' && checkPlugin.id == pluginToAdd.id) {
48 | pluginExists = true;
49 | }
50 | })
51 | if(!pluginExists) {
52 | packageJSON.cordovaPlugins.push(pluginToAdd);
53 | }
54 | }
55 | });
56 |
57 | fs.writeFileSync('package.json', JSON.stringify(packageJSON, null, 2));
58 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ionicgulpseed",
3 | "version": "1.2.1",
4 | "description": "A blank seed project for rapid development of Ionic projects through gulp workflows",
5 | "author": "Thomas Maximini ",
6 | "dependencies": {
7 | "bluebird": "^3.0.5"
8 | },
9 | "devDependencies": {
10 | "beepbeep": "^1.2.0",
11 | "bower": "^1.3.3",
12 | "chai": "^3.4.1",
13 | "connect-livereload": "^0.5.2",
14 | "del": "^1.1.1",
15 | "express": "^4.11.1",
16 | "glob": "^4.3.5",
17 | "gulp": "^3.8.10",
18 | "gulp-angular-templatecache": "^1.5.0",
19 | "gulp-autoprefixer": "^2.1.0",
20 | "gulp-cached": "^1.1.0",
21 | "gulp-changed": "^1.2.1",
22 | "gulp-concat": "^2.4.3",
23 | "gulp-iconfont": "^1.0.0",
24 | "gulp-iconfont-css": "0.0.9",
25 | "gulp-if": "^1.2.5",
26 | "gulp-inject": "^1.1.1",
27 | "gulp-jshint": "^1.9.0",
28 | "gulp-livereload": "^3.7.0",
29 | "gulp-load-plugins": "^0.8.0",
30 | "gulp-ng-annotate": "^0.5.0",
31 | "gulp-protractor": "^1.0.0",
32 | "gulp-remember": "^0.3.0",
33 | "gulp-rev": "^3.0.0",
34 | "gulp-sass": "^2.0.1",
35 | "gulp-shell": "^0.2.11",
36 | "gulp-strip-css-comments": "^1.1.0",
37 | "gulp-strip-debug": "^1.0.2",
38 | "gulp-uglify": "^1.1.0",
39 | "gulp-util": "^2.2.14",
40 | "jshint-stylish": "^1.0.0",
41 | "karma": "^0.13.15",
42 | "karma-chai": "^0.1.0",
43 | "karma-chrome-launcher": "^0.2.1",
44 | "karma-coverage": "^0.5.3",
45 | "karma-firefox-launcher": "^0.1.7",
46 | "karma-mocha": "^0.2.1",
47 | "karma-ng-html2js-preprocessor": "^0.2.0",
48 | "karma-sinon": "^1.0.4",
49 | "lodash": "^3.0.0",
50 | "merge-stream": "^0.1.7",
51 | "mocha": "^2.3.3",
52 | "open": "0.0.5",
53 | "protractor": "^2.5.1",
54 | "ripple-emulator": "^0.9.28",
55 | "run-sequence": "^1.0.2",
56 | "shelljs": "^0.3.0",
57 | "sinon": "^1.17.2",
58 | "streamqueue": "^0.1.1",
59 | "yargs": "^1.3.3"
60 | },
61 | "scripts": {
62 | "gulp": "./node_modules/.bin/gulp"
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration
2 | // Generated on Sat Nov 14 2015 22:37:58 GMT+1100 (AEDT)
3 |
4 |
5 | var _ = require('lodash');
6 |
7 |
8 | /**
9 | * This function returns a list of js/html files
10 | * to be loaded to karma runner
11 | */
12 | function filesArray(){
13 |
14 | var vendorJsFiles = require('./vendor.json');
15 |
16 | var mockJsFiles = [
17 | 'bower_components/angular-mocks/angular-mocks.js'
18 | ];
19 |
20 | var appJsFiles = [
21 | 'app/scripts/**/*.js',
22 | 'test/unit/**/*.js'
23 | ];
24 |
25 | var htmlFiles = ['app/templates/**/*.html'];
26 |
27 | return _.union(vendorJsFiles, mockJsFiles, appJsFiles, htmlFiles);
28 | }
29 |
30 | module.exports = function(config) {
31 | config.set({
32 |
33 | // base path that will be used to resolve all patterns (eg. files, exclude)
34 | basePath: '',
35 |
36 | // frameworks to use
37 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
38 | frameworks: ['mocha', 'chai', 'sinon'],
39 |
40 |
41 | // list of files / patterns to load in the browser
42 | files: filesArray(),
43 |
44 |
45 | // list of files to exclude
46 | exclude: [
47 | ],
48 |
49 | // preprocess matching files before serving them to the browser
50 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
51 | preprocessors: {
52 | 'app/scripts/**/*.js': ['coverage'],
53 | 'app/templates/**/*.html': ['ng-html2js']
54 | },
55 |
56 | // settings for ng-html2js preprocessor
57 | ngHtml2JsPreprocessor: {
58 | stripPrefix: 'app/',
59 | moduleName: 'AppTemplate'
60 | },
61 |
62 | // settings for coverage plugin
63 | coverageReporter: {
64 | type: 'html',
65 | dir: 'coverage/'
66 | },
67 |
68 | // test results reporter to use
69 | // possible values: 'dots', 'progress'
70 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter
71 | reporters: ['progress', 'coverage'],
72 |
73 |
74 | // web server port
75 | port: 9876,
76 |
77 |
78 | // enable / disable colors in the output (reporters and logs)
79 | colors: true,
80 |
81 |
82 | // level of logging
83 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
84 | logLevel: config.LOG_INFO,
85 |
86 |
87 | // enable / disable watching file and executing tests whenever any file changes
88 | autoWatch: true,
89 |
90 |
91 | // start these browsers
92 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
93 | browsers: ['Chrome', 'Firefox'],
94 |
95 | // Continuous Integration mode
96 | // if true, Karma captures browsers, runs the tests and exits
97 | singleRun: false,
98 |
99 | // Concurrency level
100 | // how many browser should be started simultanous
101 | concurrency: Infinity
102 | })
103 | }
104 |
--------------------------------------------------------------------------------
/config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | IonicGulpSeed
4 |
5 | A blank seed project for rapid development of Ionic projects through gulp workflows
6 |
7 |
8 | Thomas Maximini
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/hooks/after_prepare/010_add_platform_class.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | // Add Platform Class
4 | // v1.0
5 | // Automatically adds the platform class to the body tag
6 | // after the `prepare` command. By placing the platform CSS classes
7 | // directly in the HTML built for the platform, it speeds up
8 | // rendering the correct layout/style for the specific platform
9 | // instead of waiting for the JS to figure out the correct classes.
10 |
11 | var fs = require('fs');
12 | var path = require('path');
13 |
14 | var rootdir = process.argv[2];
15 |
16 | function addPlatformBodyTag(indexPath, platform) {
17 | // add the platform class to the body tag
18 | try {
19 | var platformClass = 'platform-' + platform;
20 | var cordovaClass = 'platform-cordova platform-webview';
21 |
22 | var html = fs.readFileSync(indexPath, 'utf8');
23 |
24 | var bodyTag = findBodyTag(html);
25 | if(!bodyTag) return; // no opening body tag, something's wrong
26 |
27 | if(bodyTag.indexOf(platformClass) > -1) return; // already added
28 |
29 | var newBodyTag = bodyTag;
30 |
31 | var classAttr = findClassAttr(bodyTag);
32 | if(classAttr) {
33 | // body tag has existing class attribute, add the classname
34 | var endingQuote = classAttr.substring(classAttr.length-1);
35 | var newClassAttr = classAttr.substring(0, classAttr.length-1);
36 | newClassAttr += ' ' + platformClass + ' ' + cordovaClass + endingQuote;
37 | newBodyTag = bodyTag.replace(classAttr, newClassAttr);
38 |
39 | } else {
40 | // add class attribute to the body tag
41 | newBodyTag = bodyTag.replace('>', ' class="' + platformClass + ' ' + cordovaClass + '">');
42 | }
43 |
44 | html = html.replace(bodyTag, newBodyTag);
45 |
46 | fs.writeFileSync(indexPath, html, 'utf8');
47 |
48 | process.stdout.write('add to body class: ' + platformClass + '\n');
49 | } catch(e) {
50 | process.stdout.write(e);
51 | }
52 | }
53 |
54 | function findBodyTag(html) {
55 | // get the body tag
56 | try{
57 | return html.match(/])(.*?)>/gi)[0];
58 | }catch(e){}
59 | }
60 |
61 | function findClassAttr(bodyTag) {
62 | // get the body tag's class attribute
63 | try{
64 | return bodyTag.match(/ class=["|'](.*?)["|']/gi)[0];
65 | }catch(e){}
66 | }
67 |
68 | if (rootdir) {
69 |
70 | // go through each of the platform directories that have been prepared
71 | var platforms = (process.env.CORDOVA_PLATFORMS ? process.env.CORDOVA_PLATFORMS.split(',') : []);
72 |
73 | for(var x=0; x
21 | # Cordova Hooks
22 |
23 | This directory may contain scripts used to customize cordova commands. This
24 | directory used to exist at `.cordova/hooks`, but has now been moved to the
25 | project root. Any scripts you add to these directories will be executed before
26 | and after the commands corresponding to the directory name. Useful for
27 | integrating your own build systems or integrating with version control systems.
28 |
29 | __Remember__: Make your scripts executable.
30 |
31 | ## Hook Directories
32 | The following subdirectories will be used for hooks:
33 |
34 | after_build/
35 | after_compile/
36 | after_docs/
37 | after_emulate/
38 | after_platform_add/
39 | after_platform_rm/
40 | after_platform_ls/
41 | after_plugin_add/
42 | after_plugin_ls/
43 | after_plugin_rm/
44 | after_plugin_search/
45 | after_prepare/
46 | after_run/
47 | after_serve/
48 | before_build/
49 | before_compile/
50 | before_docs/
51 | before_emulate/
52 | before_platform_add/
53 | before_platform_rm/
54 | before_platform_ls/
55 | before_plugin_add/
56 | before_plugin_ls/
57 | before_plugin_rm/
58 | before_plugin_search/
59 | before_prepare/
60 | before_run/
61 | before_serve/
62 | pre_package/ <-- Windows 8 and Windows Phone only.
63 |
64 | ## Script Interface
65 |
66 | All scripts are run from the project's root directory and have the root directory passes as the first argument. All other options are passed to the script using environment variables:
67 |
68 | * CORDOVA_VERSION - The version of the Cordova-CLI.
69 | * CORDOVA_PLATFORMS - Comma separated list of platforms that the command applies to (e.g.: android, ios).
70 | * CORDOVA_PLUGINS - Comma separated list of plugin IDs that the command applies to (e.g.: org.apache.cordova.file, org.apache.cordova.file-transfer)
71 | * CORDOVA_HOOK - Path to the hook that is being executed.
72 | * CORDOVA_CMDLINE - The exact command-line arguments passed to cordova (e.g.: cordova run ios --emulate)
73 |
74 | If a script returns a non-zero exit code, then the parent cordova command will be aborted.
75 |
76 |
77 | ## Writing hooks
78 |
79 | We highly recommend writting your hooks using Node.js so that they are
80 | cross-platform. Some good examples are shown here:
81 |
82 | [http://devgirl.org/2013/11/12/three-hooks-your-cordovaphonegap-project-needs/](http://devgirl.org/2013/11/12/three-hooks-your-cordovaphonegap-project-needs/)
83 |
84 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Ionic Gulp Seed
2 | ### An ionic starter project with a gulp toolchain
3 |
4 | Heads-up: There is now also a [Yeoman Generator](https://github.com/tmaximini/generator-ionic-gulp) available for this seed.
5 |
6 | ## Features
7 |
8 | * Gulp jobs for development, building, unit testing, emulating and running your app
9 | * Compiles and concatenates your Sass
10 | * Local development server with live reload, even inside ios emulator
11 | * Automatically inject all your JS sources into `index.html`
12 | * Auto min-safe all Angular DI through `ng-annotate`, no need to use weird bracket notation
13 | * Comes already with [ng-cordova](http://ngcordova.com/) and [lodash](https://lodash.com)
14 | * generate icon font from svg files
15 | * Blazing fast
16 | * E2E(End-to-End) testing with Protractor
17 |
18 | ## Commands
19 |
20 | | gulp command | shortcut | what it does |
21 | |-----------------------------|----------------------|------------------------------------------------------------------------------------------------|
22 | | `gulp` | — | run local development server, start watchers, auto reload browser on change, targetfolder /tmp |
23 | | `gulp --build` | `gulp -b` | create a build from current `/app` folder, minify assets, targetfolder `/www` |
24 | | `gulp --emulate ` | `gulp -e ` | run a build first, then ionic emulate . defaults to ios |
25 | | `gulp --run ` | `gulp -r ` | run a build first, then ionic run . defaults to ios |
26 | | `gulp test-unit` | none | run all the test cases under `test/unit` folder using Karma runner |
27 | | `gulp test-e2e` | none | run all the test cases under `test/e2e` folder using Protractor |
28 |
29 | ## Installation
30 |
31 | I recommend using the available [Yeoman Generator](https://github.com/tmaximini/generator-ionic-gulp).
32 |
33 | ```bash
34 | npm install -g yo generator-ionic-gulp
35 | yo ionic-gulp
36 | ```
37 |
38 | OR you can clone the repo manually:
39 |
40 | 1. Clone this project `git clone https://github.com/tmaximini/ionic-gulp-seed.git `
41 | 2. Change remote to your repo `git remote set-url origin https://github.com//.git`
42 | 3. run `npm install` and `bower install` to install dependencies
43 |
44 |
45 | ## Structure
46 |
47 | The source code lives inside the `app` folder.
48 |
49 | | Source Files | Location |
50 | | ------------- | ------------- |
51 | | Javascript | `app/scripts` |
52 | | Styles (scss) | `app/styles` |
53 | | Templates | `app/templates` |
54 | | Images | `app/images` |
55 | | Fonts | `app/fonts` |
56 | | Icons | `app/icons` |
57 |
58 | A lot of starter kits and tutorials encourage you to work directly inside the `www` folder, but I chose `app` instead, as it conforms better with most Angular.js projects. Note that `www` is gitignored and will be created dynamically during our build process.
59 |
60 | All 3rd party Javascript sources have to be manually added into `.vendor.json` and will be concatenated into a single `vendor.js` file.
61 | I know there is [wiredep](https://github.com/taptapship/wiredep) but I prefer to explicitly control which files get injected and also wiredep ends up adding lots of `