cordova-plugin-mfp
Version:
IBM MobileFirst Platform Foundation Cordova Plugin
626 lines (499 loc) • 20.8 kB
JavaScript
// Licensed Materials - Property of IBM
// 5725-I43 (C) Copyright IBM Corp. 2015. All Rights Reserved.
// US Government Users Restricted Rights - Use, duplication or
// disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
/*jslint node:true */
/*jshint node:true */
;
// Public modules
var eTree = require('elementtree');
var subElement = eTree.SubElement;
var log = require('npmlog');
var CordovaConfigXMLParser =
require('../cordova-lib/configparser/ConfigParser.js');
// Private modules
var consts = require('./config-xml-constants.js');
var strings = require('ibm-strings');
// Create a SubClass of ConfigParser for MFP Config.xml updates
var InheritanceManager = {};
InheritanceManager.extend = function(subClass, baseClass) {
function Inheritance() {
}
Inheritance.prototype = baseClass.prototype;
subClass.prototype = new Inheritance();
subClass.prototype.constructor = subClass;
subClass.baseConstructor = baseClass;
subClass.superClass = baseClass.prototype;
};
/*
This class provides API to read, write, and delete XML elements in a Cordova
config.xml file.
*/
var MFPConfigXMLParser = function (path, logLevel) {
var methodMap; // Map for all get, set, and delete methods
var that; // Points to this
CordovaConfigXMLParser.call(this, path);
// Set log level
if (logLevel)
log.level = logLevel;
that = this;
methodMap = consts.METHOD_MAP;
logSilly(JSON.stringify(this, null, 2));
logSilly('Method map: ' + methodMap);
/*
Performs a log.silly() call on the message passed.
message - message to log
*/
function logSilly(message) {
log.silly(consts.MODULE, message);
}
/*
Performs a log.verbose() call on the message passed.
message - message to log
*/
function logVerbose(message) {
log.verbose(consts.MODULE, message);
}
/*
Deletes an element form the config xml file. The elementPath must be passed.
elementPath - Path of element to delete
*/
this.deleteElement = function (elementPath) {
var foundElements; // Found elements
var parentElement; // Parent of found elements
var elementRemoved; // Removed element
logVerbose('Deleting an element.');
elementPath = elementPath.join();
elementPath = elementPath.replace(/,/g, '');
elementPath = elementPath.replace(/\.\//g, '/');
elementPath = '.' + elementPath;
foundElements = that.doc.findall(elementPath);
elementRemoved = false;
logSilly('Element path: ' + elementPath);
logSilly('Found elements: ' + foundElements);
// Get the first occurrence of the element
if (foundElements[0]) {
parentElement = that.doc.find(elementPath + '/..');
// Remove the element
if (parentElement)
parentElement.remove(foundElements[0]);
else
that.doc.getroot().remove(foundElements[0]);
elementRemoved = true;
logVerbose('Deleted element.');
logSilly('Deleted element path: ' + elementPath);
} else {
logVerbose('Could not find element.');
logSilly('Could not find path: ' + elementPath);
}
return elementRemoved;
};
/*
Returns a attribute value from the passed path, and key. The elementPath,
and attributeKey must be passed.
elementPath - Path to element
attributeKey - Key to read from
*/
this.getValue = function (elementPath, attributeKey) {
var foundElements; // Found elements
var attribValue; // Attribute key value
elementPath = elementPath.split(',');
elementPath = elementPath.join();
elementPath = elementPath.replace(/,/g, '');
elementPath = elementPath.replace(/\.\//g, '/');
elementPath = '.' + elementPath;
foundElements = that.doc.findall(elementPath);
logSilly('Getting XML value.');
logSilly('Element path: ' + elementPath);
logSilly('Attribute key: ' + attributeKey);
logSilly('Found elements: ' + foundElements);
// Get the first occurrence of the element
if (foundElements[0]) {
if (attributeKey)
attribValue = foundElements[0].get(attributeKey);
else
attribValue = foundElements[0].text;
logSilly('Found element path' + elementPath + ' with key ' +
attributeKey + ' with value of ' + attribValue);
} else {
logSilly('Could not find path ' + elementPath +
' with attribute ' + attributeKey);
}
return attribValue;
};
/*
Sets an attribute key value for the path, and key passed. The elementPath,
attributeKey, and attributeValue must be passed.
elementPath - Path of element to write
attributeValue - Value to write
attributeKey - Key to write to
*/
this.setValue = function (elementPath, attributeValue, attributeKey) {
var isValueSet; // Flag denotes if value was set
var currentLocationInPath; // Current location in XML tree
var newLocationInPath; // Location to search
var matchingElements; // All matching elements
var cleanElement; // Scrubbed element
var endOfElementText; // End position in element
var elementAttributeKey; // Current attribute key
var elementAttributeValue; // Current attribute value
isValueSet = true;
elementPath = elementPath.split(',');
currentLocationInPath = that.doc;
logSilly('Setting XML value.');
logSilly('Element path: ' + elementPath);
logSilly('Attribute value: ' + attributeValue);
logSilly('Attribute key: ' + attributeKey);
elementPath.forEach(function(element, index) {
matchingElements = currentLocationInPath.findall(element);
// Check for any matching elements
if (matchingElements.length !== 0)
newLocationInPath = matchingElements[0];
else {
cleanElement = element.substr(2);
endOfElementText = cleanElement.indexOf('/[@');
// Add found element key, and value to the element
if (endOfElementText >= 0) {
elementAttributeKey =
cleanElement.substr(endOfElementText+3,
cleanElement.indexOf('='));
elementAttributeKey = elementAttributeKey.substr(0,
elementAttributeKey.indexOf('=')).trim();
elementAttributeValue =
cleanElement.substr(cleanElement.indexOf('=') + 2);
elementAttributeValue = elementAttributeValue.substr(0,
elementAttributeValue.indexOf('"')).trim();
cleanElement = cleanElement.substr(0, endOfElementText);
}
// Set the index to the current index
if (index === 0)
newLocationInPath = subElement(that.doc.getroot(),
cleanElement);
else
newLocationInPath = subElement(currentLocationInPath,
cleanElement);
if (elementAttributeKey && elementAttributeValue)
newLocationInPath.set(elementAttributeKey,
elementAttributeValue);
}
// update the current location in path
currentLocationInPath = newLocationInPath;
elementAttributeKey = undefined;
elementAttributeValue = undefined;
});
// Update the element at the current location
if (attributeKey)
currentLocationInPath.set(attributeKey, attributeValue);
else
currentLocationInPath.text = attributeValue;
return isValueSet;
};
/*
Outputs the XML stored in memory to XML file passed to the constructor. An
error is thrown if the write operation does not occur.
*/
this.writeToFile = function () {
// Attempt to write to config.xml
try {
this.write();
} catch (err) {
throw err;
}
return true;
};
/*
Returns a string containing a method to get a platform attribute.
path - Path to platform
attrib - Attribute to return
*/
function getPlatformAttribMethod(path, attrib) {
return strings.format(consts.GET_PLATFORM_ATTRIB, path.ios,
path.android, path.win8, path.winphone8, path.win10, attrib);
}
/*
Returns a string containing a method to get a platform attribute.
Alternative platforms handling of just android, ios, windows (parent windows
container)
path - Path to platform
attrib - Attribute to return
*/
function getPlatformAttribAltMethod(path, attrib) {
return strings.format(consts.GET_PLATFORM_ATTRIB_ALT, path.ios,
path.android, path.win, attrib);
}
/*
Returns a string containing a method to get an attribute.
path - Path to platform
attrib - Attribute to return
*/
function getAttribMethod(path, attrib) {
return strings.format(consts.GET_ATTRIB, path, attrib);
}
/*
Returns a string containing a method to get a platform text.
path - Path to platform
*/
function getPlatformText(path) {
return strings.format(consts.GET_PLATFORM_TEXT, path.ios, path.android,
path.win8, path.winphone8, path.win10);
}
/*
Returns a string containing a method to get a platform text.
Alternative platforms handling of just android, ios, windows (parent
windows container)
path - Path to platform
*/
function getPlatformTextAlt(path) {
return strings.format(consts.GET_PLATFORM_TEXT_ALT, path.ios,
path.android, path.win);
}
/*
Returns a string containing a method to get text.
path - Path to platform
*/
function getText(path) {
return strings.format(consts.GET_TEXT, path);
}
/*
Returns a string that contains a method to get a platform attribute,
platform text, attribute, or text from XML. The resultant string is
determined from that path, and attrib variables.
path - XML element path
attrib - XML attrib value
*/
function getMethod(path, attrib) {
var res; // Resultant method
logSilly('Creating get method.');
logSilly('Path: ' + path);
logSilly('Attrib: ' + attrib);
// Determine if the method gets an attribute
if (attrib) {
// Determine if the get attribute method is platform specific
if (path.android && path.ios && path.win8 && path.winphone8 &&
path.win10)
res = getPlatformAttribMethod(path, attrib);
else if (path.android && path.ios && path.win)
res = getPlatformAttribAltMethod(path, attrib);
else
res = getAttribMethod(path, attrib);
} else {
// Determine if the get text method is platform specific
if (path.android && path.ios && path.win8 && path.winphone8 &&
path.win10)
res = getPlatformText(path);
else if (path.android && path.ios && path.win)
res = getPlatformTextAlt(path);
else
res = getText(path);
}
logSilly('Get method: ' + res);
return res;
}
/*
Returns a string containing a method to set a platform attribute.
path - Path to platform
attrib - Attribute to return
*/
function setPlatformAttrib(path, attrib) {
return strings.format(consts.SET_PLATFORM_ATTRIB,path.ios, path.android,
path.win8, path.winphone8, path.win10, attrib);
}
/*
Returns a string containing a method to set a platform attribute.
Alternative platforms handling of just android, ios, windows (parent
windows container)
path - Path to platform
attrib - Attribute to return
*/
function setPlatformAttribAlt(path, attrib) {
return strings.format(consts.SET_PLATFORM_ATTRIB_ALT,path.ios,
path.android, path.win, attrib);
}
/*
Returns a string containing a method to set an attribute.
path - Path to platform
attrib - Attribute to return
*/
function setAttrib(path, attrib) {
return strings.format(consts.SET_ATTRIB, path, attrib);
}
/*
Returns a string containing a method to set a platform text.
path - Path to platform
*/
function setPlatformText(path) {
return strings.format(consts.SET_PLATFORM_TEXT, path.ios,
path.android, path.win8, path.winphone8, path.win10);
}
/*
Returns a string containing a method to set a platform text.
Alternative platforms handling of just android, ios, windows (paren
windows container)
path - Path to platform
*/
function setPlatformTextAlt(path) {
return strings.format(consts.SET_PLATFORM_TEXT_ALT, path.ios,
path.android, path.win);
}
/*
Returns a string containing a method to set text.
path - Path to platform
*/
function setText(path) {
return strings.format(consts.SET_TEXT, path);
}
/*
Returns a string that contains a method to set a platform attribute,
platform text, attribute, or text from XML. The resultant string is
determined from that path, and attrib variables.
path - XML element path
attrib - XML attrib value
*/
function setMethod(path, attrib) {
var res; // Resultant method
logSilly('Creating set method.');
logSilly('Path: ' + path);
logSilly('Attrib: ' + attrib);
// Determine if the method sets an attribute
if (attrib) {
// Determine if the set attribute method is platform specific
if (path.android && path.ios && path.win8 && path.winphone8 &&
path.win10)
res = setPlatformAttrib(path, attrib);
else if (path.android && path.ios && path.win)
res = setPlatformAttribAlt(path, attrib);
else
res = setAttrib(path, attrib);
} else {
// Determine if the set text method is platform specific
if (path.android && path.ios && path.win8 && path.winphone8 &&
path.win10)
res = setPlatformText(path);
else if (path.android && path.ios && path.win)
res = setPlatformTextAlt(path);
else
res = setText(path);
}
logSilly('Set method: ' + res);
return res;
}
/*
Returns a string containing a method to delete a platform element.
path - Path to element to delete
*/
function deletePlatformElement(path) {
return strings.format(consts.DELETE_PLATFORM_ELEMENT, path.ios,
path.android, path.win8, path.winphone8, path.win10);
}
/*
Returns a string containing a method to delete a platform element.
Alternative platforms handling of just android, ios, windows (parent windows
container)
path - Path to element to delete
*/
function deletePlatformElementAlt(path) {
return strings.format(consts.DELETE_PLATFORM_ELEMENT_ALT, path.ios,
path.android, path.win);
}
/*
Returns a string containing a method to delete an element.
path - Path to element to delete
*/
function deleteElement(path) {
strings.format(consts.DELETE_ELEMENT, path);
}
/*
Returns a string containing a method to delete a platform element, or an
element. The resultant string is determined from the path passed.
path - Element path to delete
*/
function deleteMethod(path) {
var res; // Resultant method
logSilly('Creating delete method.');
logSilly('Path: ' + path);
// Determine if the method deletes an attribute
if (path.android && path.ios && path.win8 && path.winphone8 &&
path.win10)
res = deletePlatformElement(path);
else if (path.android && path.ios && path.win)
res = deletePlatformElementAlt(path);
else
res = deleteElement(path);
logSilly('Delete method: ' + res);
return res;
}
/*
Dynamically adds get, set, and delete methods to the object. These methods
are created based on the methodMap.
*/
function initializeMethods() {
var getParams; // Parameters for the get methods
var setParams; // Parameters for the set methods
var deleteParams; // Paramters for the delete methods
logVerbose('Initializing get, set, and delete methods.');
// Initialize all get, set, and delete methods
for (var i = 0; i < methodMap.length; i++) {
logSilly('Initializing methods for ' + methodMap[i].name);
getParams = methodMap[i].param.concat(getMethod(methodMap[i].path,
methodMap[i].attrib));
that[consts.GET + methodMap[i].name] = Function.apply(that,
getParams);
setParams = [consts.VALUE].concat(methodMap[i].param.concat(
setMethod(methodMap[i].path, methodMap[i].attrib)));
that[consts.SET + methodMap[i].name] = Function.apply(that,
setParams);
deleteParams =
methodMap[i].param.concat(deleteMethod(methodMap[i].path));
that[consts.DELETE + methodMap[i].name] = Function.apply(that,
deleteParams);
}
}
/*
Writes default values to the XML file if the do not exist. Default values
are defined in the methodMap.
*/
function writeDefaults() {
// Write default values for all unwritten keys
for (var i = 0; i < methodMap.length; i++) {
logSilly('Determining if defaults needed for ' + methodMap[i].name);
// Determine if the write is platform specific
if (methodMap[i].param && methodMap[i].param.length > 0 &&
methodMap[i].param.indexOf(consts.PLATFORM) > -1) {
// Write default if value isn't defined
if (!that[consts.GET + methodMap[i].name](consts.ANDROID))
that[consts.SET + methodMap[i].name](
methodMap[i].defaultValue, consts.ANDROID);
// Write default if value isn't defined
if (!that[consts.GET + methodMap[i].name](consts.IOS))
that[consts.SET + methodMap[i].name](
methodMap[i].defaultValue, consts.IOS);
// Write default if value isn't defined
if (!that[consts.GET + methodMap[i].name](consts.WIN))
that[consts.SET + methodMap[i].name](
methodMap[i].defaultValue, consts.WIN);
// Write default if value isn't defined
if (!that[consts.GET + methodMap[i].name](consts.WIN8))
that[consts.SET + methodMap[i].name](
methodMap[i].defaultValue, consts.WIN8);
// Write default if value isn't defined
if (!that[consts.GET + methodMap[i].name](consts.WINPHONE8))
that[consts.SET + methodMap[i].name](
methodMap[i].defaultValue, consts.WINPHONE8);
// Write default if value isn't defined
if (!that[consts.GET + methodMap[i].name](consts.WIN10))
that[consts.SET + methodMap[i].name](
methodMap[i].defaultValue, consts.WIN10);
} else {
// Write default if value isn't defined
if (!that[consts.GET + methodMap[i].name]())
that[consts.SET + methodMap[i].name](
methodMap[i].defaultValue);
}
}
that.writeToFile();
}
initializeMethods();
writeDefaults();
};
InheritanceManager.extend(MFPConfigXMLParser, CordovaConfigXMLParser);
module.exports = MFPConfigXMLParser;