$(document).ready( runUGUI );
UGUI is a library and framework used to bootstrap NW.js projects however it specializes in allowing the quick and easy conversion of CLI to GUI.
A00. Intro
A01. UGUI Start
A02. UGUI variables
B00. Simplified Commands
B01. Run CMD
B02. Run CMD (Advanced)
B03. Read a file
B04. Read contents of a folder
B05. Write to file
B06. Create a folder
B07. Delete a file
B08. Delete a folder
C00. CLI Command Processing
C01. Clicking Submit
C02. Building the command array
C03. Build UGUI Args object
C04. Find key value
C05. Parse argument
C06. Process all
C07. Convert command array to string
C08. Set input file path, file name, and extension
C09. Set input folder path and folder name
c10. Prevent user from entering quotes in forms
C11. Color processor
D00. UI Elements
D01. Submit is locked until required is fulfilled
D02. Replace HTML text with text from package.json
D03. Update about modal
D04. Navigation bar functionality
D05. Launch links in default browser
E00. Warnings
E01. Warn if identical data-argNames
F00. UGUI Developer Toolbar
F01. Detect if in developer environment
F02. Put all executables in dropdowns
F03. Real-time updating of command output in UGUI Dev Tools
F04. Put CLI help info in UGUI dev tools
F05. Swap Bootswatches
F06. Save chosen Bootswatch
F07. Custom keyboard shortcuts
G00. Plugins
G01. EZDZ: Drag and drop file browse box
G02. Range slider
G03. Cut/copy/paste context menu
H00. Settings
H01. Save Settings
H02. Load Settings
H03. The UGUI Object
This is the start of the file. We have UGUI wait until the document is ready before performing any actions. We’ve also added in a way to delay the running of UGUI until Webkit Developer Tools can launch. This will allow you to hit a debugger in time, if contributing to UGUI.
Wait for the document to load before running ugui.js. Use either runUGUI or waitUGUI for immediate or delayed launch.
$(document).ready( runUGUI );
This lets you open NW.js, then immediately launch the Webkit Developer Tools, then a few seconds later run UGUI. Good for hitting a debugger in time, as often the JS runs before the Webkit Developer Tools can open.
function waitUGUI() {
require("nw.gui").Window.get().showDevTools();
setTimeout(runUGUI, 6000);
}
Container for all UGUI components
function runUGUI() {
This is the one place where the UGUI version is declared
var uguiVersion = "1.2.0";
All arguments sent in the command
var allArgElements = $("cmd arg");
var index = 0;
All executables
var executable = [];
for (index = 0; index < $("cmd").length; index++) {
var currentCommandBlock = $("cmd")[index];
executable.push($(currentCommandBlock).attr("executable"));
}
Create the argsForm array containing all elements with a data-argName
for each executable form.
var argsForm = [];
for (index = 0; index < executable.length; index++) {
argsForm.push( $("#" + executable[index] + " *[data-argName]" ) );
}
Get all text fields where a quote could be entered
var textFields = $( "textarea[data-argName], input[data-argName][type=text]" ).toArray();
Allow access to the filesystem
var fs = require("fs");
Access the contents of the package.json file
var packageJSON = require("nw.gui").App.manifest;
Name of the developer’s application as a URL/File path safe name, set in package.json
var appName = packageJSON.name;
The app title that is used dynamically throughout the UI and title bar, set in package.json
var appTitle = packageJSON.window.title;
Version of the developer’s application, set in package.json
var appVersion = packageJSON.version;
Description or tagline for application, set in package.json
var appDescription = packageJSON.description;
Name of the app developer or development team, set in package.json
var authorName = packageJSON.author;
Name of the starting page for the app, set in package.json
var indexFile = packageJSON.main;
Full path to the app project folder
var pathToProject = window.location.pathname.split(indexFile)[0];
Detect if in darwin
, freebsd
, linux
, sunos
, or win32
var platform = process.platform;
If you’re on Windows then folders in file paths are separated with \
, otherwise OS’s use /
var correctSlash = "/";
if ( platform == "win32" ) {
correctSlash = "\\";
} else {
correctSlash = "/";
}
Detect if Bootstrap is loaded
var bootstrap3_enabled = (typeof $().emulateTransitionEnd == 'function');
Detect if Bootstrap Slider is loaded
var slider_enabled = (typeof $().slider == 'function' );
You can stylize console outputs in Webkit, these are essentially CSS classes
var consoleNormal = "font-family: sans-serif";
var consoleBold = "font-family: sans-serif;" +
"font-weight: bold";
var consoleCode = "background: #EEEEF6;" +
"border: 1px solid #B2B0C1;" +
"border-radius: 7px;" +
"padding: 2px 8px 3px;" +
"color: #5F5F5F;" +
"line-height: 22px;" +
"box-shadow: 0px 0px 1px 1px rgba(178,176,193,0.3)";
var consoleError = "background: #F6EEEE;" +
"border: 1px solid #C1B0B2;" +
"border-radius: 7px;" +
"padding: 2px 8px 3px;" +
"color: #5F5F5F;" +
"line-height: 22px;" +
"box-shadow: 0px 0px 1px 1px rgba(193,176,178,0.3)";
Placing this at the start of a console output will let you style it.
Example: console.info(º+"Some bold text.", consoleBold);
var º = "%c";
Make sure the ugui
and ugui.args
objects exist, if not create them
if (!window.ugui) {
window.ugui = {};
window.ugui.args = {};
}
These are easy to run commands for common tasks a desktop application would perform. Such as reading, writing, and deleting files and folders or running native executables.
This is what makes running your CLI program and arguments easier. Cow & Taco examples below to make life simpler.
$("#taco").click( function() { runcmd('pngquant --force "file.png"'); }); runcmd("node --version", function(data) { $("#cow").html("<pre>Node Version: " + data + "</pre>"); });
function runcmd(executableAndArgs, callback) {
Validate that the required argument is passed and is a string
if (!executableAndArgs || typeof(executableAndArgs) !== "string") {
console.info(º+"You must pass in a string containing the exectuable " +
"and arguments to be sent to the command line.", consoleNormal);
console.info(º+"Example:", consoleBold);
console.info(º+'ugui.helpers.runcmd("pngquant.exe --speed 11mph --force file.png");', consoleCode);
return;
}
var exec = require("child_process").exec;
var child = exec( executableAndArgs,
Throw errors and information into console
function(error, stdout, stderr) {
console.log(executableAndArgs);
console.log("stdout: " + stdout);
console.log("stderr: " + stderr);
if (error !== null) {
console.log("Executable Error: " + error);
}
console.log("---------------------");
}
);
Return data from command line
child.stdout.on("data", function(chunk) {
if (typeof callback === "function") {
callback(chunk);
}
});
}
This is a more advanced option for running executables. You can pass in a parameters object to get additional functionality such as running a function when an executable closes, finishes, errors, or returns data.
ugui.helpers.runcmdAdvanced(parameters);
Below is an example parameters object.
var parameters = { "executableAndArgs": "node --version", "returnedData": function(data) { console.log("The text from the executable: " + data); }, "onExit": function(code) { console.log("Executable finished with the exit code: " + code); }, "onError": function(err) { console.log("Executable finished with the error: " + err); }, "onClose": function(code) { console.log("Executable has closed with the exit code: " + code); } };
function runcmdAdvanced(parameters) {
Validate that required argument is passed
if (!parameters) {
console.info(º+"You must pass in an object with your options.", consoleNormal);
console.info(º+"Example:", consoleBold);
console.info(º+"var parameters = { 'executableAndArgs': 'node --version' };", consoleCode);
console.info(º+"ugui.helpers.runcmdAdv(parameters);", consoleCode);
return;
}
Validate types
if (Object.prototype.toString.call(parameters) !== "[object Object]") {
console.info(º+"Your parameters must be passed as an object.", consoleNormal);
return;
} else if (typeof(parameters.executableAndArgs) !== "string") {
console.info(º+"Executable and arguments must be passed as a string. Example:", consoleNormal);
console.info(º+'"node --version"', consoleCode);
return;
} else if (parameters.returnedData && typeof(parameters.returnedData) !== "function") {
console.info(º+"returnedData must be a function.", consoleNormal);
return;
} else if (parameters.onExit && typeof(parameters.onExit) !== "function") {
console.info(º+"onExit must be a function.", consoleNormal);
return;
} else if (parameters.onError && typeof(parameters.onError) !== "function") {
console.info(º+"onError must be a function.", consoleNormal);
return;
} else if (parameters.onClose && typeof(parameters.onClose) !== "function") {
console.info(º+"onClose must be a function.", consoleNormal);
return;
}
var exec = require("child_process").exec;
var child = exec( parameters.executableAndArgs,
Throw errors and information into console
function(error, stdout, stderr) {
console.log(parameters.executableAndArgs);
console.log("stdout: " + stdout);
console.log("stderr: " + stderr);
if (error !== null) {
console.log("Executable Error: " + error);
} else {
return child;
}
console.log("---------------------");
}
);
Detect when executable finishes
child.on("exit", function(code) {
if (typeof parameters.onExit === "function") {
parameters.onExit(code);
}
});
Detect when executable errors
child.on("error", function(code) {
if (typeof parameters.onError === "function") {
parameters.onError(code);
}
});
Detect when the executable is closed
child.on("close", function(code) {
if (typeof parameters.onClose === "function") {
parameters.onClose(code);
}
});
Return data from command line
child.stdout.on("data", function(chunk) {
if (typeof parameters.returnedData === "function") {
parameters.returnedData(chunk);
}
});
}
A function that allows you to set the contents of a file to a variable. Like so:
var devToolsHTML = ugui.helpers.readAFile("_markup/ugui-devtools.htm");
function readAFile(filePathAndName) {
Validate that required argument is passed
if (!filePathAndName) {
console.info(º+"Supply a path to the file you want to read as " +
"an argument to this function.", consoleNormal);
return;
}
Validate types
if (typeof(filePathAndName) !== "string") {
console.info(º+"File path must be passed as a string.", consoleNormal);
return;
}
var fileData = fs.readFileSync(filePathAndName, {encoding: "UTF-8"});
return fileData;
}
Supply a path to a folder as a string and UGUI will return an object with each file and folder as a sub-object. Each item returned will have an “isFolder” property to tell if it’s a file or a folder, and with the exception of some system files, they should all have a file size as well.
To make things easier, we also return an array that lists all items returned.
var mediaContents = ugui.helpers.readAFolder("_media");
Since you can’t use spaces or dots in dot notation, folders and files like “Hello World” and “file.txt” can’t be accessed by doing
mediaContents.Hello World.size
ormediaContents.file.txt.isFolder
. So to access those use:
mediaContents["Hello World"].size mediaContents["file.txt"].isFolder
function readAFolder(filePath, callback) {
Validate that required argument is passed
if (!filePath) {
console.info(º+"Supply a path to the file you want to read as " +
"an argument to this function.", consoleNormal);
return;
}
Validate types
if (typeof(filePath) !== "string") {
console.info(º+"File path must be passed as a string.", consoleNormal);
return;
} else if (callback && typeof(callback) !== "function") {
console.info(º+"Callback must be passed as a function.", consoleNormal);
return;
}
Create an object with an array in it
var contents = {};
var contentsList = [];
fs.readdir only accepts unix style folder paths
if (platform == "win32") {
filePath = filePath.replace("\\","/");
}
Read the directory passed in
fs.readdir(filePath, function (err, files) {
If there were problems reading the contents of a folder, stop and report them
if (err) {
console.info(º+"Unable to read contents of the folder:", consoleNormal);
console.warn(º+err.message, consoleError);
return;
}
files.forEach( function (file) {
fs.lstat(filePath + correctSlash + file, function(err, stats) {
Retain an array of all files and folders
contentsList.push(file);
Check if it’s a folder
if (!err && stats.isDirectory()) {
contents[file] = {
"isFolder": true,
"size": 0
}
Check if it has a file size
} else if (!err && file !== "undefined") {
contents[file] = {
"isFolder": false,
"size": stats.size
}
Catch-all
} else {
contents[file] = {
"isFolder": false
}
}
});
});
});
If a callback was passed in, run it
if (callback) {
callback(contents, contentsList);
Otherwise just return the contents of the folder
} else {
return [contents, contentsList];
}
}
This will override the contents of a file you pass in with the data you supply. If the file you point to doesn’t exist, it will be created with your supplied data.
ugui.helpers.writeToFile("C:/folder/new_file.htm", "Text.");
function writeToFile(filePathAndName, data, callback) {
Validate that required arguments are passed and are the correct types
if (!filePathAndName || typeof(filePathAndName) !== "string") {
console.info(º+"Supply a path to the file you want to create or replace the " +
"contents of as the first argument to this function.", consoleNormal);
console.info(º+"File path and name must be passed as a string.", consoleNormal);
console.info(º+"Example:", consoleBold);
console.info(º+'ugui.helpers.writeToFile("C:/folder/file.htm", "Your data.");', consoleCode);
return;
} else if (!data) {
console.info(º+"You must pass in the data to be stored as the second argument " +
"to this function.", consoleNormal);
return;
} else if (typeof(data) !== "string") {
console.info(º+"The data to be stored must be passed as a string.", consoleNormal);
return;
} else if (callback && typeof(callback) !== "function") {
console.info(º+"Your callback must be passed as a function.", consoleNormal);
return;
}
Write to the file the user passed in
fs.writeFile(filePathAndName, data, function(err) {
If there was a problem writing to the file
if (err) {
console.info(º+"There was an error attempting to save your data.", consoleNormal);
console.warn(º+err.message, consoleError);
return;
If the file was updated and the user passed in a callback function, run it
} else if (callback) {
callback();
}
});
}
This will create a new folder in the location you pass in. You cannot create a new folder with a folder in it. So if
C:/Taco
doesn’t exist then the following wouldn’t work:
ugui.helpers.createAFolder("C:/Taco/Cheese");
You’d need to create the “Taco” folder first, then the “Cheese” folder, like so:
ugui.helpers.createAFolder("C:/Taco", function(){ ugui.helpers.createAFolder("C:/Taco/Cheese"); });
In this example we are using a callback to create a subfolder. This ensures that the “Taco” folder will exist before we attempt to create the “Cheese” folder.
function createAFolder(filePath, callback) {
Validate that required argument is passed and is the correct types
if (!filePath || typeof(filePath) !== "string") {
console.info(º+"Supply a path to where you want your folder as the first " +
"argument to this function.", consoleNormal);
console.info(º+"Folder path must be passed as a string.", consoleNormal);
console.info(º+"Example:", consoleBold);
console.info(º+'ugui.helpers.createAFolder("C:/folder/new_folder");', consoleCode);
return;
If a callback was passed in and it isn’t a function
} else if (callback && typeof(callback) !== "function") {
console.info(º+"Your callback must be passed as a function.", consoleNormal);
return;
}
Create the folder in the supplied location
fs.mkdir(filePath, function(err) {
If there was a problem creating the folder
if (err) {
console.info(º+"There was an error attempting to create the folder.", consoleNormal);
console.warn(º+err.message, consoleError);
return;
If the folder was created and the user passed in a callback function, run it now
} else if (callback) {
callback();
}
});
}
Though UGUI doesn’t currently use this functionality anywhere within itself, we thought it would be nice to offer a quick and easy way of deleting files.
ugui.helpers.deleteAFile("C:/folder/delete_me.htm");
function deleteAFile(filePathAndName, callback) {
Validate that required argument is passed and is the correct types
if (!filePathAndName || typeof(filePathAndName) !== "string") {
console.info(º+"Supply a path to the file you want to delete as " +
"the first argument to this function.", consoleNormal);
console.info(º+"File path must be passed as a string.", consoleNormal);
console.info(º+"Example:", consoleBold);
console.info(º+'ugui.helpers.deleteAFile("C:/folder/delete_me.txt");', consoleCode);
return;
If a callback was passed in and it isn’t a function
} else if (callback && typeof(callback) !== "function") {
console.info(º+"Your callback must be passed as a function.", consoleNormal);
return;
}
Delete the selected file
fs.unlink(filePathAndName, function(err) {
If there was a problem deleting the file
if (err) {
console.info(º+"There was an error attempting to delete the file.", consoleNormal);
console.warn(º+err.message, consoleError);
return;
If the file deleted and the user passed in a callback function, run it now
} else if (callback) {
callback();
}
});
}
Though UGUI doesn’t currently use this functionality anywhere within itself, we thought it would be nice to offer a quick and easy way to delete folders.
ugui.helpers.deleteAFolder("C:/path/to/folder");
NOTE: This will not delete a folder unless it is empty.
function deleteAFolder(filePath, callback) {
Validate that required argument is passed and is the correct types
if (!filePath || typeof(filePath) !== "string") {
console.info(º+"Supply a path to the folder you want to delete as " +
"the first argument to this function.", consoleNormal);
console.info(º+"Folder path must be passed as a string.", consoleNormal);
console.info(º+"Example:", consoleBold);
console.info(º+'ugui.helpers.deleteAFolder("C:/folder/delete_me");', consoleCode);
return;
If a callback was passed in and it isn’t a function
} else if (callback && typeof(callback) !== "function") {
console.info(º+"Your callback must be passed as a function.", consoleNormal);
return;
}
Delete the selected folder
fs.rmdir(filePath, function(err) {
If there was a problem deleting the folder
if (err) {
console.info(º+"There was an error attempting to delete the folder.", consoleNormal);
console.warn(º+err.message, consoleError);
return;
If the folder deleted and the user passed in a callback function, run it now
} else if (callback) {
callback();
}
});
}
This section is the primary purpose, and the heart of UGUI.
It’s what takes the <cmd>
, <arg>
, and <def>
stuff,
matches it with the data-argName
stuff, and ultimately
outputs it to the command-line.
It’s also responsible for building the UGUI Arg object, which is used for other things, like saving settings.
What happens when you click the submit button.
When the button is pressed, prevent it from submitting the form like it normally would in a browser. Detect which form the submit button is in and what executable it corresponds to. Remove quotes from all fields. Build the command line array based on UGUI Args Object and turn it into a string.
Detect if text from the command line is meant to be printed on the page. Then run the command.
When you click the submit button.
$(".sendCmdArgs").click( function(event) {
Prevent the form from sending like a normal website.
event.preventDefault();
Get the correct executable to use based on the form you clicked on
var thisExecutable = $(this).closest("form").attr("id");
Remove all single/double quotes from any text fields
removeTypedQuotes();
Build the command line array with the executable and all commands
var builtCommandArray = buildCommandArray(thisExecutable);
Convert the array to a string that can be ran in a command line using the runcmd function
var builtCommandString = convertCommandArraytoString(builtCommandArray);
Check if the form has an element with a class of returnedCmdText
if ( $("#" + thisExecutable + " .returnedCmdText").length > 0 ) {
If so, run a command and put its returned text on the page
runcmd( builtCommandString, function(data) {
$("#" + thisExecutable + " .returnedCmdText").html(data);
});
} else {
Run the command!
runcmd(builtCommandString);
}
});
What happens when you click the submit button or when the UGUI Developer Toolbar’s “CMD Output” section is updated to preview the outputted command that would be sent to the command line/terminal.
function buildCommandArray(thisExecutable) {
Validate types
if (thisExecutable !== undefined && typeof(thisExecutable) !== "string") {
console.info(º+"Executable must be passed as a string.", consoleNormal);
return;
}
If no executable was passed in, just use the first one in <cmd>
‘s
thisExecutable = thisExecutable || executable[0];
Set up commands to be sent to command line
var cmds = [ thisExecutable ];
Fill out window.ugui.args
object
buildUGUIArgObject();
Process all definitions and place them in window.ugui.args
patternMatchingDefinitionEngine();
Setting up arrays
var cmdArgsText = [];
Loop through all the <args>
in the <cmd>
with the selected executable
for (index = 0; index < $("cmd[executable=" + thisExecutable + "] arg").length; index++) {
Set the current <arg>
var currentArg = $("cmd[executable=" + thisExecutable + "] arg")[index];
Put the <arg>
text into an array
cmdArgsText.push( $(currentArg).text() );
}
Loop through all phrases and add processed versions to output array
for (index = 0; index < cmdArgsText.length; index++) {
cmdArgsText[index]
is --quality ((meow)) to ((oink.min))
cmds.push( parseArgument(cmdArgsText[index]) );
}
After all the processing is done and the array is built, return it
return cmds;
}
This grabs all the data about the elements on the page that have a
data-argName
and puts that information on the window object, located here:window.ugui.args
function buildUGUIArgObject() {
Reset the UGUI Args Object to remove any stragglers
window.ugui.args = {};
Make an array containing every element on the page with an attribute of data-argName
var cmdArgs = $("*[data-argName]");
Cycle through all elements with a data-argName
in <form id="currentexecutable">
for (index = 0; index < cmdArgs.length; index++) {
Get bob
from <input data-argName="bob" value="--kitten" />
var argName = $(cmdArgs[index]).attr("data-argName");
Get --carrot
from <input type="radio" data-argName="vegCarrot" value="--carrot" />
var argValue = $(cmdArgs[index]).val();
Declare variable now to be defined below
var argType = "";
Get input
from <input data-argName="bob" type="checkbox" />
var argTag = $(cmdArgs[index]).prop("tagName").toLowerCase();
See if the current item is a range slider
if ( $(cmdArgs[index]).hasClass("slider") ) {
Manually set the type to range
for range slider elements
argType = "range";
See if the element is an item in one of Bootstrap’s fake dropdowns
} else if ( $(cmdArgs[index]).parent().parent().hasClass("dropdown-menu") ) {
Manually set the type to range
for range slider elements
argType = "dropdown";
} else if ( $(cmdArgs[index]).attr("nwdirectory") ) {
Manually set the type if it’s a directory browser
argType = "folder";
} else if (argTag == "select") {
Manually set the type if it’s a traditional dropdown
argType = "select";
} else {
Get checkbox
from <input data-argName="bob" type="checkbox" />
argType = $(cmdArgs[index]).attr("type");
}
Basic info put on every object
window.ugui.args[argName] = {
"value": argValue,
"htmltag": argTag,
"htmltype": argType
};
Special info just for <input type="file" nwdirectory="nwdirectory">
if (argType === "folder") {
setInputFolderPathName(cmdArgs[index], argName);
window.ugui.args[argName].htmltag = argTag;
window.ugui.args[argName].htmltype = argType;
}
Special info just for <input type="file">
if (argType === "file") {
setInputFilePathNameExt(cmdArgs[index], argName);
window.ugui.args[argName].htmltag = argTag;
window.ugui.args[argName].htmltype = argType;
}
Special info just for <input type="color">
if (argType === "color") {
colorProcessor(argValue, argName);
window.ugui.args[argName].htmltag = argTag;
window.ugui.args[argName].htmltype = argType;
}
For checkboxes and radio dials, add special info
if (argType === "checkbox" || argType === "radio" || argType === "dropdown") {
if ( $(cmdArgs[index]).prop("checked") ) {
window.ugui.args[argName].htmlticked = true;
} else {
window.ugui.args[argName].htmlticked = false;
}
}
if (argTag === "textarea") {
window.ugui.args[argName] = {
"value": argValue,
"htmltag": argTag,
"htmltype": "textarea"
};
}
}
}
Run once on page load
buildUGUIArgObject();
This is a general purpose function that allows retrieving information from an object. Here is an example object and how
findKeyValue()
works to return data from it:
var a = { "b": "dog", "c": { "d": "cat", "e": "bat" } }; var ab = ["b"]; var acd = ["c","d"]; console.log( findKeyValue(a,ab) ); //dog console.log( findKeyValue(a,acd) ); //cat
function findKeyValue(obj, arr) {
Validate that both required arguments are passed
if(!obj || !arr) {
console.info(º+"You need to supply an object and an array of " +
"strings to drill down within the object.", consoleNormal);
return;
}
Validate types
if (Object.prototype.toString.call(obj) !== "[object Object]") {
console.info(º+"First argument must be passed as an object.", consoleNormal);
return;
} else if (Object.prototype.toString.call(arr) !== "[object Array]") {
console.info(º+"Second argument must be passed as strings in an array.", consoleNormal);
return;
}
Validate that all items of the array are strings
for (i = 0; i < arr.length; i++) {
if (typeof(arr[i]) !== "string") {
console.info(º+"Second argument must be passed as strings in an array.", consoleNormal);
return;
}
}
/* console.log(obj, arr); */
for (var i = 0; i < arr.length; i++) {
obj = obj[arr[i]];
}
For stuff like ((moo))
, assume the user means ((moo.value))
if (Object.prototype.toString.call(obj) === "[object Object]") {
obj = obj.value;
}
/* console.log(obj); */
return obj;
}
This takes the argument from the
<cmd><arg>
, finds all the((keywords))
and replaces them with the information on the UGUI Args Object found here:window.ugui.args
function parseArgument(argumentText) {
Validate that required argument is passed
if (!argumentText) {
console.info(º+"This processes strings of text that contain " +
"((keywords)) in them from the <cmd> tags.", consoleNormal);
return;
}
Validate types
if (typeof(argumentText) !== "string") {
console.info(º+"Argument text must be passed as a string.", consoleNormal);
return;
}
argumentText = "and ((meow)), with ((oink)) too. "
var regexToMatch = /\(\((.*?)\)\)/;
Keep rerunning this until all ((keywords))
in argumentText
are replaced with their actual values
while ( regexToMatch.test(argumentText) ) {
match = ["((meow))","meow"]
var match = regexToMatch.exec(argumentText);
var uguiArgObj = window.ugui.args;
var regExMatch = RegExp( "\\(\\(" + match[1] + "\\)\\)" );
matched = uguiArgObj.meow
var matched = uguiArgObj[match[1]];
if (matched === undefined) {
var matchName = match[1].split(".")[0];
matched = uguiArgObj[matchName];
}
/* console.log( "-----------------" ); */
/* console.log( "value: ", matched.value ); */
Skip all unchecked checkboxes and unchecked radio dials. Skip everything without a value
if (
(matched.htmltype === "checkbox" && matched.htmlticked === false) ||
(matched.htmltype === "radio" && matched.htmlticked === false) ||
(matched.htmltype === "dropdown" && matched.htmlticked === false) ||
(typeof(matched.value) === "undefined") ||
(matched.value === "")
) {
Replace the --quality ((meow))
with an empty string
argumentText = "";
return argumentText;
Run all the non-checkbox/radio/file elements, all checked checkboxes and checked radio dials
} else if (
(matched.htmltype !== "checkbox" && matched.htmltype !== "radio") ||
(matched.htmltype === "checkbox" && matched.htmlticked === true) ||
(matched.htmltype === "radio" && matched.htmlticked === true)
) {
Find the correct value from the UGUI Args Object
var foundKeyValue = findKeyValue( uguiArgObj, match[1].split(".") );
Replace the “–quality ((meow))” with “–quality 9”
argumentText = argumentText.replace( regExMatch, foundKeyValue );
And whatever’s left
} else {
Replace the “–quality ((meow))” with “”
argumentText = "";
}
/* console.log(argumentText); */
}
return argumentText;
}
This loops through all
<def>
‘s and processes the value of them to create the correct key value pairs on the UGUI Args Object.
function patternMatchingDefinitionEngine() {
A regular expression that matches ((x))
and captures x
var re = /\(\((.*?)\)\)/gi;
$("def").each(function(index, value) {
Assign “value” to def
def = <def name="quality">((min)),((max))</def>
var def = value;
Get the actual definition from the <def>
definition = "((min)),((max))"
var definition = $("def").html();
Get the argument associated with this <def>
arg = ugui.args.quality
var arg = ugui.args[$("def").attr("name")];
var match;
var currentIndex = 0;
var separators = [];
var args = [];
Loop through the definition grabbing all the separators and arguments
while (true) {
Assign the RegEx result to match and check to see if there is a match
if ((match = re.exec(definition)) !== null) {
Grab any text separating the values and push it to a collector array
separators.push(definition.slice(currentIndex, match.index));
Update the slice start index for the next iteration
currentIndex = re.lastIndex;
Add the argument from the definition to the global UGUI object
arg[match[1]] = "";
Add the argument to the args
array for value assignment in next loop
args.push(match[1]);
If there are no more arguments:
} else {
Put the last part of the definition into the separator array
separators.push(definition.slice(currentIndex));
End the loop
break;
}
};
Get the value of the associated argument
argValue = "0,75"
var argValue = arg.value;
splitIndex
is used to keep track of where we are in the value
splitIndex = 0;
Loop through the arguments defined by this <def>
, parse the value using the separators, and assign the correct value
for (var i = 0; i < args.length; i++) {
The separators around the current argumentfirstSeparator = ""
secondSeparator = ","
firstSeparator = separators[i];
secondSeparator = separators[i + 1];
The first if catches cases where the dev has unnecessarily used a <def>
if (firstSeparator == "" && secondSeparator == "") {
arg[args[i]] = argValue;
This catches if there is no text before the first value to map
} else if (firstSeparator == "") {
arg[args[i]] = argValue.slice(splitIndex, argValue.indexOf(secondSeparator));
splitIndex = argValue.indexOf(secondSeparator);
This catches if there is no text after the last value to map
} else if (secondSeparator == "") {
arg[args[i]] = argValue.slice((argValue.indexOf(firstSeparator, splitIndex) + firstSeparator.length));
This catches in all other cases
} else {
arg[args[i]] = argValue.slice(
(argValue.indexOf(firstSeparator, splitIndex) + firstSeparator.length),
argValue.indexOf(secondSeparator, (splitIndex + firstSeparator.length))
);
splitIndex = argValue.indexOf(secondSeparator, (splitIndex + firstSeparator.length))
}
}
})
}
Take the array of executable and commands, remove empty arguments and put everything into a string to be sent out to the command line.
function convertCommandArraytoString( cmdArray ) {
Validate that the required argument is passed
if (!cmdArray) {
console.info(º+"Accepts an array of executable and commands, " +
"removes empty arguments and puts everything into a string " +
"ready to be sent out to the command line.", consoleNormal);
return;
}
Validate types
if (Object.prototype.toString.call(cmdArray) !== "[object Array]") {
console.info(º+"Command array must be passed as strings in an array.", consoleNormal);
return;
}
Validate that all items of the array are strings
for (i = 0; i < cmdArray.length; i++) {
if (typeof(cmdArray[i]) !== "string") {
console.info(º+"Arguments must be passed as strings in an array.", consoleNormal);
return;
}
}
Create and empty variable
var cmdString = "";
cmdArray = ["cli_filename", "", "", "-nyan", "--speed 1mph", "", "", "-pear", "--potato", "", "", "", "-m "Text"", ""C:\Users\jwilcurt\Desktop\IICL Stuff.new.png""]
for (index = 0; index < cmdArray.length; index++) {
Make sure the executable isn’t preceded with a space
if (index === 0) {
cmdString = cmdArray[0];
Add in the rest of the arguments, skipping blank ones
} else if (cmdArray[index]) {
cmdString = cmdString + " " + cmdArray[index];
}
}
Return the command string that will be ran
return cmdString;
}
This processes elements with a
data-argName
that are<input type="file">
. It creates special properties for the element and places them on the UGUI Args Object found here:window.ugui.args
function setInputFilePathNameExt(currentElement, argName) {
Validate that both required arguments are passed
if (!currentElement || !argName) {
console.info(º+"You must pass in the element as an object and " +
"its argName as a string.", consoleNormal);
return;
}
Validate types
if (typeof(currentElement) !== "object") {
console.info(º+"Element must be passed as a jQuery object.", consoleNormal);
return;
} else if (typeof(argName) !== "string") {
console.info(º+"The argName must be passed as a string.", consoleNormal);
return;
}
Create a variable that contains all the file information supplied by Webkit
var fileAttributes = currentElement.files[0];
Before continuing, verify that the user has selected a file
if (fileAttributes) {
Create filename and file path variables to be used below
var filename = "";
var filepath = "";
Either C:\users\bob\desktop\cows.new.png
or /home/bob/desktop/cows.new.png
var fullFilepath = fileAttributes.path;
cows.new.png
filename = fileAttributes.name;
If you’re on Windows then folders in file paths are separated with \
, otherwise OS’s use /
if ( platform == "win32" ) {
Get the index of the final backslash so we can split the name from the path
var lastBackslash = fullFilepath.lastIndexOf("\\");
C:\users\bob\desktop\
filepath = fullFilepath.substring(0, lastBackslash+1);
} else {
Get the index of the final backslash so we can split the name from the path
var lastSlash = fullFilepath.lastIndexOf("/");
/home/bob/desktop/
filepath = fullFilepath.substring(0, lastSlash+1);
}
Split "cows.new.png"
into ["cows", "new", "png"]
var filenameSplit = filename.split(".");
Remove last item in array, ["cows", "new"]
filenameSplit.pop();
Combine them back together as a string putting the .
back in, "cows.new"
var filenameNoExt = filenameSplit.join(".");
Create the args object parameters on the UGUI Args Object
window.ugui.args[argName] = {
"fullpath": fileAttributes.path,
"path": filepath,
"name": filenameNoExt,
"nameExt": filename,
"ext": filename.split(".").pop(),
"lastModified": fileAttributes.lastModified,
"lastModifiedDate": fileAttributes.lastModifiedDate,
"size": fileAttributes.size,
"type": fileAttributes.type,
"value": fileAttributes.path,
"webkitRelativePath": fileAttributes.webkitRelativePath
};
}
}
This processes elements with a
data-argName
that are<input type="file" nwdirectory="nwdirectory">
. It creates special properties for the element and places them on the UGUI Args Object found here:window.ugui.args
function setInputFolderPathName(currentElement, argName) {
Validate that both required arguments are passed
if (!currentElement || !argName) {
console.info(º+"You must pass in the element as an object and " +
"its argName as a string.", consoleNormal);
return;
}
Validate types
if (typeof(currentElement) !== "object") {
console.info(º+"Element must be passed as a jQuery object.", consoleNormal);
return;
} else if (typeof(argName) !== "string") {
console.info(º+"The argName must be passed as a string.", consoleNormal);
return;
}
Create a variable that contains all the file information supplied by Webkit
var fileAttributes = currentElement.files[0];
Before continuing, verify that the user has selected a file
if (fileAttributes) {
Create folder name and file path variables to be used below
var folderName = "";
var filePath = "";
Either C:\users\bob\desktop\cows.new.png
or /home/bob/desktop/cows.new.png
Use the first one, unless you are loading settings and it doesn’t exist
var fullFilePath = fileAttributes.fullpath || fileAttributes.path;
If you’re on Windows then folders in file paths are separated with \
, otherwise OS’s use /
if ( platform == "win32" ) {
Get the index of the final backslash so we can split the name from the path
var lastBackslash = fullFilePath.lastIndexOf("\\");
C:\users\bob\desktop\
filePath = fullFilePath.substring(0, lastBackslash+1);
folderName = fullFilePath.split("\\").pop();
} else {
Get the index of the final backslash so we can split the name from the path
var lastSlash = fullFilePath.lastIndexOf("/");
/home/bob/desktop/
filePath = fullFilePath.substring(0, lastSlash+1);
folderName = fullFilePath.split("/").pop();
}
Create the args object parameters on the UGUI Args Object
window.ugui.args[argName] = {
"contents": readAFolder(fullFilePath)[0],
"contentsList": readAFolder(fullFilePath)[1],
"fullpath": fullFilePath,
"path": filePath,
"folderName": fileAttributes.name || folderName,
"lastModified": fileAttributes.lastModified,
"lastModifiedDate": fileAttributes.lastModifiedDate,
"value": fileAttributes.path,
"webkitRelativePath": fileAttributes.webkitRelativePath
};
}
}
In all input text fields and textareas, remove both single and double quotes as they are typed, on page load, and when the form is submitted.
Remove all quotes on every text field whenever typing or leaving the field
$(textFields).keyup( removeTypedQuotes );
$(textFields).blur( removeTypedQuotes );
function removeTypedQuotes() {
Loop through all text fields on the page
for (index = 0; index < textFields.length; index++) {
User entered text of current text field
var textFieldValue = $( textFields[index] ).val();
If the current text field has a double or single quote in it
if ( textFieldValue.indexOf('"') != -1 || textFieldValue.indexOf("'") != -1 ) {
Remove quotes in current text field
$( textFields[index] ).val( $( textFields[index] ).val().replace(/['"]/g, '') );
}
}
}
removeTypedQuotes();
Process input elements with a type of color to generate RGB, Hex, and Decimal values, then place them on the
ugui.args.{data-argName}
object.
function colorProcessor(inputColor, argName) {
Validate that both required arguments are passed
if (!inputColor || !argName) {
console.info(º+"You must pass in your Hex color (#FF0000) as a " +
"string accompanied by it's argName.", consoleNormal);
return;
}
Validate types
if (typeof(inputColor) !== "string") {
console.info(º+"Hex color must be passed as a string.", consoleNormal);
return;
} else if (inputColor[0] !== "#") {
console.info(º+"Hex color must begin with #.", consoleNormal);
return;
} else if (typeof(argName) !== "string") {
console.info(º+"argName must be passed as a string.", consoleNormal);
return;
}
Setup variables
var R = ""; var r = "";
var G = ""; var g = "";
var B = ""; var b = "";
var rgb = inputColor.split("");
var sansOctothorpe = rgb[1] + rgb[2] + rgb[3] + rgb[4] + rgb[5] + rgb[6];
for (var i = 1; i < rgb.length; i++) {
var rgbi = rgb[i];
Convert Hex to Dec
if (rgbi == "A" || rgbi == "a") { rgbi = "10" }
if (rgbi == "B" || rgbi == "b") { rgbi = "11" }
if (rgbi == "C" || rgbi == "c") { rgbi = "12" }
if (rgbi == "D" || rgbi == "d") { rgbi = "13" }
if (rgbi == "E" || rgbi == "e") { rgbi = "14" }
if (rgbi == "F" || rgbi == "f") { rgbi = "15" }
Set RrGgBb to decimal
if (i === 1) { R = rgbi; } else
if (i === 2) { r = rgbi; } else
if (i === 3) { G = rgbi; } else
if (i === 4) { g = rgbi; } else
if (i === 5) { B = rgbi; } else
if (i === 6) { b = rgbi; }
}
As 0-255
var Red = (parseInt(R) * 16) + parseInt(r);
var Green = (parseInt(G) * 16) + parseInt(g);
var Blue = (parseInt(B) * 16) + parseInt(b);
As 0-100%
var RP = Math.floor( (Red/255) * 100 );
var GP = Math.floor( (Green/255) * 100 );
var BP = Math.floor( (Blue/255) * 100 );
var DecRrGgBb = R + " " + r + " " + G + " " + g + " " + B + " " + b;
Create the args object parameters on the UGUI Args Object
window.ugui.args[argName] = {
"rgb": "rgb(" + Red + "," + Green + "," + Blue + ")",
"decred": Red,
"decgreen": Green,
"decblue": Blue,
"decRrGgBb": DecRrGgBb,
"hexRrGgBb": sansOctothorpe,
"percentRed": RP,
"percentGreen": GP,
"percentBlue": BP,
"value": inputColor
};
}
These are things specific to the stuff on the page. These may not be relevent to apps made using UGUI that do a lot of custom UI work.
Gray out the submit button until all required elements are filled out. On every change, click, or keystroke, check all forms to verify that if any need unlocked or locked.
function unlockSubmit() {
Cycle through each executable
for (index = 0; index < executable.length; index++) {
Get the current executable
var currentExecutable = executable[index];
If a required element wasn’t filled out in this form
if ( $("#" + currentExecutable).is(":invalid") ) {
Disable/Lock the submit button
$("#" + currentExecutable + " .sendCmdArgs").prop("disabled", true);
If all required elements in a form have been fulfilled
} else {
Enable/Unlock the submit button
$("#" + currentExecutable + " .sendCmdArgs").prop("disabled", false);
}
}
}
for (index = 0; index < argsForm.length; index++) {
When you click out of a form element
$(argsForm[index]).keyup ( unlockSubmit );
$(argsForm[index]).mouseup( unlockSubmit );
$(argsForm[index]).change ( unlockSubmit );
}
On page load have this run once to unlock submit if nothing is required.
unlockSubmit();
Some text on the page can be auto-filled from the content in the package.json. This replaces the text on the page.
$(".applicationName").html(appName);
$(".applicationTitle").html(appTitle);
$(".applicationDescription").html(appDescription);
getAboutModal();
This pulls in information about the application from the package.json file and puts in in the “About” modal. It also pulls in UGUI’s about info from the
_markdown
folder.
function getAboutModal() {
$.get("_markup/ugui-about.htm", function( aboutMarkup ) {
Put UGUI about info in about modal
$("#aboutModal .modal-body").append( aboutMarkup );
Wait for the “UGUI about” info to be loaded before updating the “App about” section Load application name, version number, and author from package.json
$(".applicationName").html(appTitle);
$(".versionApp").html(appVersion).prepend("V");
$(".authorName").html(authorName);
$(".versionUGUI").html(uguiVersion);
$("#aboutModal .nwjsVersion").append(" (Version " + process.versions["node-webkit"] + ")");
$("#aboutModal .chromiumVersion").append(" (Version " + process.versions["chromium"] + ")");
$("#aboutModal .iojsVersion").append(" (Version " + process.versions["node"] + ")");
After all content is loaded, detect all links that should open in the default browser
openDefaultBrowser();
Remove modal, enable scrollbar
function removeModal() {
$("#aboutModal").slideUp("slow", function() {
$("body").removeClass('no-overflow');
If the navigation is expanded, then close it after exiting the modal
if ( !$(".navbar-toggle").hasClass("collapsed") ) {
$(".navbar-toggle").trigger("click");
}
});
}
When clicking on background or X, remove modal
$("#aboutModal").click( removeModal );
Allow you to click in the modal without triggering the removeModal
function called when you click its parent element
$("#aboutModal .modal-content").click( function( event ) {
event.stopPropagation();
});
$("#aboutModal .glyphicon-remove").click( removeModal );
});
}
Everything in this section controls the visibility and the functionality of the items in the top navigation bar.
Clicking View > Command Line Output in the Nav Bar
$('.navbar a[href="#cmdoutput"]').click( function() {
$('#uguiDevTools nav span[data-nav="uguiCommand"]').trigger("click");
});
Clicking View > Console in the Nav Bar
$('.navbar a[href="#console"]').click( function() {
require("nw.gui").Window.get().showDevTools();
});
Clicking View > Fullscreen
$('.navbar a[href="#fullscreen"]').click( function() {
require("nw.gui").Window.get().toggleFullscreen();
});
Clicking “About” in the Nav Bar
$('.navbar a[href="#about"]').click( function() {
Get the current Window
var win = require("nw.gui").Window.get();
Show the modal
$("#aboutModal").fadeIn("slow");
function setModalHeight() {
if ( win.height < 301 ) {
$(".modal-header").addClass("shortScreen");
} else {
$(".modal-header").removeClass("shortScreen");
}
modalBodyHeight();
}
Get the current height of the window and set the modal to 75% of that
function modalBodyHeight() {
$("#aboutModal .modal-body").css("max-height", (win.height * 0.5) + "px" );
}
Make the header of the modal small when app is tiny
setModalHeight();
win.on("resize", setModalHeight );
Remove page scrollbar when modal displays
$("body").addClass('no-overflow');
});
Makes sure that the logo and app name in the nav bar are vertically centered
function centerNavLogo() {
var navHeight = $(".navbar").height();
$(".navbar-brand").css("line-height", navHeight + "px");
$(".navbar-brand").css("padding-top", "0px");
$(".navbar-brand *").css("line-height", navHeight + "px");
}
Run once on page load
centerNavLogo();
When you click on the exit in the navigation, close this instance of NW.js
$('.navbar a[href="#exit"]').click( function() {
require("nw.gui").Window.get().close(true);
});
Detects all links on the page with a class of
external-link
and sets them to open the link in the user’s default browser instead of using NW.js as a browser which can cause issues.
function openDefaultBrowser() {
Load native UI library.
var gui = require("nw.gui");
Open URL with default browser.
$(".external-link").click( function( event ) {
Prevent the link from loading in NW.js
event.preventDefault();
Get the href
URL for the current link
var url = $(this).attr("href");
Launch the user’s default browser and load the URL for the link they clicked
gui.Shell.openExternal(url);
});
}
Run once on page load
openDefaultBrowser();
These are warnings that occur when UGUI detects you are doing
something that could break its functionality. They are
designed to be precautionary and informative. They only occur
when in dev
mode.
If the developer uses the same
data-argName
value for multiple elements, display a warning.
function warnIfDuplicateArgNames() {
var duplicatesArray = {};
var cmdArgs = "";
var cmdArgsWithoutDuplicates = [];
Cycle through each executable
for (index = 0; index < executable.length; index++) {
All elements with a data-argName
in a form with a matching executable ID
cmdArgs = "";
cmdArgs = argsForm[index];
duplicatesArray = {};
Loop through all form elements for this executable
for (var subindex = 0; subindex < cmdArgs.length; subindex++) {
Put each element’s data-argName
and into an array
duplicatesArray[cmdArgs[subindex].dataset.argname] = cmdArgs[subindex];
}
Create a new array with duplicate argName
s removed
cmdArgsWithoutDuplicates = [];
for ( var key in duplicatesArray ) {
cmdArgsWithoutDuplicates.push(duplicatesArray[key]);
}
If the new array had any duplicates removed display a warning.
if ( cmdArgsWithoutDuplicates.length < cmdArgs.length ) {
$.get("_markup/ugui-multiargnames.htm", function(multiArgNamesMarkup) {
Put alert message at the top of page
$("body.dev").prepend( multiArgNamesMarkup );
});
Keep the console warning formatted nicely for cli filenames under 16 characters in length
var spacesNeeded = 16 - executable[index].length;
var spaces = "";
if (spacesNeeded > 0) {
for (subindex = 0; subindex < spacesNeeded; subindex ++) {
spaces = spaces + " ";
}
}
console.warn( "" );
console.warn( "////////////////////////////////////////" );
console.warn( "// All data-argName's must be unique. //" );
console.warn( "// FOUND IN " + executable[index].toUpperCase() + " SECTION. " + spaces + "//");
console.warn( "////////////////////////////////////////" );
}
}
}
The UGUI Developer Toolbar appears at the bottom of your app
when the <body>
has a class of dev
. It is meant to be
informative and give you access to quick/common tasks.
Detects if you’re in Development or Production environment.
If you have a class of
dev
orprod
in thebody
tag UGUI will enable key bindings such asF12
orCTRL+Shift+I
to launch Webkit’s Developer Tools, orF5
to refresh. Also it displays the Command Line output at the bottom of the page.
Check if the body has a class of prod for Production Environment
if ( $("body").hasClass("prod") ) {
$("#uguiDevTools").remove();
} else if ( $("body").hasClass("dev") ) {
Grab the UGUI Developer Toolbar markup
$.get("_markup/ugui-devtools.htm", function( uguiDevToolsMarkup ) {
Put Developer Toolbar markup on the page
$("body.dev").append( uguiDevToolsMarkup );
Update the UGUI version to the correct version
$("#uguiDevTools .versionUGUI").html(window.ugui.version);
fillExecutableDropdowns();
putExeHelpInDevTools();
$("#uguiDevTools section").addClass("shrink");
$("#uguiDevTools section *").addClass("shrink");
$("#uguiDevTools").show();
Hide/Show based on UGUI Dev Tools navigation
$("#uguiDevTools nav span").click( function() {
var sectionClicked = $(this).attr("data-nav");
$("#uguiDevTools nav span").removeClass("selected");
if ( $("#uguiDevTools section." + sectionClicked).hasClass("shrink") ) {
$("#uguiDevTools nav span[data-nav=" + sectionClicked + "]").addClass("selected");
$("#uguiDevTools section").addClass("shrink");
$("#uguiDevTools section *").addClass("shrink");
$("#uguiDevTools section." + sectionClicked).removeClass("shrink");
$("#uguiDevTools section." + sectionClicked + " *").removeClass("shrink");
} else {
$("#uguiDevTools nav span[data-nav=" + sectionClicked + "]").removeClass("selected");
$("#uguiDevTools section." + sectionClicked).addClass("shrink");
$("#uguiDevTools section." + sectionClicked + " *").addClass("shrink");
}
});
swatchSwapper();
When the developer clicks “Keep”
$("#setNewSwatch").click( function() {
The currently selected swatch
var newSwatch = $("#swatchSwapper").val();
Update index.htm to use the selected swatch as the new default
saveNewSwatch(newSwatch);
});
openDefaultBrowser();
Update the UGUI Developer Toolbar’s “CMD Output” section
updateUGUIDevCommandLine();
$("#uguiDevTools .uguiCommand .executableName").change(updateUGUIDevCommandLine);
});
Get NW.js GUI and WIN
var gui = require("nw.gui");
Get the window object
var win = require("nw.gui").Window.get();
Keyboard shortcuts
keyBindings();
Check for duplicate data-argName
s
warnIfDuplicateArgNames();
}
In the UGUI Developer Toolbar, there are dropdowns in the “CMD Output” and “Executable Info” sections that contain all of the executables used in the app.
function fillExecutableDropdowns() {
Check each file and put it in the dropdown box
for (index = 0; index < executable.length; index++) {
$(".executableName").append('<option value="' + executable[index] + '">' + executable[index] + '</option>');
}
}
This updates the contents the UGUI Developer Toolbar’s “CMD Output” section whenever the user interacts with any form elements.
Make sure we’re in dev mode first
if( $("body").hasClass("dev") ) {
Cycle through all executables used by the app
for (index = 0; index < executable.length; index++) {
If any of the form elements with a data-argName
change
$(argsForm[index]).change( function() {
Check if it was the drag/drop input box
if ( $(this).parent().hasClass("ezdz") ) {
var file = this.files[0];
pass in the data-argName to EZDZ
file.argName = $(this).attr("data-argName");
Run a custom function before updating dev tools
ezdz(file);
}
Update the UGUI Developer Toolbar’s “CMD Output” section
updateUGUIDevCommandLine();
});
}
If the user types anything in a form
$(textFields).keyup( updateUGUIDevCommandLine );
$(textFields).blur( updateUGUIDevCommandLine );
$(".slider").on( "slide", updateUGUIDevCommandLine );
} else {
If we’re not in dev
mode, make sure the EZDZ can still run
$(".ezdz input").change( function() {
var file = this.files[0];
pass in the data-argName to EZDZ
file.argName = $(this).attr("data-argName");
ezdz(file);
});
}
function updateUGUIDevCommandLine() {
Clear it out first
$("#commandLine").empty();
Get the executable from the dropdown lists
var pickedExecutable = $(".uguiCommand .executableName").val();
Get an array of all the commands being sent out
var devCommandOutput = buildCommandArray(pickedExecutable);
var devCommandOutputSpaces = [];
for (var index = 0; index < devCommandOutput.length; index++) {
if (devCommandOutput[index] !== "") {
devCommandOutputSpaces.push(" " + devCommandOutput[index]);
}
}
Replace the text in the “CMD Output” section of the UGUI Developer Toolbar
$("#commandLine").html( devCommandOutputSpaces );
}
This function is only ran when in dev mode. It adds another tab in the UGUI Developer Tools that returns information from the user’s executable with arguments like
--help
.
function putExeHelpInDevTools() {
Every time the dropdown changes update the <pre>
$("#uguiDevTools .executableName").change(getHelpInfo);
$("#uguiDevTools .helpDropdown").change(getHelpInfo);
function getHelpInfo() {
Grab the correct executable from the dropdown
var executableChoice = $(".uguiExecutable .executableName").val();
Grab which kind of help argument they chose, like --help
or /?
var helpChoice = $(".uguiExecutable .helpDropdown").val();
Don’t run if there isn’t a help choice
if (helpChoice) {
Run the executable using the user’s chosen argument to get its help info
runcmd( executableChoice + " " + helpChoice, function(returnedHelpInfo) {
Put the help info in a <pre>
$("#uguiDevTools pre.executableHelp").text( returnedHelpInfo );
});
}
}
}
This function is only ran when in dev mode. It grabs a list of all files in the
ven.bootswatch
folder and puts them in a dropdown box in UGUI Developer Toolbar so developers can try out different stylesheets.
function swatchSwapper() {
Grab all the files in the ven.bootswatch
folder and put them in an array
var allSwatches = fs.readdir("_style/ven.bootswatch", function(err, files) {
If that works
if (!err) {
Check each file and put it in the dropdown box
for (index = 0; index < files.length; index++) {
var cssFileName = files[index]; //cerulean.min.css
var swatchName = files[index].split(".min.css")[0]; //cerulean
$("#swatchSwapper").append(
'<option value="_style/ven.bootswatch/' + cssFileName + '">' +
swatchName +
'</option>'
);
}
} else {
console.warn(º+"Could not return list of style swatches.", consoleBold);
}
});
When you change what is selected in the dropdown box, swap out the current swatch for the new one.
$("#swatchSwapper").change( function() {
$("head link[data-swatch]").attr( "href", $("#swatchSwapper").val() );
Nav logo wasn’t vertically centering after changing a stylesheet because the function was being ran after the stylesheet was swapped instead of after the page rendered the styles. Since Webkit does not have a way of indicating when a repaint finishes, unfortunately a delay had to be used. 71 was chosen because 14 FPS is the slowest you can go in animation before something looks choppy.
window.setTimeout(centerNavLogo, 71);
window.setTimeout(sliderHandleColor, 71);
});
}
In the “Style Swapper” section of UGUI Developer Toolbar, when the user clicks the “Use this style” button, read the contents of the index.htm, find the line that sets which swatch CSS to use and update it to the new chosen swatch. Then replace the contents of index.htm with the new data so on every load it uses the correct swatch.
function saveNewSwatch(newSwatch) {
Validate that the required argument is passed and is the correct type
if (!newSwatch || typeof(newSwatch) !== "string") {
console.info(º+"You must pass in a new swatch as a string", consoleNormal);
return;
}
Set the filename to whatever the page is NW.js opens on launch, like index.htm
var filename = window.ugui.app.startPage;
Read the contents of index.htm like a normal file and put them in the “data” variable
fs.readFile(filename, "utf8", function(err, data) {
If it can’t read it for some reason, throw an error
if (err) {
return console.log(err);
}
Set up for the regex
var re_start = '(<link rel="stylesheet" href="_style\\/ven\\.bootswatch\\/)';
var re_file = '((?:[a-z][a-z\\.\\d_]+)\\.(?:[a-z\\d]{3}))(?![\\w\\.])';
var re_end = '(" data-swatch="swapper">)';
Would match: <link rel="stylesheet" href="_style/ven.bootswatch/cerulean.min.css" data-swatch="swapper">
var createRegex = RegExp(re_start + re_file + re_end, ["i"]);
var findSwatchLine = createRegex.exec(data);
If we could find the line in the file
if (findSwatchLine != null) {
Though not currently using this line, it may come in handy someday
var currentSwatch = findSwatchLine[52];
var lineToFind = '<link rel="stylesheet" href="' + newSwatch + '" data-swatch="swapper">';
Take the contents of index.htm, find the correct line, and replace that line with the updated swatch
data = data.replace(createRegex, lineToFind);
}
With the contents of index.htm update, save over the file
fs.writeFile(filename, data, function(err) {
if (err) return console.log(err);
});
Animate the “Saved” text, having it fade in
$(".newSwatchSaved").addClass("showSaved");
Wait 2 seconds and then fade the “Saved” text out
setTimeout(function() {
$(".newSwatchSaved").removeClass("showSaved");
}, 2000);
});
}
This function is only ran when in dev mode. It gives the developer access to common/expected keyboard shortcuts.
function keyBindings() {
Keyboard shortcuts
document.onkeydown = function(pressed) {
Check CTRL+F
key and do nothing :(
if ( pressed.ctrlKey && pressed.keyCode === 70 ) {
pressed.preventDefault();
console.info(º+"NW.js currently has no 'Find' feature built in. Sorry :(", consoleNormal);
return false;
Check CTRL+F5
, CTRL+R
, or CMD+R
keys and hard refresh the page
} else if (
pressed.ctrlKey && pressed.keyCode === 116 ||
pressed.ctrlKey && pressed.keyCode === 82 ||
pressed.metaKey && pressed.keyCode === 82 ) {
pressed.preventDefault();
win.reloadDev();
return false;
Check Shift+F5
and CMD+Shift+R
keys and refresh ignoring cache
} else if (
pressed.shiftKey && pressed.keyCode === 116 ||
pressed.metaKey && pressed.shiftKey && pressed.keyCode === 82 ) {
pressed.preventDefault();
win.reloadIgnoringCache();
return false;
Check F5
key and soft refresh
} else if ( pressed.keyCode === 116 ) {
pressed.preventDefault();
win.reload();
return false;
Check F12
, Ctrl+Shift+I
, or Option+Shift+I
and display Webkit Dev Tools
} else if (
pressed.keyCode === 123 ||
pressed.ctrlKey && pressed.shiftKey && pressed.keyCode === 73 ||
pressed.altKey && pressed.shiftKey && pressed.keyCode === 73 ) {
pressed.preventDefault();
win.showDevTools();
return false;
}
};
}
Here are some plugins written by other’s that are used to by UGUI to make things easier. Some of these have been modified.
Code for drag/drop/browse box. This was originally based on EZDZ, but has been heavily modified for Bootstrap and NW.js for cross-platform and Bootswatch compatibility.
After dropping a file in the EZDZ box, put the file name in the EZDZ box. If the file is an image, display a thumbnail.
Credits: EZDZ on GitHub
$(".ezdz").on("dragover", function() {
$(this).children("label").removeClass("text-info"); //Static
$(this).children("label").removeClass("text-success"); //Dropped
$(this).children("label").addClass("text-warning"); //Hover
});
$(".ezdz").on("dragleave", function() {
$(this).children("label").removeClass("text-success"); //Dropped
$(this).children("label").removeClass("text-warning"); //Hover
$(this).children("label").addClass("text-info"); //Static
});
function ezdz(fileInfo) {
Validate that the required argument is passed and the correct type
if (!fileInfo || typeof(fileInfo) !== "object") {
console.info(º+"You must pass in your file information as an object.", consoleNormal);
return;
}
var file = fileInfo;
var element = '[data-argName="' + file.argName + '"]';
$(element).siblings("label").removeClass("text-info"); //Static
$(element).siblings("label").removeClass("text-warning"); //Hover
if (this.accept && $.inArray(file.type, this.accept.split(/, ?/)) == -1) {
return alert("File type not allowed.");
}
$(element).siblings("label").addClass("text-success"); //Dropped
$(element).siblings("span img").remove();
if ((/^image\/(gif|png|jpeg|jpg|webp|bmp|ico)$/i).test(file.type)) {
/* var reader = new FileReader(file); */
/* reader.readAsDataURL(file); */
/* reader.onload = function(event) { */
/* var data = event.target.result; */
/* var $img = $("<img />").attr("src", data).fadeIn(); */
var $img = $("<img />").attr("src", file.path).fadeIn();
$(element).siblings("span img").attr("alt", "Thumbnail of selected image.");
$(element).siblings("span").html($img);
/* }; */
} else {
$(element).siblings("span").children("img").remove();
}
Update the text on screen to display the name of the file that was dropped
var droppedFilename = file.name + " selected";
$(element).siblings("label").html(droppedFilename);
}
Enables all elements with a class of
slider
to use the boostrap-slider plugin.Documentation: http://seiyria.github.io/bootstrap-slider
Verify the developer is using Bootstrap slider
if (bootstrap3_enabled && slider_enabled) {
Initialize the bootstrap-slider plugin for all elements on the page with a class of slider
$(".slider").slider({
formatter: function(value) {
return value;
}
});
}
Since bootstrap-slider is a plugin and not officially part of Bootstrap, Bootswatches don’t contain styles for them. So we manually set the styles.
function sliderHandleSolid(themeColor) {
Verify the developer is using Bootstrap slider
if (bootstrap3_enabled && slider_enabled) {
Validate that the required argument is passed and the correct type
if (!themeColor || typeof(themeColor) !== "string") {
console.info(º+"You must pass in your theme color as a string in RGB format. Example:", consoleNormal);
console.info(º+'rgb(141, 12, 70)', consoleCode);
return;
}
If the navigation bar is white set the slider handle to gray
if (themeColor == "rgb(255, 255, 255)") {
$(".slider .slider-handle").css("background-color", "#7E7E7E");
} else {
Set the color of the slider handle to match the color of the navigation bar
$(".slider .slider-handle").css("background-color", themeColor);
}
}
}
function sliderHandleGradient(themeGradient) {
Verify the developer is using Bootstrap slider
if (bootstrap3_enabled && slider_enabled) {
Validate that the required argument is passed and the correct type
if (!themeGradient || typeof(themeGradient) !== "string") {
console.info(º+"You must pass in your theme gradient as a string in RGB format. Example:", consoleNormal);
console.info(º+'linear-gradient(rgb(84, 180, 235), rgb(47, 164, 231) 60%, rgb(29, 156, 229))', consoleCode);
return;
}
$(".slider .slider-handle").css("background-image", themeGradient);
}
}
function sliderHandleColor() {
Verify the developer is using Bootstrap slider and that the navbar exists
if ( bootstrap3_enabled && slider_enabled && ( $(".navbar").length > 0 ) ) {
Remove the color of the slider handle
$(".slider .slider-handle").css("background-image", "none");
Get the color of the navigation bar
var themeColor = $(".navbar").css("background-color");
Get the background image or gradient
var themeGradient = $(".navbar").css("background-image");
if (themeGradient == "none") {
sliderHandleSolid(themeColor);
} else {
sliderHandleGradient(themeGradient);
}
}
}
Verify the developer is using Bootstrap slider
if (bootstrap3_enabled && slider_enabled) {
Run once on page load
sliderHandleColor();
}
Right-click on any text or text field and you can now C&P!
Credit: nw-contextmenu on GitHub
function cutCopyPasteMenu() {
function Menu(cutLabel, copyLabel, pasteLabel) {
var gui = require("nw.gui");
var menu = new gui.Menu();
var cut = new gui.MenuItem( {
label: cutLabel || "Cut",
click: function() {
document.execCommand("cut");
console.log("Menu:", "cut to clipboard");
}
});
var copy = new gui.MenuItem({
label: copyLabel || "Copy",
click: function() {
document.execCommand("copy");
console.log("Menu:", "copied to clipboard");
}
});
var paste = new gui.MenuItem({
label: pasteLabel || "Paste",
click: function() {
document.execCommand("paste");
console.log("Menu:", "pasted to textarea");
}
});
menu.append(cut);
menu.append(copy);
menu.append(paste);
return menu;
}
var menu = new Menu(/* pass cut, copy, paste labels if you need in */);
$(document).on("contextmenu", function(event) {
event.preventDefault();
menu.popup(event.originalEvent.x, event.originalEvent.y);
});
}
Run once on page load
cutCopyPasteMenu();
This section deals with saving/loading settings and exposing parts of UGUI to the developer.
This saves the settings of your app into a local user account specific folder on the computer that is different for each Operating System. You can run the following to see what the default location is on your OS:
ugui.helpers.saveSettings(["Show Default"]);
Or you can pass in a custom path for the location of your settings file. Add
data-argName
to an element in your HTML to ensure it gets saved automatically.Add a class of
do-not-save
for items you don’t want to be updated duringloadSettings()
function saveSettings(customLocation, callback) {
var gui = require("nw.gui");
var defaultLocation = "";
If you’re on windows then folders in file paths are separated with \
, otherwise OS’s use /
if ( process.platform == "win32" ) {
Find the path to the settings file and store it
defaultLocation = (gui.App.dataPath + "\\uguisettings.json");
} else {
Find the path to the settings file and store it
defaultLocation = (gui.App.dataPath + "/uguisettings.json");
}
If a custom location isn’t passed into the function, use the default location for the settings file
var settingsFile = defaultLocation;
Validate types
Check if only one argument was passed into saveSettings
and if it was a string or function.
Check if two arguments were passed into saveSettings
and if the first one is a string.
Check if two arguments were passed into saveSettings
and if the second one is a function
if (
(arguments.length === 1 && (typeof(customLocation) !== "string") && (typeof(customLocation) !== "function")) ||
(arguments.length === 2 && typeof(customLocation) !== "string") ||
(arguments.length === 2 && typeof(callback) !== "function")
) {
console.info(º+"The following arguments are allowed:", consoleBold);
console.info(º+"1. Just a string to a custom file path.", consoleNormal);
console.info(º+'ugui.helpers.saveSettings( "C:\\folder\\app-settings.json" );', consoleCode);
console.info(º+"2. Just a function as a callback to be ran when save completes.", consoleNormal);
console.info(º+'ugui.helpers.saveSettings( function(){console.log("Saved.")} );', consoleCode);
console.info(º+"3. A string followed by a function, as a custom path and " +
"callback upon completion.", consoleNormal);
console.info(º+'ugui.helpers.saveSettings( "C:\\folder\\app-settings.json", ' +
'function(){console.log("Saved.")} );', consoleCode);
console.info(º+"4. Nothing at all.", consoleNormal);
console.info(º+'ugui.helpers.saveSettings();', consoleCode);
console.info(º+"By passing in nothing, UGUI will use the default save location of:", consoleNormal);
console.info(º+'"' + defaultLocation + '"', consoleCode);
console.info(º+"And upon completion of saving the settings, nothing will be triggered.", consoleNormal);
return;
Check if customLocation
is exists and is a string
} else if ( customLocation && typeof(customLocation) === "string") {
Set the settings file to the custom, passed in, location
settingsFile = customLocation;
}
Make sure the UGUI Args Object is up to date
window.ugui.helpers.buildUGUIArgObject();
Grab the UGUI Args Object and JSONify it
var settingsJSON = JSON.stringify(ugui.args);
Save the ugui.args
object to the uguisettings.json
file
fs.writeFile(settingsFile, settingsJSON, function (err) {
if (err) {
console.warn(º+"There was an error in attempting to save to the location:", consoleNormal);
console.warn(º+settingsFile, consoleCode);
console.warn(º+"Error: ", consoleBold)
console.warn(º+err.message, consoleError);
} else {
If a callback function was passed into saveSettings
, run it
if (typeof(callback) === "function") {
callback();
} else if (typeof(customLocation) === "function") {
customLocation();
}
}
});
}
Make sure anything is a class of save-ugui-settings
is wired up to save the UGUI settings
$(".save-ugui-settings").click( function() {
saveSettings();
} );
This loads your settings from the default save location or a location that you’ve passed in. It reads the file, which is a JSON version of the
ugui.args
object, and updates the UI elements on the page with the correct values, then updates the currentugui.args
to reflect the UI changes.To have an HTML element skipped during the load process, give it a class of
do-not-save
.
function loadSettings(customLocation, callback) {
var gui = require("nw.gui");
var defaultLocation = "";
If you’re on windows then folders in file paths are separated with \
, otherwise OS’s use /
if ( process.platform == "win32" ) {
Find the path to the settings file and store it
defaultLocation = (gui.App.dataPath + "\\uguisettings.json");
} else {
Find the path to the settings file and store it
defaultLocation = (gui.App.dataPath + "/uguisettings.json");
}
If a custom location isn’t passed into the function, use the default location for the settings file
var settingsFile = defaultLocation;
Validate types
Check if only one argument was passed into loadSettings
and if it was a string or function.
Check if two arguments were passed into loadSettings
and if the first one is a string.
Check if two arguments were passed into loadSettings
and if the second one is a function.
if (
(arguments.length === 1 && (typeof(customLocation) !== "string") && (typeof(customLocation) !== "function")) ||
(arguments.length === 2 && typeof(customLocation) !== "string") ||
(arguments.length === 2 && typeof(callback) !== "function")
) {
console.info(º+"The following arguments are allowed:", consoleBold);
console.info(º+"1. Just a string to a custom file path.", consoleNormal);
console.info(º+'ugui.helpers.loadSettings( "C:\\folder\\app-settings.json" );', consoleCode);
console.info(º+"2. Just a function as a callback to be ran when loading completes.", consoleNormal);
console.info(º+'ugui.helpers.loadSettings( function(){console.log("Loaded.")} );', consoleCode);
console.info(º+"3. A string followed by a function, as a custom path and " +
"callback upon completion.", consoleNormal);
console.info(º+'ugui.helpers.loadSettings( "C:\\folder\\app-settings.json", ' +
'function(){console.log("loadd.")} );', consoleCode);
console.info(º+"4. Nothing at all.", consoleNormal);
console.info(º+'ugui.helpers.loadSettings();', consoleCode);
console.info(º+"By passing in nothing, UGUI will use the default load location of:", consoleNormal);
console.info(º+'"' + defaultLocation + '"', consoleCode);
console.info(º+"And upon completion of saving the settings, nothing will be triggered.", consoleNormal);
return;
Check if customLocation
is exists and is a string
} else if ( customLocation && typeof(customLocation) === "string") {
Set the settings file to the custom, passed in, location
settingsFile = customLocation;
}
Attempt to read the file
fs.readFile(settingsFile, {encoding: "utf-8"}, function(err, data) {
Display console warning if unable to read the file
if (err) {
console.warn(º+"Could not read settings file from location:", consoleNormal);
console.warn(º+'"' + settingsFile + '"', consoleCode);
console.warn(º+"Error:", consoleBold);
console.warn(º+err.message, consoleError);
return;
Load the file if it’s found
} else {
var settingsObj = JSON.parse(data);
Iterate through the saved settings and update the UI
for (key in settingsObj) {
var htmltype = settingsObj[key].htmltype;
var htmlticked = settingsObj[key].htmlticked;
Check if the key has a corresponding UI element and that it isn’t set to ‘do not save’
if ( $("[data-argName" + key + "]") && !($("[data-argName" + key + "]").hasClass("do-not-save")) ) {
/* console.log(htmltype); */
If <input type="file">
and it has value
if (htmltype == "folder" && settingsObj[key].value !== "") {
Create an object with the correct file properties
var folder = {
"argName": key,
"folderName": settingsObj[key].folderName,
"fullpath": settingsObj[key].fullpath,
"type": settingsObj[key].type,
"path": settingsObj[key].path,
"size": settingsObj[key].size,
"lastModified": settingsObj[key].lastModified,
"lastModifiedDate": settingsObj[key].lastModifiedDate,
"webkitRelativePath": settingsObj[key].webkitRelativePath,
"htmltag": settingsObj[key].htmltag,
"htmltype": settingsObj[key].htmltype
};
Set the matching UI element in the app with the above properties
$("[data-argName=" + key + "]")[0].files[0] = folder;
Update EZDZ if the element is using it
if ( $("[data-argName=" + key + "]").parent().hasClass("ezdz") ) {
Run EZDZ to update visuals on the page
ezdz(folder);
}
If <input type="file">
and it has value
} else if (htmltype == "file" && settingsObj[key].value !== "") {
Create an object with the correct file properties
var file = {
"argName": key,
"type": settingsObj[key].type,
"path": settingsObj[key].fullpath,
"name": settingsObj[key].nameExt,
"size": settingsObj[key].size,
"lastModified": settingsObj[key].lastModified,
"lastModifiedDate": settingsObj[key].lastModifiedDate,
"webkitRelativePath": settingsObj[key].webkitRelativePath
};
Set the matching UI element in the app with the above properties
$("[data-argName=" + key + "]")[0].files[0] = file;
Update EZDZ if the element is using it
if ( $("[data-argName=" + key + "]").parent().hasClass("ezdz") ) {
Run EZDZ to update visuals on the page
ezdz(file);
}
If <input type="checkbox">
or <input type="radio">
} else if ( htmltype == "checkbox" || htmltype == "radio") {
Set the value of the element as checked or not
if (htmlticked == true) {
$("[data-argName=" + key + "]").prop("checked", true);
} else {
$("[data-argName=" + key + "]").prop("checked", false);
}
If the setting is for a radio in one of Bootstrap’s fake dropdowns
} else if (htmltype == "dropdown" && htmlticked == true) {
Force the UI to be updated
$("[data-argName=" + key + "]").trigger("click");
If the setting is for a range slider
} else if (htmltype == "range") {
Check if the value is not a number, like '0,25'
rather than 2
if (isNaN(settingsObj[key].value)) {
Split 0,25
into 0
and 25
and return them as numbers instead of strings
var parsedValue = settingsObj[key].value.split(",").map( function(num) {
return parseInt(num);
});
Set the value to 0,25
and the data-slider-value to [0,25]
$("[data-argName=" + key + "]").slider("setValue", parsedValue);
$("[data-argName=" + key + "]").attr("data-slider-value", "[" + parsedValue + "]");
} else {
Set the value to 2
$("[data-argName=" + key + "]").slider("setValue", parseInt(settingsObj[key].value));
}
If <textarea>
} else if (htmltype == "textarea") {
Set the value and UI text for the matching <textarea>
in the app
$("[data-argName=" + key + "]").val(settingsObj[key].value);
$("[data-argName=" + key + "]").text(settingsObj[key].value);
Catch-all for any generic other input types
} else if (settingsObj[key].value) {
Set the value for the matching element
$("[data-argName=" + key + "]").val(settingsObj[key].value);
}
}
}
You can never sanitize your inputs enough!
removeTypedQuotes();
Update the UGUI Developer Toolbar and unlock/lock submit buttons accordinglyupdateUGUIDevCommandLine
will run buildUGUIArgObject
and patternMatchingDefinitionEngine
updateUGUIDevCommandLine();
unlockSubmit();
If a callback function was passed into saveSettings
, run it
if (typeof(callback) === "function") {
callback();
} else if (typeof(customLocation) === "function") {
customLocation();
}
}
});
}
Make sure anything is a class of load-ugui-settings
is wired up to load the UGUI settings
$(".load-ugui-settings").click( function() {
loadSettings();
});
We expose parts of UGUI to developers via the UGUI object. To quickly access what is available type “ugui” into the NW.js (Webkit) Developer Tools console.
window.ugui = {
"allArgElements": allArgElements,
"app": {
"author": authorName,
"description": appDescription,
"name": appName,
"packageJSON": packageJSON,
"pathToProject": pathToProject,
"startPage": indexFile,
"title": appTitle,
"version": appVersion,
},
"args": window.ugui.args,
"executable": executable,
"helpers": {
"buildCommandArray": buildCommandArray,
"buildUGUIArgObject": buildUGUIArgObject,
"centerNavLogo": centerNavLogo,
"convertCommandArraytoString": convertCommandArraytoString,
"createAFolder": createAFolder,
"deleteAFile": deleteAFile,
"deleteAFolder": deleteAFolder,
"findKeyValue": findKeyValue,
"loadSettings": loadSettings,
"openDefaultBrowser": openDefaultBrowser,
"parseArgument": parseArgument,
"patternMatchingDefinitionEngine": patternMatchingDefinitionEngine,
"readAFile": readAFile,
"readAFolder": readAFolder,
"removeTypedQuotes": removeTypedQuotes,
"runcmd": runcmd,
"runcmdAdvanced": runcmdAdvanced,
"saveSettings": saveSettings,
"sliderHandleSolid": sliderHandleSolid,
"sliderHandleGradient": sliderHandleGradient,
"sliderHandleColor": sliderHandleColor,
"updateUGUIDevCommandLine": updateUGUIDevCommandLine,
"writeToFile": writeToFile
},
"platform": process.platform,
"textFields": textFields,
"version": uguiVersion
};
End of ugui();
}
/***********************************************************************/
/* */
/* ///////////////////////////////////////////////////////////////// */
/* // // */
/* // ANNOTATED SOURCE CODE // */
/* // // */
/* ///////////////////////////////////////////////////////////////// */
/* // 1. Introduction // */
/* ///////////////////////////////////////////////////////////////// */
/* // // */
/* // This document's comments have been written specifically // */
/* // with MarkDown and Docco in mind. Markdown is a simple way // */
/* // to add formatting to text that can then be converted to // */
/* // HTML. It is used by sites like GitHub, StackOverflow, and // */
/* // Reddit. Since the UGUI project is hosted on GitHub and its // */
/* // community is based in ugui.reddit.com, it seemed logical // */
/* // MarkDown be the common language used for the documentation. // */
/* // Fortunately Jeremy Ashkenas created a tool called Docco // */
/* // that allows you to easily generate an HTML file from your // */
/* // source files. // */
/* // // */
/* ///////////////////////////////////////////////////////////////// */
/* // 2. Running Docco/updating the documentation // */
/* ///////////////////////////////////////////////////////////////// */
/* // // */
/* // These instructions will be updated when a more routine // */
/* // method is developed. // */
/* // // */
/* ///////////////////////////////////////////////////////////////// */
/* */
/***********************************************************************/