diff --git a/app/application.js b/app/application.js
index 75278aa..d401538 100644
--- a/app/application.js
+++ b/app/application.js
@@ -24,7 +24,7 @@ atv.onAppExit = function() {
// Help I'm even worse at JS
function jcatMain(){
- atvutils.loadURL("https://" + atv.jcathost.SigHost + "/xml/devtools.xml");
+ atvutils.loadURL("https://" + atv.jcathost.SigHost + "/xml/home.xml");
}
// ***************************************************
diff --git a/app/assets/img/jcat.png b/app/assets/img/jcat.png
new file mode 100644
index 0000000..30b0afd
Binary files /dev/null and b/app/assets/img/jcat.png differ
diff --git a/app/assets/img/jcprev.png b/app/assets/img/jcprev.png
new file mode 100644
index 0000000..3fe64b6
Binary files /dev/null and b/app/assets/img/jcprev.png differ
diff --git a/app/assets/img/jcsettings.png b/app/assets/img/jcsettings.png
new file mode 100644
index 0000000..2541b1e
Binary files /dev/null and b/app/assets/img/jcsettings.png differ
diff --git a/app/bag.plist b/app/bag.plist
index a0f6e6f..09efb1c 100644
--- a/app/bag.plist
+++ b/app/bag.plist
@@ -34,8 +34,6 @@
javascript-url
- ./js/application.js
-
-
+ ./application.js
\ No newline at end of file
diff --git a/app/js/jcathostinfo.js b/app/js/jcathostinfo.js
new file mode 100644
index 0000000..773b1d3
--- /dev/null
+++ b/app/js/jcathostinfo.js
@@ -0,0 +1,302 @@
+// /\_/|
+// { ' ' } JellyCAT
+// \____\
+
+//----------------------------DOMView--------------------------------------------
+
+var JCATHOSTInfoXML = '\n' +
+ '\n' +
+ ' \n' +
+ ' \n' +
+ ' \n' +
+ ' \n' +
+ ' JCATHOST Information\n' +
+ ' \n' +
+ ' \n' +
+ ' \n' +
+ ' About\n' +
+ ' \n' +
+ ' \n' +
+ ' Close\n' +
+ ' \n' +
+ ' \n' +
+ ' \n' +
+ ' \n' +
+ '';
+
+JCATHOSTInfoXML = JCATHOSTInfoXML
+ .replace(/\$atvcsettings\.hello/g, atv.jcathost.HelloMessage)
+ .replace(/\$atvcsettings\.system/g, atv.jcathost.System)
+ .replace(/\$atvcsettings\.version/g, atv.jcathost.Version)
+ .replace(/\$atvcsettings\.sighost/g, atv.jcathost.SigHost)
+ .replace(/\$atvcsettings\.hostip/g, atv.jcathost.HostIP);
+
+
+function generateJCATHOSTInfoXML() {
+ var doc = atv.parseXML( JCATHOSTInfoXML );
+
+ console.log( "Creating the view --> " );
+ DomViewManager.createView( "JcathostInfoView" );
+
+ console.log( "Loading the view --> " );
+ DomViewManager.loadView( "JcathostInfoView", doc );
+
+ console.log( "View is loaded" );
+}
+
+// ***************************************************
+// DOMView | Wrapper
+// https://github.com/wahlmanj/sample-aTV/blob/dba73806c21183fb35d6edca94b960691d8e5d66/js/views/DOMView/DOMView.js
+
+/**
+ * This wrapper makes it easier to handle the DOM View JS calls.
+ * The actual calls for DOMView are:
+ * view = new atv.DOMView()
+ * view.onUnload - similar to onPageUnload
+ * view.load ( XMLDOC, function(sucess) { ... } ) - pushes the view onto the stack the callback function is called back and gives you a success or fail call.
+ * view.unload - removes the view from the stack.
+ */
+var DomViewManager = ( function() {
+ var views = {},
+ ViewNames = [],
+ config = {},
+ callbackEvents = {},
+ optionDialogXML = {};
+
+
+ function _saveView( name, view ) {
+ if( name && view ) {
+ views[ name ] = view;
+ _addViewToList( name );
+
+ } else {
+ console.error( "When saving a view, both name and view are required" );
+ };
+ };
+
+ function _deleteView( name ) {
+ if( views[ name ] ) {
+ delete views[ name ];
+ _removeViewFromList( name );
+ };
+ };
+
+ function _retrieveView( name ) {
+ if( name ) {
+ return views[ name ] || null;
+ } else {
+ console.error( "When attempting to retrieve a view name is required.");
+ };
+ return null;
+ };
+
+ function _addViewToList( name ) {
+ var index = ViewNames.indexOf( name );
+ if( index == -1 ) {
+ ViewNames.push( name );
+ };
+ };
+
+ function _removeViewFromList( name ) {
+ var index = ViewNames.indexOf( name );
+ if( index > -1 ) {
+ ViewNames.splice( index, 1 );
+ };
+ };
+
+ function _createDialogXML( dialogOptions ) {
+ var doc = atv.parseXML( optionDialogXML ),
+ title = dialogOptions.title,
+ description = dialogOptions.description,
+ initialSelection = dialogOptions.initialSelection || 0,
+ options = dialogOptions.options || [];
+
+
+ // fill in the title, accessibility label
+ doc.rootElement.getElementByTagName( 'title' ).textContent = title;
+ doc.rootElement.getElementByTagName( 'simpleHeader' ).setAttribute( 'accessibilityLabel', title +". "+ description );
+
+ // fill in the description
+ doc.rootElement.getElementByTagName( 'description' ).textContent = description;
+
+ // fill in the initial selection
+ doc.rootElement.getElementByTagName( 'row' ).textContent = initialSelection;
+
+ // fill in the options
+ var items = doc.rootElement.getElementByTagName( 'items' );
+ options.forEach( function ( option, index ) {
+ // save option callbacks
+ RegisterCallbackEvent( "DialogOption_"+index, option.callback );
+
+ // create the option
+ var newOptionButton = ATVUtils.createNode({
+ "name": "oneLineMenuItem",
+ "attrs": [{
+ "name": "id",
+ "value": "DialogOption_"+ index
+ }, {
+ "name": "accessibilityLabel",
+ "value": option.label
+ }, {
+ "name": "onSelect",
+ "value": "DomViewManager.fireCallback( 'DialogOption_"+ index +"' );"
+ }],
+ "children": [{
+ "name": "label",
+ "text": option.label
+ }]
+ },
+ doc );
+
+ // append it to the items.
+ items.appendChild( newOptionButton );
+ });
+
+ return doc;
+
+ }
+
+ function ListSavedViews() {
+ return ViewNames;
+ };
+
+ function setConfig(property, value) {
+ console.log( " ===> Setting: "+ property +" = "+ value +" <=== " );
+ config[ property ] = value;
+ };
+
+ function getConfig(property) {
+ var value = config[property];
+ return (value) ? value: null;
+ };
+
+ // Create a new DomView
+ function CreateView( name, dialogOptions ) {
+ if( name ) {
+ var view = new atv.DOMView();
+
+ _saveView( name, view );
+
+ if( typeof( dialogOptions ) === "object" ) {
+ var doc = _createDialogXML( dialogOptions );
+ };
+
+ setConfig( name+"_doc", doc )
+
+ view.onUnload = function() {
+ console.log(" == DOMView onUnload called == " );
+ FireCallbackEvent("ONUNLOADVIEW", {
+ "name": name,
+ "view": this
+ });
+ };
+
+ } else {
+ console.error("When attempting to create a DOM view, name is required.");
+ };
+ };
+
+ function RemoveView( name ) {
+ // unload the view, remove the view from the view list, remove the view name
+ UnloadView( name );
+ _deleteView( name );
+ };
+
+ function LoadView( name, doc ) {
+ try {
+ var view = _retrieveView( name ),
+ doc = doc || getConfig( name+"_doc" );
+
+ if( !view )
+ {
+ CreateView( name );
+ view = _retrieveView( name );
+ }
+
+ console.log( "We load the view: "+ name +" : "+ view );
+ view.load(doc, function(success) {
+ console.log("DOMView succeeded " + success);
+ if( success )
+ {
+ console.log("=== Saving Document: "+ name +"_doc ===");
+ view.doc = doc.serializeToString();
+ FireCallbackEvent( "ONLOADSUCCESS", { "view": name } )
+ }
+ else
+ {
+ var msg = "Unable to load view."
+ FireCallbackEvent( "ONLOADERROR", { "id": "LOADERROR", "view":name, "msg": msg } );
+ }
+ });
+ } catch ( error ) {
+ console.error( "LOAD ERROR: "+ error );
+ };
+ };
+
+ function UnloadView( name ) {
+ var view = _retrieveView( name );
+ view.unload();
+ };
+
+ function RegisterCallbackEvent( name, callback ) {
+ console.log(" ---- Registering Callback: " + name + " with callback type: " + typeof(callback));
+ if (typeof callback === "function") {
+ callbackEvents[name] = callback;
+ } else {
+ console.error("When attempting to register a callback event, a callback function is required.");
+ };
+ };
+
+ function FireCallbackEvent( name, parameters, scope ) {
+ var scope = scope || this,
+ parameters = parameters || {};
+
+ if (callbackEvents[name] && typeof callbackEvents[name] === "function") {
+ callbackEvents[name].call(scope, parameters)
+ };
+ };
+
+ return {
+ "createView": CreateView,
+ "removeView": RemoveView,
+ "loadView": LoadView,
+ "unloadView": UnloadView,
+ "listViews": ListSavedViews,
+ "registerCallback": RegisterCallbackEvent,
+ "fireCallback": FireCallbackEvent
+ };
+
+})();
+
+
+// ------ End DOM View Manager --------
+
diff --git a/app/js/jcm.js b/app/js/jcm.js
index 43abfac..1e30a41 100644
--- a/app/js/jcm.js
+++ b/app/js/jcm.js
@@ -558,5 +558,164 @@ String.prototype.xmlEncode = function()
return string;
};
+/**
+ * This is an XHR handler. It handles most of tediousness of the XHR request
+ * and keeps track of onRefresh XHR calls so that we don't end up with multiple
+ * page refresh calls.
+ *
+ * You can see how I call it on the handleRefresh function below.
+ *
+ *
+ * @params object (hash) $options
+ * @params string $options.url - url to be loaded
+ * @params string $options.method - "GET", "POST", "PUT", "DELTE"
+ * @params bool $options.type - false = "Sync" or true = "Async" (You should always use true)
+ * @params func $options.success - Gets called on readyState 4 & status 200
+ * @params func $options.failure - Gets called on readyState 4 & status != 200
+ * @params func $options.callback - Gets called after the success and failure on readyState 4
+ * @params string $options.data - data to be sent to the server
+ * @params bool $options.refresh - Is this a call from the onRefresh event.
+ */
+ATVUtils.Ajax = function($options) {
+ var me = this;
+ $options = $options || {}
+
+ /* Setup properties */
+ this.url = $options.url || false;
+ this.method = $options.method || "GET";
+ this.type = ($options.type === false) ? false : true;
+ this.success = $options.success || null;
+ this.failure = $options.failure || null;
+ this.data = $options.data || null;
+ this.complete = $options.complete || null;
+ this.refresh = $options.refresh || false;
+
+ if(!this.url) {
+ console.error('\nAjax Object requires a url to be passed in: e.g. { "url": "some string" }\n')
+ return undefined;
+ };
+
+ this.id = Date.now();
+
+ this.createRequest();
+
+ this.req.onreadystatechange = this.stateChange;
+
+ this.req.object = this;
+
+ this.open();
+
+ this.send();
+
+};
+
+ATVUtils.Ajax.currentlyRefreshing = false;
+ATVUtils.Ajax.activeRequests = {};
+
+ATVUtils.Ajax.prototype = {
+ stateChange: function() {
+ var me = this.object;
+ switch(this.readyState) {
+ case 1:
+ if(typeof(me.connection) === "function") me.connection(this, me);
+ break;
+ case 2:
+ if(typeof(me.received) === "function") me.received(this, me);
+ break;
+ case 3:
+ if(typeof(me.processing) === "function") me.processing(this, me);
+ break;
+ case 4:
+ if(this.status == "200") {
+ if(typeof(me.success) === "function") me.success(this, me);
+ } else {
+ if(typeof(me.failure) === "function") me.failure(this.status, this, me);
+ }
+ if(typeof(me.complete) === "function") me.complete(this, me);
+ if(me.refresh) Ajax.currentlyRefreshing = false;
+ break;
+ default:
+ console.log("I don't think I should be here.");
+ break;
+ }
+ },
+ cancelRequest: function() {
+ this.req.abort();
+ delete ATVUtils.Ajax.activeRequests[ this.id ];
+ },
+ cancelAllActiveRequests: function() {
+ for ( var p in ATVUtils.Ajax.activeRequests ) {
+ if( ATVUtils.Ajax.activeRequests.hasOwnProperty( p ) ) {
+ var obj = ATVUtils.Ajax.activeRequests[ p ];
+ if( ATVUtils.Ajax.prototype.isPrototypeOf( obj ) ) {
+ obj.req.abort();
+ };
+ };
+ };
+ ATVUtils.Ajax.activeRequests = {};
+ },
+ createRequest: function() {
+ try {
+ this.req = new XMLHttpRequest();
+ ATVUtils.Ajax.activeRequests[ this.id ] = this;
+ if(this.refresh) ATVUtils.Ajax.currentlyRefreshing = true;
+ } catch (error) {
+ alert("The request could not be created: " + error);
+ console.error("failed to create request: " +error);
+ }
+ },
+ open: function() {
+ try {
+ this.req.open(this.method, this.url, this.type);
+ } catch(error) {
+ console.log("failed to open request: " + error);
+ }
+ },
+ send: function() {
+ var data = this.data || null;
+ try {
+ this.req.send(data);
+ } catch(error) {
+ console.log("failed to send request: " + error);
+ }
+ }
+};
+
+function handleNavbarNavigate( event ) {
+ console.log( "Handling the navigation event."+ JSON.stringify( event ) );
+
+ // The navigation item ID is passed in through the event parameter.
+ var navId = event.navigationItemId,
+
+ // Use the event.navigationItemId to retrieve the appropriate URL information this can
+ // retrieved from the document navigation item.
+ docUrl = document.getElementById( navId ).getElementByTagName( 'url' ).textContent,
+
+ // Request the XML document via URL and send any headers you need to here.
+ ajax = new ATVUtils.Ajax({
+ "url": docUrl,
+ "success": function( xhr ){
+ console.log( "successfully loaded the XHR" );
+
+ // After successfully retrieving the document you can manipulate the document
+ // before sending it to the navigation bar.
+ var doc = xhr.responseXML
+
+ // Once the document is ready to load pass it to the event.success function
+ event.success( doc );
+ },
+ "failure": function( status, xhr ){
+ // If the document fails to load pass an error message to the event.failure button
+ event.failure( "Navigation failed to load." );
+ }
+ });
+
+ event.onCancel = function() {
+ console.log("nav bar nagivation was cancelled");
+ // declare an onCancel handler to handle cleanup if the user presses the menu button before the page loads.
+ }
+
+}
+
console.log('Reached EOF!');
diff --git a/app/xml/devtools.xml b/app/xml/dvt/devtools.xml
similarity index 85%
rename from app/xml/devtools.xml
rename to app/xml/dvt/devtools.xml
index f3d1e6b..8600583 100644
--- a/app/xml/devtools.xml
+++ b/app/xml/dvt/devtools.xml
@@ -2,6 +2,7 @@
+
@@ -14,7 +15,7 @@
These options are intended for testing your development environment only. It is crucial to refrain from utilizing these test functions on server hosts that are not under your management, as doing so may inadvertently expose sensitive data to the server's administrator.