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 @@