First Commit

This commit is contained in:
Lorenzo Iovino 2016-01-29 13:14:27 +01:00
commit feb864dc47
170 changed files with 4671 additions and 0 deletions

283
hackatonApp/www/js/app.js Normal file
View file

@ -0,0 +1,283 @@
// Ionic Starter App
angular.module('underscore', [])
.factory('_', function() {
return window._; // assumes underscore has already been loaded on the page
});
// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'
angular.module('your_app_name', [
'ionic',
'angularMoment',
'your_app_name.controllers',
'your_app_name.directives',
'your_app_name.filters',
'your_app_name.services',
'your_app_name.factories',
'your_app_name.config',
'your_app_name.views',
'underscore',
'ngMap',
'ngResource',
'ngCordova',
'slugifier',
'ionic.contrib.ui.tinderCards',
'youtube-embed'
])
.run(function($ionicPlatform, PushNotificationsService, $rootScope, $ionicConfig, $timeout) {
$ionicPlatform.on("deviceready", 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) {
StatusBar.styleDefault();
}
PushNotificationsService.register();
});
// This fixes transitions for transparent background views
$rootScope.$on("$stateChangeStart", function(event, toState, toParams, fromState, fromParams){
if(toState.name.indexOf('auth.walkthrough') > -1)
{
// set transitions to android to avoid weird visual effect in the walkthrough transitions
$timeout(function(){
$ionicConfig.views.transition('android');
$ionicConfig.views.swipeBackEnabled(false);
console.log("setting transition to android and disabling swipe back");
}, 0);
}
});
$rootScope.$on("$stateChangeSuccess", function(event, toState, toParams, fromState, fromParams){
if(toState.name.indexOf('app.feeds-categories') > -1)
{
// Restore platform default transition. We are just hardcoding android transitions to auth views.
$ionicConfig.views.transition('platform');
// If it's ios, then enable swipe back again
if(ionic.Platform.isIOS())
{
$ionicConfig.views.swipeBackEnabled(true);
}
console.log("enabling swipe back and restoring transition to platform default", $ionicConfig.views.transition());
}
});
$ionicPlatform.on("resume", function(){
PushNotificationsService.register();
});
})
.config(function($stateProvider, $urlRouterProvider, $ionicConfigProvider) {
$stateProvider
//INTRO
.state('auth', {
url: "/auth",
templateUrl: "views/auth/auth.html",
abstract: true,
controller: 'AuthCtrl'
})
.state('auth.walkthrough', {
url: '/walkthrough',
templateUrl: "views/auth/walkthrough.html"
})
.state('auth.login', {
url: '/login',
templateUrl: "views/auth/login.html",
controller: 'LoginCtrl'
})
.state('auth.signup', {
url: '/signup',
templateUrl: "views/auth/signup.html",
controller: 'SignupCtrl'
})
.state('auth.forgot-password', {
url: "/forgot-password",
templateUrl: "views/auth/forgot-password.html",
controller: 'ForgotPasswordCtrl'
})
.state('app', {
url: "/app",
abstract: true,
templateUrl: "views/app/side-menu.html",
controller: 'AppCtrl'
})
//MISCELLANEOUS
.state('app.miscellaneous', {
url: "/miscellaneous",
views: {
'menuContent': {
templateUrl: "views/app/miscellaneous/miscellaneous.html"
}
}
})
.state('app.maps', {
url: "/miscellaneous/maps",
views: {
'menuContent': {
templateUrl: "views/app/miscellaneous/maps.html",
controller: 'MapsCtrl'
}
}
})
.state('app.image-picker', {
url: "/miscellaneous/image-picker",
views: {
'menuContent': {
templateUrl: "views/app/miscellaneous/image-picker.html",
controller: 'ImagePickerCtrl'
}
}
})
//LAYOUTS
.state('app.layouts', {
url: "/layouts",
views: {
'menuContent': {
templateUrl: "views/app/layouts/layouts.html"
}
}
})
.state('app.tinder-cards', {
url: "/layouts/tinder-cards",
views: {
'menuContent': {
templateUrl: "views/app/layouts/tinder-cards.html",
controller: 'TinderCardsCtrl'
}
}
})
.state('app.slider', {
url: "/layouts/slider",
views: {
'menuContent': {
templateUrl: "views/app/layouts/slider.html"
}
}
})
//FEEDS
.state('app.feeds-categories', {
url: "/feeds-categories",
views: {
'menuContent': {
templateUrl: "views/app/feeds/feeds-categories.html",
controller: 'FeedsCategoriesCtrl'
}
}
})
.state('app.category-feeds', {
url: "/category-feeds/:categoryId",
views: {
'menuContent': {
templateUrl: "views/app/feeds/category-feeds.html",
controller: 'CategoryFeedsCtrl'
}
}
})
.state('app.feed-entries', {
url: "/feed-entries/:categoryId/:sourceId",
views: {
'menuContent': {
templateUrl: "views/app/feeds/feed-entries.html",
controller: 'FeedEntriesCtrl'
}
}
})
//WORDPRESS
.state('app.wordpress', {
url: "/wordpress",
views: {
'menuContent': {
templateUrl: "views/app/wordpress/wordpress.html",
controller: 'WordpressCtrl'
}
}
})
.state('app.post', {
url: "/wordpress/:postId",
views: {
'menuContent': {
templateUrl: "views/app/wordpress/wordpress_post.html",
controller: 'WordpressPostCtrl'
}
},
resolve: {
post_data: function(PostService, $ionicLoading, $stateParams) {
$ionicLoading.show({
template: 'Loading post ...'
});
var postId = $stateParams.postId;
return PostService.getPost(postId);
}
}
})
//OTHERS
.state('app.settings', {
url: "/settings",
views: {
'menuContent': {
templateUrl: "views/app/settings.html",
controller: 'SettingsCtrl'
}
}
})
.state('app.forms', {
url: "/forms",
views: {
'menuContent': {
templateUrl: "views/app/forms.html"
}
}
})
.state('app.profile', {
url: "/profile",
views: {
'menuContent': {
templateUrl: "views/app/profile.html"
}
}
})
.state('app.bookmarks', {
url: "/bookmarks",
views: {
'menuContent': {
templateUrl: "views/app/bookmarks.html",
controller: 'BookMarksCtrl'
}
}
})
;
// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/auth/walkthrough');
});

