Repository: poetic/ember-cli-cordova Branch: master Commit: c78241c56602 Files: 125 Total size: 96.2 KB Directory structure: gitextract_1pswgu92/ ├── .bowerrc ├── .editorconfig ├── .ember-cli ├── .gitignore ├── .hound.yml ├── .jshintrc ├── .npmignore ├── .travis.yml ├── .watchmanconfig ├── LICENSE ├── README.md ├── addon/ │ ├── initializers/ │ │ └── in-app-livereload.js │ ├── mixins/ │ │ ├── controllers/ │ │ │ └── nav-bar.js │ │ ├── cordova-events.js │ │ └── routes/ │ │ └── nav-bar.js │ ├── services/ │ │ └── cordova.js │ └── utils/ │ └── redirect.js ├── app/ │ ├── components/ │ │ └── cdv-nav-bar.js │ ├── initializers/ │ │ └── in-app-livereload.js │ ├── services/ │ │ └── cordova.js │ └── templates/ │ ├── cdv-generic-nav-bar.hbs │ └── components/ │ └── cdv-nav-bar.hbs ├── blueprints/ │ ├── cordova-init/ │ │ ├── files/ │ │ │ ├── config/ │ │ │ │ └── environment.js │ │ │ └── gitignore │ │ └── index.js │ └── cordova-starter-kit/ │ ├── files/ │ │ ├── app/ │ │ │ ├── adapters/ │ │ │ │ └── application.js │ │ │ ├── routes/ │ │ │ │ └── application.js │ │ │ ├── styles/ │ │ │ │ └── app.scss │ │ │ ├── templates/ │ │ │ │ └── application.hbs │ │ │ └── transitions.js │ │ └── config/ │ │ └── environment.js │ └── index.js ├── bower.json ├── docs/ │ ├── commands.md │ ├── configuration.md │ ├── events.md │ ├── faq.md │ ├── getting-started.md │ └── nav-bar.md ├── ember-cli-build.js ├── index.js ├── lib/ │ ├── commands/ │ │ ├── archive.js │ │ ├── build.js │ │ ├── cordova.js │ │ ├── index.js │ │ ├── open.js │ │ └── prepare.js │ ├── ext/ │ │ └── promise.js │ ├── models/ │ │ └── project-with-config.js │ ├── tasks/ │ │ ├── add-platforms.js │ │ ├── archive.js │ │ ├── build.js │ │ ├── cordova.js │ │ ├── create-cordova-project.js │ │ ├── link-environment.js │ │ ├── modify-xml.js │ │ ├── open.js │ │ ├── post-build.js │ │ ├── update-config-xml-android-version-code.js │ │ ├── update-config-xml-version.js │ │ ├── update-config-xml.js │ │ └── verify-dist.js │ ├── ui/ │ │ └── index.js │ └── utils/ │ ├── default-platform.js │ ├── open.js │ ├── run-command.js │ └── string.js ├── node-tests/ │ ├── fixtures/ │ │ └── project/ │ │ ├── .ember-cdv │ │ └── cordova/ │ │ └── config.xml │ ├── helpers/ │ │ ├── _helper.js │ │ ├── mocks.js │ │ ├── noop.js │ │ └── stub.js │ └── unit/ │ ├── addon-test.js │ ├── models/ │ │ └── project-with-config-test.js │ └── tasks/ │ ├── add-platforms-test.js │ ├── archive-test.js │ ├── build-test.js │ ├── cordova-test.js │ ├── create-cordova-project-test.js │ ├── link-environment-test.js │ ├── open-test.js │ ├── post-build-test.js │ ├── update-config-xml-test.js │ ├── update-config-xml-version-test.js │ └── verify-dist-test.js ├── package.json ├── public/ │ ├── .gitkeep │ └── inject-cordova.js ├── testem.json └── tests/ ├── .jshintrc ├── dummy/ │ ├── .jshintrc │ ├── app/ │ │ ├── app.js │ │ ├── components/ │ │ │ └── .gitkeep │ │ ├── controllers/ │ │ │ ├── .gitkeep │ │ │ └── nav-bar.js │ │ ├── helpers/ │ │ │ └── .gitkeep │ │ ├── index.html │ │ ├── models/ │ │ │ └── .gitkeep │ │ ├── resolver.js │ │ ├── router.js │ │ ├── routes/ │ │ │ ├── .gitkeep │ │ │ └── nav-bar/ │ │ │ ├── index.js │ │ │ ├── options-from-model.js │ │ │ └── page-1.js │ │ ├── styles/ │ │ │ ├── .gitkeep │ │ │ └── app.css │ │ ├── templates/ │ │ │ ├── .gitkeep │ │ │ ├── application.hbs │ │ │ ├── components/ │ │ │ │ └── .gitkeep │ │ │ └── nav-bar.hbs │ │ └── views/ │ │ └── .gitkeep │ ├── config/ │ │ └── environment.js │ └── public/ │ ├── .gitkeep │ ├── crossdomain.xml │ └── robots.txt ├── helpers/ │ ├── describe-app.js │ ├── destroy-app.js │ ├── module-for-acceptance.js │ ├── resolver.js │ └── start-app.js ├── index.html ├── integration/ │ └── nav-bar-test.js ├── test-helper.js └── unit/ └── .gitkeep ================================================ FILE CONTENTS ================================================ ================================================ FILE: .bowerrc ================================================ { "directory": "bower_components" } ================================================ FILE: .editorconfig ================================================ # EditorConfig helps developers define and maintain consistent # coding styles between different editors and IDEs # editorconfig.org root = true [*] end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true indent_style = space indent_size = 2 [*.js] indent_style = space indent_size = 2 [*.hbs] indent_style = space indent_size = 2 [*.css] indent_style = space indent_size = 2 [*.html] indent_style = space indent_size = 2 [*.md] trim_trailing_whitespace = false ================================================ FILE: .ember-cli ================================================ { /** Ember CLI sends analytics information by default. The data is completely anonymous, but there are times when you might want to disable this behavior. Setting `disableAnalytics` to true will prevent any data from being sent. */ "disableAnalytics": false } ================================================ FILE: .gitignore ================================================ # See http://help.github.com/ignore-files/ for more about ignoring files. # compiled output /dist !/dist/.keep /tmp # dependencies /node_modules /bower_components/* # misc /.sass-cache /connect.lock /coverage/* /libpeerconnection.log npm-debug.log testem.log .idea ================================================ FILE: .hound.yml ================================================ javascript: enabled: true config_file: .jshintrc ================================================ FILE: .jshintrc ================================================ { "predef": [ "document", "window", "-Promise" ], "browser": true, "boss": true, "curly": true, "debug": false, "devel": true, "eqeqeq": true, "evil": true, "forin": false, "immed": false, "laxbreak": false, "newcap": true, "noarg": true, "noempty": false, "nonew": false, "nomen": false, "onevar": false, "plusplus": false, "regexp": false, "undef": true, "sub": true, "strict": false, "white": false, "eqnull": true, "esnext": true, "unused": true, "moz": true } ================================================ FILE: .npmignore ================================================ test-app tests ================================================ FILE: .travis.yml ================================================ language: node_js sudo: false cache: directories: - node_modules install: - npm install -g bower - npm install - bower install script: - npm test ================================================ FILE: .watchmanconfig ================================================ { "ignore_dirs": ["tmp", "dist"] } ================================================ FILE: LICENSE ================================================ Copyright (c) 2014 Jake Craige 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. ================================================ FILE: README.md ================================================ # ember-cli-cordova [![Build Status](https://travis-ci.org/poetic/ember-cli-cordova.svg?branch=master)](https://travis-ci.org/poetic/ember-cli-cordova) [![Gitter](https://badges.gitter.im/poetic/ember-cli-cordova.svg)](https://gitter.im/poetic/ember-cli-cordova?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) I will not be focusing on backward compatibility with older ember-cli versions as it's moving too fast and the API is constantly changing. I will always have this working with the latest stable release of ember-cli. ## Goals To provide a toolchain tightly integrated with ember-cli to make developing hybrid apps with cordova and ember as simple as possible. ## Supported Platforms Android and iOS. While we don't plan on actively supporting other platforms, feel free to open an issue or submit a pull request. ## Required Ember Versions Releases as of 0.1.0 require Ember 2.x and ember-cli 2.3.0. The lastest release for Ember 1.x is 0.0.19 and requires at least ember-cli >= 0.1.1 ## Getting Started Please see our Getting Started guide [here](https://github.com/poetic/ember-cli-cordova/blob/master/docs/getting-started.md) ## Blueprints + `ember g cordova-init com.reverse.domain --platform=android` Required generator that sets up the cordova project with a few tweaks to the ember app + (optional) `ember g cordova-starter-kit` Adds some packages and files that makes up the base setup for projects I develop. ## Commands + `ember cordova:open` open xcode project + `ember cordova:build --environment=production --platform=ios` build cordova project + `ember cordova:archive 0.0.2 --environment=staging --commit --tag` archive ios project with xcode + `ember cordova:prepare` needs to be run after cloning a project + `ember cordova` Passes commands(plugin(s), platform(s), run, emulate) and arguments to the cordova command + `ember help` ember cli help with a section for addon provided commands as well # Docs Documentation can be found found in the docs directory [here](https://github.com/poetic/ember-cli-cordova/tree/master/docs). - [Getting Started](https://github.com/poetic/ember-cli-cordova/blob/master/docs/getting-started.md) - [Configuration](https://github.com/poetic/ember-cli-cordova/blob/master/docs/configuration.md) - [FAQ](https://github.com/poetic/ember-cli-cordova/blob/master/docs/faq.md) # ember-cordova [ember-cordova](https://github.com/isleofcode/ember-cordova) recently started as a fork of ember-cli-cordova by some contributors and maintainers. It only supports Ember 2, and includes added features such as build hooks, native splash screen & icon management, a platform service (e.g. isIOS) and an ember/cordova plugin ecosystem. ember-cli-cordova will still be maintained and active. It does not include features such as mobiletouch by default, starter blueprints and support for Ember <2. For these items, your best bet is to continue with ember-cli-cordova. # Dependency Docs - [ember-cli](http://ember-cli.com) - [cordova](http://cordova.apache.org/docs/en/4.0.0/) # Contributing ## Working with master ``` sh git clone https://github.com/poetic/ember-cli-cordova.git cd ember-cli-cordova npm i && bower i npm link ember new CordovaTest cd CordovaTest npm install --save-dev ember-cli-cordova npm link ember-cli-cordova ``` After this, any changes you make to the cloned repo will be instantly reflected in the test app you generated. It just symlinks the node_modules folder. # Example App You can find an example app using this here: [jakecraige/ember-cli-cordova-example-app](https://github.com/jakecraige/ember-cli-cordova-example-app) # Credits [ember-cli](https://github.com/stefanpenner/ember-cli) [ember](https://github.com/emberjs/emberjs) ================================================ FILE: addon/initializers/in-app-livereload.js ================================================ import redirect from '../utils/redirect'; export var initialize = function(app, config) { var url = config.cordova.emberUrl || 'http://localhost:4200'; return redirect(url); }; export default { name: 'cordova:in-app-livereload', initialize: initialize }; ================================================ FILE: addon/mixins/controllers/nav-bar.js ================================================ import Ember from 'ember'; export default Ember.Mixin.create({ nav: { title: { }, leftButton: { }, rightButton: { } }, actions: { leftButton: function() { var leftAction = this.get('nav.leftButton.action'); if(leftAction) { leftAction(); } }, rightButton: function() { var rightAction = this.get('nav.rightButton.action'); if(rightAction) { rightAction(); } }, resetNavBar: function() { this.set('nav', { title: { }, leftButton: { }, rightButton: { } }); } } }); ================================================ FILE: addon/mixins/cordova-events.js ================================================ /* jshint esnext:true */ import Ember from 'ember'; // include this mixin to define cordova event listeners with an onCordova object // // onCordova supports arrays, strings, and anonymous functions, e.g.: // // ``` // export default MyEmberObject.extend({ // onCordova: { // pause: ['pauseListening', 'disconnectPeripheral'], // resume: 'resumeListening', // volumeup: function() { console.log('a little bit louder now'); } // } // }); // ``` export default Ember.Mixin.create({ cordova: Ember.inject.service(), subscribeToCordovaEvents: Ember.on('init', function() { var cordova = this.get('cordova'), onCordova = this.get('onCordova'); Ember.keys(onCordova).forEach(function(key) { var func = Ember.get(onCordova, key); // subscribe to events if (func instanceof Array) { func.forEach(function(fn) { if (this._validateIsFunction(fn)) { cordova.on(key, this, fn); } }, this); } else { if (this._validateIsFunction(func)) { cordova.on(key, this, func); } } }, this); }), _validateIsFunction: function(func) { var isFunction = false; if (func instanceof Function) { isFunction = true; } else if (typeof func === 'string') { var fn = this.get(func); isFunction = fn instanceof Function; } return isFunction; } }); ================================================ FILE: addon/mixins/routes/nav-bar.js ================================================ import Ember from 'ember'; export default Ember.Mixin.create({ _navController: Ember.computed('nav.controller', function() { var name = this.get('nav.controller') || 'application'; return this.controllerFor(name); }), afterModel: function(model) { this._setDefaults(); this._setNavOptions(model); this._setNavActions(); return this._super.apply(this, arguments); }, // Since we are using so many nested paths this makes sure they are set to // null values _setDefaults: function() { var ctrl = this.get('_navController'); if(!ctrl.get('nav')) { ctrl.send('resetNavBar'); } else if(!ctrl.get('nav.title')) { ctrl.set('nav.title', {}); } else if(!ctrl.get('nav.leftButton')) { ctrl.set('nav.leftButton', {}); } else if(!ctrl.get('nav.rightButton')) { ctrl.set('nav.rightButton', {}); } }, _setNavOptions: function(model) { var ctrl = this.get('_navController'); var navOptions = Ember.A([ 'title.text', 'leftButton.text', 'leftButton.icon', 'rightButton.text', 'rightButton.icon' ]); navOptions.forEach(function(key){ var optionPath = 'nav.' + key; var value = this.get(optionPath); if (value) { if(Ember.typeOf(value) === 'function') { value = value.call(this, model); } ctrl.set(optionPath, value); } }, this); }, _setNavActions: function() { var ctrl = this.get('_navController'); Ember.A(['leftButton', 'rightButton']).forEach(function(button) { var actionPath = 'nav.' + button + '.action'; var action = this.get(actionPath); if (action) { ctrl.set(actionPath, Ember.run.bind(this, action)); } }, this); }, actions: { willTransition: function() { this.get('_navController').send('resetNavBar'); return this._super.apply(this, arguments); } } }); ================================================ FILE: addon/services/cordova.js ================================================ /* jshint esnext:true */ import Ember from 'ember'; // from https://cordova.apache.org/docs/en/4.0.0/cordova_events_events.md.html // use var because cordova/android was throwing errors re: const && strict mode var CORDOVA_EVENTS = Ember.A([ 'deviceready', 'pause', 'resume', 'backbutton', 'menubutton', 'searchbutton', 'startcallbutton', 'endcallbutton', 'volumedownbutton', 'volumeupbutton', 'batterycritical', 'batterylow', 'batterystatus', 'online', 'offline' ]); // the cordova service listens for cordova events emitted to the document, // and triggers the same events in emberland. // // subscribe to cordova events as such: // // ```javascript // export default MyEmberObject.extend({ // cordova: Ember.inject.service() // // init: function() { // cordova.on('resume', function() { console.log('i am resumed'); }); // } // }); // ``` export default Ember.Service.extend( Ember.Evented, { setEventTriggers: Ember.on('init', function() { var _this = this; CORDOVA_EVENTS.forEach(function(eventName) { Ember.$(document).on(eventName, function() { _this.trigger(eventName); }); }); }) }); ================================================ FILE: addon/utils/redirect.js ================================================ import Ember from 'ember'; export default function(url) { if(window.location.href.indexOf('file://') > -1) { Ember.run.later(function() { window.location.replace(url); }, 50); } } ================================================ FILE: app/components/cdv-nav-bar.js ================================================ import Ember from 'ember'; export default Ember.Component.extend({ tagName: 'header' }); ================================================ FILE: app/initializers/in-app-livereload.js ================================================ /* globals cordova */ import config from '../config/environment'; import reloadInitializer from 'ember-cli-cordova/initializers/in-app-livereload'; var inAppReload = reloadInitializer.initialize; export var initialize = function(app) { if(typeof cordova === 'undefined' || config.environment !== 'development' || (config.cordova && (!config.cordova.liveReload || !config.cordova.liveReload.enabled))) { return; } return inAppReload(app, config); }; export default { name: 'cordova:in-app-livereload', initialize: initialize }; ================================================ FILE: app/services/cordova.js ================================================ /* jshint esnext:true */ import CordovaService from 'ember-cli-cordova/services/cordova'; export default CordovaService.extend({}); ================================================ FILE: app/templates/cdv-generic-nav-bar.hbs ================================================ {{#if nav.leftButton.text}} {{/if}} {{#if nav.title.text}}

