nativeloop
Version:
⭐ Axway Amplify module for using nativeloop with Appcelerator Titanium SDK Framework
441 lines (390 loc) • 15.9 kB
JavaScript
'use strict';
/***
* __ _ __ __
* ____ ___ ____ / /_ (_)/ /___ / /_ ___ _____ ____
* / __ `__ \ / __ \ / __ \ / // // _ \ / __ \ / _ \ / ___// __ \
* / / / / / // /_/ // /_/ // // // __// / / // __// / / /_/ /
* /_/ /_/ /_/ \____//_.___//_//_/ \___//_/ /_/ \___//_/ \____/
*
* mobile solutions for everyday heroes
*
* @file This is the core class for top navigation style windows.
* @module nativeloop/navigator
* @author Brenton House <brenton.house@gmail.com>
* @version 1.0.0
* @since 1.0.0
* @copyright Copyright (c) 2017 by Superhero Studios Incorporated. All Rights Reserved.
* @license Licensed under the terms of the MIT License (MIT)
*
*/
const Alloy = require( "/alloy" );
const apm = require( "nativeloop/apm" );
const utils = require( 'nativeloop/utils' );
const __modulename = __filename;
const EventEmitter = require( 'nativeloop/eventemitter2' );
// const events = require( "events" );
// const util = require( 'util' );
const Navigator = function() {
this._isInNavigatorStack = false;
this.controller = null;
this._navStack = [];
if( navigatorStack.length === 0 ) {
navigatorStack.push( this );
this._isInNavigatorStack = true;
}
//TODO: make delimiter configurable
var localEvents = new EventEmitter( {
wildcard: true,
newListener: true,
delimiter: '::',
maxListeners: 20
} );
this.id = utils.createGuid();
Alloy.Navigators = Alloy.Navigators || {};
Alloy.Navigators[ this.id ] = this;
localEvents.trigger = localEvents.emit;
localEvents.fire = localEvents.emit;
_.assignIn( this, localEvents );
// util.inherits( this, localEvents );
console.error( '_.keys(localEvents): ' + JSON.stringify( _.keysIn( localEvents ), null, 2 ) );
console.error( '_.keys(this): ' + JSON.stringify( _.keys( this ), null, 2 ) );
console.error( '_.keysIn(this): ' + JSON.stringify( _.keysIn( this ), null, 2 ) );
console.error( 'localEvents.emit: ' + JSON.stringify( _.isFunction( localEvents.emit ), null, 2 ) );
console.error( 'this.emit: ' + JSON.stringify( _.isFunction( this.emit ), null, 2 ) );
this.on( 'newListener', e => {
console.error( 'you are here → newListener event fired: ' + JSON.stringify( e, null, 2 ) );
} );
this.onAny( function( event, value ) {
console.log( 'All events trigger this.' );
console.error( 'event: ' + JSON.stringify( event, null, 2 ) );
console.error( 'value: ' + JSON.stringify( value, null, 2 ) );
} );
this.on( "nav::open::**", ( e, args ) => {
var __prefix = __modulename + " nav::open::** ";
apm.leaveBreadcrumb( __prefix + "entering" );
var commands = parseEventHorizon( this.event, args );
if( commands.length < 3 ) {
console.error( "[frame] Attempted to call nav::open with no target" );
apm.leaveBreadcrumb( __prefix + "exiting" );
__prefix = null;
return;
}
this.push( commands[ 2 ], commands[ 3 ] || args );
apm.leaveBreadcrumb( __prefix + "exiting" );
__prefix = null;
} );
// events.on( "nav::open::*", function() {
// var __prefix = __modulename + "nav::open::* ";
// apm.leaveBreadcrumb( __prefix + "entering" );
// console.info( "event = " + this.event );
// var split = this.event.split( "::" );
// split.length > 2 && Navigator.topmost().go( split[ 2 ] );
// apm.leaveBreadcrumb( __prefix + "exiting" );
// __prefix = null;
// } );
this.on( "nav::back", () => {
var __prefix = __modulename + " nav::back ";
apm.leaveBreadcrumb( __prefix + "entering" );
console.info( "event = " + this.event );
// Navigator.topmost().goBack();
this.goBack();
apm.leaveBreadcrumb( __prefix + "exiting" );
__prefix = null;
} );
this.on( "nav::*", () => {
var __prefix = __modulename + " nav::* ";
apm.leaveBreadcrumb( __prefix + "entering" );
console.info( "nav event = " + this.event );
apm.leaveBreadcrumb( __prefix + "exiting" );
__prefix = null;
} );
this.actionHandler = e => {
var __prefix = __modulename + ".actionHandler: ";
apm.leaveBreadcrumb( __prefix + "entering" );
var eventName;
console.error( 'e: ' + JSON.stringify( e, null, 2 ) );
console.error( 'e.type: ' + JSON.stringify( e.type, null, 2 ) );
console.error( ' e.section.items[ e.itemIndex ]: ' + JSON.stringify( e.section.items[ e.itemIndex ], null, 2 ) );
if( e.section && !_.isNil( e.itemIndex ) ) {
eventName = e.section.items[ e.itemIndex ].properties[ e.type ];
if( eventName ) {
Ti.API.trace( "actionHandler: Triggering event - " + eventName );
// console.error("listener count: " + Alloy.Globals.Events.listeners(event_name).length);
this.emit( eventName, e );
}
return;
}
if( !e || !e.source || !e.source[ e.type ] ) {
console.error( "no context available for ActionHandler" );
return;
}
if( e && e.source && e.source[ e.type ] ) {
eventName = e.source[ e.type ];
Ti.API.trace( "actionHandler: Triggering event - " + eventName );
// console.error("listener count: " + Alloy.Globals.Events.listeners(event_name).length);
this.trigger( eventName, e );
} else if( e && e.source && e.source.collection_name && e.type === "change" ) {
eventName = e.source.collection_name + "::change";
apm.leaveBreadcrumb( __prefix + "Triggering event - " + event_name );
// console.error("listener count: " + Alloy.Globals.Events.listeners(event_name).length);
this.trigger( eventName, e );
}
apm.leaveBreadcrumb( __prefix + "exiting" );
__prefix = null;
};
};
// var localEvents = new EventEmitter( {
// wildcard: true,
// newListener: false,
// delimiter: '::',
// maxListeners: 20
// } );
// localEvents.trigger = localEvents.emit;
// localEvents.fire = localEvents.emit;
// Navigator.prototype = Object.create( localEvents.prototype );
module.exports = Navigator;
var navigatorStack = [];
var resolvePayload = function( payload, params ) {
var __prefix = __modulename + ".resolvePayload: ";
apm.leaveBreadcrumb( __prefix + "entering" );
_.isNil( payload ) ? payload = {} : _.isString( payload ) && ( payload = {
moduleName: payload
} );
_.isObject( params ) && _.defaults( payload, params );
_.defaults( payload, {
animated: true
} );
apm.leaveBreadcrumb( __prefix + "exiting" );
__prefix = null;
return payload;
};
var parseEventHorizon = function( event ) {
var __prefix = __modulename + ".parseEventHorizon: ";
apm.leaveBreadcrumb( __prefix + "entering" );
console.info( "event = " + event );
var params = event.split( "::" );
var response = [];
_.forEach( params, function( param ) {
if( _.includes( param, ":" ) ) {
var obj = {};
_.forEach( param.split( "," ), function( prop ) {
var a = prop.split( ":" );
a.length > 1 && _.set( obj, a[ 0 ], a[ 1 ] );
} );
response.push( obj );
} else response.push( param );
} );
apm.leaveBreadcrumb( __prefix + "exiting" );
__prefix = null;
return response;
};
Navigator.prototype.canGoBack = function() {
var __prefix = __modulename + ".canGoBack: ";
apm.leaveBreadcrumb( __prefix + "entering" );
return this._navStack.length > 0;
};
/**
* Navigates to the previous entry in the navigation stack
* @function goBack
*/
Navigator.prototype.goBack = function() {
var __prefix = __modulename + ".goBack: ";
apm.leaveBreadcrumb( __prefix + "entering" );
if( !this.canGoBack() ) {
apm.leaveBreadcrumb( __prefix + "exiting" );
return;
}
var previous_window = this._navStack.pop();
this.controller && this.controller.goBack( {
window: previous_window,
options: {}
} );
apm.leaveBreadcrumb( __prefix + "exiting" );
__prefix = null;
};
Navigator.prototype.goHome = function() {
var __prefix = __modulename + ".goHome: ";
apm.leaveBreadcrumb( __prefix + "entering" );
if( !this.canGoBack() ) {
apm.leaveBreadcrumb( __prefix + "exiting" );
__prefix = null;
return;
}
this._navStack.pop();
this.controller && this.controller.goHome( {
options: {}
} );
apm.leaveBreadcrumb( __prefix + "exiting" );
__prefix = null;
};
Navigator.prototype.go = function( payload, params ) {
var __prefix = __modulename + ".go: ";
apm.leaveBreadcrumb( __prefix + "entering" );
apm.leaveBreadcrumb( __prefix + "payload: " + JSON.stringify( payload, params ) );
if( !this._isInNavigatorStack ) {
navigatorStack.push( this );
this._isInNavigatorStack = true;
}
this.performNavigation( resolvePayload( payload, params ) );
apm.leaveBreadcrumb( __prefix + ".exiting" );
__prefix = null;
};
/**
* @function push
* @param {object} params - screen parameters
* @param {string} params.title - title of the screen as appears in the nav bar (optional)
* @param {object} params.navigatorStyle - override the navigator style for the tab screen
* @param {object} params.navigatorButtons - override the nav buttons for the tab screen
* @param {object[]} params.navigatorButtons.leftButtons - override the left nav buttons for the tab screen
* @param {string} params.navigatorButtons.leftButtons[].title - title for the left nav button
* @param {string} params.navigatorButtons.leftButtons[].id - id for this button
* @param {boolean} [params.navigatorButtons.leftButtons[].disabled=false] - used to disable the button (optional)
* @param {string} [params.navigatorButtons.leftButtons[].image] - local image asset name to use for button (optional)
* @param {string} [params.navigatorButtons.leftButtons[].icon] - local icon name to use for button (optional)
* @param {object[]} params.navigatorButtons.rightButtons - override the right nav buttons for the tab screen
* @param {object[]} params.navigatorButtons.rightButtons[].title - title for the right nav button
* @param {string} params.navigatorButtons.rightButtons[].id - id for this button
* @param {boolean} [params.navigatorButtons.rightButtons[].disabled=false] - used to disable the button (optional)
* @param {string} [params.navigatorButtons.rightButtons[].image] - local image asset name to use for button (optional)
* @param {string} [params.navigatorButtons.rightButtons[].icon] - local icon name to use for button (optional)
* @param {object} [params.passProps] - simple serializable object that will pass as props to all top screens (optional)
*/
Navigator.prototype.push = function( params ) {
var __prefix = __modulename + ".push: ";
apm.leaveBreadcrumb( __prefix + "entering" );
apm.leaveBreadcrumb( __prefix + "params: " + JSON.stringify( params, null, 2 ) );
if( !this._isInNavigatorStack ) {
navigatorStack.push( this );
this._isInNavigatorStack = true;
}
if( _.isString( params ) ) {
params = { screen: { name: params } }
} else if( _.isString( params.screen ) ) {
params.screen = { name: params }
}
// params.navigator = this;
params.__navigatorId = this.id;
this._navStack.push( params );
if( this.controller ) this.controller.push( params );
else {
this.controller = Alloy.createWidget( "nativeloop", "navigator", params );
// this.controller.getView().open();
}
apm.leaveBreadcrumb( __prefix + ".exiting" );
__prefix = null;
};
// Navigator.prototype.performNavigation2 = function( params ) {
// var __prefix = __modulename + ".performNavigation2: ";
// apm.leaveBreadcrumb( __prefix + "entering" );
// console.error( 'params: ' + JSON.stringify( params, null, 2 ) );
// this._navStack.push( params );
// if( this.controller ) this.controller.push( params );
// else {
// this.controller = Alloy.createWidget( "nativeloop", "navigator", {
// root: params
// } );
// // this.controller.getView().open();
// }
// apm.leaveBreadcrumb( __prefix + "exiting" );
// __prefix = null;
// };
Navigator.prototype.performNavigation = function( payload ) {
var __prefix = __modulename + ".performNavigation: ";
apm.leaveBreadcrumb( __prefix + "entering" );
console.error( 'payload: ' + JSON.stringify( payload, null, 2 ) );
this._navStack.push( payload );
if( this.controller ) this.controller.go( payload );
else {
this.controller = Alloy.createWidget( "nativeloop", "navigator", {
root: payload
} );
// this.controller.getView().open();
}
apm.leaveBreadcrumb( __prefix + "exiting" );
__prefix = null;
};
Navigator.topmost = function() {
var __prefix = __modulename + ".topmost: ";
apm.leaveBreadcrumb( __prefix + "entering" );
if( navigatorStack.length > 0 ) {
apm.leaveBreadcrumb( __prefix + "exiting - returning topmost navigator" );
var topmost = navigatorStack[ navigatorStack.length - 1 ];
return topmost;
}
apm.leaveBreadcrumb( __prefix + "exiting - no navigators found" );
__prefix = null;
return void 0;
};
// Navigator.prototype.actionHandler = function( e ) {
// var __prefix = __modulename + ".actionHandler: ";
// apm.leaveBreadcrumb( __prefix + "entering" );
// var eventName;
// console.error( 'e: ' + JSON.stringify( e, null, 2 ) );
// console.error( 'e.type: ' + JSON.stringify( e.type, null, 2 ) );
// console.error( ' e.section.items[ e.itemIndex ]: ' + JSON.stringify( e.section.items[ e.itemIndex ], null, 2 ) );
// if( e.section && !_.isNil( e.itemIndex ) ) {
// eventName = e.section.items[ e.itemIndex ].properties[ e.type ];
// if( eventName ) {
// Ti.API.trace( "actionHandler: Triggering event - " + eventName );
// // console.error("listener count: " + Alloy.Globals.Events.listeners(event_name).length);
// this.trigger( eventName, e );
// }
// return;
// }
// if( !e || !e.source || !e.source[ e.type ] ) {
// console.error( "no context available for ActionHandler" );
// return;
// }
// if( e && e.source && e.source[ e.type ] ) {
// eventName = e.source[ e.type ];
// Ti.API.trace( "actionHandler: Triggering event - " + eventName );
// // console.error("listener count: " + Alloy.Globals.Events.listeners(event_name).length);
// this.trigger( eventName, e );
// } else if( e && e.source && e.source.collection_name && e.type === "change" ) {
// eventName = e.source.collection_name + "::change";
// apm.leaveBreadcrumb( __prefix + "Triggering event - " + event_name );
// // console.error("listener count: " + Alloy.Globals.Events.listeners(event_name).length);
// this.trigger( eventName, e );
// }
// apm.leaveBreadcrumb( __prefix + "exiting" );
// __prefix = null;
// };
// Navigator.prototype.on( "nav::open::**", function( e, args ) {
// var __prefix = __modulename + " nav::open::** ";
// apm.leaveBreadcrumb( __prefix + "entering" );
// var commands = parseEventHorizon( this.event, args );
// if( commands.length < 3 ) {
// console.error( "[frame] Attempted to call nav::open with no target" );
// apm.leaveBreadcrumb( __prefix + "exiting" );
// __prefix = null;
// return;
// }
// this.push( commands[ 2 ], commands[ 3 ] || args );
// apm.leaveBreadcrumb( __prefix + "exiting" );
// __prefix = null;
// } );
// // events.on( "nav::open::*", function() {
// // var __prefix = __modulename + "nav::open::* ";
// // apm.leaveBreadcrumb( __prefix + "entering" );
// // console.info( "event = " + this.event );
// // var split = this.event.split( "::" );
// // split.length > 2 && Navigator.topmost().go( split[ 2 ] );
// // apm.leaveBreadcrumb( __prefix + "exiting" );
// // __prefix = null;
// // } );
// Navigator.prototype.on( "nav::back", function() {
// var __prefix = __modulename + " nav::back ";
// apm.leaveBreadcrumb( __prefix + "entering" );
// console.info( "event = " + this.event );
// // Navigator.topmost().goBack();
// this.goBack();
// apm.leaveBreadcrumb( __prefix + "exiting" );
// __prefix = null;
// } );
// Navigator.prototype.on( "nav::*", function() {
// var __prefix = __modulename + " nav::* ";
// apm.leaveBreadcrumb( __prefix + "entering" );
// console.info( "nav event = " + this.event );
// apm.leaveBreadcrumb( __prefix + "exiting" );
// __prefix = null;
// } );