View file

@ -0,0 +1,5 @@
angular.module('your_app_name.config', [])
.constant('WORDPRESS_API_URL', 'http://wordpress.startapplabs.com/blog/api/')
.constant('GCM_SENDER_ID', '574597432927')
;

View file

@ -0,0 +1,465 @@
angular.module('your_app_name.controllers', [])
.controller('AuthCtrl', function($scope, $ionicConfig) {
})
// APP
.controller('AppCtrl', function($scope, $ionicConfig) {
})
//LOGIN
.controller('LoginCtrl', function($scope, $state, $templateCache, $q, $rootScope) {
$scope.doLogIn = function(){
$state.go('app.feeds-categories');
};
$scope.user = {};
$scope.user.email = "john@doe.com";
$scope.user.pin = "12345";
// We need this for the form validation
$scope.selected_tab = "";
$scope.$on('my-tabs-changed', function (event, data) {
$scope.selected_tab = data.title;
});
})
.controller('SignupCtrl', function($scope, $state) {
$scope.user = {};
$scope.user.email = "john@doe.com";
$scope.doSignUp = function(){
$state.go('app.feeds-categories');
};
})
.controller('ForgotPasswordCtrl', function($scope, $state) {
$scope.recoverPassword = function(){
$state.go('app.feeds-categories');
};
$scope.user = {};
})
.controller('RateApp', function($scope) {
$scope.rateApp = function(){
if(ionic.Platform.isIOS()){
//you need to set your own ios app id
AppRate.preferences.storeAppURL.ios = '1234555553>';
AppRate.promptForRating(true);
}else if(ionic.Platform.isAndroid()){
//you need to set your own android app id
AppRate.preferences.storeAppURL.android = 'market://details?id=ionFB';
AppRate.promptForRating(true);
}
};
})
.controller('SendMailCtrl', function($scope) {
$scope.sendMail = function(){
cordova.plugins.email.isAvailable(
function (isAvailable) {
// alert('Service is not available') unless isAvailable;
cordova.plugins.email.open({
to: 'envato@startapplabs.com',
cc: 'hello@startapplabs.com',
// bcc: ['john@doe.com', 'jane@doe.com'],
subject: 'Greetings',
body: 'How are you? Nice greetings from IonFullApp'
});
}
);
};
})
.controller('MapsCtrl', function($scope, $ionicLoading) {
$scope.info_position = {
lat: 43.07493,
lng: -89.381388
};
$scope.center_position = {
lat: 43.07493,
lng: -89.381388
};
$scope.my_location = "";
$scope.$on('mapInitialized', function(event, map) {
$scope.map = map;
});
$scope.centerOnMe= function(){
$scope.positions = [];
$ionicLoading.show({
template: 'Loading...'
});
// with this function you can get the users current position
// we use this plugin: https://github.com/apache/cordova-plugin-geolocation/
navigator.geolocation.getCurrentPosition(function(position) {
var pos = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
$scope.current_position = {lat: pos.G,lng: pos.K};
$scope.my_location = pos.G+", "+pos.K;
$scope.map.setCenter(pos);
$ionicLoading.hide();
});
};
})
.controller('AdsCtrl', function($scope, $ionicActionSheet, AdMob, iAd) {
$scope.manageAdMob = function() {
// Show the action sheet
var hideSheet = $ionicActionSheet.show({
//Here you can add some more buttons
buttons: [
{ text: 'Show Banner' },
{ text: 'Show Interstitial' }
],
destructiveText: 'Remove Ads',
titleText: 'Choose the ad to show',
cancelText: 'Cancel',
cancel: function() {
// add cancel code..
},
destructiveButtonClicked: function() {
console.log("removing ads");
AdMob.removeAds();
return true;
},
buttonClicked: function(index, button) {
if(button.text == 'Show Banner')
{
console.log("show banner");
AdMob.showBanner();
}
if(button.text == 'Show Interstitial')
{
console.log("show interstitial");
AdMob.showInterstitial();
}
return true;
}
});
};
$scope.manageiAd = function() {
// Show the action sheet
var hideSheet = $ionicActionSheet.show({
//Here you can add some more buttons
buttons: [
{ text: 'Show iAd Banner' },
{ text: 'Show iAd Interstitial' }
],
destructiveText: 'Remove Ads',
titleText: 'Choose the ad to show - Interstitial only works in iPad',
cancelText: 'Cancel',
cancel: function() {
// add cancel code..
},
destructiveButtonClicked: function() {
console.log("removing ads");
iAd.removeAds();
return true;
},
buttonClicked: function(index, button) {
if(button.text == 'Show iAd Banner')
{
console.log("show iAd banner");
iAd.showBanner();
}
if(button.text == 'Show iAd Interstitial')
{
console.log("show iAd interstitial");
iAd.showInterstitial();
}
return true;
}
});
};
})
// FEED
//brings all feed categories
.controller('FeedsCategoriesCtrl', function($scope, $http) {
$scope.feeds_categories = [];
$http.get('feeds-categories.json').success(function(response) {
$scope.feeds_categories = response;
});
})
//bring specific category providers
.controller('CategoryFeedsCtrl', function($scope, $http, $stateParams) {
$scope.category_sources = [];
$scope.categoryId = $stateParams.categoryId;
$http.get('feeds-categories.json').success(function(response) {
var category = _.find(response, {id: $scope.categoryId});
$scope.categoryTitle = category.title;
$scope.category_sources = category.feed_sources;
});
})
//this method brings posts for a source provider
.controller('FeedEntriesCtrl', function($scope, $stateParams, $http, FeedList, $q, $ionicLoading, BookMarkService) {
$scope.feed = [];
var categoryId = $stateParams.categoryId,
sourceId = $stateParams.sourceId;
$scope.doRefresh = function() {
$http.get('feeds-categories.json').success(function(response) {
$ionicLoading.show({
template: 'Loading entries...'
});
var category = _.find(response, {id: categoryId }),
source = _.find(category.feed_sources, {id: sourceId });
$scope.sourceTitle = source.title;
FeedList.get(source.url)
.then(function (result) {
$scope.feed = result.feed;
$ionicLoading.hide();
$scope.$broadcast('scroll.refreshComplete');
}, function (reason) {
$ionicLoading.hide();
$scope.$broadcast('scroll.refreshComplete');
});
});
};
$scope.doRefresh();
$scope.bookmarkPost = function(post){
$ionicLoading.show({ template: 'Post Saved!', noBackdrop: true, duration: 1000 });
BookMarkService.bookmarkFeedPost(post);
};
})
// SETTINGS
.controller('SettingsCtrl', function($scope, $ionicActionSheet, $state) {
$scope.airplaneMode = true;
$scope.wifi = false;
$scope.bluetooth = true;
$scope.personalHotspot = true;
$scope.checkOpt1 = true;
$scope.checkOpt2 = true;
$scope.checkOpt3 = false;
$scope.radioChoice = 'B';
// Triggered on a the logOut button click
$scope.showLogOutMenu = function() {
// Show the action sheet
var hideSheet = $ionicActionSheet.show({
//Here you can add some more buttons
// buttons: [
// { text: '<b>Share</b> This' },
// { text: 'Move' }
// ],
destructiveText: 'Logout',
titleText: 'Are you sure you want to logout? This app is awsome so I recommend you to stay.',
cancelText: 'Cancel',
cancel: function() {
// add cancel code..
},
buttonClicked: function(index) {
//Called when one of the non-destructive buttons is clicked,
//with the index of the button that was clicked and the button object.
//Return true to close the action sheet, or false to keep it opened.
return true;
},
destructiveButtonClicked: function(){
//Called when the destructive button is clicked.
//Return true to close the action sheet, or false to keep it opened.
$state.go('auth.walkthrough');
}
});
};
})
// TINDER CARDS
.controller('TinderCardsCtrl', function($scope, $http) {
$scope.cards = [];
$scope.addCard = function(img, name) {
var newCard = {image: img, name: name};
newCard.id = Math.random();
$scope.cards.unshift(angular.extend({}, newCard));
};
$scope.addCards = function(count) {
$http.get('http://api.randomuser.me/?results=' + count).then(function(value) {
angular.forEach(value.data.results, function (v) {
$scope.addCard(v.user.picture.large, v.user.name.first + " " + v.user.name.last);
});
});
};
$scope.addFirstCards = function() {
$scope.addCard("https://dl.dropboxusercontent.com/u/30675090/envato/tinder-cards/left.png","Nope");
$scope.addCard("https://dl.dropboxusercontent.com/u/30675090/envato/tinder-cards/right.png", "Yes");
};
$scope.addFirstCards();
$scope.addCards(5);
$scope.cardDestroyed = function(index) {
$scope.cards.splice(index, 1);
$scope.addCards(1);
};
$scope.transitionOut = function(card) {
console.log('card transition out');
};
$scope.transitionRight = function(card) {
console.log('card removed to the right');
console.log(card);
};
$scope.transitionLeft = function(card) {
console.log('card removed to the left');
console.log(card);
};
})
// BOOKMARKS
.controller('BookMarksCtrl', function($scope, $rootScope, BookMarkService, $state) {
$scope.bookmarks = BookMarkService.getBookmarks();
// When a new post is bookmarked, we should update bookmarks list
$rootScope.$on("new-bookmark", function(event){
$scope.bookmarks = BookMarkService.getBookmarks();
});
$scope.goToFeedPost = function(link){
window.open(link, '_blank', 'location=yes');
};
$scope.goToWordpressPost = function(postId){
$state.go('app.post', {postId: postId});
};
})
// WORDPRESS
.controller('WordpressCtrl', function($scope, $http, $ionicLoading, PostService, BookMarkService) {
$scope.posts = [];
$scope.page = 1;
$scope.totalPages = 1;
$scope.doRefresh = function() {
$ionicLoading.show({
template: 'Loading posts...'
});
//Always bring me the latest posts => page=1
PostService.getRecentPosts(1)
.then(function(data){
$scope.totalPages = data.pages;
$scope.posts = PostService.shortenPosts(data.posts);
$ionicLoading.hide();
$scope.$broadcast('scroll.refreshComplete');
});
};
$scope.loadMoreData = function(){
$scope.page += 1;
PostService.getRecentPosts($scope.page)
.then(function(data){
//We will update this value in every request because new posts can be created
$scope.totalPages = data.pages;
var new_posts = PostService.shortenPosts(data.posts);
$scope.posts = $scope.posts.concat(new_posts);
$scope.$broadcast('scroll.infiniteScrollComplete');
});
};
$scope.moreDataCanBeLoaded = function(){
return $scope.totalPages > $scope.page;
};
$scope.bookmarkPost = function(post){
$ionicLoading.show({ template: 'Post Saved!', noBackdrop: true, duration: 1000 });
BookMarkService.bookmarkWordpressPost(post);
};
$scope.doRefresh();
})
// WORDPRESS POST
.controller('WordpressPostCtrl', function($scope, post_data, $ionicLoading) {
$scope.post = post_data.post;
$ionicLoading.hide();
$scope.sharePost = function(link){
window.plugins.socialsharing.share('Check this post here: ', null, null, link);
};
})
.controller('ImagePickerCtrl', function($scope, $rootScope, $cordovaCamera) {
$scope.images = [];
$scope.selImages = function() {
window.imagePicker.getPictures(
function(results) {
for (var i = 0; i < results.length; i++) {
console.log('Image URI: ' + results[i]);
$scope.images.push(results[i]);
}
if(!$scope.$$phase) {
$scope.$apply();
}
}, function (error) {
console.log('Error: ' + error);
}
);
};
$scope.removeImage = function(image) {
$scope.images = _.without($scope.images, image);
};
$scope.shareImage = function(image) {
window.plugins.socialsharing.share(null, null, image);
};
$scope.shareAll = function() {
window.plugins.socialsharing.share(null, null, $scope.images);
};
})
;