{{nav.title.text}}

{{/if}} {{#if nav.rightButton.text}} {{/if}} ================================================ FILE: app/templates/components/cdv-nav-bar.hbs ================================================ {{yield}} ================================================ FILE: blueprints/cordova-init/files/config/environment.js ================================================ /* jshint node: true */ module.exports = function(environment) { var ENV = { modulePrefix: '<%= modulePrefix %>', environment: environment, baseURL: '/', defaultLocationType: 'auto', EmberENV: { FEATURES: { // Here you can enable experimental features on an ember canary build // e.g. 'with-controller': true } }, APP: { // Here you can pass flags/options to your application instance // when it is created }, cordova: { rebuildOnChange: false, emulate: false } }; if (environment === 'development') { // ENV.APP.LOG_RESOLVER = true; ENV.APP.LOG_ACTIVE_GENERATION = true; // ENV.APP.LOG_TRANSITIONS = true; // ENV.APP.LOG_TRANSITIONS_INTERNAL = true; ENV.APP.LOG_VIEW_LOOKUPS = true; } if (environment === 'test') { // Testem prefers this... ENV.baseURL = '/'; ENV.locationType = 'none'; // keep test console output quieter ENV.APP.LOG_ACTIVE_GENERATION = false; ENV.APP.LOG_VIEW_LOOKUPS = false; ENV.APP.rootElement = '#ember-testing'; } if (environment === 'production') { } return ENV; }; ================================================ FILE: blueprints/cordova-init/files/gitignore ================================================ # See http://help.github.com/ignore-files/ for more about ignoring files. # compiled output /dist /tmp # dependencies /node_modules /bower_components/* # misc /.sass-cache /connect.lock /coverage/* /libpeerconnection.log npm-debug.log testem.log # iOS cordova/platforms/ios/build/ cordova/platforms/ios/www/ cordova/platforms/ios/cordova/console.log *.xcuserdatad # android cordova/platforms/android/assets/www cordova/platforms/android/bin cordova/platforms/android/gen cordova/platforms/android/local.properties cordova/platforms/android/ant-build cordova/platforms/android/ant-gen cordova/platforms/android/CordovaLib/ant-build cordova/platforms/android/CordovaLib/ant-gen cordova/platforms/android/CordovaLib/bin cordova/platforms/android/CordovaLib/gen cordova/platforms/android/CordovaLib/local.properties # wp8 cordova/platforms/wp8/bin cordova/platforms/wp8/obj cordova/platforms/wp8/www cordova/platforms/wp8/.staging cordova/platforms/wp8/*.suo cordova/platforms/wp8/*.csproj.user #browser cordova/platforms/browser/build cordova/platforms/browser/www ================================================ FILE: blueprints/cordova-init/index.js ================================================ var projectWithConfig = require('../../lib/models/project-with-config'); var Promise = require('../../lib/ext/promise'); var stringUtils = require('../../lib/utils/string'); var defaultPlatform = require('../../lib/utils/default-platform'); module.exports = { locals: function(options) { var name = options.project.pkg.name; return { namespace: stringUtils.classify(name), modulePrefix: stringUtils.dasherize(name) } }, afterInstall: function(options) { this.options = options.entity.options; this.options.platform = options.platform || defaultPlatform(this.project); projectWithConfig(this.project, options.entity.name); return this.setupCordova(); }, setupCordova: function() { var createProject = require('../../lib/tasks/create-cordova-project')(this.project); var addPlatforms = require('../../lib/tasks/add-platforms')(this.project, this.options); var updateConfig = require('../../lib/tasks/update-config-xml')(this.project); var linkEnvironment = require('../../lib/tasks/link-environment')(this.project); return createProject().then(addPlatforms).then(updateConfig).then(linkEnvironment); } }; ================================================ FILE: blueprints/cordova-starter-kit/files/app/adapters/application.js ================================================ import DS from 'ember-data'; import config from '../config/environment'; export default DS.ActiveModelAdapter.extend({ host: config.apiUrl }); ================================================ FILE: blueprints/cordova-starter-kit/files/app/routes/application.js ================================================ import Ember from 'ember'; export default Ember.Route.extend({ actions: { back: function() { history.back(); }, openLink: function(url) { window.open(url, '_system'); } } }); ================================================ FILE: blueprints/cordova-starter-kit/files/app/styles/app.scss ================================================ * { -webkit-tap-highlight-color: rgba(0,0,0,0); -webkit-tap-highlight-color: transparent; box-sizing: border-box; -webkit-touch-callout: none; -webkit-user-select: none; input, textarea { -webkit-touch-callout: auto; -webkit-user-select: auto; } } ================================================ FILE: blueprints/cordova-starter-kit/files/app/templates/application.hbs ================================================

Welcome to ember-cli-cordova!

{{liquid-outlet name="main"}} {{liquid-outlet modal}} ================================================ FILE: blueprints/cordova-starter-kit/files/app/transitions.js ================================================ export default function() { } ================================================ FILE: blueprints/cordova-starter-kit/files/config/environment.js ================================================ /* jshint node: true */ var os = require('os'); var ifaces = os.networkInterfaces(); var addresses = []; for (var dev in ifaces) { ifaces[dev].forEach(function(details){ if(details.family === 'IPv4' && details.address !== '127.0.0.1') { addresses.push(details.address); } }); } module.exports = function(environment) { var ENV = { modulePrefix: '<%= modulePrefix %>', environment: environment, baseURL: '/', defaultLocationType: 'auto', EmberENV: { FEATURES: { // Here you can enable experimental features on an ember canary build // e.g. 'with-controller': true } }, APP: { // Here you can pass flags/options to your application instance // when it is created }, cordova: { rebuildOnChange: false, emulate: false, emberUrl: 'http://' + addresses[0] + ':4200', liveReload: { enabled: false, platform: 'ios' } } }; if (environment === 'development') { // ENV.APP.LOG_RESOLVER = true; ENV.APP.LOG_ACTIVE_GENERATION = true; // ENV.APP.LOG_TRANSITIONS = true; // ENV.APP.LOG_TRANSITIONS_INTERNAL = true; ENV.APP.LOG_VIEW_LOOKUPS = true; ENV.apiUrl = 'http://' + addresses[0] + ':3000/api/v1'; ENV.development = true; } if (environment === 'test') { // Testem prefers this... ENV.baseURL = '/'; ENV.locationType = 'auto'; // keep test console output quieter ENV.APP.LOG_ACTIVE_GENERATION = false; ENV.APP.LOG_VIEW_LOOKUPS = false; ENV.APP.rootElement = '#ember-testing'; } if (environment === 'staging') { ENV.apiUrl = 'http://<%= modulePrefix %>-staging.herokuapp.com/api/v1'; ENV.staging = true; } if (environment === 'production') { ENV.apiUrl = 'http://<%= modulePrefix %>.herokuapp.com/api/v1'; ENV.production = true; } return ENV; }; ================================================ FILE: blueprints/cordova-starter-kit/index.js ================================================ var path = require('path'); var chalk = require('chalk'); var Promise = require('../../lib/ext/promise'); var stringUtils = require('../../lib/utils/string'); var runCommand = require('../../lib/utils/run-command'); module.exports = { // Allows the generator to not require an entity name normalizeEntityName: function(entityName) { return entityName; }, locals: function(options) { var name = options.project.pkg.name; return { namespace: stringUtils.classify(name), modulePrefix: stringUtils.dasherize(name) } }, addPluginToProject: function(name) { var ui = this.ui; return runCommand('cordova plugin add ' + name, null, { cwd: path.join(this.project.root, 'cordova') })().then(function() { if (ui) { ui.writeLine(' ' + chalk.green('install plugin') + ' ' + name); } }); }, afterInstall: function() { return Promise.all([ this.addPackageToProject('broccoli-sass'), this.addPackageToProject('liquid-fire'), this.addPackageToProject('ember-gestures') ]); } }; ================================================ FILE: bower.json ================================================ { "name": "ember-cli-cordova", "dependencies": { "ember": "~2.3.1", "ember-cli-shims": "0.1.0", "ember-cli-test-loader": "0.2.2", "ember-qunit-notifications": "0.1.0" } } ================================================ FILE: docs/commands.md ================================================ ##Overview All commands follow the pattern `ember cordova:{command}`. You can use the `cdv` alias insted of`cordova`, for example `ember cdv:{command}`. ##Open ####Description Open the native platform project with the default or specified application ####Available options + platform (default:ios) + application (default:system default application) ####Examples + `ember cordova:open` + `ember cordova:open --platform=android --application=eclipse` ##Archive ####Description Build project and create xcode archive. If the tag or commit options are present they will be performed after archiving. ####Available options + environment (default:staging) + tag (default:false) + commit (default:false) ####Examples + `ember cordova:archive` + `ember cordova:archive 0.0.2 --environment=staging --commit --tag ` ##Build ####Description Build the ember and cordova project together running in the simulator or on a device ####Available options + environment (default:development) + platform (default:ios) ####Examples + `ember cordova:build` + `ember cordova:build --environment=production --platform=ios` ##Prepare ####Description Needed after cloning or copying a project. ###Available options ####Examples + `ember cordova:prepare` ##Cordova ####Description Passes commands(plugin(s), platform(s), run, emulate) and arguments to the cordova command ###Available options + run + emulate + platform(s) + plugin(s) ####Examples + `ember cordova platform` + `ember cordova platforms` + `ember cordova run` ================================================ FILE: docs/configuration.md ================================================ ### Configuration All configuration is currently optional. Configuration will be done in your app's `config/environment`. You need to set it up like this: ```js ENV.cordova = { // Rebuild the cordova project on file changes. Blocks the server until it's // finished. // // default: false rebuildOnChange: true, // Run the cordova emulate command after the build is finished // // default: false emulate: true, // Which emulated target to deploy to // // default: emulateTarget: { ios: "iPad-2", android: "android-20" }, // Which platform to build and/or emulate // // default: 'ios' platform: 'ios', // Which URL the ember server is running on. This is used when using // live-reload that comes with the starter kit. // // default: 'the-device-ip:4200' emberUrl: 'http://10.0.1.12:4200', // Whether or not to use liveReload on the device simulator. Requires a few // plugins to be installed that come with the starter-kit. It will cause your // app to not boot up in the browser // // default: false and iOS liveReload: { enabled: false, platform: 'ios' } }; ``` ================================================ FILE: docs/events.md ================================================ # Events ## Description ember-cli-cordova creates a service at `services/cordova.js`, which listens for events defined and emitted by Cordova (e.g. `deviceready`, `pause`, `resume`). ## Usage **Simple Usage:** Many events require only simple callbacks, e.g. pausing / resuming listener functions, logging the event, etc. In these cases, extend your object/class with the provided mixin, which will look for an `onCordova` object and run the provided functions when an event matching the key is emitted. For example: ```javascript import CordovaEventsMixin from 'ember-cli-cordova/mixins/cordova-events'; export default MyEmberObject.extend( CordovaEventsMixin, { onCordova: { pause: ['pauseListening', 'disconnectPeripheral'], resume: 'resumeListening', volumeup: function() { console.log('a little bit louder now'); } } }); ``` (Yes, `onCordova` supports arrays of named functions, single named functions, and anonymous functions!) **Advanced Usage:** If you have more advanced needs, e.g. turning on/off an event subscription when an `Ember.Route` is activated/deactivated, or just prefer a more manual approach, you can inject the provided service and tinker away: ```javascript export default MyRoute.extend({ cordova: Ember.inject.service(), activate: function() { // use named function to unsubscribe later this.get('cordova').on('pause', this, '_resumeListening'); }, deactivate: function() { this.get('cordova').off('pause', this, '_resumeListening'); }, _resumeListening: function() { console.log('do your thing'); } }); ``` ================================================ FILE: docs/faq.md ================================================ # FAQ #### I am getting `Current working directory is not a Cordova-based project.` when I run a cordova command If you are running a cli command, make sure the dist directory exists. You can run `ember build` to create it if it doesnt. You can also try to run `ember cordova:prepare` #### When running `ember cordova:archive` command I get an Xcode build error saying the scheme doesnt exist Error example: ``` ld[10658:1007] WARNING: Timed out waiting for /"runContextManager.runContexts" (10.000125 seconds elapsed) xcodebuild: error: The project 'MyApp' does not contain a scheme named 'MyApp'. ``` This is caused by not having opened the project in Xcode before. It automatically generates some info it needs to archive the project. To fix this, run `ember cordova:open` and let it open in Xcode. After you've done this once you can just run `ember cordova:archive` command again and it shouldn't give you any more trouble. ================================================ FILE: docs/getting-started.md ================================================ # Getting Started This guide will walk you through setting up your first app with ember-cli-cordova. ## Prerequisites - [ember-cli](http://www.ember-cli.com) - [cordova](https://www.npmjs.org/package/cordova) Ember-cli-cordova requires ember-cli and cordova. You may install them as follows: ``` npm install -g ember-cli npm install -g cordova ``` ## Setting Up The App First, let's set up your ember-cli project: ```sh ember new hello ``` After that's set up, we need to add the ember-cli-cordova addon to the application. Go in the freshly generated `hello` folder, then install the addon. ```sh ember install ember-cli-cordova ``` Ember cli-cordova requires cordova. If you don't have cordova, use this line to install it. ```sh npm install -g cordova ``` To intialize the cordova project we use a generator provided by ember-cli-cordova. You pass in the com domain identifier that you want to use with your app. It can be anything you like as long as it's unique. This matters if you plan on releasing it to the app stores. It takes an optional `platform` argument that defaults to `ios`. If you want to generate an android project you would pass in `--platform=android` at the end or set your default platform in [cordova configuration](https://github.com/poetic/ember-cli-cordova/blob/master/docs/configuration.md). ```sh ember generate cordova-init com.poeticsystems.hello ``` This will prompt you to overwrite some default files. You should overwrite them as they provide some required settings and helpful additions. This will also create the cordova project for you in the `cordova` directory. If you ever need raw access to the cordova project you can `cd` into this directory to run the command or modify files. After that, the project is ready to go. There are some configuration options in your environment config that you can set to enable / disable some features. See the [configuration](https://github.com/poetic/ember-cli-cordova/blob/master/docs/configuration.md) section for information on that. ### Optional Starter Kit There's also a starter kit generator. This includes lots of goodies that we use at our company to develop our cordova apps. things like [broccoli-sass](https://github.com/joliss/broccoli-sass) for sass support and [liquid-fire](https://github.com/ef4/liquid-fire) for animations. It also includes a default application adapter, modal component, style resets and extra configuration. To run this, simple run ```sh ember generate cordova-starter-kit ``` ## Developing The App Once your project is set up, you're ready to start developing. We've tried to keep the experience as similar to ember-cli as possible. You just need to move your `locationType` setting in `config/environment.js` to `defaultLocationType` so that it'd be used when not building for cordova (cordova needs `hash` as `locationType`). Then you can simply run the `serve` command and begin ```sh ember serve ``` This will run the ember server and behave no different than in vanilla ember-cli. This is the primary place you will be working as it provides the quickest feedback loop, debugging tools and best experience. The one drawback to this is that any cordova plugins you use will not work in the browser. This means that when you want to test the functionality of a plugin, you will need to load the app up on a simulator or device. When you need to serve or build files for a browser environment (not for cordova) be sure to override the `EMBER_CLI_CORDOVA` environment variable to set it to a falsy value (`0`, `no`, `off` or `false`). It'll allow you to use `locationType` as specified in `defaultLocationType` and will not inject the `cordova.js` script tag. ```sh EMBER_CLI_CORDOVA=0 ember serve ``` ### Running The App On A Simulator Or Device When you need to run on a device or simulator, we have some options to automate this. By default, all features that affect the cordova build are disabled. You will need to enable the ones you want in the `config/environment.js`. #### Normal Cordova Build To run a simple cordova build with ember linked up, run ``` ember cordova:build ``` This will build your ember project, link everything up to cordova and run a cordova build. If you choose this route, no changes will be reflected in the running app until you run it again. To simplify, after every change you will need to run this command. Sometimes that's what you want, but we have an option to automate this. In your `config/environment` you can set `cordova.rebuildOnChange` to true. This will hook into the ember server and automate this build after every change. Then when you run the app again, you will be able to see the changes. While this is convenient at times(mainly plugin development) it's still not as quick as we want it to be. We want Livereload on the device! #### Livereload When enabled, this feature will allow you to use ember-cli's livereload when the app is running on you device or simulator. This allows you get instant feedback on a real device which allows you to get the full experience of using the app and plugins with an instant feedback loop. It is disabled in production...[for now](https://github.com/poetic/ember-cli-cordova/pull/56). Livereload is currently disabled by default and will need to be turned on in your `config/environment`. To enable it, set `cordova.liveReload.enabled` to true, and set `cordova.liveReload.platform` to the platform you will be running the app on. **A few things to be aware of** - You will need to rebuild with 'ember cordova:build' when you make changes to the environment config. - When you add/remove/update plugins or native code you will also need to run the `ember cordova:build`. - You will need to set the `emberUrl` in the config if you are running the app on a device that is not on the same computer or if your ember server is on a different port. It defaults to `http://localhost:4200`. The reason for this is that when the app starts up, it redirects to the url your ember server is running on so it must be set correctly. - Livereload is a fairly new feature in ember-cli-cordova and we are really excited about it. If you have any trouble with it please submit an issue or PR so that we can resolve it. ================================================ FILE: docs/nav-bar.md ================================================ # Nav Bar ## Description The nav-bar component, partial, and mixins provide an easy to use way of having a global nav bar that gets updated between routes automatically by defining options on the route. The component itself is very barebones but there is also a partial you can include within it along with a few mixins to get a full featured nav bar without much work. # Usage Add this in your application template ```hbs {{#cdv-nav-bar}} {{partial 'cdv-generic-nav-bar'}} {{/cdv-nav-bar }} ``` In your application controller, mixin the controller NavBarMixin. If you don't do this, the actions within the nav-bar won't work. This is where all state for the nav bar lives. ```js import NavBarMixin from 'ember-cli-cordova/mixins/controllers/nav-bar'; export default Ember.Controller.extend(NavBarMixin); ``` Then in any route you can mixin the route NavBarMixin and set options for the nav bar. The options will be reset on each transition. This is implemented using ember's [willTransition](http://emberjs.com/api/classes/Ember.Route.html#event_willTransition) in the route. All options are optional. ```js import NavBarMixin from 'ember-cli-cordova/mixins/routes/nav-bar'; export default Ember.Route.extend(NavBarMixin, { nav: { // Default: application // If the cdv-nav-bar is included in something other than the application // template this needs to be set to that controller: 'application', // The text or icon option for title, leftButton, or rightButton can be // a string or function. If it's a function // it will be called in the // context of the afterModel hook and have the // model passed in as an // argument title: { text: 'Title' }, leftButton: { // Text to show text: function(model) { return model.get('title'); }, // Class of an icon to display icon: 'save', // Action to trigger when it is clicked. It will trigger in the context of // the route so you have access to the correct `this`. action: function() { // ... } }, // Same options as leftButton rightButton: { // ... }, } }); ``` ================================================ FILE: ember-cli-build.js ================================================ /*jshint node:true*/ /* global require, module */ var EmberAddon = require('ember-cli/lib/broccoli/ember-addon'); module.exports = function(defaults) { var app = new EmberAddon(defaults, { // Add options here }); /* This build file specifies the options for the dummy test app of this addon, located in `/tests/dummy` This build file does *not* influence how the addon or the app using it behave. You most likely want to be modifying `./index.js` or app's build file */ return app.toTree(); }; ================================================ FILE: index.js ================================================ 'use strict'; var path = require('path'); var fs = require('fs'); var commands = require('./lib/commands'); var postBuild = require('./lib/tasks/post-build'); var defaults = require('lodash').defaults; var chalk = require('chalk'); var mergeTrees = require('broccoli-merge-trees'); var Funnel = require('broccoli-funnel'); module.exports = { name: 'ember-cli-cordova', _isTargetCordova: function () { return !process.env.EMBER_CLI_CORDOVA || ['0', 'off', 'false', 'no'].indexOf(process.env.EMBER_CLI_CORDOVA.toLowerCase()) === -1; }, config: function (env, config) { var conf = {isCordovaBuild: this._isTargetCordova()}; if (conf.isCordovaBuild && env !== 'test') { if (config.locationType && config.locationType !== 'hash') { throw new Error('ember-cli-cordova: You must specify the locationType as \'hash\' in your environment.js or rename it to defaultLocationType.'); } conf.locationType = 'hash'; } else if (!conf.locationType) { conf.locationType = config.defaultLocationType || 'auto'; } conf.cordova = defaults(config.cordova || {}, { liveReload: { enabled: false, platform: 'ios' } }); return conf; }, contentFor: function (type) { if (this._isTargetCordova() && type === 'body') { return ''; } }, includedCommands: function () { return commands; }, cdvConfig: function () { return this.project.config(process.env.EMBER_ENV || 'development').cordova; }, postBuild: function () { if (this._isTargetCordova()) { return postBuild(this.project, this.cdvConfig())(); } else { return function () { }; } }, treeForPublic: function (tree) { var config = this.cdvConfig(); if (this._isTargetCordova() && config.liveReload.enabled) { if (!config.liveReload.platform) { throw new Error('ember-cli-cordova: You must specify a liveReload.platform in your environment.js'); } var platformsPath = path.join(this.project.root, 'cordova', 'platforms'); var pluginsPath; if (config.liveReload.platform === 'ios') { pluginsPath = path.join(platformsPath, 'ios', 'www'); } else if (config.liveReload.platform === 'browser') { pluginsPath = path.join(platformsPath, 'browser', 'www'); } else if (config.liveReload.platform === 'android') { pluginsPath = path.join(platformsPath, 'android', 'assets', 'www'); } else { pluginsPath = path.join(platformsPath, config.liveReload.platform); } var files = ['cordova.js', 'cordova_plugins.js']; files.forEach(function (file) { var filePath = path.join(pluginsPath, file); if (!fs.existsSync(filePath)) { var err = new Error('ember-cli-cordova: ' + filePath + ' did not exist. It is required for Device LiveReload to work.'); err.stack = null; throw err; } }); if (fs.existsSync(path.join(pluginsPath, 'plugins'))) { files.push('plugins/**'); } var pluginsTree = new Funnel(this.treeGenerator(pluginsPath), { srcDir: '/', include: files, destDir: '/' }); console.log(chalk.green('ember-cli-cordova: Device LiveReload is enabled')); return mergeTrees([tree, pluginsTree]); } return tree; } }; ================================================ FILE: lib/commands/archive.js ================================================ 'use strict'; var path = require('path'); var projectWithConfig = require('../models/project-with-config'); module.exports = { name: 'cordova:archive', aliases: ['cdv:archive'], description: 'Build project and create xcode archive. If the tag or commit options are present they will be performed after archiving.', works: 'insideProject', anonymousOptions: [ '' ], availableOptions: [ { name: 'environment', type: String, default: 'staging' }, { name: 'tag', type: Boolean, default: false }, { name: 'commit', type: Boolean, default: false } ], run: function(options, rawArgs) { projectWithConfig(this.project); var version = rawArgs[0]; return require('../tasks/archive')(version, options, this.project)(); } }; ================================================ FILE: lib/commands/build.js ================================================ 'use strict'; var path = require('path'); var chalk = require('chalk'); var defaultPlatform = require('../utils/default-platform'); module.exports = { name: 'cordova:build', aliases: ['cdv:build'], description: 'Build the ember and cordova project together running in the simulator or on a device', works: 'insideProject', availableOptions: [ { name: 'environment', type: String, default: 'development' }, { name: 'platform', type: String } ], run: function(options) { var platform = options.platform || defaultPlatform(this.project); return require('../tasks/build')(options.environment, platform, this.project)(); } }; ================================================ FILE: lib/commands/cordova.js ================================================ 'use strict'; var path = require('path'); var chalk = require('chalk'); module.exports = { name: 'cordova', aliases: ['cdv'], description: 'Passes commands(plugin(s), platform(s), run, emulate) and arguments to the cordova command', works: 'insideProject', allowedCordovaCommands: [ 'plugin', 'plugins', 'platform', 'platforms', 'run', 'emulate' ], validateAndRun: function(rawArgs) { if(this.allowedCordovaCommands.indexOf(rawArgs[0]) > -1) { return this.run({}, rawArgs); } }, run: function(options, rawArgs) { return require('../tasks/cordova')(rawArgs, this.project)(); } }; ================================================ FILE: lib/commands/index.js ================================================ module.exports = { 'cordova': require('./cordova'), 'cordova:build': require('./build'), 'cordova:open': require('./open'), 'cordova:prepare': require('./prepare'), 'cordova:archive': require('./archive') }; ================================================ FILE: lib/commands/open.js ================================================ 'use strict'; var path = require('path'); var defaultPlatform = require('../utils/default-platform'); module.exports = { name: 'cordova:open', aliases: ['cdv:open'], description: 'Open the native platform project with the default or specified application', works: 'insideProject', availableOptions: [ { name: 'platform', type: String }, { name: 'application', type: String} ], run: function(options) { var platform = options.platform || defaultPlatform(this.project); return require('../tasks/open')(this.project, platform, options.application)(); } }; ================================================ FILE: lib/commands/prepare.js ================================================ var path = require('path'); var linkEnv = require('../tasks/link-environment'); var runCommand = require('../utils/run-command'); var Promise = require('../ext/promise'); module.exports = { name: 'cordova:prepare', aliases: ['cdv:prepare'], description: 'Needed after cloning or copying a project.', works: 'insideProject', run: function() { var installDeps = runCommand('npm install && bower install', 'Installing npm and bower dependencies', { cwd: this.project.root }); // Because of this being parallel. It breaks the logging and it looks like // // Symlinking ember dir to cordova www... // Installing npm and bower dependencies...donedone return Promise.all([linkEnv(this.project)(), installDeps()]); } }; ================================================ FILE: lib/ext/promise.js ================================================ // https://github.com/stefanpenner/ember-cli/blob/master/lib/ext/promise.js 'use strict'; var RSVP = require('rsvp'); var Promise = RSVP.Promise; module.exports = PromiseExt; // Utility functions on on the native CTOR need some massaging module.exports.hash = function() { return this.resolve(RSVP.hash.apply(null, arguments)); }; module.exports.denodeify = function() { var fn = RSVP.denodeify.apply(null, arguments); var Constructor = this; return function() { return Constructor.resolve(fn.apply(null, arguments)); }; }; module.exports.filter = function() { return this.resolve(RSVP.filter.apply(null, arguments)); }; module.exports.map = function() { return this.resolve(RSVP.map.apply(null, arguments)); }; function PromiseExt() { Promise.apply(this, arguments); } PromiseExt.prototype = Object.create(Promise.prototype); PromiseExt.prototype.constructor = PromiseExt; PromiseExt.__proto__ = Promise; PromiseExt.prototype.returns = function(value) { return this.then(function() { return value; }); }; PromiseExt.prototype.invoke = function(method) { var args = Array.prototype.slice(arguments, 1); return this.then(function(value) { return value[method].apply(value, args); }, undefined, 'invoke: ' + method + ' with: ' + args); }; PromiseExt.prototype.map = function(mapFn) { var Constructor = this.constructor; return this.then(function(values) { return Constructor.map(values, mapFn); }); }; PromiseExt.prototype.filter = function(mapFn) { var Constructor = this.constructor; return this.then(function(values) { return Constructor.filter(values, mapFn); }); }; ================================================ FILE: lib/models/project-with-config.js ================================================ 'use strict'; var stringUtils = require('../utils/string'); var getComId = function(project) { var fs = require('fs'); var path = require('path'); var configPath = path.join(project.root, 'cordova', 'config.xml'); var configFile = fs.readFileSync(configPath, { encoding: 'utf-8'}); var idRegex = /id=\"([\w\-\.]+)\"/; var matches = configFile.match(idRegex); if(matches.length) { return matches[1]; } throw new Error('Unable to find an id within your cordova/config.xml'); } module.exports = function(project, id) { project.cordovaConfig = { name: stringUtils.classify(project.name()), id: id || getComId(project) }; return project; }; ================================================ FILE: lib/tasks/add-platforms.js ================================================ 'use strict'; var runCommand = require('../utils/run-command'); var path = require('path'); module.exports = function(project, options) { var command = 'cordova platforms add ' + options.platform; return runCommand(command, 'Adding ' + options.platform + ' platform to cordova', { cwd: path.join(project.root, 'cordova') }); }; ================================================ FILE: lib/tasks/archive.js ================================================ 'use strict'; var path = require('path'); var runCommand = require('../utils/run-command'); var Promise = require('../ext/promise'); var defaultPlatform = require('../utils/default-platform'); module.exports = function(version, options, project, platform) { var config = project.cordovaConfig; var updateXml = function() { return Promise.resolve(); }; var archiveProject = function() { return Promise.resolve(); }; platform = platform || 'ios'; if (version) { updateXml = require('./update-config-xml-version')(version, project); } var build = require('./build')(options.environment, platform, project); if(platform === 'ios') { var iosPath = path.join(project.root, 'cordova', 'platforms/ios'); var archiveCommand = 'xcodebuild -scheme ' + config.name + ' archive'; var archiveMessage = 'Archiving project with xcodebuild'; archiveProject = runCommand(archiveCommand, archiveMessage, { cwd: iosPath }); } if(platform === 'android' && version) { var __updateXml = updateXml; updateXml = function () { var androidVersionCode = require('./update-config-xml-android-version-code')(project); return __updateXml().then(androidVersionCode); } } var commitCommand = 'git add . && git commit -m "archive version: ' + version + '"'; var commitProject = runCommand(commitCommand, 'Commiting changes', { cwd: project.root }); var tagCommand = 'git tag -a -m "' + 'Version ' + version + '" ' + version; var tagProject = runCommand(tagCommand, 'Tagging with version ' + version, { cwd: project.root }); return function() { var promises = updateXml().then(build).then(archiveProject); if (options.commit && options.tag) { promises.then(commitProject).then(tagProject); } else { if (options.commit) { promises.then(commitProject) } else if (options.tag) { promises.then(tagProject); } } return promises; } }; ================================================ FILE: lib/tasks/build.js ================================================ 'use strict'; var runCommand = require('../utils/run-command'); var path = require('path'); var linkEnv = require('../tasks/link-environment'); module.exports = function(env, platform, project) { var emberCommand = 'ember build --environment ' + env; var emberMsg = 'Building ember project for environment ' + env; var emberBuild = runCommand(emberCommand, emberMsg, { cwd: project.root }); var cdvCommand = 'cordova build ' + platform; if (env !== 'development') { cdvCommand += ' --release' } var cdvMsg = 'Building cordova project for platform ' + platform; var cdvBuild = runCommand(cdvCommand, cdvMsg, { cwd: path.join(project.root, 'cordova') }); return function(){ return linkEnv(project)().then(emberBuild).then(cdvBuild); }; }; ================================================ FILE: lib/tasks/cordova.js ================================================ 'use strict'; var path = require('path'); var runCommand = require('../utils/run-command'); module.exports = function(rawArgs, project) { var joinedArgs = rawArgs.join(' '); var cdvCommand = 'cordova ' + joinedArgs; var msg = "Running 'cordova " + joinedArgs + "'"; return function(){ return runCommand(cdvCommand, msg, { cwd: path.join(project.root, 'cordova') })(); }; }; ================================================ FILE: lib/tasks/create-cordova-project.js ================================================ 'use strict'; var runCommand = require('../utils/run-command'); var path = require('path'); module.exports = function(project) { var config = project.cordovaConfig; var command = 'cordova create cordova ' + config.id + ' ' + config.name; return runCommand(command, 'Creating Cordova project', { cwd: project.root }); }; ================================================ FILE: lib/tasks/link-environment.js ================================================ 'use strict'; var Promise = require('../ext/promise'); var fs = require('fs-extra'); var symlink = Promise.denodeify(fs.symlink); var remove = Promise.denodeify(fs.remove); var path = require('path'); var chalk = require('chalk'); var verifyDist = require('./verify-dist'); module.exports = function(project){ if(!project) { throw new Error('A project must be passed into this function'); } var cordovaPath = path.join(project.root, 'cordova'); var wwwPath = path.join(cordovaPath, 'www'); return function() { // allows us to do a relative symlink process.chdir(cordovaPath); return remove(wwwPath) .then(symlink.bind(this, '../dist', 'www', 'dir')) .then(verifyDist(project)); }; }; ================================================ FILE: lib/tasks/modify-xml.js ================================================ 'use strict'; var fs = require('fs'); var chalk = require('chalk'); var path = require('path'); var ui = require('../ui'); var Promise = require('../ext/promise'); // Used as the context of this for the replaceFn so it can be used var replaceObject = { xmlReplace: function(regex, value, xml) { return xml.replace(regex, '$1' + value + '$2'); } }; module.exports = function(message, root, replaceFn) { return function modifyXml() { return new Promise(function(resolve, reject){ try { var configPath = path.join(root, 'config.xml'); ui.start(chalk.green(message)); var xml = fs.readFileSync(configPath, { encoding: 'utf8' }); xml = replaceFn.call(replaceObject, xml); fs.writeFileSync(configPath, xml); resolve(); } catch(e) { reject(e); } }); }; }; ================================================ FILE: lib/tasks/open.js ================================================ 'use strict'; var Promise = require('../ext/promise'); var path = require('path'); var runCommand = require('../utils/run-command'); var getOpenCommand = require('../utils/open'); module.exports = function(project, platform, application) { var projectPath, command; if (platform === 'ios') { projectPath = path.join(project.root, 'cordova', 'platforms/ios/*.xcodeproj'); } else if (platform === 'android') { projectPath = path.join(project.root, 'cordova', 'platforms/android/.project'); } else { return Promise.reject(new Error('The ' + platform + ' platform is not supported. Please use "ios" or "android"')); } var command = getOpenCommand(projectPath, application); return runCommand(command, 'Opening ' + platform + ' project with the default application'); }; ================================================ FILE: lib/tasks/post-build.js ================================================ 'use strict'; var runCommand = require('../utils/run-command'); var defaultPlatform = require('../utils/default-platform'); var path = require('path'); var chalk = require('chalk'); var ui = require('../ui'); var Promise = require('../ext/promise'); function createCommand(project, options) { var platform = options.platform || defaultPlatform(project); var command = 'cordova build ' + platform; if (options.emulate) { command += ' && cordova emulate ' + platform; if (options.emulateTarget) { if (options.emulateTarget[platform]) { command += ' --target="' + options.emulateTarget[platform] + '"'; } } } return runCommand(command, null, { cwd: path.join(project.root, 'cordova') }); } module.exports = function(project, options) { if (!options.rebuildOnChange) { return function() {}; } return function() { var rebuild = createCommand(project, options)(); rebuild.then(function() { ui.write(chalk.green('Cordova build successful.\n')); }); return Promise.resolve(); } }; ================================================ FILE: lib/tasks/update-config-xml-android-version-code.js ================================================ 'use strict'; var fs = require('fs'); var path = require('path'); var Promise = require('../ext/promise'); var versionCodeRegex = /(android-versionCode=\")[\d.]+(\")/; var versionCodeMatch = /android-versionCode=\"([\d.])+\"/; module.exports = function(project) { return new Promise(function(resolve, reject){ try { var cordovaPath = path.join(project.root, 'cordova'); var configPath = path.join(cordovaPath, 'config.xml'); var xml = fs.readFileSync(configPath, { encoding: 'utf8' }); var match = xml.match(versionCodeMatch); if(match) { var versionCode = (parseInt(match[1], 10)) + 1; var message = 'Update config.xml with android-versionCode ' + versionCode; return require('./modify-xml')(message, cordovaPath, function(xml) { return this.xmlReplace(versionCodeRegex, versionCode, xml); })().then(resolve, reject); } else { reject(); } } catch (e) { reject(e); } }); }; ================================================ FILE: lib/tasks/update-config-xml-version.js ================================================ 'use strict'; var path = require('path'); var versionRegex = /(version=\")[\d.]+(\")/; module.exports = function(version, project) { var message = 'Update config.xml with version ' + version; var cordovaPath = path.join(project.root, 'cordova'); return require('./modify-xml')(message, cordovaPath, function(xml) { return this.xmlReplace(versionRegex, version, xml); }); }; ================================================ FILE: lib/tasks/update-config-xml.js ================================================ 'use strict'; var path = require('path'); // Match the outer tags so we can match and reinsert them with a String#replace var idRegex = /(id=\")[\w\.]+(\")/; var nameRegex = /()\w+(<\/name>)/; var endWidgetRegex = /(.*)(<\/widget>)/; var preferences = [ // haha, 4 spaces at the beginning ' ' ]; module.exports = function(project) { var config = project.cordovaConfig; var message = 'Update config.xml with your project settings'; var cordovaPath = path.join(project.root, 'cordova'); return require('./modify-xml')(message, cordovaPath, function(xml) { xml = this.xmlReplace(idRegex, config.id, xml); xml = this.xmlReplace(nameRegex, config.name, xml); // add preference tag(s) xml = this.xmlReplace(endWidgetRegex, preferences.join('\n') + '\n', xml); return xml; }); }; ================================================ FILE: lib/tasks/verify-dist.js ================================================ 'use strict'; var runCommand = require('../utils/run-command'); var path = require('path'); var fs = require('fs'); var Promise = require('../ext/promise'); module.exports = function(project) { return function() { var distPath = path.join(project.root, 'dist'); if(fs.existsSync(distPath)) { return Promise.resolve(); } else { return runCommand('ember build', 'Building ember app since dist/ dir doesn\'t exist yet', { cwd: project.root })(); } } }; ================================================ FILE: lib/ui/index.js ================================================ 'use strict'; var PleasantProgress = require('pleasant-progress'); module.exports = { pleasantProgress: new PleasantProgress(), start: function(msg) { this.pleasantProgress.stop(true); this.pleasantProgress.start(msg) }, write: function(msg) { this.pleasantProgress.stream.write(msg); } }; ================================================ FILE: lib/utils/default-platform.js ================================================ module.exports = function defaultPlatform(project) { var config = project.config().cordova || {}; return config.platform || 'ios'; }; ================================================ FILE: lib/utils/open.js ================================================ 'use strict'; /* This file needs to be removed when issue https://github.com/pwnall/node-open/issues/30 is resolved, original file can be seen here: https://github.com/pwnall/node-open/blob/0c3ad272bfbc163cce8806e64630c623a9cfd8f4/lib/open.js */ module.exports = function(target, appName) { var opener; switch (process.platform) { case 'darwin': if (appName) { opener = 'open -a "' + escape(appName) + '"'; } else { opener = 'open'; } break; case 'win32': // if the first parameter to start is quoted, it uses that as the title // so we pass a blank title so we can quote the file we are opening if (appName) { opener = 'start "" "' + escape(appName) + '"'; } else { opener = 'start'; } break; default: if (appName) { opener = escape(appName); } else { // use Portlands xdg-open everywhere else opener = 'xdg-open'; } break; } if (process.env.SUDO_USER) { opener = 'sudo -u ' + process.env.SUDO_USER + ' ' + opener; } return opener + ' ' + target; } ================================================ FILE: lib/utils/run-command.js ================================================ 'use strict'; var Promise = require('../ext/promise'); var exec = require('child_process').exec; var chalk = require('chalk'); var ui = require('../ui'); var defaults = require('lodash').defaults; module.exports = function runCommand(command, startedMsg, options) { if(options == null) { options = {} } return function() { if(startedMsg) { ui.start(chalk.green(startedMsg)); } options = defaults(options, { maxBuffer: 5000 * 1024 }); return new Promise(function(resolve, reject) { exec(command, options, function(err, stdout, stderr) { ui.write('\n'); if (stdout && stdout.length) { ui.write(stdout); } if (stderr && stderr.length) { ui.write(stderr); } if (err) { return reject(commandError(command, err)); } resolve(stdout); }); }); }; }; function commandError(command, err) { ui.write(chalk.red('\nError thrown while running shell command: "' + command + '"\n')); if(err.stack) { ui.write(err.stack); } else { ui.write(err); } } ================================================ FILE: lib/utils/string.js ================================================ // https://github.com/emberjs/ember.js/blob/v1.5.0/packages/ember-runtime/lib/system/string.js 'use strict'; var STRING_DECAMELIZE_REGEXP = (/([a-z\d])([A-Z])/g); var _s = require('underscore.string'); module.exports = { decamelize: function(str) { return str ? str.replace(STRING_DECAMELIZE_REGEXP, '$1_$2').toLowerCase() : ''; }, dasherize: function(str) { return str ? _s.dasherize(str).replace(/^\-/, '') : ''; }, classify: function(str) { // Have to humanize first so that 'MyApp' doesnt turn into 'Myapp' return str ? _s.classify(_s.humanize(str)) : ''; } }; ================================================ FILE: node-tests/fixtures/project/.ember-cdv ================================================ { "name": "TestApp", "modulePrefix": "test-app", "id": "com.poetic.test-app" } ================================================ FILE: node-tests/fixtures/project/cordova/config.xml ================================================ ExampleApp A sample Apache Cordova application that responds to the deviceready event. Apache Cordova Team ================================================ FILE: node-tests/helpers/_helper.js ================================================ global.expect = require('chai').expect; global.sinon = require('sinon'); // be sure to not have any env variable set delete process.env.EMBER_CLI_CORDOVA; // Requiring a relative path will need to be relative to THIS file path global.proxyquire = require('proxyquire'); global.Promise = require('../../lib/ext/promise'); global.noop = require('./noop'); global.resolveFn = function() { return Promise.resolve() }; global.newProject = function() { return { cordovaConfig: { id: 'com.poetic.test-app', name: 'TestApp' }, root: 'project-root', config: function (){ return { cordova: {} }; } } }; ================================================ FILE: node-tests/helpers/mocks.js ================================================ var noop = require('./noop'); exports.ui = { write: noop, pleasantProgress: { write: noop, start: noop, stop: noop, clear: noop, } } exports.Promise = { denodeify: function(fn) { return fn; } } ================================================ FILE: node-tests/helpers/noop.js ================================================ module.exports = function() {}; ================================================ FILE: node-tests/helpers/stub.js ================================================ 'use strict'; module.exports = function stub(obj, name, value) { var original = obj[name]; obj[name] = function() { obj[name].called++; obj[name].calledWith.push(arguments); return value; }; obj[name].restore = function() { obj[name] = original; }; obj[name].called = 0; obj[name].calledWith = []; return obj[name]; }; ================================================ FILE: node-tests/unit/addon-test.js ================================================ var addon = require('../../index'); function expectWithConfig(config, env, call) { if (call) { return expect(addon.config(env || 'development', config)); } else { return expect(addon.config.bind(addon, env || 'development', config)); } } var errRegex = /ember-cli-cordova: You must specify the locationType as 'hash' in your environment\.js/; describe('Addon', function () { describe('config', function () { var savedEnvVar; beforeEach(function () { savedEnvVar = process.env.EMBER_CLI_CORDOVA; }); afterEach(function () { process.env.EMBER_CLI_CORDOVA = savedEnvVar; }); describe('validates location type', function () { it('should throw Error when auto', function () { expectWithConfig({ locationType: 'auto' }).to.throw(Error, errRegex); }); it('should not throw an error when hash', function () { expectWithConfig({ locationType: 'hash' }).to.not.throw(Error, errRegex); }); it('should not throw an error with auto in test environment', function () { expectWithConfig({ locationType: 'auto' }, 'test').to.not.throw(Error, errRegex); }); it('should not throw an error when the env var is set to 0', function () { process.env.EMBER_CLI_CORDOVA = '0'; expectWithConfig({ locationType: 'auto' }).to.not.throw(Error, errRegex); }); }); describe('should replace the locationType', function () { it('should use the defaultLocationType when building for test', function () { expectWithConfig({ defaultLocationType: 'auto' }, 'test', true).to.have.property('locationType', 'auto'); }); it('should use the defaultLocationType when the env var is set to 0', function () { process.env.EMBER_CLI_CORDOVA = '0'; expectWithConfig({ defaultLocationType: 'auto' }, null, true).to.have.property('locationType', 'auto'); }); it('should use hash as locationType', function () { expectWithConfig({ defaultLocationType: 'auto' }, null, true).to.have.property('locationType', 'hash'); }); }); }); }); ================================================ FILE: node-tests/unit/models/project-with-config-test.js ================================================ var expect = require('chai').expect; var path = require('path'); var projectWithConfig = require('../../../lib/models/project-with-config'); describe('Model - ProjectWithConfig', function() { var project; beforeEach(function() { project = { root: path.join(__dirname, '..', '..', 'fixtures/project'), name: function() {} } }); it('adds the ember cordova config instance', function() { project = projectWithConfig(project); expect(project.cordovaConfig.id).to.equal('com.example.app'); }); }); ================================================ FILE: node-tests/unit/tasks/add-platforms-test.js ================================================ describe('Tasks - Add Platforms', function() { it('creates the proper command', function() { var addPlatforms = proxyquire('../../lib/tasks/add-platforms', { '../utils/run-command': function(command) { expect(command).to.contain('platforms add some-platform'); } }); return addPlatforms({root: 'test'}, {platform: 'some-platform'}); }); it('executes command in cordova directory', function() { var addPlatforms = proxyquire('../../lib/tasks/add-platforms', { '../utils/run-command': function(_, __, options) { expect(options.cwd).to.equal('test/cordova'); } }); return addPlatforms({root: 'test'}, {platform: 'some-platform'}); }); }); ================================================ FILE: node-tests/unit/tasks/archive-test.js ================================================ describe('Tasks - Archive', function() { var project; beforeEach(function() { project = newProject(); }); describe('version parameter validation', function() { it('calls config-xml-version with version', function() { var archiveVersion = '0.1.0'; var archive = proxyquire('../../lib/tasks/archive', { './update-config-xml-version': function(version, project) { expect(version).to.eql(archiveVersion); return resolveFn; }, './build': resolveFn, '../utils/run-command': resolveFn }); return archive(archiveVersion, {}, project)(); }); it('doesn\'t call config-xml-version with version when undefined', function() { var archive = proxyquire('../../lib/tasks/archive', { './update-config-xml-version': function(version, project) { expect(false, 'should not have called here').to.be.ok; return resolveFn; }, './build': resolveFn, '../utils/run-command': resolveFn }); return archive(undefined, {}, project)(); }); }); it('prepares proper commands', function() { var archiveVersion = "0.1.0"; var commandOffset = 0; var commands = [ 'xcodebuild -scheme ' + project.cordovaConfig.name + ' archive', 'git add . && git commit -m "archive version: ' + archiveVersion + '"', 'git tag -a -m "Version ' + archiveVersion + '" ' + archiveVersion ]; var archive = proxyquire('../../lib/tasks/archive', { '../utils/run-command': function(command, msg, options){ expect(command).to.eql(commands[commandOffset++]); return resolveFn; }, './update-config-xml-version': function(version, project) { expect(version).to.eql(archiveVersion) return resolveFn; }, './build': resolveFn }); return archive(archiveVersion, {}, project); }); describe('executes proper commands', function() { var archiveVersion; beforeEach(function() { archiveVersion = '0.1.0'; }); it('with no options', function() { var commands = [ 'update-config-xml-version', 'build', 'xcodebuild -scheme ' + project.cordovaConfig.name + ' archive' ]; var options = {}; return expectCommandsToBeCalled( archiveVersion, options, project, commands ); }); it('with commit option', function() { var commands = [ 'update-config-xml-version', 'build', 'xcodebuild -scheme ' + project.cordovaConfig.name + ' archive', 'git add . && git commit -m "archive version: ' + archiveVersion + '"' ]; var options = { commit: true }; return expectCommandsToBeCalled( archiveVersion, options, project, commands ); }); it('with tag option', function() { var commands = [ 'update-config-xml-version', 'build', 'xcodebuild -scheme ' + project.cordovaConfig.name + ' archive', 'git tag -a -m "Version ' + archiveVersion + '" ' + archiveVersion ]; var options = { tag: true }; return expectCommandsToBeCalled( archiveVersion, options, project, commands ); }); // TODO: It says tag is never called. But I see no reason why it shouldn't // be. Will need to investigate and fix later it.skip('with commit and tag option', function() { var commands = [ 'update-config-xml-version', 'build', 'xcodebuild -scheme ' + project.cordovaConfig.name + ' archive', 'git add . && git commit -m "archive version: ' + archiveVersion + '"', 'git tag -a -m "Version ' + archiveVersion + '" ' + archiveVersion ]; var options = { commit: true, tag: true }; return expectCommandsToBeCalled( archiveVersion, options, project, commands ); }); }); }); function expectCommandsToBeCalled(archiveVersion, options, project, commands) { var stubbedArchive = stubArchive(); var stubs = stubbedArchive.stubs; var archive = stubbedArchive.archive; return archive(archiveVersion, options, project)().then(function() { commands.forEach(function(command, index) { var stub = stubs[command]; if (stub) { expect(stub.called, command + ' was never called').to.be.ok; } else { expect(false, command + ' was never even stubbed').to.be.ok; } }); }); } function stubArchive() { var RSVP = require('rsvp'); var stubs = {}; var archive = proxyquire('../../lib/tasks/archive', { '../utils/run-command': function(command, msg, options){ return stubs[command] = sinon.stub().returns(RSVP.resolve(command)); }, './update-config-xml-version': function(version, project) { return stubs['update-config-xml-version'] = sinon.stub().returns( Promise.resolve('update-config-xml-version') ); }, './build': function(env, platform, project) { return stubs['build'] = sinon.stub().returns(Promise.resolve('build')); } }); return { stubs: stubs, archive: archive }; } ================================================ FILE: node-tests/unit/tasks/build-test.js ================================================ describe('Tasks - Build', function() { var project, commandOffset; beforeEach(function() { project = newProject(); commandOffset = 0; }); describe('env argument', function() { it('development - runs proper commands', function() { var commands = [ 'ember build --environment development', 'cordova build ios' ]; var build = proxyquire('../../lib/tasks/build', { '../utils/run-command': function(command) { expect(command).to.eql(commands[commandOffset++]); return resolveFn; }, '../tasks/link-environment': function() { return resolveFn; } }); return build('development', 'ios', project)(); }); it('production - runs proper commands', function() { var commands = [ 'ember build --environment production', 'cordova build ios --release' ]; var build = proxyquire('../../lib/tasks/build', { '../utils/run-command': function(command) { expect(command).to.eql(commands[commandOffset++]); return resolveFn; }, '../tasks/link-environment': function() { return resolveFn; } }); return build('production', 'ios', project)(); }); }); describe('platform argument', function() { it('development - runs proper commands', function() { var commands = [ 'ember build --environment development', 'cordova build android' ]; var build = proxyquire('../../lib/tasks/build', { '../utils/run-command': function(command) { expect(command).to.eql(commands[commandOffset++]); return resolveFn; }, '../tasks/link-environment': function() { return resolveFn; } }); return build('development', 'android', project)(); }); it('production - runs proper commands', function() { var commands = [ 'ember build --environment production', 'cordova build android --release' ]; var build = proxyquire('../../lib/tasks/build', { '../utils/run-command': function(command) { expect(command).to.eql(commands[commandOffset++]); return resolveFn; }, '../tasks/link-environment': function() { return resolveFn; } }); return build('production', 'android', project)(); }); }); }); ================================================ FILE: node-tests/unit/tasks/cordova-test.js ================================================ describe('Tasks - Cordova', function() { it('creates a proper command', function() { var cordova = proxyquire('../../lib/tasks/cordova', { '../utils/run-command': function(command, msg, options){ expect(command).to.match(/cordova plugins add org\.apache\.test$/); return noop; }, }); return cordova(['plugins', 'add', 'org.apache.test'], { root: 'test' })(); }); it('executes in proper directory', function() { var cordova = proxyquire('../../lib/tasks/cordova', { '../utils/run-command': function(command, msg, options){ expect(options.cwd).to.match(/test\/cordova$/); return noop; }, }); return cordova(['plugins', 'add', 'org.apache.test'], { root: 'test' })(); }); }); ================================================ FILE: node-tests/unit/tasks/create-cordova-project-test.js ================================================ describe('Tasks - Create cordova project', function() { var project; beforeEach(function() { project = newProject(); }); it('creates the proper command', function() { var createProject = proxyquire('../../lib/tasks/create-cordova-project', { '../utils/run-command': function(command) { expect(command).to.eql('cordova create cordova com.poetic.test-app TestApp'); return resolveFn; } }); return createProject(project)(); }); it('should execute in proper folder', function() { var createProject = proxyquire('../../lib/tasks/create-cordova-project', { '../utils/run-command': function(_, _, options) { expect(options.cwd).to.equal('project-root'); return resolveFn; } }); return createProject(project)(); }); }); ================================================ FILE: node-tests/unit/tasks/link-environment-test.js ================================================ describe('Tasks - Link Environment', function() { var project; beforeEach(function() { project = newProject(); }); before(function() { process._chdir = process.chdir; process.chdir = noop; }); after(function() { process.chdir = process._chdir; }); it('removes the cordova/www dir', function() { var createProject = proxyquire('../../lib/tasks/link-environment', { './verify-dist': function() { return resolveFn; }, 'fs-extra': { remove: function(path, callback) { expect(path).to.eql('project-root/cordova/www'); return callback(null, true); }, symlink: function(from, to, type, _, callback) { return callback(null, true); } } }); return createProject(project)(); }); it('creates a relative dir symlink', function() { var createProject = proxyquire('../../lib/tasks/link-environment', { './verify-dist': function() { return resolveFn; }, 'fs-extra': { remove: function(path, callback) { return callback(null, true); }, symlink: function(from, to, type, _, callback) { expect(from).to.eql('../dist'); expect(to).to.eql('www'); expect(type).to.eql('dir'); return callback(null, true); } } }); return createProject(project)(); }); }); ================================================ FILE: node-tests/unit/tasks/open-test.js ================================================ describe('Tasks - Open', function() { var project; beforeEach(function() { project = newProject(); }); it('rejects when the platform isn\'t supported', function() { var open = proxyquire('../../lib/tasks/open', {}); return open(project, 'fake-platform').catch(function(err) { expect(err.toString()).to.match(/platform is not supported/); }); }); describe('runs correct command on each platform', function() { var platform; before(function() { platform = process.platform; }); after(function() { process.platform = platform; }); describe('darwin', function() { beforeEach(function() { process.platform = 'darwin'; }); it('ios', function() { return assertOpenCommand(project, 'ios', 'open project-root/cordova/platforms/ios/*.xcodeproj'); }); it('android', function() { return assertOpenCommand(project, 'android', 'open project-root/cordova/platforms/android/.project'); }); }); describe('win32', function() { beforeEach(function() { process.platform = 'win32'; }); it('ios', function() { return assertOpenCommand(project, 'ios', 'start project-root/cordova/platforms/ios/*.xcodeproj'); }); it('android', function() { return assertOpenCommand(project, 'android', 'start project-root/cordova/platforms/android/.project'); }); }); describe('other', function() { beforeEach(function() { process.platform = 'other'; }); it('ios', function() { return assertOpenCommand(project, 'ios', 'xdg-open project-root/cordova/platforms/ios/*.xcodeproj'); }); it('android', function() { return assertOpenCommand(project, 'android', 'xdg-open project-root/cordova/platforms/android/.project'); }); }); }); }); function assertOpenCommand(project, platform, assertion) { var open = proxyquire('../../lib/tasks/open', { '../utils/run-command': function(command) { expect(command).to.eql(assertion); } }); return open(project, platform); } ================================================ FILE: node-tests/unit/tasks/post-build-test.js ================================================ var uiMock = { write: noop }; describe('Tasks - Post Build', function() { var project; beforeEach(function() { project = newProject(); }); var options; describe('rebuildOnChange is false', function() { beforeEach(function() { options = { rebuildOnChange: false }; }); it('return noop', function() { var postBuild = proxyquire('../../lib/tasks/post-build', {}); var res = postBuild({}, options); expect(res.toString()).to.eql(noop.toString()); }); }); describe('rebuildOnChange is true', function() { beforeEach(function() { options = { rebuildOnChange: true }; }); it('returns resolving promise and executes correct build', function() { var postBuild = proxyquire('../../lib/tasks/post-build', { '../utils/run-command': function() { return resolveFn; }, '../ui': uiMock }); return postBuild(project, options)().then(function() { expect(true).to.be.ok; }); }); describe('emulate is false', function() { beforeEach(function() { options.emulate = false; }); it('runs correct command', function() { var postBuild = proxyquire('../../lib/tasks/post-build', { '../utils/run-command': function(command){ expect(command).to.eql('cordova build ios'); return resolveFn; }, '../ui': uiMock }); return postBuild(project, options)().then(function() { expect(true).to.be.ok; }); }); }); describe('emulate is true', function() { beforeEach(function() { options.emulate = true; }); it('runs correct command', function() { var postBuild = proxyquire('../../lib/tasks/post-build', { '../utils/run-command': function(command){ expect(command).to.eql('cordova build ios && cordova emulate ios'); return resolveFn; }, '../ui': uiMock }); return postBuild(project, options)().then(function() { expect(true).to.be.ok; }); }); }); describe('platform is android and emulate is true', function() { beforeEach(function() { options.platform = 'android'; options.emulate = true; }); it('runs correct command', function() { var postBuild = proxyquire('../../lib/tasks/post-build', { '../utils/run-command': function(command){ expect(command).to.eql('cordova build android && cordova emulate android'); return resolveFn; }, '../ui': uiMock }); return postBuild(project, options)().then(function() { expect(true).to.be.ok; }); }); }); }); }); ================================================ FILE: node-tests/unit/tasks/update-config-xml-test.js ================================================ var path = require('path'); var uiMock = { start: noop }; var project; describe('Tasks - Update config xml', function() { beforeEach(function() { project = { cordovaConfig: { id: 'com.poetic.test-app', name: 'TestApp' }, root: path.join(__dirname, '..', '..', 'fixtures/project') } }); it('updates id and name', function() { return proxyUpdate(function(xml) { expect(xml).to.match(/\sid=\"com\.poetic\.test\-app"\s/); expect(xml).to.match(/TestApp<\/name>/); }); }); it('adds DisallowOverscroll preference', function() { return proxyUpdate(function(xml) { expect(xml).to.match(//); }); }); }); function proxyUpdate(callback) { var update = proxyquire('../../lib/tasks/update-config-xml', { './modify-xml': proxyquire('../../lib/tasks/modify-xml', { 'fs': { writeFileSync: function(path, xml) { callback(xml); } }, '../ui': uiMock }) }); return update(project)(); } ================================================ FILE: node-tests/unit/tasks/update-config-xml-version-test.js ================================================ var path = require('path'); describe('Tasks - Update config xml version', function() { var project; beforeEach(function() { project = { root: path.join(__dirname, '..', '..', 'fixtures/project') } }); it('updates version and writes it', function() { var update = proxyquire('../../lib/tasks/update-config-xml-version', { './modify-xml': proxyquire('../../lib/tasks/modify-xml', { 'fs': { writeFileSync: function(path, xml) { expect(path).to.eql(project.root + '/cordova/config.xml'); expect(xml).to.match(/\sversion=\"0.1.0"\s/); } } }) }); return update('0.1.0', project)(); }); }); ================================================ FILE: node-tests/unit/tasks/verify-dist-test.js ================================================ describe('Tasks - Verify Dist', function() { var project; beforeEach(function() { project = newProject(); }); it('resolves when path exists', function() { var verifyDist = proxyquire('../../lib/tasks/verify-dist', { 'fs': { existsSync: function() { return true; } } }); return verifyDist(project)().then(function() { expect(true).to.be.ok; }); }); it('runs ember build when it doesn\'t exist', function() { var verifyDist = proxyquire('../../lib/tasks/verify-dist', { '../utils/run-command': function(command) { expect(command).to.eql('ember build'); } }); return verifyDist(project); }); }); ================================================ FILE: package.json ================================================ { "name": "ember-cli-cordova", "version": "0.1.0-beta-2", "description": "A tool for creating hybrid apps using a combination of ember-cli and cordova ", "homepage": "https://github.com/poetic/ember-cli-cordova", "repository": { "type": "git", "url": "git+https://github.com/poetic/ember-cli-cordova.git" }, "main": "index.js", "directories": { "doc": "docs", "test": "tests" }, "scripts": { "node-test": "mocha --require node-tests/helpers/_helper.js --reporter spec node-tests/**/*-test.js node-tests/**/**/*-test.js", "ember-test": "ember test", "test": "npm run node-test && npm run ember-test" }, "engines": { "node": ">= 0.10.0" }, "author": "Jake Craige ", "license": "MIT", "ember-addon": { "configPath": "tests/dummy/config" }, "keywords": [ "ember-addon" ], "dependencies": { "broccoli-funnel": "^0.2.3", "broccoli-merge-trees": "^1.1.0", "chalk": "^0.4.0", "ember-cli-babel": "^5.1.5", "findup-sync": "^0.1.3", "fs-extra": "^0.26.5", "lodash": "^4.5.1", "pleasant-progress": "^1.0.1", "recursive-readdir": "^1.1.1", "rsvp": "^3.0.6", "sinon": "^1.17.3", "underscore.string": "^2.3.3" }, "devDependencies": { "broccoli-asset-rev": "^2.2.0", "chai": "^1.9.1", "ember-ajax": "0.7.1", "ember-cli": "2.3.0", "ember-cli-app-version": "^1.0.0", "ember-cli-dependency-checker": "^1.2.0", "ember-cli-htmlbars": "^1.0.1", "ember-cli-htmlbars-inline-precompile": "^0.3.1", "ember-cli-inject-live-reload": "^1.3.1", "ember-cli-qunit": "^1.2.1", "ember-cli-release": "0.2.8", "ember-cli-sri": "^2.0.0", "ember-cli-uglify": "^1.2.0", "ember-disable-prototype-extensions": "^1.1.0", "ember-disable-proxy-controllers": "^1.0.1", "ember-export-application-global": "^1.0.4", "ember-load-initializers": "^0.5.0", "ember-resolver": "^2.0.3", "ember-sinon": "0.5.0", "ember-try": "^0.1.2", "glob": "^4.5.3", "loader.js": "^4.0.0", "mocha": "^1.20.1", "mocha-jshint": "0.0.7", "proxyquire": "^1.0.1", "qunit-bdd": "jakecraige/qunit-bdd.git#ember-addon", "tmp-sync": "^1.0.1" } } ================================================ FILE: public/.gitkeep ================================================ ================================================ FILE: public/inject-cordova.js ================================================ // ember-cli-cordova (function() { var platform = navigator.platform; if (platform.match(/(ipad|iphone|ipod|android)/i)) { var script = document.createElement('script'); script.setAttribute('src', 'cordova.js'); document.head.appendChild(script); } })() ================================================ FILE: testem.json ================================================ { "framework": "qunit", "test_page": "tests/index.html", "launch_in_ci": ["PhantomJS"], "launch_in_dev": ["PhantomJS", "Chrome"] } ================================================ FILE: tests/.jshintrc ================================================ { "predef": [ "document", "window", "location", "setTimeout", "$", "-Promise", "QUnit", "define", "console", "equal", "notEqual", "notStrictEqual", "test", "asyncTest", "testBoth", "testWithDefault", "raises", "throws", "deepEqual", "start", "stop", "ok", "strictEqual", "module", "moduleFor", "moduleForComponent", "moduleForModel", "process", "expect", "visit", "exists", "fillIn", "click", "keyEvent", "triggerEvent", "find", "findWithAssert", "wait", "DS", "keyEvent", "isolatedContainer", "startApp", "andThen", "currentURL", "currentPath", "currentRouteName", "cordova", "describe", "before", "after", "it", "lazy", "helper", "sinon" ], "node": false, "browser": false, "boss": true, "curly": false, "debug": false, "devel": false, "eqeqeq": true, "evil": true, "forin": false, "immed": false, "laxbreak": false, "newcap": true, "noarg": true, "noempty": false, "nonew": false, "nomen": false, "onevar": false, "plusplus": false, "regexp": false, "undef": true, "sub": true, "strict": false, "white": false, "eqnull": true, "esnext": true } ================================================ FILE: tests/dummy/.jshintrc ================================================ { "predef": { "document": true, "window": true, "-Promise": true, "DummyENV": true }, "browser" : true, "boss" : true, "curly": true, "debug": false, "devel": true, "eqeqeq": true, "evil": true, "forin": false, "immed": false, "laxbreak": false, "newcap": true, "noarg": true, "noempty": false, "nonew": false, "nomen": false, "onevar": false, "plusplus": false, "regexp": false, "undef": true, "sub": true, "strict": false, "white": false, "eqnull": true, "esnext": true, "unused": true } ================================================ FILE: tests/dummy/app/app.js ================================================ import Ember from 'ember'; import Resolver from './resolver'; import loadInitializers from 'ember-load-initializers'; import config from './config/environment'; let App; Ember.MODEL_FACTORY_INJECTIONS = true; App = Ember.Application.extend({ modulePrefix: config.modulePrefix, podModulePrefix: config.podModulePrefix, Resolver }); loadInitializers(App, config.modulePrefix); export default App; ================================================ FILE: tests/dummy/app/components/.gitkeep ================================================ ================================================ FILE: tests/dummy/app/controllers/.gitkeep ================================================ ================================================ FILE: tests/dummy/app/controllers/nav-bar.js ================================================ import Ember from 'ember'; import NavBarMixin from 'ember-cli-cordova/mixins/controllers/nav-bar'; export default Ember.Controller.extend(NavBarMixin); ================================================ FILE: tests/dummy/app/helpers/.gitkeep ================================================ ================================================ FILE: tests/dummy/app/index.html ================================================ Dummy {{content-for 'head'}} {{content-for 'head-footer'}} {{content-for 'body'}} {{content-for 'body-footer'}} ================================================ FILE: tests/dummy/app/models/.gitkeep ================================================ ================================================ FILE: tests/dummy/app/resolver.js ================================================ import Resolver from 'ember-resolver'; export default Resolver; ================================================ FILE: tests/dummy/app/router.js ================================================ import Ember from 'ember'; import config from './config/environment'; var Router = Ember.Router.extend({ location: config.locationType }); Router.map(function() { this.resource('nav-bar', function() { this.route('page-1'); this.route('options-from-model'); this.route('should-reset'); }); }); export default Router; ================================================ FILE: tests/dummy/app/routes/.gitkeep ================================================ ================================================ FILE: tests/dummy/app/routes/nav-bar/index.js ================================================ import Ember from 'ember'; import NavBarMixin from 'ember-cli-cordova/mixins/routes/nav-bar'; export default Ember.Route.extend(NavBarMixin, { nav: { controller: 'nav-bar', title: { text: 'Index' }, leftButton: { text: 'iLeft' }, rightButton: { text: 'iRight' }, } }); ================================================ FILE: tests/dummy/app/routes/nav-bar/options-from-model.js ================================================ import Ember from 'ember'; import NavBarMixin from 'ember-cli-cordova/mixins/routes/nav-bar'; export default Ember.Route.extend(NavBarMixin, { nav: { controller: 'nav-bar', title: { text: function(model) { return model.get('title'); } }, leftButton: { text: function(model) { return model.get('leftButton'); }, icon: function(model) { return model.get('leftClass'); } }, rightButton: { text: function(model) { return model.get('rightButton'); }, icon: function(model) { return model.get('rightClass'); } } }, model: function() { return Ember.Object.create({ title: 'modelOption', leftButton: 'modelLeft', leftClass: 'leftClass', rightButton: 'modelRight', rightClass: 'rightClass' }); } }); ================================================ FILE: tests/dummy/app/routes/nav-bar/page-1.js ================================================ import Ember from 'ember'; import NavBarMixin from 'ember-cli-cordova/mixins/routes/nav-bar'; export default Ember.Route.extend(NavBarMixin, { nav: { controller: 'nav-bar', title: { text: 'Page 1' }, leftButton: { text: 'pLeft' }, rightButton: { text: 'pRight' }, } }); ================================================ FILE: tests/dummy/app/styles/.gitkeep ================================================ ================================================ FILE: tests/dummy/app/styles/app.css ================================================ html, body { margin: 20px; } ================================================ FILE: tests/dummy/app/templates/.gitkeep ================================================ ================================================ FILE: tests/dummy/app/templates/application.hbs ================================================ {{outlet}} ================================================ FILE: tests/dummy/app/templates/components/.gitkeep ================================================ ================================================ FILE: tests/dummy/app/templates/nav-bar.hbs ================================================ {{#cdv-nav-bar}} {{partial 'cdv-generic-nav-bar'}} {{/cdv-nav-bar }} {{outlet}} ================================================ FILE: tests/dummy/app/views/.gitkeep ================================================ ================================================ FILE: tests/dummy/config/environment.js ================================================ /* jshint node: true */ module.exports = function(environment) { var ENV = { modulePrefix: 'dummy', environment: environment, baseURL: '/', locationType: 'hash', EmberENV: { FEATURES: { // Here you can enable experimental features on an ember canary build // e.g. 'with-controller': true } }, APP: { // Here you can pass flags/options to your application instance // when it is created } }; if (environment === 'development') { // ENV.APP.LOG_RESOLVER = true; ENV.APP.LOG_ACTIVE_GENERATION = true; // ENV.APP.LOG_TRANSITIONS = true; // ENV.APP.LOG_TRANSITIONS_INTERNAL = true; ENV.APP.LOG_VIEW_LOOKUPS = true; } if (environment === 'test') { // Testem prefers this... ENV.baseURL = '/'; ENV.locationType = 'auto'; // keep test console output quieter ENV.APP.LOG_ACTIVE_GENERATION = false; ENV.APP.LOG_VIEW_LOOKUPS = false; ENV.APP.rootElement = '#ember-testing'; } if (environment === 'production') { } return ENV; }; ================================================ FILE: tests/dummy/public/.gitkeep ================================================ ================================================ FILE: tests/dummy/public/crossdomain.xml ================================================ ================================================ FILE: tests/dummy/public/robots.txt ================================================ # robotstxt.org/ User-agent: * ================================================ FILE: tests/helpers/describe-app.js ================================================ import Ember from 'ember'; import startApp from './start-app'; export default function(name, callback) { return describe(name, function() { before(function() { this.app = startApp(); }); after(function() { Ember.run(this.app, 'destroy'); }); lazy('store', function() { return this.app.__container__.lookup('store:main'); }); helper('lookupController', function(name) { return this.app.__container__.lookup('controller:' + name); }); callback.call(this); }); } ================================================ FILE: tests/helpers/destroy-app.js ================================================ import Ember from 'ember'; export default function destroyApp(application) { Ember.run(application, 'destroy'); } ================================================ FILE: tests/helpers/module-for-acceptance.js ================================================ import { module } from 'qunit'; import startApp from '../helpers/start-app'; import destroyApp from '../helpers/destroy-app'; export default function(name, options = {}) { module(name, { beforeEach() { this.application = startApp(); if (options.beforeEach) { options.beforeEach.apply(this, arguments); } }, afterEach() { destroyApp(this.application); if (options.afterEach) { options.afterEach.apply(this, arguments); } } }); } ================================================ FILE: tests/helpers/resolver.js ================================================ import Resolver from '../../resolver'; import config from '../../config/environment'; const resolver = Resolver.create(); resolver.namespace = { modulePrefix: config.modulePrefix, podModulePrefix: config.podModulePrefix }; export default resolver; ================================================ FILE: tests/helpers/start-app.js ================================================ import Ember from 'ember'; import Application from '../../app'; import config from '../../config/environment'; export default function startApp(attrs) { let application; let attributes = Ember.merge({}, config.APP); attributes = Ember.merge(attributes, attrs); // use defaults, but you can override; Ember.run(() => { application = Application.create(attributes); application.setupForTesting(); application.injectTestHelpers(); }); return application; } ================================================ FILE: tests/index.html ================================================ Dummy Tests {{content-for 'head'}} {{content-for 'test-head'}} {{content-for 'head-footer'}} {{content-for 'test-head-footer'}} {{content-for 'body'}} {{content-for 'test-body'}} {{content-for 'body-footer'}} {{content-for 'test-body-footer'}} ================================================ FILE: tests/integration/nav-bar-test.js ================================================ import Ember from 'ember'; import describeApp from '../helpers/describe-app'; describeApp('Integration - Nav Bar', function() { describe('Route Mixin', function() { describe('Template', function() { it('updates between routes', function() { visit('nav-bar'); andThen(function() { equal(find('header h1').text().trim(), 'Index'); equal(find('header button:first').text().trim(), 'iLeft'); equal(find('header button:last').text().trim(), 'iRight'); }); visit('nav-bar/page-1'); andThen(function() { equal(find('header h1').text().trim(), 'Page 1'); equal(find('header button:first').text().trim(), 'pLeft'); equal(find('header button:last').text().trim(), 'pRight'); }); }); it('values can be a function', function() { visit('nav-bar/options-from-model'); andThen(function() { var leftButton = find('header button:first'); var title = find('header h1'); var rightButton = find('header button:last'); equal(title.text().trim(), 'modelOption'); equal(leftButton.text().trim(), 'modelLeft'); ok(leftButton.find('i').hasClass('leftClass')); equal(rightButton.text().trim(), 'modelRight'); ok(rightButton.find('i').hasClass('rightClass')); }); }); }); describe('Actions', function() { before(function() { var navIndex = this.app.__container__.lookup('route:nav-bar/index'); var page1 = this.app.__container__.lookup('route:nav-bar/page-1'); var spec = this; spec.navIndexStub = sinon.stub(); navIndex.setProperties({ 'nav.leftButton.action': function() { spec.navIndexStub('left'); }, 'nav.rightButton.action': function() { spec.navIndexStub('right'); } }); spec.page1Stub = sinon.stub(); page1.setProperties({ 'nav.leftButton.action': function() { spec.page1Stub('left'); }, 'nav.rightButton.action': function() { spec.page1Stub('right'); } }); }); it('updates between routes', function() { visit('nav-bar'); click('header button:first'); andThen(Ember.run.bind(this, function() { ok(this.navIndexStub.calledWith('left')); ok(!this.navIndexStub.calledWith('right')); })); click('header button:last'); andThen(Ember.run.bind(this, function() { ok(this.navIndexStub.calledWith('left')); ok(this.navIndexStub.calledWith('right')); })); visit('nav-bar/page-1'); click('header button:first'); andThen(Ember.run.bind(this, function() { ok(this.page1Stub.calledWith('left')); ok(!this.page1Stub.calledWith('right')); })); click('header button:last'); andThen(Ember.run.bind(this, function() { ok(this.page1Stub.calledWith('left')); ok(this.page1Stub.calledWith('right')); })); }); }); describe('willTransiton reset', function() { it('resets nav options on transition', function() { visit('nav-bar'); andThen(function() { equal(find('header h1').text().trim(), 'Index'); }); visit('nav-bar/should-reset'); andThen(Ember.run.bind(this, function() { var ctrl = this.lookupController('nav-bar'); equal(find('header h1').text().trim(), ''); equal(find('header button:first').text().trim(), ''); equal(find('header button:last').text().trim(), ''); deepEqual(ctrl.get('nav'), {title: {}, leftButton: {}, rightButton: {}}); })); }); }); }); }); ================================================ FILE: tests/test-helper.js ================================================ import resolver from './helpers/resolver'; import { setResolver } from 'ember-qunit'; setResolver(resolver); document.write('
'); QUnit.config.urlConfig.push({ id: 'nocontainer', label: 'Hide container'}); var containerVisibility = QUnit.urlParams.nocontainer ? 'hidden' : 'visible'; document.getElementById('ember-testing-container').style.visibility = containerVisibility; ================================================ FILE: tests/unit/.gitkeep ================================================