diff options
36 files changed, 558 insertions, 218 deletions
diff --git a/css/addnew.css b/css/addnew.css index 24cdd6000..d289ecb4e 100644 --- a/css/addnew.css +++ b/css/addnew.css @@ -31,11 +31,11 @@ } .add-new input[type=text] { - width: 120px; + width: 170px; } .add-new select { - width: 133px; + width: 170px; margin-top: 1px !important; height: 30px; background-color: #eee; @@ -46,7 +46,7 @@ box-sizing: border-box; } -.add-new input, +.add-new input, .add-new select { margin: 0 0 5px 0; display: inline-block; @@ -69,7 +69,7 @@ .add-new .action-button { width: 30px; background-position: center; - background-repeat: no-repeat; + background-repeat: no-repeat; } .add-new .back-button { @@ -80,15 +80,15 @@ .add-new .new-button { border-radius: 0; background-image: url('../img/add.svg'); - border-top-right-radius: 5px; - border-bottom-right-radius: 5px; + border-top-right-radius: 5px; + border-bottom-right-radius: 5px; } .add-new .create-button { border-radius: 0; background-image: url('../img/mark_read.svg'); - border-top-right-radius: 5px; - border-bottom-right-radius: 5px; + border-top-right-radius: 5px; + border-bottom-right-radius: 5px; } .add-new .error { diff --git a/css/app.css b/css/app.css new file mode 100644 index 000000000..bf1e695a1 --- /dev/null +++ b/css/app.css @@ -0,0 +1,13 @@ +.loading-icon { + background-image: url('../img/loading.gif'); + background-position: center; + background-repeat: no-repeat; +} + +#global-loading { + width: 100%; + height: 100%; +} + + + diff --git a/css/items.css b/css/content.css index 04cd0ac63..4c071451b 100644 --- a/css/items.css +++ b/css/content.css @@ -19,6 +19,22 @@ * */ +#first-run { + height: 100%; + width: 100%; + display: table; +} + +#first-run h1 { + color: #888888; + font-size: 1.5em; + font-weight: bold; + text-shadow: 0 1px 0 #FFFFFF; + display: table-cell; + text-align: center; + vertical-align: middle; +} + #app-content:after { content: ''; display: block; @@ -35,11 +51,6 @@ height: 100%; } -#app-content.loading { - background-image: url('../img/loading.gif'); - background-position: center; - background-repeat: no-repeat; -} #app-content.loading > ul { display: none; diff --git a/css/firstrun.css b/css/firstrun.css deleted file mode 100644 index 7467a7b2b..000000000 --- a/css/firstrun.css +++ /dev/null @@ -1,41 +0,0 @@ -/** -* ownCloud - News -* -* @author Alessandro Cosentino -* @author Bernhard Posselt -* @copyright 2013 Alessandro Cosentino cosenal@gmail.com -* @copyright 2013 Bernhard Posselt dev@bernhard-posselt.com -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE -* License as published by the Free Software Foundation; either -* version 3 of the License, or any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU AFFERO GENERAL PUBLIC LICENSE for more details. -* -* You should have received a copy of the GNU Affero General Public -* License along with this library. If not, see <http://www.gnu.org/licenses/>. -* -*/ - -#firstrun { - height: 100%; - margin-left: 300px; - position: relative; -} - -#firstrun .message { - color: #888888; - font-size: 1.5em; - font-weight: bold; - text-shadow: 0 1px 0 #FFFFFF; - position: absolute; - top: 50%; - text-align: center; - width: 100%; - margin-top: -0.75em; -} - diff --git a/css/feeds.css b/css/navigation.css index 9b17cd973..79f27d094 100644 --- a/css/feeds.css +++ b/css/navigation.css @@ -19,16 +19,16 @@ * */ -#undo-container { - position: fixed; - top: 0px; - width: 100%; - text-align: center; - z-index: 101; +#undo-container { + position: fixed; + top: 0px; + width: 100%; + text-align: center; + z-index: 101; line-height: 1.2; } -#undo { +#undo { z-index:101; background-color:#fc4; border:0; @@ -144,7 +144,7 @@ } .feed { - text-transform: none; + text-transform: none; } .unread-counter { @@ -182,11 +182,6 @@ button.action:hover { padding-left: 0; } -#app-navigation .rename-feed > input { - width: 155px; - height: 15px; -} - #app-navigation .folder-input { text-transform: uppercase; } @@ -205,9 +200,13 @@ button.action:hover { .rename-feed input { margin: 1px 0 0px 5px; + border-right: 1px solid #ddd; + border-radius: 2px; border-top-right-radius: 0; border-bottom-right-radius: 0; border-right: 0; + width: 208px; + height: 32px; } .rename-feed button { @@ -222,7 +221,7 @@ button.action:hover { .rename-feed .action-button { background-position: center; - background-repeat: no-repeat; + background-repeat: no-repeat; } .rename-feed .back-button { @@ -240,15 +239,21 @@ button.action:hover { } #app-navigation .ui-draggable-dragging { - width: 249px; + width: 100%; } #app-navigation .multiselect { height:20px; } +#app-navigation .progress-icon, +#app-navigation .problem-icon { + width: 299px; + line-height: 44px; +} + .progress-icon { - background-image: url('../img/loading.gif'); + background-image: url('../img/loading.gif'); } .problem-icon { diff --git a/css/owncloud6.css b/css/owncloud6.css index 5d3445cd9..1dbab96c5 100644 --- a/css/owncloud6.css +++ b/css/owncloud6.css @@ -1,13 +1,4 @@ /* Feeds */ -#app-navigation .add-new input, -#app-navigation .add-new select { - width: 170px; -} - -#app-navigation .ui-draggable-dragging { - width: 299px; -} - #app-navigation .rename-feed > input { width: 208px; height: 32px; @@ -15,7 +6,7 @@ border-radius: 2px; } -#app-navigation .progress-icon, +#app-navigation .progress-icon, #app-navigation .problem-icon { width: 299px; line-height: 44px; diff --git a/js/Gruntfile.js b/js/Gruntfile.js index df0afc2ba..5dd29b9fc 100644 --- a/js/Gruntfile.js +++ b/js/Gruntfile.js @@ -14,7 +14,9 @@ var globals = [ 'angular', // app 'app', + // ownCloud 'OC', + 'oc_requesttoken', // angular 'inject', 'module', @@ -62,9 +64,10 @@ module.exports = function (grunt) { }, dist: { src: [ - 'app/app.js', - 'app/config.js', - 'app/run.js', + 'app/App.js', + 'app/Config.js', + 'app/Run.js', + 'controller/**/*.js', 'filter/**/*.js', 'service/**/*.js', 'directive/**/*.js' @@ -84,8 +87,8 @@ module.exports = function (grunt) { dest: '<%= meta.production %>app.js', options: { wrapper: [ - '(function(angular, $, OC, undefined){\n\n\'use strict\';\n\n', - '\n})(angular, jQuery, OC);' + '(function(angular, $, OC, oc_requesttoken, undefined){\n\n\'use strict\';\n\n', + '\n})(angular, jQuery, OC, oc_requesttoken);' ] } } @@ -96,6 +99,7 @@ module.exports = function (grunt) { 'app/**/*.js', 'filter/**/*.js', 'service/**/*.js', + 'controller/**/*.js', 'directive/**/*.js', 'tests/**/*.js', 'Gruntfile.js', @@ -119,10 +123,10 @@ module.exports = function (grunt) { 'service/**/*.js', '../templates/**/*.php' ], + tasks: ['default'], options: { livereload: true - }, - tasks: ['default'] + } }, phpunit: { files: [ @@ -189,7 +193,9 @@ module.exports = function (grunt) { // make tasks available under simpler commands grunt.registerTask('default', ['jslint', 'concat', 'ngmin', 'wrap']); + grunt.registerTask('dev', ['watch:concat']); grunt.registerTask('test', ['karma:unit']); + grunt.registerTask('phpunit', ['watch:phpunit']); grunt.registerTask('e2e', ['protractor_webdriver', 'connect', 'protractor:chrome']); grunt.registerTask('ci-unit', ['default', 'karma:continuous']); grunt.registerTask('ci-e2e', ['protractor_webdriver', 'connect', 'protractor:phantomjs']); diff --git a/js/README.md b/js/README.md index a1b5f4139..db6dafc2e 100644 --- a/js/README.md +++ b/js/README.md @@ -10,7 +10,7 @@ then run: ## Building Watch mode: - grunt watch + grunt dev Single run mode: @@ -19,7 +19,7 @@ Single run mode: ## Testing Watch mode: - grunt watch:phpunit + grunt phpunit grunt test Single run mode: diff --git a/js/app/app.js b/js/app/App.js index 947a68a2e..947a68a2e 100644 --- a/js/app/app.js +++ b/js/app/App.js diff --git a/js/app/Config.js b/js/app/Config.js new file mode 100644 index 000000000..67a5e7215 --- /dev/null +++ b/js/app/Config.js @@ -0,0 +1,65 @@ +/** + * ownCloud - News + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @copyright Bernhard Posselt 2014 + */ +app.config(function ($routeProvider, $provide, $httpProvider) { + 'use strict'; + + // constants + $provide.constant('BASE_URL', OC.generateUrl('/apps/news')); + + $provide.constant('FEED_TYPE', { + FEED: 0, + FOLDER: 1, + STARRED: 2, + SUBSCRIPTIONS: 3, + SHARED: 4 + }); + + // make sure that the CSRF header is only sent to the ownCloud domain + $provide.factory('CSRFInterceptor', function ($q, BASE_URL) { + return { + request: function (config) { + if (config.url.indexOf(BASE_URL) === 0) { + config.headers.requesttoken = oc_requesttoken; + } + + return config || $q.when(config); + } + }; + }); + $httpProvider.interceptors.push('CSRFInterceptor'); + + // routing + $routeProvider + .when('/items', { + controller: 'ItemsController', + templateUrl: 'content.html', + resolve: {} + }) + .when('/items/starred', { + controller: 'StarredController', + templateUrl: 'content.html', + resolve: {} + }) + .when('/items/feeds/:id', { + controller: 'FeedController', + templateUrl: 'content.html', + resolve: {} + }) + .when('/items/folders/:id', { + controller: 'FolderController', + templateUrl: 'content.html', + resolve: {} + }) + .otherwise({ + redirectTo: '/items' + }); + +}); + diff --git a/js/app/Run.js b/js/app/Run.js new file mode 100644 index 000000000..936a03b9d --- /dev/null +++ b/js/app/Run.js @@ -0,0 +1,78 @@ +/** + * ownCloud - News + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @copyright Bernhard Posselt 2014 + */ +app.run(function ($rootScope, $location, $http, $q, Loading, Item, Feed, Folder, + Settings, Publisher, BASE_URL, FEED_TYPE) { + 'use strict'; + + // show Loading screen + Loading.setLoading('global', true); + + // listen to keys in returned queries to automatically distribute the + // incoming values to models + Publisher.subscribe(Item).toChannel('items'); + Publisher.subscribe(Folder).toChannel('folders'); + Publisher.subscribe(Feed).toChannel('feeds'); + Publisher.subscribe(Settings).toChannel('settings'); + + // load feeds, settings and last read feed + var settingsDeferred, + activeFeedDeferred; + + settingsDeferred = $q.defer(); + $http.get(BASE_URL + '/settings').then(function (data) { + Publisher.publishAll(data); + settingsDeferred.resolve(); + }); + + activeFeedDeferred = $q.defer(); + $http.get(BASE_URL + '/feeds/active').then(function (data) { + var url; + + switch (data.type) { + + case FEED_TYPE.FEED: + url = '/items/feeds/' + data.id; + break; + + case FEED_TYPE.FOLDER: + url = '/items/folders/' + data.id; + break; + + case FEED_TYPE.STARRED: + url = '/items/starred'; + break; + + default: + url = '/items'; + } + + $location.path(url); + activeFeedDeferred.resolve(); + }); + + + $q.all([settingsDeferred.promise, activeFeedDeferred.promise]).then(function () { + Loading.setLoading('global', false); + }); + + + $rootScope.$on('$routeChangeStart', function () { + Loading.setLoading('content', true); + }); + + $rootScope.$on('$routeChangeSuccess', function () { + Loading.setLoading('content', false); + }); + + // in case of wrong id etc show all items + $rootScope.$on('$routeChangeError', function () { + $location.path('/items'); + }); +});
\ No newline at end of file diff --git a/js/app/config.js b/js/app/config.js deleted file mode 100644 index 776f4ee92..000000000 --- a/js/app/config.js +++ /dev/null @@ -1,41 +0,0 @@ -/** - * ownCloud - News - * - * This file is licensed under the Affero General Public License version 3 or - * later. See the COPYING file. - * - * @author Bernhard Posselt <dev@bernhard-posselt.com> - * @copyright Bernhard Posselt 2014 - */ -app.config(function ($routeProvider, $provide) { - 'use strict'; - - $provide.constant('baseUrl', OC.generateUrl('')); - - $routeProvider - .when('/items', { - controller: 'AllItemsController', - templateUrl: 'content.html', - resolve: {} - }) - .when('/items/starred', { - controller: 'StarredItemsController', - templateUrl: 'content.html', - resolve: {} - }) - .when('/items/feeds/:id', { - controller: 'FeedItemsController', - templateUrl: 'content.html', - resolve: {} - }) - .when('/items/folders/:id', { - controller: 'FolderItemsController', - templateUrl: 'content.html', - resolve: {} - }) - .otherwise({ - redirectTo: '/items' - }); - -}); - diff --git a/js/app/run.js b/js/app/run.js deleted file mode 100644 index f91d908f2..000000000 --- a/js/app/run.js +++ /dev/null @@ -1,36 +0,0 @@ -/** - * ownCloud - News - * - * This file is licensed under the Affero General Public License version 3 or - * later. See the COPYING file. - * - * @author Bernhard Posselt <dev@bernhard-posselt.com> - * @copyright Bernhard Posselt 2014 - */ -app.run(function ($rootScope, $location, Loading, Setup, Item, Feed, Folder, - Publisher, Settings) { - 'use strict'; - - // listen to keys in returned queries to automatically distribute the - // incoming values to models - Publisher.subscribe(Item).toChannel('items'); - Publisher.subscribe(Folder).toChannel('folders'); - Publisher.subscribe(Feed).toChannel('feeds'); - Publisher.subscribe(Settings).toChannel('settings'); - - // load feeds, settings and last read feed - Setup.load(); - - $rootScope.$on('$routeChangeStart', function () { - Loading.setLoading('content', true); - }); - - $rootScope.$on('$routeChangeSuccess', function () { - Loading.setLoading('content', false); - }); - - // in case of wrong id etc show all items - $rootScope.$on('$routeChangeError', function () { - $location.path('/items'); - }); -});
\ No newline at end of file diff --git a/js/build/app.js b/js/build/app.js index 3a72dc277..a20648bd5 100644 --- a/js/build/app.js +++ b/js/build/app.js @@ -1,4 +1,4 @@ -(function(angular, $, OC, undefined){ +(function(angular, $, OC, oc_requesttoken, undefined){ 'use strict'; @@ -11,23 +11,45 @@ var app = angular.module('News', [ app.config([ '$routeProvider', '$provide', - function ($routeProvider, $provide) { + '$httpProvider', + function ($routeProvider, $provide, $httpProvider) { 'use strict'; - $provide.constant('baseUrl', OC.generateUrl('')); + // constants + $provide.constant('BASE_URL', OC.generateUrl('/apps/news')); + $provide.constant('FEED_TYPE', { + FEED: 0, + FOLDER: 1, + STARRED: 2, + SUBSCRIPTIONS: 3, + SHARED: 4 + }); + // make sure that the CSRF header is only sent to the ownCloud domain + $provide.factory('CSRFInterceptor', function ($q, BASE_URL) { + return { + request: function (config) { + if (config.url.indexOf(BASE_URL) === 0) { + config.headers.requesttoken = oc_requesttoken; + } + return config || $q.when(config); + } + }; + }); + $httpProvider.interceptors.push('CSRFInterceptor'); + // routing $routeProvider.when('/items', { - controller: 'AllItemsController', + controller: 'ItemsController', templateUrl: 'content.html', resolve: {} }).when('/items/starred', { - controller: 'StarredItemsController', + controller: 'StarredController', templateUrl: 'content.html', resolve: {} }).when('/items/feeds/:id', { - controller: 'FeedItemsController', + controller: 'FeedController', templateUrl: 'content.html', resolve: {} }).when('/items/folders/:id', { - controller: 'FolderItemsController', + controller: 'FolderController', templateUrl: 'content.html', resolve: {} }).otherwise({ redirectTo: '/items' }); @@ -36,15 +58,20 @@ app.config([ app.run([ '$rootScope', '$location', + '$http', + '$q', 'Loading', - 'Setup', 'Item', 'Feed', 'Folder', - 'Publisher', 'Settings', - function ($rootScope, $location, Loading, Setup, Item, Feed, Folder, Publisher, Settings) { + 'Publisher', + 'BASE_URL', + 'FEED_TYPE', + function ($rootScope, $location, $http, $q, Loading, Item, Feed, Folder, Settings, Publisher, BASE_URL, FEED_TYPE) { 'use strict'; + // show Loading screen + Loading.setLoading('global', true); // listen to keys in returned queries to automatically distribute the // incoming values to models Publisher.subscribe(Item).toChannel('items'); @@ -52,7 +79,37 @@ app.run([ Publisher.subscribe(Feed).toChannel('feeds'); Publisher.subscribe(Settings).toChannel('settings'); // load feeds, settings and last read feed - Setup.load(); + var settingsDeferred, activeFeedDeferred; + settingsDeferred = $q.defer(); + $http.get(BASE_URL + '/settings').then(function (data) { + Publisher.publishAll(data); + settingsDeferred.resolve(); + }); + activeFeedDeferred = $q.defer(); + $http.get(BASE_URL + '/feeds/active').then(function (data) { + var url; + switch (data.type) { + case FEED_TYPE.FEED: + url = '/items/feeds/' + data.id; + break; + case FEED_TYPE.FOLDER: + url = '/items/folders/' + data.id; + break; + case FEED_TYPE.STARRED: + url = '/items/starred'; + break; + default: + url = '/items'; + } + $location.path(url); + activeFeedDeferred.resolve(); + }); + $q.all([ + settingsDeferred.promise, + activeFeedDeferred.promise + ]).then(function () { + Loading.setLoading('global', false); + }); $rootScope.$on('$routeChangeStart', function () { Loading.setLoading('content', true); }); @@ -65,6 +122,30 @@ app.run([ }); } ]); +app.controller('AppController', [ + 'Loading', + 'Feed', + 'Folder', + function (Loading, Feed, Folder) { + 'use strict'; + this.loading = Loading; + this.isFirstRun = function () { + return Feed.size() === 0 && Folder.size() === 0; + }; + } +]); +app.controller('ItemsController', function () { + 'use strict'; + console.log('here'); +}); +app.controller('NavigationController', function () { + 'use strict'; + console.log('here'); +}); +app.controller('SettingsController', function () { + 'use strict'; + console.log('here'); +}); app.factory('Feed', [ 'Model', function (Model) { @@ -102,7 +183,8 @@ app.service('Loading', function () { 'use strict'; this.loading = { global: false, - content: false + content: false, + autopaging: false }; this.setLoading = function (area, isLoading) { this.loading[area] = isLoading; @@ -189,7 +271,7 @@ app.service('Publisher', function () { this.publishAll = function (data) { var channel, counter; for (channel in data) { - if (data.hasOwnProperty(channel)) { + if (data.hasOwnProperty(channel) && this.channels[channel] !== undefined) { for (counter = 0; counter < this.channels[channel].length; counter += 1) { this.channels[channel][counter].receive(data[channel]); } @@ -197,11 +279,23 @@ app.service('Publisher', function () { } }; }); -app.service('Setup', function () { +app.service('Settings', function () { 'use strict'; - this.load = function () { - console.log('init'); + this.settings = {}; + this.receive = function (data) { + var key; + for (key in data) { + if (data.hasOwnProperty(key)) { + this.settings[key] = data[key]; + } + } + }; + this.get = function (key) { + return this.settings[key]; + }; + this.set = function (key, value) { + this.settings[key] = value; }; }); -})(angular, jQuery, OC);
\ No newline at end of file +})(angular, jQuery, OC, oc_requesttoken);
\ No newline at end of file diff --git a/js/controller/AppController.js b/js/controller/AppController.js new file mode 100644 index 000000000..ee8115c84 --- /dev/null +++ b/js/controller/AppController.js @@ -0,0 +1,19 @@ +/** + * ownCloud - News + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @copyright Bernhard Posselt 2014 + */ +app.controller('AppController', function (Loading, Feed, Folder) { + 'use strict'; + + this.loading = Loading; + + this.isFirstRun = function () { + return Feed.size() === 0 && Folder.size() === 0; + }; + +});
\ No newline at end of file diff --git a/js/service/setup.js b/js/controller/ItemsController.js index dcb289643..61ca72fdc 100644 --- a/js/service/setup.js +++ b/js/controller/ItemsController.js @@ -7,11 +7,8 @@ * @author Bernhard Posselt <dev@bernhard-posselt.com> * @copyright Bernhard Posselt 2014 */ -app.service('Setup', function () { +app.controller('ItemsController', function () { 'use strict'; - this.load = function () { - console.log('init'); - }; - + console.log('here'); });
\ No newline at end of file diff --git a/js/controller/NavigationController.js b/js/controller/NavigationController.js new file mode 100644 index 000000000..700e6bd02 --- /dev/null +++ b/js/controller/NavigationController.js @@ -0,0 +1,14 @@ +/** + * ownCloud - News + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @copyright Bernhard Posselt 2014 + */ +app.controller('NavigationController', function () { + 'use strict'; + + console.log('here'); +});
\ No newline at end of file diff --git a/js/controller/SettingsController.js b/js/controller/SettingsController.js new file mode 100644 index 000000000..321b6dff9 --- /dev/null +++ b/js/controller/SettingsController.js @@ -0,0 +1,14 @@ +/** + * ownCloud - News + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @copyright Bernhard Posselt 2014 + */ +app.controller('SettingsController', function () { + 'use strict'; + + console.log('here'); +});
\ No newline at end of file diff --git a/js/protractor.chrome.conf.js b/js/protractor.chrome.conf.js index 5d5bdc320..09b597c08 100644 --- a/js/protractor.chrome.conf.js +++ b/js/protractor.chrome.conf.js @@ -28,6 +28,14 @@ exports.config = { return regex.test(url); }); }); + + browser.get(baseUrl + '/owncloud/index.php/apps/news/'); + browser.driver.wait(function () { + return browser.driver.getCurrentUrl().then(function (url) { + var regex = /apps\/news/; + return regex.test(url); + }); + }); }, baseUrl: baseUrl };
\ No newline at end of file diff --git a/js/protractor.phantomjs.conf.js b/js/protractor.phantomjs.conf.js index 427465808..73ed555cf 100644 --- a/js/protractor.phantomjs.conf.js +++ b/js/protractor.phantomjs.conf.js @@ -28,6 +28,14 @@ exports.config = { return regex.test(url); }); }); + + browser.get(baseUrl + '/owncloud/index.php/apps/news/'); + browser.driver.wait(function () { + return browser.driver.getCurrentUrl().then(function (url) { + var regex = /apps\/news/; + return regex.test(url); + }); + }); }, capabilities: { browserName: 'phantomjs', diff --git a/js/service/feed.js b/js/service/Feed.js index 9223ca6e7..9223ca6e7 100644 --- a/js/service/feed.js +++ b/js/service/Feed.js diff --git a/js/service/folder.js b/js/service/Folder.js index 101b8ec66..101b8ec66 100644 --- a/js/service/folder.js +++ b/js/service/Folder.js diff --git a/js/service/item.js b/js/service/Item.js index 0dd9b8677..0dd9b8677 100644 --- a/js/service/item.js +++ b/js/service/Item.js diff --git a/js/service/loading.js b/js/service/Loading.js index e6fcb73d1..eb42655a5 100644 --- a/js/service/loading.js +++ b/js/service/Loading.js @@ -12,7 +12,8 @@ app.service('Loading', function () { this.loading = { global: false, - content: false + content: false, + autopaging: false }; this.setLoading = function (area, isLoading) { diff --git a/js/service/model.js b/js/service/Model.js index dddede788..dddede788 100644 --- a/js/service/model.js +++ b/js/service/Model.js diff --git a/js/service/publisher.js b/js/service/Publisher.js index db8a1d5db..da9b0a470 100644 --- a/js/service/publisher.js +++ b/js/service/Publisher.js @@ -27,7 +27,7 @@ app.service('Publisher', function () { counter; for (channel in data) { - if (data.hasOwnProperty(channel)) { + if (data.hasOwnProperty(channel) && this.channels[channel] !== undefined) { for (counter = 0; counter < this.channels[channel].length; counter += 1) { this.channels[channel][counter].receive(data[channel]); } diff --git a/js/service/Settings.js b/js/service/Settings.js new file mode 100644 index 000000000..09a89f6ed --- /dev/null +++ b/js/service/Settings.js @@ -0,0 +1,32 @@ +/** + * ownCloud - News + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @copyright Bernhard Posselt 2014 + */ +app.service('Settings', function () { + 'use strict'; + + this.settings = {}; + + this.receive = function (data) { + var key; + for (key in data) { + if (data.hasOwnProperty(key)) { + this.settings[key] = data[key]; + } + } + }; + + this.get = function (key) { + return this.settings[key]; + }; + + this.set = function (key, value) { + this.settings[key] = value; + }; + +});
\ No newline at end of file diff --git a/js/tests/e2e/main.js b/js/tests/e2e/main.js index 3beb4c8af..328556326 100644 --- a/js/tests/e2e/main.js +++ b/js/tests/e2e/main.js @@ -11,7 +11,8 @@ describe('news page', function () { 'use strict'; beforeEach(function () { - browser.get('http://localhost/owncloud/index.php/apps/news/'); + browser.ignoreSynchronization = true; + browser.waitForAngular(); }); it('should go to the news page', function () { @@ -20,4 +21,16 @@ describe('news page', function () { }); }); + + it('should show the first run page', function () { + var firstRun, + greeting; + + firstRun = browser.findElement(By.id('first-run')); + greeting = firstRun.findElement(By.tagName('h1')); + + expect(firstRun.isDisplayed()).toBe(true); + expect(greeting.getText()).toBe('Welcome to the ownCloud News app!'); + }); + });
\ No newline at end of file diff --git a/js/tests/unit/controller/AppControllerSpec.js b/js/tests/unit/controller/AppControllerSpec.js new file mode 100644 index 000000000..b7dad7492 --- /dev/null +++ b/js/tests/unit/controller/AppControllerSpec.js @@ -0,0 +1,45 @@ +/** + * ownCloud - News + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @copyright Bernhard Posselt 2014 + */ +describe('AppController', function () { + 'use strict'; + + var controller; + + beforeEach(module('News')); + + beforeEach(inject(function ($controller) { + controller = $controller('AppController'); + })); + + + it('should expose Loading', inject(function (Loading) { + expect(controller.loading).toBe(Loading); + })); + + + it('should expose set firstrun if no feeds and folders', inject(function () { + expect(controller.isFirstRun()).toBe(true); + })); + + + it('should expose set firstrun if feeds', inject(function (Feed) { + Feed.add({url: 'test'}); + + expect(controller.isFirstRun()).toBe(false); + })); + + + it('should expose set firstrun if folders', inject(function (Folder) { + Folder.add({name: 'test'}); + + expect(controller.isFirstRun()).toBe(false); + })); + +});
\ No newline at end of file diff --git a/js/tests/unit/service/LoadingSpec.js b/js/tests/unit/service/LoadingSpec.js index f8146b87f..2033f33cc 100644 --- a/js/tests/unit/service/LoadingSpec.js +++ b/js/tests/unit/service/LoadingSpec.js @@ -15,6 +15,7 @@ describe('Loading', function () { it('should be not load by default', inject(function (Loading) { expect(Loading.isLoading('global')).toBe(false); expect(Loading.isLoading('content')).toBe(false); + expect(Loading.isLoading('autopaging')).toBe(false); })); it('should set loading', inject(function (Loading) { diff --git a/js/tests/unit/service/PublisherSpec.js b/js/tests/unit/service/PublisherSpec.js index f7fa67796..2b9206c93 100644 --- a/js/tests/unit/service/PublisherSpec.js +++ b/js/tests/unit/service/PublisherSpec.js @@ -24,7 +24,13 @@ describe('Publisher', function () { }); expect(obj.receive).toHaveBeenCalledWith('tom'); + })); + + it('should not broadcast to not subscribed channels', inject(function (Publisher) { + Publisher.publishAll({ + test: 'tom' + }); })); });
\ No newline at end of file diff --git a/js/tests/unit/service/SettingsSpec.js b/js/tests/unit/service/SettingsSpec.js new file mode 100644 index 000000000..65dc4bf2f --- /dev/null +++ b/js/tests/unit/service/SettingsSpec.js @@ -0,0 +1,30 @@ +/** + * ownCloud - News + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @copyright Bernhard Posselt 2014 + */ +describe('Settings', function () { + 'use strict'; + + beforeEach(module('News')); + + it('should receive default settings', inject(function (Settings) { + Settings.receive({ + 'showAll': true + }); + + expect(Settings.get('showAll')).toBe(true); + })); + + + it('should set values', inject(function (Settings) { + Settings.set('showAll', true); + + expect(Settings.get('showAll')).toBe(true); + })); + +});
\ No newline at end of file diff --git a/templates/main.php b/templates/main.php index 8755a2542..465dadaba 100644 --- a/templates/main.php +++ b/templates/main.php @@ -9,39 +9,49 @@ \OCP\Util::addScript('news', 'build/app'); \OCP\Util::addStyle('news', 'bootstrap/tooltip'); +\OCP\Util::addStyle('news', 'navigation'); \OCP\Util::addStyle('news', 'addnew'); -\OCP\Util::addStyle('news', 'feeds'); -\OCP\Util::addStyle('news', 'items'); +\OCP\Util::addStyle('news', 'app'); +\OCP\Util::addStyle('news', 'content'); \OCP\Util::addStyle('news', 'settings'); \OCP\Util::addStyle('news', 'showall'); -\OCP\Util::addStyle('news', 'firstrun'); -\OCP\Util::addStyle('news', 'owncloud6'); ?> -<div id="app" ng-app="News" ng-cloak ng-controller="AppController"> + +<div id="app" ng-app="News" ng-cloak ng-controller="AppController as App"> + + <div id="global-loading" class="loading-icon" ng-show="App.loading.isLoading('global')"></div> + <!-- <div id="undo-container"> <div undo-notification id="undo"> <a href="#"><?php p($l->t('Undo deletion of %s', '{{ getCaption() }}')); ?></a> </div> </div> - <div id="app-navigation" ng-controller="FeedController"> - <news-translate key="appName"><?php p($l->t('News')); ?></news-translate> + <news-translate key="appName"><?php p($l->t('News')); ?></news-translate> + --> + + <div id="app-navigation" ng-controller="NavigationController" ng-hide="App.loading.isLoading('global')"> <ul class="with-icon" data-id="0" droppable> - <?php print_unescaped($this->inc('part.addnew')) ?> - <?php print_unescaped($this->inc('part.feed.unread')) ?> - <?php print_unescaped($this->inc('part.feed.starred')) ?> - <?php print_unescaped($this->inc('part.listfeed', ['folderId' => '0'])) ?> - <?php print_unescaped($this->inc('part.listfolder')) ?> - <?php print_unescaped($this->inc('part.showall')); ?> + <?php //print_unescaped($this->inc('part.addnew')) ?> + <?php //print_unescaped($this->inc('part.feed.unread')) ?> + <?php //print_unescaped($this->inc('part.feed.starred')) ?> + <?php //print_unescaped($this->inc('part.listfeed', ['folderId' => '0'])) ?> + <?php //print_unescaped($this->inc('part.listfolder')) ?> + <?php //print_unescaped($this->inc('part.showall')); ?> </ul> <div id="app-settings" ng-controller="SettingsController"> - <?php print_unescaped($this->inc('part.settings')) ?> + <!--<?php print_unescaped($this->inc('part.settings')) ?>--> </div> </div> + <script type="text/ng-template" id="content.html"><?php print_unescaped($this->inc('part.content')) ?></script> + + <div id="app-content" ng-hide="App.loading.isLoading('global')" ng-view></div> + + <!-- <div id="app-content" ng-class="{ loading: isLoading(), autopaging: isAutoPaging() @@ -55,8 +65,7 @@ news-auto-focus> <?php print_unescaped($this->inc("part.items")); ?> </div> - <div id="firstrun" ng-show="initialized && feedBusinessLayer.noFeeds()"> - <?php print_unescaped($this->inc("part.firstrun")); ?> - </div> + + --> </div> diff --git a/templates/part.content.php b/templates/part.content.php new file mode 100644 index 000000000..d3a59b08c --- /dev/null +++ b/templates/part.content.php @@ -0,0 +1,3 @@ +<div id="first-run" ng-if="App.isFirstRun()"> + <h1><?php p($l->t('Welcome to the ownCloud News app!')) ?></h1> +</div>
\ No newline at end of file diff --git a/templates/part.firstrun.php b/templates/part.firstrun.php deleted file mode 100644 index 6edf8617e..000000000 --- a/templates/part.firstrun.php +++ /dev/null @@ -1,3 +0,0 @@ -<h1 class="message"> - <?php p($l->t('Welcome to the ownCloud News app!')) ?> -</h1>
\ No newline at end of file diff --git a/templates/part.items.php b/templates/part.items.php index 8b062b787..200d5fffd 100644 --- a/templates/part.items.php +++ b/templates/part.items.php @@ -1,5 +1,3 @@ -<div class="pull-refresh" ng-class="{refresh: refresh}"></div> - <ul> <li class="feed_item" @@ -14,9 +12,9 @@ class="star" > </button> - <a class="external" - target="_blank" - ng-href="{{ item.url }}" + <a class="external" + target="_blank" + ng-href="{{ item.url }}" title="<?php p($l->t('read on website')) ?>"> </a> <span class="timeago" title="{{item.pubDate*1000|date:'dd-MM-yyyy'}}"> @@ -26,7 +24,7 @@ <a ng-click="item.active = !item.active" href="#">{{ item.title }}</a> </h1> </div> - + <h2 class="item_date"> <span class="timeago" title="{{item.pubDate*1000|date:'dd-MM-yyyy'}}"> {{ getRelativeDate(item.pubDate) }} @@ -36,7 +34,7 @@ <div class="item_utils"> <ul class="primary_item_utils"> <li> - <button + <button title="<?php p($l->t('star')) ?>" ng-class="{ important: item.isStarred() }" ng-click="itemBusinessLayer.toggleStarred(item.id)" |