define(['mmirf/resources','mmirf/util/deferred','mmirf/util/loadFile','mmirf/util/isArray','mmirf/paramsParseFunc','mmirf/logger', 'module', 'require'],
/**
* A Utility class to support various functions.<br>
*
*
* @class mmir.CommonUtils
* @name mmir.CommonUtils
* @static
* @hideconstructor
*
* @public
*
* @requires Resources (optionally: jQuery)
* @requires mmir.SemanticInterpreter (in {@link mmir.CommonUtils#loadCompiledGrammars})
*
* @requires util/isArray
* @requires util/deferred in #loadImpl, #loadDirectoryStructure, #setToCompatibilityMode
* @requires util/loadFile in #loadDirectoryStructure
*
*
* @example var isList = mmir.CommonUtils.isArray(list);
*
*/
function(
resources, deferred, loadFile, _isArray, paramsParseFunc, Logger, module, require
) {
/** @scope mmir.CommonUtils.prototype *///for jsdoc2
/**
* @private
* @type CommonUtils
* @memberOf mmir.CommonUtils#
*/
var instance = null;
/**
* @private
* @type mmir.tools.Logger
* @memberOf mmir.CommonUtils#
*/
var logger = Logger.create(module);
/**
* @private
* @type mmir.tools.Logger
* @memberOf mmir.CommonUtils#
*/
var _conf = module.config(module);
/**
* JSON-Object containing the directory Structure of the application. Only
* directories defined by the Property
* {@link CommonUtils-constructor-directoriesToParse} are contained
* within the JSON-Object.
*
* @type JSON
* @private
* @memberOf mmir.CommonUtils#
*/
this.directoryStructure;
/**
* Constructor-Method of Class {@link mmir.CommonUtils}
*
* @param {Resources} res
* the resources-provider (e.g. URL for base directory etc)
*
* @constructs mmir.CommonUtils
* @memberOf mmir.CommonUtils#
* @function
* @private
*/
function constructor(res) {
// private members.
/**
* The Prefix for the file names of partial-files.<br>
* Files named <PARTIAL-PREFIX>filename.ehtml inside a
* views-directory are recognized as partials.
*
* @type String
* @private
*/
var partialsPrefix = '~';
/**
* Protocol / prefix that is used URIs to indicate to load scripts via require()
* instead of loading via ≶script> tags:
*
* @type String
* @private
* @example
*
* mmir.util.loadScript('require://controllers/calendar', function(...
* ->
* mmir.require(['controllers/calendar'], function(...
*/
var reqProtocol = 'require://';
/**
* RegExp for testing if URL starts with {@link #reqProtocol}
*
* @type RegExp
* @private
*/
var testReq = new RegExp('^'+reqProtocol.replace('/', '\\/'));
// /**
// * Array of Directories (Strings) to parse at the starting process<br>
// * those directories are then accessable by the functions
// * {@link mmir.CommonUtils#listDir}
// *
// * TODO read from properties (implement mechanism such that
// * \build.settings and this refer to the same resource)
// *
// * @type Array
// * @private
// */
// var directoriesToParse = [
// "controllers",
// "views",
// "models",
// "config",
// "helpers"
// ];
/** @lends mmir.CommonUtils.prototype */
return {
/**
* Helper function for
* {@link mmir.CommonUtils#listDir}
* to clear-up/normalize the pathname parameter
*
* @function
* @private
* @param {string}
* pathname The path that should be stripped of "file://" and a
* beginning or trailing "/"
* @returns {String} The stripped pathname - devoid of beginning "file://"
* or "/" and trailing "/"
*
* @memberOf mmir.CommonUtils.prototype
*/
stripPathName: function(pathname) {
// FIXME this is a HACK; TODO handle this in a general way!
var basePath = res.getBasePath();
if(basePath){
//helper: check if string starts with basePath (case-sensitive)
var re = new RegExp('^'+basePath);
if (re.test(pathname)) {
pathname = pathname.substring(basePath.length);
}
}
if (pathname.indexOf("file://") !== -1) {
pathname = pathname.replace("file://", "");
}
if (pathname[pathname.length - 1] === "/") {
pathname = pathname.substring(0, pathname.length - 1);
}
if (pathname[0] !== "/") {
pathname = "/" + pathname;
}
return pathname;
},
// public members.
/**
* @function
* @public
* @returns {String} The Prefix for the file names of partial-files
* @memberOf mmir.CommonUtils.prototype
*/
getPartialsPrefix : function() {
return partialsPrefix;
},
/**
* @function
* @public
* @returns {Object} Directory structure as json object
* @memberOf mmir.CommonUtils.prototype
*/
getDirectoryStructure : function() {
return this.directoryStructure;
},
/**
* extracts all the strings from a String-Array into a single string
*
* @function
* @public
* @returns {string} text
* @memberOf mmir.CommonUtils#
*/
concatArray : function(array) {
return array.join(', ');
},
/**
* Regular Expression for matching HTML comments.<br>
*
* This RegExp also matches multi-line comments.
*
* Note upon using the RegExp that it does not consider if a HTML
* comment is specified within a String or data-definition (i.e. the
* comment is matched regardless were its defined).
*
* @type String|RegExp
* @public
* @memberOf mmir.CommonUtils.prototype
*
* @example <!-- some comment -->
*/
regexHTMLComment : /<!--([\r\n]|.)*?-->/igm,
/**
* Protocol / prefix that is used URIs to indicate to load scripts via require()
* instead of loading via ≶script> tags:
*
* @type String
* @private
* @example
* mmir.util.loadScript('require://controllers/calendar', function(...
* ->
* mmir.require(['controllers/calendar'], function(...
*/
requireProtocol: reqProtocol,
/**
* Checks <code>uri</code> for "require://" protocol:
*
* If require-protocol, does <code>require()</code> the resource
* <pre>
* "require://controller/application" -> require('controller/application')
* </pre>
*
* Otherwise loads as URL via {@link #getLocalScript}.
*
* @function
* @async
* @param {String} uri
* the URI for the script: either require-recouse or file path/URL
* @param {Function}
* success success callback function
* @param {Function}
* fail fail callback function
*
* @see #getLocalScript
* @memberOf mmir.CommonUtils.prototype
*/
loadScript : function(uri, success, fail) {
if(testReq.test(uri)){
var reqUri = uri.substring(reqProtocol.length);
if(typeof WEBPACK_BUILD !== 'undefined' && WEBPACK_BUILD){
try {
var expModule = __webpack_require__(reqUri);
if(success){
setTimeout(function(){success.call(instance, expModule)}, 0);
} else {
logger.debug('CommonUtils', 'loadScript', 'Successfully required script from ' + uri);
}
} catch(e) {
if(fail){
setTimeout(function(){fail.call(instance, e)}, 0);
} else {
logger.error('CommonUtils', 'loadScript', 'Requiring script failed for "' + uri + '"', e);
}
}
return;
} else {
require([reqUri],
function(expModule){success? success.call(instance, expModule) : logger.debug('CommonUtils', 'loadScript', 'Successfully required script from ' + uri)},
function(err){fail? fail.call(instance, err) : logger.error('CommonUtils', 'loadScript', 'Requiring script failed for "' + uri + '"', e)}
);
return;
}
}
return this.getLocalScript(uri, success, fail);
},
/**
* Get the file path/name for a compiled grammar (executable JavaScript grammars).
*
* @function
* @param {String} generatedGrammarsPath Path of the grammars which should be loaded, e.g. <b>gen/grammar/</b>
* @param {String} grammarId the ID (e.g. language code) for the grammar
* @param {Boolean} [isFileNameOnly] OPTIONAL
* if TRUE then only the file name will be returned, otherwise the full path is returned
*
* @returns {String} file path / name for the compiled grammar
* (returns an empty string, if there is no compile grammar for the specified grammar ID)
*
* @public
* @memberOf mmir.CommonUtils.prototype
*/
getCompiledGrammarPath : function(generatedGrammarsPath, grammarId, isFileNameOnly) {
var files = instance.listDir(generatedGrammarsPath, /\.js$/i);//get *.js files
if(!files){
return '';
}
var f, index, id;
for(var i=0,size=files.length; i < size; ++i){
f = files[i];
index = f.lastIndexOf('.');
if (index !== -1) {
id = f.substring(0, index);
if(id === grammarId){
return isFileNameOnly || (typeof WEBPACK_BUILD !== 'undefined' && WEBPACK_BUILD)? files[i] : generatedGrammarsPath + files[i];
}
}
}
return '';
},
/**
* Get the IDs of compiled resources
*
* @function
* @param {String} compiledResourcesPath Path for the resources, e.g. <b>gen/grammar/</b>
*
* @returns {Array<String>} list of IDs for the compiled resources
*
* @public
* @memberOf mmir.CommonUtils.prototype
*/
getCompiledResourcesIds : function(compiledResourcesPath) {
var files = instance.listDir(compiledResourcesPath, /\.js$/i);//get *.js files
var ids = [];
if(!files){
return ids;
}
var f, m, re = typeof WEBPACK_BUILD !== 'undefined' && WEBPACK_BUILD? /^mmirf\/.+\/([^/]+)\.js$/i : /(.+)\.js$/i;
for(var i=0,size=files.length; i < size; ++i){
f = files[i];
m = re.exec(f);
if(m){
ids.push(m[1]);
}
}
return ids;
},
/**
* Load all compiled grammars (executable JavaScript grammars).
*
* @function
* @param {String} generatedGrammarsPath Path of the grammars which should be loaded, e.g. <b>gen/grammar/</b>
* @param {Function} cbFunction The function that should be executed after the plugins are loaded.
* If the execution of following functions is dependent on the presence of the grammars,
* they should be triggered from inside the callback-function.
* @param {Array<String>} [ignoreGrammarIds] OPTIONAL
* grammar IDs that should be ignored, i.e. not loaded, even if there is a file available
*
* @returns {Promise} a deferred promise (see loadImpl())
*
* @requires mmir.SemanticInterpreter (must be loaded as dependency "mmirf/semanticInterpreter" at least once before this function is loaded)
*
* @async
* @public
* @memberOf mmir.CommonUtils.prototype
*/
loadCompiledGrammars : function(generatedGrammarsPath, cbFunction, ignoreGrammarIds) {
return instance.loadImpl(
generatedGrammarsPath,
false,
cbFunction,
function isGrammarAlreadyLoaded(grammarFileName) {
// "file name" for webpack is "mmirf/grammar/<grammar ID>", otherwise the file-name is "<grammar ID>.js"
var m = (typeof WEBPACK_BUILD !== 'undefined' && WEBPACK_BUILD? /\/?([^/]+)$/ : /^(.+)\.js$/i).exec(grammarFileName);
if (m) {
var id = m[1];
if(ignoreGrammarIds){
for(var p in ignoreGrammarIds){
if(ignoreGrammarIds.hasOwnProperty(p) && ignoreGrammarIds[p] == id){
return true;
}
}
}
return require('mmirf/semanticInterpreter').hasGrammar(id);
} else {
return false;
}
},
function loadCompiledGrammarsStatus(status, fileName, msg) {
if (status === 'info') {
if(logger.isInfo()) logger.info('CommonUtils', 'loadCompiledGrammars', 'loaded "'+ fileName + '": ' + msg);
}
else if (status === 'warning') {
//filter "already loaded" warnings for ignored files:
if(ignoreGrammarIds && /already loaded/.test(msg)){
for(var p in ignoreGrammarIds){
if(ignoreGrammarIds.hasOwnProperty(p) && fileName.indexOf(ignoreGrammarIds[p]) === 0){
return;/////////////////////// EARLY EXIT ////////////////
}
}
}
if(logger.isWarn()) logger.warn('CommonUtils', 'loadCompiledGrammars', 'loading "'+ fileName + '": ' + msg);
}
else if (status === 'error') {
logger.error('CommonUtils', 'loadCompiledGrammars', 'loading "' + fileName + '": ' + msg);
}
else {
logger.error('CommonUtils', 'loadCompiledGrammars', status + ' (UNKNOWN STATUS) -> "' + fileName + '": ' + msg);
}
}
);
},
/**
* Load implementation files (i.e. JavaScript files) from a directory (if <tt>librariesPath</tt> is a String) or
* or a list of files-names (if <tt>librariesPath</tt> is an Array of Strings).
*
*
*
* @function
* @param {String|Array<String>} librariesPath
* Path (or list of of the plugins which should be loaded, e.g. <b>mmirf/plugins/</b>
* NOTE: The (String) path must be an entry in directories.json!
* (directories.json is used to generate/"query" the file-list for the path)
*
* @param {Boolean} isSerial
* Set <code>true</code> if the libraries should be loaded serially, i.e. synchronously, that is "one after the other" (later ones may depend on earlier ones).
* set <code>false</code> if libraries should be loaded in parallel, i.e. "asychronously" (NOTE in this case, the libraries must not depend on each other).
*
* NOTE: The loading process as a hole is asynchronous (regardless of parameter <tt>isSerial</tt>),
* i.e. loading is completed when <tt>completedCallback()</tt> is invoked,
* NOT when this function returns!
*
* @param {Function} [completedCallback]
* The function that should be executed after the libraries are loaded.
* If the execution of following functions is dependent on the presence of the libraries,
* they should be capsuled inside this callback-function.
* @param {Function} [checkIsAlreadyLoadedFunc]
* If provided, this function checks (based on the file-name), if the library is already
* loaded.
* The signature for the callback is <code>checkIsAlreadyLoadedFunc(String fileName) return [true|false]</code>,
* i.e. the function may check - based on the file-name - if the library is already loaded.
* If the function returns <tt>true</tt>, the library will not be loaded, and loading continues
* with the next library-file.
*
* NOTE: if <tt>isSerial</tt> is <tt>false</tt>, libraries with lower indices in the list may
* still be loading, when later entries are checked with this callback. In consequence,
* the "is already loaded"-check may not be accurate, in case parallel loading is
* used and the library-list contains "duplicate" entries.
* @param {Function} [statusCallback]
* If provided, this function is invoked, when a library was loaded loaded (INFO) or an
* error occurs.
* The signature for the callback is
* <code>statusCallback(String statusLevel, String fileName, String message, [result])</code>
* where <tt>statusLevel</tt> is one of <tt>info, warning, error</tt>,
* <tt>fileName</tt> is the file-name for the library that this status message concerns, and
* <tt>message</tt> is a message text with details concerning the status, and OPTIONALLY
* <tt>result</tt> is the result (may be undefined if no result is returned; the actual value may depend on the execution environment)
*
* @returns {Promise} a deferred promise that will be fulfilled when loadImpl() has finished.
*
* @async
* @public
* @memberOf mmir.CommonUtils.prototype
*/
loadImpl: function (librariesPath, isSerial, completedCallback, checkIsAlreadyLoadedFunc, statusCallback){
var _defer = deferred();
if(completedCallback){
_defer.then(completedCallback, completedCallback);
}
var isIds = false;//<- interpret file-entries as IDs (or as file-names, i.e. "as-is")
var theFileList;
if(typeof librariesPath === 'string'){
theFileList = instance.listDir(librariesPath, /\.js$/ig) || [];//get *.js files
if(typeof WEBPACK_BUILD !== 'undefined' && WEBPACK_BUILD){
isIds = true;
librariesPath = reqProtocol;
theFileList = theFileList.map(function(file){ return file.replace(/\.js$/ig, '')});
} else {
isIds = true;
theFileList = theFileList.map(function(file){
var m;
if(m = /^mmirf\/(.+)\/([^/]+)$/.exec(file)){
return reqProtocol + librariesPath + m[2].replace(/\.js$/ig, '');
} else {
return librariesPath + file;
}
});
librariesPath = '';
}
}
else {
theFileList = librariesPath;
librariesPath = '';
}
var size = theFileList.length;
var progress = 0;
var doLoadImplFile = function doLoadImplFile(fileList, index){
if( ! index){
index = 0;
}
var fileName = fileList[index];
//handler that is invoked after file has been processed (loaded or omitted):
var handleScriptDone = function(){
//"notify" that this file has been DONE:
++progress;
//check: are all entries of the list done?
if (progress < size){
if( isSerial ){
//synchronous load: load next entry recursively, when previous, i.e. this, one has finished:
doLoadImplFile(fileList, index+1);
}
//all entries already have been processed -> stop now.
return;
}
//ASSERT: all entries of the file-list are DONE -> trigger completedCallback by resolving deferred
_defer.resolve();
};
var displayFileName = fileName;
if(isIds){
displayFileName = fileName.replace(/^.+\//, '');
}
if ( checkIsAlreadyLoadedFunc && checkIsAlreadyLoadedFunc(displayFileName) ){
if(statusCallback){
statusCallback('warning', displayFileName, 'already loaded ' + librariesPath+displayFileName);
}
handleScriptDone();
} else {
instance.loadScript(librariesPath + fileName,
function(result){
if(statusCallback){
statusCallback('info', displayFileName, 'done loading ' + librariesPath+displayFileName, result);
}
handleScriptDone();
},
function(exception) {
if(statusCallback){
statusCallback('error', displayFileName, 'could not load "' + librariesPath+displayFileName + '": ' + exception);
}
else {
// print out an error message
logger.error('[loadImpl] Could not load "' + librariesPath+displayFileName + '": ', exception);
}
//NOTE: in case of an error, will still try to load the other files from the list:
handleScriptDone();
}
);//END: localScript(callbacks)
}
};//END: doLoadImplFile(name,index)
if(logger.isVerbose()) logger.verbose('about to load all libraries from path "'+librariesPath+'"...');
if(size < 1){
//if there are no files to resolve:
// immediately resolve Promise / trigger callback
_defer.resolve();
}
else if( ! isSerial){
//asynchronous load: trigger loading for all at once:
for(var counter=0; counter < size; ++counter){
doLoadImplFile(theFileList, counter);
}
}
else {
//synchronous load: start with first (the next one will be loaded recursively, when the first one was loaded)
doLoadImplFile(theFileList);
}
return _defer;
},
/**
* Detects via the user-agent-string if the application is running
* on Android.
*
* @function
* @public
* @returns {Boolean} <b>True</b> if application is running on
* Android, <b>False</b> otherwise
*
* @memberOf mmir.CommonUtils.prototype
*/
isRunningOnAndroid : function() {
// Testing if user-Agent-/ or appVersion-String contains 'android'
if ((navigator.userAgent.toLowerCase().indexOf("android") > -1)
|| (navigator.appVersion.toLowerCase().indexOf("android") > -1)) {
return true;
}
else {
return false;
}
},
/**
* Should detect - via the user-agent-string - if the application is
* running on Android, Symbian or iOS; in other words: on a
* smartphone.
*
* @function
* @public
* @returns {Boolean} <b>True</b> if application is running on
* smartphone, <b>False</b> otherwise
*
* @memberOf mmir.CommonUtils.prototype
*/
isRunningOnSmartphone : function() {
// Testing if user-Agent-/ or appVersion-String contains
// 'Android' or 'iOS'
// at the moment only Android-, iOS and Symbian-strings are 'implemented'
var testString = navigator.userAgent.toLowerCase()
+ navigator.appVersion.toLowerCase();
if ((testString.indexOf("android") > -1)
|| (testString.indexOf("ios") > -1)
|| (testString.indexOf("symbian") > -1)) {
return true;
}
else {
return false;
}
},
/**
*
* Similar to the jQuery.getScript() function - appending a <script>
* element for javascript-source to the header of the main document.
*
* The success-callback is invoked if the script was
* successfully loaded, otherwise the fail-callback.
*
* @function
* @param {String}
* scriptUrl source of javascript-file
* @param {Function}
* success success callback function
* @param {Function}
* fail fail callback function
* @async
* @public
* @memberOf mmir.CommonUtils.prototype
*/
getLocalScript : function(scriptUrl, success, fail) {
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = scriptUrl;
script.onload = function(evt) {
if(success){
success.call(instance, evt);
} else {
logger.debug('CommonUtils', 'getLocalScript', 'Successfully loaded script from ' + scriptUrl)
}
};
script.onerror = function(e) {
if(fail){
fail.call(instance, e);
} else {
logger.error('CommonUtils', 'getLocalScript', 'Loading script failed for "' + scriptUrl + '"', e);
}
};
head.appendChild(script);
},
/**
* This function returns an array of strings (file names) with the contents of
* the directory <code>pathname</code>.
*
* The <code>pathname</code> must be one of the directories (or sub-directories)
* of the framework's parsed folders, see {@link #directoriesToParse}.
*
* If a <code>filter</code> is use, only files which's names match
* the filter are included in the returned list.
*
* @function
* @param {String} pathname
* Path of the directory which's contents should be
* returned
* @param {RegExp|Function} [filter]
* Filter for file-names:
* if <code>String</code> the file-name or part of the file-name (no wild cards!)
* (comparison is <b>not case-sensitive</b>),
* e.g.: <b>someFile.js</b>, <b>.js</b> or <b>myview.ehtml</b>
* if <code>RegExp</code> the file-name must match the regular expression,
* e.g.: <b>/.*\.js/ig</b> or <b>/^.*\.ehtml$/ig</b>
* if <code>Function</code> the file-name is included, if the function returns <code>true</code>,
* where the function signature is <code>function(fileName: String) : Boolean</code>,
* note that argument <code>fileName</code> will have been transformed to lower-case characters
*
* @public
* @returns {Array} Array of Strings which contains the contents of
* the directory.
* Or <code>null</code>, if <code>pathname</code> is not one of the framework's
* parsed folders.
*
* @memberOf mmir.CommonUtils.prototype
*/
listDir : function(pathname, filter) {
pathname = this.stripPathName(pathname);
var tmp = this.directoryStructure[pathname];
if (typeof tmp === 'undefined') {
logger.debug('CommonUtils', 'listDir', 'path "' + pathname + '" not found.');
return null;////////////////// EARLY EXIT ///////////////////////////////
} else if(!filter){
return tmp;////////////////// EARLY EXIT ///////////////////////////////
}
var retValue = [];
var isFunc = typeof filter === 'function';
var strFilter = typeof filter === 'string' && filter.toLowerCase();
var isMatch, entry;
for (var i = 0, size = tmp.length; i < size; ++i) {
entry = tmp[i];
if(strFilter){
isMatch = entry === filter || (entry && entry.toLowerCase().indexOf(strFilter) !== -1);
} else if(!isFunc){
//reset search-position for RegExp
filter.lastIndex = 0;
isMatch = filter.test(entry);
} else {
isMatch = filter(entry);
}
if(isMatch) {
retValue.push(entry);
}
}
return retValue;
},
/**
* Checks if an object is an <code>Array</code>.
*
* <p>
* This function can be safely run in arbitrary contexts, e.g.
*
* <pre>
* var checkArray = mmir.CommonUtils.isArray;
* if( checkArray(someObject) ){
* ...
* </pre>
*
* @function
* @param {Object}
* object the Object for checking if it is an Array
* @public
* @returns {Boolean} <code>true</code> if <code>object</code>
* is an <code>Array</code>, otherwise
* <code>false</code>.
*
* @memberOf mmir.CommonUtils.prototype
*/
isArray : function(object) {
return _isArray(object);
},
/**
*
* IMPORTED FROM paramsParseFunc.js
* <p>
*
* Convert parameter-part of an URL to a "dictionary", containing
* the parameter keys and values
* <p>
*
* <code>?id=5&name=heinz&name=kunz</code> →
* <pre>
* {
* id: "5",
* name: ["heinz", "kunz"],
*
* //utility functions
* has: function(key) : Boolean,
* isMultiple: function(key) : Boolean,// is entry an Array of values
* getKeys: function() : String[], // get list of all keys
* }
* </pre>
* <p>
*
* The returned "dictionary" has the following functions:
* <ul>
* <li>has(String key): returns <code>true</code> if the
* dictionary contains an entry for <code>key</code></li>
* <li>isMultiple(String key): returns <code>true</code> if the
* entry for <code>key</code> is an Array (i.e. the URL contained
* multiple values for this key)</li>
* <li>getKeys(): returns an Array with the keys (String) for all
* entries</li>
* </ul>
*
* @function
* @param {String} urlParamsPartStrings
* the parameter-part of the URL, i.e. <code>&...</code>
* @return {Object} a "dictionary" for the parameters
* @public
* @memberOf mmir.CommonUtils.prototype
*/
parseParamsToDictionary : paramsParseFunc,
/**
* This function is used check whether a network connection is
* enabled. </br> This version of checking the network connection is
* based on the cordova 2.3.0 API.
*
* TODO implement with HTML5 functions (in addition to / instead of
* cordova)?
*
* @requires Cordova: org.apache.cordova.network-information
*
* @function
* @public
* @returns {Boolean} <code>true</code> if a network connection is enabled
*
* @memberOf mmir.CommonUtils.prototype
*/
checkNetworkConnection : function() {
if(logger.isVerbose()) logger.verbose("Checking network status...");
if(typeof navigator === 'undefined'){
logger.error('Cannot check network status: navigator object is not available!');
return 'UNKNOWN';
}
//ASSERT: navigator exists
if(!navigator.connection || !navigator.connection.type || typeof Connection === 'undefined'){
if(logger.isInfo()) logger.info('Cannot use Cordova plugin network-information for checking network status: object navigator.connection is not available');
if(typeof navigator.onLine !== 'undefined'){
return navigator.onLine;
}
else {
return 'UNKNOWN';
}
}
var networkState = navigator.connection.type;
//TODO make states-obj a 'private' field of CommonUtils
var states = {};
states[Connection.UNKNOWN] = 'Unknown connection';
states[Connection.ETHERNET] = 'Ethernet connection';
states[Connection.WIFI] = 'WiFi connection';
states[Connection.CELL_2G] = 'Cell 2G connection';
states[Connection.CELL_3G] = 'Cell 3G connection';
states[Connection.CELL_4G] = 'Cell 4G connection';
states[Connection.CELL] = 'Cell generic connection';
states[Connection.NONE] = 'No network connection';
if (Connection.NONE === networkState){
//alert('Connection type: ' + states[networkState]);
return false;
}
return true;
},
/**
* Parses the directory structure and stores the result in the class-property {@link mmir.CommonUtils-directoryStructure}
*
* @function
* @param {Function} [success] The function that should be executed after the diretories are parsed - it's best to include all following functions inside the callback-function.
* @param {Function} [errorFunc] callback function that is invoked if an error occured during initialization.
* @async
* @public
* @memberOf mmir.CommonUtils.prototype
*/
loadDirectoryStructure: function (success, errorFunc) {
var _defer = deferred();
var self = this;
if(success || errorFunc){
_defer.then(success, errorFunc);
}
if(_conf && _conf.directories){
setTimeout(function(){
if(logger.isVerbose()) logger.verbose("DirectoryListing.getDirectoryStructure: loaded from module.config().directories");
self.directoryStructure = _conf.directories;
if(logger.isVerbose()) logger.verbose("[getDirectoryStructure] finished.");
_defer.resolve(self);
}, 0);
return _defer;/////////////////// EARLY EXIT //////////////////////
}
var directoryFileUrl = res.getDirectoriesFileUrl();
//load configuration file asynchronously:
loadFile({
async: true,
dataType: "json",
url: directoryFileUrl,
success: function(data){
if(logger.isVerbose()) logger.verbose("DirectoryListing.getDirectoryStructure: loaded file from "+directoryFileUrl);
if(data){
if(logger.isVerbose()) logger.verbose("DirectoryListing.getDirectoryStructure: Succeeded to load directory structure from '"+directoryFileUrl+"'! Data: "+ JSON.stringify(data));
self.directoryStructure = data;
if(logger.isVerbose()) logger.verbose("[getDirectoryStructure] finished.");
_defer.resolve(self);
}
},
error: function(jqXHR, textStatus, errorThrown){
if(logger.isVerbose()) logger.verbose("DirectoryListing.getDirectoryStructure: failed to load file from '"+directoryFileUrl+"'! Status "+textStatus+": "+ errorThrown+ ", "+JSON.stringify(jqXHR));
var msg = "[ERROR] " + textStatus+": failed to load file from '"+directoryFileUrl+"' - "+ errorThrown;
if( ! errorFunc){
logger.error('CommonUtils', 'loadDirectoryStructure', msg);
}
_defer.reject(msg);
}
});
return _defer;
},
init: function(success, errorFunc){
var initPromise;
//use the Deferred from load-dir-struct, since this is the only async initialization atm:
initPromise = this.loadDirectoryStructure.apply(this, arguments);
//replace init so that we do not ivoke load-dir-struct multiple times
this.__initDeferred = initPromise;
this.init = function initCompleted(onsuccess, onerror){
if(onsuccess || onerror){
this.__initDeferred.then(success, onerror);
}
return this.__initDeferred;
};
return initPromise;
}
};// END: return {...
}// END: constructor()
instance = new constructor(resources);
return instance;
});