View file

@ -0,0 +1,374 @@
angular.module('your_app_name.directives', [])
.directive('myTabs', function() {
return {
restrict: 'E',
transclude: true,
scope: {},
controller: function($scope) {
var tabs = $scope.tabs = [];
$scope.select = function(tab) {
angular.forEach(tabs, function(tab) {
tab.selected = false;
});
tab.selected = true;
$scope.$emit('my-tabs-changed', tab);
};
this.addTab = function(tab) {
if (tabs.length === 0) {
$scope.select(tab);
}
tabs.push(tab);
};
},
templateUrl: 'views/common/my-tabs.html'
};
})
.directive('myTab', function() {
return {
require: '^myTabs',
restrict: 'E',
transclude: true,
scope: {
title: '@'
},
link: function(scope, element, attrs, tabsCtrl) {
tabsCtrl.addTab(scope);
},
templateUrl: 'views/common/my-tab.html'
};
})
.directive('validPin', function($http) {
return {
require: 'ngModel',
link: function(scope, ele, attrs, c) {
scope.$watch(attrs.ngModel, function(pinValue) {
// $http({
// method: 'POST',
// url: '/api/check/' + attrs.validPin,
// data: {'pin': attrs.validPin}
// }).success(function(data, status, headers, cfg) {
// c.$setValidity('valid-pin', data.isValid);
// }).error(function(data, status, headers, cfg) {
// c.$setValidity('valid-pin', false);
// });
if(pinValue=="12345")
{
c.$setValidity('valid-pin', true);
}
else
{
c.$setValidity('valid-pin', false);
}
});
}
};
})
.directive('showHideContainer', function(){
return {
scope: {
},
controller: function($scope, $element, $attrs) {
$scope.show = false;
$scope.toggleType = function($event){
$event.stopPropagation();
$event.preventDefault();
$scope.show = !$scope.show;
// Emit event
$scope.$broadcast("toggle-type", $scope.show);
};
},
templateUrl: 'views/common/show-hide-password.html',
restrict: 'A',
replace: false,
transclude: true
};
})
.directive('showHideInput', function(){
return {
scope: {
},
link: function(scope, element, attrs) {
// listen to event
scope.$on("toggle-type", function(event, show){
var password_input = element[0],
input_type = password_input.getAttribute('type');
if(!show)
{
password_input.setAttribute('type', 'password');
}
if(show)
{
password_input.setAttribute('type', 'text');
}
});
},
require: '^showHideContainer',
restrict: 'A',
replace: false,
transclude: false
};
})
.directive('biggerText', function($ionicGesture) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
$ionicGesture.on('touch', function(event){
event.stopPropagation();
event.preventDefault();
var text_element = document.querySelector(attrs.biggerText),
root_element = document.querySelector(".menu-content"),
current_size_str = window.getComputedStyle(text_element, null).getPropertyValue('font-size'),
current_size = parseFloat(current_size_str),
new_size = Math.min((current_size+2), 24),
new_size_str = new_size + 'px';
root_element.classList.remove("post-size-"+current_size_str);
root_element.classList.add("post-size-"+new_size_str);
}, element);
}
};
})
.directive('smallerText', function($ionicGesture) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
$ionicGesture.on('touch', function(event){
event.stopPropagation();
event.preventDefault();
var text_element = document.querySelector(attrs.smallerText),
root_element = document.querySelector(".menu-content"),
current_size_str = window.getComputedStyle(text_element, null).getPropertyValue('font-size'),
current_size = parseFloat(current_size_str),
new_size = Math.max((current_size-2), 12),
new_size_str = new_size + 'px';
root_element.classList.remove("post-size-"+current_size_str);
root_element.classList.add("post-size-"+new_size_str);
}, element);
}
};
})
.directive('ionicYoutubeVideo', function($timeout, $ionicPlatform, youtubeEmbedUtils) {
return {
restrict: 'E',
scope: {
videoId: '@'
},
controller: function($scope, $element, $attrs) {
$scope.playerVars = {
rel: 0,
showinfo: 0
};
$ionicPlatform.on("pause", function(){
var yt_ready = youtubeEmbedUtils.ready;
if(yt_ready)
{
$scope.yt_video.stopVideo();
}
});
},
templateUrl: 'views/common/ionic-youtube-video.html',
replace: false
};
})
.directive('postContent', function($timeout, _, $compile) {
return {
restrict: 'A',
scope: {},
link: function(scope, element, attrs) {
/**
* JavaScript function to match (and return) the video Id
* of any valid Youtube Url, given as input string.
* @author: Stephan Schmitz <eyecatchup@gmail.com>
* @url: http://stackoverflow.com/a/10315969/624466
*/
// Ver: https://regex101.com/r/tY9jN6/1
function ytVidId(url) {
var p = /^(?:https?:\/\/)?(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11,})(?:\S+)?$/gmi;
return (url.match(p)) ? RegExp.$1 : false;
}
$timeout(function(){
var iframes = element.find('iframe');
if(iframes.length > 0)
{
angular.forEach(iframes, function(i) {
var iframe = angular.element(i),
youtube_video_id = ((iframe.length > 0) && (!_.isUndefined(iframe[0].src))) ? ytVidId(iframe[0].src) : false;
if(youtube_video_id !== false)
{
// Then it's a youtube video, compile our custom directive
var ionic_yt_video = $compile("<ionic-youtube-video video-id='"+youtube_video_id+"'></ionic-youtube-video>")(scope);
iframe.parent().append(ionic_yt_video);
iframe.remove();
}
});
}
}, 10);
}
};
})
//Use this directive to open external links using inAppBrowser cordova plugin
.directive('dynamicAnchorFix', function($ionicGesture, $timeout, $cordovaInAppBrowser) {
return {
scope: {},
link: function(scope, element, attrs) {
$timeout(function(){
var anchors = element.find('a');
if(anchors.length > 0)
{
angular.forEach(anchors, function(a) {
var anchor = angular.element(a);
anchor.bind('click', function (event) {
event.preventDefault();
event.stopPropagation();
var href = event.currentTarget.href;
var options = {};
//inAppBrowser see documentation here: http://ngcordova.com/docs/plugins/inAppBrowser/
$cordovaInAppBrowser.open(href, '_blank', options)
.then(function(e) {
// success
})
.catch(function(e) {
// error
});
});
});
}
}, 10);
},
restrict: 'A',
replace: false,
transclude: false
};
})
.directive('multiBg', function(_){
return {
scope: {
multiBg: '=',
interval: '=',
helperClass: '@'
},
controller: function($scope, $element, $attrs) {
$scope.loaded = false;
var utils = this;
this.animateBg = function(){
// Think i have to use apply because this function is not called from this controller ($scope)
$scope.$apply(function () {
$scope.loaded = true;
$element.css({'background-image': 'url(' + $scope.bg_img + ')'});
});
};
this.setBackground = function(bg) {
$scope.bg_img = bg;
};
if(!_.isUndefined($scope.multiBg))
{
if(_.isArray($scope.multiBg) && ($scope.multiBg.length > 1) && !_.isUndefined($scope.interval) && _.isNumber($scope.interval))
{
// Then we need to loop through the bg images
utils.setBackground($scope.multiBg[0]);
}
else
{
// Then just set the multiBg image as background image
utils.setBackground($scope.multiBg[0]);
}
}
},
templateUrl: 'views/common/multi-bg.html',
restrict: 'A',
replace: true,
transclude: true
};
})
.directive('bg', function() {
return {
restrict: 'A',
require: '^multiBg',
scope: {
ngSrc: '@'
},
link: function(scope, element, attr, multiBgController) {
element.on('load', function() {
multiBgController.animateBg();
});
}
};
})
.directive('preImg', function() {
return {
restrict: 'E',
transclude: true,
scope: {
ratio:'@',
helperClass: '@'
},
controller: function($scope) {
$scope.loaded = false;
this.hideSpinner = function(){
// Think i have to use apply because this function is not called from this controller ($scope)
$scope.$apply(function () {
$scope.loaded = true;
});
};
},
templateUrl: 'views/common/pre-img.html'
};
})
.directive('spinnerOnLoad', function() {
return {
restrict: 'A',
require: '^preImg',
scope: {
ngSrc: '@'
},
link: function(scope, element, attr, preImgController) {
element.on('load', function() {
preImgController.hideSpinner();
});
}
};
})
;

