/**
* @license
* Copyright 2020 Roberto Luiz Souza Monteiro,
* Renata Souza Barreto,
* Hernane Borges de Barros Pereira.
*
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* MaiaScript system library.
* @class
*/
function System() {
init();
/**
* Creates the attributes of the class.
*/
function init() {
// Class attributes goes here.
}
/**
* Convert Unicode caracters to Latin1.
* @param {string} str - Unicode string.
* @return {string} The Unicode string converted to Latin1.
*/
this.base64EncodeUnicode = function(str) {
// First we escape the string using encodeURIComponent to get the UTF-8 encoding of the characters,
// then we convert the percent encodings into raw bytes, and finally feed it to btoa() function.
utf8Bytes = encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) {
return String.fromCharCode('0x' + p1);
});
return btoa(utf8Bytes);
}
/**
* Converts an array to a CSV file, using the character indicated as the column separator.
* @param {array} csvData - CSV data.
* @param {string} recordSeparator - The separator characters.
* @param {array} header - Column descriptors.
* @return {string} The CSV file data.
*/
this.createCSV = function(csvData, recordSeparator, header) {
if (typeof separator != 'undefined') {
var separator = ',';
}
if (typeof csvData != 'undefined') {
var fileContents = '';
if (typeof header != 'undefined') {
for (var i = 0; i < header.length; i++) {
fileContents += '"' + header[i] + '"';
if (i < header.length - 1) {
fileContents += recordSeparator;
}
}
fileContents += '\n';
}
for (var i = 0; i < csvData.length; i++) {
record = csvData[i];
for (var j = 0; j < record.length; j++) {
if (typeof record[j] == 'string') {
fileContents += '"' + record[j] + '"';
} else if (typeof record[j] == 'object') {
fileContents += JSON.stringify(record[j]);
} else {
fileContents += record[j];
}
if (j < record.length - 1) {
fileContents += recordSeparator;
}
}
fileContents += '\n';
}
return fileContents;
} else {
throw new Error('Invalid argument for function createCSV. Argument must be an array.');
}
}
/**
* Download a file.
* @param {string} fileName - File name.
* @param {string} fileData - Data to save.
* @param {string} mimeType - Mime type (default: 'text/plain').
* @return The file is downloaded.
*/
this.downloadFile = function(fileName, fileData, mimeType) {
if (typeof mimeType == 'undefined') {
var mimeType = 'text/plain';
}
var uri = 'data:' + mimeType + ';charset=utf-8;base64,' + this.base64EncodeUnicode(fileData);
var downloadLink = document.createElement('a');
downloadLink.href = uri;
downloadLink.download = fileName;
document.body.appendChild(downloadLink);
downloadLink.click();
document.body.removeChild(downloadLink);
}
/**
* Converts a CSV record to an array, using the character indicated as the column separator.
* @param {string} csvData - CSV file data.
* @param {number} numberOfHeaderLines - Number of header lines and column descriptors to ignore.
* @param {string} recordSeparator - The separator characters.
* @param {boolean} allowRepeatChar - The separator character can be repeated (for formatting).
* @param {boolean} doEval - Run core.eval before adding the column to the record.
* @return {array} The array containing the parts of the CSV or NULL if the CSV record is not well formed.
*/
this.parseCSV = function(csvData, numberOfHeaderLines, recordSeparator, allowRepeatChar, doEval) {
if (typeof csvData != 'undefined') {
var fileLines = core.split(csvData, '\r\n');
var csvArray = [];
for (i = numberOfHeaderLines; i < fileLines.length; i++) {
var record = core.splitCSV(fileLines[i], recordSeparator, allowRepeatChar, doEval);
csvArray.push(record);
}
return csvArray;
} else {
throw new Error('Invalid argument for function loadCSV. Argument must be a string.');
}
}
/**
* Displays a message in the console.
* @param {string} text - Text to display.
*/
this.log = function(text) {
console.log(text);
}
/**
* Loads a CSV file and converts it to an array, using the character indicated as the column separator.
* @param {string} inputFile - CSV file.
* @param {number} numberOfHeaderLines - Number of header lines and column descriptors to ignore.
* @param {string} recordSeparator - The separator characters.
* @param {boolean} allowRepeatChar - The separator character can be repeated (for formatting).
* @param {boolean} doEval - Run core.eval before adding the column to the record.
* @return {array} The array containing the parts of the CSV or NULL if the CSV record is not well formed.
*/
this.loadCSV = function(inputFile, numberOfHeaderLines, recordSeparator, allowRepeatChar, doEval) {
if (typeof process != 'undefined') {
var fs = require('fs');
var readTextFile = fs.readFileSync;
function getXml(data) {
compiledCode.xml += data;
}
function read(input) {
if (/^{.*}$/.test(input)) {
return input.substring(1, input.length - 1);
} else {
var content = readTextFile(input, 'utf-8');
return content.length > 0 && content.charCodeAt(0) == 0xFEFF ? content.substring(1) : content;
}
}
if (typeof inputFile != 'undefined') {
var fileContents = read(String(inputFile));
return this.parseCSV(fileContents, numberOfHeaderLines, recordSeparator, allowRepeatChar, doEval);
} else {
throw new Error('Invalid argument for function parseCSV. Argument must be a string.');
}
}
}
/**
* Displays a message in the console.
* @param {string} text - Text to display.
*/
this.print = function(text) {
this.log(text);
}
/**
* Displays a formated string based on format specifiers passed to the function.
* @param {string} fmt - A string containing format specifiers.
* @param {object} arguments - Objects to be formatted.
* @return {string} A formatted string based on format specifiers passed to the function.
*/
this.printf = function(fmt) {
this.log(string.sprintFormat(string.sprintfParse(fmt), arguments));
}
/**
* Displays a message on the console and advances the cursor to the next line.
* @param {string} text - Text to display.
*/
this.println = function(text) {
this.log(text + '\r\n');
}
/**
* Reads data from browser storage.
* @param {object} obj - Object to store data: {'key': value, 'key': value, ...}
* @param {object} callBack - Callback function to call after access to storage.
* @return Data from storage.
*/
this.readDataFromStorage = function(obj, callBack) {
for (key in obj) {
if (typeof localStorage.getItem(key) != 'undefined') {
obj[key] = localStorage.getItem(key);
} else {
obj[key] = {};
}
}
if (typeof callBack != 'undefined') {
callBack();
}
}
/**
* Imports a native module.
* @param {string} moduleName - Module name.
* @return {object} The native module reference.
*/
this.require = function(moduleName) {
var moduleReference;
if (typeof process !== 'undefined') {
var moduleReference = require(moduleName);
}
return moduleReference;
}
/**
* Displays a message in a dialog box asking for confirmation.
* @param {string} text - Text to display.
* @return {string} User choice.
*/
this.showConfirmDialog = function(text) {
return confirm(text);
}
/**
* Displays a message in a dialog box asking you to enter text.
* @param {string} text - Text to display.
* @param {string} defaultText - Default text to display in the text box.
* @return {string} User-typed text.
*/
this.showInputDialog = function(text, defaultText = '') {
return prompt(text, defaultText);
}
/**
* Displays a message in a dialog box.
* @param {string} text - Text to display.
*/
this.showMessageDialog = function(text) {
alert(text);
}
/**
* Load a MaiaScript module.
* @param {string} inputFile - Module name.
* @return {object} The MaiaScript module loaded.
*/
this.source = function(inputFile) {
if (typeof process != 'undefined') {
var fs = require('fs');
var readTextFile = fs.readFileSync;
function getXml(data) {
compiledCode.xml += data;
}
function read(input) {
if (/^{.*}$/.test(input)) {
return input.substring(1, input.length - 1);
} else {
var content = readTextFile(input, 'utf-8');
return content.length > 0 && content.charCodeAt(0) == 0xFEFF ? content.substring(1) : content;
}
}
if (typeof inputFile != 'undefined') {
var code = read(String(inputFile));
core.eval(code, global);
} else {
throw new Error('Invalid argument for function source. Argument must be a string.');
}
}
}
/**
* Upload a file.
* @param {object} fileObject - File data structure.
* @param {function} callBack - callback to be called when the file is loaded.
* @return The file is uploaded.
*/
this.uploadFile = function(fileObject, callBack) {
var input = document.createElement('input');
input.type = 'file';
input.onchange = e => {
var file = e.target.files[0];
fileObject.fullFileName = file.name;
fileObject.fileName = fileObject.fullFileName.split('.').shift();
fileObject.fileExtension = fileObject.fullFileName.split('.').pop();
var reader = new FileReader();
reader.readAsText(file,'UTF-8');
reader.onload = readerEvent => {
fileObject.fileData = readerEvent.target.result;
if (typeof callBack != 'undefined') {
callBack(fileObject);
}
}
}
input.click();
}
/**
* Writes data to storage.
* @param {object} obj - Object to store data: {'key': value, 'key': value, ...}
* @param {object} callBack - Callback function to call after access to storage.
* @return Data written to storage.
*/
this.writeDataToStorage = function(obj, callBack) {
for (key in obj) {
if (typeof obj[key] != 'undefined') {
localStorage.setItem(key, obj[key]);
} else {
localStorage.setItem(key, {});
}
}
if (typeof callBack != 'undefined') {
callBack();
}
}
}
system = new System();