UNPKG

cordova-plugin-mfp

Version:

IBM MobileFirst Platform Foundation Cordova Plugin

626 lines (499 loc) 20.8 kB
// 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 */ 'use strict'; // 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;