View file

@ -0,0 +1,212 @@
angular.module('your_app_name.factories', [])
.factory('FeedLoader', function ($resource){
return $resource('http://ajax.googleapis.com/ajax/services/feed/load', {}, {
fetch: { method: 'JSONP', params: {v: '1.0', callback: 'JSON_CALLBACK'} }
});
})
// Factory for node-pushserver (running locally in this case), if you are using other push notifications server you need to change this
.factory('NodePushServer', function ($http){
// Configure push notifications server address
// - If you are running a local push notifications server you can test this by setting the local IP (on mac run: ipconfig getifaddr en1)
var push_server_address = "http://192.168.1.102:8000";
return {
// Stores the device token in a db using node-pushserver
// type: Platform type (ios, android etc)
storeDeviceToken: function(type, regId) {
// Create a random userid to store with it
var user = {
user: 'user' + Math.floor((Math.random() * 10000000) + 1),
type: type,
token: regId
};
console.log("Post token for registered device with data " + JSON.stringify(user));
$http.post(push_server_address+'/subscribe', JSON.stringify(user))
.success(function (data, status) {
console.log("Token stored, device is successfully subscribed to receive push notifications.");
})
.error(function (data, status) {
console.log("Error storing device token." + data + " " + status);
});
},
// CURRENTLY NOT USED!
// Removes the device token from the db via node-pushserver API unsubscribe (running locally in this case).
// If you registered the same device with different userids, *ALL* will be removed. (It's recommended to register each
// time the app opens which this currently does. However in many cases you will always receive the same device token as
// previously so multiple userids will be created with the same token unless you add code to check).
removeDeviceToken: function(token) {
var tkn = {"token": token};
$http.post(push_server_address+'/unsubscribe', JSON.stringify(tkn))
.success(function (data, status) {
console.log("Token removed, device is successfully unsubscribed and will not receive push notifications.");
})
.error(function (data, status) {
console.log("Error removing device token." + data + " " + status);
});
}
};
})
.factory('AdMob', function ($window){
var admob = $window.AdMob;
if(admob)
{
// Register AdMob events
// new events, with variable to differentiate: adNetwork, adType, adEvent
document.addEventListener('onAdFailLoad', function(data){
console.log('error: ' + data.error +
', reason: ' + data.reason +
', adNetwork:' + data.adNetwork +
', adType:' + data.adType +
', adEvent:' + data.adEvent); // adType: 'banner' or 'interstitial'
});
document.addEventListener('onAdLoaded', function(data){
console.log('onAdLoaded: ' + data);
});
document.addEventListener('onAdPresent', function(data){
console.log('onAdPresent: ' + data);
});
document.addEventListener('onAdLeaveApp', function(data){
console.log('onAdLeaveApp: ' + data);
});
document.addEventListener('onAdDismiss', function(data){
console.log('onAdDismiss: ' + data);
});
var defaultOptions = {
// bannerId: admobid.banner,
// interstitialId: admobid.interstitial,
// adSize: 'SMART_BANNER',
// width: integer, // valid when set adSize 'CUSTOM'
// height: integer, // valid when set adSize 'CUSTOM'
position: admob.AD_POSITION.BOTTOM_CENTER,
// offsetTopBar: false, // avoid overlapped by status bar, for iOS7+
bgColor: 'black', // color name, or '#RRGGBB'
// x: integer, // valid when set position to 0 / POS_XY
// y: integer, // valid when set position to 0 / POS_XY
isTesting: true, // set to true, to receiving test ad for testing purpose
// autoShow: true // auto show interstitial ad when loaded, set to false if prepare/show
};
var admobid = {};
if(ionic.Platform.isAndroid())
{
admobid = { // for Android
banner: 'ca-app-pub-6869992474017983/9375997553',
interstitial: 'ca-app-pub-6869992474017983/1657046752'
};
}
if(ionic.Platform.isIOS())
{
admobid = { // for iOS
banner: 'ca-app-pub-6869992474017983/4806197152',
interstitial: 'ca-app-pub-6869992474017983/7563979554'
};
}
admob.setOptions(defaultOptions);
// Prepare the ad before showing it
// - (for example at the beginning of a game level)
admob.prepareInterstitial({
adId: admobid.interstitial,
autoShow: false,
success: function(){
console.log('interstitial prepared');
},
error: function(){
console.log('failed to prepare interstitial');
}
});
}
else
{
console.log("No AdMob?");
}
return {
showBanner: function() {
if(admob)
{
admob.createBanner({
adId:admobid.banner,
position:admob.AD_POSITION.BOTTOM_CENTER,
autoShow:true,
success: function(){
console.log('banner created');
},
error: function(){
console.log('failed to create banner');
}
});
}
},
showInterstitial: function() {
if(admob)
{
// If you didn't prepare it before, you can show it like this
// admob.prepareInterstitial({adId:admobid.interstitial, autoShow:autoshow});
// If you did prepare it before, then show it like this
// - (for example: check and show it at end of a game level)
admob.showInterstitial();
}
},
removeAds: function() {
if(admob)
{
admob.removeBanner();
}
}
};
})
.factory('iAd', function ($window){
var iAd = $window.iAd;
// preppare and load ad resource in background, e.g. at begining of game level
if(iAd) {
iAd.prepareInterstitial( { autoShow:false } );
}
else
{
console.log("No iAd?");
}
return {
showBanner: function() {
if(iAd)
{
// show a default banner at bottom
iAd.createBanner({
position:iAd.AD_POSITION.BOTTOM_CENTER,
autoShow:true
});
}
},
showInterstitial: function() {
// ** Notice: iAd interstitial Ad only supports iPad.
if(iAd)
{
// If you did prepare it before, then show it like this
// - (for example: check and show it at end of a game level)
iAd.showInterstitial();
}
},
removeAds: function() {
if(iAd)
{
iAd.removeBanner();
}
}
};
})
;

