diff --git a/UI/Templates/Themes/mobile/CommonUI/UIxPageFrame.wox b/UI/Templates/Themes/mobile/CommonUI/UIxPageFrame.wox new file mode 100644 index 000000000..90101fb0b --- /dev/null +++ b/UI/Templates/Themes/mobile/CommonUI/UIxPageFrame.wox @@ -0,0 +1,66 @@ + + + + + + + + <var:string value="title"/> + + + + + + + + + + + + + + + + + + + + + + diff --git a/UI/Templates/Themes/mobile/ContactsUI/UIxContactFoldersView.wox b/UI/Templates/Themes/mobile/ContactsUI/UIxContactFoldersView.wox new file mode 100644 index 000000000..fa19f3ded --- /dev/null +++ b/UI/Templates/Themes/mobile/ContactsUI/UIxContactFoldersView.wox @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/UI/Templates/Themes/mobile/MainUI/SOGoRootPage.wox b/UI/Templates/Themes/mobile/MainUI/SOGoRootPage.wox new file mode 100644 index 000000000..1e743cdc8 --- /dev/null +++ b/UI/Templates/Themes/mobile/MainUI/SOGoRootPage.wox @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + diff --git a/UI/WebServerResources/js/Common/ui-mobile.js b/UI/WebServerResources/js/Common/ui-mobile.js new file mode 100644 index 000000000..96fd8c2cd --- /dev/null +++ b/UI/WebServerResources/js/Common/ui-mobile.js @@ -0,0 +1,41 @@ +/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* JavaScript for SOGoContacts */ + +(function() { + 'use strict'; + + /* Constructor */ + function Dialog() { + } + + Dialog.alert = function(title, content) { + var alertPopup = this.$ionicPopup.alert({ + title: title, + template: content + }); + // alertPopup.then(function(res) { + // console.log('Thank you for not eating my delicious ice cream cone'); + // }); + }; + + Dialog.$factory = ['$ionicPopup', function($ionicPopup) { + angular.extend(Dialog, { $ionicPopup: $ionicPopup }); + + return Dialog; // return constructor + }]; + + angular.module('SOGo.UIMobile', ['ionic']) + + .factory('sgDialog', Dialog.$factory); + // angular.module('SOGo').factory('sgDialog', Dialog); + + // Dialog.prototype.alert = function(title, content) { + // var alertPopup = $ionicPopup.alert({ + // title: title, + // template: content + // }); + // alertPopup.then(function(res) { + // console.log('Thank you for not eating my delicious ice cream cone'); + // }); + // }; +})(); diff --git a/UI/WebServerResources/js/mobile/ContactsUI.js b/UI/WebServerResources/js/mobile/ContactsUI.js new file mode 100644 index 000000000..00a234fe5 --- /dev/null +++ b/UI/WebServerResources/js/mobile/ContactsUI.js @@ -0,0 +1,167 @@ +/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* JavaScript for SOGoContacts (mobile) */ + +(function() { + 'use strict'; + + angular.module('SOGo.Common', []); + + angular.module('SOGo.Contacts', ['ionic', 'SOGo.Common', 'SOGo.Contacts']) + + .constant('sgSettings', { + 'baseURL': '/SOGo/so/francis/Contacts' + }) + + .run(function($ionicPlatform) { + $ionicPlatform.ready(function() { + // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard + // for form inputs) + if(window.cordova && window.cordova.plugins.Keyboard) { + cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true); + } + if(window.StatusBar) { + // org.apache.cordova.statusbar required + StatusBar.styleDefault(); + } + }); + }) + + .config(function($stateProvider, $urlRouterProvider) { + $stateProvider + .state('app', { + url: "/app", + abstract: true, + templateUrl: "menu.html", + controller: 'AppCtrl' + }) + + .state('app.addressbooks', { + url: "/addressbooks", + views: { + 'menuContent': { + templateUrl: "addressbooks.html", + controller: 'AddressBooksCtrl' + } + } + }) + + .state('app.addressbook', { + url: "/addressbook/:addressbook_id", + views: { + 'menuContent': { + templateUrl: "addressbook.html", + controller: 'AddressBookCtrl' + } + } + }) + + .state('app.contact', { + url: "/addressbook/:addressbook_id/:card_id", + views: { + 'menuContent': { + templateUrl: "card.html", + controller: 'CardCtrl' + } + } + }); + + // if none of the above states are matched, use this as the fallback + $urlRouterProvider.otherwise('/app/addressbooks'); + }) + +// .directive('sgAddress', function() { +// return { +// restrict: 'A', +// replace: false, +// scope: { data: '=sgAddress' }, +// controller: ['$scope', function($scope) { +// $scope.addressLines = function(data) { +// var lines = []; +// if (data.street) lines.push(data.street); +// if (data.street2) lines.push(data.street2); +// var locality_region = []; +// if (data.locality) locality_region.push(data.locality); +// if (data.region) locality_region.push(data.region); +// if (locality_region.length > 0) lines.push(locality_region.join(', ')); +// if (data.country) lines.push(data.country); +// if (data.postalcode) lines.push(data.postalcode); +// return lines.join('
'); +// }; +// }], +// template: '
' +// } +// }) + +.controller('AppCtrl', ['$scope', '$http', function($scope, $http) { + $scope.UserLogin = UserLogin; + $scope.UserFolderURL = UserFolderURL; + $scope.ApplicationBaseURL = ApplicationBaseURL; + // $scope.logout = function(url) { + // $http.get(url) + // .success(function(data, status, headers) { + // console.debug(headers); + // }); + // }; +}]) + +.controller('AddressBooksCtrl', ['$scope', '$rootScope', '$timeout', 'sgAddressBook', function($scope, $rootScope, $timeout, AddressBook) { + // Initialize with data from template + $scope.addressbooks = AddressBook.$all(contactFolders); + // $scope.select = function(rowIndex) { + // $rootScope.selectedAddressBook = $rootScope.addressbooks[rowIndex]; + // }; + // $scope.rename = function() { + // console.debug("rename folder"); + // $scope.editMode = $rootScope.addressbook.id; + // //focus('folderName'); + // }; + // $scope.save = function() { + // console.debug("save addressbook"); + // $rootScope.addressbook.$save() + // .then(function(data) { + // console.debug("saved!"); + // $scope.editMode = false; + // }, function(data, status) { + // console.debug("failed"); + // }); + // }; +}]) + + .controller('AddressBookCtrl', ['$scope', '$rootScope', '$stateParams', 'sgAddressBook', function($scope, $rootScope, $stateParams, AddressBook) { + var id = $stateParams.addressbook_id; + $rootScope.addressbook = AddressBook.$find(id); + + $scope.search = { 'status': null, 'filter': null, 'last_filter': null }; + $scope.doSearch = function(keyEvent) { + if ($scope.search.last_filter != $scope.search.filter) { + if ($scope.search.filter.length > 2) { + $rootScope.addressbook.$filter($scope.search.filter).then(function(data) { + if (data.length == 0) + $scope.search.status = 'no-result'; + else + $scope.search.status = ''; + }); + } + else if ($scope.search.filter.length == 0) { + $scope.searchStatus = ''; + $rootScope.addressbook = AddressBook.$find(id); + } + else { + $scope.search.status = 'min-char'; + $rootScope.addressbook.cards = []; + } + } + $scope.search.last_filter = $scope.search.filter; + }; + + }]) + + .controller('CardCtrl', ['$scope', '$rootScope', '$stateParams', 'sgAddressBook', 'sgCard', function($scope, $rootScope, $stateParams, AddressBook, Card) { + $scope.UserFolderURL = UserFolderURL; + if (!$rootScope.addressbook) { + $rootScope.addressbook = AddressBook.$find($stateParams.addressbook_id); + } + $rootScope.addressbook.$getCard($stateParams.card_id); + }]) + +})(); diff --git a/UI/WebServerResources/js/mobile/SOGoRootPage.js b/UI/WebServerResources/js/mobile/SOGoRootPage.js new file mode 100644 index 000000000..f52ff9d19 --- /dev/null +++ b/UI/WebServerResources/js/mobile/SOGoRootPage.js @@ -0,0 +1,66 @@ +/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* JavaScript for SOGoRootPage (mobile) */ + +(function() { + 'use strict'; + + angular.module('SOGo.RootPage', ['SOGo.Authentication', 'SOGo.UIMobile', 'ionic']) + + .constant('sgSettings', { + 'baseURL': '/SOGo/so/francis/' + }) + + .run(function($ionicPlatform) { + $ionicPlatform.ready(function() { + // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard + // for form inputs) + if(window.cordova && window.cordova.plugins.Keyboard) { + cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true); + } + if(window.StatusBar) { + // org.apache.cordova.statusbar required + StatusBar.styleDefault(); + } + }); + }) + + .config(function($stateProvider, $urlRouterProvider) { + $stateProvider + + .state('app', { + url: "/app", + abstract: true, + templateUrl: "menu.html", + controller: 'AppCtrl' + }) + + .state('app.login', { + url: "/login", + views: { + 'menuContent': { + templateUrl: "login.html", + controller: 'LoginCtrl' + } + } + }); + + // if none of the above states are matched, use this as the fallback + $urlRouterProvider.otherwise('/app/login'); + }) + + .controller('AppCtrl', function($scope) { + $scope.ApplicationBaseURL = ApplicationBaseURL; + }) + + .controller('LoginCtrl', ['$scope', 'Authentication', 'sgDialog', function($scope, Authentication, Dialog) { + $scope.creds = { 'username': null, 'password': null }; + $scope.login = function(creds) { + Authentication.login(creds) + .then(function(url) { + window.location.href = url; + }, function(msg) { + Dialog.alert(l('Warning'), msg.error); + }); + }; + }]); +})(); diff --git a/UI/WebServerResources/scss/mobile.scss b/UI/WebServerResources/scss/mobile.scss new file mode 100644 index 000000000..77557011d --- /dev/null +++ b/UI/WebServerResources/scss/mobile.scss @@ -0,0 +1,35 @@ +@import "ionic/ionic"; + +.list-clear { + .list { + border-top: 1px solid $item-light-border; + ion-item { + border: 0; + &, a { + padding-top: 5px !important; + padding-bottom: 5px !important; + } + address { + margin-bottom: 5px !important; + } + } + } +} + +ion-content { + a { + &.button { + margin-left: 5px; + margin-right: 5px; + } + } +} + +ion-item { + small { + display: block; + color: $positive; + } + .list-clear & { + } +} \ No newline at end of file