diff options
author | Marko Pušnik <marko.pusnik@guru.si> | 2015-10-05 15:57:43 +0200 |
---|---|---|
committer | Marko Pušnik <marko.pusnik@guru.si> | 2015-10-05 15:57:43 +0200 |
commit | 16e584cc8dc057290e14f829b507fbbef3cdf60f (patch) | |
tree | 2f6c0aa706f7d38425f69dd50f491b4492ba1a01 | |
parent | 28e59b13a7c348570ee15663dc5153c5c8012794 (diff) |
handle phonegap native mobile app
-rw-r--r-- | config.xml | 177 | ||||
-rw-r--r-- | cordova.js | 3 | ||||
-rw-r--r-- | index.html | 6 | ||||
-rw-r--r-- | js/codeq/comms.js | 4 | ||||
-rw-r--r-- | js/codeq/core.js | 84 | ||||
-rw-r--r-- | js/codeq/init.js | 100 |
6 files changed, 236 insertions, 138 deletions
@@ -3,8 +3,8 @@ <!-- config.xml reference: https://build.phonegap.com/docs/config-xml --> <widget xmlns = "http://www.w3.org/ns/widgets" xmlns:gap = "http://phonegap.com/ns/1.0" - id = "si.uni-lj.fri.codeq" - version = "0.0.1"> + id = "si.uni-lj.fri.gameteam.codeq" + version = "0.1.0"> <!-- 1.0 first release @@ -13,10 +13,10 @@ <name>Code Q</name> <description> - Code Q. + CodeQ je e-storitev in mobilna aplikacija za učenje programiranja. Aplikacija omogoča uporabniku samostojno učenje programiranja prek reševanja skrbno pripravljenih programerskih nalog s pomočjo samodejno generiranih namigov in avtomatskih testnih primerov. </description> - <author href="http://www.codeq.net" email="info@codeq.net"> + <author href="http://www.codeq.net" email="info@codeq.si"> Univerza v Ljubljani, Fakulteta za računalništvo in informatiko, A.I.LAB Ljubljana. </author> @@ -39,34 +39,49 @@ <preference name="exit-on-suspend" value="false" /> <!-- ios: if set to true, app will terminate when home button is pressed --> <preference name="show-splash-screen-spinner" value="true" /> <!-- ios: if set to false, the spinner won't appear on the splash screen during app loading --> <preference name="auto-hide-splash-screen" value="true" /> <!-- ios: if set to false, the splash screen must be hidden using a JavaScript API --> - <preference name="disable-cursor" value="false" /> <!-- blackberry: prevents a mouse-icon/cursor from being displayed on the app --> + <preference name="deployment-target" value="5.0" /> <!-- ios:--> <preference name="android-installLocation" value="auto" /> <!-- android: app install location. 'auto' will choose. 'internalOnly' is device memory. 'preferExternal' is SDCard. --> + <preference name="android-minSdkVersion" value="10" /> <!-- android:--> <!-- Define a specific version of PhoneGap to build into your app. <preference name="phonegap-version" value="3.5.0" /> --> + <preference name="phonegap-version" value="cli-5.2.0" /> - <!-- Plugins --> + <!-- Feature --> + <!-- + <feature name="http://api.phonegap.com/1.0/network" /> + <feature name="http://api.phonegap.com/1.0/camera" /> + <feature name="http://api.phonegap.com/1.0/notification" /> + <feature name="http://api.phonegap.com/1.0/geolocation" /> + <feature name="http://api.phonegap.com/1.0/media" /> + <feature name="http://api.phonegap.com/1.0/contacts" /> + <feature name="http://api.phonegap.com/1.0/file" /> + <feature name="http://api.phonegap.com/1.0/battery" /> + <feature name="http://api.phonegap.com/1.0/device" /> + --> - <!-- Core plugins --> - <gap:plugin name="org.apache.cordova.battery-status" /> - <gap:plugin name="org.apache.cordova.camera" /> - <gap:plugin name="org.apache.cordova.media-capture" /> - <gap:plugin name="org.apache.cordova.console" /> - <gap:plugin name="org.apache.cordova.contacts" /> - <gap:plugin name="org.apache.cordova.device" /> - <gap:plugin name="org.apache.cordova.device-motion" /> - <gap:plugin name="org.apache.cordova.device-orientation" /> - <gap:plugin name="org.apache.cordova.dialogs" /> - <gap:plugin name="org.apache.cordova.file" /> - <gap:plugin name="org.apache.cordova.file-transfer" /> - <gap:plugin name="org.apache.cordova.geolocation" /> - <gap:plugin name="org.apache.cordova.globalization" /> - <gap:plugin name="org.apache.cordova.inappbrowser" /> - <gap:plugin name="org.apache.cordova.media" /> - <gap:plugin name="org.apache.cordova.network-information" /> - <gap:plugin name="org.apache.cordova.splashscreen" /> - <gap:plugin name="org.apache.cordova.vibration" /> + <!-- Plugins --> + <!-- + <gap:plugin name="org.apache.cordova.battery-status" version="0.2.11" /> + <gap:plugin name="org.apache.cordova.camera" version="0.3.2" /> + <gap:plugin name="org.apache.cordova.console" version="0.2.11" /> + <gap:plugin name="org.apache.cordova.contacts" version="0.2.13" /> + <gap:plugin name="org.apache.cordova.device" version="0.2.12" /> + <gap:plugin name="org.apache.cordova.device-motion" version="0.2.10" /> + <gap:plugin name="org.apache.cordova.device-orientation" version="0.3.9" /> + <gap:plugin name="org.apache.cordova.dialogs" version="0.2.10" /> + <gap:plugin name="org.apache.cordova.file" version="1.3.1" /> + <gap:plugin name="org.apache.cordova.file-transfer" version="0.4.6" /> + <gap:plugin name="org.apache.cordova.geolocation" version="0.3.10" /> + <gap:plugin name="org.apache.cordova.globalization" version="0.3.1" /> + <gap:plugin name="org.apache.cordova.inappbrowser" version="0.5.2" /> + <gap:plugin name="org.apache.cordova.media" version="0.2.13" /> + <gap:plugin name="org.apache.cordova.media-capture" version="0.3.3" /> + <gap:plugin name="org.apache.cordova.network-information" version="0.2.12" /> + <gap:plugin name="org.apache.cordova.splashscreen" version="0.3.4" /> + <gap:plugin name="org.apache.cordova.vibration" version="0.3.11" /> + --> <!-- Third party plugins --> <!-- A list of available plugins are available at https://build.phonegap.com/plugins --> @@ -76,32 +91,90 @@ <!-- Define app icon for each platform. --> <icon src="icon.png" /> - <icon src="res/icon/android/icon-36-ldpi.png" gap:platform="android" gap:qualifier="ldpi" /> - <icon src="res/icon/android/icon-48-mdpi.png" gap:platform="android" gap:qualifier="mdpi" /> - <icon src="res/icon/android/icon-72-hdpi.png" gap:platform="android" gap:qualifier="hdpi" /> - <icon src="res/icon/android/icon-96-xhdpi.png" gap:platform="android" gap:qualifier="xhdpi" /> - <icon src="res/icon/blackberry/icon-80.png" gap:platform="blackberry" /> - <icon src="res/icon/blackberry/icon-80.png" gap:platform="blackberry" gap:state="hover"/> - <icon src="res/icon/ios/icon-57.png" gap:platform="ios" width="57" height="57" /> - <icon src="res/icon/ios/icon-72.png" gap:platform="ios" width="72" height="72" /> - <icon src="res/icon/ios/icon-57-2x.png" gap:platform="ios" width="114" height="114" /> - <icon src="res/icon/ios/icon-72-2x.png" gap:platform="ios" width="144" height="144" /> - <icon src="res/icon/webos/icon-64.png" gap:platform="webos" /> - <icon src="res/icon/windows-phone/icon-48.png" gap:platform="winphone" /> - <icon src="res/icon/windows-phone/icon-173.png" gap:platform="winphone" gap:role="background" /> + + <!-- iOS --> + <!-- iPhone 6 / 6+ --> + <icon src="icon-60@3x.png" gap:platform="ios" width="180" height="180" /> + + <!-- iPhone / iPod Touch --> + <icon src="icon-60.png" gap:platform="ios" width="60" height="60" /> + <icon src="icon-60@2x.png" gap:platform="ios" width="120" height="120" /> + + <!-- iPad --> + <icon src="icon-76.png" gap:platform="ios" width="76" height="76" /> + <icon src="icon-76@2x.png" gap:platform="ios" width="152" height="152" /> + + <!-- Settings Icon --> + <icon src="icon-small.png" gap:platform="ios" width="29" height="29" /> + <icon src="icon-small@2x.png" gap:platform="ios" width="58" height="58" /> + + <!-- Spotlight Icon --> + <icon src="icon-40.png" gap:platform="ios" width="40" height="40" /> + <icon src="icon-40@2x.png" gap:platform="ios" width="80" height="80" /> + + <!-- iPhone / iPod Touch --> + <icon src="icon.png" gap:platform="ios" width="57" height="57" /> + <icon src="icon@2x.png" gap:platform="ios" width="114" height="114" /> + + <!-- iPad --> + <icon src="icon-72.png" gap:platform="ios" width="72" height="72" /> + <icon src="icon-72@2x.png" gap:platform="ios" width="144" height="144" /> + + <!-- iPhone Spotlight and Settings Icon --> + <icon src="icon-small.png" gap:platform="ios" width="29" height="29" /> + <icon src="icon-small@2x.png" gap:platform="ios" width="58" height="58" /> + + <!-- iPad Spotlight and Settings Icon --> + <icon src="icon-50.png" gap:platform="ios" width="50" height="50" /> + <icon src="icon-50@2x.png" gap:platform="ios" width="100" height="100" /> + + <!-- Android --> + <icon src="ldpi.png" gap:platform="android" gap:qualifier="ldpi" /> + <icon src="mdpi.png" gap:platform="android" gap:qualifier="mdpi" /> + <icon src="hdpi.png" gap:platform="android" gap:qualifier="hdpi" /> + <icon src="xhdpi.png" gap:platform="android" gap:qualifier="xhdpi" /> + <icon src="xxhdpi.png" gap:platform="android" gap:qualifier="xxhdpi" /> + <icon src="fr-xxhdpi.png" gap:platform="android" gap:qualifier="fr-xxhdpi" /> + + <!-- Windows Phone --> + <icon src="icon.png" gap:platform="winphone" /> + <icon src="tileicon.png" gap:platform="winphone" gap:role="background" /> <!-- Define app splash screen for each platform. --> - <gap:splash src="res/screen/android/screen-ldpi-portrait.png" gap:platform="android" gap:qualifier="port-ldpi" /> - <gap:splash src="res/screen/android/screen-mdpi-portrait.png" gap:platform="android" gap:qualifier="port-mdpi" /> - <gap:splash src="res/screen/android/screen-hdpi-portrait.png" gap:platform="android" gap:qualifier="port-hdpi" /> - <gap:splash src="res/screen/android/screen-xhdpi-portrait.png" gap:platform="android" gap:qualifier="port-xhdpi" /> - <gap:splash src="res/screen/blackberry/screen-225.png" gap:platform="blackberry" /> - <gap:splash src="res/screen/ios/screen-iphone-portrait.png" gap:platform="ios" width="320" height="480" /> - <gap:splash src="res/screen/ios/screen-iphone-portrait-2x.png" gap:platform="ios" width="640" height="960" /> - <gap:splash src="res/screen/ios/screen-iphone-portrait-568h-2x.png" gap:platform="ios" width="640" height="1136" /> - <gap:splash src="res/screen/ios/screen-ipad-portrait.png" gap:platform="ios" width="768" height="1024" /> - <gap:splash src="res/screen/ios/screen-ipad-landscape.png" gap:platform="ios" width="1024" height="768" /> - <gap:splash src="res/screen/windows-phone/screen-portrait.jpg" gap:platform="winphone" /> + <gap:splash src="splash.png" /> + + <!-- iOS --> + <!-- iPhone and iPod touch --> + <gap:splash src="Default.png" gap:platform="ios" width="320" height="480" /> + <gap:splash src="Default@2x.png" gap:platform="ios" width="640" height="960" /> + + <!-- iPhone 5 / iPod Touch (5th Generation) --> + <gap:splash src="Default-568h@2x.png" gap:platform="ios" width="640" height="1136" /> + + <!-- iPhone 6 --> + <gap:splash src="Default-667h@2x.png" gap:platform="ios" width="750" height="1334" /> + <gap:splash src="Default-Portrait-736h@3x.png" gap:platform="ios" width="1242" height="2208" /> + <gap:splash src="Default-Landscape-736h@3x.png" gap:platform="ios" width="2208" height="1242" /> + + <!-- iPad --> + <gap:splash src="Default-Portrait.png" gap:platform="ios" width="768" height="1024" /> + <gap:splash src="Default-Landscape.png" gap:platform="ios" width="1024" height="768" /> + + <!-- Retina iPad --> + <gap:splash src="Default-Portrait@2x.png" gap:platform="ios" width="1536" height="2048" /> + <gap:splash src="Default-Landscape@2x.png" gap:platform="ios" width="2048" height="1536" /> + + <!-- Android --> + <gap:splash src="ldpi.png" gap:platform="android" gap:qualifier="ldpi" /> + <gap:splash src="mdpi.png" gap:platform="android" gap:qualifier="mdpi" /> + <gap:splash src="hdpi.png" gap:platform="android" gap:qualifier="hdpi" /> + <gap:splash src="xhdpi.png" gap:platform="android" gap:qualifier="xhdpi" /> + <gap:splash src="fr-xhdpi.png" gap:platform="android" gap:qualifier="fr-xhdpi" /> + <gap:splash src="portrait-xxhdpi.png" gap:platform="android" gap:qualifier="port-xxhdpi" /> + <gap:splash src="landscape-xxhdpi.png" gap:platform="android" gap:qualifier="land-xxhdpi" /> + + <!-- Windows Phone --> + <gap:splash src="splash/winphone/splash.jpg" gap:platform="winphone" /> <gap:config-file platform="ios" parent="CFBundleShortVersionString"> <string>100</string> @@ -121,9 +194,11 @@ --> <access origin="*"/> - <!-- Added the following intents to support the removal of whitelist code from base cordova to a plugin --> - <!-- Whitelist configuration. Refer to https://cordova.apache.org/docs/en/edge/guide_appdev_whitelist_index.md.html --> + + <!-- Whitelist configuration. Refer to https://github.com/apache/cordova-plugin-whitelist --> <plugin name="cordova-plugin-whitelist" version="1" /> + <!-- Intent Whitelist --> + <!-- Controls which URLs the app is allowed to ask the system to open. By default, no external URLs are allowed. --> <allow-intent href="http://*/*" /> <allow-intent href="https://*/*" /> <allow-intent href="tel:*" /> diff --git a/cordova.js b/cordova.js new file mode 100644 index 0000000..1aa58fd --- /dev/null +++ b/cordova.js @@ -0,0 +1,3 @@ +// differentiates between a native Phonegap/Cordova app, and a web app +// a Phonegap/Cordova build injects a native version of this file +codeq.isWebApp = true;
\ No newline at end of file @@ -468,8 +468,6 @@ <script src="js/q.js"></script> <!-- Bootstrap --> <script src="js/bootstrap/bootstrap.min.js"></script> - <!-- Cordova/PhoneGap --> - <script type="text/javascript" src="cordova.js"></script> <!-- CodeMirror stuff --> <script src="js/codemirror/codemirror.js"></script> <script src="js/codemirror/matchbrackets.js"></script> @@ -478,6 +476,10 @@ <script src="js/codemirror/show-hint.js"></script> <!-- codeq app --> <script src="js/codeq/core.js"></script> + <!-- Cordova/PhoneGap --> + <script type="text/javascript" src="cordova.js"></script> + <!-- codeq app cont. --> + <script src="js/codeq/init.js"></script> <script src="js/codeq/translation.js"></script> <script src="js/codeq/statusbar.js"></script> <script src="js/codeq/navigation.js"></script> diff --git a/js/codeq/comms.js b/js/codeq/comms.js index ad2376e..3671e95 100644 --- a/js/codeq/comms.js +++ b/js/codeq/comms.js @@ -198,7 +198,7 @@ }, ajaxPrefix, ajaxDataPrefix, ajaxResPrefix; - ajaxPrefix = location.pathname; + ajaxPrefix = codeq.ajaxPrefix; if (!ajaxPrefix) ajaxPrefix = '/'; else if (ajaxPrefix[ajaxPrefix.length - 1] !== '/') { ajaxPrefix = ajaxPrefix.split('/'); @@ -233,7 +233,7 @@ else { // create a new connection connectPromise = deferred; - socket = eio('ws://' + location.host, { + socket = eio(codeq.eioHost, { 'upgrade': true, 'path': '/ws', 'transports': ['polling', 'websocket'] diff --git a/js/codeq/core.js b/js/codeq/core.js index 2d88f18..02bc2f0 100644 --- a/js/codeq/core.js +++ b/js/codeq/core.js @@ -393,6 +393,7 @@ 'en': 'English', 'sl': 'Slovenščina' }, + 'isWebApp': false, // this is a PhoneGap/Cordova build, will be overridden in cordova.js for webapp 'getLang': function () { return lang; }, @@ -570,87 +571,4 @@ } } }; - - var loadGuiTranslations = function () { - var langs = codeq.availableLangs, - loaders = [], - loaderLangs = [], - i, lang; - for (i = langs.length - 1; i >= 0; i--) { - lang = langs[i]; - loaders.push(codeq.comms.getGuiTranslation(lang)); - loaderLangs.push(lang); - } - return Q.all(loaders) - .then(function (results) { - // convert translations into something that the translation module can use - var dictionary = {}, - i, json, key, lang, translations; - for (i = results.length - 1; i >= 0; i--) { - json = results[i]; - lang = loaderLangs[i]; - for (key in json) { - if (!json.hasOwnProperty(key)) continue; - translations = dictionary[key]; - if (translations) translations[lang] = json[key]; - else { - translations = {}; - dictionary[key] = translations; - translations[lang] = json[key]; - } - } - } - // ensure each key contains all translations - for (key in dictionary) { - if (!dictionary.hasOwnProperty(key)) continue; - translations = dictionary[key]; - for (i = langs.length - 1; i >= 0; i--) { - lang = langs[i]; - if (!(lang in translations)) translations[lang] = "(Untranslated: " + lang + ")"; - } - } - // register with the system - codeq.tr.registerDictionary('gui', dictionary); - }); - }; - - // ================================================================================ - // The boot sequence - // ================================================================================ - - $(document).ready(function () { - // set the language - var navigatorLang = navigator.language || navigator.browserLanguage, // language reported by browser - lang = null, // the translation language that will be chosen - key; - if (typeof navigatorLang === 'string') { - navigatorLang = navigatorLang.split('-')[0]; // truncate the language variant, in eg. en-US - } - else navigatorLang = 'en'; - for (key in codeq.supportedLangs) { - if (!codeq.supportedLangs.hasOwnProperty(key)) continue; - if (key === navigatorLang) lang = key; // we support the browser's language - codeq.availableLangs.push(key); - } - - // the boot chain of async handlers: must be a sequence of .then() terminated with a .fail().done() - loadGuiTranslations() - .then(codeq.comms.getResourceTree) - .then(function (resourceTree) { - resources = resourceTree; // save the loaded resource tree to the internal variable - - codeq.fire('init'); // tell any interested modules that we are now initialized, perhaps they want to initialize too - codeq.setLang(lang || 'en'); // initial language setting, this also translates the GUI - // go to login - codeq.globalStateMachine.transition('login'); - - //For performance reasons, the Tooltip and Popover data-apis are opt-in, meaning you must initialize them yourself. - $('[data-toggle="popover"]').popover() - }) - .fail(function (e) { - codeq.log.error('CodeQ failed to start: ' + e, e); - alert('CodeQ failed to start: ' + e); - }) - .done(); - }); })(); diff --git a/js/codeq/init.js b/js/codeq/init.js new file mode 100644 index 0000000..b7e903c --- /dev/null +++ b/js/codeq/init.js @@ -0,0 +1,100 @@ +(function () { + + + var loadGuiTranslations = function () { + var langs = codeq.availableLangs, + loaders = [], + loaderLangs = [], + i, lang; + for (i = langs.length - 1; i >= 0; i--) { + lang = langs[i]; + loaders.push(codeq.comms.getGuiTranslation(lang)); + loaderLangs.push(lang); + } + return Q.all(loaders) + .then(function (results) { + // convert translations into something that the translation module can use + var dictionary = {}, + i, json, key, lang, translations; + for (i = results.length - 1; i >= 0; i--) { + json = results[i]; + lang = loaderLangs[i]; + for (key in json) { + if (!json.hasOwnProperty(key)) continue; + translations = dictionary[key]; + if (translations) translations[lang] = json[key]; + else { + translations = {}; + dictionary[key] = translations; + translations[lang] = json[key]; + } + } + } + // ensure each key contains all translations + for (key in dictionary) { + if (!dictionary.hasOwnProperty(key)) continue; + translations = dictionary[key]; + for (i = langs.length - 1; i >= 0; i--) { + lang = langs[i]; + if (!(lang in translations)) translations[lang] = "(Untranslated: " + lang + ")"; + } + } + // register with the system + codeq.tr.registerDictionary('gui', dictionary); + }); + }; + + // ================================================================================ + // The boot sequence + // ================================================================================ + + var Boot = function () { + // set the language + var navigatorLang = navigator.language || navigator.browserLanguage, // language reported by browser + lang = null, // the translation language that will be chosen + key; + if (typeof navigatorLang === 'string') { + navigatorLang = navigatorLang.split('-')[0]; // truncate the language variant, in eg. en-US + } + else navigatorLang = 'en'; + for (key in codeq.supportedLangs) { + if (!codeq.supportedLangs.hasOwnProperty(key)) continue; + if (key === navigatorLang) lang = key; // we support the browser's language + codeq.availableLangs.push(key); + } + + // the boot chain of async handlers: must be a sequence of .then() terminated with a .fail().done() + loadGuiTranslations() + .then(codeq.comms.getResourceTree) + .then(function (resourceTree) { + resources = resourceTree; // save the loaded resource tree to the internal variable + + codeq.fire('init'); // tell any interested modules that we are now initialized, perhaps they want to initialize too + codeq.setLang(lang || 'en'); // initial language setting, this also translates the GUI + // go to login + codeq.globalStateMachine.transition('login'); + + //For performance reasons, the Tooltip and Popover data-apis are opt-in, meaning you must initialize them yourself. + $('[data-toggle="popover"]').popover() + }) + .fail(function (e) { + codeq.log.error('CodeQ failed to start: ' + e, e); + alert('CodeQ failed to start: ' + e); + }) + .done(); + }; + + if (codeq.isWebApp) { + // we are a web app + $(window).on('load', Boot); + codeq.ajaxPrefix = location.pathname; + codeq.eioHost= 'ws://' + location.host; + } + else { + // we are a phonegap native app + document.addEventListener("deviceready", Boot, false); + codeq.ajaxPrefix = 'http://codeq.si/'; + codeq.eioHost= 'ws://codeq.si'; + } + +})(); |