View file

@ -0,0 +1,15 @@
angular.module('your_app_name.filters', [])
.filter('rawHtml', function($sce){
return function(val) {
return $sce.trustAsHtml(val);
};
})
.filter('parseDate', function() {
return function(value) {
return Date.parse(value);
};
})
;

View file

@ -0,0 +1,227 @@
angular.module('your_app_name.services', [])
.service('FeedList', function ($rootScope, FeedLoader, $q){
this.get = function(feedSourceUrl) {
var response = $q.defer();
//num is the number of results to pull form the source
FeedLoader.fetch({q: feedSourceUrl, num: 20}, {}, function (data){
response.resolve(data.responseData);
});
return response.promise;
};
})
// PUSH NOTIFICATIONS
.service('PushNotificationsService', function ($rootScope, $cordovaPush, NodePushServer, GCM_SENDER_ID){
/* Apple recommends you register your application for push notifications on the device every time its run since tokens can change. The documentation says: By requesting the device token and passing it to the provider every time your application launches, you help to ensure that the provider has the current token for the device. If a user restores a backup to a device other than the one that the backup was created for (for example, the user migrates data to a new device), he or she must launch the application at least once for it to receive notifications again. If the user restores backup data to a new device or reinstalls the operating system, the device token changes. Moreover, never cache a device token and give that to your provider; always get the token from the system whenever you need it. */
this.register = function() {
var config = {};
// ANDROID PUSH NOTIFICATIONS
if(ionic.Platform.isAndroid())
{
config = {
"senderID": GCM_SENDER_ID
};
$cordovaPush.register(config).then(function(result) {
// Success
console.log("$cordovaPush.register Success");
console.log(result);
}, function(err) {
// Error
console.log("$cordovaPush.register Error");
console.log(err);
});
$rootScope.$on('$cordovaPush:notificationReceived', function(event, notification) {
console.log(JSON.stringify([notification]));
switch(notification.event)
{
case 'registered':
if (notification.regid.length > 0 ) {
console.log('registration ID = ' + notification.regid);
NodePushServer.storeDeviceToken("android", notification.regid);
}
break;
case 'message':
if(notification.foreground == "1")
{
console.log("Notification received when app was opened (foreground = true)");
}
else
{
if(notification.coldstart == "1")
{
console.log("Notification received when app was closed (not even in background, foreground = false, coldstart = true)");
}
else
{
console.log("Notification received when app was in background (started but not focused, foreground = false, coldstart = false)");
}
}
// this is the actual push notification. its format depends on the data model from the push server
console.log('message = ' + notification.message);
break;
case 'error':
console.log('GCM error = ' + notification.msg);
break;
default:
console.log('An unknown GCM event has occurred');
break;
}
});
// WARNING: dangerous to unregister (results in loss of tokenID)
// $cordovaPush.unregister(options).then(function(result) {
// // Success!
// }, function(err) {
// // Error
// });
}
if(ionic.Platform.isIOS())
{
config = {
"badge": true,
"sound": true,
"alert": true
};
$cordovaPush.register(config).then(function(result) {
// Success -- send deviceToken to server, and store for future use
console.log("result: " + result);
NodePushServer.storeDeviceToken("ios", result);
}, function(err) {
console.log("Registration error: " + err);
});
$rootScope.$on('$cordovaPush:notificationReceived', function(event, notification) {
console.log(notification.alert, "Push Notification Received");
});
}
};
})
// BOOKMARKS FUNCTIONS
.service('BookMarkService', function (_, $rootScope){
this.bookmarkFeedPost = function(bookmark_post){
var user_bookmarks = !_.isUndefined(window.localStorage.ionFullApp_feed_bookmarks) ?
JSON.parse(window.localStorage.ionFullApp_feed_bookmarks) : [];
//check if this post is already saved
var existing_post = _.find(user_bookmarks, function(post){ return post.link == bookmark_post.link; });
if(!existing_post){
user_bookmarks.push({
link: bookmark_post.link,
title : bookmark_post.title,
date: bookmark_post.publishedDate,
excerpt: bookmark_post.contentSnippet
});
}
window.localStorage.ionFullApp_feed_bookmarks = JSON.stringify(user_bookmarks);
$rootScope.$broadcast("new-bookmark");
};
this.bookmarkWordpressPost = function(bookmark_post){
var user_bookmarks = !_.isUndefined(window.localStorage.ionFullApp_wordpress_bookmarks) ?
JSON.parse(window.localStorage.ionFullApp_wordpress_bookmarks) : [];
//check if this post is already saved
var existing_post = _.find(user_bookmarks, function(post){ return post.id == bookmark_post.id; });
if(!existing_post){
user_bookmarks.push({
id: bookmark_post.id,
title : bookmark_post.title,
date: bookmark_post.date,
excerpt: bookmark_post.excerpt
});
}
window.localStorage.ionFullApp_wordpress_bookmarks = JSON.stringify(user_bookmarks);
$rootScope.$broadcast("new-bookmark");
};
this.getBookmarks = function(){
return {
feeds : JSON.parse(window.localStorage.ionFullApp_feed_bookmarks || '[]'),
wordpress: JSON.parse(window.localStorage.ionFullApp_wordpress_bookmarks || '[]')
};
};
})
// WP POSTS RELATED FUNCTIONS
.service('PostService', function ($rootScope, $http, $q, WORDPRESS_API_URL){
this.getRecentPosts = function(page) {
var deferred = $q.defer();
$http.jsonp(WORDPRESS_API_URL + 'get_recent_posts/' +
'?page='+ page +
'&callback=JSON_CALLBACK')
.success(function(data) {
deferred.resolve(data);
})
.error(function(data) {
deferred.reject(data);
});
return deferred.promise;
};
this.getPost = function(postId) {
var deferred = $q.defer();
$http.jsonp(WORDPRESS_API_URL + 'get_post/' +
'?post_id='+ postId +
'&callback=JSON_CALLBACK')
.success(function(data) {
deferred.resolve(data);
})
.error(function(data) {
deferred.reject(data);
});
return deferred.promise;
};
this.shortenPosts = function(posts) {
//we will shorten the post
//define the max length (characters) of your post content
var maxLength = 500;
return _.map(posts, function(post){
if(post.content.length > maxLength){
//trim the string to the maximum length
var trimmedString = post.content.substr(0, maxLength);
//re-trim if we are in the middle of a word
trimmedString = trimmedString.substr(0, Math.min(trimmedString.length, trimmedString.lastIndexOf("</p>")));
post.content = trimmedString;
}
return post;
});
};
this.sharePost = function(link){
window.plugins.socialsharing.share('Check this post here: ', null, null, link);
};
})
;