(function () {
var $injector = angular.injector(['ng']);
$injector.invoke(function ($http, $rootScope) {
$rootScope.$apply(function () {
$http.post('/rest/user/login', {
}).then(function successCallback(res) {
angular.module("app").constant("USER", res.data.user);
angular.bootstrap(document, ['app']);
});
});
});
})();
var app = angular.module('app', ['ui.bootstrap', 'amChartsDirective', 'ngRoute', 'pascalprecht.translate']);
app.filter('html', ['$sce', function ($sce) {
return function (text) {
return $sce.trustAsHtml(text);
};
}]);
app.filter('useFilter', function ($filter) {
return function () {
if (typeof arguments[0] == 'undefined') {
return '';
};
var filterName = [].splice.call(arguments, 1, 1)[0];
return $filter(filterName).apply(null, arguments);
};
})
app.filter('useFilter2', function ($filter) {
return function () {
if (typeof arguments[0] == 'undefined') {
return '--';
};
var filterName = [].splice.call(arguments, 1, 1)[0];
return $filter(filterName).apply(null, arguments);
};
})
app.filter('exists', function ($filter) {
return function (v) {
if (v === 0 || v == '0.00') {
return '--';
}
if (!v) {
return '';
};
return v;
};
})
app.filter('secondsToHHmmss', function ($filter) {
return function (seconds) {
if (seconds) {
return $filter('date')(new Date(0, 0, 0).setSeconds(seconds), 'HH:mm:ss');
}
return '00:00:00';
};
})
app.filter('mcdate', function ($filter) {
return function (datum) {
var d = new Date(datum);
return d.getDate() + '/' + (d.getMonth() + 1) + '/' + d.getFullYear() + ' - ' + d.getHours() + ':' + d.getMinutes();
};
})
app.filter('minzero', function ($filter) {
return function (int) {
return (int < 0) ? 0 : int;
};
})
app.filter('path', function () {
return function (url) {
return url = url.substring(url.indexOf("/"));
};
})
app.filter('truefalse', function () {
return function (b) {
return (b) ? 'Yes' : 'No';
};
})
app.filter('string', function () {
return function (b) {
return b;
};
})
app.filter('objToArray', function () {
return function (input, attribute) {
if (!angular.isObject(input)) return input;
var array = [];
for (var objectKey in input) {
array.push(input[objectKey]);
}
return array;
}
})
app.factory('h', function ($rootScope, $http) {
return {
siteId: function () {
if ($rootScope.user.site) {
if ($rootScope.user.site._id) {
return $rootScope.user.site._id.$oid;
}
}
},
login: function (cb) {
$http.post('/rest/user/login', {
}).then(function successCallback(res) {
$rootScope.user = res.data.user;
cb();
});
},
colors: function () {
return angular.extend([], ['#E91E63', '#3F51B5', '#00BCD4', '#8BC34A', '#FF9800', '#795548', '#607D8B', '#00CC00', '#0000CC', '#DDDDDD', '#999999', '#333333', '#990000'], $rootScope.user.reseller.config.chartcolors)
},
metrics: function (key) {
var allMetrics = {
analytics: {
sessions: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
users: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
pageviews: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
pageviewsPerSession: { typefilter: 'number', filtercomparator: 2, 'datemerge': 'avg' },
avgSessionDuration: { typefilter: 'secondsToHHmmss', filtercomparator: 0, 'datemerge': 'avg' },
percentNewSessions: { typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' },
bounceRate: { typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg', 'reversesign': true },
goalCompletionsAll: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
goalValueAll: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
goalConversionRateAll: { typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' },
goalAbandonRateAll: { typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' },
uniquePageviews: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
avgTimeOnPage: { typefilter: 'secondsToHHmmss', filtercomparator: 0, 'datemerge': 'avg' },
entrances: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
exitRate: { typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' },
pageValue: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
exits: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
ROAS: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
costPerTransaction: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
totalValue: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
adCost: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
CPC: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
adClicks: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
transactions: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
uniquePurchases: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
totalValue: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
revenuePerTransaction: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
itemQuantity: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
itemsPerPurchase: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
},
facebookads: {
clicks: { name: 'Klikken', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
impressions: { name: 'Impressies', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
cpc: { name: 'cpc', typefilter: 'number', filtercomparator: 2, 'before': '€', 'datemerge': 'avg' },
cpm: { name: 'cpm', typefilter: 'number', filtercomparator: 2, 'before': '€', 'datemerge': 'avg' },
ctr: { name: 'Ctr', typefilter: 'number', filtercomparator: 2, 'after': '%', 'datemerge': 'avg' },
Conversions: { name: 'Conversions', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
Cost: { name: 'Cost', typefilter: 'number', filtercomparator: 0, 'before': '€', 'datemerge': 'sum' },
CostPerConversion: { name: 'spend / conversie', typefilter: 'number', filtercomparator: 0, 'before': '€', 'datemerge': 'avg' },
ConversionRate: { name: 'Conversie ratio', typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' },
AveragePosition: { name: 'Gemiddelde positie', typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
ConversionValue: { name: 'Totale conversiewaarde', typefilter: 'number', filtercomparator: 0, 'before': '€', 'datemerge': 'sum' },
relevance_score: { name: 'Relevantie Score', typefilter: 'number', filtercomparator: 0, hide: { 'panel': true }, 'datemerge': 'avg' },
spend: { name: 'Kosten', typefilter: 'number', filtercomparator: 2, 'before': '€', 'datemerge': 'sum' },
},
facebookinsights: {
fans: { name: 'Fans', typefilter: 'number', filtercomparator: 0 },
interacties: { name: 'Interactions', typefilter: 'number', filtercomparator: 0 },
bereik: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 },
},
googlexads: {
Clicks: { name: 'Clicks', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
Impressions: { name: 'Impressions', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
Date: { name: 'Date', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
AverageCpc: { name: 'Avg cost / Click', typefilter: 'number', filtercomparator: 2, 'before': '€', 'datemerge': 'avg' },
Ctr: { name: 'Ctr', typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' },
Conversions: { name: 'Conversions', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
Cost: { name: 'Cost', typefilter: 'number', filtercomparator: 2, 'before': '€', 'datemerge': 'sum' },
CostPerConversion: { name: 'Cost / conversion', typefilter: 'number', filtercomparator: 2, 'before': '€', 'datemerge': 'avg' },
ConversionRate: { name: 'Conversion rate', typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' },
AbsoluteTopImpressionPercentage: { name: 'AbsoluteTopImpressionPercentage', typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' },
ConversionValue: { name: 'Conversion value', typefilter: 'number', filtercomparator: 0, 'before': '€', 'datemerge': 'sum' },
SearchImpressionShare: { name: 'Zoekimpressie aandeel', typefilter: 'number', filtercomparator: 2, 'after': '%', 'datemerge': 'avg' },
SearchAbsoluteTopImpressionShare: { name: 'Top Positie', typefilter: 'number', filtercomparator: 2, 'after': '%', 'datemerge': 'avg' },
roas: { name: 'ROAS', typefilter: 'number', filtercomparator: 2, 'after': '%', 'datemerge': 'avg' },
},
instagram: {
impressions: { name: 'Fans', typefilter: 'number', filtercomparator: 0 },
reach: { name: 'Interactions', typefilter: 'number', filtercomparator: 0 },
follower_count: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 },
profile_views: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 },
website_clicks: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 },
email_contacts: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 },
get_directions_clicks: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 },
phone_call_clicks: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 },
text_message_clicks: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 },
},
linkedin: {
Placeholder: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
shareCount: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
likeCount: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
engagement: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
clickCount: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
impressionCount: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
commentCount: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
networksize: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
networksizeexternal: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
networksizeinternal: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
},
linkedinxads: {
impressions: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
clicks: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
oneClickLeads: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
costInLocalCurrency: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
externalWebsiteConversions: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
costInLocalCurrency: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
networksize: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
networksizeexternal: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
networksizeinternal: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
},
mailchimp: {
Placeholder: { name: '', typefilter: 'number', filtercomparator: 0 },
member_count: { name: 'Aanmeldingen', typefilter: 'number', filtercomparator: 0 },
list_rating: { name: 'Rating', typefilter: 'number', filtercomparator: 0 },
click_rate: { name: 'Klik Ratio', typefilter: 'number', filtercomparator: 0, 'after': '%' },
open_rate: { name: 'Open Ratio', typefilter: 'number', filtercomparator: 0, 'after': '%' },
emails_sent: { name: 'Email verstuurd', typefilter: 'number', filtercomparator: 0 },
send_time: { name: 'Verstuurd op', typefilter: 'mcdate', filtercomparator: 0 },
unsubscribed: { name: 'Afmeldingen', typefilter: 'number', filtercomparator: 0 },
unsubscribe_count: { name: 'Afmeldingen', typefilter: 'number', filtercomparator: 0 },
cleaned_count: { name: 'Verwijderd', typefilter: 'number', filtercomparator: 0 },
bounces: { name: 'Bounce', typefilter: 'number', filtercomparator: 0 },
total_orders: { name: 'Orders', typefilter: 'number', filtercomparator: 0 },
recipient_clicks: { name: 'klikken', typefilter: 'number', filtercomparator: 0 },
total_revenue: { name: 'Totale opbrangest', typefilter: 'number', filtercomparator: 0, 'after': '€' },
},
mybusiness: {
Placeholder: { name: '', typefilter: 'number', filtercomparator: 0 },
QUERIES_DIRECT: { name: 'Directe zoekopdrachten', typefilter: 'number', filtercomparator: 0 },
QUERIES_INDIRECT: { name: 'Indirecte zoekopdrachten', typefilter: 'number', filtercomparator: 0 },
VIEWS_MAPS: { name: 'Google maps', typefilter: 'number', filtercomparator: 0 },
VIEWS_SEARCH: { name: 'Google zoeken', typefilter: 'number', filtercomparator: 0 },
QUERIES_DIRECT: { name: 'Bedrijf zoekopdacht', typefilter: 'number', filtercomparator: 0 },
QUERIES_INDIRECT: { name: 'Categorie zoekopdracht', typefilter: 'number', filtercomparator: 0 },
PHOTOS_VIEWS_MERCHANT: { name: 'Van eigenaars', typefilter: 'number', filtercomparator: 0 },
PHOTOS_VIEWS_CUSTOMERS: { name: 'Van bezoekers', typefilter: 'number', filtercomparator: 0 },
PHOTOS_COUNT_MERCHANT: { name: 'Van eigenaar', typefilter: 'number', filtercomparator: 0 },
PHOTOS_COUNT_CUSTOMERS: { name: 'Van bezoekers', typefilter: 'number', filtercomparator: 0 },
Date: { name: 'Datum', typefilter: 'number', filtercomparator: 0 },
AverageCpc: { name: 'Gemiddelde kosten per klik', typefilter: 'number', filtercomparator: 2, 'before': '€' },
Ctr: { name: 'Ctr', typefilter: 'number', filtercomparator: 0, 'after': '%' },
Conversions: { name: 'Conversions', typefilter: 'number', filtercomparator: 0 },
Cost: { name: 'Cost', typefilter: 'number', filtercomparator: 0, 'before': '€' },
CostPerConversion: { name: 'Kosten per conversie', typefilter: 'number', filtercomparator: 0, 'before': '€' },
ConversionRate: { name: 'Conversie ratio', typefilter: 'number', filtercomparator: 0, 'after': '%' },
AveragePosition: { name: 'Gemiddelde positie', typefilter: 'number', filtercomparator: 1 },
ConversionValue: { name: 'Totale conversiewaarde', typefilter: 'number', filtercomparator: 0, 'before': '€' },
},
searchconsole: {
clicks: { typefilter: 'number', filtercomparator: 0, 'reverse': true, 'datemerge': 'sum' },
ctr: { typefilter: 'number', filtercomparator: 2, 'after': '%', 'reverse': true, 'datemerge': 'avg' },
impressions: { typefilter: 'number', filtercomparator: 0, 'reverse': true, 'datemerge': 'sum' },
Date: { typefilter: 'number', filtercomparator: 0 },
position: { typefilter: 'number', filtercomparator: 1, 'reverse': false, 'reversesign': true, 'datemerge': 'avg' },
},
youtube: {
commentCount: { name: 'Clicks', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
subscriberCount: { name: 'Impressions', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
videoCount: { name: 'Date', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
viewCount: { name: 'Avg cost / Click', typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
views: { name: 'Ctr', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
shares: { name: 'Conversions', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
likes: { name: 'Cost', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
dislikes: { name: 'Cost / conversion', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
comments: { name: 'Conversion rate', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
subscribersGained: { name: 'AbsoluteTopImpressionPercentage', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
subscribersLost: { name: 'Conversion value', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
estimatedMinutesWatched: { name: 'Zoekimpressie aandeel', typefilter: 'number', filtercomparator: 1, 'datemerge': 'sum' },
annotationCloseRate: { name: 'Top Positie', typefilter: 'number', filtercomparator: 2, 'after': '%', 'datemerge': 'avg' },
annotationClickThroughRate: { name: 'ROAS', typefilter: 'number', filtercomparator: 2, 'after': '%', 'datemerge': 'avg' },
averageViewDuration: { name: 'ROAS', typefilter: 'secondsToHHmmss', filtercomparator: 0, 'datemerge': 'avg' },
},
analytics4: {
totalUsers: { name: 'totalUsers', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
screenPageViews: { name: 'screenPageViews', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
screenPageViewsPerSession: { name: 'screenPageViewsPerSession', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
sessions: { name: 'Sessions', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
newUsers: { name: 'Users', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
pageviews: { name: 'Pageviews', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
pageviewsPerSession: { name: 'Pageviews / session', typefilter: 'number', filtercomparator: 2, 'datemerge': 'avg' },
averageSessionDuration: { name: 'Average session duration', typefilter: 'secondsToHHmmss', filtercomparator: 0, 'datemerge': 'avg' },
percentNewSessions: { name: 'Percentrage new sessions', typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' },
bounceRate: { name: 'Bounce Ratio', typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' },
goalCompletionsAll: { name: 'Goals', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
goalValueAll: { name: 'Goalvalue', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
goalConversionRateAll: { name: 'Goalconversion ratio', typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' },
goalAbandonRateAll: { name: 'Doel verlatings ratio', typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' },
uniquePageviews: { name: 'Unique Pageviews', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
avgTimeOnPage: { name: 'Avg time on page', typefilter: 'secondsToHHmmss', filtercomparator: 0, 'datemerge': 'avg' },
entrances: { name: 'Entrances', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
exitRate: { name: 'Exit rate', typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' },
pageValue: { name: 'Pagevalue', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
exits: { name: 'Exits', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
ROAS: { name: 'ROAS', typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
costPerTransaction: { name: 'Cost per transaction', typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
totalValue: { name: 'Total value', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
adCost: { name: 'Ad Cost', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
CPC: { name: 'CPC', typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
adClicks: { name: 'Ad Clicks', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
transactions: { name: 'Transacions', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
uniquePurchases: { name: 'Unique Purchases', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
totalValue: { name: 'Total Value', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
revenuePerTransaction: { name: 'Revenue per Transaction', typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
itemQuantity: { name: 'Item Quentity', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
itemsPerPurchase: { name: 'items / purchase', typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
eventCount: { name: 'items / purchase', typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
eventCountPerUser: { name: 'items / purchase', typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
mobileDeviceBranding: { name: 'Mobile device model', typefilter: 'text', filtercomparator: 3 },
itemsPurchased: { name: 'Items purchased', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
itemRevenue: { name: 'Item revenue', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
conversions: { name: 'Conversions', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
eventValue: { name: 'Event value', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
sessionConversionRate: { name: 'Session conversion rate', typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' },
userEngagementDuration: { name: 'User engagement duration', typefilter: 'secondsToHHmmss', filtercomparator: 0, 'datemerge': 'sum' },
engagementRate: { name: 'User engagement rate', typefilter: 'number', filtercomparator: 2, 'after': '%', 'datemerge': 'avg' },
}
}
return allMetrics[key];
}
}
});
app.directive('bullet', function ($compile) {
return {
restrict: 'E',
scope: {
type: '='
},
template: '',
};
});
app.directive("clientscript", function () {
var updateScripts = function (element) {
return function (script) {
element.empty();
var scriptTag = angular.element(document.createElement("script"));
scriptTag.text(script)
element.append(scriptTag);
};
};
return {
restrict: "EA",
scope: {
scripts: "="
},
link: function (scope, element) {
scope.$watch("scripts", updateScripts(element));
}
};
})
app.filter('maxserp', function () {
return function (text, length, end) {
if (text == 100 || text === undefined) {
return '--';
}
return text;
}
})
app.directive('change', function () {
return {
restrict: 'E',
replace: true,
scope: {
type: '@'
},
template: '{{change}} ',
link: function (scope) {
scope.$watch('type', function () {
if (scope.type == '0') {
scope.change = '--';
} else if (scope.type < 1) {
scope.change = scope.type + ' ';
scope.class = 'fa fa-long-arrow-down text-warning';
} else {
scope.change = scope.type + ' ';
scope.class = 'fa fa-long-arrow-up text-success';
}
});
}
};
});
app.directive('infiniteScroll', [
'$rootScope', '$window', '$timeout',
function ($rootScope, $window, $timeout) {
return {
link: function (scope, elem, attrs) {
var checkWhenEnabled, handler, scrollDistance, scrollEnabled;
$window = angular.element($window);
scrollDistance = 0;
if (attrs.infiniteScrollDistance != null) {
scope.$watch(attrs.infiniteScrollDistance, function (value) {
return scrollDistance = parseInt(value, 10);
});
}
scrollEnabled = true;
checkWhenEnabled = false;
if (attrs.infiniteScrollDisabled != null) {
scope.$watch(attrs.infiniteScrollDisabled, function (value) {
scrollEnabled = !value;
if (scrollEnabled && checkWhenEnabled) {
checkWhenEnabled = false;
return handler();
}
});
}
handler = function () {
var elementBottom, remaining, shouldScroll, windowBottom;
windowBottom = $window.height() + $window.scrollTop();
elementBottom = elem.offset().top + elem.height();
remaining = elementBottom - windowBottom;
shouldScroll = remaining <= $window.height() * scrollDistance;
if (shouldScroll && scrollEnabled) {
if ($rootScope.$$phase) {
return scope.$eval(attrs.infiniteScroll);
} else {
return scope.$apply(attrs.infiniteScroll);
}
} else if (shouldScroll) {
return checkWhenEnabled = true;
}
};
$window.on('scroll', handler);
scope.$on('$destroy', function () {
return $window.off('scroll', handler);
});
return $timeout((function () {
if (attrs.infiniteScrollImmediateCheck) {
if (scope.$eval(attrs.infiniteScrollImmediateCheck)) {
return handler();
}
} else {
return handler();
}
}), 0);
}
};
}
])
app.filter('cleanurl', function () {
return function (url) {
return url.replace(/(^\w+:|^)\/\//, '');
};
});
app.filter('mstotime', function () {
return function (bytes) {
return (bytes > 1000) ? Math.round(bytes / 10) / 100 + 's' : Math.round(bytes) + 'ms';
};
});
app.filter('filename', function () {
return function (url) {
url = url.split(/[?#]/)[0].replace(/\/$/, "");
return url.substring(url.lastIndexOf('/') + 1)
};
});
app.directive('ngGauge', gaugeMeterDirective)
.provider('ngGauge', gaugeMeterProviderFn);
gaugeMeterProviderFn.$inject = [];
function gaugeMeterProviderFn() {
var defaultOptions = {
size: 200,
value: undefined,
min: 0,
max: 100,
cap: 'butt',
thick: 6,
type: 'full',
foregroundColor: 'rgba(0, 150, 136, 1)',
backgroundColor: 'rgba(0, 0, 0, 0.1)',
duration: 1500,
fractionSize: null,
labelOnly: false,
};
this.setOptions = function (customOptions) {
if (!(customOptions && angular.isObject(customOptions)))
throw new Error('Invalid option type specified in the ngGaugeProvider');
defaultOptions = angular.merge(defaultOptions, customOptions);
};
var ngGauge = {
getOptions: function () {
return angular.extend({}, defaultOptions);
}
};
this.$get = function () {
return ngGauge;
};
}
gaugeMeterDirective.$inject = ['ngGauge'];
function gaugeMeterDirective(ngGauge) {
var tpl = '
' +
'{{prepend}}' +
'{{value | number}}' +
'{{value | number: fractionSize}}' +
'{{append}}' +
'{{ label }}' +
'
';
var Gauge = function (element, options) {
this.element = element.find('canvas')[0];
this.text = element.find('span');
this.legend = element.find('b');
this.unit = element.find('u');
this.context = this.element.getContext('2d');
this.options = options;
this.init();
};
Gauge.prototype = {
init: function () {
this.setupStyles();
this.create(null, null);
},
setupStyles: function () {
this.context.canvas.width = this.options.size;
this.context.canvas.height = this.options.size;
this.context.lineCap = this.options.cap;
this.context.lineWidth = this.options.thick;
var lfs = this.options.size * 0.30,
llh = this.options.size;
this.text.css({
display: 'inline-block',
fontWeight: 'normal',
width: '100%',
position: 'absolute',
textAlign: 'center',
overflow: 'hidden',
textOverflow: 'ellipsis',
fontSize: lfs + 'px',
lineHeight: llh + 'px'
});
this.unit.css({
textDecoration: 'none',
fontSize: '0.6em',
fontWeight: 200,
opacity: 0.8
});
var fs = this.options.labelOnly ? lfs * 0.8 : this.options.size / 13;
var lh = this.options.labelOnly ? llh : (5 * fs) + parseInt(this.options.size);
this.legend.css({
display: 'inline-block',
width: '100%',
position: 'absolute',
textAlign: 'center',
overflow: 'hidden',
textOverflow: 'ellipsis',
fontWeight: 'normal',
fontSize: fs + 'px',
lineHeight: lh + 'px'
});
},
create: function (nv, ov) {
var self = this,
type = this.getType(),
bounds = this.getBounds(type),
duration = this.getDuration(),
min = this.getMin(),
max = this.getMax(),
value = this.clamp(this.getValue(), min, max),
start = bounds.head,
unit = (bounds.tail - bounds.head) / (max - min),
displacement = unit * (value - min),
tail = bounds.tail,
color = this.getForegroundColorByRange(value),
requestID,
startTime;
if (nv && ov) {
displacement = unit * nv - unit * ov;
}
function animate(timestamp) {
timestamp = timestamp || new Date().getTime();
var runtime = timestamp - startTime;
var progress = Math.min(runtime / duration, 1); // never exceed 100%
var previousProgress = ov ? (ov * unit) : 0;
var middle = start + previousProgress + displacement * progress;
self.drawShell(start, middle, tail, color);
if (runtime < duration) {
requestID = window.requestAnimationFrame(function (timestamp) {
animate(timestamp);
});
} else {
cancelAnimationFrame(requestID);
}
}
requestAnimationFrame(function (timestamp) {
startTime = timestamp || new Date().getTime();
animate(timestamp);
});
},
getBounds: function (type) {
var head, tail;
if (type == 'semi') {
head = Math.PI;
tail = 2 * Math.PI;
} else if (type == 'full') {
head = 1.5 * Math.PI;
tail = 3.5 * Math.PI;
} else if (type === 'arch') {
head = 0.8 * Math.PI;
tail = 2.2 * Math.PI;
}
return {
head: head,
tail: tail
};
},
drawShell: function (start, middle, tail, color) {
var
context = this.context,
center = this.getCenter(),
radius = this.getRadius(),
foregroundColor = color,
backgroundColor = this.getBackgroundColor();
this.clear();
middle = Math.max(middle, start); // never below 0%
middle = Math.min(middle, tail); // never exceed 100%
context.beginPath();
context.strokeStyle = backgroundColor;
context.arc(center.x, center.y, radius, middle, tail, false);
context.stroke();
context.beginPath();
context.strokeStyle = foregroundColor;
context.arc(center.x, center.y, radius, start, middle, false);
context.stroke();
},
clear: function () {
this.context.clearRect(0, 0, this.getWidth(), this.getHeight());
},
update: function (nv, ov) {
this.create(nv, ov);
},
destroy: function () {
this.clear();
},
getRadius: function () {
var center = this.getCenter();
return center.x - this.getThickness();
},
getCenter: function () {
var x = this.getWidth() / 2,
y = this.getHeight() / 2;
return {
x: x,
y: y
};
},
getValue: function () {
return this.options.value;
},
getMin: function () {
return this.options.min;
},
getMax: function () {
return this.options.max;
},
getWidth: function () {
return this.context.canvas.width;
},
getHeight: function () {
return this.context.canvas.height;
},
getThickness: function () {
return this.options.thick;
},
getBackgroundColor: function () {
return this.options.backgroundColor;
},
getForegroundColor: function () {
return this.options.foregroundColor;
},
getForegroundColorByRange: function (value) {
var isNumber = function (value) {
return value != undefined && !isNaN(parseFloat(value)) && !isNaN(Number(value));
};
var match = Object.keys(this.options.thresholds)
.filter(function (item) { return isNumber(item) && Number(item) <= value; })
.sort(function (a, b) { return Number(a) > Number(b); }).reverse()[0];
return match !== undefined ? this.options.thresholds[match].color || this.getForegroundColor() : this.getForegroundColor();
},
getLineCap: function () {
return this.options.cap;
},
getType: function () {
return this.options.type;
},
getDuration: function () {
return this.options.duration;
},
clamp: function (value, min, max) {
return Math.max(min, Math.min(max, value));
}
};
return {
restrict: 'E',
replace: true,
template: tpl,
scope: {
append: '@?',
backgroundColor: '@?',
cap: '@?',
foregroundColor: '@?',
label: '@?',
labelOnly: '@?',
prepend: '@?',
size: '@?',
thick: '@?',
type: '@?',
duration: '@?',
value: '=?',
min: '=?',
max: '=?',
thresholds: '=?',
fractionSize: '=?'
},
link: function (scope, element) {
var defaults = ngGauge.getOptions(); // fetching default settings from provider
scope.min = angular.isDefined(scope.min) ? scope.min : defaults.min;
scope.max = angular.isDefined(scope.max) ? scope.max : defaults.max;
scope.value = angular.isDefined(scope.value) ? scope.value : defaults.value;
scope.size = angular.isDefined(scope.size) ? scope.size : defaults.size;
scope.cap = angular.isDefined(scope.cap) ? scope.cap : defaults.cap;
scope.thick = angular.isDefined(scope.thick) ? scope.thick : defaults.thick;
scope.type = angular.isDefined(scope.type) ? scope.type : defaults.type;
scope.duration = angular.isDefined(scope.duration) ? scope.duration : defaults.duration;
scope.labelOnly = angular.isDefined(scope.labelOnly) ? scope.labelOnly : defaults.labelOnly;
scope.foregroundColor = angular.isDefined(scope.foregroundColor) ? scope.foregroundColor : defaults.foregroundColor;
scope.backgroundColor = angular.isDefined(scope.backgroundColor) ? scope.backgroundColor : defaults.backgroundColor;
scope.thresholds = angular.isDefined(scope.thresholds) ? scope.thresholds : {};
scope.fractionSize = angular.isDefined(scope.fractionSize) ? scope.fractionSize : defaults.fractionSize;
var gauge = new Gauge(element, scope);
scope.$watch('value', watchData, false);
scope.$watch('min', watchData, false);
scope.$watch('max', watchData, false);
scope.$watch('cap', watchOther, false);
scope.$watch('thick', watchOther, false);
scope.$watch('type', watchOther, false);
scope.$watch('size', watchOther, false);
scope.$watch('duration', watchOther, false);
scope.$watch('foregroundColor', watchOther, false);
scope.$watch('backgroundColor', watchOther, false);
scope.$watch('thresholds', watchOther, false);
scope.$watch('fractionSize', watchData, false);
scope.$on('$destroy', function () { });
scope.$on('$resize', function () { });
function watchData(nv, ov) {
if (!gauge) return;
if (!angular.isDefined(nv) || angular.equals(nv, ov)) return;
gauge.update(nv, ov);
}
function watchOther(nv, ov) {
if (!angular.isDefined(nv) || angular.equals(nv, ov)) return;
gauge.destroy();
gauge.init();
}
}
};
}
// oude /hub/v1/-adressen naar de pagina die ze vervangt
function hubRedirect(p) {
return {llmtraffic: '/ai-insights/verkeer', aioverview: '/ai-insights', keywordperformance: '/search-insights/gevolgd'}[p.view] || '/search-insights';
}
app.config(['$routeProvider', '$locationProvider', 'USER', '$sceProvider', '$translateProvider', function AppConfig($routeProvider, $locationProvider, USER, $sceProvider, $translateProvider) {
angular.lowercase = angular.$$lowercase;
$translateProvider.useStaticFilesLoader({
prefix: '/translations/',
suffix: '.json?r=' + Math.random()
});
/* ZET */
$translateProvider.preferredLanguage(USER.site.locale.lang);
$translateProvider.useSanitizeValueStrategy('sce');
$sceProvider.enabled(false);
$routeProvider
.when('/', {
title: 'APP',
templateUrl: viewfolder + '/home/index.html?r=' + r,
nav: 'dashboard'
})
/* help*/
.when('/help', {
title: 'Help',
templateUrl: viewfolder + '/help/index.html?r=' + r,
nav: 'help'
})
/* uptime-monitor */
.when('/uptime', {
title: 'Uptime',
templateUrl: viewfolder + '/uptime/index.html?r=' + r,
nav: 'uptime'
})
/* Posities in Google (SERP-tracker): overzicht, /serp/keywords en /serp/competitors; zichtbaar via user.site.show.serp */
.when('/serp', {
title: 'Rank tracker',
templateUrl: viewfolder + '/serp/index.html?r=' + r,
nav: 'serp'
})
/* Search Console Insights: overzicht, /onderwerpen(/:id), /gevolgd, /verkennen; zichtbaar via user.site.show.gscinsights (js/controller/gscinsights.js) */
.when('/search-insights', {
title: 'Search Insights',
templateUrl: viewfolder + '/gscinsights/index.html?r=' + r,
nav: 'gscinsights'
})
.when('/search-insights/:tab', {
title: 'Search Insights',
templateUrl: viewfolder + '/gscinsights/index.html?r=' + r,
nav: 'gscinsights',
reloadOnSearch: false
})
.when('/search-insights/:tab/:id', {
title: 'Search Insights',
templateUrl: viewfolder + '/gscinsights/index.html?r=' + r,
nav: 'gscinsights'
})
.when('/ai-insights', {
title: 'AI Insights',
templateUrl: viewfolder + '/aiinsights/index.html?r=' + r,
nav: 'aiinsights'
})
.when('/ai-insights/:tab', {
title: 'AI Insights',
templateUrl: viewfolder + '/aiinsights/index.html?r=' + r,
nav: 'aiinsights'
})
.when('/ai-insights/:tab/:id', {
title: 'AI Insights',
templateUrl: viewfolder + '/aiinsights/index.html?r=' + r,
nav: 'aiinsights'
})
.when('/serp/:tab', {
title: 'Rank tracker',
templateUrl: viewfolder + '/serp/index.html?r=' + r,
nav: 'serp'
})
/* Core Web Vitals (CrUX): /crux, /crux/bezoekers, /crux/diagnose; zichtbaar via user.site.show.crux (gelanceerd 2026-10-29, standaard aan).
De oude tabs van v1 (In Google, Waarom trager) gaan naar hun opvolger; vóór /crux/:tab, de eerste match telt */
.when('/crux/zoekresultaten', { redirectTo: '/crux/bezoekers' })
.when('/crux/waarom', { redirectTo: '/crux/diagnose' })
.when('/crux', {
title: 'Core Web Vitals',
templateUrl: viewfolder + '/crux/index.html?r=' + r,
nav: 'crux'
})
.when('/crux/:tab', {
title: 'Core Web Vitals',
templateUrl: viewfolder + '/crux/index.html?r=' + r,
nav: 'crux'
})
/* contentcheck (verstopt, alleen eigen admins: contentcheck::allowed) */
.when('/content-intelligence/check', { title: 'Contentcheck', templateUrl: viewfolder + '/content/check.html?r=' + r, nav: 'content' })
.when('/content-intelligence/check/:id', { title: 'Contentcheck', templateUrl: viewfolder + '/content/check.html?r=' + r, nav: 'content' })
/* mcp server */
.when('/mcp', {
title: 'MCP Server',
templateUrl: viewfolder + '/mcp/index.html?r=' + r,
nav: 'mcp'
})
/* onpage seo*/
.when('/onpage-seo', {
title: 'ONPAGE',
templateUrl: viewfolder + '/onpage/index.status.html?r=' + r,
nav: 'onpage'
})
.when('/onpage-seo/scan/:pageid', {
title: 'ONPAGE SCAN',
templateUrl: viewfolder + '/onpage/scan.html?r=' + r,
nav: 'onpage',
controller: function ($scope, $routeParams) {
$scope.pageid = $routeParams.pageid;
},
})
.when('/onpage-seo/:viewrulelabel', {
title: 'ONPAGE',
templateUrl: viewfolder + '/onpage/index.status.html?r=' + r,
nav: 'onpage',
controller: function ($scope, $routeParams) {
$scope.viewrulelabel = $routeParams.viewrulelabel;
},
})
.when('/onpage-seo/:viewrulelabel/:viewrule', {
title: 'ONPAGE',
templateUrl: viewfolder + '/onpage/index.status.html?r=' + r,
nav: 'onpage',
controller: function ($scope, $routeParams) {
$scope.viewrulelabel = $routeParams.viewrulelabel;
$scope.viewrule = $routeParams.viewrule;
},
})
/* linkbuilding*/
.when('/content/', {
title: 'Content Intelligence',
templateUrl: viewfolder + '/content/index.html?r=' + r,
nav: 'content'
})
.when('/content/:modelid', {
title: 'Content Intelligence',
templateUrl: viewfolder + '/content/model.html?r=' + r,
nav: 'content',
controller: function ($scope, $routeParams) {
$scope.modelid = $routeParams.modelid;
},
})
/* linkbuilding*/
.when('/linkbuilding/assistant', {
title: 'Linkbuilding',
templateUrl: viewfolder + '/linkbuilding/assistant.html?r=' + r,
nav: 'linkbuilding'
})
.when('/linkbuilding/template', {
title: 'Linkbuilding',
templateUrl: viewfolder + '/linkbuilding/template.html?r=' + r,
nav: 'linkbuilding'
})
.when('/linkbuilding/wizzard', {
title: 'Linkbuilding',
templateUrl: viewfolder + '/linkbuilding/wizzard.html?r=' + r,
nav: 'linkbuilding'
})
.when('/linkbuilding/manager', {
title: 'Linkbuilding',
templateUrl: viewfolder + '/linkbuilding/manager.html?r=' + r,
nav: 'linkbuilding'
})
// LLM Visibility is opgegaan in AI Insights (2026-10-27)
.when('/llm-visibility', { redirectTo: '/ai-insights/antwoorden' })
/* reports*/
.when('/analytics/:report/:view', {
title: 'SITES',
templateUrl: viewfolder + '/api/analytics.html?r=' + r,
nav: 'analytics',
controller: function ($scope, $routeParams) {
$scope.urlreport = $routeParams.report;
$scope.urlview = $routeParams.view;
},
})
.when('/analytics4/:report/:view', {
title: 'SITES',
templateUrl: viewfolder + '/api/analytics4.html?r=' + r,
nav: 'analytics4',
controller: function ($scope, $routeParams) {
$scope.urlreport = $routeParams.report;
$scope.urlview = $routeParams.view;
},
})
.when('/matomo/:report/:view', {
title: 'SITES',
templateUrl: viewfolder + '/api/matomo.html?r=' + r,
nav: 'matomo',
controller: function ($scope, $routeParams) {
$scope.urlreport = $routeParams.report;
$scope.urlview = $routeParams.view;
},
})
/* de oude Search Console-pagina is Search Insights geworden (2026-10-27) */
.when('/searchconsole/:report/:view', { redirectTo: '/search-insights' })
.when('/searchconsole/:report/:view/:urlfilter', { redirectTo: '/search-insights' })
.when('/youtube/:report/:view', {
title: 'youtube',
templateUrl: viewfolder + '/api/youtube.html?r=' + r,
nav: 'tools',
controller: function ($scope, $routeParams) {
$scope.urlreport = $routeParams.report;
$scope.urlview = $routeParams.view;
},
})
// de Performance HUB is opgegaan in Search Insights en AI Insights (2026-10-27); een functie, anders zet
// Angular de routeparameters als ?report=...&view=... achter het nieuwe adres
.when('/hub/:report/:view', { redirectTo: hubRedirect })
.when('/hub/:report/:view/:urlfilter', { redirectTo: hubRedirect })
.when('/mailchimp/:report/:view', {
title: 'mailchimp',
templateUrl: viewfolder + '/api/mailchimp.html?r=' + r,
nav: 'tools',
controller: function ($scope, $routeParams) {
$scope.urlreport = $routeParams.report;
$scope.urlview = $routeParams.view;
},
})
.when('/mailchimp/:report/:view/:filter', {
title: 'mailchimp',
templateUrl: viewfolder + '/api/mailchimp.html?r=' + r,
nav: 'tools',
controller: function ($scope, $routeParams) {
$scope.urlreport = $routeParams.report;
$scope.urlview = $routeParams.view;
$scope.urlfilter = $routeParams.filter;
},
})
.when('/facebookads/:report/:view', {
title: 'facebookads',
templateUrl: viewfolder + '/api/facebookxads.html?r=' + r,
nav: 'ads',
controller: function ($scope, $routeParams) {
$scope.urlreport = $routeParams.report;
$scope.urlview = $routeParams.view;
},
})
.when('/facebookinsights/:report/:view', {
title: 'facebookinsights',
templateUrl: viewfolder + '/api/facebookinsights.html?r=' + r,
nav: 'tools',
controller: function ($scope, $routeParams) {
$scope.urlreport = $routeParams.report;
$scope.urlview = $routeParams.view;
},
})
.when('/instagram/:report/:view', {
title: 'instagram',
templateUrl: viewfolder + '/api/instagram.html?r=' + r,
nav: 'tools',
controller: function ($scope, $routeParams) {
$scope.urlreport = $routeParams.report;
$scope.urlview = $routeParams.view;
},
})
.when('/linkedin/:report/:view', {
title: 'linkedin',
templateUrl: viewfolder + '/api/linkedin.html?r=' + r,
nav: 'tools',
controller: function ($scope, $routeParams) {
$scope.urlreport = $routeParams.report;
$scope.urlview = $routeParams.view;
},
})
.when('/linkedinxads/:report/:view', {
title: 'linkedinxads',
templateUrl: viewfolder + '/api/linkedinxads.html?r=' + r,
nav: 'tools',
controller: function ($scope, $routeParams) {
$scope.urlreport = $routeParams.report;
$scope.urlview = $routeParams.view;
},
})
.when('/googleads/:report/:view', {
title: 'googleads',
templateUrl: viewfolder + '/api/googlexads.html?r=' + r,
nav: 'ads',
controller: function ($scope, $routeParams) {
$scope.urlreport = $routeParams.report;
$scope.urlview = $routeParams.view;
},
})
.when('/mybusiness/:report/:view', {
title: 'MYBUSINESS',
templateUrl: viewfolder + '/api/mybusiness.html?r=' + r,
nav: 'tools',
controller: function ($scope, $routeParams) {
$scope.urlreport = $routeParams.report;
$scope.urlview = $routeParams.view;
},
})
.when('/planning', {
title: 'planning',
templateUrl: viewfolder + '/planning/index.html?r=' + r,
nav: 'planning',
})
.when('/site', {
title: 'SITES',
templateUrl: viewfolder + '/site/index.html?r=' + r,
nav: 'sites',
})
.when('/site/upgrade/:orderstate', {
title: 'SITES',
templateUrl: viewfolder + '/site/upgrade.html?r=' + r,
nav: 'sites',
controller: function ($scope, $routeParams) {
$scope.orderstate = $routeParams.orderstate;
},
allowguest: true
})
.when('/site/upgrade', {
title: 'SITES',
templateUrl: viewfolder + '/site/upgrade.html?r=' + r,
nav: 'sites',
allowguest: true
})
.when('/sites', {
title: 'SITES',
templateUrl: viewfolder + '/sites/index.html?r=' + r,
nav: 'sites',
})
.when('/sites/new', {
title: 'Add a new site',
templateUrl: viewfolder + '/sites/first.html?r=' + r,
nav: 'sites',
})
.when('/rank-tracker', {
title: 'Rank Tracker',
templateUrl: viewfolder + '/rank-tracker/index.html?r=' + r,
nav: 'ranktracker',
})
.when('/rank-tracker/competitors', {
title: 'Rank Tracker - Competitors',
templateUrl: viewfolder + '/rank-tracker/competitors.html?r=' + r,
nav: 'ranktracker',
})
.when('/rank-tracker/insights', {
title: 'Rank Tracker - Insights',
templateUrl: viewfolder + '/rank-tracker/insights.html?r=' + r,
nav: 'ranktracker',
})
.when('/keywordtool', {
title: 'Rank Tracker',
templateUrl: viewfolder + '/keywordtool/index.html?r=' + r,
nav: 'keywordtool',
})
.when('/insights', {
title: 'Insights',
templateUrl: viewfolder + '/insights/index.html?r=' + r,
nav: 'insights',
})
.when('/insights/:report', {
title: 'Insights',
templateUrl: viewfolder + '/insights/index.html?r=' + r,
nav: 'tools',
controller: function ($scope, $routeParams) {
$scope.urlreport = $routeParams.report;
},
})
/*report*/
.when('/report', {
title: 'Report',
templateUrl: viewfolder + '/report/index.html?r=' + r,
nav: 'report',
})
.when('/report/:report_id', {
title: 'Report',
templateUrl: viewfolder + '/report/report.html?r=' + r,
nav: 'report',
controller: function ($scope, $routeParams) {
$scope.report_id = $routeParams.report_id;
},
})
.when('/reportpage/:key', {
title: 'Report',
templateUrl: viewfolder + '/report/page.html?r=' + r,
nav: 'report',
controller: function ($scope, $routeParams) {
$scope.key = $routeParams.key;
},
})
/* guest*/
.when('/sites/first', {
title: 'Add your first site',
templateUrl: viewfolder + '/sites/first.html?r=' + r,
nav: 'sites',
allowguest: true,
})
.when('/user/login', {
title: 'LOGIN',
allowguest: true,
nav: 'user',
class: 'fullscreen',
templateUrl: viewfolder + '/user/login.html?r=' + r,
})
.when('/user', {
title: 'USER',
nav: 'user',
templateUrl: viewfolder + '/user/index.html?r=' + r,
})
.when('/user/register', {
title: 'LOGIN',
nav: 'user',
class: 'fullscreen',
templateUrl: viewfolder + '/user/register.html?r=' + r,
allowguest: true,
})
.when('/user/recover', {
title: 'RECOVER PASSWORD',
templateUrl: viewfolder + '/user/recover.html?r=' + r,
nav: 'user',
class: 'fullscreen',
allowguest: true,
})
.when('/settings/reseller', {
title: 'RESELLER',
templateUrl: viewfolder + '/reseller/index.html?r=' + r,
nav: 'user',
allowguest: true,
})
.when('/settings/reseller/:tab', {
title: 'RESELLER',
templateUrl: viewfolder + '/reseller/index.html?r=' + r,
nav: 'user',
allowguest: true,
})
.when('/settings/site', {
title: 'RESELLER',
templateUrl: viewfolder + '/site/index.html?r=' + r,
nav: 'user',
allowguest: false,
})
.otherwise({
redirectTo: '/'
});
// enable html5Mode for pushstate ('#'-less URLs)
$locationProvider.html5Mode(true);
}]);
app.run(['$route', '$rootScope', '$location', '$window', 'USER', function ($route, $rootScope, $location, $window, USER) {
$rootScope.r = r;
$rootScope.user = USER;
//set menu state
$rootScope.app = {
body: { class: ['md-open', 'closed'] }
};
$rootScope.$on('$routeChangeSuccess', function (event, current, prev) {
$rootScope.app = {
body: { class: ['md-open', 'closed'] }
};
$rootScope.modal = {};
if (!$rootScope.user._id && !$route.current.allowguest) {
$location.path('/user/login');
} else if (!$rootScope.user.site._id && !$route.current.allowguest) {
$location.path('/sites/first');
} else if (!$route.current.allowguest && $rootScope.user.site._id && current.originalPath != '/site/upgrade' && $rootScope.user.site.status.expire - (Date.now() / 1000) < 0) {
//if ($rootScope.user.reseller.config.own) {
$location.path('/site/upgrade');
//}
}
// het menu (2026-10-29): de AI-crawlers staan onder AI Insights en de snelheid per pagina onder Snelheid, als die er zijn
var nav = $route.current.nav, label = ($route.current.params || {}).viewrulelabel, u = $rootScope.user || USER, show = (u.site && u.site.show) || {};
if (nav === 'onpage' && label === 'aibots' && show.aiinsights) { nav = 'aiinsights'; }
if (nav === 'onpage' && label === 'speed' && show.crux) { nav = 'crux'; }
$rootScope.app.meta = { nav: nav, class: $route.current.class, title: USER.reseller.config.name + ' - ' + $route.current.title, description: $route.current.description };
$rootScope.app.sitesdropdown = false;
});
}])
app.controller('core', ['$scope', '$rootScope', '$location', 'h', '$templateRequest', '$window', '$http', '$route', '$translate', '$http',
function($scope, $rootScope, $location, h, $templateRequest, $window, $http, $route, $translate, $http) {
$scope.fnToggleMenu = function() {
$rootScope.app.body.class = ($rootScope.app.body.class[0] == 'md-open') ? ['md-closed', 'open'] : ['md-open', 'closed'];
}
$scope.fnLogout = function() {
$http.post('/rest/user/logout').then(function successCallback(res) {
h.login(function() { $location.path('/user/login'); });
});
}
$scope.fnModal = function(url) {
$rootScope.modal = {};
$rootScope.modal.show = true;
$rootScope.modal.url = viewfolder+'/' + url + '.html';
}
$scope.fnCloseModal = function() {
$rootScope.modal = {};
}
$scope.fnClick = function(path) {
$location.path(path);
}
$scope.fnGoto = function(path) {
//$location.path(path);
$window.location.href = path;
}
$scope.fnSetLang = function(lang) {
$rootScope.user.site.locale.lang = lang;
$translate.use(lang);
$http.get('/rest/global/lang.set', {
params: {
'lang': lang,
}
});
}
$scope.fnChangeSite = function(site) {
$http.post('/rest/sites/change', { websiteid: site._id.$oid }).then(function successCallback(res) {
h.login(function() {
$rootScope._pages = false;
$rootScope._history = false;
if ($location.path() == '/site/upgrade') {
$scope.fnClick('/');
}
$route.reload();
});
});
}
// de lijst pas opbouwen bij de eerste klik; openen en sluiten doet Bootstrap zelf
// (omdraaien liep uit de pas met Bootstrap: na sluiten zonder keuze bleef de lijst leeg)
$scope.fnSitesDropdown = function(site) {
$rootScope.app.sitesdropdown = true;
}
$scope.fnDaysLeft = function() {
return Math.ceil(($rootScope.user.site.status.expire - (Date.now() / 1000)) / (24 * 60 * 60));
}
$scope.isValidSite = function() {
return ($rootScope.user.site.status.expire > (Date.now() / 1000)) ? true : false;
}
$scope.colors = ['#E91E63', '#3F51B5', '#00BCD4', '#8BC34A', '#FF9800', '#795548', '#607D8B', '#00CC00', '#0000CC', '#DDDDDD', '#999999', '#333333', '#990000']
$scope.fnPdf = function() {
console.log('asdasdasd');
var imgs = document.getElementsByTagName('canvas');
for (var i in imgs) {
if (typeof(imgs[i]) == 'object') {
var img = imgs[i].toDataURL("image/png");
var replace = document.createElement("img");
replace.src = img;
imgs[i].parentNode.replaceChild(replace, imgs[i]);
}
}
$http.post("/rest/report/page.download", {
html: angular.element('.reportcontainer').html()
}).then(function successCallback(res) {
$scope.fnGoto('https://robinssl.seoserver.nl/engels/page.php?website_id=' + h.siteId() + '&reseller_id=' + $scope.user.reseller._id.$oid + '&key=' + res.data.k)
/*$http.get('https://robinssl.seoserver.nl/engels/page.php', { 'params': { 'website_id': h.siteId(), 'reseller_id': $scope.user.reseller._id.$oid, 'key': res.data.k } }).then(function successCallback(pdf) {
var newBlob = new Blob([pdf.data], { type: "application/pdf" })
console.log(newBlob);
});*/
});
}
}
]);
// Dashboard (/): widgets per site in de stijl van de nieuwe pagina's (docs/ui.md). Iedereen deelt per site dezelfde
// indeling; rol 4 of lager mag hem aanpassen: slepen, breedte trekken aan de rechterrand, instellingen, weghalen, en
// widgets of een hele indeling kiezen in de widgetkiezer. Opslag en regels: rest/include/home.php en rest/data/home/.
// Arjen (2026-10-28): wie al een dashboard had, ziet dezelfde widgets op dezelfde plek; alleen nieuwe sites krijgen de
// nieuwe standaardindeling. Search Insights en AI Insights tekenen hun tegels en grafieken met dezelfde code als hun
// eigen pagina (gsciView, aiView).
app.controller('home', ['$scope', '$rootScope', '$http', '$translate', '$timeout', '$q', 'h', 'mtFmt', 'gsciView', 'aiView',
function($scope, $rootScope, $http, $translate, $timeout, $q, h, mtFmt, gsciView, aiView) {
if ($rootScope.user.firstrun) {
$scope.fnModal('home/modal.firstrun');
}
$scope.fnCloseFirstRun = function() {
$http.get('/rest/user/firstrun.set');
$rootScope.user.firstrun = false;
$scope.fnCloseModal();
}
// favoriet: de huidige site in user.sites (favorieten staan bovenaan in de siteswitcher)
var fnCurrentSite = function() {
return ($rootScope.user.sites || []).find(function(site) {
return site._id && site._id.$oid == h.siteId();
});
}
$scope.isFavorite = function() {
var site = fnCurrentSite();
return !!(site && site.favorite);
}
$scope.fnFavorite = function() {
var site = fnCurrentSite();
if (!site) {
return;
}
site.favorite = !site.favorite;
$http.post('/rest/sites/favorite', { websiteid: h.siteId(), favorite: site.favorite }).then(function successCallback(res) {
if (res.data.cb != 'ok') {
site.favorite = !site.favorite;
}
}, function errorCallback() {
site.favorite = !site.favorite;
});
}
var t = function (k, v) { return $translate.instant(k, v); };
var f = mtFmt;
var show = ($rootScope.user.site && $rootScope.user.site.show) || {};
var WIDTHS = [3, 4, 6, 8, 9, 12];
var MAX = 24;
var GA4_METRICS = ['sessions', 'totalUsers', 'screenPageViews', 'screenPageViewsPerSession', 'averageSessionDuration', 'newUsers', 'bounceRate', 'eventCount', 'eventCountPerUser'];
var ADS_METRICS = ['Clicks', 'Impressions', 'Cost', 'AverageCpc', 'Ctr', 'Conversions', 'CostPerConversion', 'ConversionRate', 'ConversionValue', 'SearchImpressionShare', 'SearchAbsoluteTopImpressionShare', 'roas'];
var GSC_METRICS = ['clicks', 'impressions', 'ctr', 'position'];
// Analytics 4 per kanaal (sessionDefaultChannelGroup; analytics4/report?channel=)
var GA4_CHANNELS = { organic: 'Organic Search', paid: 'Paid Search', direct: 'Direct', referral: 'Referral', social: 'Organic Social', email: 'Email' };
// gemiddelden tel je niet op: in de kop het gemiddelde in plaats van het totaal
var AVERAGES = ['screenPageViewsPerSession', 'averageSessionDuration', 'bounceRate', 'eventCountPerUser', 'AverageCpc', 'Ctr', 'CostPerConversion', 'ConversionRate', 'SearchImpressionShare', 'SearchAbsoluteTopImpressionShare', 'roas', 'ctr', 'position'];
var ICONS = {
all: 'M4 4h7v7H4zM13 4h7v7h-7zM4 13h7v7H4zM13 13h7v7h-7z',
gsc: 'M21 21l-4.3-4.3M11 18a7 7 0 1 1 0-14 7 7 0 0 1 0 14z',
ai: 'M21 12a8 8 0 0 1-11.6 7.1L4 20l1-4.6A8 8 0 1 1 21 12z',
seo: 'M9 11l3 3 8-8M20 12v7a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11',
rank: 'M4 20V10M10 20V4M16 20v-6M22 20H2',
up: 'M3 12h4l3-8 4 16 3-8h4',
ga: 'M4 20v-6M10 20V8M16 20v-9M22 20V4',
ads: 'M3 11l18-8-8 18-2-8z',
star: 'M12 3l2.8 5.7 6.2.9-4.5 4.4 1.1 6.2L12 17.3 6.4 20.2l1.1-6.2L3 9.6l6.2-.9z',
layout: 'M3 4h18v6H3zM3 14h8v6H3zM15 14h6v6h-6z'
};
// de groepen in de widgetkiezer, met de tool die in het menu moet staan
var CATS = [
{ key: 'all_tools', icon: ICONS.all, tool: null },
{ key: 'gscinsights', icon: ICONS.gsc, tool: 'gscinsights', href: '/search-insights' },
{ key: 'aiinsights', icon: ICONS.ai, tool: 'aiinsights', href: '/ai-insights' },
{ key: 'onpage', icon: ICONS.seo, tool: 'onpageseo', href: '/onpage-seo' },
{ key: 'serp', icon: ICONS.rank, tool: 'serp', href: '/serp' },
{ key: 'uptime', icon: ICONS.up, tool: 'uptime', href: '/uptime' },
{ key: 'analytics', icon: ICONS.ga, tool: 'analytics', href: '/analytics4/channels/all' },
{ key: 'googleads', icon: ICONS.ads, tool: 'googleads', href: '/googleads/campaigns/all' }
];
var CAT = {};
CATS.forEach(function (c) { CAT[c.key] = c; });
// alle widgets (zelfde lijst als homeWidgets::TYPES): groep, voorbeeldplaatje, standaardbreedte, instellingen
var WIDGETS = {
// De stand in één zin rekent met Search Insights: zonder die tool niet te kiezen
summary: { cat: 'all_tools', kind: 'sentence', span: 12, tip: true, needs: 'gscinsights' },
todo: { cat: 'all_tools', kind: 'list', span: 8, tip: true },
si_kpis: { cat: 'gscinsights', kind: 'kpis', span: 12, tip: true },
si_chart: { cat: 'gscinsights', kind: 'bars', span: 8, metrics: GSC_METRICS, metric: 'clicks', tip: true },
si_changes: { cat: 'gscinsights', kind: 'list', span: 4 },
si_kansen: { cat: 'gscinsights', kind: 'list', span: 6 },
searchinsights_tracked: { cat: 'gscinsights', kind: 'table', span: 6, more: '/search-insights/gevolgd' },
searchconsole_timeline: { cat: 'gscinsights', kind: 'line', span: 6, metrics: GSC_METRICS, metric: 'clicks', link: function () { return explore({ dim: 'date' }); } },
searchconsole_chart: { cat: 'gscinsights', kind: 'top', span: 6, metrics: GSC_METRICS, metric: 'clicks', dimensions: ['query', 'page', 'country', 'device'], dimension: 'query',
link: function (w) { return explore({ dim: w.dimension || 'query', sort: w.metric || 'clicks' }); } },
searchconsole_keywords: { cat: 'gscinsights', kind: 'table', span: 6, more: '/search-insights/verkennen' },
ai_kpis: { cat: 'aiinsights', kind: 'kpis', span: 12 },
ai_chart: { cat: 'aiinsights', kind: 'bars', span: 6, more: '/ai-insights/verkeer' },
onpage_seo: { cat: 'onpage', kind: 'kpis', span: 12 },
onpage_changes: { cat: 'onpage', kind: 'list', span: 6, more: '/onpage-seo/changes' },
onpage_changes_donut: { cat: 'onpage', kind: 'counts', span: 4, more: '/onpage-seo/changes' },
ranktracer: { cat: 'serp', kind: 'dist', span: 6, more: '/serp/keywords' },
uptime: { cat: 'uptime', kind: 'heat', span: 4 },
analytics4_timeline: { cat: 'analytics', kind: 'line', span: 4, metrics: GA4_METRICS, metric: 'sessions', filters: Object.keys(GA4_CHANNELS),
link: function (w) { return '/analytics4/channels/' + (GA4_VIEW[w.filter] || 'all') + '?' + qs({ metric: w.metric }); } },
googleads_timeline: { cat: 'googleads', kind: 'line', span: 6, metrics: ADS_METRICS, metric: 'Clicks', link: function (w) { return '/googleads/campaigns/all?' + qs({ metric: w.metric }); } },
googleads_performance_chart: { cat: 'googleads', kind: 'top', span: 6, metrics: ADS_METRICS, metric: 'Clicks', dimensions: ['CampaignName', 'AdGroupName', 'Query'], dimension: 'CampaignName',
link: function (w) { return '/googleads/campaigns/' + (w.dimension === 'AdGroupName' ? 'adgroups' : 'all') + '?' + qs({ metric: w.metric }); } },
googleads_conversion_chart: { cat: 'googleads', kind: 'top', span: 6, metrics: ['Conversions', 'CostPerConversion', 'ConversionRate', 'ConversionValue'], metric: 'Conversions', dimensions: ['ConversionTypeName'], dimension: 'ConversionTypeName',
link: function (w) { return '/googleads/campaigns/all?' + qs({ metric: w.metric }); } }
};
var offered = function (type) {
var w = WIDGETS[type], tool = w && (w.needs || CAT[w.cat].tool);
return !!w && (!tool || !!show[tool]);
};
var d = $scope.d = {
f: f, icons: ICONS, widgets: [], loaded: false, edit: false, compare: 'prev', hasCompare: false,
canEdit: ($rootScope.user.site && $rootScope.user.site.role <= 4), max: MAX,
picker: null, templates: [], canTemplates: false, confirm: null, form: null, drag: null, over: null, settings: null
};
// ------------------------------------------------------------------ gegevens
// elk adres één keer per bezoek: widgets die hetzelfde nodig hebben (De stand, Doe dit eerst, de tegels) delen het
var cache = {};
var get = function (url, params) {
var p = angular.extend({ websiteid: h.siteId() }, params || {});
var key = url + '|' + JSON.stringify(p);
if (!cache[key]) {
cache[key] = $http.get(url, { params: p }).then(function (res) { return res.data; }, function (res) { return { error: res.status === 403 ? 'no access' : 'failed' }; });
}
return cache[key];
};
var state = function (kind, extra) { return angular.extend({ state: kind }, extra || {}); };
var connect = function (cat) { return state('connect', { href: CAT[cat].href }); };
// Search Console: niet gekoppeld of geen property gekozen = koppelen; anders een fout.
// gscinsights/report zonder koppeling: action (getcustomer, of connect met voorbeelddata die we niet tonen)
var gscState = function (x) {
if (x && x.action) { return connect('gscinsights'); }
if (!x || !x.error) { return null; }
return x.error === 'not_connected' || x.error === 'no_property' ? connect('gscinsights') : state('error');
};
// pad zonder domein; de scan bewaart adressen met en zonder https://
var path = function (u) { return String(u || '').replace(/^(https?:\/\/)?[^\/]+/, '') || '/'; };
var countryName = function (cc) { try { return cc ? new Intl.DisplayNames([$translate.use() || 'nl'], { type: 'region' }).of(cc.toUpperCase()) : ''; } catch (e) { return cc; } };
var metricFmt = function (m) {
if (m === 'ctr' || m === 'bounceRate' || m === 'Ctr' || m === 'ConversionRate' || m === 'SearchImpressionShare' || m === 'SearchAbsoluteTopImpressionShare') { return function (v) { return f.pct(v); }; }
if (m === 'position') { return f.pos; }
if (m === 'Cost' || m === 'AverageCpc' || m === 'CostPerConversion' || m === 'ConversionValue') { return f.euro; }
if (m === 'screenPageViewsPerSession' || m === 'eventCountPerUser' || m === 'roas') { return function (v) { return f.num(v, 2); }; }
return function (v) { return f.num(v); };
};
// een reeks per dag (GA4, Google Ads, Search Console) als lijn, met het totaal of gemiddelde in de kop. Vandaag
// telt nog maar half (Arjen 2026-10-28: de lijn dook aan het eind omlaag) en valt weg.
var dayLine = function (rows, dateKey, metric, label) {
var iso = function (r) { var s = String(r[dateKey]); return s.length === 8 ? s.substr(0, 4) + '-' + s.substr(4, 2) + '-' + s.substr(6, 2) : s.substr(0, 10); };
var n = new Date(), today = n.getFullYear() + '-' + ('0' + (n.getMonth() + 1)).slice(-2) + '-' + ('0' + n.getDate()).slice(-2);
rows = (rows || []).filter(function (r) { return iso(r) < today; }).sort(function (a, b) { return iso(a) < iso(b) ? -1 : 1; });
var dates = rows.map(iso);
var values = rows.map(function (r) { var v = parseFloat(r[metric]); return isNaN(v) ? null : v; });
var sum = values.reduce(function (a, v) { return a + (v || 0); }, 0);
var fmt = metricFmt(metric);
return {
kind: 'line', fmt: fmt, invert: metric === 'position',
big: values.length ? fmt(AVERAGES.indexOf(metric) >= 0 ? sum / values.length : sum) : '–',
bigLabel: AVERAGES.indexOf(metric) >= 0 ? t('home.w.average') : t('home.w.total'),
chart: { labels: dates.map(function (x, i) { return i % 7 === 0 ? f.day(x) : ''; }), titles: dates.map(function (x) { return f.dayWeek(x); }), series: [{ label: label, color: '#2563eb', values: values, width: 2.5, strong: true }] }
};
};
// de grootste 8 per dimensie, met een balk naar verhouding
var topRows = function (rows, dim, metric, href, label) {
var fmt = metricFmt(metric);
rows = (rows || []).slice().sort(function (a, b) { return (parseFloat(b[metric]) || 0) - (parseFloat(a[metric]) || 0); }).slice(0, 8);
var max = rows.length ? Math.max.apply(null, rows.map(function (r) { return parseFloat(r[metric]) || 0; })) : 0;
return { kind: 'top', rows: rows.map(function (r) { var v = parseFloat(r[metric]) || 0; return { label: label(r), href: href ? href(r) : null, value: fmt(v), share: max ? 100 * v / max : 0 }; }) };
};
// deep links (Arjen 2026-10-28): elke tegel, rij en "Bekijken" opent de plek op de pagina van de tool waar het
// over gaat, met dezelfde metriek en hetzelfde filter. De pagina's lezen dit alleen bij het openen.
var qs = function (o) { return Object.keys(o).filter(function (k) { return o[k] !== null && o[k] !== undefined && o[k] !== ''; }).map(function (k) { return k + '=' + encodeURIComponent(o[k]); }).join('&'); };
var explore = function (o) { return '/search-insights/verkennen?' + qs(o); };
var GA4_VIEW = { organic: 'organic', paid: 'paid', direct: 'direct', referral: 'referral', social: 'social', email: 'email' };
var ONPAGE_VIEW = { all: 'all', content: 'content', technical: 'technical', mobile: 'mobile', indexability: 'indexability' };
var exploreRow = function (dim, r) {
if (dim === 'page') { return explore({ page: r.page, page_op: 'equals' }); }
if (dim === 'country') { return explore({ country: r.country }); }
if (dim === 'device') { return explore({ device: String(r.device || '').toLowerCase() }); }
return gsciView.exploreHref(r.query);
};
var LOAD = {
si_kpis: function (w) {
return get('/rest/gscinsights/overview', { part: 'kpis', compare: d.compare }).then(function (x) {
if (gscState(x)) { return gscState(x); }
// klikken, vertoningen, CTR, positie: Verkennen gesorteerd op die kolom; conversies of omzet: per pagina
return { kind: 'kpis', kpis: gsciView.kpis(x.totals.now, x.totals.before, x.ga4).map(function (k) {
k.href = !k.key ? null : (k.key === 'conversions' || k.key === 'revenue' ? explore({ dim: 'page', sort: k.key }) : explore({ sort: k.key }));
return k;
}) };
});
},
si_chart: function (w) {
return get('/rest/gscinsights/overview', { part: 'chart', compare: 'prev' }).then(function (x) {
if (gscState(x)) { return gscState(x); }
var c = gsciView.overviewChart(x, w.metric || 'clicks');
return { kind: c.chartKind === 'line' ? 'line' : 'bars', chart: c.chart, fmt: c.chartFmt, invert: c.chartInvert, title: c.chartTitle, sub: c.brandNote };
});
},
si_changes: function (w) {
return get('/rest/gscinsights/overview', { part: 'why', compare: d.compare }).then(function (x) {
if (gscState(x)) { return gscState(x); }
var why = gsciView.why(x.why);
if (!why.rows.length) { return state('empty', { text: t('home.w.no_changes') }); }
return { kind: 'list', sub: why.text, rows: why.rows.slice(0, 6).map(function (r) {
return { lead: (r.up ? '+' : '') + r.diff, leadCls: r.up ? 'text-green-600' : 'text-red-600', text: r.q, sub: r.why, href: r.href };
}) };
});
},
si_kansen: function (w) {
return get('/rest/gscinsights/overview', { part: 'actions', compare: 'prev' }).then(function (x) {
if (gscState(x)) { return gscState(x); }
if (!x.actions.length) { return state('empty', { text: t('home.w.no_chances') }); }
return { kind: 'list', rows: x.actions.slice(0, 6).map(function (a) {
return { badge: a.kind, text: gsciView.actionText(a), end: a.gain ? '+' + f.num(a.gain) + ' ' + t('home.w.clicks') : '', href: gsciView.exploreHref(a.query) };
}) };
});
},
searchinsights_tracked: function (w) {
return get('/rest/gscinsights/tracked').then(function (x) {
if (gscState(x)) { return gscState(x); }
var months = (x.months || []).map(function (m) { return f.monthLong(m); });
var rows = [];
(x.groups || []).forEach(function (g) { (g.keywords || []).forEach(function (k) { rows.push(k); }); });
if (!rows.length) { return state('empty', { text: t('gscinsights.intro.tracked'), href: '/search-insights/gevolgd', action: t('gscinsights.tracked.add') }); }
rows.sort(function (a, b) { return b.now.clicks - a.now.clicks; });
return { kind: 'tracked', months: months, rows: rows.slice(0, 8).map(function (k) {
return { q: k.query, href: gsciView.exploreHref(k.query), pos: f.pos(k.now.position), posDelta: k.year && k.year.position && k.now.position ? k.now.position - k.year.position : null,
clicks: f.num(k.now.clicks), change: k.change, spark: k.monthly_pos };
}) };
});
},
searchconsole_timeline: function (w) {
var m = w.metric || 'clicks';
return get('/rest/gscinsights/report', { dimension: 'date', end: 'TODAY', metrics: m, start: '30DAYSAGO', report: 'searchAnalytics' }).then(function (x) {
return gscState(x) || dayLine(x.data, 'date', m, t('gscinsights.kpi.' + m));
});
},
searchconsole_chart: function (w) {
var m = w.metric || 'clicks', dim = w.dimension || 'query';
return get('/rest/gscinsights/report', { dimension: dim, end: 'TODAY', metrics: m, start: '30DAYSAGO' }).then(function (x) {
return gscState(x) || topRows(x.data, dim, m, function (r) { return exploreRow(dim, r); }, function (r) {
if (dim === 'page') { return path(r.page); }
if (dim === 'country') { return countryName(r.cc) || String(r.country || '').toUpperCase(); }
if (dim === 'device') { return t('gscinsights.explore.device_name.' + r.device); }
return r[dim];
});
});
},
searchconsole_keywords: function (w) {
return get('/rest/gscinsights/report', { dimension: 'query', end: 'TODAY', metrics: 'clicks,ctr,position,impressions', start: '30DAYSAGO', report: 'searchAnalytics' }).then(function (x) {
if (gscState(x)) { return gscState(x); }
return { kind: 'keywords', rows: (x.data || []).slice(0, 10).map(function (r) {
return { q: r.query, href: gsciView.exploreHref(r.query), pos: f.pos(r.position), clicks: f.num(r.clicks), impressions: f.num(r.impressions), ctr: f.pct(r.ctr) };
}) };
});
},
ai_kpis: function (w) {
return get('/rest/aiinsights/overview', { part: 'kpis' }).then(function (x) {
if (x.error) { return state('error'); }
return { kind: 'kpis', kpis: aiView.kpis(x).map(function (k, i) { k.href = i < 2 ? '/ai-insights/antwoorden' : '/ai-insights/verkeer'; return k; }) };
});
},
ai_chart: function (w) {
return get('/rest/aiinsights/overview', { part: 'chart' }).then(function (x) {
if (x.error) { return state('error'); }
var c = aiView.chart(x);
return c ? { kind: 'bars', chart: c } : connect('analytics');
});
},
onpage_seo: function (w) {
return get('/rest/onpage/list').then(function (x) {
var hist = (x && x.history) || [];
if (!hist.length) { return state('empty', { text: t('home.w.no_scan') }); }
var last = hist[hist.length - 1], prev = hist.length > 1 ? hist[hist.length - 2] : null;
var tile = function (key, label) {
return { label: label, href: '/onpage-seo/' + ONPAGE_VIEW[key], value: f.pct(last[key] || 0, 0), delta: prev ? (last[key] || 0) - (prev[key] || 0) : null, unit: 'pt' };
};
var kpis = [tile('all', t('home.onpage.overallseo')), tile('content', t('home.onpage.contentseo')), tile('technical', t('home.onpage.technicalseo')),
tile('mobile', t('home.onpage.mobileseo')), tile('indexability', t('menu.onpage.indexability'))];
kpis[0].note = t('home.w.vs_prev_scan');
return { kind: 'kpis', kpis: kpis };
});
},
onpage_changes: function (w) {
return $q.all([get('/rest/onpage/rules', { lang: $rootScope.user.site.locale.lang }), get('/rest/onpage/changes')]).then(function (r) {
var rules = (r[0] && r[0].rules) || {}, list = ((r[1] && r[1].data) || []).filter(function (c) { return c.url; });
if (!list.length) { return state('empty', { text: t('home.changes.text_paragraph_no_changes') }); }
return { kind: 'list', rows: list.slice(0, 6).map(function (c) {
var rule = rules[c.rule] ? rules[c.rule].title : c.rule;
return { mark: c.r === true ? 'ok' : (c.r === false ? 'bad' : 'info'), text: path(c.url), sub: rule + (c.to ? ': ' + c.to : ''),
href: c.page_id && c.page_id.$oid ? '/onpage-seo/scan/' + c.page_id.$oid : null };
}) };
});
},
onpage_changes_donut: function (w) {
return get('/rest/onpage/changes').then(function (x) {
var n = { done: 0, issue: 0, change: 0 };
((x && x.data) || []).forEach(function (c) { n[c.r === true ? 'done' : (c.r === false ? 'issue' : 'change')]++; });
var total = n.done + n.issue + n.change;
if (!total) { return state('empty', { text: t('home.changes.text_paragraph_no_changes') }); }
return { kind: 'counts', total: total, items: [
{ label: t('home.w.count_issue'), href: '/onpage-seo/changes', n: n.issue, color: '#f59e0b', share: 100 * n.issue / total },
{ label: t('home.w.count_done'), href: '/onpage-seo/changes', n: n.done, color: '#16a34a', share: 100 * n.done / total },
{ label: t('home.w.count_change'), href: '/onpage-seo/changes', n: n.change, color: '#9ca3af', share: 100 * n.change / total }
] };
});
},
// Rank tracker: de posities uit de laatste meting, met het verschil met de meting daarvoor (zoals op /serp)
ranktracer: function (w) {
return get('/rest/serp/get').then(function (x) {
if (x.error) { return state('error'); }
if (x.trial) { return state('empty', { text: t('serp.trial_text') }); }
var last = function (r, before) {
for (var i = (before === undefined ? r.measured.length : before) - 1; i >= 0; i--) { if (r.measured[i]) { return i; } }
return -1;
};
var depth = x.depth || 20;
var rows = (x.keywords || []).map(function (r) {
var i = last(r), j = i < 0 ? -1 : last(r, i);
var pos = i < 0 ? undefined : r.series[i], prev = j < 0 ? undefined : r.series[j];
var rank = function (p) { return p === null ? depth + 1 : p; };
return { q: r.q, href: '/serp/keywords?' + qs({ q: r.q }), cc: r.cc, device: r.device, star: r.star, waiting: i < 0, pos: pos,
label: pos === undefined ? '' : (pos === null ? '> ' + depth : pos),
diff: pos === undefined || prev === undefined ? 0 : rank(prev) - rank(pos) };
});
if (!rows.length) { return state('empty', { text: t('serp.empty_text'), href: '/serp/keywords', action: t('serp.add') }); }
var measured = rows.filter(function (r) { return !r.waiting; });
rows.sort(function (a, b) {
var pa = a.waiting ? 1000 : (a.pos === null ? 999 : a.pos), pb = b.waiting ? 1000 : (b.pos === null ? 999 : b.pos);
return (b.star - a.star) || (pa - pb);
});
var count = function (lo, hi) { return measured.filter(function (r) { return r.pos && r.pos >= lo && r.pos <= hi; }).length; };
var dist = [
{ label: t('home.w.top3'), n: count(1, 3) }, { label: '4–10', n: count(4, 10) }, { label: '11–' + depth, n: count(11, depth) },
{ label: t('home.w.not_found'), n: measured.filter(function (r) { return r.pos === null; }).length, grey: true }
];
dist.forEach(function (x2) { x2.share = measured.length ? 100 * x2.n / measured.length : 0; });
return { kind: 'rank', total: rows.length, top10: count(1, 10), dist: dist, rows: rows.slice(0, 6) };
});
},
uptime: function (w) {
return get('/rest/uptime/get').then(function (x) {
if (x.error) { return state('error'); }
if (!x.enabled && !x.last_check_at) { return state('empty', { text: t('uptime.intro_text'), href: '/uptime', action: t('uptime.enable') }); }
var cls = { up: 'bg-green-500', warn: 'bg-amber-400', blocked: 'bg-amber-400', failing: 'bg-amber-400', down: 'bg-red-500' };
var pill = { up: 'bg-green-100 text-green-800', down: 'bg-red-100 text-red-800', pending: 'bg-gray-100 text-gray-700' };
return {
kind: 'uptime', stateText: t('uptime.state.' + x.state), stateCls: pill[x.state] || 'bg-amber-100 text-amber-800',
since: x.state === 'up' && x.up_since ? t('home.w.since', { date: f.day(x.up_since) }) : (x.state === 'down' && x.down_since ? t('home.w.since', { date: f.day(x.down_since) }) : ''),
bars: (x.bars || []).map(function (b) {
return { cls: cls[b.outcome] || 'bg-gray-200', title: f.dayWeek(b.at) + ' ' + new Date(b.at).getHours() + ':00' + (b.outcome ? ' · ' + t('uptime.state.' + b.outcome) : '') };
}),
first: x.bars && x.bars.length ? f.day(x.bars[0].at) : '',
up7: x.uptime_7d === null ? '–' : f.pct(x.uptime_7d, x.uptime_7d === 100 ? 0 : 2),
ttfb: x.ttfb_median_7d === null ? '–' : f.num(x.ttfb_median_7d) + ' ms',
cert: x.cert_expires ? f.day(x.cert_expires) : '–'
};
});
},
analytics4_timeline: function (w) {
var m = w.metric || 'sessions';
var p = { dimension: 'date', end: 'TODAY', metrics: m, start: '30DAYSAGO' };
if (GA4_CHANNELS[w.filter]) { p.channel = GA4_CHANNELS[w.filter]; }
return get('/rest/analytics4/report', p).then(function (x) {
if (x.action) { return connect('analytics'); }
return x.error ? state('error') : dayLine(x.data, 'date', m, t('metrics.' + m));
});
},
googleads_timeline: function (w) {
var m = w.metric || 'Clicks';
return get('/rest/googlexads/report', { dimension: 'Date', end: 'TODAY', metrics: m, start: '30DAYSAGO', report: 'ACCOUNT_PERFORMANCE_REPORT' }).then(function (x) {
if (x.action) { return connect('googleads'); }
return x.error ? state('error') : dayLine(x.data, 'Date', m, t('metrics.' + m));
});
},
googleads_performance_chart: function (w) {
var REPORT = { CampaignName: 'CAMPAIGN_PERFORMANCE_REPORT', AdGroupName: 'ADGROUP_PERFORMANCE_REPORT', Query: 'SEARCH_QUERY_PERFORMANCE_REPORT' };
var m = w.metric || 'Clicks', dim = w.dimension || 'CampaignName';
return get('/rest/googlexads/report', { dimension: dim, end: 'TODAY', metrics: m, start: '30DAYSAGO', report: REPORT[dim] || REPORT.CampaignName }).then(function (x) {
if (x.action) { return connect('googleads'); }
return x.error ? state('error') : topRows(x.data, dim, m, null, function (r) { return r[dim]; });
});
},
googleads_conversion_chart: function (w) {
var m = w.metric || 'Conversions';
return get('/rest/googlexads/report', { dimension: 'ConversionTypeName', end: 'TODAY', metrics: m, start: '30DAYSAGO', report: 'ACCOUNT_PERFORMANCE_REPORT' }).then(function (x) {
if (x.action) { return connect('googleads'); }
return x.error ? state('error') : topRows(x.data, 'ConversionTypeName', m, null, function (r) { return r.ConversionTypeName; });
});
},
// De stand in één zin: bezoek uit Google (en AI, als dat er is) tegenover de vorige periode, plus de grootste kans.
// AI kent alleen de vorige 28 dagen: tegenover vorig jaar telt alleen Google.
summary: function (w) {
var withAi = show.aiinsights && d.compare === 'prev';
return $q.all([
get('/rest/gscinsights/overview', { part: 'kpis', compare: d.compare }),
withAi ? get('/rest/aiinsights/overview', { part: 'kpis' }) : $q.when(null),
get('/rest/gscinsights/overview', { part: 'actions', compare: 'prev' })
]).then(function (r) {
if (gscState(r[0])) { return gscState(r[0]); }
var g = r[0].totals, ai = r[1] && !r[1].error && r[1].traffic ? r[1].traffic : null;
var now = g.now.clicks + (ai ? ai.now.sessions : 0);
var before = g.before ? g.before.clicks + (ai ? ai.before.sessions : 0) : null;
var ch = before ? 100 * (now - before) / before : null;
var chance = ((r[2] && r[2].actions) || []).filter(function (a) { return a.kind === 'chance'; })[0];
return {
kind: 'summary', href: '/search-insights',
lead: t(ai ? 'home.w.summary_both' : 'home.w.summary_google', { n: f.num(now) }),
change: ch === null ? '' : t(ch >= 0 ? 'home.w.summary_more' : 'home.w.summary_less', { pct: f.num(Math.abs(ch)) + '%' }),
up: ch !== null && ch >= 0,
vs: ch === null ? '' : t(d.compare === 'year' ? 'home.w.vs_year' : 'home.w.vs_prev'),
chance: chance ? t('home.w.summary_chance', { q: chance.query, gain: f.num(chance.gain) }) : '',
chanceHref: chance ? gsciView.exploreHref(chance.query) : null
};
});
},
// Doe dit eerst: storingen en nieuwe scanfouten bovenaan, dan de kansen uit Google op opbrengst, dan AI
todo: function (w) {
var none = $q.when(null);
return $q.all([
show.uptime ? get('/rest/uptime/get') : none,
show.onpageseo ? get('/rest/onpage/changes') : none,
show.gscinsights ? get('/rest/gscinsights/overview', { part: 'actions', compare: 'prev' }) : none,
show.aiinsights ? get('/rest/aiinsights/overview', { part: 'actions' }) : none
]).then(function (r) {
var items = [], weekAgo = Date.now() - 7 * 86400000;
if (r[0] && !r[0].error) {
(r[0].incidents || []).filter(function (i) { return i.outcome === 'down' && i.start >= weekAgo; }).slice(0, 1).forEach(function (i) {
var mins = Math.max(1, Math.round(((i.end || Date.now()) - i.start) / 60000));
items.push({ rank: 0, pill: t('home.w.pill_down'), pillCls: 'bg-red-100 text-red-800', tool: t('home.w.cat.uptime'), href: '/uptime',
text: t(i.end ? 'home.w.todo_down' : 'home.w.todo_down_now', { date: f.day(i.start), time: new Date(i.start).getHours() + ':' + ('0' + new Date(i.start).getMinutes()).slice(-2), dur: mins >= 60 ? f.num(mins / 60, 1) + ' ' + t('uptime.unit_hour') : mins + ' min' }) });
});
}
if (r[1] && r[1].data) {
var bad = r[1].data.filter(function (c) { return c.r === false; }).length;
if (bad) { items.push({ rank: 1, pill: t('home.w.pill_issues', { n: bad }), pillCls: 'bg-red-100 text-red-800', tool: t('home.w.cat.onpage'), href: '/onpage-seo/changes', text: t('home.w.todo_issues', { n: bad }) }); }
}
if (r[2] && !r[2].error && r[2].actions) {
r[2].actions.slice(0, 4).forEach(function (a) {
items.push({ rank: 2, gain: a.gain || 0, badge: a.kind, text: gsciView.actionText(a), end: a.gain ? '+' + f.num(a.gain) + ' ' + t('home.w.clicks') : '', tool: 'Search Insights', href: gsciView.exploreHref(a.query) });
});
}
if (r[3] && !r[3].error && r[3].actions) {
aiView.actions(r[3].actions).slice(0, 2).forEach(function (a) { items.push({ rank: 3, badge: a.kind, text: a.text, tool: 'AI Insights', href: a.href }); });
}
if (!items.length) { return state('empty', { text: t('home.w.todo_nothing') }); }
items.sort(function (a, b) { return (a.rank - b.rank) || ((b.gain || 0) - (a.gain || 0)); });
return { kind: 'list', rows: items.slice(0, 6) };
});
}
};
// titel, groep en link van een widget op het dashboard; v = wat er getekend wordt
var decorate = function (w) {
var def = WIDGETS[w.type], cat = CAT[def.cat];
w.cat = def.cat;
w.icon = cat.icon;
w.tool = t('home.w.cat.' + def.cat);
var mkey = w.type.indexOf('searchconsole') === 0 || w.type === 'si_chart' ? 'gscinsights.kpi.' : 'metrics.';
// de titel uit de widget zelf, met het kanaal erbij; een eigen titel (instellingen) gaat voor
w.autoTitle = t('home.w.title.' + w.type, { metric: w.metric ? t(mkey + w.metric) : '', dimension: w.dimension ? t('dimensions.' + w.dimension) : '' })
+ (w.filter && def.filters ? ' · ' + t('home.w.channel.' + w.filter) : '');
w.title = w.ownTitle || w.autoTitle;
w.more = (def.link ? def.link(w) : def.more) || cat.href || null;
w.hasSettings = true;
w.filterOpts = def.filters ? [{ key: null, label: t('home.w.channel.all') }].concat(def.filters.map(function (x) { return { key: x, label: t('home.w.channel.' + x) }; })) : null;
w.metricOpts = def.metrics ? def.metrics.map(function (m) { return { key: m, label: t(mkey + m) }; }) : null;
w.dimensionOpts = def.dimensions && def.dimensions.length > 1 ? def.dimensions.map(function (x) { return { key: x, label: t('dimensions.' + x) }; }) : null;
w.width = Math.round(100 * w.colspan / 12) + '%';
// vaste hoogte op de widget (zoals het oude dashboard): even hoog naast elkaar en niets verspringt bij het laden;
// een zin of een rij tegels houdt zijn eigen hoogte
w.fixed = def.kind !== 'sentence' && def.kind !== 'kpis';
return w;
};
var load = function (w) {
var mine = w.v = { state: 'loading' };
LOAD[w.type](w).then(function (v) {
if (w.v === mine) {
w.v = v;
if (v.title && !w.ownTitle) { w.title = v.title; }
}
}, function () { if (w.v === mine) { w.v = state('error'); } });
};
var setWidgets = function (list) {
d.widgets = (list || []).filter(function (x) { return offered(x.type); }).map(function (x) {
return decorate({ type: x.type, metric: x.metric || WIDGETS[x.type].metric || null, dimension: x.dimension || WIDGETS[x.type].dimension || null, chart: x.chart || null, colspan: x.colspan || 6,
filter: x.filter || null, ownTitle: x.title || '' });
});
d.hasCompare = d.widgets.some(function (w) { return w.type === 'si_kpis' || w.type === 'summary' || w.type === 'si_changes'; });
d.widgets.forEach(load);
};
$http.get('/rest/home/widgets.list', { params: { websiteid: h.siteId() } }).then(function (res) {
// niets te tonen van een eigen indeling (alleen tools die deze rol niet ziet): de standaard, zoals vroeger
var mine = (res.data || []).filter(function (x) { return offered(x.type); });
return mine.length || !(res.data || []).length ? res : $http.get('/rest/home/widgets.list', { params: { websiteid: h.siteId(), which: 'fallback' } });
}).then(function (res) {
$translate.onReady().then(function () {
setWidgets(res.data);
d.loaded = true;
});
});
d.setCompare = function (c) {
if (d.compare === c) { return; }
d.compare = c;
d.widgets.forEach(function (w) { if (w.type === 'si_kpis' || w.type === 'summary' || w.type === 'si_changes') { load(w); } });
};
// ------------------------------------------------------------------ bewaren
var saveTimer = null;
var save = function () {
if (!d.canEdit) { return; }
$timeout.cancel(saveTimer);
saveTimer = $timeout(function () {
$http.post('/rest/home/widgets.save', { websiteid: h.siteId(), widgets: cleanList() });
}, 400);
};
var cleanList = function () { return d.widgets.map(function (w) { return { type: w.type, metric: w.metric, dimension: w.dimension, chart: w.chart, colspan: w.colspan, filter: w.filter, title: w.ownTitle }; }); };
// ------------------------------------------------------------------ bewerken
d.toggleEdit = function () { d.edit = !d.edit; d.settings = null; d.confirm = null; };
d.remove = function (w) { d.widgets.splice(d.widgets.indexOf(w), 1); d.settings = null; save(); refreshPicker(); };
d.move = function (w, step) {
var i = d.widgets.indexOf(w), j = i + step;
if (j < 0 || j >= d.widgets.length) { return; }
d.widgets.splice(i, 1);
d.widgets.splice(j, 0, w);
save();
};
// slepen: de gesleepte widget komt vóór of na de widget waar je hem loslaat, naar de helft waar de muis is
// (links/rechts, bij een brede widget boven/onder); op een lege plek in het raster komt hij achteraan
d.dragStart = function (w) { d.drag = w; d.settings = null; };
d.dragOver = function (w, after) { d.over = w; d.after = after; };
d.dropOn = function (w) {
var from = d.drag, after = d.after;
d.drag = d.over = null;
if (!from || from === w) { return; }
d.widgets.splice(d.widgets.indexOf(from), 1);
d.widgets.splice(w ? d.widgets.indexOf(w) + (after ? 1 : 0) : d.widgets.length, 0, from);
save();
};
d.dragEnd = function () { d.drag = d.over = null; };
// breedte: de dichtstbijzijnde van 25, 33, 50, 67, 75 en 100%
d.setWidth = function (w, cols) {
var best = WIDTHS[0];
WIDTHS.forEach(function (x) { if (Math.abs(x - cols) < Math.abs(best - cols)) { best = x; } });
if (w.colspan !== best) { w.colspan = best; w.width = Math.round(100 * best / 12) + '%'; return true; }
return false;
};
d.widthDone = function () { save(); };
d.openSettings = function (w) { d.settings = d.settings === w ? null : w; };
d.changed = function (w) { decorate(w); load(w); save(); };
// eigen titel: alleen de kop verandert, de gegevens niet
d.retitle = function (w) { w.ownTitle = (w.ownTitle || '').slice(0, 60); w.title = w.ownTitle.trim() || w.autoTitle; save(); };
// ------------------------------------------------------------------ widgetkiezer
var refreshPicker = function () {
var p = d.picker;
if (!p) { return; }
var q = (p.q || '').toLowerCase().trim();
var on = {};
d.widgets.forEach(function (w) { on[w.type] = true; });
var types = Object.keys(WIDGETS).filter(offered);
p.cats = [{ key: 'tip', icon: ICONS.star }, { key: 'all', icon: ICONS.all }].concat(CATS.filter(function (c) { return !c.tool || show[c.tool]; }))
.concat([{ key: 'layouts', icon: ICONS.layout }]).map(function (c) {
var n = c.key === 'layouts' ? p.layouts.length : types.filter(function (x) { return c.key === 'all' || (c.key === 'tip' ? WIDGETS[x].tip : WIDGETS[x].cat === c.key); }).length;
return { key: c.key, icon: c.icon, label: t('home.w.cat.' + c.key), n: n };
});
p.showLayouts = p.cat === 'layouts' && !q;
p.full = d.widgets.length >= MAX;
p.cards = types.filter(function (x) {
var w = WIDGETS[x];
if (q) { return (t('home.w.name.' + x) + ' ' + t('home.w.desc.' + x) + ' ' + t('home.w.cat.' + w.cat)).toLowerCase().indexOf(q) >= 0; }
return p.cat === 'all' || (p.cat === 'tip' ? w.tip : w.cat === p.cat);
}).map(function (x) {
var w = WIDGETS[x];
return { type: x, kind: w.kind, name: t('home.w.name.' + x), desc: t('home.w.desc.' + x), tool: t('home.w.cat.' + w.cat), icon: CAT[w.cat].icon, size: Math.round(100 * w.span / 12) + '%', on: !!on[x] };
});
p.hint = q ? t('home.w.found', { n: p.cards.length, q: p.q }) : (p.showLayouts ? t('home.w.layouts_hint') : (p.cat === 'tip' ? t('home.w.tip_hint') : t('home.w.cards_hint')));
};
// een indeling als schets: een blokje per widget, zo breed als de widget
var sketch = function (list) { return list.filter(function (x) { return offered(x.type); }).map(function (x) { return x.colspan || 6; }); };
var loadLayouts = function () {
$q.all([
$http.get('/rest/home/widgets.list', { params: { websiteid: h.siteId(), which: 'default' } }),
$http.get('/rest/home/template.list', { params: { websiteid: h.siteId() } })
]).then(function (r) {
var tl = r[1].data || {};
d.canTemplates = !!tl.can_edit;
d.picker.layouts = [{ id: null, name: t('home.w.layout_default'), description: t('home.w.layout_default_desc'), widgets: r[0].data, blocks: sketch(r[0].data) }]
.concat((tl.templates || []).map(function (x) { return angular.extend(x, { own: true, blocks: sketch(x.widgets) }); }));
refreshPicker();
});
};
d.openPicker = function (cat) {
d.picker = { cat: cat || 'tip', q: '', layouts: [], cards: [], cats: [] };
d.confirm = null;
d.form = null;
refreshPicker();
loadLayouts();
};
d.closePicker = function () { d.picker = null; d.confirm = null; d.form = null; };
d.pickCat = function (key) { d.picker.cat = key; d.picker.q = ''; d.confirm = null; refreshPicker(); };
d.search = function () { refreshPicker(); };
d.add = function (card) {
if (card.on || d.widgets.length >= MAX) { return; }
var def = WIDGETS[card.type];
var w = decorate({ type: card.type, metric: def.metric || null, dimension: def.dimension || null, chart: null, colspan: def.span });
d.widgets.push(w);
d.hasCompare = d.hasCompare || w.type === 'si_kpis' || w.type === 'summary' || w.type === 'si_changes';
load(w);
save();
d.closePicker();
d.edit = true;
};
// een indeling vervangt de huidige: eerst bevestigen (in de kaart, geen venster van de browser)
d.useLayout = function (l) {
if (d.confirm !== l) { d.confirm = l; return; }
setWidgets(l.widgets);
save();
d.closePicker();
};
// indelingen van de white label: de huidige indeling bewaren, bijwerken of weghalen (rol 1-3 bij de reseller)
d.newTemplate = function () { d.form = { name: '', description: '' }; };
d.saveTemplate = function (l) {
var tpl = l ? { id: l.id, name: l.name, description: l.description, widgets: cleanList() } : { name: d.form.name, description: d.form.description, widgets: cleanList() };
$http.post('/rest/home/template.save', { websiteid: h.siteId(), template: tpl }).then(function () { d.form = null; loadLayouts(); });
};
d.deleteTemplate = function (l) {
if (d.confirm !== 'del' + l.id) { d.confirm = 'del' + l.id; return; }
$http.post('/rest/home/template.delete', { websiteid: h.siteId(), id: l.id }).then(function () { d.confirm = null; loadLayouts(); });
};
}
]);
// Dashboard: een widget verslepen (HTML5 slepen; op een telefoon de pijltjes in de werkbalk). home-drag="w"
app.directive('homeDrag', function () {
return {
link: function (scope, el, attrs) {
var d = scope.d, node = el[0];
scope.$watch('d.edit', function (on) { node.setAttribute('draggable', on ? 'true' : 'false'); });
el.on('dragstart', function (e) {
if (!d.edit) { return; }
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('text/plain', 'widget');
scope.$apply(function () { d.dragStart(scope.$eval(attrs.homeDrag)); });
});
el.on('dragover', function (e) {
if (!d.drag) { return; }
e.preventDefault();
e.stopPropagation();
e.dataTransfer.dropEffect = 'move';
var w = scope.$eval(attrs.homeDrag), r = node.getBoundingClientRect();
var after = w.colspan >= 9 ? e.clientY > r.top + r.height / 2 : e.clientX > r.left + r.width / 2;
if (d.over !== w || d.after !== after) { scope.$apply(function () { d.dragOver(w, after); }); }
});
el.on('drop', function (e) {
e.preventDefault();
e.stopPropagation();
scope.$apply(function () { d.dropOn(scope.$eval(attrs.homeDrag)); });
});
el.on('dragend', function () { scope.$apply(function () { d.dragEnd(); }); });
}
};
});
// Dashboard: loslaten op een lege plek in het raster zet de widget achteraan. home-drop-end
app.directive('homeDropEnd', function () {
return {
link: function (scope, el) {
var d = scope.d;
el.on('dragover', function (e) {
if (!d.drag) { return; }
e.preventDefault();
if (d.over) { scope.$apply(function () { d.over = null; }); }
});
el.on('drop', function (e) {
if (!d.drag) { return; }
e.preventDefault();
scope.$apply(function () { d.dropOn(null); });
});
}
};
});
// Dashboard: breedte kiezen door aan de rechterrand te trekken; klikt vast op 25/33/50/67/75/100%. home-resize="w"
app.directive('homeResize', function () {
return {
link: function (scope, el, attrs) {
var start = null;
el.on('pointerdown', function (e) {
var grid = el[0].closest('[data-home-grid]'), item = el[0].closest('[draggable]');
if (!grid) { return; }
e.preventDefault();
e.stopPropagation();
el[0].setPointerCapture(e.pointerId);
if (item) { item.setAttribute('draggable', 'false'); }
var w = scope.$eval(attrs.homeResize);
start = { x: e.clientX, cols: w.colspan, col: (grid.clientWidth + 24) / 12, item: item, w: w };
});
el.on('pointermove', function (e) {
if (!start) { return; }
var cols = start.cols + (e.clientX - start.x) / start.col;
if (scope.d.setWidth(start.w, cols)) { scope.$apply(); }
});
var end = function () {
if (!start) { return; }
if (start.item) { start.item.setAttribute('draggable', 'true'); }
start = null;
scope.$apply(function () { scope.d.widthDone(); });
};
el.on('pointerup', end);
el.on('pointercancel', end);
}
};
});
app.controller('help', ['$scope', '$timeout', '$http', '$rootScope', 'h',
function($scope, $timeout, $http, $rootScope, h) {
$http.get('https://www.marketingtracer.com/help/listjson', {
params: {
lang: $rootScope.user.site.locale.lang,
}
}).then(function successCallback(res) {
$scope.topics = res.data;
});
$scope.getText = function(_id, sub_id, subtopic) {
$http.get('https://www.marketingtracer.com/help/subtopicjson', {
params: {
lang: $rootScope.user.site.locale.lang,
_id: _id,
sub_id: sub_id,
}
}).then(function successCallback(res) {
subtopic.html = res.data;
});
}
var users = {
userList: function() {
$http.get('/rest/user/reseller.site.list', {
params: {
websiteid: h.siteId(),
}
}).then(function successCallback(res) {
$scope.users = res.data;
});
},
matchUser: function(UserId) {
for (var i in $scope.users) {
if ($scope.users[i]._id.$oid == UserId) {
return $scope.users[i].name;
}
}
return '';
}
}
}
]);
app.controller("ranktracker", [
"$scope",
"$timeout",
"$http",
"$rootScope",
"$filter",
"h",
function ($scope, $timeout, $http, $rootScope, $filter, h) {
$scope.rankings = [];
$scope.page = {
bFilterStar: false,
label: "",
lgchart: "",
labels: {},
filter: {},
sortType: "q",
collapse: {},
chartlg: false,
locale: $rootScope.user.site.locale,
fnChartLg: function (c) {
this.chartlg = this.chartlg == c ? false : c;
},
sortReverse: false,
fnSort: function (s) {
if ($scope.page.sortType == s) {
$scope.page.sortReverse = !$scope.page.sortReverse;
} else {
$scope.page.sortReverse = false;
}
$scope.page.sortType = s;
},
provider: "google",
};
$scope.fnCustomDate = {
init: function () {
var d = new Date();
d.setMonth(d.getMonth() - 1);
$scope.customdate = { start: d, end: new Date(), show: false };
},
set: function () {
$scope.customdate.show = false;
$rootScope.reportdates.start = Math.round($scope.customdate.start.getTime() / 1000);
$rootScope.reportdates.end = Math.round($scope.customdate.end.getTime() / 1000);
$rootScope.reportdates.description = "Custom";
$scope.getKeywords();
},
};
$scope.dateoptions = [
{ start: false, end: false, description: "All times" },
{ start: "TODAY", end: "TODAY", description: "Today" },
{ start: "YESTYERDAY", end: "YESTYERDAY", description: "Yesterday" },
{ start: "7DAYSAGO", end: "TODAY", description: "Past 7 days" },
{ start: "14DAYSAGO", end: "TODAY", description: "Past 14 days" },
{ start: "30DAYSAGO", end: "TODAY", description: "Past 30 days" },
{ start: "1YEARAGO", end: "TODAY", description: "Past year" },
{ start: "THISMONTH", end: "TODAY", description: "This month" },
{ start: "LASTMONTH", end: "TODAY", description: "Previous month" },
];
if (!$rootScope.reportdates) {
$rootScope.reportdates = { start: false, end: false, description: "All time" };
}
$scope.fnDateSelection = function (reportdates) {
$rootScope.reportdates.start = reportdates.start;
$rootScope.reportdates.end = reportdates.end;
$rootScope.reportdates.description = reportdates.description;
$scope.getKeywords();
$scope.getVisibility();
};
$scope.do = function (obj, method, param) {
if (obj == "fnSingle") {
fnSingle[method](param);
} else {
fnMultiple[method](param);
}
};
var fnSingle = {
getParams: function (ranking) {
return {
websiteid: h.siteId(),
ids: [ranking._id.$oid],
};
},
pre_options: function (ranking) {
ranking.pre_options = !ranking.pre_options;
if (ranking.pre_options) {
$http
.get("/rest/rank-tracker/history", {
params: {
websiteid: h.siteId(),
ranking_id: ranking._id.$oid,
provider: $scope.page.provider,
start: $rootScope.reportdates.start,
end: $rootScope.reportdates.end,
},
})
.then(function successCallback(res) {
var data = res.data;
});
}
},
options: function (ranking) {
$http
.post(
"/rest/rank-tracker/edit",
angular.extend(
{
"summary.google.start": ranking.summary.google.start,
"summary.googlemobile.start": ranking.summary.googlemobile.start,
"meta.label": ranking.meta.label,
url: ranking.url,
fields: ["summary.google.start", "summary.googlemobile.start", "meta.label", "url"],
},
fnSingle.getParams(ranking)
)
)
.then(function successCallback(res) {
$scope.getKeywords();
});
},
sanitize: function (ranking) {
$http.post("/rest/rank-tracker/sanitize", angular.extend({ "q": ranking.q }, fnSingle.getParams(ranking))).then(function successCallback(res) {
$scope.getKeywords();
});
},
delete: function (ranking) {
$http.post("/rest/rank-tracker/delete", fnSingle.getParams(ranking)).then(function successCallback(res) {
$scope.getKeywords();
});
},
star: function (ranking) {
$http.post("/rest/rank-tracker/edit", angular.extend({ "meta.star": !ranking.meta.star, fields: ["meta.star"] }, fnSingle.getParams(ranking))).then(function successCallback(res) {
$scope.getKeywords();
});
},
};
var fnMultiple = {
getParams: function (ranking) {
var ids = [];
for (var i in $scope.rankings) {
if ($scope.rankings[i].checked) {
ids.push($scope.rankings[i]._id.$oid);
}
}
return {
websiteid: h.siteId(),
ids: ids,
};
},
multioptions: function () {
$scope.page.multioptions = false;
for (var i in $scope.rankings) {
if ($scope.rankings[i].checked) {
$scope.page.multioptions = true;
break;
}
}
},
check: function (ranking) {
ranking.checked = !ranking.checked;
fnMultiple.multioptions();
},
checkall: function (label) {
$scope.page.labels[label] = !$scope.page.labels[label];
for (var i in $scope.rankings) {
if ($scope.rankings[i].meta.label == label) {
$scope.rankings[i].checked = $scope.page.labels[label];
}
}
fnMultiple.multioptions();
},
options: function (ranking) {
$http
.post(
"/rest/rank-tracker/edit",
angular.extend(
{
"meta.label": $scope.page.label,
fields: ["meta.label"],
},
fnMultiple.getParams(ranking)
)
)
.then(function successCallback(res) {
$scope.getKeywords();
});
},
delete: function (ranking) {
$http.post("/rest/rank-tracker/delete", fnMultiple.getParams(ranking)).then(function successCallback(res) {
$scope.getKeywords();
});
},
resetvolume: function (ranking) {
$http.post("/rest/rank-tracker/resetvolume", fnMultiple.getParams(ranking)).then(function successCallback(res) {
$scope.getKeywords();
});
},
export: function (ranking) {
$http.post("/rest/rank-tracker/export", fnMultiple.getParams(ranking)).then(function successCallback(res) {
var element = document.createElement("a");
element.setAttribute("href", "data:text/html;," + encodeURIComponent(res.data.csv));
element.setAttribute("download", "export.csv");
element.style.display = "none";
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
});
},
exportxls: function (ranking) {
$http.post("/rest/rank-tracker/exportxls", fnMultiple.getParams(ranking)).then(function successCallback(res) {
var element = document.createElement("a");
element.setAttribute("href", "data:text/html;," + encodeURIComponent(res.data.csv));
element.setAttribute("download", "export.xls");
element.style.display = "none";
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
});
},
};
// ranking grafiek'heschiedenis
$scope.fnRankingHistory = function (ranking, provider) {
if (ranking.active && $scope.page.provider == provider) {
ranking.active = false;
return;
}
$scope.page.provider = provider;
for (var x in $scope.rankings) {
$scope.rankings[x].active = false;
}
ranking.active = true;
$http
.get("/rest/rank-tracker/history", {
params: {
websiteid: h.siteId(),
ranking_id: ranking._id.$oid,
provider: $scope.page.provider,
start: $rootScope.reportdates.start,
end: $rootScope.reportdates.end,
},
})
.then(function successCallback(res) {
var data = res.data;
var graphs = [];
var _d = {};
var d = [];
let urlkeyexists = {};
for (var i in data) {
if (data[i]?.data?.length > 0 || typeof data[i]?.data === "object") {
if (data[i]?.data?.length === 0) {
// stupid array identifies as object!
} else {
console.log(data[i]?.data);
console.log(data[i]?.data?.length);
console.log(typeof data[i]?.data);
for (var y in data[i].data) {
_d[data[i].data[y].date] = _d[data[i].data[y].date] || { date: data[i].data[y].date };
_d[data[i].data[y].date][i] = data[i].data[y].pos;
}
graphs.push({
balloonText: data[i].url + "
position: [[value]]",
title: data[i].url,
bullet: "round",
bulletBorderAlpha: 1,
bulletColor: "#FFFFFF",
useLineColorForBulletBorder: true,
fillAlphas: 0,
lineThickness: 2,
lineAlpha: 1,
bulletSize: 7,
valueField: i,
connect: false,
});
}
}
}
for (var i in _d) {
d.push(_d[i]);
}
ranking.chart = {
data: d,
type: "serial",
theme: "light",
marginLeft: 0,
marginRight: 0,
marginTop: 10,
categoryField: "date",
rotate: false,
pathToImages: "vendor/amchart/images/",
dataDateFormat: "YYYYMMDD",
legend: {
position: "bottom",
enabled: true,
useGraphSettings: true,
},
categoryAxis: {
gridPosition: "start",
parseDates: true,
labelRotation: 45,
},
valueAxes: [
{
reversed: true,
position: "left",
axisAlpha: 0,
labelsEnabled: true,
minimum: 1,
},
],
graphs: graphs,
};
});
};
// haal alle sleutelwoorden op
$scope.getKeywords = function (a) {
// all active plans
$scope.urls = {};
var startDate = $scope.custominit ? $scope.custominit.start : $rootScope.reportdates.start;
$scope.page.bFilterStar = $scope.custominit ? $scope.custominit.bFilterStar : $scope.page.bFilterStar;
if ($scope.page.bFilterStar == true) {
$scope.page.filter.meta = { star: true };
}
$http
.get("/rest/rank-tracker/list", {
params: {
websiteid: h.siteId(),
start: startDate,
end: $rootScope.reportdates.end,
},
})
.then(function successCallback(res) {
$scope.page.rankinglength = res.data.length;
if ($scope.page.rankinglength === 0) {
//$scope.fnModal("rank-tracker/modal.addkeyword");
}
$scope.change = { nverlies: 0, nwinst: 0, nsame: 0, verlies: 0, winst: 0, totaal: 0, n: 0 };
$scope.pie = { top3: 0, top10: 0, top100: 0, overig: 0 };
$scope._rankings = angular.copy(res.data);
//$scope.rankings = res.data;
$scope.sortranking();
});
};
$scope.switchstar = function () {
if ($scope.page.filter.meta) {
delete $scope.page.filter.meta;
} else {
$scope.page.filter.meta = { star: true };
}
$scope.sortranking();
};
$scope.sortranking = function () {
$scope.rankings = $filter("filter")($scope._rankings, $scope.page.filter);
if ($scope.rankings.length > 0) {
for (var i in $scope.rankings) {
if ($scope.rankings[i].active) {
var active = i;
}
}
}
var sorted = {};
// some stats
var totalenhancements = {};
for (var i in $scope.rankings) {
var ranking = $scope.rankings[i];
ranking.meta.label = ranking.meta.label || "--";
if (ranking?.url && ranking.url.indexOf("http") != 0) {
ranking.url = "https://" + ranking.url;
}
var tmpg = ranking?.summary?.google?.pos || 100;
var tmpgm = ranking?.summary?.googlemobile?.pos || 100;
ranking.summary = ranking?.summary || { google: { pos: tmpg }, googlemobile: { pos: tmpgm } };
//ranking.summary.google = ranking?.summary?.google || {pos:100}
//ranking.summary.googlemobile.pos = ranking.summary.googlemobile.pos || 100
if (active && i == active) {
$scope.fnRankingHistory(ranking, $scope.page.provider);
}
// kan weg
if (ranking.summary.google.pos < 4) {
++$scope.pie.top3;
} else if (ranking.summary.google.pos < 11) {
++$scope.pie.top10;
} else if (ranking.summary.google.pos < 100) {
++$scope.pie.top100;
} else {
++$scope.pie.overig;
}
//health
ranking.health = 100 - ((ranking.summary.google.worst - ranking.summary.google.pos + 0.5) / (ranking.summary.google.worst - ranking.summary.google.best)) * 100;
if (ranking.health > 100) {
ranking.health = 100;
}
sorted[ranking.meta.label] = sorted[ranking.meta.label] || [];
sorted[ranking.meta.label].push(ranking);
//change
if (ranking.summary.google.start > ranking.summary.google.pos) {
$scope.change.nwinst += 1;
$scope.change.winst += ranking.summary.google.start - ranking.summary.google.pos;
} else if (ranking.summary.google.start < ranking.summary.google.pos) {
$scope.change.nverlies += 1;
$scope.change.verlies += ranking.summary.google.pos - ranking.summary.google.start;
} else {
$scope.change.nsame += 1;
}
// enhancements
var enhancements = {};
if (typeof ranking.summary.google.enhancements == "object" && ranking.summary.google.enhancements != null) {
if (typeof ranking.summary.google.enhancements.other == "object") {
ranking.summary.google.enhancements.other = ranking.summary.google.enhancements.other || {};
ranking.summary.google.enhancements.other = Object.values(ranking.summary.google.enhancements.other);
}
if (typeof ranking.summary.google.enhancements.my == "object") {
ranking.summary.google.enhancements.my = ranking.summary.google.enhancements.my || {};
ranking.summary.google.enhancements.my = Object.values(ranking.summary.google.enhancements.my);
}
ranking.summary.google.enhancements.other = ranking.summary.google.enhancements.other || [];
ranking.summary.google.enhancements.my = ranking.summary.google.enhancements.my || [];
ranking.summary.google.enhancements.other.forEach(function (v, k) {
totalenhancements[v] = totalenhancements[v] || { v: v, my: 0, other: 0 };
totalenhancements[v].other += 1;
enhancements[v] = enhancements[v] || { v: v, my: 0, other: 0 };
enhancements[v].other += 1;
});
ranking.summary.google.enhancements.my.forEach(function (v, k) {
totalenhancements[v] = totalenhancements[v] || { v: v, my: 0, other: 0 };
totalenhancements[v].my += 1;
enhancements[v] = enhancements[v] || { v: v, my: 0, other: 0 };
enhancements[v].my += 1;
});
}
ranking.enhancements = Object.values(enhancements).sort(function (a, b) {
return a.v < b.v ? -1 : 1;
});
$scope.totalenhancements = Object.values(totalenhancements).sort(function (a, b) {
return a.v < b.v ? -1 : 1;
});
$scope.change.n += 1;
$scope.change.totaal += ranking.summary.google.start - ranking.summary.google.pos;
}
let sortedranking = [];
Object.keys(sorted).forEach(function (k) {
let _sorted = sorted[k];
sortedranking.push({ label: k, rankings: _sorted });
});
$scope.sortedranking = sortedranking;
};
$scope.charts = {};
$scope.changes = {};
var chart = {
small: {
type: "serial",
categoryField: "date",
dataDateFormat: "YYYYMMDD",
autoMargins: false,
categoryAxis: { parseDates: true, gridAlpha: 0, axisAlpha: 0 },
valueAxes: [{ gridAlpha: 0, axisAlpha: 0, color: "#FFFFFF", stackType: "regular" }],
},
large: {
type: "serial",
categoryField: "date",
dataDateFormat: "YYYYMMDD",
autoMargins: true,
categoryAxis: { gridPosition: "start", parseDates: true, gridThickness: 0 },
valueAxes: [{ position: "left", axisAlpha: 0, labelsEnabled: true, dashLength: 4, color: "#dedede", stackType: "regular" }],
},
visibility: function (data, type) {
$scope.charts.visibility = angular.extend({}, chart[type], {
data: data,
graphs: [
{
balloonText: "Visibility: [[value]]%",
fillAlphas: 0,
lineAlpha: 1,
bulletAlpha: 0.7,
valueField: "visibility",
lineColor: h.colors()[1],
},
],
});
$scope.charts.visibilitylg = angular.extend({}, chart["large"], {
data: data,
graphs: [
{
balloonText: "Visibility: [[value]]%",
lineAlpha: 1,
valueField: "visibility",
lineColor: h.colors()[1],
bullet: "round",
bulletBorderAlpha: 1,
bulletColor: "#FFFFFF",
useLineColorForBulletBorder: true,
fillAlphas: 0,
lineThickness: 2,
lineAlpha: 1,
bulletSize: 7,
},
],
});
$scope.changes.visibility = { cur: data[data.length - 1].visibility, start: data[0].visibility, dif: data[data.length - 1].visibility - data[0].visibility };
},
avgpos: function (data, type) {
var _data = data.reduce(function (acc, cur) {
if (cur.avg) {
acc.push(cur);
}
return acc;
}, []);
if (_data.length == 1) {
_data.unshift({ date: "20191031", avg: 0 });
}
$scope.charts.avgpos = angular.extend({}, chart[type], {
data: _data,
graphs: [
{
balloonText: "Avg position: [[value]]",
lineAlpha: 1,
valueField: "avg",
lineColor: h.colors()[3],
},
],
valueAxes: [{ gridAlpha: 0, axisAlpha: 0, color: "#FFFFFF", stackType: "regular", reversed: true }],
});
$scope.charts.avgposlg = angular.extend({}, chart["large"], {
data: _data,
graphs: [
{
balloonText: "Avg position: [[value]]",
valueField: "avg",
lineColor: h.colors()[3],
lineAlpha: 1,
bullet: "round",
bulletBorderAlpha: 1,
bulletColor: "#FFFFFF",
useLineColorForBulletBorder: true,
fillAlphas: 0,
lineThickness: 2,
lineAlpha: 1,
bulletSize: 7,
},
],
valueAxes: [{ gridAlpha: 0, axisAlpha: 0, color: "#FFFFFF", stackType: "regular", reversed: true }],
});
$scope.changes.avgpos = { cur: _data[_data.length - 1].avg, start: _data[0].avg, dif: (_data[_data.length - 1].avg - _data[0].avg) * -1 };
},
enhancement: function (data, type) {
var _data = data.reduce(function (acc, cur) {
if (cur.my_enh || cur.other_enh) {
acc.push(cur);
}
return acc;
}, []);
if (_data.length == 1) {
_data.unshift({ date: "20191031", my_enh: 0, other_enh: 0 });
}
$scope.charts.enhancement = angular.extend({}, chart[type], {
data: _data,
graphs: [
{
balloonText: "My enhancements: [[value]]",
fillAlphas: 0.6,
lineAlpha: 1,
valueField: "my_enh",
lineColor: h.colors()[4],
},
{
balloonText: "Total enhancements: [[value]]",
fillAlphas: 0.6,
lineAlpha: 1,
valueField: "other_enh",
lineColor: "#DDDDDD",
},
],
});
$scope.charts.enhancementlg = angular.extend({}, chart["large"], {
data: _data,
graphs: [
{
balloonText: "My enhancements: [[value]]",
bullet: "round",
lineAlpha: 1,
bullet: "round",
bulletBorderAlpha: 1,
bulletColor: "#FFFFFF",
useLineColorForBulletBorder: true,
fillAlphas: 0.6,
lineThickness: 2,
lineAlpha: 1,
bulletSize: 7,
valueField: "my_enh",
lineColor: h.colors()[4],
},
{
balloonText: "Total enhancements: [[value]]",
bullet: "round",
lineAlpha: 1,
bullet: "round",
bulletBorderAlpha: 1,
bulletColor: "#FFFFFF",
useLineColorForBulletBorder: true,
fillAlphas: 0.6,
lineThickness: 2,
lineAlpha: 1,
bulletSize: 7,
valueField: "other_enh",
lineColor: "#DDDDDD",
},
],
});
$scope.changes.enhancement = { cur: _data[_data.length - 1]?.my_enh, start: _data[0]?.my_enh, dif: _data[_data.length - 1]?.my_enh - _data[0]?.my_enh };
},
top: function (data, type) {
var _data = data.reduce(function (acc, cur) {
if (cur.top3 || cur.top10 || cur.top50 || cur.top100 || cur.norank) {
acc.push(cur);
}
return acc;
}, []);
$scope.charts.top = angular.extend({}, chart[type], {
data: _data,
graphs: [
{ balloonText: "Not ranked: [[value]]", fillAlphas: 0.6, lineAlpha: 0.6, valueField: "norank", lineColor: "#DDDDDD" },
{ balloonText: "Top100: [[value]]", fillAlphas: 0.25, lineAlpha: 0.25, valueField: "top100", lineColor: h.colors()[2] },
{ balloonText: "Top50: [[value]]", fillAlphas: 0.45, lineAlpha: 0.45, valueField: "top50", lineColor: h.colors()[2] },
{ balloonText: "Top10: [[value]]", fillAlphas: 0.65, lineAlpha: 0.65, valueField: "top10", lineColor: h.colors()[2] },
{ balloonText: "Top3: [[value]]", fillAlphas: 0.85, lineAlpha: 0.85, valueField: "top3", lineColor: h.colors()[2] },
{ balloonText: "Top1: [[value]]", fillAlphas: 1, lineAlpha: 1, valueField: "top1", lineColor: h.colors()[2] },
],
});
$scope.changes.top = {
cur: _data[_data.length - 1],
start: _data[0],
dif: {
top1: _data[_data.length - 1].top1 - _data[0].top1 || 0,
top3: _data[_data.length - 1].top3 - _data[0].top3 || 0,
top10: _data[_data.length - 1].top10 - _data[0].top10 || 0,
top50: _data[_data.length - 1].top50 - _data[0].top50 || 0,
top100: _data[_data.length - 1].top100 - _data[0].top100 || 0,
norank: _data[_data.length - 1].norank - _data[0].norank || 0,
},
};
},
};
// haal alle sleutelwoorden op
$scope.getVisibility = function (a) {
$http
.get("/rest/rank-tracker/visibility", {
params: {
websiteid: h.siteId(),
start: $rootScope.reportdates.start,
end: $rootScope.reportdates.end,
},
})
.then(function successCallback(res) {
chart.avgpos(res.data, "small");
chart.visibility(res.data, "small");
chart.enhancement(res.data, "small");
chart.top(res.data, "small");
});
};
$scope.fnAddKeywords = function () {
$http
.post("/rest/rank-tracker/add", {
keywords: $scope.page.addkeywords,
locale: $scope.page.locale,
websiteid: h.siteId(),
})
.then(function successCallback(res) {
$scope.getKeywords();
$scope.fnCloseModal();
$scope.page.addkeywords = "";
});
};
$scope.getKeywords();
$scope.getVisibility();
$http.get("/rest/locale/language.list").then(function successCallback(res) {
$scope.languages = res.data;
});
$http.get("/rest/locale/country.list").then(function successCallback(res) {
$scope.countries = res.data;
});
$scope.fnSearchCity = function (q) {
$http.get("/rest/locale/city.list", { params: { q: q } }).then(function successCallback(res) {
$scope.cities = res.data;
});
};
$scope.setCity = function (city) {
$scope.page.locale.city = city.city;
$scope.page.locale.uule = city.uule;
$scope.cities = [];
};
},
]);
app.controller('ranktrackerinsights', ['$scope', '$timeout', '$http', '$rootScope', '$filter', 'h',
function($scope, $timeout, $http, $rootScope, $filter, h) {
$scope.rankings = [];
if($scope.custominit){
$scope.page = {'timeframe': '31d'};
$scope.mds = [
{ 'title': '31-day mean - position improvement', 'timeframe':'31d', 'start': 'r31d', 'end': 'r62d', 'dif': 's31dc', 'vol': 's31dvol', 'order': '-median.s31dc', 'lengthindex': '31dl', 'comp': 'gt' },
{ 'title': '31-day mean - position loss', 'timeframe':'31d', 'start': 'r31d', 'end': 'r62d', 'dif': 's31dc', 'vol': 's31dvol', 'order': 'median.s31dc', 'lengthindex': '31dw', 'comp': 'lt' },
];
} else {
$scope.page = {'timeframe': '3d'};
$scope.mds = [
{ 'title': '3-day mean - position improvement', 'timeframe':'3d', 'start': 'r3d', 'end': 'r6d', 'dif': 's3dc', 'vol': 's3dvol', 'order': '-median.s3dc', 'lengthindex': '3dw', 'comp': 'gt' },
{ 'title': '3-day mean - traffic improvement', 'timeframe':'3d', 'start': 'r3d', 'end': 'r6d', 'dif': 's3dc', 'vol': 's3dvol', 'order': '-median.s3dvol', 'lengthindex': '3dw', 'comp': 'gt' },
{ 'title': '3-day mean - position loss', 'timeframe':'3d', 'start': 'r3d', 'end': 'r6d', 'dif': 's3dc', 'vol': 's3dvol', 'order': 'median.s3dc', 'lengthindex': '3dl', 'comp': 'lt' },
{ 'title': '3-day mean - traffic loss', 'timeframe':'3d', 'start': 'r3d', 'end': 'r6d', 'dif': 's3dc', 'vol': 's3dvol', 'order': 'median.s3dvol', 'lengthindex': '3dl', 'comp': 'lt' },
{ 'title': '7-day mean - position improvement', 'timeframe':'7d', 'start': 'r7d', 'end': 'r14d', 'dif': 's7dc', 'vol': 's7dvol', 'order': '-median.s7dc', 'lengthindex': '7dw', 'comp': 'gt' },
{ 'title': '7-day mean - traffic improvement', 'timeframe':'7d', 'start': 'r7d', 'end': 'r14d', 'dif': 's7dc', 'vol': 's7dvol', 'order': '-median.s7dvol', 'lengthindex': '7dw', 'comp': 'gt' },
{ 'title': '7-day mean - position loss', 'timeframe':'7d', 'start': 'r7d', 'end': 'r14d', 'dif': 's7dc', 'vol': 's7dvol', 'order': 'median.s7dc', 'lengthindex': '7dl', 'comp': 'lt' },
{ 'title': '7-day mean - traffic loss', 'timeframe':'7d', 'start': 'r7d', 'end': 'r14d', 'dif': 's7dc', 'vol': 's7dvol', 'order': 'median.s7dvol', 'lengthindex': '7dl', 'comp': 'lt' },
{ 'title': '31-day mean - position improvement', 'timeframe':'31d', 'start': 'r31d', 'end': 'r62d', 'dif': 's31dc', 'vol': 's31dvol', 'order': '-median.s31dc', 'lengthindex': '31dl', 'comp': 'gt' },
{ 'title': '31-day mean - traffic improvement', 'timeframe':'31d', 'start': 'r31d', 'end': 'r62d', 'dif': 's31dc', 'vol': 's31dvol', 'order': '-median.s31dvol', 'lengthindex': '31dl', 'comp': 'gt' },
{ 'title': '31-day mean - position loss', 'timeframe':'31d', 'start': 'r31d', 'end': 'r62d', 'dif': 's31dc', 'vol': 's31dvol', 'order': 'median.s31dc', 'lengthindex': '31dw', 'comp': 'lt' },
{ 'title': '31-day mean - traffic loss', 'timeframe':'31d', 'start': 'r31d', 'end': 'r62d', 'dif': 's31dc', 'vol': 's31dvol', 'order': 'median.s31dvol', 'lengthindex': '31dw', 'comp': 'lt' },
];
}
$scope.exists = function(prop, comp) {
return function(item) {
return item.median.hasOwnProperty(prop) && (comp == 'lt') ? item.median[prop] < 0 : item.median[prop] > 0
}
}
var competitors = {
listinsights: function() {
$http.get("/rest/rank-tracker/median", {
params: {
websiteid: h.siteId(),
}
}).then(function successCallback(res) {
$scope.insights = res.data;
$scope.lengths = $scope.insights.reduce(function(acc, cur) {
if (cur.median.s3dc > 0) {
acc['3dw'] += 1;
} else if (cur.median.s3dc < 0) {
acc['3dl'] += 1;
}
if (cur.median.s7dc > 0) {
acc['7dw'] += 1;
} else if (cur.median.s7dc < 0) {
acc['7dl'] += 1;
}
if (cur.median.s7dc > 0) {
acc['31dw'] += 1;
} else if (cur.median.s31dc < 0) {
acc['31dl'] += 1;
}
return acc;
}, { '3dl': 0, '3dw': 0, '7dl': 0, '7dw': 0, '31dl': 0, '31dw': 0 })
});
},
}
competitors.listinsights();
// ranking grafiek'heschiedenis
$scope.fnRankingHistory = function(ranking, provider) {
if (ranking.active && $scope.page.provider == provider) {
ranking.active = false;
return;
}
$scope.page.provider = provider;
for (var x in $scope.rankings) {
$scope.rankings[x].active = false;
}
ranking.active = true;
$http.get("/rest/rank-tracker/history", {
params: {
websiteid: h.siteId(),
ranking_id: ranking._id.$oid,
provider: 'google',
}
}).then(function successCallback(res) {
var data = res.data;
var graphs = [];
var _d = {};
var d = [];
for (var i in data) {
for (var y in data[i].data) {
_d[data[i].data[y].date] = _d[data[i].data[y].date] || { 'date': data[i].data[y].date };
_d[data[i].data[y].date][i] = data[i].data[y].pos;
}
graphs.push({
balloonText: data[i].url + "
position: [[value]]",
"title": data[i].url,
"bullet": "round",
"bulletBorderAlpha": 1,
"bulletColor": "#FFFFFF",
"useLineColorForBulletBorder": true,
"fillAlphas": 0,
"lineThickness": 2,
"lineAlpha": 1,
"bulletSize": 7,
"valueField": i,
"connect": false,
})
}
for (var i in _d) {
d.push(_d[i]);
}
ranking.chart = {
data: d,
type: 'serial',
theme: 'light',
marginLeft: 0,
marginRight: 0,
marginTop: 10,
categoryField: 'date',
rotate: false,
pathToImages: 'vendor/amchart/images/',
dataDateFormat: 'YYYYMMDD',
legend: {
position: "bottom",
enabled: true,
"useGraphSettings": true,
},
categoryAxis: {
gridPosition: "start",
parseDates: true,
labelRotation: 45
},
valueAxes: [{
reversed: true,
position: "left",
axisAlpha: 0,
labelsEnabled: true,
minimum: 1,
}],
graphs: graphs,
}
});
}
// set competitors
$scope.fnAddCompetitors = function() {
$http.post('/rest/rank-tracker/competitors.edit', {
competitors: $scope.competitors,
websiteid: h.siteId()
}).then(function successCallback(res) {
competitors.listinsights();
competitors.listkeywords();
$scope.fnCloseModal();
});
}
}
]);
app.controller('ranktrackercompetitors', ['$scope', '$timeout', '$http', '$rootScope', '$filter', 'h',
function($scope, $timeout, $http, $rootScope, $filter, h) {
$scope.rankings = [];
$scope.blazak = {};
$scope.page = {
label: '',
labels: {},
table: {
'curpage': 0,
'itemsperpage': 14,
'offset': 0,
'filter': {},
'order': { 'k': 'url', 'r': false },
'fnOrder': function(k, b) {
this.order.r = (k == this.order.k) ? !this.order.r : b;
this.order.k = k;
},
fnSetOffset: function() {
this.offset = this.itemsperpage * (this.curpage - 1);
},
fnFilterProperty: function() {
var pages = angular.copy($rootScope._pages);
$scope.pages = $filter('filter')(pages, $scope.page.table.filter);
}
},
date: 'alltime',
dates: ['alltime', '4weeks', '4months', 'thismonth'],
tab: 'my',
provider: 'google'
}
$scope.do = function(obj, method, param) {
if (obj == 'fnSingle') {
fnSingle[method](param);
} else {
fnMultiple[method](param);
}
}
$scope.export = function () {
$http.post("/rest/rank-tracker/exportcompetitors", {
websiteid: h.siteId(),
}).then(function successCallback(res) {
var element = document.createElement("a");
element.setAttribute("href", "data:text/html;," + encodeURIComponent(res.data.csv));
element.setAttribute("download", "export.csv");
element.style.display = "none";
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
});
};
var competitors = {
listcompetitors: function() {
$http.get("/rest/rank-tracker/competitors.list", {
params: {
websiteid: h.siteId(),
}
}).then(function successCallback(res) {
$scope.competitors = res.data;
if ($scope.competitors.length === 0 && $rootScope.user.site.role < 6) {
$scope.fnModal('rank-tracker/modal.editcompetitors');
}
});
},
listkeywords: function() {
if ($scope.rankings.length > 0) {
for (var i in $scope.rankings) {
if ($scope.rankings[i].active) {
var active = i;
}
}
}
var sorted = {};
// all active plans
$scope.urls = {}
$http.get('/rest/rank-tracker/competitors.listkeywords', {
params: {
websiteid: h.siteId(),
}
}).then(function successCallback(res) {
$scope.page.rankinglength = res.data.length;
$scope.rankings = res.data;
// some stats
for (var i in $scope.rankings) {
var ranking = $scope.rankings[i];
ranking.summary.google.pos = ranking.summary.google.pos || 100
ranking.summary.googlemobile.pos = ranking.summary.googlemobile.pos || 100
sorted[ranking.meta.label] = sorted[ranking.meta.label] || [];
sorted[ranking.meta.label].push(ranking);
}
$scope.sortedranking = sorted;
});
}
}
competitors.listcompetitors();
competitors.listkeywords();
// ranking grafiek'heschiedenis
$scope.fnRankingHistory = function(ranking, provider) {
provider = 'google';
console.log(ranking);
if (ranking.active && $scope.page.provider == provider) {
ranking.active = false;
return;
}
$scope.page.provider = provider;
for (var x in $scope.rankings) {
$scope.rankings[x].active = false;
}
ranking.active = true;
$http.get("/rest/rank-tracker/competitors.history", {
params: {
websiteid: h.siteId(),
ranking_id: ranking._id.$oid,
provider: $scope.page.provider,
}
}).then(function successCallback(res) {
var data = res.data;
var graphs = [];
var _d = {};
var d = [];
for (var i in data) {
console.log(data[i]);
for (var y in data[i].data) {
_d[data[i].data[y].date] = _d[data[i].data[y].date] || { 'date': data[i].data[y].date };
_d[data[i].data[y].date][i] = data[i].data[y].pos;
}
graphs.push({
balloonText: data[i].url + "
position: [[value]]",
"title": data[i].url,
"bullet": "round",
"bulletBorderAlpha": 1,
"bulletColor": "#FFFFFF",
"useLineColorForBulletBorder": true,
"fillAlphas": 0,
"lineThickness": 2,
"lineAlpha": 1,
"bulletSize": 7,
"valueField": i,
"connect": false,
})
}
for (var i in _d) {
d.push(_d[i]);
}
ranking.chart = {
data: d,
type: 'serial',
theme: 'light',
marginLeft: 0,
marginRight: 0,
marginTop: 10,
fontFamily: 'Roboto',
categoryField: 'date',
rotate: false,
pathToImages: 'vendor/amchart/images/',
dataDateFormat: 'YYYYMMDD',
legend: {
position: "bottom",
enabled: true,
"useGraphSettings": true,
},
categoryAxis: {
gridPosition: "start",
parseDates: true,
labelRotation: 45
},
valueAxes: [{
reversed: true,
position: "left",
axisAlpha: 0,
labelsEnabled: true,
minimum: 1,
}],
graphs: graphs,
}
});
}
// set competitors
$scope.fnAddCompetitors = function() {
$http.post('/rest/rank-tracker/competitors.edit', {
competitors: $scope.competitors,
websiteid: h.siteId()
}).then(function successCallback(res) {
competitors.listcompetitors();
competitors.listkeywords();
$scope.fnCloseModal();
});
}
}
]);
app.controller('linkbuildingassistant', ['$scope', '$http', '$rootScope', '$window', '$filter', 'h',
function($scope, $http, $rootScope, $window, $filter, h) {
$scope.page = {
'quickselect': {},
'importtab': false,
'categories': [],
'tags': {},
'dates': [],
'kdates': {},
'newlink': { 'moz': { 'targetscope': 'page', 'n': '50' } },
'multiplelinks': {},
'filter': {},
table: {
'curpage': 0,
'itemsperpage': 100,
'offset': 0,
fnSetOffset: function() {
this.offset = this.itemsperpage * (this.curpage - 1);
},
}
}
/* months*/
var thismonth = new Date().getMonth() + 3;
for (var i = 0; i < 15; i++) {
var date = new Date(new Date().getFullYear(), thismonth, 0);
$scope.page.dates.push({ 'date': date });
$scope.page.kdates[date.toString()] = date;
thismonth = thismonth - 1;
}
// do
$scope.do = function(obj, method, param) {
if (obj == 'fnSingle') {
return fnSingle[method](param);
} else if (obj == 'fnWizzard') {
return fnWizzard[method](param);
} else if (obj == 'fnTemplates') {
return fnTemplates[method](param);
} else {
return fnMultiple[method](param);
}
}
// link
var fnLinks = {
list: function() {
$http.get("/rest/linkbuilding/link.list", {
params: {
websiteid: h.siteId(),
}
}).then(function successCallback(res) {
$scope.page.multioptions = false;
$scope.page.checkall = false;
for (var i in res.data) {
var date = new Date(res.data[i].date * 1);
res.data[i].monthstring = date.toLocaleString('default', { year: 'numeric', 'month': 'long' })
res.data[i].d = res.data[i].date*1;
res.data[i].date = $scope.page.kdates[date.toString()];
if (res.data[i].my.tag) {
$scope.page.tags[res.data[i].my.tag] = res.data[i].my.tag;
}
}
res.data = $filter('orderBy')(res.data, 'd', true)
$scope.links = res.data;
});
},
}
// categories
var fnCategories = {
list: function() {
if ($scope.categories) {
return;
}
$http.get('/rest/linkbuilding/manager.categories.list').then(function successCallback(res) {
$scope.categories = res.data;
});
}
}
// categories
var fnTemplates = {
list: function() {
$http.get('/rest/linkbuilding/template.list', {
params: {
'websiteid': h.siteId(),
}
}).then(function successCallback(res) {
$scope.mailTemplates = res.data;
});
},
'get_mails_by_key': function(key) {
for (var i in $scope.mailTemplates) {
if ($scope.mailTemplates[i].key == key) {
return $scope.mailTemplates[i].mails;
}
}
}
}
//wizzard
var fnWizzard = {
'moz-domain': function() {
$http.post("/rest/linkbuilding/wizzard.moz.domain",
angular.extend({ 'domain': $scope.page.mozdomain }, { websiteid: h.siteId() })
).then(function successCallback(res) {
fnLinks.list();
});
},
'add_url': function() {
$http.post("/rest/linkbuilding/link.add.url",
angular.extend($scope.page.newlink, { websiteid: h.siteId(), 'date': new Date(new Date().getFullYear(), new Date().getMonth() + 1, 0) })
).then(function successCallback(res) {
$scope.page.newlink = { 'moz': { 'targetscope': 'page', 'n': '50' } };
fnLinks.list();
});
},
'add_bulk': function() {
$http.post("/rest/linkbuilding/link.add.bulk",
angular.extend({ 'my': $scope.page.newlink.my, 'bulk': $scope.page.newlink.bulk, 'allowduplicates': $scope.page.newlink.allowduplicates }, { websiteid: h.siteId(), 'date': new Date(new Date().getFullYear(), new Date().getMonth() + 1, 0) })
).then(function successCallback(res) {
$scope.page.newlink = { 'moz': { 'targetscope': 'page', 'n': '50' } };
fnLinks.list();
});
},
'add_search': function() {
$http.post("/rest/linkbuilding/link.add.search",
angular.extend($scope.page.newlink, { websiteid: h.siteId(), 'date': new Date(new Date().getFullYear(), new Date().getMonth() + 1, 0) })
).then(function successCallback(res) {
$scope.page.newlink = { 'moz': { 'targetscope': 'page', 'n': '50' } };
fnLinks.list();
});
},
'add_moz': function() {
$http.post("/rest/linkbuilding/link.add.moz",
angular.extend($scope.page.newlink, { websiteid: h.siteId(), 'date': new Date(new Date().getFullYear(), new Date().getMonth() + 1, 0) })
).then(function successCallback(res) {
$scope.page.newlink = { 'moz': { 'targetscope': 'page', 'n': '50' } };
fnLinks.list();
});
},
'list_google_alerts': function() {
$http.get("/rest/linkbuilding/rss.list.google.alerts", {
params: {
websiteid: h.siteId(),
}
}).then(function successCallback(res) {
$scope.page.google_alerts = res.data;
});
},
'add_google_alerts': function() {
$http.post("/rest/linkbuilding/rss.add.google_alerts",
angular.extend({}, { 'alert': $scope.page.newlink.google_alerts }, { websiteid: h.siteId() })
).then(function successCallback(res) {
$scope.page.newlink = { 'moz': { 'targetscope': 'page', 'n': '50' } };
$scope.page.importtab = false;
fnLinks.list();
});
},
'remove_google_alert': function(alert) {
$http.post("/rest/linkbuilding/rss.remove.google.alerts",
angular.extend({}, { 'alert': alert }, { websiteid: h.siteId() })
).then(function successCallback(res) {
fnWizzard.list_google_alerts();
$scope.page.newlink = { 'moz': { 'targetscope': 'page', 'n': '50' } };
});
},
}
$scope.fnCopyText = function(text) {
var body = angular.element($window.document.body);
var textarea = angular.element('');
textarea.css({
position: 'fixed',
opacity: '0'
});
textarea.val(text);
body.append(textarea);
textarea[0].select();
try {
var successful = document.execCommand('copy');
if (!successful) throw successful;
} catch (err) {
}
textarea.remove();
}
// single link actions
var fnSingle = {
'getParams': function(link) {
return {
'websiteid': h.siteId(),
'ids': [link._id.$oid],
}
},
'pre_edit': function(link) {
fnCategories.list();
$scope.page.curlink = link;
$scope.fnModal('linkbuilding/modal/single-edit')
},
'edit': function(link) {
var fields = ['partner.url', 'my.status', 'my.url', 'my.anchor', 'date', 'text', 'trade.anchor', 'trade.url', 'partner.type', 'partner.domain.contactform', 'partner.domain.email', 'partner.domain.manager.email', 'partner.domain.manager.name', 'partner.domain.manager.CatId'];
$http.post("/rest/linkbuilding/link.edit",
angular.extend(link, fnSingle.getParams(link), { 'fields': fields })
).then(function successCallback(res) { fnLinks.list(); })
},
'pre_mail': function(link) {
if (!link.mail && $scope.mailTemplates[0] !== undefined) {
link.mail = { key: $scope.mailTemplates[0].key }
}
$scope.page.curlink = link;
$scope.fnModal('linkbuilding/modal/mail')
},
'mail': function(link) {
$http.post("/rest/linkbuilding/link.mail",
angular.extend(link, fnSingle.getParams(link))
).then(function successCallback(res) {
fnLinks.list();
})
},
'contactform': function(link) {
$scope.page.curlink = link;
$scope.page.curlink.mailtemplate = $scope.mailTemplates[$scope.mailTemplates.length - 1];
$scope.fnModal('linkbuilding/modal/contactform')
},
'getmailbody': function(link) {
var text = link.mailtemplate.mails[0].body;
// strip tags
text = text.replace(/(<([^>]+)>)/ig, "");
//replace
text = text.replace(/\[partner_link\]/g, link.partner.url);
text = text.replace(/\[partner_domain\]/g, link.partner.domain.domain);
console.log(text);
return text;
},
'checkstatus': function(link) {
link.inprogress = true;
$http.get("/rest/linkbuilding/link.checkstatus", {
'params': { websiteid: h.siteId(), '_id': link['_id']['$oid'] }
}).then(function successCallback(res) {
link.inprogress = false;
link.my = res.data.my
});
},
'delete': function(link) {
$http.post("/rest/linkbuilding/link.delete",
fnSingle.getParams(link)
).then(function successCallback(res) {
fnLinks.list();
});
}
}
// multiple link actions
var fnMultiple = {
getParams: function() {
var ids = [];
for (var i in $scope.links) {
if ($scope.links[i].checked) {
ids.push($scope.links[i]._id.$oid)
}
}
return {
'websiteid': h.siteId(),
'ids': ids,
}
},
multioptions: function() {
$scope.page.multioptions = false;
for (var i in $scope.links) {
if ($scope.links[i].checked) {
$scope.page.multioptions = true;
break
}
}
},
check: function(array) {
var event = array[0];
var link = array[1];
if (event.ctrlKey || event.shiftKey) {
var forceselect = false;
var _links = $filter('filter')($scope.links, $scope.page.filter);
// var _links = $scope.links;
for (var _link in _links) {
// curlink zetten
var curlink = _links[_link];
// eingen link gevonden
if (forceselect == true) {
if (curlink == link) {
forceselect = false;
break;
}
if (curlink.checked == true) {
forceselect = false;
break;
}
curlink.checked = true;
}
// 1e selectie = true
if (forceselect == false) {
if (curlink.checked == true) {
forceselect = true;
}
if (curlink == link) {
forceselect = true;
}
}
}
}
link.checked = !link.checked;
fnMultiple.multioptions();
},
checkall: function() {
$scope.page.checkall = !$scope.page.checkall;
var _links = $filter('filter')($scope.links, $scope.page.filter);
for (var i in _links) {
_links[i].checked = $scope.page.checkall;
}
fnMultiple.multioptions();
},
quickselect: function(m) {
for (var i in $scope.links) {
var bool = true
var t = false
if ($scope.page.quickselect.email) {
t = true;
bool = ($scope.links[i].partner.domain.email) ? bool : false;
}
if ($scope.page.quickselect.contactform) {
t = true;
bool = ($scope.links[i].partner.domain.contactform) ? bool : false;
}
if ($scope.page.quickselect.nocontact) {
t = true;
bool = ($scope.links[i].partner.domain.email || $scope.links[i].partner.domain.contactform) ? false : bool;
}
if (t) {
$scope.links[i].checked = bool;
}
}
fnMultiple.multioptions();
},
_findallstatus: function() {
for (var i in $scope.links) {
if ($scope.links[i].checked) {
$http.get("/rest/linkbuilding/link.checkstatus", {
'params': { websiteid: h.siteId(), '_id': $scope.links[i]['_id']['$oid'] }
}).then(function successCallback(res) {
$scope.links[i].inprogress = false;
$scope.links[i].checked = false;
fnMultiple._findallstatus();
});
break;
}
}
},
findallstatus: function() {
for (var i in $scope.links) {
if ($scope.links[i].checked) {
$scope.links[i].inprogress = true;
}
}
fnMultiple._findallstatus();
},
_findallcontact: function() {
for (var i in $scope.links) {
if ($scope.links[i].checked) {
$http.get("/rest/linkbuilding/link.findcontact", {
'params': { websiteid: h.siteId(), '_id': $scope.links[i]['_id']['$oid'] }
}).then(function successCallback(res) {
$scope.links[i] = res.data;
var date = new Date($scope.links[i].date * 1);
$scope.links[i].monthstring = date.toLocaleString('default', { year: 'numeric', 'month': 'long' })
$scope.links[i].date = $scope.page.kdates[date.toString()];
$scope.links[i].inprogress = false;
$scope.links[i].checked = false;
fnMultiple._findallcontact();
});
break;
}
}
},
findallcontact: function() {
for (var i in $scope.links) {
if ($scope.links[i].checked) {
$scope.links[i].inprogress = true;
}
}
fnMultiple._findallcontact();
},
'status': function() {
$http.post("/rest/linkbuilding/link.edit",
angular.extend({ 'fields': ['my.status'] },
fnMultiple.getParams(),
$scope.page.multiplelinks)
).then(function successCallback(res) {
fnLinks.list();
})
},
'date': function() {
$http.post("/rest/linkbuilding/link.edit",
angular.extend({ 'fields': ['date'] },
fnMultiple.getParams(),
$scope.page.multiplelinks)
).then(function successCallback(res) {
fnLinks.list();
})
},
'tag': function() {
$http.post("/rest/linkbuilding/link.edit",
angular.extend({ 'fields': ['my.tag'] },
fnMultiple.getParams(),
$scope.page.multiplelinks)
).then(function successCallback(res) {
fnLinks.list();
})
},
pre_edit: function(link) {
},
edit: function(link) {
$http.post("/rest/rank-tracker/edit",
angular.extend({
'my.status': $scope.page.multiplelinks.status,
'fields': ['my.status']
}, fnMultiple.getParams(link))).then(function successCallback(res) {
fnLinks.list();
})
},
pre_mail: function() {
$scope.page.multiplelinks.mail = { key: $scope.mailTemplates[0].key }
$scope.fnModal('linkbuilding/modal/multiple.mail')
},
'mail': function(link) {
$http.post("/rest/linkbuilding/link.mail",
angular.extend($scope.page.multiplelinks, fnMultiple.getParams())
).then(function successCallback(res) {
fnLinks.list();
})
},
delete: function(link) {
$http.post("/rest/linkbuilding/link.delete", fnMultiple.getParams(link)).then(function successCallback(res) { fnLinks.list(); })
}
}
$scope.fnExportAll = function() {
var text = '';
var out = '';
for (var _link in $scope.links) {
var curlink = $scope.links[_link];
text = text + curlink.url + "\r\n";
out += $filter('date')(new Date(curlink.d), 'dd-MM-yyyy') + ';'
out += curlink.partner.url+';'
if(curlink.my.url){
out += curlink.my.url+';'
} else {
out += ';'
}
if(curlink.my.url){
out += curlink.my.anchor + ';'
} else {
out += ';'
}
out += curlink.my.status + ';'
out += "\n";
}
var element = document.createElement('a');
element.setAttribute('href', 'data:text/html;,' + encodeURIComponent(out));
element.setAttribute('download', 'linkbuilding_export.csv');
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
// list links
fnLinks.list();
fnTemplates.list();
}
]);
app.controller('linkbuildingtemplate', ['$scope', '$timeout', '$http', '$rootScope', '$filter', 'h',
function($scope, $timeout, $http, $rootScope, $filter, h) {
//haal Template templates op
var getTemplates = function() {
$http.get('/rest/linkbuilding/template.list', {
params: {
'websiteid': h.siteId(),
}
}).then(function successCallback(res) {
$scope.mailTemplates = res.data;
});
};
getTemplates();
$scope.curTemplate = { workflow: [] };
$scope.fnNewTemplate = function() {
$scope.hideTemplateoptions = true;
$scope.templatetab = 1
$scope.curTemplate = { method: 'manual', provider:"", mails: [{ 'type': 'primary' }] };
}
$scope.fnRemoveFollowUp = function(index) {
$scope.curTemplate.mails.splice(index, 1);
}
$scope.fnAddFollowUp = function() {
$scope.curTemplate.mails.push({ method: 'manual', 'type': 'followup' });
}
$scope.fnCloseTemplate = function(curTemplate) {
$scope.hideTemplateoptions = false;
$scope.templatetab = 0
}
$scope.fnAddWorkFlow = function() {
$scope.curTemplate.workflow.push({ persoon: USER.UserId + "" });
}
$scope.fnRemoveWorkFlow = function(index) {
$scope.curTemplate.workflow.splice(index, 1);
}
$scope.fnAddTemplate = function() {
$http.post('/rest/linkbuilding/template.add', { 'websiteid': h.siteId(), 'template': $scope.curTemplate }).then(function successCallback(res) {
getTemplates();
$scope.templatetab = 0;
$scope.hideTemplateoptions = false;
});
}
$scope.fnShowEditTemplate = function(mailTemplate) {
$scope.templatetab = 1
$scope.curTemplate = mailTemplate;
}
$scope.fnDeleteTemplate = function(mailTemplate) {
$http.post('/rest/linkbuilding/template.delete', { 'websiteid': h.siteId(), 'template': mailTemplate}).then(function successCallback(res) {
getTemplates();
$scope.templatetab = 0;
$scope.hideTemplateoptions = false;
});
}
}
]);
app.controller('user', ['$scope', '$rootScope', '$http', '$location', '$translate', 'h',
function($scope, $rootScope, $http, $location, $translate, h) {
$scope.curUser = {};
$scope.page = {};
var _cb = {
loginfailed: function() {
$scope.page.message = { 'key': 'user.global.message_login_failed', class: 'text-warning' }
},
loginok: function(res) {
$rootScope.user = res.user;
//console.log($rootScope.user);
$location.path('/');
},
registrationnotvalid: function() {
$scope.page.message = { 'key': 'user.global.message_registration_failed', class: 'text-warning' }
},
registrationexists: function() {
$scope.page.message = { 'key': 'user.global.message_login_exists', class: 'text-warning' }
},
registrationok: function(res) {
$rootScope.user = res.user;
$scope.fnGoto('/sites/first');
//h.login($location.path('/sites/first'));
},
recoverfailed: function() {
$scope.page.message = { 'key': 'user.global.message_recover_failed', class: 'text-warning' }
},
recoverok: function() {
$scope.page.message = { 'key': 'user.global.message_recover_ok', class: 'text-warning' }
},
}
$scope.checklogin = function() {
if ($rootScope.user._id) {
$location.path('/');
}
if (!$rootScope.user.reseller.config.own && $location.path() == '/user/register') {
$location.path('/user/login');
}
}
$scope.userdetails = {
init: function() {
$http.get('/rest/user/user.get').then(function successCallback(res) {
$scope.curUser = res.data;
});
},
'set': function() {
$http.post('/rest/user/user.set', $scope.curUser);
},
'invoice': function(key) {
$scope.fnGoto('/rest/pay/invoice.link?type=user&key=' + key)
}
}
$scope.fnLogin = function() {
$http.post('/rest/user/login', $scope.curUser).then(function successCallback(res) {
_cb[res.data.cb](res.data)
});
}
$scope.fnRegister = function() {
$http.post('/rest/user/register', $scope.curUser).then(function successCallback(res) {
_cb[res.data.cb](res.data)
});
}
$scope.fnRecover = function() {
$http.post('/rest/user/recover', $scope.curUser).then(function successCallback(res) {
_cb[res.data.cb](res.data)
});
}
}
]);
app.controller('sites', ['$scope', '$rootScope', '$http', '$location', 'h',
function($scope, $rootScope, $http, $location, h) {
$scope.rand = function(min,max){
return Math.floor(Math.random() * (max - min + 1) + min)
}
$scope.bShowAdminDelete = function(site) {
return (site.status.expire > (Date.now() / 1000)) ? false : true;
}
$scope.page = {
pending: false,
orderstate: 'init'
};
if ($scope.orderstate) {
$scope.page.orderstate = $scope.orderstate;
}
$scope.curSite = {};
$scope.do = function(obj, method, param) {
if (obj == 'fnSite') {
fnSite[method](param);
}
}
var fnSite = {
'wemessage': function() {
$scope.fnGoto('/rest/pay/wemessage.start')
},
'list': function() {
$http.get('/rest/sites/list').then(function successCallback(res) {
$scope.sites = res.data;
});
},
'add': function() {
$http.post('/rest/sites/add', $scope.curSite).then(function successCallback(res) {
_cb[res.data.cb](res.data)
});
},
'adminupgrade': function() {
$http.post('/rest/sites/adminupgrade', { websiteid: h.siteId() })
},
'unpark': function() {
$http.post('/rest/sites/adminunpark', { websiteid: h.siteId() }).then(function successCallback(res) {
h.login(function() { $scope.fnClick('/') });
});
},
'admindelete': function(site) {
$http.post('/rest/sites/remove', site).then(function successCallback(res) {
side.hidden = true;
});
},
'delete': function(site) {
$http.post('/rest/sites/remove', $scope.curSite).then(function successCallback(res) {
$scope.curSite = {};
h.login(function() {});
fnSite.list();
});
},
'pre_edit': function(site) {
$http.get('/rest/locale/language.list').then(function successCallback(res) {
$scope.languages = res.data;
});
$http.get('/rest/locale/country.list').then(function successCallback(res) {
$scope.countries = res.data;
});
$scope.curSite = site;
$scope.fnModal('sites/modal/edit');
},
'edit': function(site) {
$http.post('/rest/sites/edit', site).then(function successCallback(res) {
});
},
'order_options': function() {
$http.get('/rest/pay/options.list').then(function successCallback(res) {
$scope.options = res.data;
var index = ($rootScope.user.site.locale.lang == 'nl') ? 0 : 1;
$scope.order = { 'currency': $scope.options.currency[index], 'method': $scope.options.methods[index] };
});
},
'pre_order': function(package) {
$http.post('/rest/sites/edit', site).then(function successCallback(res) {
});
},
}
var _cb = {
domainvalid: function(site) {
h.login(function() {
$location.path('/');
});
},
domaininvalid: function() {
$scope.page.message = { html: 'The domain is invalid', class: 'text-warning' }
},
domainduplicate: function() {
$scope.page.message = { html: 'This domain is not available for trials versions.', class: 'text-warning' }
},
deletefailed: function() {
$scope.page.message = { html: 'Registration failed, the user with email adress ' + $scope.curUser.email + ' allready exists. Did you mean to ', class: 'text-danger' }
},
}
}
]);
app.controller('site', ['$scope', '$timeout', '$http', '$rootScope', '$location', '$anchorScroll', '$filter', 'h',
function($scope, $timeout, $http, $rootScope, $location, $anchorScroll, $filter, h) {
$scope.page = {
newteammember: {},
newmenu: {}
};
$scope.roles = [
{ 'role': 4, 'name': 'owner' },
{ 'role': 5, 'name': 'normal user' },
{ 'role': 6, 'name': 'guest' },
]
$scope.do = function(obj, method, param) {
if (obj == 'fnSite') {
fnSite[method](param);
} else if (obj == 'fnPage') {
fnPage[method](param);
}
}
$http.get('/rest/locale/language.list').then(function successCallback(res) {
$scope.languages = res.data;
});
$http.get('/rest/locale/country.list').then(function successCallback(res) {
$scope.countries = res.data;
});
var fnSite = {
get: function() {
$http.get('/rest/sites/get', {
params: {
'websiteid': h.siteId(),
}
}).then(function successCallback(res) {
if (res.data._id) {
$scope.page.tab = 'edit';
$scope.user.site.users = res.data.users;
$scope.user.site.names = res.data.names;
$scope.user.site.api = res.data.api;
} else {
$scope.page.tab = 'intro';
}
});
},
'searchcity': function(q) {
$http.get('/rest/locale/city.list', { 'params': { 'q': q } }).then(function successCallback(res) {
$scope.cities = res.data;
});
},
'setcity': function(city) {
$scope.user.site.locale.city = city.city;
$scope.user.site.locale.uule = city.uule;
$scope.cities = [];
},
'add': function() {
$http.post('/rest/sites/teammember.add',
angular.extend({ 'websiteid': h.siteId() }, $scope.page.newteammember)
).then(function successCallback(res) {
$scope.page.newteammember = {};
fnSite.get();
});
},
'park': function() {
$http.post('/rest/sites/adminpark', { websiteid: h.siteId() }).then(function successCallback(res) {
h.login(function() { $scope.fnClick('/') });
});
},
'delete': function(teammember) {
$http.post('/rest/sites/teammember.delete',
angular.extend({ 'websiteid': h.siteId() }, teammember)
).then(function successCallback(res) {
fnSite.get();
});
},
'update': function(reseller) {
$http.post('/rest/sites/teammembers.update',
angular.extend({ 'websiteid': h.siteId() }, $scope.user.site)
).then(function successCallback(res) {
fnSite.get();
});
},
'edit': function(site) {
if (!$scope.user.site.locale.city || !$scope.user.site.locale.uule) {
$scope.user.site.locale.uule = '';
$scope.user.site.locale.city = '';
}
$http.post('/rest/sites/edit',
angular.extend({ 'websiteid': h.siteId() }, $scope.user.site)
).then(function successCallback(res) {
});
},
'addmenu': function() {
$scope.user.site.menu = $scope.user.site.menu || [];
$scope.user.site.menu.push($scope.page.newmenu);
fnSite.edit($scope.user.site);
},
'removemenu': function(index) {
$scope.user.site.menu.splice(index, 1);
fnSite.edit($scope.user.site);
},
}
fnSite.get();
}
]);
// Site-instellingen, Koppelingen: wat aan deze site gekoppeld is, om weg te halen (rest/data/connections)
app.controller('siteConnections', ['$scope', '$http', '$translate', 'h', function ($scope, $http, $translate, h) {
var s = $scope.conn = { list: null };
var load = function () {
$http.get('/rest/connections/list', { params: { websiteid: h.siteId() } }).then(function (res) {
s.list = res.data.connections || [];
});
};
// eerst een bevestiging in de rij zelf (geen browserdialoog), dan weg
s.remove = function (c) {
if (s.asking !== c.key) { s.asking = c.key; return; }
s.asking = null;
c.busy = true;
$http.post('/rest/connections/remove', { websiteid: h.siteId(), key: c.key }).then(function () {
$scope.$root.$broadcast('siteConnectionsChanged', c.key);
load();
}, function () { c.busy = false; });
};
load();
}]);
app.controller('contentlist', ['$scope', '$http', '$rootScope', '$filter', '$location', 'h', '$timeout',
function($scope, $http, $rootScope, $filter, $location, h, $timeout) {
$scope.page = { 'newmodel': { 'lang': $rootScope.user.site.locale.lang } };
var content = {
listModels: function() {
$http.get('/rest/content/model.list', {
params: {
websiteid: h.siteId(),
}
}).then(function successCallback(res) {
$scope.models = res.data.data;
content.checkProgress();
});
},
addModel: function(model) {
$http.post('/rest/content/model.add', angular.extend({ websiteid: h.siteId() }, model)).then(function successCallback(res) {
$scope.page.newmodel = {}
content.listModels();
});
},
createModel: function(model) {
$http.post('/rest/content/model.create', angular.extend({ websiteid: h.siteId() }, model)).then(function successCallback(res) {
model.status = 'checking';
});
},
deleteModel: function(model) {
$http.post('/rest/content/model.delete', angular.extend({ websiteid: h.siteId() }, model)).then(function successCallback(res) {
content.listModels();
});
},
checkProgress: function() {
var l = false;
for (var i in $scope.models) {
if ($scope.models[i].status == 'pending') {
l = true;
}
}
if (l) {
$timeout(function() {
content.listModels()
}, 5000);
}
}
}
$scope.do = function(method, param) {
content[method](param);
}
content.listModels()
}
]);
app.directive('wrapInTag', function () {
return {
restrict: 'A',
link: function (scope, elm, attr) {
console.log(attr);
var tag = attr.tag || 'strong';
var words = eval(attr.words) || [];
var text = attr.text;
for (var i = 0; i < words.length; i++) {
text = text.replace(words[i], '<' + tag + '>' + words[i] + '' + tag + '>');
}
elm.html(text);
}
}
});
app.controller('contentmodel', ['$scope', '$http', '$rootScope', '$filter', '$location', 'h', '$timeout',
function ($scope, $http, $rootScope, $filter, $location, h, $timeout) {
$scope.page = {
states: {}, 'tab': 'research', 'type': 'article', 'tones': {
"informative": true,
"persuasive": false,
"emotional": false,
"witty": true,
"funny": false,
"professional": true,
"informal": false
}
};
$scope.mypage = {};
$scope.page.states.explore = { 'open': false, 'cluster': 1 }
var model = {
getModel: function () {
$http.get('/rest/content/model.get', {
params: {
'websiteid': h.siteId(),
'modelid': $scope.modelid
}
}).then(function successCallback(res) {
$scope.q = res.data.q;
$scope.clusters = res.data.clusters;
$scope.dna = res.data.dna;
$scope.wordfreq = res.data.wordfreq;
$scope.trans = res.data.trans;
$scope.r = res.data.r;
$scope.lsi = res.data.lsi;
$scope.target = res.data.target;
$scope.pages = res.data.pages;
$scope.write = res.data.write;
$scope.x = {};
for (var i in $scope.wordfreq) {
$scope.x[$scope.wordfreq[i].word] = $scope.wordfreq[i].avg;
$scope.wordfreq[i].maxminavg = $scope.wordfreq[i].max - $scope.wordfreq[i].avg
}
charts.tfchart();
charts.dnaChart();
model.getMyPage();
});
},
setMyPage: function () {
$scope.mypage.pending = true;
$http.post('/rest/content/model.setmypage', angular.extend({ websiteid: h.siteId(), 'modelid': $scope.modelid }, $scope.mypage)).then(function successCallback(res) {
model.getMyPage()
});
},
writestatus: function () {
var l = false;
$http.get('/rest/content/model.get', {
params: {
'websiteid': h.siteId(),
'modelid': $scope.modelid
}
}).then(function successCallback(res) {
if (res.data.write.status == 'pending') {
l = true;
}
if (l) {
$timeout(function () {
model.writestatus();
}, 5000);
} else {
model.getMyPage();
$scope.write = res.data.write;
}
});
},
write: function () {
$scope.write = $scope.write || {};
$scope.write.status = 'pending';
$scope.page.tab = 'write';
$http.post('/rest/content/model.pre_write', angular.extend({ websiteid: h.siteId(), 'modelid': $scope.modelid }, { 'type': $scope.page.type, 'tones': $scope.page.tones })).then(function successCallback(res) {
model.writestatus();
// need to set up checks here!
});
},
getMyPage: function () {
$scope.mypage.pending = true;
$http.get('/rest/content/model.getmypage', {
params: {
'websiteid': h.siteId(),
'modelid': $scope.modelid
}
}).then(function successCallback(res) {
$scope.mypage = res.data;
if (res.data.mna) {
for (var i in $scope.wordfreq) {
var word = $scope.wordfreq[i].word;
$scope.wordfreq[i].my = res.data.counter[word] || 0;
}
$scope.mna = res.data.mna;
charts.tfchart();
charts.dnaChart();
$scope.mypage.pending = false;
model.getSpamandSuggestions();
$scope.page.tab = 'write';
}
});
},
getSpamandSuggestions: function () {
$scope.kwspam = [];
$scope.kwsuggestions = [];
for (var i in $scope.wordfreq) {
var f = $scope.wordfreq[i];
if (f.my > f.max) {
$scope.kwspam.push({ 'word': f.word, 'my': f.my, 'max': f.max });
}
if (f.my < f.avg) {
$scope.kwsuggestions.push({ 'word': f.word, 'my': f.my, 'avg': f.avg });
}
}
},
exploreCluster(cluster) {
lines = [];
$scope.page.states.explore = { 'open': true, 'cluster': cluster }
for (var i in $scope.clusters) {
for (var y in $scope.clusters[i]['lines']) {
var line = $scope.clusters[i]['lines'][y]['text'];
var src = $scope.clusters[i]['lines'][y]['src'];
var fit = $scope.clusters[i]['lines'][y]['dna'][cluster];
if ($scope.clusters[i]['lines'][y]['text'].length > 133) {
lines.push({ 'line': line, 'fit': fit, 'src': src, 'wordscore': $scope.clusters[i]['lines'][y]['wordscore'], 'score': $scope.clusters[i]['lines'][y]['score'] });
}
}
}
$scope.page.lines = lines;
},
exploreWord: function (word) {
$scope.page.states.explore.open = false;
var s = word.split(' ');
var boldarray = [];
for (var i in s) {
for (var w in $scope.trans[s[i]]) {
boldarray.push(w)
}
}
suggestions = [];
for (var i in $scope.clusters) {
for (var y in $scope.clusters[i]['lines']) {
var sent = $scope.clusters[i]['lines'][y];
if (sent.clean.indexOf(' ' + word + ' ') !== -1) {
suggestions.push(sent)
$scope.page.states.exploreword = { 'open': true, 'word': word, 'boldarray': boldarray, 'suggestions': suggestions }
}
}
}
}
}
model.getModel();
$scope.do = function (method, param) {
model[method](param);
}
var charts = {
tfchart: function () {
var d = angular.copy($filter('orderBy')($scope.wordfreq, 'avg', true));
var d = d.map(function (c) {
c.word = ($scope.trans[c.word]) ? Object.keys($scope.trans[c.word])[0] : c.word;
return c;
})
$scope.tfidfchart = {
data: d,
type: "serial",
//autoMarginOffset: 20,
marginLeft: 16,
categoryField: "word",
legend: {
enabled: false
},
chartScrollbar: {
"enabled": true,
"hideResizeGrips": true,
"offset": 10,
"scrollbarHeight": 10
},
categoryAxis: {
gridPosition: "start",
parseDates: false,
gridThickness: 0,
"labelRotation": 45
},
valueAxes: [{
"stackType": "regular",
dashLength: 4,
color: '#dedede',
position: "top",
axisAlpha: 0,
labelsEnabled: false
}],
graphs: [{
balloonText: "AVG distribution top 10 result
[[value]]",
type: "column",
title: "Keyword value",
valueField: "avg",
fillAlphas: 1,
lineColor: '#28a745',
}, {
balloonText: "Max distribution top 10 result
[[value]]",
type: "column",
title: "Keyword value",
valueField: "maxminavg",
fillAlphas: 1,
lineColor: '#dddddd',
}, {
balloonText: "My distribution
[[value]]",
"bullet": "round",
"bulletBorderAlpha": 1,
"bulletColor": "#FFFFFF",
"useLineColorForBulletBorder": true,
"fillAlphas": 0,
"lineThickness": 2,
"lineAlpha": 1,
"bulletSize": 7,
"valueField": "my",
lineColor: '#ffc107',
}],
zoom: [0, 18]
}
},
dnaChart: function () {
var dna = [];
var mna = [];
var ordered_clusters = $filter('orderBy')($scope.clusters, 'score', true);
for (var i in ordered_clusters) {
if ($scope.mna) {
$scope.max_fit = (Math.max(...$scope.dna), Math.max(...$scope.mna))
dna.push({ 'cluster': ordered_clusters[i].cluster, 'dna': $scope.dna[ordered_clusters[i].cluster] * 100, 'mna': $scope.mna[ordered_clusters[i].cluster] * 100, 'i': (i * 1) + 1 })
} else {
$scope.max_fit = Math.max(...$scope.dna);
dna.push({ 'cluster': ordered_clusters[i].cluster, 'dna': $scope.dna[ordered_clusters[i].cluster] * 100, 'i': (i * 1) + 1 })
}
}
$scope.dnachart = {
"type": "radar",
data: dna,
"theme": "none",
"valueAxes": [{
"labelsEnabled": false,
"axisTitleOffset": 14,
"minimum": 0,
"axisAlpha": 0.15
}],
"startDuration": 2,
"graphs": [{
"balloonText": "Cluster [[i]]
Goal: [[value]]%",
"bullet": "round",
"lineThickness": 2,
"fillAlphas": 0.8,
"valueField": "dna",
lineColor: '#28a745',
}, {
"balloonText": "Cluster [[i]]
My page: [[value]]%",
"bullet": "round",
"color": "#dedede",
"fillAlphas": 0.3,
"lineThickness": 2,
"valueField": "mna",
}],
"categoryField": "i",
"export": {
"enabled": true
}
};
},
}
$scope.untrans = function (w) {
var s = w.split(' ');
for (var i in s) {
s[i] = Object.keys($scope.trans[s[i]])[0];
}
return s.join(' ');
}
}
]);
app.controller('report', ['$scope', '$timeout', '$http', '$rootScope', '$controller', '$window', 'h',
function($scope, $timeout, $http, $rootScope, $controller, $window, h) {
// nieuw of huidig rapport
$scope.page = { 'newreport': { show: false }, dates: [], kdates: {},'simpleview':true };
var d = new Date();
var thismonth = d.getMonth() + 1;
var thismonth = new Date().getMonth() + 3;
for (var i = 0; i < 15; i++) {
var date = new Date(new Date().getFullYear(), thismonth, 0);
$scope.page.dates.push({ 'date': date });
$scope.page.kdates[date.toString()] = date;
thismonth = thismonth - 1;
}
$scope.do = function(obj, method, param) {
if (obj == 'fnReport') {
fnReport[method](param);
}
}
var fnReport = {
list: function() {
$http.get('/rest/report/report.list', {
params: {
websiteid: h.siteId(),
}
}).then(function successCallback(res) {
$scope.reports = res.data;
angular.forEach(res.data, function(k, v) {
var date = new Date(k.download.date * 1);
k.download.date = $scope.page.kdates[date.toString()];
k.download = k.download || { status: '' }
if (k.download.status == 'pending') {
$timeout(function() {
fnReport.list();
}, 10000);
}
})
});
},
'add': function(report) {
$http.post('/rest/report/report.add',
angular.extend({ websiteid: h.siteId() }, report)
).then(function successCallback(res) {
fnReport.list();
});
},
create: function(report) {
$http.post('/rest/report/report.generate', angular.extend({ websiteid: h.siteId() }, report))
report.download.status = 'pending'
fnReport.update(report);
},
'update': function(report) {
report.download = report.download || {};
report.download.date = report.download.date || new Date();
report.download.date = Math.round(report.download.date.getTime() / 1000)
if(report.download.enddate){
if($scope.page.simpleview == true){
delete report.download.enddate
} else {
console.log(report.download.enddate);
report.download.enddate = report.download.enddate || new Date();
report.download.enddate = Math.round(report.download.enddate.getTime() / 1000)
}
}
$http.post('/rest/report/report.update',
angular.extend({ websiteid: h.siteId() }, report)
).then(function successCallback(res) {
fnReport.list();
});
},
'download': function(report) {
console.log(report);
$window.location.href = '/rest/report/report.download/?websiteid=' + h.siteId() + '&reportid=' + report.report_id;
},
'delete': function(report) {
$http.post('/rest/report/report.delete',
angular.extend({ websiteid: h.siteId() }, report)
).then(function successCallback(res) {
fnReport.list();
});
},
}
fnReport.list();
}
]);
app.controller('reportitem', ['$scope', '$timeout', '$http', '$rootScope', '$location', '$anchorScroll', '$filter', 'h',
function($scope, $timeout, $http, $rootScope, $location, $anchorScroll, $filter, h) {
$scope.do = function(obj, method, param) {
if (obj == 'fnReport') {
fnReport[method](param);
} else if (obj == 'fnPage') {
fnPage[method](param);
}
}
// Search Insights en Rank tracker: dezelfde controllers als de pagina's, in rapportstand (custominit.gsci / .serp)
$scope.reportcategories = [{
'translate': 'gscinsights.title',
'types': [
{ 'translate': 'gscinsights.tab.overview', 'view': 'gscinsights/report_page.html', 'init': { 'gsci': true, 'urlview': 'overview' } },
{ 'translate': 'gscinsights.tab.topics', 'view': 'gscinsights/report_page.html', 'init': { 'gsci': true, 'urlview': 'topics' } },
{ 'translate': 'gscinsights.tab.tracked', 'view': 'gscinsights/report_page.html', 'init': { 'gsci': true, 'urlview': 'tracked' } },
{ 'translate': 'gscinsights.overview.actions_title', 'view': 'gscinsights/report_page.html', 'init': { 'gsci': true, 'urlview': 'actions' } },
{ 'translate': 'menu.searchconsole.keywords', 'view': 'gscinsights/report.html', 'init': { 'urlreport': 'campaigns', 'urlview': 'keywords' } },
{ 'translate': 'menu.searchconsole.pages', 'view': 'gscinsights/report.html', 'init': { 'urlreport': 'campaigns', 'urlview': 'pages' } },
{ 'translate': 'menu.searchconsole.country', 'view': 'gscinsights/report.html', 'init': { 'urlreport': 'campaigns', 'urlview': 'country' } },
{ 'translate': 'menu.searchconsole.device', 'view': 'gscinsights/report.html', 'init': { 'urlreport': 'campaigns', 'urlview': 'device' } }
]
},
{
'translate': 'menu.serp',
'types': [
{ 'translate': 'serp.tab.overview', 'view': 'serp/report.html', 'init': { 'serp': true, 'urlview': 'overview' } },
{ 'translate': 'serp.tab.keywords', 'view': 'serp/report.html', 'init': { 'serp': true, 'urlview': 'keywords' } },
{ 'translate': 'serp.tab.competitors', 'view': 'serp/report.html', 'init': { 'serp': true, 'urlview': 'competitors' } }
]
},
/* {
'translate': 'menu.linkbuilding.linkbuilding',
'types': [
{ 'translate': 'menu.linkbuilding.assistant', 'view': 'linkbuilding/assistant.html', 'init': '' },
]
},*/
{
'translate': 'menu.onpage.onpage',
'types': [
{ 'translate': 'menu.onpage.overview', 'view': 'onpage/index.status.html', 'init': { 'viewrulelabel': 'all' } }
]
},
{
'translate': 'menu.analytics4.analytics',
'types': [
{ 'parent': 'menu.analytics.channels.channels', 'translate': 'menu.analytics.channels.all', 'view': 'api/analytics4.html', 'init': { 'urlreport': 'channels', 'urlview': 'all' } },
{ 'parent': 'menu.analytics.channels.channels', 'translate': 'menu.analytics.channels.organic', 'view': 'api/analytics4.html', 'init': { 'urlreport': 'channels', 'urlview': 'organic' } },
{ 'parent': 'menu.analytics.channels.channels', 'translate': 'menu.analytics.channels.paid', 'view': 'api/analytics4.html', 'init': { 'urlreport': 'channels', 'urlview': 'paid' } },
{ 'parent': 'menu.analytics.channels.channels', 'translate': 'menu.analytics.channels.display', 'view': 'api/analytics4.html', 'init': { 'urlreport': 'channels', 'urlview': 'display' } },
{ 'parent': 'menu.analytics.channels.channels', 'translate': 'menu.analytics.channels.social', 'view': 'api/analytics4.html', 'init': { 'urlreport': 'channels', 'urlview': 'social' } },
{ 'parent': 'menu.analytics.channels.channels', 'translate': 'menu.analytics.channels.referral', 'view': 'api/analytics4.html', 'init': { 'urlreport': 'channels', 'urlview': 'referral' } },
{ 'parent': 'menu.analytics.channels.channels', 'translate': 'menu.analytics.channels.email', 'view': 'api/analytics4.html', 'init': { 'urlreport': 'channels', 'urlview': 'email' } },
{ 'parent': 'menu.analytics.channels.channels', 'translate': 'menu.analytics.channels.other', 'view': 'api/analytics4.html', 'init': { 'urlreport': 'channels', 'urlview': 'other' } },
]
},
{
'translate': 'menu.googleads.googleads',
'types': [
{ 'translate': 'menu.googleads.all', 'view': 'api/googlexads.html', 'init': { 'urlreport': 'campaigns', 'urlview': 'all' } },
{ 'translate': 'menu.googleads.adgroups', 'view': 'api/googlexads.html', 'init': { 'urlreport': 'campaigns', 'urlview': 'adgroups' } },
{ 'translate': 'menu.googleads.keywords', 'view': 'api/googlexads.html', 'init': { 'urlreport': 'campaigns', 'urlview': 'keywords' } },
{ 'translate': 'menu.googleads.ads', 'view': 'api/googlexads.html', 'init': { 'urlreport': 'campaigns', 'urlview': 'ads' } },
{ 'translate': 'menu.googleads.conversions', 'view': 'api/googlexads.html', 'init': { 'urlreport': 'campaigns', 'urlview': 'conversions' } },
]
},
{
'translate': 'menu.facebookads.facebookads',
'types': [
{ 'translate': 'menu.facebookads.all', 'view': 'api/facebookxads.html', 'init': { 'urlreport': 'campaigns', 'urlview': 'all' } },
{ 'translate': 'menu.facebookads.adsets', 'view': 'api/facebookxads.html', 'init': { 'urlreport': 'campaigns', 'urlview': 'adsets' } },
{ 'translate': 'menu.facebookads.ads', 'view': 'api/facebookxads.html', 'init': { 'urlreport': 'campaigns', 'urlview': 'ads' } },
{ 'translate': 'menu.facebookads.keywords', 'view': 'api/facebookxads.html', 'init': { 'urlreport': 'campaigns', 'urlview': 'keywords' } },
{ 'translate': 'menu.facebookads.age', 'view': 'api/facebookxads.html', 'init': { 'urlreport': 'campaigns', 'urlview': 'age' } },
{ 'translate': 'menu.facebookads.gender', 'view': 'api/facebookxads.html', 'init': { 'urlreport': 'campaigns', 'urlview': 'gender' } },
]
},
{
'translate': 'menu.facebookinsights.facebookinsights',
'types': [
{ 'translate': 'menu.facebookinsights.fans', 'view': 'api/facebookinsights.html', 'init': { 'urlreport': 'page', 'urlview': 'fans' } },
{ 'translate': 'menu.facebookinsights.engagements', 'view': 'api/facebookinsights.html', 'init': { 'urlreport': 'page', 'urlview': 'engagements' } },
{ 'translate': 'menu.facebookinsights.reach', 'view': 'api/facebookinsights.html', 'init': { 'urlreport': 'page', 'urlview': 'reach' } },
{ 'translate': 'menu.facebookinsights.posts', 'view': 'api/facebookinsights.html', 'init': { 'urlreport': 'page', 'urlview': 'posts' } }
]
},
{
'translate': 'menu.mybusiness.mybusiness',
'types': [
{ 'translate': 'menu.mybusiness.all', 'view': 'api/mybusiness.html', 'init': { 'urlreport': 'business', 'urlview': 'all' } },
{ 'translate': 'menu.mybusiness.reviews', 'view': 'api/mybusiness.html', 'init': { 'urlreport': 'business', 'urlview': 'reviews' } },
]
},
{
'translate': 'menu.planning',
'types': [
{ 'translate': 'menu.planning', 'view': 'planning/index.html', 'init': '' },
]
},
{
'translate': 'menu.linkbuilding',
'types': [
{ 'translate': 'menu.linkbuilding', 'view': 'linkbuilding/assistant.html', 'init': '' },
]
},
];
var fnPage = {
'new': function() {
return {};
},
'type': function(o) {
o.page.type = false;
$timeout(function() {
o.page.type = o.type;
o.page.changetype = false;
fnReport.update();
}, 500);
}
}
var fnReport = {
get: function() {
$http.get('/rest/report/report.get', {
params: {
websiteid: h.siteId(),
report_id: $scope.report_id,
}
}).then(function successCallback(res) {
console.log('ORIG DATE TS', res.data.download.date)
// Handle both seconds and milliseconds timestamps
var dateTs = res.data.download.date * 1;
if (dateTs < 10000000000) dateTs = dateTs * 1000; // Convert seconds to milliseconds
var date = new Date(dateTs);
if(res.data.download.enddate){
console.log('END DATE TS', res.data.download.enddate)
// Handle both seconds and milliseconds timestamps
var endDateTs = res.data.download.enddate * 1;
if (endDateTs < 10000000000) endDateTs = endDateTs * 1000;
var enddate = new Date(endDateTs);
var endts = new Date(enddate.getFullYear(), enddate.getMonth(), 0).getTime() / 1000;
} else {
var endts = new Date(date.getFullYear(), date.getMonth() + 1, 0).getTime() / 1000;
}
res.data.download.date = date;
$rootScope.reportdates = {
/* api */
'end': endts,
'start': new Date(date.getFullYear(), date.getMonth(), 1).getTime() / 1000,
/* planning */
'datestring': date.toLocaleString('default', { year: 'numeric', 'month': 'long' })
}
console.log('REPORTDATES', $rootScope.reportdates);
$scope.report = res.data;
});
},
getsettings: function() {
$http.get('/rest/report/settings.get', {
params: {
websiteid: h.siteId(),
report_id: $scope.report_id,
}
}).then(function successCallback(res) {
$scope.settings = res.data;
});
},
'addpage': function(index) {
console.log(index, 'is index');
$scope.report.pages = $scope.report.pages || [];
$scope.report.pages.splice(index, 0, fnPage.new());
$timeout(function() {
angular.element('html, body').animate({ scrollTop: angular.element('#page' + index).offset().top - 120 }, 400);
}, 200);
},
'deletepage': function(index) {
$scope.report.pages = $scope.report.pages || [];
$scope.report.pages.splice(index, 1);
fnReport.update();
},
'update': function(report) {
report = $scope.report;
report.download = report.download || {};
report.download.date = report.download.date || new Date();
report.download.date = Math.round(report.download.date.getTime() / 1000)
$http.post('/rest/report/report.update',
angular.extend({ websiteid: h.siteId() }, $scope.report)
).then(function successCallback(res) {
fnReport.get();
});
},
}
fnReport.get();
fnReport.getsettings();
}
]);
app.controller('reportpage', ['$scope', '$timeout', '$http', '$rootScope', '$controller', '$window', 'h',
function($scope, $timeout, $http, $rootScope, $controller, $window, h) {
}
]);
app.controller('coreapi', ['$scope', '$timeout', '$http', '$rootScope', '$filter', '$location', 'h',
function ($scope, $timeout, $http, $rootScope, $filter, $location, h) {
$scope.charts = {};
$scope.progresschart = {};
$scope.viewfilters = {};
var colorindex = 0;
$scope.dateoptions = [
{ start: 'TODAY', end: 'TODAY', description: 'Today' },
{ start: 'YESTYERDAY', end: 'YESTYERDAY', description: 'Yesterday' },
{ start: '7DAYSAGO', end: 'TODAY', description: 'Past 7 days' },
{ start: '14DAYSAGO', end: 'TODAY', description: 'Past 14 days' },
{ start: '30DAYSAGO', end: 'TODAY', description: 'Past 30 days' },
{ start: '1YEARAGO', end: 'TODAY', description: 'Past year' },
{ start: 'THISMONTH', end: 'TODAY', description: 'This month' },
{ start: 'LASTMONTH', end: 'TODAY', description: 'Previous month' },
]
$scope.compareoptions = [
{ 'compare': false, 'comparedescription': 'Do not compare' },
{ 'compare': 'PERIOD', 'comparedescription': 'Compare with previous period' },
{ 'compare': 'YEAR', 'comparedescription': 'Compare with previous year' },
]
$scope.fnCustomDate = {
'init': function () {
var d = new Date()
d.setMonth(d.getMonth() - 1);
$scope.customdate = { 'start': d, 'end': new Date(), 'show': false }
},
'set': function () {
console.log('------------------- AHHHHH ');
$scope.customdate.show = false;
$rootScope.reportdates.start = Math.round($scope.customdate.start.getTime() / 1000)
$rootScope.reportdates.end = Math.round($scope.customdate.end.getTime() / 1000)
$rootScope.reportdates.description = 'Custom';
getReportData();
}
}
$scope.fnCustomDate.init();
$scope.table = {
'curpage': 0,
'itemsperpage': 20,
'offset': 0,
fnSetOffset: function () {
this.offset = this.itemsperpage * (this.curpage - 1);
}
}
if (!$rootScope.reportdates) {
$rootScope.reportdates = { 'start': '30DAYSAGO', 'end': 'TODAY', 'description': 'Past 30 days', 'compare': false, 'comparedescription': 'Do not compare' };
}
$scope.fnDateSelection = function (reportdates) {
$rootScope.reportdates.start = reportdates.start;
$rootScope.reportdates.end = reportdates.end;
$rootScope.reportdates.description = reportdates.description;
getReportData();
}
$scope.fnCompareSelection = function (reportdates) {
$rootScope.reportdates.compare = reportdates.compare;
$rootScope.reportdates.comparedescription = reportdates.comparedescription;
getReportData();
}
$scope.getCustomer = function () {
if ($rootScope.user.site.role < 6) {
$http.get('/rest/' + ($scope.cfg.restbase || $scope.cfg.urlbase) + '/getcustomer', {
params: {
action: 'getproperties',
websiteid: h.siteId(),
}
}).then(function successCallback(res) {
$scope.customers = res.data;
$scope.fnModal('api/modal/' + $scope.cfg.urlbase + '.selectcustomer');
});
}
}
$scope.setCustomer = function (data) {
$http.get('/rest/' + ($scope.cfg.restbase || $scope.cfg.urlbase) + '/setcustomer', {
params: {
websiteid: h.siteId(),
customer: data
}
}).then(function successCallback(res) {
getReportData();
});
}
$scope.useApiGrant = function (apigrant) {
$http.get('/rest/api-core/apigrants.set', {
params: {
websiteid: h.siteId(),
'type': $scope.cfg.urlbase,
'grantid': apigrant.grantid,
}
}).then(function successCallback(res) {
getReportData();
});
}
$scope.fnOptions = function () {
if ($scope.view.viewfilters) {
$http.get('/rest/' + $scope.cfg.urlbase + '/getviewfilters', {
params: {
websiteid: h.siteId(),
viewfilters: $scope.view.viewfilters.join(',')
}
}).then(function successCallback(res) {
$scope.viewfilteroptions = res.data.data
});
}
if ($scope.cfg.switchclient) {
$http.get('/rest/' + ($scope.cfg.restbase || $scope.cfg.urlbase) + '/getcustomer', {
params: {
action: 'getproperties',
websiteid: h.siteId(),
}
}).then(function successCallback(res) {
$scope.customers = res.data;
});
}
$scope.fnModal('api/modal/' + $scope.cfg.urlbase + '.options');
}
$scope.pullCustomer = function () {
$http.get('/rest/' + ($scope.cfg.restbase || $scope.cfg.urlbase) + '/pullcustomer', {
params: {
websiteid: h.siteId()
}
}).then(function successCallback(res) {
getReportData();
});
}
var _fnFetchData = function (i) {
if ($scope.view[i]) {
var vv = {};
var metrics = ($scope.view[i].metrics) ? $scope.view[i].metrics : $scope.metrics;
if ($scope.viewfilters) {
for (var y in $scope.viewfilters) {
vv[y] = $scope.viewfilters[y]['viewfilter'];
}
}
// een view kan een eigen url hebben (de oude Search Console-subrapporten, tot die pagina weg is)
$http.get($scope.view[i].url || $scope.cfg.report_endpoint, {
params: {
websiteid: h.siteId(),
metrics: metrics.join(','),
dimension: $scope.view[i].dimension,
dimension2: $scope.view[i].dimension2,
report: $scope.view[i].report,
channel: $scope.view[i].channel,
context: $scope.view[i].context,
viewfilters: vv,
compare: $scope.view[i].compare || $rootScope.reportdates.compare,
allowcomp: $scope.view[i].allowcomp,
level: $scope.view[i].level,
endpoint: $scope.view[i].endpoint,
summary: $scope.view[i].summary,
breakdowns: $scope.view[i].breakdowns,
filterdimension: $scope.view[i].filterdimension,
filterexpression: $scope.view[i].filterexpression,
filteroperator: $scope.view[i].filteroperator,
sort: $scope.view[i].sort,
sortorder: $scope.view[i].sortorder,
start: ($scope.view[i].start) ? $scope.view[i].start : $rootScope.reportdates.start,
end: ($scope.view[i].end) ? $scope.view[i].end : $rootScope.reportdates.end,
limit: $scope.view[i].limit,
status: $scope.view[i].status,
campaignid: $scope.view[i].campaignid,
filter: $scope.view[i].filter,
campaign: $scope.view[i].campaign,
adgroup: $scope.view[i].adgroup,
network: $scope.view[i].network,
zeroimpressions: $scope.view[i].zeroimpressions,
}
}).then(function successCallback(res) {
if ($scope.view[i].callback) {
$scope.view[i].callback(res.data);
}
if (res.data.error) {
$scope.fnModal('api/modal/global.norights');
} else if (res.data.action == 'connect') {
$scope.fnModal('api/modal/' + $scope.cfg.urlbase + '.connect');
$http.get('/rest/api-core/apigrants.get', {
params: {
websiteid: h.siteId(),
'type': $scope.cfg.urlbase,
}
}).then(function successCallback(res) {
if (res.data.data !== null) {
$scope.apigrants = res.data.data;
}
});
if (res.data.sets) {
for (var set in res.data.sets) {
$scope.analytics[set] = res.data.sets[set];
for (var y in $scope.charts) {
if ($scope.charts[y].dataset == set) {
fnMakeChart($scope.charts[y]);
}
}
}
$scope.analytics[i] = { totals: res.data.totals };
} else {
$scope.analytics[i] = res.data;
for (var y in $scope.charts) {
if ($scope.charts[y].dataset == i) {
fnMakeChart($scope.charts[y]);
}
}
}
} else if (res.data.action == 'getcustomer') {
$scope.getCustomer();
} else if (res.data.sets) {
for (var set in res.data.sets) {
$scope.analytics[set] = res.data.sets[set];
for (var y in $scope.charts) {
if ($scope.charts[y].dataset == set) {
fnMakeChart($scope.charts[y]);
}
}
}
$scope.analytics[i] = { totals: res.data.totals };
} else {
$scope.analytics[i] = res.data;
for (var y in $scope.charts) {
if ($scope.charts[y].dataset == i) {
fnMakeChart($scope.charts[y]);
}
}
}
}, function errorCallback() {
$scope.fnModal('api/modal/global.error');
});
}
}
var getReportData = function () {
$scope.fnCloseModal();
$scope.analytics = {};
$scope.pagecharts = {};
_fnFetchData('first');
_fnFetchData('second');
_fnFetchData('third');
_fnFetchData('fourth');
}
var fnMakeChart = function (chart) {
console.log(chart.dataset);
var dataset = $scope.analytics[chart.dataset].data;
var dimension = (chart.dimension) ? chart.dimension : ($scope.cfg.dimensionprefix + $scope.view[chart.dataset].dimension);
var metric = (chart.metric) ? chart.metric : $scope.metric;
$scope.progresschart[chart.chart] = false;
if (chart['type'] == 'line') {
_charts.fnLineChart(chart, dataset, dimension, metric);
} else if (chart['type'] == 'bar') {
_charts.fnBarChart(chart, dataset, dimension, metric);
} else if (chart['type'] == 'pie') {
_charts.fnPieChart(chart, dataset, dimension, metric);
} else if (chart['type'] == 'linemulti') {
_charts.fnLineChartMultiple(chart, dataset, dimension, metric);
} else if (chart['type'] == 'bubble') {
_charts.fnBubbleChart(chart, dataset, dimension, metric);
} else if (chart['type'] == 'progress') {
_charts.fnProgressChart(chart, dataset, dimension, metric);
}
}
$scope.colors = ['#E91E63', '#3F51B5', '#00BCD4', '#8BC34A', '#FF9800', '#795548', '#607D8B', '#00CC00', '#0000CC', '#DDDDDD', '#999999', '#333333', '#990000']
var _charts = {
fnBubbleChart: function (chart, dataset, dimension, metric) {
return false;
},
fnProgressChart: function (chart, dataset, dimension, metric) {
$scope.pagecharts[chart.chart] = false
var b = $filter('orderBy')(dataset, metric, $scope.order.reverse).slice(0, 5);
$scope.progresschart[chart.chart] = b;
},
fnLineChart: function (chart, dataset, dimension, metric) {
$scope.gloMetrics[metric] = $scope.gloMetrics[metric] || {};
var datamerge = $scope.gloMetrics[metric].datemerge;
var datesubstr = ($scope.cfg.dateformat == 'YYYYMMDD') ? [0, 4, 4, 6, 6, 8] : [0, 4, 5, 7, 8, 10];
var data = {};
// if (dataset.length > 62 && datamerge) {
// for (var i in dataset) {
// // todo date format YYYY-MM-DD vs YYYYMMDD
// var year = dataset[i][dimension].toString().substring(datesubstr[0], datesubstr[1]);
// var month = dataset[i][dimension].toString().substring(datesubstr[2], datesubstr[3]);
// var day = dataset[i][dimension].toString().substring(datesubstr[4], datesubstr[5]);
// var date = new Date(year, month - 1, day);
// onejan = new Date(date.getFullYear(), 0, 1);
// week = Math.ceil((((date - onejan) / 86400000) + onejan.getDay() + 1) / 7);
// var yw = year + '_' + week;
// if (data[yw]) {
// data[yw][metric] += dataset[i][metric];
// data[yw]['n'] += 1;
// } else {
// data[yw] = dataset[i];
// data[yw]['n'] = 1;
// }
// }
// // todo calc average
// dataset = $filter('orderBy')(Object.values(data), 'dimension', false);
// if (datamerge == 'avg') {
// dataset = dataset.map(function (c) {
// c[metric] = c[metric] / c['n'];
// return c;
// })
// }
// }
// A new function to merge data into 31-day buckets, starting from the last entry.
if (dataset.length > 62 && datamerge) { // Condition changed to 31 for one bucket period.
// Assuming the dataset is sorted by date, with the most recent date at the end.
// If not sorted, you would need to find the maximum date first.
const lastEntry = dataset[dataset.length - 1];
const endDateYear = lastEntry[dimension].toString().substring(datesubstr[0], datesubstr[1]);
const endDateMonth = lastEntry[dimension].toString().substring(datesubstr[2], datesubstr[3]);
const endDateDay = lastEntry[dimension].toString().substring(datesubstr[4], datesubstr[5]);
// Set the anchor date to the end of the day of the last entry.
const anchorDate = new Date(endDateYear, endDateMonth - 1, endDateDay);
anchorDate.setHours(23, 59, 59, 999); // Use end of day to ensure the last day is included.
const data = {};
const MS_PER_DAY = 86400000; // Milliseconds in one day (24 * 60 * 60 * 1000)
let period = 7;
// Loop backwards from the end of the dataset.
for (let i = dataset.length - 1; i >= 0; i--) {
const item = dataset[i];
// Parse the date for the current item.
const year = item[dimension].toString().substring(datesubstr[0], datesubstr[1]);
const month = item[dimension].toString().substring(datesubstr[2], datesubstr[3]);
const day = item[dimension].toString().substring(datesubstr[4], datesubstr[5]);
const currentDate = new Date(year, month - 1, day);
// Calculate how many days ago this date was from our anchor date.
const daysDifference = (anchorDate.getTime() - currentDate.getTime()) / MS_PER_DAY;
// Determine the bucket index. Each bucket is a 31-day period.
// Math.floor(0 / 31) = 0, Math.floor(30.9 / 31) = 0, Math.floor(31 / 31) = 1
const bucketIndex = Math.floor(daysDifference / period);
// Create a representative date for the bucket's start day for a consistent key.
const bucketStartDate = new Date(anchorDate);
bucketStartDate.setDate(anchorDate.getDate() - (bucketIndex + 1) * period + 1);
// Format the bucket key to match the API's date format.
const bYear = bucketStartDate.getFullYear();
const bMonth = ('0' + (bucketStartDate.getMonth() + 1)).slice(-2);
const bDay = ('0' + bucketStartDate.getDate()).slice(-2);
const bucketKey = ($scope.cfg.dateformat === 'YYYYMMDD')
? '' + bYear + bMonth + bDay
: bYear + '-' + bMonth + '-' + bDay;
// Aggregate data into the bucket.
if (data[bucketKey]) {
data[bucketKey][metric] += item[metric];
data[bucketKey]['n'] += 1;
} else {
// Create a new entry for the bucket.
data[bucketKey] = { ...item }; // Copy item to avoid modifying original
data[bucketKey][dimension] = bucketKey; // Set the dimension to our bucket's start date
data[bucketKey]['n'] = 1;
}
}
// Convert the aggregated data object back to an array and sort it.
dataset = $filter('orderBy')(Object.values(data), dimension, false);
// If 'avg' is specified, calculate the average for each bucket.
if (datamerge === 'avg') {
dataset = dataset.map(function (c) {
c[metric] = c[metric] / c['n'];
return c;
});
}
}
$scope.pagecharts[chart.chart] = {
data: dataset,
type: 'serial',
theme: 'light',
marginLeft: 0,
marginRight: 0,
marginTop: 10,
fontFamily: 'Roboto',
categoryField: dimension,
rotate: false,
pathToImages: 'vendor/amchart/images/',
dataDateFormat: $scope.cfg.dateformat,
categoryAxis: {
gridPosition: "start",
parseDates: true,
gridThickness: 0
},
valueAxes: [{
position: "left",
axisAlpha: 0,
labelsEnabled: !chart.hideAxisLabels,
dashLength: 4,
color: '#dedede',
}],
graphs: [{
balloonText: $filter('translate')('metrics.' + metric) + "
[[value]]",
"bullet": "round",
"bulletBorderAlpha": 1,
"bulletColor": "#FFFFFF",
"useLineColorForBulletBorder": true,
"fillAlphas": 0.2,
"lineThickness": 2,
"lineAlpha": 1,
"bulletSize": 7,
"connect": true,
"type": "smoothedLine",
"title": "Expenses",
"valueField": metric,
lineColor: $scope.colors[colorindex],
}],
}
colorindex += 1;
},
fnLineChartMultiple: function (chart, dataset, dimension, metric) {
var d = [];
var dimension2 = (chart.dimension2) ? chart.dimension2 : $scope.cfg.dimensionprefix + $scope.view[chart.dataset].dimension2;
var datamerge = ($scope.gloMetrics[metric] || {}).datemerge;
if (dataset && dataset.length > 62 && datamerge) {
var datesubstr = ($scope.cfg.dateformat == 'YYYYMMDD') ? [0, 4, 4, 6, 6, 8] : [0, 4, 5, 7, 8, 10];
var lastEntry = dataset[dataset.length - 1];
if (lastEntry) {
var lastYear = lastEntry[dimension].toString().substring(datesubstr[0], datesubstr[1]);
var lastMonth = lastEntry[dimension].toString().substring(datesubstr[2], datesubstr[3]);
var lastDay = lastEntry[dimension].toString().substring(datesubstr[4], datesubstr[5]);
var anchorDate = new Date(lastYear, lastMonth - 1, lastDay);
anchorDate.setHours(23, 59, 59, 999);
var MS_PER_DAY = 86400000;
var period = 7;
var bucketMap = {};
var formatBucketKey = function (dateObj) {
var year = dateObj.getFullYear();
var month = ('0' + (dateObj.getMonth() + 1)).slice(-2);
var day = ('0' + dateObj.getDate()).slice(-2);
if ($scope.cfg.dateformat === 'YYYYMMDD') {
return '' + year + month + day;
}
return year + '-' + month + '-' + day;
};
for (var idx = dataset.length - 1; idx >= 0; idx--) {
var row = dataset[idx];
var keyYear = row[dimension].toString().substring(datesubstr[0], datesubstr[1]);
var keyMonth = row[dimension].toString().substring(datesubstr[2], datesubstr[3]);
var keyDay = row[dimension].toString().substring(datesubstr[4], datesubstr[5]);
var currentDate = new Date(keyYear, keyMonth - 1, keyDay);
var daysDifference = (anchorDate.getTime() - currentDate.getTime()) / MS_PER_DAY;
var bucketIndex = Math.floor(daysDifference / period);
var bucketStart = new Date(anchorDate);
bucketStart.setDate(anchorDate.getDate() - (bucketIndex + 1) * period + 1);
var bucketKey = formatBucketKey(bucketStart);
var segment = row[dimension2];
if (!segment) {
continue;
}
bucketMap[bucketKey] = bucketMap[bucketKey] || {};
bucketMap[bucketKey][segment] = bucketMap[bucketKey][segment] || { sum: 0, count: 0 };
bucketMap[bucketKey][segment].sum += parseFloat(row[metric]) || 0;
bucketMap[bucketKey][segment].count += 1;
}
var mergedDataset = [];
var bucketKeys = Object.keys(bucketMap).sort();
for (var kIndex = 0; kIndex < bucketKeys.length; kIndex++) {
var bucketKey = bucketKeys[kIndex];
var segments = bucketMap[bucketKey];
for (var segmentName in segments) {
if (!segments.hasOwnProperty(segmentName)) {
continue;
}
var entry = segments[segmentName];
var value = (datamerge === 'avg' && entry.count > 0) ? entry.sum / entry.count : entry.sum;
if (!isFinite(value)) {
value = 0;
}
var mergedRow = {};
mergedRow[dimension] = bucketKey;
mergedRow[dimension2] = segmentName;
mergedRow[metric] = value;
mergedDataset.push(mergedRow);
}
}
dataset = mergedDataset;
}
}
if (!chart.graphs || !chart.graphs.length) {
var totalsByDimension2 = {};
dataset.forEach(function (row) {
var groupKey = row[dimension2];
if (!groupKey) {
return;
}
var value = parseFloat(row[metric]);
if (isNaN(value)) {
return;
}
totalsByDimension2[groupKey] = (totalsByDimension2[groupKey] || 0) + value;
});
chart.graphs = Object.keys(totalsByDimension2)
.map(function (key) {
return { name: key, total: totalsByDimension2[key] };
})
.sort(function (a, b) { return b.total - a.total; })
.slice(0, 5)
.map(function (item) { return item.name; });
}
for (var i in dataset) {
var row = dataset[i];
d[row[dimension]] = d[row[dimension]] || {};
d[row[dimension]].c = row[dimension];
if (chart.graphs) {
for (var y in chart.graphs) {
if (chart.graphs[y] == row[dimension2]) {
d[row[dimension]]['t' + chart.graphs[y]] = row[metric];
}
}
}
}
console.log('chart', chart);
var b = [];
Object.keys(d).sort().forEach(function (key) {
b.push(d[key]);
});
var graphs = [];
for (var y in chart.graphs) {
// *** FIX: Changed 'var' to 'let' to correctly scope the variable for the closure ***
let segmentName = chart.graphs[y];
graphs.push({
balloonText: chart.graphs[y] + '
' + $filter('translate')('metrics.' + metric) + " [[value]]",
"bullet": "round",
"bulletBorderAlpha": 1,
"bulletColor": "#FFFFFF",
"useLineColorForBulletBorder": true,
"fillAlphas": 0,
"lineThickness": 2,
"lineAlpha": 1,
"bulletSize": 7,
"title": "Expenses",
"valueField": 't' + chart.graphs[y],
lineColor: $scope.colors[y],
stacked: false,
balloonFunction: function (item) {
var dateLabel = $filter('date')(item.category, 'yyyy-MM-dd');
var rawValue = item.values.value;
var formatted = $filter('useFilter')(
rawValue,
$scope.gloMetrics[metric].typefilter,
$scope.gloMetrics[metric].filtercomparator
);
var suffix = $scope.gloMetrics[metric].after || '';
return (
'' +
'
' + segmentName + '
' + // This will now use the correct segmentName
'
' + dateLabel + '
' +
'
' +
$filter('translate')('metrics.' + metric) +
': ' + formatted + suffix + '' +
'
' +
'
'
);
}
});
if (chart.graphs[y] == 'male') {
graphs[y].lineColor = '#3F51B5';
}
if (chart.graphs[y] == 'female') {
graphs[y].lineColor = '#E91E63';
}
}
$scope.pagecharts[chart.chart] = {
data: b,
type: 'serial',
theme: 'light',
marginLeft: 0,
marginRight: 0,
marginTop: 10,
fontFamily: 'Roboto',
categoryField: 'c',
rotate: false,
pathToImages: 'vendor/amchart/images/',
dataDateFormat: $scope.cfg.dateformat,
legend: {
enabled: false
},
categoryAxis: {
gridPosition: "start",
parseDates: true,
labelRotation: 45
},
valueAxes: [{
position: "left",
axisAlpha: 0,
labelsEnabled: true,
}],
graphs: graphs,
};
if (chart.stacked) {
$scope.pagecharts[chart.chart].valueAxes[0].stackType = "regular";
}
},
fnBarChart: function (chart, dataset, dimension, metric) {
//inject color attribute with value
if (typeof $scope.analytics[chart.dataset].data != undefined) {
for (var i = 0; i < $scope.analytics[chart.dataset].data.length; i++) { $scope.analytics[chart.dataset].data[i].color = $scope.colors[i]; }
}
$scope.pagecharts[chart.chart] = {
data: dataset.slice(0, 6),
type: 'serial',
theme: 'light',
marginLeft: 0,
marginRight: 0,
marginTop: 10,
fontFamily: 'Roboto',
categoryField: dimension,
rotate: false,
pathToImages: 'vendor/amchart/images/',
dataDateFormat: $scope.cfg.dateformat,
legend: {
enabled: false
},
categoryAxis: {
gridPosition: "start",
parseDates: false,
labelRotation: 0,
gridThickness: 0,
labelFunction: function (value, valueText, axis) { return (value.length > 19) ? value.substr(0, 17) + '...' : value },
},
valueAxes: [{
position: "left",
axisAlpha: 0,
labelsEnabled: true,
dashLength: 4,
color: '#dedede',
}],
graphs: [{
fillColorsField: "color",
balloonText: "[[category]]: [[value]]",
type: "column",
columnWidth: 0.40,
title: "Zoekwoord waarde",
valueField: metric,
fillAlphas: 1,
lineColor: '#009688',
autoColor: true,
}],
}
},
fnPieChart: function (chart, dataset, dimension, metric) {
$scope.pagecharts[chart.chart] = {
data: dataset.slice(0, 9),
type: 'pie',
theme: 'light',
marginLeft: 0,
marginRight: 0,
marginTop: 10,
fontFamily: 'Roboto',
categoryField: dimension,
pathToImages: 'vendor/amchart/images/',
"precision": 0,
"decimalSeparator": ",",
"thousandsSeparator": ".",
legend: {
enabled: true,
position: 'right',
autoMargins: false,
marginRight: 100,
},
titleField: dimension,
valueField: metric,
labelRadius: 5,
radius: '42%',
innerRadius: '60%',
labelText: '[[title]]',
}
}
}
$scope.fnAddChart = function (name, functionname) {
_charts[name] = functionname;
}
// Grafieken voor een metric. Heeft de view er geen eigen grafiek voor (veel views noemen alleen een paar
// metrics in view.charts), dan dezelfde grafieken als de standaardmetric van de view, met de naam van deze
// metric; een taart wordt een staaf bij een gemiddelde of percentage.
var fnChartsFor = function (metric) {
if (!$scope.view || !$scope.view.charts) {
return {};
}
if ($scope.view.charts[metric]) {
return $scope.view.charts[metric];
}
var base = $scope.view.charts[$scope.view.selectedmetric] || $scope.view.charts[Object.keys($scope.view.charts)[0]];
if (!Array.isArray(base)) {
return {};
}
var label = $filter('translate')('metrics.' + metric);
if (label === 'metrics.' + metric) {
label = (($scope.gloMetrics || {})[metric] || {}).name || metric;
}
var avg = ((($scope.gloMetrics || {})[metric]) || {}).datemerge === 'avg';
$scope.view.charts[metric] = base.map(function (chart) {
var copy = angular.extend({}, chart, {
name: chart.name === '_' ? '_' : label,
type: (chart.type === 'pie' && avg) ? 'bar' : chart.type
});
delete copy.metric;
return copy;
});
return $scope.view.charts[metric];
}
$scope.fnSwitchMetric = function (selectedmetric) {
$scope.metric = selectedmetric;
$scope.charts = fnChartsFor($scope.metric);
if ($scope.view && $scope.view.fullchart && Array.isArray($scope.charts)) {
var hasActive = false;
for (var idx = 0; idx < $scope.charts.length; idx++) {
if ($scope.charts[idx].active) {
hasActive = true;
break;
}
}
if (!hasActive && $scope.charts.length) {
$scope.charts[0].active = true;
}
}
var reverse = ($scope.gloMetrics[selectedmetric].reverse === true || $scope.gloMetrics[selectedmetric].reverse === false) ? $scope.gloMetrics[selectedmetric].reverse : true;
$scope.order = { order: selectedmetric, 'reverse': reverse };
for (var i in $scope.charts) {
fnMakeChart($scope.charts[i]);
}
}
$scope.fnActivateChart = function (chart) {
if (!$scope.charts || !chart) {
return;
}
angular.forEach($scope.charts, function (item) {
item.active = false;
});
chart.active = true;
fnMakeChart(chart);
}
$scope.fnConnect = function () {
window.location.replace($scope.cfg.authurl + '&h=/' + $scope.cfg.urlbase + '/' + $scope.urlreport + '/' + $scope.urlview);
}
$scope.getReportData = function () {
getReportData();
}
$scope.fnMakeChart = function (chart) {
fnMakeChart(chart);
}
$scope.fnPctChange = function (o, n) {
if (n == 0) {
return '0%';
}
var pct = ((n - o) / o) * 100;
var npct = $filter('number')(pct, 2);
if (pct < 0) {
return '' + npct + '%';
}
return '+ ' + npct + '%';
}
$scope.fnSaveSelectedMetrics = function () {
$http.post('/rest/api-core/selectedmetrics.set', {
websiteid: h.siteId(),
'type': $scope.cfg.urlbase,
'view': $scope.urlreport + '-' + $scope.urlview,
'selectedmetrics': $scope.selectedmetrics,
});
}
$scope.fnRemoveViewfilter = function (type) {
delete $scope.viewfilters[type];
getReportData();
}
$scope.init = function () {
if ($scope.custominit) {
$scope.urlreport = $scope.custominit.urlreport;
$scope.urlview = $scope.custominit.urlview;
}
/* set selection of view metric and chart*/
$scope.views = $scope.reportconfig[$scope.urlreport].views;
$scope.view = $scope.reportconfig[$scope.urlreport].views[$scope.urlview];
/* selected wmetrics ophalen ...... aparte functie ... ?*/
$scope.selectedmetrics = $scope.view.selectedmetrics;
$http.get('/rest/api-core/selectedmetrics.get', {
params: {
websiteid: h.siteId(),
'type': $scope.cfg.urlbase,
'view': $scope.urlreport + '-' + $scope.urlview,
}
}).then(function successCallback(res) {
if (res.data.data !== null) {
$scope.selectedmetrics = res.data.data;
}
});
$scope.metrics = $scope.view.metrics;
$scope.metric = $scope.view.selectedmetric;
// een link vanaf het dashboard (?metric=sessions) opent de pagina op die metriek; alleen bij het openen
var asked = $location.search().metric;
if (asked && ($scope.view.metrics || []).indexOf(asked) > -1) {
$scope.metric = asked;
}
$scope.order = { order: $scope.metric, reverse: true };
$scope.charts = fnChartsFor($scope.metric);
getReportData();
}
var l = {
"ab": "Abkhaz",
"aa": "Afar",
"af": "Afrikaans",
"ak": "Akan",
"sq": "Albanian",
"am": "Amharic",
"ar": "Arabic",
"an": "Aragonese",
"hy": "Armenian",
"as": "Assamese",
"av": "Avaric",
"ae": "Avestan",
"ay": "Aymara",
"az": "Azerbaijani",
"bm": "Bambara",
"ba": "Bashkir",
"eu": "Basque",
"be": "Belarusian",
"bn": "Bengali; Bangla",
"bh": "Bihari",
"bi": "Bislama",
"bs": "Bosnian",
"br": "Breton",
"bg": "Bulgarian",
"my": "Burmese",
"ca": "Catalan; Valencian",
"ch": "Chamorro",
"ce": "Chechen",
"ny": "Chichewa; Chewa; Nyanja",
"zh": "Chinese",
"cv": "Chuvash",
"kw": "Cornish",
"co": "Corsican",
"cr": "Cree",
"hr": "Croatian",
"cs": "Czech",
"da": "Danish",
"dv": "Divehi; Dhivehi; Maldivian;",
"nl": "Nederlands",
"dz": "Dzongkha",
"en": "English",
"eo": "Esperanto",
"et": "Estonian",
"ee": "Ewe",
"fo": "Faroese",
"fj": "Fijian",
"fi": "Finnish",
"fr": "French",
"ff": "Fula; Fulah; Pulaar; Pular",
"gl": "Galician",
"ka": "Georgian",
"de": "German",
"el": "Greek, Modern",
"gn": "GuaranÃ",
"gu": "Gujarati",
"ht": "Haitian; Haitian Creole",
"ha": "Hausa",
"he": "Hebrew (modern)",
"hz": "Herero",
"hi": "Hindi",
"ho": "Hiri Motu",
"hu": "Hungarian",
"ia": "Interlingua",
"id": "Indonesian",
"ie": "Interlingue",
"ga": "Irish",
"ig": "Igbo",
"ik": "Inupiaq",
"io": "Ido",
"is": "Icelandic",
"it": "Italian",
"iu": "Inuktitut",
"ja": "Japanese",
"jv": "Javanese",
"kl": "Kalaallisut, Greenlandic",
"kn": "Kannada",
"kr": "Kanuri",
"ks": "Kashmiri",
"kk": "Kazakh",
"km": "Khmer",
"ki": "Kikuyu, Gikuyu",
"rw": "Kinyarwanda",
"ky": "Kyrgyz",
"kv": "Komi",
"kg": "Kongo",
"ko": "Korean",
"ku": "Kurdish",
"kj": "Kwanyama, Kuanyama",
"la": "Latin",
"lb": "Luxembourgish, Letzeburgesch",
"lg": "Ganda",
"li": "Limburgish, Limburgan, Limburger",
"ln": "Lingala",
"lo": "Lao",
"lt": "Lithuanian",
"lu": "Luba-Katanga",
"lv": "Latvian",
"gv": "Manx",
"mk": "Macedonian",
"mg": "Malagasy",
"ms": "Malay",
"ml": "Malayalam",
"mt": "Maltese",
"mi": "MÄori",
"mr": "Marathi (MarÄá¹hÄ«)",
"mh": "Marshallese",
"mn": "Mongolian",
"na": "Nauru",
"nv": "Navajo, Navaho",
"nb": "Norwegian Bokmål",
"nd": "North Ndebele",
"ne": "Nepali",
"ng": "Ndonga",
"nn": "Norwegian Nynorsk",
"no": "Norwegian",
"ii": "Nuosu",
"nr": "South Ndebele",
"oc": "Occitan",
"oj": "Ojibwe, Ojibwa",
"cu": "Old Church Slavonic, Church Slavic, Church Slavonic, Old Bulgarian, Old Slavonic",
"om": "Oromo",
"or": "Oriya",
"os": "Ossetian, Ossetic",
"pa": "Panjabi, Punjabi",
"pi": "PÄli",
"fa": "Persian (Farsi)",
"pl": "Polish",
"ps": "Pashto, Pushto",
"pt": "Portuguese",
"qu": "Quechua",
"rm": "Romansh",
"rn": "Kirundi",
"ro": "Romanian",
"ru": "Russian",
"sa": "Sanskrit (Saá¹ská¹›ta)",
"sc": "Sardinian",
"sd": "Sindhi",
"se": "Northern Sami",
"sm": "Samoan",
"sg": "Sango",
"sr": "Serbian",
"gd": "Scottish Gaelic; Gaelic",
"sn": "Shona",
"si": "Sinhala, Sinhalese",
"sk": "Slovak",
"sl": "Slovene",
"so": "Somali",
"st": "Southern Sotho",
"az": "South Azerbaijani",
"es": "Spanish; Castilian",
"su": "Sundanese",
"sw": "Swahili",
"ss": "Swati",
"sv": "Swedish",
"ta": "Tamil",
"te": "Telugu",
"tg": "Tajik",
"th": "Thai",
"ti": "Tigrinya",
"bo": "Tibetan Standard, Tibetan, Central",
"tk": "Turkmen",
"tl": "Tagalog",
"tn": "Tswana",
"to": "Tonga (Tonga Islands)",
"tr": "Turkish",
"ts": "Tsonga",
"tt": "Tatar",
"tw": "Twi",
"ty": "Tahitian",
"ug": "Uyghur, Uighur",
"uk": "Ukrainian",
"ur": "Urdu",
"uz": "Uzbek",
"ve": "Venda",
"vi": "Vietnamese",
"vo": "Volapük",
"wa": "Walloon",
"cy": "Welsh",
"wo": "Wolof",
"fy": "Western Frisian",
"xh": "Xhosa",
"yi": "Yiddish",
"yo": "Yoruba",
"za": "Zhuang, Chuang",
"zu": "Zulu"
};
var c = {
"AF": "Afghanistan",
"AX": "Åland",
"AL": "Albanië",
"DZ": "Algerije",
"VI": "Amerikaanse Maagdeneilanden",
"AS": "Amerikaans-Samoa",
"AD": "Andorra",
"AO": "Angola",
"AI": "Anguilla",
"AQ": "Antarctica",
"AG": "Antigua en Barbuda",
"AR": "Argentinië",
"AM": "Armenië",
"AW": "Aruba",
"AU": "Australië",
"AZ": "Azerbeidzjan",
"BS": "Bahama's",
"BH": "Bahrein",
"BD": "Bangladesh",
"BB": "Barbados",
"BE": "België",
"BZ": "Belize",
"BJ": "Benin",
"BM": "Bermuda",
"BT": "Bhutan",
"BO": "Bolivia",
"BQ": "Bonaire, Sint Eustatius en Saba",
"BA": "Bosnië en Herzegovina",
"BW": "Botswana",
"BV": "Bouvet",
"BR": "Brazilië",
"VG": "Britse Maagdeneilanden",
"IO": "Brits Indische Oceaanterritorium",
"BN": "Brunei",
"BG": "Bulgarije",
"BF": "Burkina Faso",
"BI": "Burundi",
"KH": "Cambodja",
"CA": "Canada",
"CF": "Centraal-Afrikaanse Republiek",
"CL": "Chili",
"CN": "China",
"CX": "Christmaseiland",
"CC": "Cocoseilanden",
"CO": "Colombia",
"KM": "Comoren",
"CG": "Congo-Brazzaville",
"CD": "Congo-Kinshasa",
"CK": "Cookeilanden",
"CR": "Costa Rica",
"CU": "Cuba",
"CW": "Curaçao",
"CY": "Cyprus",
"DK": "Denemarken",
"DJ": "Djibouti",
"DM": "Dominica",
"DO": "Dominicaanse Republiek",
"DE": "Duitsland",
"EC": "Ecuador",
"EG": "Egypte",
"SV": "El Salvador",
"GQ": "Equatoriaal-Guinea",
"ER": "Eritrea",
"EE": "Estland",
"ET": "Ethiopië",
"FO": "Faeröer",
"FK": "Falklandeilanden",
"FJ": "Fiji",
"PH": "Filipijnen",
"FI": "Finland",
"FR": "Frankrijk",
"TF": "Franse Zuidelijke en Antarctische Gebiede",
"GF": "Frans-Guyana",
"PF": "Frans-Polynesië",
"GA": "Gabon",
"GM": "Gambia",
"GE": "Georgië",
"GH": "Ghana",
"GI": "Gibraltar",
"GD": "Grenada",
"GR": "Griekenland",
"GL": "Groenland",
"GP": "Guadeloupe",
"GU": "Guam",
"GT": "Guatemala",
"GG": "Guernsey",
"GN": "Guinee",
"GW": "Guinee-Bissau",
"GY": "Guyana",
"HT": "Haïti",
"HM": "Heard en McDonaldeilanden",
"HN": "Honduras",
"HU": "Hongarije",
"HK": "Hongkong",
"IE": "Ierland",
"IS": "IJsland",
"IN": "India",
"ID": "Indonesië",
"IQ": "Irak",
"IR": "Iran",
"IL": "Israël",
"IT": "Italië",
"CI": "Ivoorkust",
"JM": "Jamaica",
"JP": "Japan",
"YE": "Jemen",
"JE": "Jersey",
"JO": "Jordanië",
"KY": "Kaaimaneilanden",
"CV": "Kaapverdië",
"CM": "Kameroen",
"KZ": "Kazachstan",
"KE": "Kenia",
"KG": "Kirgizië",
"KI": "Kiribati",
"UM": "Kleine afgelegen eilanden van de Verenigde Staten",
"KW": "Koeweit",
"XK": "Kosovo",
"HR": "Kroatië",
"LA": "Laos",
"LS": "Lesotho",
"LV": "Letland",
"LB": "Libanon",
"LR": "Liberia",
"LY": "Libië",
"LI": "Liechtenstein",
"LT": "Litouwen",
"LU": "Luxemburg",
"MO": "Macau",
"MK": "Macedonië",
"MG": "Madagaskar",
"MW": "Malawi",
"MV": "Maldiven",
"MY": "Maleisië",
"ML": "Mali",
"MT": "Malta",
"IM": "Man",
"MA": "Marokko",
"MH": "Marshalleilanden",
"MQ": "Martinique",
"MR": "Mauritanië",
"MU": "Mauritius",
"YT": "Mayotte",
"MX": "Mexico",
"FM": "Micronesia",
"MD": "Moldavië",
"MC": "Monaco",
"MN": "Mongolië",
"ME": "Montenegro",
"MS": "Montserrat",
"MZ": "Mozambique",
"MM": "Myanmar",
"NA": "Namibië",
"NR": "Nauru",
"NL": "Nederland",
"NP": "Nepal",
"NI": "Nicaragua",
"NC": "Nieuw-Caledonië",
"NZ": "Nieuw-Zeeland",
"NE": "Niger",
"NG": "Nigeria",
"NU": "Niue",
"MP": "Noordelijke Marianen",
"KP": "Noord-Korea",
"NO": "Noorwegen",
"NF": "Norfolk",
"UG": "Oeganda",
"UA": "Oekraïne",
"UZ": "Oezbekistan",
"OM": "Oman",
"AT": "Oostenrijk",
"TL": "Oost-Timor",
"PK": "Pakistan",
"PW": "Palau",
"PS": "Palestina",
"PA": "Panama",
"PG": "Papua-Nieuw-Guinea",
"PY": "Paraguay",
"PE": "Peru",
"PN": "Pitcairneilanden",
"PL": "Polen",
"PT": "Portugal",
"PR": "Puerto Rico",
"QA": "Qatar",
"RE": "Réunion",
"RO": "Roemenië",
"RU": "Rusland",
"RW": "Rwanda",
"BL": "Saint-Barthélemy",
"KN": "Saint Kitts en Nevis",
"LC": "Saint Lucia",
"PM": "Saint-Pierre en Miquelon",
"VC": "Saint Vincent en de Grenadines",
"SB": "Salomonseilanden",
"WS": "Samoa",
"SM": "San Marino",
"SA": "Saoedi-Arabië",
"ST": "Sao Tomé en Principe",
"SN": "Senegal",
"RS": "Servië",
"SC": "Seychellen",
"SL": "Sierra Leone",
"SG": "Singapore",
"SH": "Sint-Helena, Ascension en Tristan da Cunha",
"MF": "Sint-Maarten",
"SX": "Sint Maarten",
"SI": "Slovenië",
"SK": "Slowakije",
"SD": "Soedan",
"SO": "Somalië",
"ES": "Spanje",
"SJ": "Spitsbergen en Jan Mayen",
"LK": "Sri Lanka",
"SR": "Suriname",
"SZ": "Swaziland",
"SY": "Syrië",
"TJ": "Tadzjikistan",
"TW": "Taiwan",
"TZ": "Tanzania",
"TH": "Thailand",
"TG": "Togo",
"TK": "Tokelau",
"TO": "Tonga",
"TT": "Trinidad en Tobago",
"TD": "Tsjaad",
"CZ": "Tsjechië",
"TN": "Tunesië",
"TR": "Turkije",
"TM": "Turkmenistan",
"TC": "Turks- en Caicoseilanden",
"TV": "Tuvalu",
"UY": "Uruguay",
"VU": "Vanuatu",
"VA": "Vaticaanstad",
"VE": "Venezuela",
"AE": "Verenigde Arabische Emiraten",
"US": "Verenigde Staten",
"GB": "Verenigd Koninkrijk",
"VN": "Vietnam",
"WF": "Wallis en Futuna",
"EH": "Westelijke Sahara",
"BY": "Wit-Rusland",
"ZM": "Zambia",
"ZW": "Zimbabwe",
"ZA": "Zuid-Afrika",
"GS": "Zuid-Georgia en de Zuidelijke Sandwicheilanden",
"KR": "Zuid-Korea",
"SS": "Zuid-Soedan",
"SE": "Zweden",
"CH": "Zwitserland",
};
$scope.fnLC = function (a) {
var b = a.split("_");
return l[b[0]];
}
$scope.fnC = function (a) {
return c[a];
}
}
]);
app.controller('analytics', ['$scope', '$timeout', '$http', '$rootScope', '$controller', '$filter', 'h',
function($scope, $timeout, $http, $rootScope, $controller, $filter, h) {
$scope.cfg = {
authurl: 'https://app.pageowl.app/rest/analytics/connect?websiteid=' + h.siteId(),
dateformat: "YYYYMMDD",
dimensionprefix: 'ga:',
urlbase: 'analytics',
switchclient: true,
report_endpoint: '/rest/analytics/v4',
}
$scope.gloMetrics = h.metrics('analytics');
/* $scope.gloMetrics = {
sessions: { name: 'Sessions', typefilter: 'number', filtercomparator: 0 ,'datemerge':'sum'},
users: { name: 'Users', typefilter: 'number', filtercomparator: 0 ,'datemerge':'sum'},
pageviews: { name: 'Pageviews', typefilter: 'number', filtercomparator: 0 ,'datemerge':'sum'},
pageviewsPerSession: { name: 'Pageviews / session', typefilter: 'number', filtercomparator: 2 ,'datemerge':'avg'},
avgSessionDuration: { name: 'Average session duration', typefilter: 'secondsToHHmmss', filtercomparator: 0 ,'datemerge':'avg'},
percentNewSessions: { name: 'Percentrage new sessions', typefilter: 'number', filtercomparator: 0, 'after': '%' ,'datemerge':'avg'},
bounceRate: { name: 'Bounce Ratio', typefilter: 'number', filtercomparator: 0, 'after': '%' ,'datemerge':'avg'},
goalCompletionsAll: { name: 'Goals', typefilter: 'number', filtercomparator: 0 ,'datemerge':'sum'},
goalValueAll: { name: 'Goalvalue', typefilter: 'number', filtercomparator: 0 ,'datemerge':'sum'},
goalConversionRateAll: { name: 'Goalconversion ratio', typefilter: 'number', filtercomparator: 0, 'after': '%' ,'datemerge':'avg'},
goalAbandonRateAll: { name: 'Doel verlatings ratio', typefilter: 'number', filtercomparator: 0, 'after': '%' ,'datemerge':'avg'},
uniquePageviews: { name: 'Unique Pageviews', typefilter: 'number', filtercomparator: 0 ,'datemerge':'sum'},
avgTimeOnPage: { name: 'Avg time on page', typefilter: 'secondsToHHmmss', filtercomparator: 0 ,'datemerge':'avg'},
entrances: { name: 'Entrances', typefilter: 'number', filtercomparator: 0 ,'datemerge':'sum'},
exitRate: { name: 'Exit rate', typefilter: 'number', filtercomparator: 0, 'after': '%' ,'datemerge':'avg'},
pageValue: { name: 'Pagevalue', typefilter: 'number', filtercomparator: 0 ,'datemerge':'sum'},
exits: { name: 'Exits', typefilter: 'number', filtercomparator: 0 ,'datemerge':'sum'},
ROAS: { name: 'ROAS', typefilter: 'number', filtercomparator: 0 ,'datemerge':'avg'},
costPerTransaction: { name: 'Cost per transaction', typefilter: 'number', filtercomparator: 0 ,'datemerge':'avg'},
totalValue: { name: 'Total value', typefilter: 'number', filtercomparator: 0 ,'datemerge':'sum'},
adCost: { name: 'Ad Cost', typefilter: 'number', filtercomparator: 0 ,'datemerge':'sum'},
CPC: { name: 'CPC', typefilter: 'number', filtercomparator: 0 ,'datemerge':'avg'},
adClicks: { name: 'Ad Clicks', typefilter: 'number', filtercomparator: 0 ,'datemerge':'sum'},
transactions: { name: 'Transacions', typefilter: 'number', filtercomparator: 0 ,'datemerge':'sum'},
uniquePurchases: { name: 'Unique Purchases', typefilter: 'number', filtercomparator: 0 ,'datemerge':'sum'},
totalValue: { name: 'Total Value', typefilter: 'number', filtercomparator: 0 ,'datemerge':'sum'},
revenuePerTransaction: { name: 'Revenue per Transaction', typefilter: 'number', filtercomparator: 0 ,'datemerge':'avg'},
itemQuantity: { name: 'Item Quentity', typefilter: 'number', filtercomparator: 0 ,'datemerge':'sum'},
itemsPerPurchase: { name: 'items / purchase', typefilter: 'number', filtercomparator: 0 ,'datemerge':'avg'},
};*/
$scope.selectedmetrics = {};
$scope.reportconfig = {
channels: {
views: {
all: {
name: 'All',
view: 'all',
viewfilters: ['goals'],
first: { dimension: 'date' },
second: { dimension: 'channelGrouping', sort: 'sessions', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'sessions',
selectedmetrics: { 'sessions': true, 'users': true, 'pageviews': true, 'pageviewsPerSession': true, 'avgSessionDuration': true, 'percentNewSessions': true, 'bounceRate': true, 'goalCompletionsAll': true, 'goalValueAll': true, 'goalConversionRateAll': true },
metrics: ['sessions', 'users', 'pageviews', 'pageviewsPerSession', 'avgSessionDuration', 'percentNewSessions', 'bounceRate', 'goalCompletionsAll', 'goalValueAll', 'goalConversionRateAll'],
table: { dataset: 'second' },
panels: { dataset: 'second' },
charts: {
sessions: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions / channel', type: 'pie', dataset: 'second' }],
users: [{ 'chart': 'c1', 'name': 'Users', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Users / channel', type: 'pie', dataset: 'second' }],
pageviews: [{ 'chart': 'c1', 'name': 'Pagina weergaven', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Pageviews / channel', type: 'pie', dataset: 'second' }],
pageviewsPerSession: [{ 'chart': 'c1', 'name': 'Pageviews per session', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Pageviews per session /channel', type: 'bar', dataset: 'second' }],
avgSessionDuration: [{ 'chart': 'c1', 'name': 'Average session duration', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
percentNewSessions: [{ 'chart': 'c1', 'name': 'Percentage new Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
bounceRate: [{ 'chart': 'c1', 'name': 'Bounce ratio', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
goalCompletionsAll: [{ 'chart': 'c1', 'name': 'Goals', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
goalValueAll: [{ 'chart': 'c1', 'name': 'Goalvalue', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
goalConversionRateAll: [{ 'chart': 'c1', 'name': 'Goalconverions ratio', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
},
},
organic: {
name: 'Organic',
view: 'organic',
viewfilters: ['goals'],
first: { dimension: 'date', channel: 'Organic Search' },
second: { dimension: 'keyword', channel: 'Organic Search', sort: 'users', sortorder: 'DESCENDING' },
third: { dimension: 'source', channel: 'Organic Search', sort: 'users', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'sessions',
selectedmetrics: { 'sessions': true, 'users': true, 'pageviews': true, 'pageviewsPerSession': true, 'avgSessionDuration': true, 'percentNewSessions': true, 'bounceRate': true, 'goalCompletionsAll': true, 'goalValueAll': true, 'goalConversionRateAll': true },
metrics: ['sessions', 'users', 'pageviews', 'pageviewsPerSession', 'avgSessionDuration', 'percentNewSessions', 'bounceRate', 'goalCompletionsAll', 'goalValueAll', 'goalConversionRateAll'],
table: { dataset: 'second' },
panels: { dataset: 'third' },
charts: {
sessions: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'third' }],
users: [{ 'chart': 'c1', 'name': 'Users', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'third' }],
pageviews: [{ 'chart': 'c1', 'name': 'PageViews', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'third' }],
pageviewsPerSession: [{ 'chart': 'c1', 'name': 'Pageviews per session', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'third' }],
avgSessionDuration: [{ 'chart': 'c1', 'name': 'Average session duration', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'third' }],
percentNewSessions: [{ 'chart': 'c1', 'name': 'Percentage new Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'third' }],
bounceRate: [{ 'chart': 'c1', 'name': 'Bounce ratio', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'third' }],
goalCompletionsAll: [{ 'chart': 'c1', 'name': 'Goals', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'third' }],
goalValueAll: [{ 'chart': 'c1', 'name': 'Goalvalue', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'third' }],
goalConversionRateAll: [{ 'chart': 'c1', 'name': 'Goalconverions ratio', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'third' }],
},
},
paid: {
name: 'Betaalde zoekopdrachten',
view: 'paid',
viewfilters: ['goals'],
first: { dimension: 'date', channel: 'Paid Search' },
second: { dimension: 'keyword', channel: 'Paid Search', sort: 'sessions', sortorder: 'DESCENDING' },
third: { dimension: 'year', channel: 'Paid Search', sort: 'sessions', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'sessions',
selectedmetrics: { 'sessions': true, 'users': true, 'pageviews': true, 'pageviewsPerSession': true, 'avgSessionDuration': true, 'percentNewSessions': true, 'bounceRate': true, 'goalCompletionsAll': true, 'goalValueAll': true, 'goalConversionRateAll': true },
metrics: ['sessions', 'users', 'pageviews', 'pageviewsPerSession', 'avgSessionDuration', 'percentNewSessions', 'bounceRate', 'goalCompletionsAll', 'goalValueAll', 'goalConversionRateAll'],
table: { dataset: 'second' },
panels: { dataset: 'third' },
charts: {
sessions: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions', type: 'pie', dataset: 'second' }],
users: [{ 'chart': 'c1', 'name': 'Users', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviews: [{ 'chart': 'c1', 'name': 'PageViews', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviewsPerSession: [{ 'chart': 'c1', 'name': 'Pageviews per session', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
avgSessionDuration: [{ 'chart': 'c1', 'name': 'Average session duration', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
percentNewSessions: [{ 'chart': 'c1', 'name': 'Percentage new Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
bounceRate: [{ 'chart': 'c1', 'name': 'Bounce ratio', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
goalCompletionsAll: [{ 'chart': 'c1', 'name': 'Goals', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
goalValueAll: [{ 'chart': 'c1', 'name': 'Goalvalue', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
goalConversionRateAll: [{ 'chart': 'c1', 'name': 'Goalconverions ratio', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
},
},
display: {
name: 'Display',
view: 'display',
viewfilters: ['goals'],
first: { dimension: 'date', channel: 'Display' },
second: { dimension: 'source', channel: 'Display', sort: 'sessions', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'sessions',
selectedmetrics: { 'sessions': true, 'users': true, 'pageviews': true, 'pageviewsPerSession': true, 'avgSessionDuration': true, 'percentNewSessions': true, 'bounceRate': true, 'goalCompletionsAll': true, 'goalValueAll': true, 'goalConversionRateAll': true },
metrics: ['sessions', 'users', 'pageviews', 'pageviewsPerSession', 'avgSessionDuration', 'percentNewSessions', 'bounceRate', 'goalCompletionsAll', 'goalValueAll', 'goalConversionRateAll'],
table: { dataset: 'second' },
panels: { dataset: 'second' },
charts: {
sessions: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions', type: 'pie', dataset: 'second' }],
users: [{ 'chart': 'c1', 'name': 'Users', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviews: [{ 'chart': 'c1', 'name': 'PageViews', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviewsPerSession: [{ 'chart': 'c1', 'name': 'Pageviews per session', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
avgSessionDuration: [{ 'chart': 'c1', 'name': 'Average session duration', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
percentNewSessions: [{ 'chart': 'c1', 'name': 'Percentage new Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
bounceRate: [{ 'chart': 'c1', 'name': 'Bounce ratio', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
goalCompletionsAll: [{ 'chart': 'c1', 'name': 'Goals', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
goalValueAll: [{ 'chart': 'c1', 'name': 'Goalvalue', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
goalConversionRateAll: [{ 'chart': 'c1', 'name': 'Goalconverions ratio', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
},
},
social: {
name: 'Social',
view: 'social',
viewfilters: ['goals'],
first: { dimension: 'date', channel: 'Social' },
second: { dimension: 'socialNetwork', channel: 'Social', sort: 'sessions', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'sessions',
selectedmetrics: { 'sessions': true, 'users': true, 'pageviews': true, 'pageviewsPerSession': true, 'avgSessionDuration': true, 'percentNewSessions': true, 'bounceRate': true, 'goalCompletionsAll': true, 'goalValueAll': true, 'goalConversionRateAll': true },
metrics: ['sessions', 'users', 'pageviews', 'pageviewsPerSession', 'avgSessionDuration', 'percentNewSessions', 'bounceRate', 'goalCompletionsAll', 'goalValueAll', 'goalConversionRateAll'],
table: { dataset: 'second' },
panels: { dataset: 'second' },
charts: {
sessions: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions', type: 'pie', dataset: 'second' }],
users: [{ 'chart': 'c1', 'name': 'Users', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviews: [{ 'chart': 'c1', 'name': 'PageViews', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviewsPerSession: [{ 'chart': 'c1', 'name': 'Pageviews per session', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
avgSessionDuration: [{ 'chart': 'c1', 'name': 'Average session duration', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
percentNewSessions: [{ 'chart': 'c1', 'name': 'Percentage new Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
bounceRate: [{ 'chart': 'c1', 'name': 'Bounce ratio', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
goalCompletionsAll: [{ 'chart': 'c1', 'name': 'Goals', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
goalValueAll: [{ 'chart': 'c1', 'name': 'Goalvalue', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
goalConversionRateAll: [{ 'chart': 'c1', 'name': 'Goalconverions ratio', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
},
},
referral: {
name: 'Referral',
view: 'referral',
viewfilters: ['goals'],
first: { dimension: 'date', channel: 'Referral', sort: 'date', sortorder: 'ASCENDING', },
second: { dimension: 'source', channel: 'Referral', sort: 'sessions', sortorder: 'DESCENDING' },
third: { dimension: 'year', channel: 'Referral', sort: 'year', sortorder: 'ASCENDING', 'allowcomp': true },
selectedmetric: 'sessions',
selectedmetrics: { 'sessions': true, 'users': true, 'pageviews': true, 'pageviewsPerSession': true, 'avgSessionDuration': true, 'percentNewSessions': true, 'bounceRate': true, 'goalCompletionsAll': true, 'goalValueAll': true, 'goalConversionRateAll': true },
metrics: ['sessions', 'users', 'pageviews', 'pageviewsPerSession', 'avgSessionDuration', 'percentNewSessions', 'bounceRate', 'goalCompletionsAll', 'goalValueAll', 'goalConversionRateAll'],
table: { dataset: 'second' },
panels: { dataset: 'third' },
charts: {
sessions: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
users: [{ 'chart': 'c1', 'name': 'Users', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviews: [{ 'chart': 'c1', 'name': 'PageViews', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviewsPerSession: [{ 'chart': 'c1', 'name': 'Pageviews per session', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
avgSessionDuration: [{ 'chart': 'c1', 'name': 'Average session duration', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
percentNewSessions: [{ 'chart': 'c1', 'name': 'Percentage new Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
bounceRate: [{ 'chart': 'c1', 'name': 'Bounce ratio', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
goalCompletionsAll: [{ 'chart': 'c1', 'name': 'Goals', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
goalValueAll: [{ 'chart': 'c1', 'name': 'Goalvalue', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
goalConversionRateAll: [{ 'chart': 'c1', 'name': 'Goalconverions ratio', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
},
},
email: {
name: 'E-mail',
view: 'email',
viewfilters: ['goals'],
first: { dimension: 'date', channel: 'Email' },
second: { dimension: 'source', channel: 'Email', sort: 'sessions', sortorder: 'DESCENDING', },
third: { dimension: 'year', channel: 'Email', sort: 'year', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'sessions',
selectedmetrics: { 'sessions': true, 'users': true, 'pageviews': true, 'pageviewsPerSession': true, 'avgSessionDuration': true, 'percentNewSessions': true, 'bounceRate': true, 'goalCompletionsAll': true, 'goalValueAll': true, 'goalConversionRateAll': true },
metrics: ['sessions', 'users', 'pageviews', 'pageviewsPerSession', 'avgSessionDuration', 'percentNewSessions', 'bounceRate', 'goalCompletionsAll', 'goalValueAll', 'goalConversionRateAll'],
table: { dataset: 'second' },
panels: { dataset: 'third' },
charts: {
sessions: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions', type: 'pie', dataset: 'second' }],
users: [{ 'chart': 'c1', 'name': 'Users', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviews: [{ 'chart': 'c1', 'name': 'PageViews', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviewsPerSession: [{ 'chart': 'c1', 'name': 'Pageviews per session', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
avgSessionDuration: [{ 'chart': 'c1', 'name': 'Average session duration', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
percentNewSessions: [{ 'chart': 'c1', 'name': 'Percentage new Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
bounceRate: [{ 'chart': 'c1', 'name': 'Bounce ratio', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
goalCompletionsAll: [{ 'chart': 'c1', 'name': 'Goals', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
goalValueAll: [{ 'chart': 'c1', 'name': 'Goalvalue', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
goalConversionRateAll: [{ 'chart': 'c1', 'name': 'Goalconverions ratio', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
},
},
other: {
name: 'Overig',
view: 'other',
viewfilters: ['goals'],
first: { dimension: 'date', channel: '(Other)' },
second: { dimension: 'source', channel: '(Other)', sort: 'sessions', sortorder: 'DESCENDING', },
third: { dimension: 'year', channel: '(Other)', sort: 'year', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'sessions',
selectedmetrics: { 'sessions': true, 'users': true, 'pageviews': true, 'pageviewsPerSession': true, 'avgSessionDuration': true, 'percentNewSessions': true, 'bounceRate': true, 'goalCompletionsAll': true, 'goalValueAll': true, 'goalConversionRateAll': true },
metrics: ['sessions', 'users', 'pageviews', 'pageviewsPerSession', 'avgSessionDuration', 'percentNewSessions', 'bounceRate', 'goalCompletionsAll', 'goalValueAll', 'goalConversionRateAll'],
table: { dataset: 'second' },
panels: { dataset: 'third' },
charts: {
sessions: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions', type: 'pie', dataset: 'second' }],
users: [{ 'chart': 'c1', 'name': 'Users', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviews: [{ 'chart': 'c1', 'name': 'PageViews', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviewsPerSession: [{ 'chart': 'c1', 'name': 'Pageviews per session', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
avgSessionDuration: [{ 'chart': 'c1', 'name': 'Average session duration', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
percentNewSessions: [{ 'chart': 'c1', 'name': 'Percentage new Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
bounceRate: [{ 'chart': 'c1', 'name': 'Bounce ratio', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
goalCompletionsAll: [{ 'chart': 'c1', 'name': 'Goals', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
goalValueAll: [{ 'chart': 'c1', 'name': 'Goalvalue', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
goalConversionRateAll: [{ 'chart': 'c1', 'name': 'Goalconverions ratio', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
},
},
},
},
audience: {
views: {
local: {
name: 'Lokaal',
view: 'local',
viewfilters: ['goals'],
first: { dimension: 'country', sort: 'sessions', sortorder: 'DESCENDING' },
second: { dimension: 'country', sort: 'sessions', sortorder: 'DESCENDING' },
third: { dimension: 'year', sort: 'year', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'sessions',
selectedmetrics: { 'sessions': true, 'users': true, 'pageviews': true, 'pageviewsPerSession': true, 'avgSessionDuration': true, 'percentNewSessions': true, 'bounceRate': true, 'goalCompletionsAll': true, 'goalValueAll': true, 'goalConversionRateAll': true },
metrics: ['sessions', 'users', 'pageviews', 'pageviewsPerSession', 'avgSessionDuration', 'percentNewSessions', 'bounceRate', 'goalCompletionsAll', 'goalValueAll', 'goalConversionRateAll'],
table: { dataset: 'first' },
panels: { dataset: 'second' },
charts: {
sessions: [{ 'chart': 'c1', 'name': 'Sessions', type: 'bar', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'third' }],
users: [{ 'chart': 'c1', 'name': 'Users', type: 'bar', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'third' }],
pageviews: [{ 'chart': 'c1', 'name': 'PageViews', type: 'bar', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'third' }],
pageviewsPerSession: [{ 'chart': 'c1', 'name': 'Pageviews per session', type: 'bar', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'third' }],
avgSessionDuration: [{ 'chart': 'c1', 'name': 'Average session duration', type: 'bar', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'third' }],
percentNewSessions: [{ 'chart': 'c1', 'name': 'Percentage new Sessions', type: 'bar', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'third' }],
bounceRate: [{ 'chart': 'c1', 'name': 'Bounce ratio', type: 'bar', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'third' }],
goalCompletionsAll: [{ 'chart': 'c1', 'name': 'Goals', type: 'bar', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'third' }],
goalValueAll: [{ 'chart': 'c1', 'name': 'Goalvalue', type: 'bar', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'third' }],
goalConversionRateAll: [{ 'chart': 'c1', 'name': 'Goalconverions ratio', type: 'bar', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'third' }],
},
},
age: {
name: 'Leeftijd',
view: 'age',
viewfilters: ['goals'],
first: { dimension: 'date', dimension2: 'userAgeBracket' },
second: { dimension: 'userAgeBracket', sort: 'userAgeBracket', sortorder: 'ASCENDING', },
third: { dimension: 'year', sort: 'year', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'sessions',
selectedmetrics: { 'sessions': true, 'users': true, 'pageviews': true, 'pageviewsPerSession': true, 'avgSessionDuration': true, 'percentNewSessions': true, 'bounceRate': true, 'goalCompletionsAll': true, 'goalValueAll': true, 'goalConversionRateAll': true },
metrics: ['sessions', 'users', 'pageviews', 'pageviewsPerSession', 'avgSessionDuration', 'percentNewSessions', 'bounceRate', 'goalCompletionsAll', 'goalValueAll', 'goalConversionRateAll'],
table: { dataset: 'second' },
panels: { dataset: 'third' },
charts: {
sessions: [{ 'chart': 'c1', 'name': 'Sessions', type: 'linemulti', dataset: 'first', graphs: ['18-24', '25-34', '35-44', '45-54', '55-64', '65+'], date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
users: [{ 'chart': 'c1', 'name': 'Users', type: 'linemulti', dataset: 'first', graphs: ['18-24', '25-34', '35-44', '45-54', '55-64', '65+'], date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviews: [{ 'chart': 'c1', 'name': 'PageViews', type: 'linemulti', dataset: 'first', graphs: ['18-24', '25-34', '35-44', '45-54', '55-64', '65+'], date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviewsPerSession: [{ 'chart': 'c1', 'name': 'Pageviews per session', type: 'linemulti', dataset: 'first', graphs: ['18-24', '25-34', '35-44', '45-54', '55-64', '65+'], date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
avgSessionDuration: [{ 'chart': 'c1', 'name': 'Average session duration', type: 'linemulti', dataset: 'first', graphs: ['18-24', '25-34', '35-44', '45-54', '55-64', '65+'], date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
percentNewSessions: [{ 'chart': 'c1', 'name': 'Percentage new Sessions', type: 'linemulti', dataset: 'first', graphs: ['18-24', '25-34', '35-44', '45-54', '55-64', '65+'], date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
bounceRate: [{ 'chart': 'c1', 'name': 'Bounce ratio', type: 'linemulti', dataset: 'first', graphs: ['18-24', '25-34', '35-44', '45-54', '55-64', '65+'], date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
goalCompletionsAll: [{ 'chart': 'c1', 'name': 'Goals', type: 'linemulti', dataset: 'first', graphs: ['18-24', '25-34', '35-44', '45-54', '55-64', '65+'], date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
goalValueAll: [{ 'chart': 'c1', 'name': 'Goalvalue', type: 'linemulti', dataset: 'first', graphs: ['18-24', '25-34', '35-44', '45-54', '55-64', '65+'], date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
goalConversionRateAll: [{ 'chart': 'c1', 'name': 'Goalconverions ratio', type: 'linemulti', dataset: 'first', graphs: ['18-24', '25-34', '35-44', '45-54', '55-64', '65+'], date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
},
},
gender: {
name: 'Geslacht',
view: 'gender',
viewfilters: ['goals'],
first: { dimension: 'date', dimension2: 'userGender', sort: 'userGender', sortorder: 'ASCENDING', },
second: { dimension: 'userGender', sort: 'userGender', sortorder: 'ASCENDING', },
third: { dimension: 'year', sort: 'year', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'sessions',
selectedmetrics: { 'sessions': true, 'users': true, 'pageviews': true, 'pageviewsPerSession': true, 'avgSessionDuration': true, 'percentNewSessions': true, 'bounceRate': true, 'goalCompletionsAll': true, 'goalValueAll': true, 'goalConversionRateAll': true },
metrics: ['sessions', 'users', 'pageviews', 'pageviewsPerSession', 'avgSessionDuration', 'percentNewSessions', 'bounceRate', 'goalCompletionsAll', 'goalValueAll', 'goalConversionRateAll'],
table: { dataset: 'second' },
panels: { dataset: 'third' },
charts: {
sessions: [{ 'chart': 'c1', 'name': 'Sessions', type: 'linemulti', dataset: 'first', graphs: ['male', 'female'] }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
users: [{ 'chart': 'c1', 'name': 'Users', type: 'linemulti', dataset: 'first', graphs: ['male', 'female'] }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviews: [{ 'chart': 'c1', 'name': 'PageViews', type: 'linemulti', dataset: 'first', graphs: ['male', 'female'] }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviewsPerSession: [{ 'chart': 'c1', 'name': 'Pageviews per session', type: 'linemulti', dataset: 'first', graphs: ['male', 'female'] }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
avgSessionDuration: [{ 'chart': 'c1', 'name': 'Average session duration', type: 'linemulti', dataset: 'first', graphs: ['male', 'female'] }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
percentNewSessions: [{ 'chart': 'c1', 'name': 'Percentage new Sessions', type: 'linemulti', dataset: 'first', graphs: ['male', 'female'] }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
bounceRate: [{ 'chart': 'c1', 'name': 'Bounce ratio', type: 'linemulti', dataset: 'first', graphs: ['male', 'female'] }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
goalCompletionsAll: [{ 'chart': 'c1', 'name': 'Goals', type: 'linemulti', dataset: 'first', graphs: ['male', 'female'] }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
goalValueAll: [{ 'chart': 'c1', 'name': 'Goalvalue', type: 'linemulti', dataset: 'first', graphs: ['male', 'female'] }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
goalConversionRateAll: [{ 'chart': 'c1', 'name': 'Goalconverions ratio', type: 'linemulti', dataset: 'first', graphs: ['male', 'female'] }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
},
},
device: {
name: 'Apparaten',
view: 'device',
viewfilters: ['goals'],
first: { dimension: 'date', dimension2: 'deviceCategory' },
second: { dimension: 'deviceCategory', sort: 'deviceCategory', sortorder: 'ASCENDING', },
third: { dimension: 'year', sort: 'year', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'sessions',
selectedmetrics: { 'sessions': true, 'users': true, 'pageviews': true, 'pageviewsPerSession': true, 'avgSessionDuration': true, 'percentNewSessions': true, 'bounceRate': true, 'goalCompletionsAll': true, 'goalValueAll': true, 'goalConversionRateAll': true },
metrics: ['sessions', 'users', 'pageviews', 'pageviewsPerSession', 'avgSessionDuration', 'percentNewSessions', 'bounceRate', 'goalCompletionsAll', 'goalValueAll', 'goalConversionRateAll'],
table: { dataset: 'second' },
panels: { dataset: 'third' },
charts: {
sessions: [{ 'chart': 'c1', 'name': 'Sessions', type: 'linemulti', dataset: 'first', graphs: ['desktop', 'mobile', 'tablet'] }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
users: [{ 'chart': 'c1', 'name': 'Users', type: 'linemulti', dataset: 'first', graphs: ['desktop', 'mobile', 'tablet'] }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviews: [{ 'chart': 'c1', 'name': 'PageViews', type: 'linemulti', dataset: 'first', graphs: ['desktop', 'mobile', 'tablet'] }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviewsPerSession: [{ 'chart': 'c1', 'name': 'Pageviews per session', type: 'linemulti', dataset: 'first', graphs: ['desktop', 'mobile', 'tablet'] }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
avgSessionDuration: [{ 'chart': 'c1', 'name': 'Average session duration', type: 'linemulti', dataset: 'first', graphs: ['desktop', 'mobile', 'tablet'] }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
percentNewSessions: [{ 'chart': 'c1', 'name': 'Percentage new Sessions', type: 'linemulti', dataset: 'first', graphs: ['desktop', 'mobile', 'tablet'] }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
bounceRate: [{ 'chart': 'c1', 'name': 'Bounce ratio', type: 'linemulti', dataset: 'first', graphs: ['desktop', 'mobile', 'tablet'] }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
goalCompletionsAll: [{ 'chart': 'c1', 'name': 'Goals', type: 'linemulti', dataset: 'first', graphs: ['desktop', 'mobile', 'tablet'] }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
goalValueAll: [{ 'chart': 'c1', 'name': 'Goalvalue', type: 'linemulti', dataset: 'first', graphs: ['desktop', 'mobile', 'tablet'] }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
goalConversionRateAll: [{ 'chart': 'c1', 'name': 'Goalconverions ratio', type: 'linemulti', dataset: 'first', graphs: ['desktop', 'mobile', 'tablet'] }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
},
},
mobile: {
name: 'Mobiel',
view: 'mobile',
viewfilters: ['goals'],
first: { dimension: 'mobileDeviceInfo', sort: 'sessions', sortorder: 'DESCENDING' },
second: { dimension: 'year', sort: 'year', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'sessions',
selectedmetrics: { 'sessions': true, 'users': true, 'pageviews': true, 'pageviewsPerSession': true, 'avgSessionDuration': true, 'percentNewSessions': true, 'bounceRate': true, 'goalCompletionsAll': true, 'goalValueAll': true, 'goalConversionRateAll': true },
metrics: ['sessions', 'users', 'pageviews', 'pageviewsPerSession', 'avgSessionDuration', 'percentNewSessions', 'bounceRate', 'goalCompletionsAll', 'goalValueAll', 'goalConversionRateAll'],
table: { dataset: 'first' },
panels: { dataset: 'second' },
charts: {
sessions: [{ 'chart': 'c1', 'name': 'Sessions', type: 'progress', dataset: 'first', graphs: ['desktop', 'mobile', 'tablet'] }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'first' }],
users: [{ 'chart': 'c1', 'name': 'Users', type: 'progress', dataset: 'first', graphs: ['desktop', 'mobile', 'tablet'] }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'first' }],
pageviews: [{ 'chart': 'c1', 'name': 'PageViews', type: 'progress', dataset: 'first', graphs: ['desktop', 'mobile', 'tablet'] }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'first' }],
pageviewsPerSession: [{ 'chart': 'c1', 'name': 'Pageviews per session', type: 'progress', dataset: 'first', graphs: ['desktop', 'mobile', 'tablet'] }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'first' }],
avgSessionDuration: [{ 'chart': 'c1', 'name': 'Average session duration', type: 'progress', dataset: 'first', graphs: ['desktop', 'mobile', 'tablet'] }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'first' }],
percentNewSessions: [{ 'chart': 'c1', 'name': 'Percentage new Sessions', type: 'progress', dataset: 'first', graphs: ['desktop', 'mobile', 'tablet'] }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'first' }],
bounceRate: [{ 'chart': 'c1', 'name': 'Bounce ratio', type: 'progress', dataset: 'first', graphs: ['desktop', 'mobile', 'tablet'] }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'first' }],
goalCompletionsAll: [{ 'chart': 'c1', 'name': 'Goals', type: 'progress', dataset: 'first', graphs: ['desktop', 'mobile', 'tablet'] }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'first' }],
goalValueAll: [{ 'chart': 'c1', 'name': 'Goalvalue', type: 'progress', dataset: 'first', graphs: ['desktop', 'mobile', 'tablet'] }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'first' }],
goalConversionRateAll: [{ 'chart': 'c1', 'name': 'Goalconverions ratio', type: 'progress', dataset: 'first', graphs: ['desktop', 'mobile', 'tablet'] }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'first' }],
},
}
},
},
conversions: {
views: {
goals: {
name: 'Doelen',
view: 'goals',
first: { dimension: 'date', },
second: { dimension: 'goalCompletionsAll' },
third: { dimension: 'year', sort: 'year', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'goalCompletionsAll',
selectedmetrics: { 'goalCompletionsAll': true, 'goalValueAll': true, 'goalConversionRateAll': true, 'goalAbandonRateAll': true },
metrics: ['goalCompletionsAll', 'goalValueAll', 'goalConversionRateAll', 'goalAbandonRateAll'],
table: { dataset: 'second' },
panels: { dataset: 'third' },
charts: {
goalCompletionsAll: [{ 'chart': 'c1', 'name': 'Goals', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
goalAbandonRateAll: [{ 'chart': 'c1', 'name': '_', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
goalValueAll: [{ 'chart': 'c1', 'name': 'Goalvalue', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
goalConversionRateAll: [{ 'chart': 'c1', 'name': 'Goalconverions ratio', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
},
},
/* DIT KLOPT NIET, HEB NOG GEEN DOELEN OF ECOMMERSE DATA*/
ecommerce: {
name: 'E-commerce',
view: 'ecommerce',
first: { dimension: 'date' },
second: { dimension: 'adMatchedQuery', },
third: { dimension: 'channelGrouping' },
selectedmetric: 'transactions',
selectedmetrics: { 'transactions': true, 'uniquePurchases': true, 'totalValue': true, 'revenuePerTransaction': true, 'itemQuantity': true, 'itemsPerPurchase': true },
metrics: ['transactions', 'uniquePurchases', 'totalValue', 'revenuePerTransaction', 'itemQuantity', 'itemsPerPurchase'],
table: { dataset: 'second' },
panels: { dataset: 'first' },
charts: {
transactions: [{ 'chart': 'c1', 'name': 'transactions', type: 'line', dataset: 'first', graphs: ['18-24', '25-34', '35-44', '45-54', '55-64', '65+'], date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'third' }],
uniquePurchases: [{ 'chart': 'c1', 'name': '_', type: 'line', dataset: 'first', graphs: ['18-24', '25-34', '35-44', '45-54', '55-64', '65+'], date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'third' }],
totalValue: [{ 'chart': 'c1', 'name': '_', type: 'line', dataset: 'first', graphs: ['18-24', '25-34', '35-44', '45-54', '55-64', '65+'], date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
revenuePerTransaction: [{ 'chart': 'c1', 'name': '_', type: 'line', dataset: 'first', graphs: ['18-24', '25-34', '35-44', '45-54', '55-64', '65+'], date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
itemQuantity: [{ 'chart': 'c1', 'name': '_', type: 'line', dataset: 'first', graphs: ['18-24', '25-34', '35-44', '45-54', '55-64', '65+'], date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
itemsPerPurchase: [{ 'chart': 'c1', 'name': '_', type: 'line', dataset: 'first', graphs: ['18-24', '25-34', '35-44', '45-54', '55-64', '65+'], date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
},
},
},
},
pages: {
views: {
all: {
name: 'Alle pagina\'s',
view: 'all',
viewfilters: ['goals', 'channels'],
first: { dimension: 'date', },
second: { dimension: 'pagePath', sort: 'pageviews', sortorder: 'DESCENDING', },
third: { dimension: 'year', sort: 'year', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'pageviews',
selectedmetrics: { 'pageviews': true, 'uniquePageviews': true, 'pageviewsPerSession': true, 'avgTimeOnPage': true, 'entrances': true, 'bounceRate': true, 'exitRate': true, 'pageValue': true },
metrics: ['pageviews', 'uniquePageviews', 'pageviewsPerSession', 'avgTimeOnPage', 'entrances', 'bounceRate', 'exitRate', 'pageValue'],
table: { dataset: 'second' },
panels: { dataset: 'third' },
charts: {
pageviews: [{ 'chart': 'c1', 'name': 'PageViews', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'progress', dataset: 'second' }],
uniquePageviews: [{ 'chart': 'c1', 'name': 'PageViews', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'progress', dataset: 'second' }],
pageviewsPerSession: [{ 'chart': 'c1', 'name': 'Pageviews per session', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'progress', dataset: 'second' }],
avgTimeOnPage: [{ 'chart': 'c1', 'name': '_', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'progress', dataset: 'second' }],
entrances: [{ 'chart': 'c1', 'name': 'Ingangen', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'progress', dataset: 'second' }],
bounceRate: [{ 'chart': 'c1', 'name': 'Bounce ratio', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'progress', dataset: 'second' }],
exitRate: [{ 'chart': 'c1', 'name': '_', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'progress', dataset: 'second' }],
pageValue: [{ 'chart': 'c1', 'name': '_', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'progress', dataset: 'second' }],
},
},
/* NIET HELAAM LEKKER */
landing: {
name: 'Landingspagina\'s',
view: 'landing',
first: { dimension: 'date' },
second: { dimension: 'landingPagePath', sort: 'pageviews', sortorder: 'DESCENDING', },
third: { dimension: 'year', sort: 'year', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'pageviews',
selectedmetrics: { 'pageviews': true, 'uniquePageviews': true, 'pageviewsPerSession': true, 'avgTimeOnPage': true, 'entrances': true, 'bounceRate': true, 'exitRate': true, 'pageValue': true },
metrics: ['pageviews', 'uniquePageviews', 'pageviewsPerSession', 'avgTimeOnPage', 'entrances', 'bounceRate', 'exitRate', 'pageValue'],
table: { dataset: 'second' },
panels: { dataset: 'third' },
charts: {
pageviews: [{ 'chart': 'c1', 'name': 'PageViews', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'progress', dataset: 'second' }],
uniquePageviews: [{ 'chart': 'c1', 'name': 'PageViews', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'progress', dataset: 'second' }],
pageviewsPerSession: [{ 'chart': 'c1', 'name': 'Pageviews per session', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'progress', dataset: 'second' }],
avgTimeOnPage: [{ 'chart': 'c1', 'name': '_', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'progress', dataset: 'second' }],
entrances: [{ 'chart': 'c1', 'name': 'Ingangen', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'progress', dataset: 'second' }],
bounceRate: [{ 'chart': 'c1', 'name': 'Bounce ratio', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'progress', dataset: 'second' }],
exitRate: [{ 'chart': 'c1', 'name': '_', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'progress', dataset: 'second' }],
pageValue: [{ 'chart': 'c1', 'name': '_', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'progress', dataset: 'second' }],
},
},
exit: {
name: 'Exit Pagina\'s',
view: 'exit',
first: { dimension: 'date' },
second: { dimension: 'exitPagePath', sort: 'exits', sortorder: 'DESCENDING', },
third: { dimension: 'year', sort: 'year', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'exits',
selectedmetrics: { 'exits': true, 'uniquePageviews': true, 'avgTimeOnPage': true, 'exitRate': true },
metrics: ['exits', 'uniquePageviews', 'avgTimeOnPage', 'exitRate'],
table: { dataset: 'second' },
panels: { dataset: 'third' },
charts: {
exits: [{ 'chart': 'c1', 'name': '_', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'progress', dataset: 'second' }],
uniquePageviews: [{ 'chart': 'c1', 'name': 'PageViews', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'progress', dataset: 'second' }],
avgTimeOnPage: [{ 'chart': 'c1', 'name': '_', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'progress', dataset: 'second' }],
exitRate: [{ 'chart': 'c1', 'name': '_', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'progress', dataset: 'second' }],
},
},
},
},
events: {
views: {
all: {
name: 'Alle pagina\'s',
view: 'all',
first: { dimension: 'date', },
second: { dimension: 'pagePath', sort: 'pageviews', sortorder: 'DESCENDING', },
selectedmetric: 'pageviews',
selectedmetrics: { 'pageviews': true, 'uniquePageviews': true, 'pageviewsPerSession': true, 'avgTimeOnPage': true, 'entrances': true, 'bounceRate': true, 'exitRate': true, 'pageValue': true },
metrics: ['pageviews', 'uniquePageviews', 'pageviewsPerSession', 'avgTimeOnPage', 'entrances', 'bounceRate', 'exitRate', 'pageValue'],
table: { dataset: 'second' },
panels: { dataset: 'first' },
charts: {
pageviews: [{ 'chart': 'c1', 'name': 'PageViews', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
uniquePageviews: [{ 'chart': 'c1', 'name': 'PageViews', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
pageviewsPerSession: [{ 'chart': 'c1', 'name': 'Pageviews per session', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
avgTimeOnPage: [{ 'chart': 'c1', 'name': '_', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
entrances: [{ 'chart': 'c1', 'name': 'Ingangen', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
bounceRate: [{ 'chart': 'c1', 'name': 'Bounce ratio', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
exitRate: [{ 'chart': 'c1', 'name': '_', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
pageValue: [{ 'chart': 'c1', 'name': '_', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
},
},
/* NIET HELAAM LEKKER */
landing: {
name: 'Landingspagina\'s',
view: 'landing',
first: { dimension: 'date' },
second: { dimension: 'landingPagePath', sort: 'pageviews', sortorder: 'DESCENDING', },
selectedmetric: 'pageviews',
selectedmetrics: { 'pageviews': true, 'uniquePageviews': true, 'pageviewsPerSession': true, 'avgTimeOnPage': true, 'entrances': true, 'bounceRate': true, 'exitRate': true, 'pageValue': true },
metrics: ['pageviews', 'uniquePageviews', 'pageviewsPerSession', 'avgTimeOnPage', 'entrances', 'bounceRate', 'exitRate', 'pageValue'],
table: { dataset: 'second' },
panels: { dataset: 'first' },
charts: {
pageviews: [{ 'chart': 'c1', 'name': 'PageViews', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
uniquePageviews: [{ 'chart': 'c1', 'name': 'PageViews', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
pageviewsPerSession: [{ 'chart': 'c1', 'name': 'Pageviews per session', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
avgTimeOnPage: [{ 'chart': 'c1', 'name': '_', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
entrances: [{ 'chart': 'c1', 'name': 'Ingangen', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
bounceRate: [{ 'chart': 'c1', 'name': 'Bounce ratio', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
exitRate: [{ 'chart': 'c1', 'name': '_', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
pageValue: [{ 'chart': 'c1', 'name': '_', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
},
},
exit: {
name: 'Exit Pagina\'s',
view: 'exit',
first: { dimension: 'date' },
second: { dimension: 'exitPagePath', sort: 'exits', sortorder: 'DESCENDING', },
selectedmetric: 'exits',
selectedmetrics: { 'exits': true, 'uniquePageviews': true, 'avgTimeOnPage': true, 'exitRate': true },
metrics: ['exits', 'uniquePageviews', 'avgTimeOnPage', 'exitRate'],
table: { dataset: 'second' },
panels: { dataset: 'first' },
charts: {
exits: [{ 'chart': 'c1', 'name': '_', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
uniquePageviews: [{ 'chart': 'c1', 'name': 'PageViews', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
avgTimeOnPage: [{ 'chart': 'c1', 'name': '_', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
exitRate: [{ 'chart': 'c1', 'name': '_', type: 'line', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
},
},
},
}
}
$scope.setAnalyticsCustomer = function(data) {
$http.get('/rest/' + $scope.cfg.urlbase + '/profileid.set', {
params: {
websiteid: h.siteId(),
profileid: data.profileid,
accountId: data.accountId,
webPropertyId: data.webPropertyId,
}
}).then(function successCallback(res) {
$scope.getReportData();
});
}
$controller('coreapi', { $scope: $scope });
$scope.init();
}
]);
app.controller('analytics4', ['$scope', '$timeout', '$http', '$rootScope', '$controller', '$filter', 'h',
function ($scope, $timeout, $http, $rootScope, $controller, $filter, h) {
$scope.cfg = {
authurl: 'https://app.marketingtracer.com/rest/analytics4/connect?websiteid=' + h.siteId(),
dateformat: "YYYYMMDD",
dimensionprefix: '',
urlbase: 'analytics4',
switchclient: true,
report_endpoint: '/rest/analytics4/report',
}
$scope.checkDataAvailability = function (data) {
if(data.data && data.data.length == 0){
$scope.msg = 'Google Signals Must Be Active: Age and gender data are only collected if you have Google Signals enabled for the GA4 property. If it\'s not active, the API will return no data. You must enable this in your GA4 Admin settings (Data Settings > Data Collection).';
}
}
if($rootScope.user.reseller?.config?.authdomain){
$scope.cfg.authurl = 'https://' + $rootScope.user.reseller.config.authdomain + '/rest/analytics4/connect?websiteid=' + h.siteId();
}
//$scope.gloMetrics = h.metrics('analytics');
$scope.gloMetrics = {
sessions: { name: 'Sessions', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
totalUsers: { name: 'totalUsers', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
screenPageViews: { name: 'screenPageViews', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
screenPageViewsPerSession: { name: 'screenPageViewsPerSession', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
sessions: { name: 'Sessions', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
newUsers: { name: 'Users', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
pageviews: { name: 'Pageviews', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
pageviewsPerSession: { name: 'Pageviews / session', typefilter: 'number', filtercomparator: 2, 'datemerge': 'avg' },
averageSessionDuration: { name: 'Average session duration', typefilter: 'secondsToHHmmss', filtercomparator: 0, 'datemerge': 'avg' },
percentNewSessions: { name: 'Percentrage new sessions', typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' },
bounceRate: { name: 'Bounce Ratio', typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' },
goalCompletionsAll: { name: 'Goals', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
goalValueAll: { name: 'Goalvalue', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
goalConversionRateAll: { name: 'Goalconversion ratio', typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' },
goalAbandonRateAll: { name: 'Doel verlatings ratio', typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' },
uniquePageviews: { name: 'Unique Pageviews', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
avgTimeOnPage: { name: 'Avg time on page', typefilter: 'secondsToHHmmss', filtercomparator: 0, 'datemerge': 'avg' },
entrances: { name: 'Entrances', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
exitRate: { name: 'Exit rate', typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' },
pageValue: { name: 'Pagevalue', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
exits: { name: 'Exits', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
ROAS: { name: 'ROAS', typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
costPerTransaction: { name: 'Cost per transaction', typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
totalValue: { name: 'Total value', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
adCost: { name: 'Ad Cost', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
CPC: { name: 'CPC', typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
adClicks: { name: 'Ad Clicks', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
transactions: { name: 'Transacions', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
uniquePurchases: { name: 'Unique Purchases', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
totalValue: { name: 'Total Value', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
revenuePerTransaction: { name: 'Revenue per Transaction', typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
itemQuantity: { name: 'Item Quentity', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
itemsPerPurchase: { name: 'items / purchase', typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
eventCount: { name: 'items / purchase', typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
eventCountPerUser: { name: 'items / purchase', typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
mobileDeviceBranding: { name: 'Mobile device model', typefilter: 'text', filtercomparator: 3 },
itemsPurchased: { name: 'Items purchased', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
itemRevenue: { name: 'Item revenue', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
conversions: { name: 'Conversions', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
eventValue: { name: 'Event value', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
sessionConversionRate: { name: 'Session conversion rate', typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' },
userEngagementDuration: { name: 'User engagement duration', typefilter: 'secondsToHHmmss', filtercomparator: 0, 'datemerge': 'sum' },
engagementRate: { name: 'User engagement rate', typefilter: 'number', filtercomparator: 2, 'after': '%', 'datemerge': 'avg' },
totalRevenue: { name: 'Total Revenue', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
};
$scope.selectedmetrics = {};
$scope.reportconfig = {
channels: {
views: {
all: {
name: 'All',
view: 'all',
viewfilters: ['goals'],
first: { dimension: 'date' },
second: { dimension: 'sessionDefaultChannelGrouping', sort: 'sessions', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'sessions',
selectedmetrics: { 'sessions': true, 'totalUsers': true, 'screenPageViews': true, 'screenPageViewsPerSession': true, 'averageSessionDuration': true, 'newUsers': true, 'bounceRate': true, 'bounceRate': true, 'eventCount': true, 'eventCountPerUser': true },
metrics: ['sessions', 'totalUsers', 'screenPageViews', 'screenPageViewsPerSession', 'averageSessionDuration', 'newUsers', 'bounceRate', 'eventCount', 'eventCountPerUser'],
table: { dataset: 'second' },
panels: { dataset: 'second' },
charts: {
sessions: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions / channel', type: 'pie', dataset: 'second' }],
totalUsers: [{ 'chart': 'c1', 'name': 'Users', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Users / channel', type: 'pie', dataset: 'second' }],
screenPageViews: [{ 'chart': 'c1', 'name': 'Pagina weergaven', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'screenPageViews / channel', type: 'pie', dataset: 'second' }],
screenPageViewsPerSession: [{ 'chart': 'c1', 'name': 'Pageviews per session', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'screenPageViewsPerSession per session /channel', type: 'bar', dataset: 'second' }],
averageSessionDuration: [{ 'chart': 'c1', 'name': 'Average session duration', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
newUsers: [{ 'chart': 'c1', 'name': 'Percentage new Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
bounceRate: [{ 'chart': 'c1', 'name': 'Bounce ratio', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
eventCount: [{ 'chart': 'c1', 'name': 'Goals', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
eventCountPerUser: [{ 'chart': 'c1', 'name': 'Goalvalue', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
},
},
organic: {
name: 'Organic',
view: 'organic',
viewfilters: ['goals'],
first: { dimension: 'date', channel: 'Organic Search' },
second: { dimension: 'landingPage', channel: 'Organic Search', sort: 'users', sortorder: 'DESCENDING' },
third: { dimension: 'sessionSource', channel: 'Organic Search', sort: 'users', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'sessions',
selectedmetrics: { 'sessions': true, 'totalUsers': true, 'screenPageViews': true, 'screenPageViewsPerSession': true, 'averageSessionDuration': true, 'newUsers': true, 'bounceRate': true, 'bounceRate': true, 'eventCount': true, 'eventCountPerUser': true },
metrics: ['sessions', 'totalUsers', 'screenPageViews', 'screenPageViewsPerSession', 'averageSessionDuration', 'newUsers', 'bounceRate', 'eventCount', 'eventCountPerUser'],
table: { dataset: 'second' },
panels: { dataset: 'third' },
charts: {
sessions: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'third' }],
users: [{ 'chart': 'c1', 'name': 'Users', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'third' }],
pageviews: [{ 'chart': 'c1', 'name': 'PageViews', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'third' }],
pageviewsPerSession: [{ 'chart': 'c1', 'name': 'Pageviews per session', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'third' }],
avgSessionDuration: [{ 'chart': 'c1', 'name': 'Average session duration', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'third' }],
percentNewSessions: [{ 'chart': 'c1', 'name': 'Percentage new Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'third' }],
bounceRate: [{ 'chart': 'c1', 'name': 'Bounce ratio', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'third' }],
goalCompletionsAll: [{ 'chart': 'c1', 'name': 'Goals', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'third' }],
goalValueAll: [{ 'chart': 'c1', 'name': 'Goalvalue', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'third' }],
goalConversionRateAll: [{ 'chart': 'c1', 'name': 'Goalconverions ratio', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'third' }],
},
},
// AI-assistenten (ChatGPT, Perplexity, Gemini, Copilot): GA4-kanaal 'AI Assistant'
ai: {
name: 'AI assistants',
view: 'ai',
viewfilters: ['goals'],
first: { dimension: 'date', channel: 'AI Assistant' },
second: { dimension: 'landingPage', channel: 'AI Assistant', sort: 'sessions', sortorder: 'DESCENDING' },
third: { dimension: 'sessionSource', channel: 'AI Assistant', sort: 'sessions', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'sessions',
selectedmetrics: { 'sessions': true, 'totalUsers': true, 'screenPageViews': true, 'screenPageViewsPerSession': true, 'averageSessionDuration': true, 'newUsers': true, 'bounceRate': true, 'eventCount': true, 'eventCountPerUser': true },
metrics: ['sessions', 'totalUsers', 'screenPageViews', 'screenPageViewsPerSession', 'averageSessionDuration', 'newUsers', 'bounceRate', 'eventCount', 'eventCountPerUser'],
table: { dataset: 'second' },
panels: { dataset: 'third' },
charts: {
sessions: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'third' }],
},
},
// Direct: vaak veel botverkeer, daarom per land
direct: {
name: 'Direct',
view: 'direct',
viewfilters: ['goals'],
first: { dimension: 'date', channel: 'Direct' },
second: { dimension: 'landingPage', channel: 'Direct', sort: 'sessions', sortorder: 'DESCENDING' },
third: { dimension: 'country', channel: 'Direct', sort: 'sessions', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'sessions',
selectedmetrics: { 'sessions': true, 'totalUsers': true, 'screenPageViews': true, 'screenPageViewsPerSession': true, 'averageSessionDuration': true, 'newUsers': true, 'bounceRate': true, 'eventCount': true, 'eventCountPerUser': true },
metrics: ['sessions', 'totalUsers', 'screenPageViews', 'screenPageViewsPerSession', 'averageSessionDuration', 'newUsers', 'bounceRate', 'eventCount', 'eventCountPerUser'],
table: { dataset: 'second' },
panels: { dataset: 'third' },
charts: {
sessions: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'third' }],
},
},
paid: {
name: 'Betaalde zoekopdrachten',
view: 'paid',
viewfilters: ['goals'],
first: { dimension: 'date', channel: 'Paid Search' },
second: { dimension: 'landingPage', channel: 'Paid Search', sort: 'sessions', sortorder: 'DESCENDING' },
third: { dimension: 'year', channel: 'Paid Search', sort: 'sessions', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'sessions',
selectedmetrics: { 'sessions': true, 'totalUsers': true, 'screenPageViews': true, 'screenPageViewsPerSession': true, 'averageSessionDuration': true, 'newUsers': true, 'bounceRate': true, 'bounceRate': true, 'eventCount': true, 'eventCountPerUser': true },
metrics: ['sessions', 'totalUsers', 'screenPageViews', 'screenPageViewsPerSession', 'averageSessionDuration', 'newUsers', 'bounceRate', 'eventCount', 'eventCountPerUser'],
table: { dataset: 'second' },
panels: { dataset: 'third' },
charts: {
sessions: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions', type: 'pie', dataset: 'second' }],
users: [{ 'chart': 'c1', 'name': 'Users', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviews: [{ 'chart': 'c1', 'name': 'PageViews', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviewsPerSession: [{ 'chart': 'c1', 'name': 'Pageviews per session', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
avgSessionDuration: [{ 'chart': 'c1', 'name': 'Average session duration', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
percentNewSessions: [{ 'chart': 'c1', 'name': 'Percentage new Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
bounceRate: [{ 'chart': 'c1', 'name': 'Bounce ratio', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
goalCompletionsAll: [{ 'chart': 'c1', 'name': 'Goals', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
goalValueAll: [{ 'chart': 'c1', 'name': 'Goalvalue', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
goalConversionRateAll: [{ 'chart': 'c1', 'name': 'Goalconverions ratio', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
},
},
display: {
name: 'Display',
view: 'display',
viewfilters: ['goals'],
first: { dimension: 'date', channel: 'Display' },
second: { dimension: 'source', channel: 'Display', sort: 'sessions', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'sessions',
selectedmetrics: { 'sessions': true, 'totalUsers': true },
metrics: ['sessions', 'totalUsers'],
table: { dataset: 'second' },
panels: { dataset: 'second' },
charts: {
sessions: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions', type: 'pie', dataset: 'second' }],
users: [{ 'chart': 'c1', 'name': 'Users', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviews: [{ 'chart': 'c1', 'name': 'PageViews', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviewsPerSession: [{ 'chart': 'c1', 'name': 'Pageviews per session', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
avgSessionDuration: [{ 'chart': 'c1', 'name': 'Average session duration', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
percentNewSessions: [{ 'chart': 'c1', 'name': 'Percentage new Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
bounceRate: [{ 'chart': 'c1', 'name': 'Bounce ratio', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
goalCompletionsAll: [{ 'chart': 'c1', 'name': 'Goals', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
goalValueAll: [{ 'chart': 'c1', 'name': 'Goalvalue', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
goalConversionRateAll: [{ 'chart': 'c1', 'name': 'Goalconverions ratio', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
},
},
social: {
name: 'Social',
view: 'social',
viewfilters: ['goals'],
first: { dimension: 'date', channel: 'Organic Social,Paid Social' },
second: { dimension: 'sessionSource', channel: 'Organic Social,Paid Social', sort: 'sessions', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'sessions',
selectedmetrics: { 'sessions': true, 'totalUsers': true, 'screenPageViews': true, 'screenPageViewsPerSession': true, 'averageSessionDuration': true, 'newUsers': true, 'bounceRate': true, 'bounceRate': true, 'eventCount': true, 'eventCountPerUser': true },
metrics: ['sessions', 'totalUsers', 'screenPageViews', 'screenPageViewsPerSession', 'averageSessionDuration', 'newUsers', 'bounceRate', 'eventCount', 'eventCountPerUser'],
table: { dataset: 'second' },
panels: { dataset: 'second' },
charts: {
sessions: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions', type: 'pie', dataset: 'second' }],
users: [{ 'chart': 'c1', 'name': 'Users', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviews: [{ 'chart': 'c1', 'name': 'PageViews', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviewsPerSession: [{ 'chart': 'c1', 'name': 'Pageviews per session', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
avgSessionDuration: [{ 'chart': 'c1', 'name': 'Average session duration', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
percentNewSessions: [{ 'chart': 'c1', 'name': 'Percentage new Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
bounceRate: [{ 'chart': 'c1', 'name': 'Bounce ratio', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
goalCompletionsAll: [{ 'chart': 'c1', 'name': 'Goals', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
goalValueAll: [{ 'chart': 'c1', 'name': 'Goalvalue', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
goalConversionRateAll: [{ 'chart': 'c1', 'name': 'Goalconverions ratio', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
},
},
referral: {
name: 'Referral',
view: 'referral',
viewfilters: ['goals'],
first: { dimension: 'date', channel: 'Referral', sort: 'date', sortorder: 'ASCENDING', },
second: { dimension: 'sessionSource', channel: 'Referral', sort: 'sessions', sortorder: 'DESCENDING' },
third: { dimension: 'year', channel: 'Referral', sort: 'year', sortorder: 'ASCENDING', 'allowcomp': true },
selectedmetric: 'sessions',
selectedmetrics: { 'sessions': true, 'totalUsers': true, 'screenPageViews': true, 'screenPageViewsPerSession': true, 'averageSessionDuration': true, 'newUsers': true, 'bounceRate': true, 'bounceRate': true, 'eventCount': true, 'eventCountPerUser': true },
metrics: ['sessions', 'totalUsers', 'screenPageViews', 'screenPageViewsPerSession', 'averageSessionDuration', 'newUsers', 'bounceRate', 'eventCount', 'eventCountPerUser'],
table: { dataset: 'second' },
panels: { dataset: 'third' },
charts: {
sessions: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
users: [{ 'chart': 'c1', 'name': 'Users', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviews: [{ 'chart': 'c1', 'name': 'PageViews', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviewsPerSession: [{ 'chart': 'c1', 'name': 'Pageviews per session', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
avgSessionDuration: [{ 'chart': 'c1', 'name': 'Average session duration', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
percentNewSessions: [{ 'chart': 'c1', 'name': 'Percentage new Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
bounceRate: [{ 'chart': 'c1', 'name': 'Bounce ratio', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
goalCompletionsAll: [{ 'chart': 'c1', 'name': 'Goals', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
goalValueAll: [{ 'chart': 'c1', 'name': 'Goalvalue', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
goalConversionRateAll: [{ 'chart': 'c1', 'name': 'Goalconverions ratio', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
},
},
email: {
name: 'E-mail',
view: 'email',
viewfilters: ['goals'],
first: { dimension: 'date', channel: 'Email' },
second: { dimension: 'sessionSource', channel: 'Email', sort: 'sessions', sortorder: 'DESCENDING', },
third: { dimension: 'year', channel: 'Email', sort: 'year', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'sessions',
selectedmetrics: { 'sessions': true, 'totalUsers': true, 'screenPageViews': true, 'screenPageViewsPerSession': true, 'averageSessionDuration': true, 'newUsers': true, 'bounceRate': true, 'bounceRate': true, 'eventCount': true, 'eventCountPerUser': true },
metrics: ['sessions', 'totalUsers', 'screenPageViews', 'screenPageViewsPerSession', 'averageSessionDuration', 'newUsers', 'bounceRate', 'eventCount', 'eventCountPerUser'],
table: { dataset: 'second' },
panels: { dataset: 'third' },
charts: {
sessions: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions', type: 'pie', dataset: 'second' }],
users: [{ 'chart': 'c1', 'name': 'Users', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviews: [{ 'chart': 'c1', 'name': 'PageViews', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviewsPerSession: [{ 'chart': 'c1', 'name': 'Pageviews per session', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
avgSessionDuration: [{ 'chart': 'c1', 'name': 'Average session duration', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
percentNewSessions: [{ 'chart': 'c1', 'name': 'Percentage new Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
bounceRate: [{ 'chart': 'c1', 'name': 'Bounce ratio', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
goalCompletionsAll: [{ 'chart': 'c1', 'name': 'Goals', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
goalValueAll: [{ 'chart': 'c1', 'name': 'Goalvalue', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
goalConversionRateAll: [{ 'chart': 'c1', 'name': 'Goalconverions ratio', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
},
},
other: {
name: 'Overig',
view: 'other',
viewfilters: ['goals'],
first: { dimension: 'date', channel: '!Direct,Organic Search,AI Assistant,Paid Search,Display,Organic Social,Paid Social,Referral,Email' },
second: { dimension: 'sessionSource', channel: '!Direct,Organic Search,AI Assistant,Paid Search,Display,Organic Social,Paid Social,Referral,Email', sort: 'sessions', sortorder: 'DESCENDING', },
third: { dimension: 'year', channel: '!Direct,Organic Search,AI Assistant,Paid Search,Display,Organic Social,Paid Social,Referral,Email', sort: 'year', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'sessions',
selectedmetrics: { 'sessions': true, 'totalUsers': true, 'screenPageViews': true, 'screenPageViewsPerSession': true, 'averageSessionDuration': true, 'newUsers': true, 'bounceRate': true, 'bounceRate': true, 'eventCount': true, 'eventCountPerUser': true },
metrics: ['sessions', 'totalUsers', 'screenPageViews', 'screenPageViewsPerSession', 'averageSessionDuration', 'newUsers', 'bounceRate', 'eventCount', 'eventCountPerUser'],
table: { dataset: 'second' },
panels: { dataset: 'third' },
charts: {
sessions: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions', type: 'pie', dataset: 'second' }],
users: [{ 'chart': 'c1', 'name': 'Users', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviews: [{ 'chart': 'c1', 'name': 'PageViews', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviewsPerSession: [{ 'chart': 'c1', 'name': 'Pageviews per session', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
avgSessionDuration: [{ 'chart': 'c1', 'name': 'Average session duration', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
percentNewSessions: [{ 'chart': 'c1', 'name': 'Percentage new Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
bounceRate: [{ 'chart': 'c1', 'name': 'Bounce ratio', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
goalCompletionsAll: [{ 'chart': 'c1', 'name': 'Goals', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
goalValueAll: [{ 'chart': 'c1', 'name': 'Goalvalue', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
goalConversionRateAll: [{ 'chart': 'c1', 'name': 'Goalconverions ratio', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
},
},
},
},
audience: {
views: {
local: {
name: 'Lokaal',
view: 'local',
viewfilters: ['goals'],
first: { dimension: 'country', sort: 'sessions', sortorder: 'DESCENDING' },
second: { dimension: 'country', sort: 'sessions', sortorder: 'DESCENDING' },
third: { dimension: 'country', sort: 'sessions', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'sessions',
selectedmetrics: { 'sessions': true, 'totalUsers': true, 'screenPageViews': true, 'screenPageViewsPerSession': true, 'averageSessionDuration': true, 'newUsers': true, 'bounceRate': true, 'bounceRate': true, 'eventCount': true, 'eventCountPerUser': true },
metrics: ['sessions', 'totalUsers', 'screenPageViews', 'screenPageViewsPerSession', 'averageSessionDuration', 'newUsers', 'bounceRate', 'eventCount', 'eventCountPerUser'],
table: { dataset: 'first' },
panels: { dataset: 'second' },
charts: {
sessions: [{ 'chart': 'c1', 'name': 'Sessions', type: 'bar', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'third' }],
users: [{ 'chart': 'c1', 'name': 'Users', type: 'bar', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'third' }],
pageviews: [{ 'chart': 'c1', 'name': 'PageViews', type: 'bar', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'third' }],
pageviewsPerSession: [{ 'chart': 'c1', 'name': 'Pageviews per session', type: 'bar', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'third' }],
avgSessionDuration: [{ 'chart': 'c1', 'name': 'Average session duration', type: 'bar', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'third' }],
percentNewSessions: [{ 'chart': 'c1', 'name': 'Percentage new Sessions', type: 'bar', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'third' }],
bounceRate: [{ 'chart': 'c1', 'name': 'Bounce ratio', type: 'bar', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'third' }],
goalCompletionsAll: [{ 'chart': 'c1', 'name': 'Goals', type: 'bar', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'third' }],
goalValueAll: [{ 'chart': 'c1', 'name': 'Goalvalue', type: 'bar', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'third' }],
goalConversionRateAll: [{ 'chart': 'c1', 'name': 'Goalconverions ratio', type: 'bar', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'third' }],
},
},
age: {
name: 'Leeftijd',
view: 'age',
viewfilters: ['goals'],
first: { dimension: 'date', dimension2: 'userAgeBracket',callback:$scope.checkDataAvailability },
second: { dimension: 'userAgeBracket', sort: 'userAgeBracket', sortorder: 'ASCENDING' },
third: { dimension: 'year', sort: 'year', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'sessions',
selectedmetrics: { 'sessions': true, 'totalUsers': true, 'screenPageViews': true, 'screenPageViewsPerSession': true, 'averageSessionDuration': true, 'newUsers': true, 'bounceRate': true, 'eventCount': true, 'eventCountPerUser': true },
metrics: ['sessions', 'totalUsers', 'screenPageViews', 'screenPageViewsPerSession', 'averageSessionDuration', 'newUsers', 'bounceRate', 'eventCount', 'eventCountPerUser'],
table: { dataset: 'second' },
panels: { dataset: 'third' },
charts: {
sessions: [{ 'chart': 'c1', 'name': 'Sessions', type: 'linemulti', dataset: 'first', graphs: ['18-24', '25-34', '35-44', '45-54', '55-64', '65+'], date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
users: [{ 'chart': 'c1', 'name': 'Users', type: 'linemulti', dataset: 'first', graphs: ['18-24', '25-34', '35-44', '45-54', '55-64', '65+'], date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviews: [{ 'chart': 'c1', 'name': 'PageViews', type: 'linemulti', dataset: 'first', graphs: ['18-24', '25-34', '35-44', '45-54', '55-64', '65+'], date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviewsPerSession: [{ 'chart': 'c1', 'name': 'Pageviews per session', type: 'linemulti', dataset: 'first', graphs: ['18-24', '25-34', '35-44', '45-54', '55-64', '65+'], date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
avgSessionDuration: [{ 'chart': 'c1', 'name': 'Average session duration', type: 'linemulti', dataset: 'first', graphs: ['18-24', '25-34', '35-44', '45-54', '55-64', '65+'], date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
percentNewSessions: [{ 'chart': 'c1', 'name': 'Percentage new Sessions', type: 'linemulti', dataset: 'first', graphs: ['18-24', '25-34', '35-44', '45-54', '55-64', '65+'], date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
bounceRate: [{ 'chart': 'c1', 'name': 'Bounce ratio', type: 'linemulti', dataset: 'first', graphs: ['18-24', '25-34', '35-44', '45-54', '55-64', '65+'], date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
goalCompletionsAll: [{ 'chart': 'c1', 'name': 'Goals', type: 'linemulti', dataset: 'first', graphs: ['18-24', '25-34', '35-44', '45-54', '55-64', '65+'], date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
goalValueAll: [{ 'chart': 'c1', 'name': 'Goalvalue', type: 'linemulti', dataset: 'first', graphs: ['18-24', '25-34', '35-44', '45-54', '55-64', '65+'], date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
goalConversionRateAll: [{ 'chart': 'c1', 'name': 'Goalconverions ratio', type: 'linemulti', dataset: 'first', graphs: ['18-24', '25-34', '35-44', '45-54', '55-64', '65+'], date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
},
},
gender: {
name: 'Geslacht',
view: 'gender',
viewfilters: ['goals'],
first: { dimension: 'date', dimension2: 'userGender' ,callback:$scope.checkDataAvailability},
second: { dimension: 'userGender', sort: 'userGender', sortorder: 'ASCENDING' },
third: { dimension: 'year', sort: 'year', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'sessions',
selectedmetrics: { 'sessions': true, 'totalUsers': true, 'screenPageViews': true, 'screenPageViewsPerSession': true, 'averageSessionDuration': true, 'newUsers': true, 'bounceRate': true, 'eventCount': true, 'eventCountPerUser': true },
metrics: ['sessions', 'totalUsers', 'screenPageViews', 'screenPageViewsPerSession', 'averageSessionDuration', 'newUsers', 'bounceRate', 'eventCount', 'eventCountPerUser'],
table: { dataset: 'second' },
panels: { dataset: 'third' },
charts: {
sessions: [{ 'chart': 'c1', 'name': 'Sessions', type: 'linemulti', dataset: 'first', graphs: ['male', 'female', 'unknown'], date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
users: [{ 'chart': 'c1', 'name': 'Users', type: 'linemulti', dataset: 'first', graphs: ['male', 'female', 'unknown'], date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviews: [{ 'chart': 'c1', 'name': 'PageViews', type: 'linemulti', dataset: 'first', graphs: ['male', 'female', 'unknown'], date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviewsPerSession: [{ 'chart': 'c1', 'name': 'Pageviews per session', type: 'linemulti', dataset: 'first', graphs: ['male', 'female', 'unknown'], date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
avgSessionDuration: [{ 'chart': 'c1', 'name': 'Average session duration', type: 'linemulti', dataset: 'first', graphs: ['male', 'female', 'unknown'], date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
percentNewSessions: [{ 'chart': 'c1', 'name': 'Percentage new Sessions', type: 'linemulti', dataset: 'first', graphs: ['male', 'female', 'unknown'], date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
bounceRate: [{ 'chart': 'c1', 'name': 'Bounce ratio', type: 'linemulti', dataset: 'first', graphs: ['male', 'female', 'unknown'], date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
goalCompletionsAll: [{ 'chart': 'c1', 'name': 'Goals', type: 'linemulti', dataset: 'first', graphs: ['male', 'female', 'unknown'], date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
goalValueAll: [{ 'chart': 'c1', 'name': 'Goalvalue', type: 'linemulti', dataset: 'first', graphs: ['male', 'female', 'unknown'], date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
goalConversionRateAll: [{ 'chart': 'c1', 'name': 'Goalconverions ratio', type: 'linemulti', dataset: 'first', graphs: ['male', 'female', 'unknown'], date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
},
},
device: {
name: 'Apparaten',
view: 'device',
viewfilters: ['goals'],
first: { dimension: 'date', dimension2: 'deviceCategory' },
second: { dimension: 'deviceCategory', sort: 'deviceCategory', sortorder: 'ASCENDING' },
third: { dimension: 'year', sort: 'year', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'sessions',
selectedmetrics: { 'sessions': true, 'totalUsers': true, 'screenPageViews': true, 'screenPageViewsPerSession': true, 'averageSessionDuration': true, 'newUsers': true, 'bounceRate': true, 'eventCount': true, 'eventCountPerUser': true },
metrics: ['sessions', 'totalUsers', 'screenPageViews', 'screenPageViewsPerSession', 'averageSessionDuration', 'newUsers', 'bounceRate', 'eventCount', 'eventCountPerUser'],
table: { dataset: 'second' },
panels: { dataset: 'third' },
charts: {
sessions: [{ 'chart': 'c1', 'name': 'Sessions', type: 'linemulti', dataset: 'first', graphs: ['desktop', 'mobile', 'tablet'], date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
users: [{ 'chart': 'c1', 'name': 'Users', type: 'linemulti', dataset: 'first', graphs: ['desktop', 'mobile', 'tablet'], date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviews: [{ 'chart': 'c1', 'name': 'PageViews', type: 'linemulti', dataset: 'first', graphs: ['desktop', 'mobile', 'tablet'], date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
pageviewsPerSession: [{ 'chart': 'c1', 'name': 'Pageviews per session', type: 'linemulti', dataset: 'first', graphs: ['desktop', 'mobile', 'tablet'], date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
avgSessionDuration: [{ 'chart': 'c1', 'name': 'Average session duration', type: 'linemulti', dataset: 'first', graphs: ['desktop', 'mobile', 'tablet'], date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
percentNewSessions: [{ 'chart': 'c1', 'name': 'Percentage new Sessions', type: 'linemulti', dataset: 'first', graphs: ['desktop', 'mobile', 'tablet'], date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
bounceRate: [{ 'chart': 'c1', 'name': 'Bounce ratio', type: 'linemulti', dataset: 'first', graphs: ['desktop', 'mobile', 'tablet'], date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
goalCompletionsAll: [{ 'chart': 'c1', 'name': 'Goals', type: 'linemulti', dataset: 'first', graphs: ['desktop', 'mobile', 'tablet'], date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
goalValueAll: [{ 'chart': 'c1', 'name': 'Goalvalue', type: 'linemulti', dataset: 'first', graphs: ['desktop', 'mobile', 'tablet'], date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
goalConversionRateAll: [{ 'chart': 'c1', 'name': 'Goalconverions ratio', type: 'linemulti', dataset: 'first', graphs: ['desktop', 'mobile', 'tablet'], date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
},
},
mobile: {
name: 'Mobiel',
view: 'mobile',
viewfilters: ['goals'],
first: { dimension: 'mobileDeviceBranding', sort: 'sessions', sortorder: 'DESCENDING' },
second: { dimension: 'mobileDeviceBranding', sort: 'year', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'sessions',
selectedmetrics: { 'sessions': true, 'totalUsers': true, 'screenPageViews': true, 'screenPageViewsPerSession': true, 'averageSessionDuration': true, 'newUsers': true, 'bounceRate': true, 'eventCount': true, 'eventCountPerUser': true },
metrics: ['sessions', 'totalUsers', 'screenPageViews', 'screenPageViewsPerSession', 'averageSessionDuration', 'newUsers', 'bounceRate', 'eventCount', 'eventCountPerUser'],
table: { dataset: 'first' },
panels: { dataset: 'second' },
charts: {
sessions: [{ 'chart': 'c1', 'name': 'Sessions', type: 'progress', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'first' }],
users: [{ 'chart': 'c1', 'name': 'Users', type: 'progress', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'first' }],
pageviews: [{ 'chart': 'c1', 'name': 'PageViews', type: 'progress', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'first' }],
pageviewsPerSession: [{ 'chart': 'c1', 'name': 'Pageviews per session', type: 'progress', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'first' }],
avgSessionDuration: [{ 'chart': 'c1', 'name': 'Average session duration', type: 'progress', dataset: 'first' }, { 'chart': 'c2', 'name': '_', 'type': 'pie', dataset: 'first' }],
percentNewSessions: [{ 'chart': 'c1', 'name': 'Percentage new Sessions', type: 'progress', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'first' }],
bounceRate: [{ 'chart': 'c1', 'name': 'Bounce ratio', type: 'progress', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'first' }],
goalCompletionsAll: [{ 'chart': 'c1', 'name': 'Goals', type: 'progress', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'first' }],
goalValueAll: [{ 'chart': 'c1', 'name': 'Goalvalue', type: 'progress', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'first' }],
goalConversionRateAll: [{ 'chart': 'c1', 'name': 'Goalconverions ratio', type: 'progress', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'first' }],
},
}
},
},
conversions: {
views: {
goals: {
name: 'Conversies',
view: 'goals',
first: { dimension: 'date' },
second: { dimension: 'eventName', sort: 'conversions', sortorder: 'DESCENDING' },
third: { dimension: 'year', sort: 'year', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'conversions',
selectedmetrics: { 'conversions': true, 'sessionConversionRate': true, 'eventValue': true },
metrics: ['conversions', 'sessionConversionRate', 'eventValue'],
table: { dataset: 'second' },
panels: { dataset: 'third' },
charts: {
conversions: [{ 'chart': 'c1', 'name': 'Conversies', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Conversies per gebeurtenis', type: 'pie', dataset: 'second' }],
sessionConversionRate: [{ 'chart': 'c1', 'name': 'Sessie conversieratio', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Conversieratio per gebeurtenis', type: 'bar', dataset: 'second' }],
eventValue: [{ 'chart': 'c1', 'name': 'Gebeurteniswaarde', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Waarde per gebeurtenis', type: 'pie', dataset: 'second' }],
},
},
ecommerce: {
name: 'Productprestaties',
view: 'ecommerce',
first: { dimension: 'date' },
second: { dimension: 'itemName', sort: 'itemsPurchased', sortorder: 'DESCENDING' },
third: { dimension: 'sessionDefaultChannelGrouping', sort: 'itemRevenue', sortorder: 'DESCENDING' },
selectedmetric: 'itemsPurchased',
// Metrics are now item-scoped to be compatible with itemName
selectedmetrics: { 'itemsPurchased': true, 'itemRevenue': true },
metrics: ['itemsPurchased', 'itemRevenue'],
table: { dataset: 'second' },
panels: { dataset: 'third' },
charts: {
itemsPurchased: [{ 'chart': 'c1', 'name': 'Aantal gekochte items', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Items per product', type: 'bar', dataset: 'second' }],
itemRevenue: [{ 'chart': 'c1', 'name': 'Productopbrengst', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Opbrengst per product', type: 'pie', dataset: 'second' }],
},
},
ecommerce_page: {
name: 'Ecommerce per Pagina',
view: 'ecommerce_page',
first: { dimension: 'date' },
second: { dimension: 'landingPage', sort: 'totalRevenue', sortorder: 'DESCENDING' },
third: { dimension: 'year', sort: 'year', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'totalRevenue',
selectedmetrics: { 'sessions': true, 'totalRevenue': true },
metrics: ['sessions', 'totalRevenue'],
table: { dataset: 'second' },
panels: { dataset: 'third' },
charts: {
sessions: [{ 'chart': 'c1', 'name': 'Sessies', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessies per pagina', type: 'bar', dataset: 'second' }],
totalRevenue: [{ 'chart': 'c1', 'name': 'Totale opbrengst', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Totale opbrengst per pagina', type: 'pie', dataset: 'second' }]
},
},
ecommerce_channel: {
name: 'Ecommerce per Kanaal',
view: 'ecommerce_channel',
first: { dimension: 'date' },
second: { dimension: 'sessionDefaultChannelGrouping', sort: 'totalRevenue', sortorder: 'DESCENDING' },
third: { dimension: 'year', sort: 'year', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'totalRevenue',
selectedmetrics: { 'sessions': true, 'totalRevenue': true },
metrics: ['sessions', 'totalRevenue'],
table: { dataset: 'second' },
panels: { dataset: 'third' },
charts: {
sessions: [{ 'chart': 'c1', 'name': 'Sessies', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessies per kanaal', type: 'bar', dataset: 'second' }],
totalRevenue: [{ 'chart': 'c1', 'name': 'Totale opbrengst', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Totale opbrengst per kanaal', type: 'pie', dataset: 'second' }]
},
},
},
},
pages: {
views: {
all: {
name: 'Alle Pagina\'s',
view: 'all',
viewfilters: ['goals', 'channels'],
first: { dimension: 'date' },
second: { dimension: 'landingPage', sort: 'screenPageViews', sortorder: 'DESCENDING' },
third: { dimension: 'year', sort: 'year', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'screenPageViews',
selectedmetrics: { 'screenPageViews': true, 'totalUsers': true, 'userEngagementDuration': true, 'engagementRate': true, 'conversions': true },
metrics: ['screenPageViews', 'totalUsers', 'userEngagementDuration', 'engagementRate', 'conversions'],
table: { dataset: 'second' },
panels: { dataset: 'third' },
charts: {
screenPageViews: [{ 'chart': 'c1', 'name': 'Paginaweergaven', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Pagina\'s', type: 'progress', dataset: 'second' }],
totalUsers: [{ 'chart': 'c1', 'name': 'Gebruikers', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Pagina\'s', type: 'progress', dataset: 'second' }],
userEngagementDuration: [{ 'chart': 'c1', 'name': 'Gemiddelde Betrokkenheidsduur', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Pagina\'s', type: 'progress', dataset: 'second' }],
engagementRate: [{ 'chart': 'c1', 'name': 'Betrokkenheidspercentage', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Pagina\'s', type: 'progress', dataset: 'second' }],
conversions: [{ 'chart': 'c1', 'name': 'Conversies', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Pagina\'s', type: 'progress', dataset: 'second' }],
},
},
landing: {
name: 'Landingspagina\'s',
view: 'landing',
first: { dimension: 'date' },
second: { dimension: 'landingPage', sort: 'sessions', sortorder: 'DESCENDING' },
third: { dimension: 'year', sort: 'year', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'sessions',
selectedmetrics: { 'sessions': true, 'totalUsers': true, 'averageSessionDuration': true, 'engagementRate': true, 'conversions': true },
metrics: ['sessions', 'totalUsers', 'averageSessionDuration', 'engagementRate', 'conversions'],
table: { dataset: 'second' },
panels: { dataset: 'third' },
charts: {
sessions: [{ 'chart': 'c1', 'name': 'Sessies', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Landingspagina\'s', type: 'progress', dataset: 'second' }],
totalUsers: [{ 'chart': 'c1', 'name': 'Gebruikers', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Landingspagina\'s', type: 'progress', dataset: 'second' }],
averageSessionDuration: [{ 'chart': 'c1', 'name': 'Gemiddelde Sessieduur', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Landingspagina\'s', type: 'progress', dataset: 'second' }],
engagementRate: [{ 'chart': 'c1', 'name': 'Betrokkenheidspercentage', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Landingspagina\'s', type: 'progress', dataset: 'second' }],
conversions: [{ 'chart': 'c1', 'name': 'Conversies', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Landingspagina\'s', type: 'progress', dataset: 'second' }],
},
},
titles: {
name: 'Paginatitels',
view: 'titles',
first: { dimension: 'date' },
second: { dimension: 'pageTitle', sort: 'screenPageViews', sortorder: 'DESCENDING' },
third: { dimension: 'year', sort: 'year', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'screenPageViews',
selectedmetrics: { 'screenPageViews': true, 'totalUsers': true, 'userEngagementDuration': true, 'engagementRate': true, 'conversions': true },
metrics: ['screenPageViews', 'totalUsers', 'userEngagementDuration', 'engagementRate', 'conversions'],
table: { dataset: 'second' },
panels: { dataset: 'third' },
charts: {
screenPageViews: [{ 'chart': 'c1', 'name': 'Paginaweergaven', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Pagina\'s', type: 'progress', dataset: 'second' }],
totalUsers: [{ 'chart': 'c1', 'name': 'Gebruikers', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Pagina\'s', type: 'progress', dataset: 'second' }],
userEngagementDuration: [{ 'chart': 'c1', 'name': 'Gemiddelde Betrokkenheidsduur', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Pagina\'s', type: 'progress', dataset: 'second' }],
engagementRate: [{ 'chart': 'c1', 'name': 'Betrokkenheidspercentage', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Pagina\'s', type: 'progress', dataset: 'second' }],
conversions: [{ 'chart': 'c1', 'name': 'Conversies', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Pagina\'s', type: 'progress', dataset: 'second' }],
},
},
},
},
events: {
views: {
all: {
name: 'Alle Gebeurtenissen',
view: 'all',
first: { dimension: 'date' },
second: { dimension: 'eventName', sort: 'eventCount', sortorder: 'DESCENDING' },
third: { dimension: 'year', sort: 'year', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'eventCount',
selectedmetrics: { 'eventCount': true, 'totalUsers': true, 'eventCountPerUser': true, 'eventValue': true },
metrics: ['eventCount', 'totalUsers', 'eventCountPerUser', 'eventValue'],
table: { dataset: 'second' },
panels: { dataset: 'third' },
charts: {
eventCount: [{ 'chart': 'c1', 'name': 'Aantal Gebeurtenissen', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Gebeurtenissen', type: 'bar', dataset: 'second' }],
totalUsers: [{ 'chart': 'c1', 'name': 'Totaal Aantal Gebruikers', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Gebeurtenissen', type: 'pie', dataset: 'second' }],
eventCountPerUser: [{ 'chart': 'c1', 'name': 'Gebeurtenissen per Gebruiker', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Gebeurtenissen', type: 'bar', dataset: 'second' }],
eventValue: [{ 'chart': 'c1', 'name': 'Gebeurteniswaarde', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Gebeurtenissen', type: 'pie', dataset: 'second' }],
},
},
conversions: {
name: 'Conversies',
view: 'conversions',
first: { dimension: 'date', filter: { 'isConversionEvent': true } },
second: { dimension: 'eventName', sort: 'eventCount', sortorder: 'DESCENDING', filter: { 'isConversionEvent': true } },
third: { dimension: 'year', sort: 'year', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'eventCount',
selectedmetrics: { 'eventCount': true, 'totalUsers': true, 'eventCountPerUser': true, 'eventValue': true },
metrics: ['eventCount', 'totalUsers', 'eventCountPerUser', 'eventValue'],
table: { dataset: 'second' },
panels: { dataset: 'third' },
charts: {
eventCount: [{ 'chart': 'c1', 'name': 'Aantal Conversies', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Conversies', type: 'bar', dataset: 'second' }],
totalUsers: [{ 'chart': 'c1', 'name': 'Totaal Aantal Gebruikers', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Conversies', type: 'pie', dataset: 'second' }],
eventCountPerUser: [{ 'chart': 'c1', 'name': 'Conversies per Gebruiker', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Conversies', type: 'bar', dataset: 'second' }],
eventValue: [{ 'chart': 'c1', 'name': 'Conversiewaarde', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Conversies', type: 'pie', dataset: 'second' }],
},
},
},
}
}
$scope.setAnalyticsCustomer = function (data) {
$http.get('/rest/' + $scope.cfg.urlbase + '/profileid.set', {
params: {
websiteid: h.siteId(),
property: data.property
}
}).then(function successCallback(res) {
$scope.getReportData();
});
}
$controller('coreapi', { $scope: $scope });
$scope.init();
}
]);
app.controller('matomo', ['$scope', '$timeout', '$http', '$rootScope', '$controller', '$filter', 'h',
function ($scope, $timeout, $http, $rootScope, $controller, $filter, h) {
$scope.cfg = {
dateformat: "YYYY-MM-DD",
dimensionprefix: '',
urlbase: 'matomo',
switchclient: true,
report_endpoint: '/rest/matomo/report',
}
$scope.gloMetrics = {
nb_visits: { name: 'Sessions', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
nb_actions: { name: 'Actions', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
nb_actions_per_visit: { name: 'Actions/Visit', typefilter: 'number', filtercomparator: 2, 'datemerge': 'avg' },
bounce_rate: { name: 'Bounce Rate', typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' },
avg_time_on_site: { name: 'Avg Session Duration', typefilter: 'secondsToHHmmss', filtercomparator: 0, 'datemerge': 'avg' },
nb_hits: { name: 'Pageviews', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
avg_time_on_page: { name: 'Avg Time on Page', typefilter: 'secondsToHHmmss', filtercomparator: 0, 'datemerge': 'avg' },
nb_conversions: { name: 'Conversions', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
revenue: { name: 'Revenue', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
nb_searches: { name: 'Site Searches', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
};
$scope.selectedmetrics = {};
$scope.reportconfig = {
visitors: {
views: {
all: {
name: 'All',
view: 'all',
first: { dimension: 'date' },
second: { dimension: 'referrerType', sort: 'nb_visits', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'nb_visits',
selectedmetrics: { 'nb_visits': true, 'nb_actions': true, 'nb_actions_per_visit': true, 'avg_time_on_site': true, 'bounce_rate': true },
metrics: ['nb_visits', 'nb_actions', 'nb_actions_per_visit', 'avg_time_on_site', 'bounce_rate'],
table: { dataset: 'second' },
panels: { dataset: 'first' },
charts: {
nb_visits: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions / referrer', type: 'pie', dataset: 'second' }],
nb_actions: [{ 'chart': 'c1', 'name': 'Actions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Actions / referrer', type: 'pie', dataset: 'second' }],
nb_actions_per_visit: [{ 'chart': 'c1', 'name': 'Actions per Visit', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Actions/Visit / referrer', type: 'bar', dataset: 'second' }],
avg_time_on_site: [{ 'chart': 'c1', 'name': 'Avg Session Duration', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
bounce_rate: [{ 'chart': 'c1', 'name': 'Bounce Rate', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
},
},
geographic: {
name: 'Geographic',
view: 'geographic',
first: { dimension: 'country', sort: 'nb_visits', sortorder: 'DESCENDING' },
second: { dimension: 'country', sort: 'nb_visits', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'nb_visits',
selectedmetrics: { 'nb_visits': true, 'nb_actions': true, 'nb_actions_per_visit': true, 'avg_time_on_site': true, 'bounce_rate': true },
metrics: ['nb_visits', 'nb_actions', 'nb_actions_per_visit', 'avg_time_on_site', 'bounce_rate'],
table: { dataset: 'first' },
panels: { dataset: 'second' },
charts: {
nb_visits: [{ 'chart': 'c1', 'name': 'Sessions', type: 'bar', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
nb_actions: [{ 'chart': 'c1', 'name': 'Actions', type: 'bar', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
nb_actions_per_visit: [{ 'chart': 'c1', 'name': 'Actions per Visit', type: 'bar', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
avg_time_on_site: [{ 'chart': 'c1', 'name': 'Avg Session Duration', type: 'bar', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
bounce_rate: [{ 'chart': 'c1', 'name': 'Bounce Rate', type: 'bar', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
},
},
device: {
name: 'Device',
view: 'device',
first: { dimension: 'deviceType', sort: 'nb_visits', sortorder: 'DESCENDING' },
second: { dimension: 'deviceType', sort: 'nb_visits', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'nb_visits',
selectedmetrics: { 'nb_visits': true, 'nb_actions': true, 'nb_actions_per_visit': true, 'avg_time_on_site': true, 'bounce_rate': true },
metrics: ['nb_visits', 'nb_actions', 'nb_actions_per_visit', 'avg_time_on_site', 'bounce_rate'],
table: { dataset: 'first' },
panels: { dataset: 'second' },
charts: {
nb_visits: [{ 'chart': 'c1', 'name': 'Sessions', type: 'bar', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
nb_actions: [{ 'chart': 'c1', 'name': 'Actions', type: 'bar', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
nb_actions_per_visit: [{ 'chart': 'c1', 'name': 'Actions per Visit', type: 'bar', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
avg_time_on_site: [{ 'chart': 'c1', 'name': 'Avg Session Duration', type: 'bar', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
bounce_rate: [{ 'chart': 'c1', 'name': 'Bounce Rate', type: 'bar', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
},
},
browser: {
name: 'Browser',
view: 'browser',
first: { dimension: 'browser', sort: 'nb_visits', sortorder: 'DESCENDING' },
second: { dimension: 'browser', sort: 'nb_visits', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'nb_visits',
selectedmetrics: { 'nb_visits': true, 'nb_actions': true, 'bounce_rate': true },
metrics: ['nb_visits', 'nb_actions', 'bounce_rate'],
table: { dataset: 'first' },
panels: { dataset: 'second' },
charts: {
nb_visits: [{ 'chart': 'c1', 'name': 'Sessions', type: 'progress', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'first' }],
nb_actions: [{ 'chart': 'c1', 'name': 'Actions', type: 'progress', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'first' }],
bounce_rate: [{ 'chart': 'c1', 'name': 'Bounce Rate', type: 'progress', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'first' }],
},
},
os: {
name: 'Operating System',
view: 'os',
first: { dimension: 'os', sort: 'nb_visits', sortorder: 'DESCENDING' },
second: { dimension: 'os', sort: 'nb_visits', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'nb_visits',
selectedmetrics: { 'nb_visits': true, 'nb_actions': true, 'bounce_rate': true },
metrics: ['nb_visits', 'nb_actions', 'bounce_rate'],
table: { dataset: 'first' },
panels: { dataset: 'second' },
charts: {
nb_visits: [{ 'chart': 'c1', 'name': 'Sessions', type: 'progress', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'first' }],
nb_actions: [{ 'chart': 'c1', 'name': 'Actions', type: 'progress', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'first' }],
bounce_rate: [{ 'chart': 'c1', 'name': 'Bounce Rate', type: 'progress', dataset: 'first' }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'first' }],
},
},
},
},
channels: {
views: {
all: {
name: 'All',
view: 'all',
first: { dimension: 'date' },
second: { dimension: 'referrerType', sort: 'nb_visits', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'nb_visits',
selectedmetrics: { 'nb_visits': true, 'nb_actions': true, 'nb_actions_per_visit': true, 'avg_time_on_site': true, 'bounce_rate': true },
metrics: ['nb_visits', 'nb_actions', 'nb_actions_per_visit', 'avg_time_on_site', 'bounce_rate'],
table: { dataset: 'second' },
panels: { dataset: 'first' },
charts: {
nb_visits: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions / channel', type: 'pie', dataset: 'second' }],
nb_actions: [{ 'chart': 'c1', 'name': 'Actions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Actions / channel', type: 'pie', dataset: 'second' }],
nb_actions_per_visit: [{ 'chart': 'c1', 'name': 'Actions per Visit', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
avg_time_on_site: [{ 'chart': 'c1', 'name': 'Avg Session Duration', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
bounce_rate: [{ 'chart': 'c1', 'name': 'Bounce Rate', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
},
},
organic: {
name: 'Organic',
view: 'organic',
first: { dimension: 'date' },
second: { dimension: 'searchEngine', sort: 'nb_visits', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'nb_visits',
selectedmetrics: { 'nb_visits': true, 'nb_actions': true, 'bounce_rate': true },
metrics: ['nb_visits', 'nb_actions', 'bounce_rate'],
table: { dataset: 'second' },
panels: { dataset: 'first' },
charts: {
nb_visits: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
nb_actions: [{ 'chart': 'c1', 'name': 'Actions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
bounce_rate: [{ 'chart': 'c1', 'name': 'Bounce Rate', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
},
},
social: {
name: 'Social',
view: 'social',
first: { dimension: 'date' },
second: { dimension: 'socialNetwork', sort: 'nb_visits', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'nb_visits',
selectedmetrics: { 'nb_visits': true, 'nb_actions': true, 'bounce_rate': true },
metrics: ['nb_visits', 'nb_actions', 'bounce_rate'],
table: { dataset: 'second' },
panels: { dataset: 'first' },
charts: {
nb_visits: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
nb_actions: [{ 'chart': 'c1', 'name': 'Actions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
bounce_rate: [{ 'chart': 'c1', 'name': 'Bounce Rate', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
},
},
referral: {
name: 'Referral',
view: 'referral',
first: { dimension: 'date' },
second: { dimension: 'website', sort: 'nb_visits', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'nb_visits',
selectedmetrics: { 'nb_visits': true, 'nb_actions': true, 'bounce_rate': true },
metrics: ['nb_visits', 'nb_actions', 'bounce_rate'],
table: { dataset: 'second' },
panels: { dataset: 'first' },
charts: {
nb_visits: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
nb_actions: [{ 'chart': 'c1', 'name': 'Actions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
bounce_rate: [{ 'chart': 'c1', 'name': 'Bounce Rate', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
},
},
campaigns: {
name: 'Campaigns',
view: 'campaigns',
first: { dimension: 'date' },
second: { dimension: 'campaign', sort: 'nb_visits', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'nb_visits',
selectedmetrics: { 'nb_visits': true, 'nb_actions': true, 'bounce_rate': true },
metrics: ['nb_visits', 'nb_actions', 'bounce_rate'],
table: { dataset: 'second' },
panels: { dataset: 'first' },
charts: {
nb_visits: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
nb_actions: [{ 'chart': 'c1', 'name': 'Actions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'pie', dataset: 'second' }],
bounce_rate: [{ 'chart': 'c1', 'name': 'Bounce Rate', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': '_', type: 'bar', dataset: 'second' }],
},
},
},
},
pages: {
views: {
all: {
name: 'All Pages',
view: 'all',
first: { dimension: 'date' },
second: { dimension: 'pageUrl', sort: 'nb_hits', sortorder: 'DESCENDING' },
selectedmetric: 'nb_hits',
selectedmetrics: { 'nb_hits': true, 'nb_visits': true, 'bounce_rate': true, 'avg_time_on_page': true },
metrics: ['nb_hits', 'nb_visits', 'bounce_rate', 'avg_time_on_page'],
table: { dataset: 'second' },
panels: { dataset: 'first' },
charts: {
nb_hits: [{ 'chart': 'c1', 'name': 'Pageviews', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Pages', type: 'progress', dataset: 'second' }],
nb_visits: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Pages', type: 'progress', dataset: 'second' }],
bounce_rate: [{ 'chart': 'c1', 'name': 'Bounce Rate', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Pages', type: 'progress', dataset: 'second' }],
avg_time_on_page: [{ 'chart': 'c1', 'name': 'Avg Time on Page', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Pages', type: 'progress', dataset: 'second' }],
},
},
titles: {
name: 'Page Titles',
view: 'titles',
first: { dimension: 'date' },
second: { dimension: 'pageTitle', sort: 'nb_hits', sortorder: 'DESCENDING' },
selectedmetric: 'nb_hits',
selectedmetrics: { 'nb_hits': true, 'nb_visits': true, 'bounce_rate': true, 'avg_time_on_page': true },
metrics: ['nb_hits', 'nb_visits', 'bounce_rate', 'avg_time_on_page'],
table: { dataset: 'second' },
panels: { dataset: 'first' },
charts: {
nb_hits: [{ 'chart': 'c1', 'name': 'Pageviews', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Pages', type: 'progress', dataset: 'second' }],
nb_visits: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Pages', type: 'progress', dataset: 'second' }],
bounce_rate: [{ 'chart': 'c1', 'name': 'Bounce Rate', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Pages', type: 'progress', dataset: 'second' }],
avg_time_on_page: [{ 'chart': 'c1', 'name': 'Avg Time on Page', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Pages', type: 'progress', dataset: 'second' }],
},
},
entry: {
name: 'Entry Pages',
view: 'entry',
first: { dimension: 'date' },
second: { dimension: 'entryPage', sort: 'nb_visits', sortorder: 'DESCENDING' },
selectedmetric: 'nb_visits',
selectedmetrics: { 'nb_visits': true, 'bounce_rate': true },
metrics: ['nb_visits', 'bounce_rate'],
table: { dataset: 'second' },
panels: { dataset: 'first' },
charts: {
nb_visits: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Entry Pages', type: 'progress', dataset: 'second' }],
bounce_rate: [{ 'chart': 'c1', 'name': 'Bounce Rate', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Entry Pages', type: 'progress', dataset: 'second' }],
},
},
exit: {
name: 'Exit Pages',
view: 'exit',
first: { dimension: 'date' },
second: { dimension: 'exitPage', sort: 'nb_visits', sortorder: 'DESCENDING' },
selectedmetric: 'nb_visits',
selectedmetrics: { 'nb_visits': true },
metrics: ['nb_visits'],
table: { dataset: 'second' },
panels: { dataset: 'first' },
charts: {
nb_visits: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Exit Pages', type: 'progress', dataset: 'second' }],
},
},
},
},
events: {
views: {
categories: {
name: 'Event Categories',
view: 'categories',
first: { dimension: 'date' },
second: { dimension: 'eventCategory', sort: 'nb_visits', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'nb_visits',
selectedmetrics: { 'nb_visits': true, 'nb_actions': true },
metrics: ['nb_visits', 'nb_actions'],
table: { dataset: 'second' },
panels: { dataset: 'first' },
charts: {
nb_visits: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Categories', type: 'bar', dataset: 'second' }],
nb_actions: [{ 'chart': 'c1', 'name': 'Actions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Categories', type: 'pie', dataset: 'second' }],
},
},
actions: {
name: 'Event Actions',
view: 'actions',
first: { dimension: 'date' },
second: { dimension: 'eventAction', sort: 'nb_visits', sortorder: 'DESCENDING', 'allowcomp': true },
selectedmetric: 'nb_visits',
selectedmetrics: { 'nb_visits': true, 'nb_actions': true },
metrics: ['nb_visits', 'nb_actions'],
table: { dataset: 'second' },
panels: { dataset: 'first' },
charts: {
nb_visits: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Actions', type: 'bar', dataset: 'second' }],
nb_actions: [{ 'chart': 'c1', 'name': 'Actions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Top Actions', type: 'pie', dataset: 'second' }],
},
},
},
},
};
// Object for modal form binding (dot rule for ng-include child scope)
$scope.matomoForm = { url: '', token: '', error: null, connecting: false };
// Custom connect function for Matomo (form-based, not OAuth)
$scope.fnMatomoConnect = function () {
$scope.matomoForm.error = null;
$scope.matomoForm.connecting = true;
$http.post('/rest/matomo/connect', {
websiteid: h.siteId(),
url: $scope.matomoForm.url,
token_auth: $scope.matomoForm.token,
}).then(function (res) {
$scope.matomoForm.connecting = false;
if (res.data.error) {
$scope.matomoForm.error = res.data.error;
} else {
$scope.getCustomer();
}
}, function () {
$scope.matomoForm.connecting = false;
$scope.matomoForm.error = 'Connection failed. Please check the URL and try again.';
});
}
// Custom site selector for Matomo
$scope.setMatomoCustomer = function (data) {
$http.get('/rest/matomo/profileid.set', {
params: {
websiteid: h.siteId(),
idsite: data.idsite
}
}).then(function () {
$scope.getReportData();
});
}
$controller('coreapi', { $scope: $scope });
$scope.init();
}
]);
app.controller('youtube', ['$scope', '$timeout', '$http', '$rootScope', '$controller', '$filter', 'h',
function($scope, $timeout, $http, $rootScope, $controller, $filter, h) {
$scope.cfg = {
authurl: 'https://app.pageowl.app/rest/youtube/connect?site_id=' + h.siteId(),
dateformat: "YYYY-MM-DD",
dimensionprefix: '',
urlbase: 'youtube',
report_endpoint: '/rest/youtube/report',
}
$scope.gloMetrics = h.metrics('youtube');
/* $scope.gloMetrics = {
commentCount: { name: 'Clicks', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
subscriberCount: { name: 'Impressions', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
videoCount: { name: 'Date', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
viewCount: { name: 'Avg cost / Click', typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
views: { name: 'Ctr', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
shares: { name: 'Conversions', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
likes: { name: 'Cost', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
dislikes: { name: 'Cost / conversion', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
comments: { name: 'Conversion rate', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
subscribersGained: { name: 'AbsoluteTopImpressionPercentage', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
subscribersLost: { name: 'Conversion value', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
estimatedMinutesWatched: { name: 'Zoekimpressie aandeel', typefilter: 'number', filtercomparator: 1, 'datemerge': 'sum' },
annotationCloseRate: { name: 'Top Positie', typefilter: 'number', filtercomparator: 2, 'after': '%', 'datemerge': 'avg' },
annotationClickThroughRate: { name: 'ROAS', typefilter: 'number', filtercomparator: 2, 'after': '%', 'datemerge': 'avg' },
averageViewDuration: { name: 'ROAS', typefilter: 'secondsToHHmmss', filtercomparator: 0, 'datemerge': 'avg' },
};
*/
$scope.fnFormatAd = function(d) {
return d.HeadlinePart1 + d.HeadlinePart2 + d.Description + d.CreativeDestinationUrl + d.CreativeFinalUrls;
}
$scope.reportconfig = {
channel: {
views: {
overview: {
name: 'Overview',
view: 'overview',
second: { dimension: 'Date', report: 'analytics', 'allowcomp': true },
third: { dimension: 'insightTrafficSourceType', report: 'analytics', metrics: ['views', 'estimatedMinutesWatched'] },
selectedmetric: 'views',
selectedmetrics: { 'Clicks': true, 'Impressions': true, 'Cost': true, 'AverageCpc': true, 'Ctr': true, 'Conversions': true, 'CostPerConversion': true, 'ConversionRate': true, 'AbsoluteTopImpressionPercentage': true, 'ConversionValue': true, 'SearchImpressionShare': true, 'roas': true },
metrics: ['views', 'shares', 'likes', 'dislikes', 'comments', 'subscribersGained', 'subscribersLost', 'estimatedMinutesWatched', 'annotationCloseRate', 'annotationClickThroughRate', 'averageViewDuration'],
//table: { dataset: 'second' },
panels: { dataset: 'second' },
charts: {
views: [{ 'chart': 'c1', 'name': 'views', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
shares: [{ 'chart': 'c1', 'name': 'Shares', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
likes: [{ 'chart': 'c1', 'name': 'Likes', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
dislikes: [{ 'chart': 'c1', 'name': 'Dislikes', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
comments: [{ 'chart': 'c1', 'name': 'Comments', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
subscribersGained: [{ 'chart': 'c1', 'name': 'Subscribers Gained', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
subscribersLost: [{ 'chart': 'c1', 'name': 'Subscribers Lost', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
estimatedMinutesWatched: [{ 'chart': 'c1', 'name': 'Minutes Watched', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
AbsoluteTopImpressionPercentage: [{ 'chart': 'c1', 'name': 'Average position', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
ConversionValue: [{ 'chart': 'c1', 'name': 'Conversion value', type: 'line', dataset: 'second', date: true },{ 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
},
},
anderekak: {
name: 'Overview',
view: 'anderekak',
first: { dimension: 'Date', report: 'channelstats' },
selectedmetric: 'views',
selectedmetrics: { 'Clicks': true, 'Impressions': true, 'Cost': true, 'AverageCpc': true, 'Ctr': true, 'Conversions': true, 'CostPerConversion': true, 'ConversionRate': true, 'AbsoluteTopImpressionPercentage': true, 'ConversionValue': true, 'SearchImpressionShare': true, 'roas': true },
metrics: ['commentCount', 'subscriberCount', 'videoCount', 'viewCount'],
//table: { dataset: 'second' },
panels: { dataset: 'second' },
charts: {
views: [{ 'chart': 'c1', 'name': 'views', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
shares: [{ 'chart': 'c1', 'name': 'Shares', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
likes: [{ 'chart': 'c1', 'name': 'Likes', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
dislikes: [{ 'chart': 'c1', 'name': 'Dislikes', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
comments: [{ 'chart': 'c1', 'name': 'Comments', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
subscribersGained: [{ 'chart': 'c1', 'name': 'Subscribers Gained', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
subscribersLost: [{ 'chart': 'c1', 'name': 'Subscribers Lost', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
estimatedMinutesWatched: [{ 'chart': 'c1', 'name': 'Minutes Watched', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
AbsoluteTopImpressionPercentage: [{ 'chart': 'c1', 'name': 'Average position', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
ConversionValue: [{ 'chart': 'c1', 'name': 'Conversion value', type: 'line', dataset: 'second', date: true },{ 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
},
},
videos: {
name: 'Ad Groups',
view: 'videos',
first: { dimension: 'Date', report: 'videos' },
//second: { dimension: 'AverageCpm', sort: 'sessions', sortorder: 'DESCENDING', },
selectedmetric: 'Clicks',
metrics: ['Clicks'],
},
},
}
}
$controller('coreapi', { $scope: $scope });
$scope.init();
}
]);
app.controller('googleads', ['$scope', '$timeout', '$http', '$rootScope', '$controller', '$filter', 'h',
function ($scope, $timeout, $http, $rootScope, $controller, $filter, h) {
$scope.cfg = {
authurl: 'https://app.marketingtracer.com/rest/googlexads/connect?websiteid=' + h.siteId(),
dateformat: "YYYY-MM-DD",
dimensionprefix: '',
urlbase: 'googlexads',
switchclient: true,
report_endpoint: '/rest/googlexads/report',
}
if ($rootScope.user.reseller?.config?.authdomain) {
$scope.cfg.authurl = 'https://' + $rootScope.user.reseller.config.authdomain + '/rest/googlexads/connect?websiteid=' + h.siteId();
}
$scope.gloMetrics = h.metrics('googlexads');
/* $scope.gloMetrics = {
Clicks: { name: 'Clicks', typefilter: 'number', filtercomparator: 0 ,'datemerge':'sum'},
Impressions: { name: 'Impressions', typefilter: 'number', filtercomparator: 0 ,'datemerge':'sum'},
Date: { name: 'Date', typefilter: 'number', filtercomparator: 0 ,'datemerge':'sum'},
AverageCpc: { name: 'Avg cost / Click', typefilter: 'number', filtercomparator: 2, 'before': '€' ,'datemerge':'avg'},
Ctr: { name: 'Ctr', typefilter: 'number', filtercomparator: 0, 'after': '%' ,'datemerge':'avg'},
Conversions: { name: 'Conversions', typefilter: 'number', filtercomparator: 0 ,'datemerge':'sum'},
Cost: { name: 'Cost', typefilter: 'number', filtercomparator: 2, 'before': '€' ,'datemerge':'sum'},
CostPerConversion: { name: 'Cost / conversion', typefilter: 'number', filtercomparator: 2, 'before': '€' ,'datemerge':'avg'},
ConversionRate: { name: 'Conversion rate', typefilter: 'number', filtercomparator: 0, 'after': '%' ,'datemerge':'avg'},
AbsoluteTopImpressionPercentage: { name: 'AbsoluteTopImpressionPercentage', typefilter: 'number', filtercomparator: 0, 'after': '%' ,'datemerge':'avg'},
ConversionValue: { name: 'Conversion value', typefilter: 'number', filtercomparator: 0, 'before': '€' ,'datemerge':'sum'},
SearchImpressionShare: { name: 'Zoekimpressie aandeel', typefilter: 'number', filtercomparator: 2, 'after': '%' ,'datemerge':'avg'},
SearchAbsoluteTopImpressionShare: { name: 'Top Positie', typefilter: 'number', filtercomparator: 2, 'after': '%' ,'datemerge':'avg'},
roas: { name: 'ROAS', typefilter: 'number', filtercomparator: 2, 'after': '%' ,'datemerge':'avg'},
};*/
$scope.fnFormatAd = function (d) {
return d.HeadlinePart1 + d.HeadlinePart2 + d.Description + d.CreativeDestinationUrl + d.CreativeFinalUrls;
}
$scope.reportconfig = {
campaigns: {
views: {
all: {
name: 'Campaigns',
view: 'all',
first: { dimension: 'Date', report: 'ACCOUNT_PERFORMANCE_REPORT' },
second: { dimension: 'CampaignName', report: 'CAMPAIGN_PERFORMANCE_REPORT', 'allowcomp': true },
selectedmetric: 'Clicks',
selectedmetrics: { 'Clicks': true, 'Impressions': true, 'Cost': true, 'AverageCpc': true, 'Ctr': true, 'Conversions': true, 'CostPerConversion': true, 'ConversionRate': true, 'AbsoluteTopImpressionPercentage': true, 'ConversionValue': true, 'SearchImpressionShare': true, 'roas': true },
metrics: ['Clicks', 'Impressions', 'Cost', 'AverageCpc', 'Ctr', 'Conversions', 'CostPerConversion', 'ConversionRate', 'AbsoluteTopImpressionPercentage', 'ConversionValue', 'roas'],
table: { dataset: 'second' },
panels: { dataset: 'second' },
charts: {
Clicks: [{ 'chart': 'c1', 'name': 'Clicks', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Clicks / Campaign', type: 'progress', dataset: 'second' }],
Impressions: [{ 'chart': 'c1', 'name': 'Impressions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Impressions / Campaign', type: 'progress', dataset: 'second' }],
Cost: [{ 'chart': 'c1', 'name': 'Kosten', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions / Campaign', type: 'progress', dataset: 'second' }],
AverageCpc: [{ 'chart': 'c1', 'name': 'Avg cost / Click', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'CPC / Campaign', type: 'progress', dataset: 'second' }],
Ctr: [{ 'chart': 'c1', 'name': 'Ctr', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Ctr / Campaign', type: 'progress', dataset: 'second' }],
Conversions: [{ 'chart': 'c1', 'name': 'Conversies', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Conversies / Campaign', type: 'progress', dataset: 'second' }],
CostPerConversion: [{ 'chart': 'c1', 'name': 'Cost / conversion', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Cost / conversion / Campaign', type: 'progress', dataset: 'second' }],
ConversionRate: [{ 'chart': 'c1', 'name': 'Conversion rate', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Conversion rate / Campaign', type: 'progress', dataset: 'second' }],
AbsoluteTopImpressionPercentage: [{ 'chart': 'c1', 'name': 'Average position', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Average position / Campaign', type: 'progress', dataset: 'second' }],
ConversionValue: [{ 'chart': 'c1', 'name': 'Conversion value', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Conversion value / Campaign', type: 'progress', dataset: 'second' }],
},
},
adgroups: {
name: 'Ad Groups',
view: 'adgroups',
first: { dimension: 'Date', report: 'ACCOUNT_PERFORMANCE_REPORT' },
second: { dimension: 'AdGroupName', report: 'ADGROUP_PERFORMANCE_REPORT', 'allowcomp': true },
//second: { dimension: 'AverageCpm', sort: 'sessions', sortorder: 'DESCENDING', },
selectedmetric: 'Clicks',
selectedmetrics: { 'Clicks': true, 'Impressions': true, 'Cost': true, 'AverageCpc': true, 'Ctr': true, 'Conversions': true, 'CostPerConversion': true, 'ConversionRate': true, 'AbsoluteTopImpressionPercentage': true, 'ConversionValue': true, 'SearchImpressionShare': true, 'roas': true },
metrics: ['Clicks', 'Impressions', 'Cost', 'AverageCpc', 'Ctr', 'Conversions', 'CostPerConversion', 'ConversionRate', 'AbsoluteTopImpressionPercentage', 'ConversionValue', 'roas'],
table: { dataset: 'second' },
panels: { dataset: 'second' },
charts: {
Clicks: [{ 'chart': 'c1', 'name': 'Clicks', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Clicks / Adgroup', type: 'progress', dataset: 'second' }],
Impressions: [{ 'chart': 'c1', 'name': 'Impressions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Impressions / Adgroup', type: 'progress', dataset: 'second' }],
Cost: [{ 'chart': 'c1', 'name': 'Kosten', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions / Adgroup', type: 'progress', dataset: 'second' }],
AverageCpc: [{ 'chart': 'c1', 'name': 'Avg cost / Click', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'CPC / Adgroup', type: 'progress', dataset: 'second' }],
Ctr: [{ 'chart': 'c1', 'name': 'Ctr', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Ctr / Adgroup', type: 'progress', dataset: 'second' }],
Conversions: [{ 'chart': 'c1', 'name': 'Conversies', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Conversies / Adgroup', type: 'progress', dataset: 'second' }],
CostPerConversion: [{ 'chart': 'c1', 'name': 'Cost / conversion', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Cost / conversion / Adgroup', type: 'progress', dataset: 'second' }],
ConversionRate: [{ 'chart': 'c1', 'name': 'Conversion rate', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Conversion rate / Adgroup', type: 'progress', dataset: 'second' }],
AbsoluteTopImpressionPercentage: [{ 'chart': 'c1', 'name': 'Average position', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Average position / Adgroup', type: 'progress', dataset: 'second' }],
ConversionValue: [{ 'chart': 'c1', 'name': 'Conversion value', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Conversion value / Adgroup', type: 'progress', dataset: 'second' }],
},
},
keywords: {
name: 'Keywords',
view: 'keywords',
first: { dimension: 'Date', report: 'ACCOUNT_PERFORMANCE_REPORT' },
second: { dimension: 'Query', report: 'SEARCH_QUERY_PERFORMANCE_REPORT', 'allowcomp': true },
selectedmetric: 'Clicks',
selectedmetrics: { 'Clicks': true, 'Impressions': true, 'Cost': true, 'AverageCpc': true, 'Ctr': true, 'Conversions': true, 'CostPerConversion': true, 'ConversionRate': true, 'AbsoluteTopImpressionPercentage': true, 'ConversionValue': true, 'roas': true },
metrics: ['Clicks', 'Impressions', 'Cost', 'AverageCpc', 'Ctr', 'Conversions', 'CostPerConversion', 'ConversionRate', 'AbsoluteTopImpressionPercentage', 'ConversionValue', 'roas'],
table: { dataset: 'second' },
panels: { dataset: 'second' },
charts: {
Clicks: [{ 'chart': 'c1', 'name': 'Clicks', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Clicks / Keyword', type: 'bar', dataset: 'second' }],
Impressions: [{ 'chart': 'c1', 'name': 'Impressions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Impressions / Keyword', type: 'bar', dataset: 'second' }],
Cost: [{ 'chart': 'c1', 'name': 'Kosten', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions / Keyword', type: 'bar', dataset: 'second' }],
AverageCpc: [{ 'chart': 'c1', 'name': 'Avg cost / Click', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'CPC / Keyword', type: 'bar', dataset: 'second' }],
Ctr: [{ 'chart': 'c1', 'name': 'Ctr', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Ctr / Keyword', type: 'bar', dataset: 'second' }],
Conversions: [{ 'chart': 'c1', 'name': 'Conversies', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Conversies / Keyword', type: 'bar', dataset: 'second' }],
CostPerConversion: [{ 'chart': 'c1', 'name': 'Cost / conversion', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Cost / conversion / Keyword', type: 'bar', dataset: 'second' }],
ConversionRate: [{ 'chart': 'c1', 'name': 'Conversion rate', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Conversion rate / Keyword', type: 'bar', dataset: 'second' }],
AbsoluteTopImpressionPercentage: [{ 'chart': 'c1', 'name': 'Average position', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Average position / Keyword', type: 'bar', dataset: 'second' }],
ConversionValue: [{ 'chart': 'c1', 'name': 'Conversion value', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Conversion value / Keyword', type: 'bar', dataset: 'second' }],
},
},
// ads: {
// name: 'Ads',
// view: 'ads',
// first: { dimension: 'Date', report: 'ACCOUNT_PERFORMANCE_REPORT', 'allowcomp': true },
// second: { dimension: 'HeadlinePart1,HeadlinePart2,Description,CreativeDestinationUrl,CreativeFinalUrls', function: 'fnFormatAd', report: 'AD_PERFORMANCE_REPORT' },
// selectedmetric: 'Clicks',
// selectedmetrics: { 'Clicks': true, 'Impressions': true, 'Cost': true, 'AverageCpc': true, 'Ctr': true, 'Conversions': true, 'CostPerConversion': true, 'ConversionRate': true, 'AbsoluteTopImpressionPercentage': true, 'ConversionValue': true, 'roas': true },
// metrics: ['Clicks', 'Impressions', 'Cost', 'AverageCpc', 'Ctr', 'Conversions', 'CostPerConversion', 'ConversionRate', 'AbsoluteTopImpressionPercentage', 'ConversionValue', 'roas'],
// table: { dataset: 'second' },
// panels: { dataset: 'second' },
// charts: {
// Clicks: [{ 'chart': 'c1', 'name': 'Clicks', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Clicks / Ad', type: 'bar', dataset: 'second' }],
// Impressions: [{ 'chart': 'c1', 'name': 'Impressions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Impressions / Ad', type: 'bar', dataset: 'second' }],
// Cost: [{ 'chart': 'c1', 'name': 'Kosten', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions / Ad', type: 'bar', dataset: 'second' }],
// AverageCpc: [{ 'chart': 'c1', 'name': 'Avg cost / Click', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'CPC / Ad', type: 'bar', dataset: 'second' }],
// Ctr: [{ 'chart': 'c1', 'name': 'Ctr', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Ctr / Ad', type: 'bar', dataset: 'second' }],
// Conversions: [{ 'chart': 'c1', 'name': 'Conversies', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Conversies / Ad', type: 'bar', dataset: 'second' }],
// CostPerConversion: [{ 'chart': 'c1', 'name': 'Cost / conversion', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Cost / conversion / Ad', type: 'bar', dataset: 'second' }],
// ConversionRate: [{ 'chart': 'c1', 'name': 'Conversion rate', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Conversion rate / Ad', type: 'bar', dataset: 'second' }],
// AbsoluteTopImpressionPercentage: [{ 'chart': 'c1', 'name': 'Average position', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Average position / Ad', type: 'bar', dataset: 'second' }],
// ConversionValue: [{ 'chart': 'c1', 'name': 'Conversion value', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Conversion value / Ad', type: 'bar', dataset: 'second' }],
// },
// },
// conversions: {
// name: 'Conversions',
// view: 'conversions',
// first: { dimension: 'Date', report: 'ACCOUNT_PERFORMANCE_REPORT' },
// second: { dimension: 'ConversionTypeName', report: 'ACCOUNT_PERFORMANCE_REPORT', 'allowcomp': true },
// selectedmetric: 'Conversions',
// selectedmetrics: { 'Conversions': true, 'ConversionValue': true },
// //metrics: ['Conversions', 'CostPerConversion', 'ConversionRate', 'ConversionValue'],
// metrics: ['Conversions','ConversionValue'],
// table: { dataset: 'second' },
// panels: { dataset: 'second' },
// charts: {
// Clicks: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions / Channel', type: 'bar', dataset: 'second' }],
// Impressions: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions / Channel', type: 'bar', dataset: 'second' }],
// Cost: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions / Channel', type: 'bar', dataset: 'second' }],
// AverageCpc: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions / Channel', type: 'bar', dataset: 'second' }],
// Ctr: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions / Channel', type: 'bar', dataset: 'second' }],
// Conversions: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions / Channel', type: 'bar', dataset: 'second' }],
// CostPerConversion: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions / Channel', type: 'bar', dataset: 'second' }],
// ConversionRate: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions / Channel', type: 'bar', dataset: 'second' }],
// AbsoluteTopImpressionPercentage: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions / Channel', type: 'bar', dataset: 'second' }],
// ConversionValue: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions / Channel', type: 'bar', dataset: 'second' }],
// },
// },
},
}
}
$controller('coreapi', { $scope: $scope });
$scope.init();
}
]);
app.controller('facebookads', ['$scope', '$timeout', '$http', '$rootScope', '$controller', '$filter', 'h',
function($scope, $timeout, $http, $rootScope, $controller, $filter, h) {
$scope.cfg = {
authurl: 'https://app.marketingtracer.com/rest/facebookads/connect?websiteid=' + h.siteId(),
dateformat: "YYYY-MM-DD",
dimensionprefix: '',
urlbase: 'facebookads',
report_endpoint: '/rest/facebookads/report',
}
$scope.gloMetrics = h.metrics('facebookads');
/* $scope.gloMetrics = {
clicks: { name: 'Klikken', typefilter: 'number', filtercomparator: 0 ,'datemerge':'sum'},
impressions: { name: 'Impressies', typefilter: 'number', filtercomparator: 0 ,'datemerge':'sum'},
cpc: { name: 'cpc', typefilter: 'number', filtercomparator: 2, 'before': '€' ,'datemerge':'avg'},
cpm: { name: 'cpm', typefilter: 'number', filtercomparator: 2, 'before': '€' ,'datemerge':'avg'},
ctr: { name: 'Ctr', typefilter: 'number', filtercomparator: 2, 'after': '%' ,'datemerge':'avg'},
Conversions: { name: 'Conversions', typefilter: 'number', filtercomparator: 0 ,'datemerge':'sum'},
Cost: { name: 'Cost', typefilter: 'number', filtercomparator: 0, 'before': '€' ,'datemerge':'sum'},
CostPerConversion: { name: $filter('translate')('metrics.spend')+' / conversie', typefilter: 'number', filtercomparator: 0, 'before': '€' ,'datemerge':'avg'},
ConversionRate: { name: 'Conversie ratio', typefilter: 'number', filtercomparator: 0, 'after': '%' ,'datemerge':'avg'},
AveragePosition: { name: 'Gemiddelde positie', typefilter: 'number', filtercomparator: 0 ,'datemerge':'avg'},
ConversionValue: { name: 'Totale conversiewaarde', typefilter: 'number', filtercomparator: 0, 'before': '€' ,'datemerge':'sum'},
relevance_score: { name: 'Relevantie Score', typefilter: 'number', filtercomparator: 0, hide: { 'panel': true } ,'datemerge':'avg'},
spend: { name: 'Kosten', typefilter: 'number', filtercomparator: 2, 'before': '€' ,'datemerge':'sum'},
};
*/
$scope.reportconfig = {
campaigns: {
views: {
all: {
name: 'Campagnes',
view: 'all',
viewfilters: ['campaigns'],
first: { dimension: 'date', level: 'account', 'endpoint': 'insights' },
second: { dimension: 'campaign_name', level: 'campaign', 'endpoint': 'insights', 'summary': 'clicks,impressions,cpc,cpm', 'allowcomp': true },
selectedmetric: 'clicks',
selectedmetrics: { 'clicks': true, 'impressions': true, 'cpc': true, 'cpm': true },
metrics: ['clicks', 'impressions', 'cpc', 'cpm','conversion_values','conversions','cost_per_conversion','website_ctr','website_purchase_roas'],
table: { dataset: 'second' },
panels: { dataset: 'second' },
charts: {
clicks: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.clicks') + ' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.clicks') + ' / Campaign', type: 'bar', dataset: 'second' }],
impressions: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.impressions') + ' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.impressions') + ' / Campaign', type: 'bar', dataset: 'second' }],
cpc: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.cpc') + ' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.cpc') + ' / Campaign', type: 'bar', dataset: 'second' }],
cpm: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.cpm') + ' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.cpm') + ' / Campaign', type: 'bar', dataset: 'second' }],
},
},
adsets: {
name: 'Advertentie Sets',
view: 'adsets',
viewfilters: ['campaigns'],
first: { dimension: 'date', level: 'account', 'endpoint': 'insights', 'summary': 'clicks,impressions,cpc,cpm,spend,ctr', 'allowcomp': true },
second: { dimension: 'adset_name', level: 'adset', endpoint: 'insights' },
third: { dimension: 'date', level: 'account', 'endpoint': 'insights' },
selectedmetric: 'clicks',
selectedmetrics: { 'clicks': true, 'impressions': true, 'cpc': true, 'cpm': true, 'ctr': true, 'spend': true },
metrics: ['clicks', 'impressions', 'cpc', 'cpm', 'ctr', 'spend'],
table: { dataset: 'second' },
panels: { dataset: 'first' },
charts: {
clicks: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.clicks') + ' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.clicks') + ' / ad set', type: 'bar', dataset: 'second' }],
impressions: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.impressions') + ' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.impressions') + ' / ad set', type: 'bar', dataset: 'second' }],
cpc: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.cpc') + ' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.cpc') + ' / ad set', type: 'bar', dataset: 'second' }],
cpm: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.cpm') + ' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.cpm') + ' / ad set', type: 'bar', dataset: 'second' }],
ctr: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.ctr') + ' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.ctr') + ' / ad set', type: 'bar', dataset: 'second' }],
spend: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.spend') + ' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.spend') + ' / ad set', type: 'bar', dataset: 'second' }],
},
},
ads: {
name: 'Advertenties',
view: 'ads',
viewfilters: ['adsets', 'campaigns', 'ads'],
first: { dimension: 'date', level: 'account', 'endpoint': 'insights', 'summary': 'clicks,impressions,cpc,cpm,spend,ctr', 'allowcomp': true },
second: { dimension: 'ad_name', level: 'ad', endpoint: 'insights' },
selectedmetric: 'clicks',
selectedmetrics: { 'clicks': true, 'impressions': true, 'cpc': true, 'cpm': true, 'ctr': true, 'spend': true },
metrics: ['clicks', 'impressions', 'cpc', 'cpm', 'ctr', 'spend'],
table: { dataset: 'second' },
panels: { dataset: 'first' },
charts: {
clicks: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.clicks') + ' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.clicks') + ' / ad', type: 'bar', dataset: 'second' }],
impressions: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.impressions') + ' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.impressions') + ' / ad', type: 'bar', dataset: 'second' }],
cpc: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.cpc') + ' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.cpc') + ' / ad', type: 'bar', dataset: 'second' }],
cpm: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.cpm') + ' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.cpm') + ' / ad', type: 'bar', dataset: 'second' }],
ctr: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.ctr') + ' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.ctr') + ' / ad', type: 'bar', dataset: 'second' }],
spend: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.spend') + ' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.spend') + ' / ad', type: 'bar', dataset: 'second' }],
},
},
age: {
name: 'Leeftijd',
view: 'age',
viewfilters: ['adsets', 'campaigns', 'ads'],
first: { level: 'account', 'endpoint': 'insights', 'breakdowns': 'age', 'dimension': 'date', 'dimension2': 'age', 'summary': 'clicks,impressions,cpc,cpm', 'allowcomp': true },
second: { level: 'account', 'endpoint': 'insights', 'breakdowns': 'age', 'dimension': 'age' },
selectedmetric: 'clicks',
selectedmetrics: { 'clicks': true, 'impressions': true, 'cpc': true, 'cpm': true },
metrics: ['clicks', 'impressions', 'cpc', 'cpm'],
table: { dataset: 'second' },
panels: { dataset: 'first' },
charts: {
clicks: [{ 'chart': 'c1', 'name': 'Klikken, leeftijd en tijd', type: 'linemulti', dataset: 'first', date: true, 'graphs': ['18-24', '25-34', '35-44', '45-54', '55-64', '65+'] }, { 'chart': 'c2', 'name': $filter('translate')('metrics.clicks') + ' / age group', type: 'bar', dataset: 'second' }],
impressions: [{ 'chart': 'c1', 'name': 'Impressies,leeftijd en tijd', type: 'linemulti', dataset: 'first', date: true, 'graphs': ['18-24', '25-34', '35-44', '45-54', '55-64', '65+'] }, { 'chart': 'c2', 'name': $filter('translate')('metrics.impressions') + ' / age group', type: 'bar', dataset: 'second' }],
cpc: [{ 'chart': 'c1', 'name': 'CPC,leeftijd en tijd', type: 'linemulti', dataset: 'first', date: true, 'graphs': ['18-24', '25-34', '35-44', '45-54', '55-64', '65+'] }, { 'chart': 'c2', 'name': $filter('translate')('metrics.cpm') + ' / age group', type: 'bar', dataset: 'second' }],
cpm: [{ 'chart': 'c1', 'name': 'CPM,leeftijd en tijd', type: 'linemulti', dataset: 'first', date: true, 'graphs': ['18-24', '25-34', '35-44', '45-54', '55-64', '65+'] }, { 'chart': 'c2', 'name': $filter('translate')('metrics.cpc') + ' / age group', type: 'bar', dataset: 'second' }],
},
},
gender: {
name: 'Geslacht',
view: 'gender',
viewfilters: ['adsets', 'campaigns', 'ads'],
first: { level: 'account', 'endpoint': 'insights', 'breakdowns': 'gender', 'dimension': 'date', 'dimension2': 'gender', 'summary': 'clicks,impressions,cpc,cpm', 'allowcomp': true },
second: { level: 'account', 'endpoint': 'insights', 'breakdowns': 'gender', 'dimension': 'gender' },
selectedmetric: 'clicks',
selectedmetrics: { 'clicks': true, 'impressions': true, 'cpc': true, 'cpm': true },
metrics: ['clicks', 'impressions', 'cpc', 'cpm'],
table: { dataset: 'second' },
panels: { dataset: 'first' },
charts: {
clicks: [{ 'chart': 'c1', 'name': 'Klikken, geslacht per dag', type: 'linemulti', dataset: 'first', date: true, 'graphs': ['male', 'female'] }, { 'chart': 'c2', 'name': $filter('translate')('metrics.clicks') + ' / Gender', type: 'bar', dataset: 'second' }],
impressions: [{ 'chart': 'c1', 'name': 'Impressies, geslacht per dag', type: 'linemulti', dataset: 'first', date: true, 'graphs': ['male', 'female'] }, { 'chart': 'c2', 'name': $filter('translate')('metrics.impressions') + ' / Gender', type: 'bar', dataset: 'second' }],
cpc: [{ 'chart': 'c1', 'name': 'CPC, geslacht per dag', type: 'linemulti', dataset: 'first', date: true, 'graphs': ['male', 'female'] }, { 'chart': 'c2', 'name': $filter('translate')('metrics.cpc') + ' / Gender', type: 'bar', dataset: 'second' }],
cpm: [{ 'chart': 'c1', 'name': 'CPM, geslacht per dag', type: 'linemulti', dataset: 'first', date: true, 'graphs': ['male', 'female'] }, { 'chart': 'c2', 'name': $filter('translate')('metrics.cpm') + ' / Gender', type: 'bar', dataset: 'second' }],
},
},
},
},
}
$controller('coreapi', { $scope: $scope });
$scope.init();
}
]);
app.controller('facebookinsights', ['$scope', '$timeout', '$http', '$rootScope', '$controller', '$filter', 'h',
function($scope, $timeout, $http, $rootScope, $controller, $filter, h) {
$scope.cfg = {
authurl: 'https://app.marketingtracer.com/rest/facebookinsights/connect?websiteid=' + h.siteId(),
dateformat: "YYYY-MM-DD",
dimensionprefix: '',
urlbase: 'facebookinsights',
report_endpoint: '/rest/facebookinsights/report',
}
$scope.gloMetrics = h.metrics('facebookinsights');
/* $scope.gloMetrics = {
fans: { name: 'Fans', typefilter: 'number', filtercomparator: 0 },
interacties: { name: 'Interactions', typefilter: 'number', filtercomparator: 0 },
bereik: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 },
};*/
//'page_fans','page_fans_country','page_fans_by_like_source','page_fans_gender_age'
$scope.reportconfig = {
page: {
views: {
fans: {
name: 'Fans',
view: 'fans',
first: { 'report': 'timeline', 'endpoint': 'insights', 'dimension': 'date' },
second: { 'report': 'fans', 'endpoint': 'insights', 'dimension': 'date' },
selectedmetric: 'fans',
metrics: [],
charts: {
fans: [
{ 'chart': 'c1', 'name': 'Total fans', type: 'line', dataset: 'page_fans_total', date: true, 'dimension': 'date', 'metric': 'change' },
{ 'chart': 'c2', 'dimension2': 'type', 'name': 'Lost and new fans', type: 'linemulti', dataset: 'page_fans_delta', date: true, 'dimension': 'date', 'metric': 'change', 'graphs': ['page_fan_removes', 'page_fans_adds_paid', 'page_fans_adds_unpaid'] },
{ 'chart': 'c3', 'name': 'Female fans / age ', type: 'bar', dataset: 'page_fans_female_age', 'dimension': 'key', 'metric': 'val' },
{ 'chart': 'c4', 'name': 'Male fans / age ', type: 'bar', dataset: 'page_fans_male_age', 'dimension': 'key', 'metric': 'val' },
{ 'chart': 'c5', 'name': 'Distribution Male and Female fans', type: 'pie', dataset: 'page_fans_age', 'dimension': 'key', 'metric': 'val' },
],
},
},
engagements: {
name: 'Interactie',
view: 'engagements',
first: { 'report': 'timeline', 'endpoint': 'insights', 'dimension': 'date' },
second: { 'report': 'engagements', 'endpoint': 'insights', 'dimension': 'date' },
selectedmetric: 'interacties',
metrics: [],
charts: {
interacties: [
{ 'chart': 'c1', 'dimension2': 'type', 'name': 'Total interactions / day', type: 'linemulti', dataset: 'engagements', date: true, 'dimension': 'date', 'metric': 'value', 'graphs': ['engagements'] },
{ 'chart': 'c2', 'dimension2': 'type', 'name': 'Interactions / type', type: 'linemulti', dataset: 'engagements', date: true, 'dimension': 'date', 'metric': 'value', 'graphs': ['engagements_comments', 'engagements_likes', 'engagements_links', 'engagements_others'] },
{ 'chart': 'c3', 'name': 'Female interactions / age ', type: 'bar', dataset: 'page_content_activity_female_age', 'dimension': 'key', 'metric': 'val' },
{ 'chart': 'c4', 'name': 'Male interactions / age ', type: 'bar', dataset: 'page_content_activity_male_age', 'dimension': 'key', 'metric': 'val' },
{ 'chart': 'c5', 'name': 'Interactions / age ', type: 'pie', dataset: 'page_content_activity_age', 'dimension': 'key', 'metric': 'val' },
],
},
},
reach: {
name: 'Bereik',
view: 'reach',
first: { 'report': 'timeline', 'endpoint': 'insights', 'dimension': 'date' },
second: { 'report': 'reach', 'endpoint': 'insights', 'dimension': 'date' },
selectedmetric: 'bereik',
metrics: [],
charts: {
bereik: [
{ 'chart': 'c1', 'name': 'Total bereik', type: 'line', dataset: 'page_impressions', date: true, 'dimension': 'date', 'metric': 'change' },
{ 'chart': 'c2', 'dimension2': 'type', 'name': 'Bereik organisch en betaald', type: 'linemulti', dataset: 'page_impressions_type', date: true, 'dimension': 'date', 'metric': 'value', 'graphs': ['page_impressions_paid', 'page_impressions_organic'] },
{ 'chart': 'c3', 'name': 'Female reach / age ', type: 'bar', dataset: 'page_impressions_female_age', 'dimension': 'key', 'metric': 'val' },
{ 'chart': 'c4', 'name': 'Male reach / age ', type: 'bar', dataset: 'page_impressions_male_age', 'dimension': 'key', 'metric': 'val' },
{ 'chart': 'c5', 'name': 'Reach / gender', type: 'pie', dataset: 'page_impressions_age', 'dimension': 'key', 'metric': 'val' },
],
},
},
posts: {
name: 'Posts',
view: 'posts',
first: { 'report': 'posts' },
selectedmetric: 'posts',
metrics: [],
charts: {
},
},
},
},
}
$controller('coreapi', { $scope: $scope });
$scope.init();
}
]);
app.controller('instagram', ['$scope', '$timeout', '$http', '$rootScope', '$controller', '$filter', 'h',
function($scope, $timeout, $http, $rootScope, $controller, $filter, h) {
$scope.cfg = {
authurl: 'https://app.pageowl.app/rest/instagram/connect?websiteid=' + h.siteId(),
dateformat: "YYYY-MM-DD",
dimensionprefix: '',
urlbase: 'instagram',
report_endpoint: '/rest/instagram/report',
}
$scope.gloMetrics = h.metrics('instagram');
/*$scope.gloMetrics = {
impressions: { name: 'Fans', typefilter: 'number', filtercomparator: 0 },
reach: { name: 'Interactions', typefilter: 'number', filtercomparator: 0 },
follower_count: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 },
profile_views: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 },
website_clicks: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 },
email_contacts: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 },
get_directions_clicks: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 },
phone_call_clicks: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 },
text_message_clicks: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 },
};*/
//'page_fans','page_fans_country','page_fans_by_like_source','page_fans_gender_age'
$scope.reportconfig = {
page: {
views: {
insights: {
name: 'insights',
view: 'insights',
first: { 'report': 'timeline', 'endpoint': 'insights', 'dimension': 'date' },
//second: { 'report': 'fans', 'endpoint': 'insights', 'dimension': 'date' },
selectedmetric: 'impressions',
metrics: ['impressions', 'reach', 'follower_count'],
panels: { dataset: 'first' },
charts: {
impressions: [
{ 'chart': 'c1', 'name': 'Follower count', type: 'line', dataset: 'follower_count', date: true, 'dimension': 'date', 'metric': 'change' },
{ 'chart': 'c2', 'name': 'Reach', type: 'line', dataset: 'reach', date: true, 'dimension': 'date', 'metric': 'change' },
{ 'chart': 'c3', 'name': 'Impressions', type: 'line', dataset: 'impressions', date: true, 'dimension': 'date', 'metric': 'change' },
],
},
},
engagements: {
name: 'Interactie',
view: 'engagements',
first: { 'report': 'timeline', 'endpoint': 'insights', 'dimension': 'date' },
//second: { 'report': 'engagements', 'endpoint': 'insights', 'dimension': 'date' },
selectedmetric: 'profile_views',
metrics: ['profile_views', 'website_clicks', 'email_contacts', 'get_directions_clicks', 'phone_call_clicks', 'text_message_clicks'],
panels: { dataset: 'first' },
charts: {
profile_views: [
{ 'chart': 'c1', 'name': 'Profile views', type: 'line', dataset: 'profile_views', date: true, 'dimension': 'date', 'metric': 'change' },
{ 'chart': 'c2', 'name': 'Website clicks', type: 'line', dataset: 'website_clicks', date: true, 'dimension': 'date', 'metric': 'change' },
{ 'chart': 'c3', 'name': 'Email contacts', type: 'line', dataset: 'email_contacts', date: true, 'dimension': 'date', 'metric': 'change' },
],
},
},
audience: {
name: 'Bereik',
view: 'audience',
//first: { 'report': 'timeline', 'endpoint': 'insights', 'dimension': 'date' },
second: { 'report': 'audience', 'endpoint': 'insights', 'dimension': 'date' },
selectedmetric: 'bereik',
metrics: [],
charts: {
bereik: [
{ 'chart': 'c1', 'name': 'Female audience / age ', type: 'bar', dataset: 'audience_gender_female_age', 'dimension': 'key', 'metric': 'val' },
{ 'chart': 'c2', 'name': 'Male audience / age ', type: 'bar', dataset: 'audience_gender_male_age', 'dimension': 'key', 'metric': 'val' },
{ 'chart': 'c3', 'name': 'Gender', type: 'pie', dataset: 'audience_gender', 'dimension': 'type', 'metric': 'val' },
],
},
},
posts: {
name: 'Posts',
view: 'posts',
first: { 'report': 'posts' },
selectedmetric: 'posts',
metrics: [],
},
stories: {
name: 'Stories',
view: 'stories',
first: { 'report': 'stories' },
selectedmetric: 'stories',
metrics: [],
},
},
},
}
$controller('coreapi', { $scope: $scope });
$scope.init();
}
]);
app.controller("linkedin", [
"$scope",
"$timeout",
"$http",
"$rootScope",
"$controller",
"$filter",
"h",
function ($scope, $timeout, $http, $rootScope, $controller, $filter, h) {
$scope.cfg = {
authurl: "https://app.pageowl.app/rest/linkedin/connect?websiteid=" + h.siteId(),
dateformat: "YYYY-MM-DD",
dimensionprefix: "",
urlbase: "linkedin",
report_endpoint: "/rest/linkedin/report",
};
$scope.gloMetrics = h.metrics("linkedin");
// Added pageViews and uniqueVisitors to global metrics
$scope.gloMetrics["pageViews"] = { typefilter: "number", filtercomparator: 0, datemerge: "sum" };
$scope.gloMetrics["uniqueVisitors"] = { typefilter: "number", filtercomparator: 0, datemerge: "sum" };
//'page_fans','page_fans_country','page_fans_by_like_source','page_fans_gender_age'
$scope.reportconfig = {
page: {
views: {
interactions: {
name: "Interactions",
view: "interactions",
second: { dimension: "title", report: "followerstatistics-time" },
third: { dimension: "title", report: "sharestatistics" },
selectedmetric: "likeCount",
metrics: ["likeCount", "shareCount", "engagement", "clickCount", "impressionCount", "commentCount"],
panels: { dataset: "third" },
charts: {
likeCount: [
{ chart: "c0", name: "Likes / days", type: "line", dataset: "third", dimension: "date" },
{ chart: "c1", name: "New followers by type", type: "pie", dataset: "newfollowerdist", dimension: "key", metric: "val" },
{ chart: "c2", metric: "abc", dimension2: "type", name: "Lost and new followers", type: "linemulti", dataset: "newfollowerdelta", date: true, dimension: "date", metric: "value", graphs: ["Organic", "Paid"] },
],
shareCount: [
{ chart: "c0", name: "Shares / Day", type: "line", dataset: "third", dimension: "date" },
{ chart: "c1", name: "New followers by type", type: "pie", dataset: "newfollowerdist", dimension: "key", metric: "val" },
{ chart: "c2", dimension2: "type", name: "Lost and new followers", type: "linemulti", dataset: "newfollowerdelta", date: true, dimension: "date", metric: "value", graphs: ["Organic", "Paid"] },
],
engagement: [
{ chart: "c0", name: "Engagement / day", type: "line", dataset: "third", dimension: "date" },
{ chart: "c1", name: "New followers by type", type: "pie", dataset: "newfollowerdist", dimension: "key", metric: "val" },
{ chart: "c2", dimension2: "type", name: "Lost and new followers", type: "linemulti", dataset: "newfollowerdelta", date: true, dimension: "date", metric: "value", graphs: ["Organic", "Paid"] },
],
clickCount: [
{ chart: "c0", name: "Clicks / day", type: "line", dataset: "third", dimension: "date" },
{ chart: "c1", name: "New followers by type", type: "pie", dataset: "newfollowerdist", dimension: "key", metric: "val" },
{ chart: "c2", dimension2: "type", name: "Lost and new followers", type: "linemulti", dataset: "newfollowerdelta", date: true, dimension: "date", metric: "value", graphs: ["Organic", "Paid"] },
],
impressionCount: [
{ chart: "c0", name: "Impressions / day", type: "line", dataset: "third", dimension: "date" },
{ chart: "c1", name: "New followers by type", type: "pie", dataset: "newfollowerdist", dimension: "key", metric: "val" },
{ chart: "c2", dimension2: "type", name: "Lost and new followers", type: "linemulti", dataset: "newfollowerdelta", date: true, dimension: "date", metric: "value", graphs: ["Organic", "Paid"] },
],
commentCount: [
{ chart: "c0", name: "Comments / day", type: "line", dataset: "third", dimension: "date" },
{ chart: "c1", name: "New followers by type", type: "pie", dataset: "newfollowerdist", dimension: "key", metric: "val" },
{ chart: "c2", dimension2: "type", name: "Lost and new followers", type: "linemulti", dataset: "newfollowerdelta", date: true, dimension: "date", metric: "value", graphs: ["Organic", "Paid"] },
],
},
},
network: {
name: "Network",
view: "network",
first: { dimension: "title", report: "networksize" },
second: { dimension: "title", report: "followerstatistics" },
selectedmetric: "val",
metrics: ["val"],
table: { dataset: "region" },
charts: {
val: [
{ chart: "c0", name: "Followers / Staff size", type: "bar", dataset: "staffcount", dimension: "key", metric: "val" },
{ chart: "c1", name: "Followers / Role", type: "pie", dataset: "seniority", dimension: "key", metric: "val" },
{ chart: "c2", name: "Followers / Country", type: "progress", dataset: "country", dimension: "key", metric: "val" },
{ chart: "c3", name: "Folowers / Industry", type: "progress", dataset: "industry", dimension: "key", metric: "val" },
{ chart: "c4", name: "Folowers / Function", type: "progress", dataset: "function", dimension: "key", metric: "val" },
],
},
},
// NEW VIEW ADDED FOR VISITORS
visitors: {
hide: true,
name: "Visitors",
view: "visitors",
first: { dimension: "title", report: "visitorstatistics" },
selectedmetric: "val",
metrics: ["pageViews", "uniqueVisitors"],
panels: { dataset: "first" },
table: { dataset: "country" },
charts: {
val: [
{ chart: "c0", name: "Visitors / Seniority", type: "pie", dataset: "seniority", dimension: "key", metric: "val" },
{ chart: "c1", name: "Visitors / Industry", type: "bar", dataset: "industry", dimension: "key", metric: "val" },
{ chart: "c2", name: "Visitors / Staff Size", type: "progress", dataset: "staffcount", dimension: "key", metric: "val" },
],
},
},
posts: {
name: "Posts",
view: "posts",
first: { dimension: "title", report: "posts" },
selectedmetric: "Placeholder",
dimension: "title",
metrics: ["open_rate", "click_rate", "emails_sent", "unsubscribed", "bounces", "total_orders", "total_revenue"],
panels: { dataset: "stats" },
charts: {
Placeholder: [
{ chart: "c0", name: "Emails sent", type: "line", dataset: "timeseries", metric: "emails_sent", dimension: "date" },
{ chart: "c1", name: "Emails opened", type: "line", dataset: "timeseries", metric: "unique_opens", dimension: "date" },
{ chart: "c2", name: "Clicks", type: "line", dataset: "timeseries", metric: "recipient_clicks", dimension: "date" },
],
},
},
personalposts: {
hide: true,
name: "Personal Posts",
view: "personalposts",
hide: true,
first: { dimension: "title", report: "personalposts" },
selectedmetric: "Placeholder",
dimension: "title",
metrics: ["open_rate", "click_rate", "emails_sent", "unsubscribed", "bounces", "total_orders", "total_revenue"],
panels: { dataset: "stats" },
charts: {
Placeholder: [
{ chart: "c0", name: "Emails sent", type: "line", dataset: "timeseries", metric: "emails_sent", dimension: "date" },
{ chart: "c1", name: "Emails opened", type: "line", dataset: "timeseries", metric: "unique_opens", dimension: "date" },
{ chart: "c2", name: "Clicks", type: "line", dataset: "timeseries", metric: "recipient_clicks", dimension: "date" },
],
},
},
},
},
};
$controller("coreapi", { $scope: $scope });
$scope.init();
},
]);
app.controller('linkedinxads', ['$scope', '$timeout', '$http', '$rootScope', '$controller', '$filter', 'h',
function($scope, $timeout, $http, $rootScope, $controller, $filter, h) {
$scope.cfg = {
authurl: 'https://app.pageowl.app/rest/linkedinxads/connect?websiteid=' + h.siteId(),
dateformat: "YYYY-MM-DD",
dimensionprefix: '',
urlbase: 'linkedinxads',
report_endpoint: '/rest/linkedinxads/report',
}
$scope.gloMetrics = h.metrics('linkedinxads');
/*
$scope.gloMetrics = {
impressions: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
clicks: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
oneClickLeads: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
costInLocalCurrency: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
externalWebsiteConversions: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
costInLocalCurrency: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
networksize: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
networksizeexternal: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
networksizeinternal: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
};
*/
//'page_fans','page_fans_country','page_fans_by_like_source','page_fans_gender_age'
$scope.reportconfig = {
campaigns: {
views: {
all: {
name: 'Campagnes',
view: 'all',
first: { dimension: 'date', report: 'campaigns-time' },
second: { dimension: 'pivotValues', report: 'campaigns-all' },
selectedmetric: 'impressions' ,
selectedmetrics: { 'impressions': true, 'clicks': true, 'oneClickLeads': true, 'costInLocalCurrency': true, 'externalWebsiteConversions': true },
metrics: ['impressions', 'clicks', 'oneClickLeads','costInLocalCurrency','externalWebsiteConversions'],
panels: { dataset: 'second' },
table: { dataset: 'second' },
charts: {
impressions: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.impressions')+' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.impressions')+' / Campaign', type: 'bar', dataset: 'second' }],
clicks: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.clicks')+' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.clicks')+' / Campaign', type: 'bar', dataset: 'second' }],
oneClickLeads: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.clicks')+' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.clicks')+' / Campaign', type: 'bar', dataset: 'second' }],
costInLocalCurrency: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.impressions')+' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.impressions')+' / Campaign', type: 'bar', dataset: 'second' }],
externalWebsiteConversions: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.cpc')+' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.cpc')+' / Campaign', type: 'bar', dataset: 'second' }],
cpm: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.cpm')+' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.cpm')+' / Campaign', type: 'bar', dataset: 'second' }],
},
},
network: {
name: 'Campagnes',
view: 'network',
//first: { dimension: 'title', 'report': 'networksize' },
second: { dimension: 'title', 'report': 'followerstatistics' },
selectedmetric: 'val',
metrics: ['val'],
table: { dataset: 'region' },
charts: {
val: [
{ 'chart': 'c0', 'name': 'Followers / Staff size', type: 'bar', dataset: 'staffcount', 'dimension': 'key', 'metric': 'val' },
{ 'chart': 'c1', 'name': 'Followers / Role', type: 'pie', dataset: 'seniority', 'dimension': 'key', 'metric': 'val' },
{ 'chart': 'c2', 'name': 'Followers / Country', type: 'progress', dataset: 'country', 'dimension': 'key', 'metric': 'val' },
{ 'chart': 'c3', 'name': 'Folowers / Industry', type: 'progress', dataset: 'industry', 'dimension': 'key', 'metric': 'val' },
{ 'chart': 'c4', 'name': 'Folowers / Function', type: 'progress', dataset: 'function', 'dimension': 'key', 'metric': 'val' },
],
},
},
posts: {
name: 'Campagne',
view: 'posts',
first: { dimension: 'title', 'report': 'posts', },
selectedmetric: 'Placeholder',
dimension: 'title',
metrics: ['open_rate', 'click_rate', 'emails_sent', 'unsubscribed', 'bounces', 'total_orders', 'total_revenue'],
panels: { dataset: 'stats' },
charts: {
Placeholder: [
{ 'chart': 'c0', 'name': 'Emails sent', type: 'line', dataset: 'timeseries', metric: 'emails_sent', dimension: 'date' },
{ 'chart': 'c1', 'name': 'Emails opened', type: 'line', dataset: 'timeseries', metric: 'unique_opens', dimension: 'date' },
{ 'chart': 'c2', 'name': 'Clicks', type: 'line', dataset: 'timeseries', metric: 'recipient_clicks', dimension: 'date' },
],
},
},
personalposts: {
hide: true,
name: 'Campagne',
view: 'personalposts',
hide: true,
first: { dimension: 'title', 'report': 'personalposts', },
selectedmetric: 'Placeholder',
dimension: 'title',
metrics: ['open_rate', 'click_rate', 'emails_sent', 'unsubscribed', 'bounces', 'total_orders', 'total_revenue'],
panels: { dataset: 'stats' },
charts: {
Placeholder: [
{ 'chart': 'c0', 'name': 'Emails sent', type: 'line', dataset: 'timeseries', metric: 'emails_sent', dimension: 'date' },
{ 'chart': 'c1', 'name': 'Emails opened', type: 'line', dataset: 'timeseries', metric: 'unique_opens', dimension: 'date' },
{ 'chart': 'c2', 'name': 'Clicks', type: 'line', dataset: 'timeseries', metric: 'recipient_clicks', dimension: 'date' },
],
},
},
},
},
}
$controller('coreapi', { $scope: $scope });
$scope.init();
}
]);
app.controller('mailchimp', ['$scope', '$timeout', '$http', '$rootScope', '$controller', '$filter', 'h',
function($scope, $timeout, $http, $rootScope, $controller, $filter, h) {
$scope.cfg = {
authurl: 'https://app.marketingtracer.com/rest/mailchimp/connect?websiteid=' + h.siteId(),
dateformat: "YYYY-MM-DD",
dimensionprefix: '',
urlbase: 'mailchimp',
report_endpoint: '/rest/mailchimp/report',
}
$scope.gloMetrics = h.metrics('mailchimp');
/*
$scope.gloMetrics = {
Placeholder: { name: '', typefilter: 'number', filtercomparator: 0 },
member_count: { name: 'Aanmeldingen', typefilter: 'number', filtercomparator: 0 },
list_rating: { name: 'Rating', typefilter: 'number', filtercomparator: 0 },
click_rate: { name: 'Klik Ratio', typefilter: 'number', filtercomparator: 0, 'after': '%' },
open_rate: { name: 'Open Ratio', typefilter: 'number', filtercomparator: 0, 'after': '%' },
emails_sent: { name: 'Email verstuurd', typefilter: 'number', filtercomparator: 0 },
send_time: { name: 'Verstuurd op', typefilter: 'mcdate', filtercomparator: 0 },
unsubscribed: { name: 'Afmeldingen', typefilter: 'number', filtercomparator: 0 },
unsubscribe_count: { name: 'Afmeldingen', typefilter: 'number', filtercomparator: 0 },
cleaned_count: { name: 'Verwijderd', typefilter: 'number', filtercomparator: 0 },
bounces: { name: 'Bounce', typefilter: 'number', filtercomparator: 0 },
total_orders: { name: 'Orders', typefilter: 'number', filtercomparator: 0 },
recipient_clicks: { name: 'klikken', typefilter: 'number', filtercomparator: 0 },
total_revenue: { name: 'Totale opbrangest', typefilter: 'number', filtercomparator: 0, 'after': '€' },
};
*/
//'page_fans','page_fans_country','page_fans_by_like_source','page_fans_gender_age'
$scope.reportconfig = {
mail: {
views: {
campaigns: {
name: 'Campagnes',
view: 'campaigns',
second: { dimension: 'title', 'report': 'campaigns' },
selectedmetric: 'member_count',
dimension: 'title',
metrics: ['open_rate', 'click_rate', 'emails_sent', 'send_time', 'unsubscribed', 'bounces'],
table: { dataset: 'second' },
charts: {},
},
campaign: {
name: 'Campagne',
view: 'campaign',
hide: true,
first: { dimension: 'title', 'report': 'campaign.sent_to', filterexpression: $scope.urlfilter },
second: { dimension: 'title', 'report': 'campaign', filterexpression: $scope.urlfilter },
selectedmetric: 'Placeholder',
dimension: 'title',
metrics: ['open_rate', 'click_rate', 'emails_sent', 'unsubscribed', 'bounces', 'total_orders', 'total_revenue'],
panels: { dataset: 'stats' },
charts: {
Placeholder: [
{ 'chart': 'c0', 'name': 'Emails sent', type: 'line', dataset: 'timeseries', metric: 'emails_sent', dimension: 'date' },
{ 'chart': 'c1', 'name': 'Emails opened', type: 'line', dataset: 'timeseries', metric: 'unique_opens', dimension: 'date' },
{ 'chart': 'c2', 'name': 'Clicks', type: 'line', dataset: 'timeseries', metric: 'recipient_clicks', dimension: 'date' },
],
},
},
lists: {
name: 'Lijsten',
view: 'lists',
second: { dimension: 'name', 'report': 'lists' },
selectedmetric: 'member_count',
dimension: 'name',
metrics: ['member_count', 'click_rate', 'open_rate', 'list_rating'],
table: { dataset: 'second' },
charts: {},
},
list: {
name: 'List',
view: 'list',
hide: true,
first: { dimension: 'title', 'report': 'list', filterexpression: $scope.urlfilter },
second: { dimension: 'title', 'report': 'list.activity', filterexpression: $scope.urlfilter },
third: { dimension: 'title', 'report': 'list.members', filterexpression: $scope.urlfilter },
selectedmetric: 'Placeholder',
dimension: 'title',
metrics: ['open_rate', 'click_rate', 'member_count', 'unsubscribe_count', 'cleaned_count'],
panels: { dataset: 'first' },
charts: {
Placeholder: [
{ 'chart': 'c0', 'name': 'Emails sent', type: 'line', dataset: 'second', metric: 'emails_sent', dimension: 'date' },
{ 'chart': 'c1', 'name': 'Emails opened', type: 'line', dataset: 'second', metric: 'unique_opens', dimension: 'date' },
{ 'chart': 'c2', 'name': 'Clicks', type: 'line', dataset: 'second', metric: 'recipient_clicks', dimension: 'date' },
],
},
},
},
},
}
$controller('coreapi', { $scope: $scope });
$scope.init();
}
]);
app.controller('mybusiness', ['$scope', '$timeout', '$http', '$rootScope', '$controller', '$filter', 'h',
function($scope, $timeout, $http, $rootScope, $controller, $filter, h) {
$scope.cfg = {
authurl: 'https://app.marketingtracer.com/rest/mybusiness/connect?websiteid=' + h.siteId(),
dateformat: "YYYY-MM-DD",
dimensionprefix: '',
urlbase: 'mybusiness',
report_endpoint: '/rest/mybusiness/report',
}
$scope.gloMetrics = h.metrics('mybusiness');
/* $scope.gloMetrics = {
Placeholder: { name: '', typefilter: 'number', filtercomparator: 0 },
QUERIES_DIRECT: { name: 'Directe zoekopdrachten', typefilter: 'number', filtercomparator: 0 },
QUERIES_INDIRECT: { name: 'Indirecte zoekopdrachten', typefilter: 'number', filtercomparator: 0 },
VIEWS_MAPS: { name: 'Google maps', typefilter: 'number', filtercomparator: 0 },
VIEWS_SEARCH: { name: 'Google zoeken', typefilter: 'number', filtercomparator: 0 },
QUERIES_DIRECT: { name: 'Bedrijf zoekopdacht', typefilter: 'number', filtercomparator: 0 },
QUERIES_INDIRECT: { name: 'Categorie zoekopdracht', typefilter: 'number', filtercomparator: 0 },
PHOTOS_VIEWS_MERCHANT: { name: 'Van eigenaars', typefilter: 'number', filtercomparator: 0 },
PHOTOS_VIEWS_CUSTOMERS: { name: 'Van bezoekers', typefilter: 'number', filtercomparator: 0 },
PHOTOS_COUNT_MERCHANT: { name: 'Van eigenaar', typefilter: 'number', filtercomparator: 0 },
PHOTOS_COUNT_CUSTOMERS: { name: 'Van bezoekers', typefilter: 'number', filtercomparator: 0 },
Date: { name: 'Datum', typefilter: 'number', filtercomparator: 0 },
AverageCpc: { name: 'Gemiddelde kosten per klik', typefilter: 'number', filtercomparator: 2, 'before': '€' },
Ctr: { name: 'Ctr', typefilter: 'number', filtercomparator: 0, 'after': '%' },
Conversions: { name: 'Conversions', typefilter: 'number', filtercomparator: 0 },
Cost: { name: 'Cost', typefilter: 'number', filtercomparator: 0, 'before': '€' },
CostPerConversion: { name: 'Kosten per conversie', typefilter: 'number', filtercomparator: 0, 'before': '€' },
ConversionRate: { name: 'Conversie ratio', typefilter: 'number', filtercomparator: 0, 'after': '%' },
AveragePosition: { name: 'Gemiddelde positie', typefilter: 'number', filtercomparator: 1 },
ConversionValue: { name: 'Totale conversiewaarde', typefilter: 'number', filtercomparator: 0, 'before': '€' },
};
*/
$scope.fnFormatAd = function(d) {
return d.HeadlinePart1 + d.HeadlinePart2 + d.Description + d.CreativeDestinationUrl + d.CreativeFinalUrls;
}
$scope.reportconfig = {
business: {
views: {
all: {
name: 'Overzicht',
view: 'all',
first: { report: 'total' },
second: { report: 'daily' },
selectedmetric: 'Placeholder',
metrics: [],
table: { dataset: 'second' },
panels: { dataset: 'second' },
charts: {
Placeholder: [
{ 'chart': 'c1', 'name': 'Search type', type: 'bar', dataset: 'queries', 'dimension': 'type', 'metric': 'queries' },
{ 'chart': 'c2', 'name': 'Searches / day', type: 'pie', type: 'line', dataset: 'second', metric: 'QUERIES', dimension: 'date' },
{ 'chart': 'c3', 'name': 'Impressions / type', type: 'bar', dataset: 'views', 'dimension': 'type', 'metric': 'views' },
{ 'chart': 'c4', 'name': 'Impressions / day', type: 'pie', type: 'line', dataset: 'second', metric: 'VIEWS', dimension: 'date' },
{ 'chart': 'c5', 'name': 'Available Photo\'s', type: 'pie', dataset: 'photocount', 'dimension': 'type', 'metric': 'photocount' },
{ 'chart': 'c6', 'name': 'Photo Impressions', type: 'pie', dataset: 'photoview', 'dimension': 'type', 'metric': 'photoview' },
{ 'chart': 'c7', 'name': 'Website clicks', type: 'pie', type: 'line', dataset: 'second', metric: 'ACTIONS_WEBSITE', dimension: 'date' },
{ 'chart': 'c8', 'name': 'Phone contact', type: 'pie', type: 'line', dataset: 'second', metric: 'ACTIONS_PHONE', dimension: 'date' },
{ 'chart': 'c9', 'name': 'Driving Directions', type: 'pie', type: 'line', dataset: 'second', metric: 'ACTIONS_DRIVING_DIRECTIONS', dimension: 'date' },
],
},
},
reviews: {
name: 'Reviews',
view: 'reviews',
first: { report: 'reviews' },
selectedmetric: 'Placeholder',
metrics: [],
table: { dataset: 'second' },
panels: { dataset: 'second' },
charts: {
Placeholder: [
{ 'chart': 'c1', 'name': 'Search type', type: 'bar', dataset: 'queries', 'dimension': 'type', 'metric': 'queries' },
{ 'chart': 'c2', 'name': 'Zoekopdrachten / day', type: 'pie', type: 'line', dataset: 'second', metric: 'QUERIES', dimension: 'date' },
{ 'chart': 'c3', 'name': 'Impressions / type', type: 'bar', dataset: 'views', 'dimension': 'type', 'metric': 'views' },
{ 'chart': 'c4', 'name': 'Impressions / day', type: 'pie', type: 'line', dataset: 'second', metric: 'VIEWS', dimension: 'date' },
{ 'chart': 'c5', 'name': 'Photo\'s', type: 'pie', dataset: 'photocount', 'dimension': 'type', 'metric': 'photocount' },
{ 'chart': 'c6', 'name': 'Photo Impressions', type: 'pie', dataset: 'photoview', 'dimension': 'type', 'metric': 'photoview' },
{ 'chart': 'c7', 'name': 'Website clicks', type: 'pie', type: 'line', dataset: 'second', metric: 'ACTIONS_WEBSITE', dimension: 'date' },
{ 'chart': 'c8', 'name': 'Phone contact', type: 'pie', type: 'line', dataset: 'second', metric: 'ACTIONS_PHONE', dimension: 'date' },
{ 'chart': 'c9', 'name': 'Driving Directions', type: 'pie', type: 'line', dataset: 'second', metric: 'ACTIONS_DRIVING_DIRECTIONS', dimension: 'date' },
],
},
},
},
}
}
$controller('coreapi', { $scope: $scope });
$scope.init();
}
]);
app.controller('keywordtool', ['$scope', '$http', '$rootScope', '$filter', '$location', 'h',
function($scope, $http, $rootScope, $filter, $location, h) {
$scope.suggest = { 'q': '', result: [] };
$scope.order = {};
$scope.fnOrder = function(field) {
var reverse = (field == $scope.order.field) ? true : false;
$scope.order = { 'field': field, 'reverse': reverse };
}
var lang = {
"de": [
{ key: 'was', 'value': 'was ', 'type': 'vraag' },
{ key: 'was ist', 'value': 'was ist ', 'type': 'vraag' },
{ key: 'wie', 'value': 'wie ', 'type': 'vraag' },
{ key: 'wann', 'value': 'wann ', 'type': 'vraag' },
{ key: 'welche', 'value': 'welche ', 'type': 'vraag' },
{ key: 'warum', 'value': 'warum ', 'type': 'vraag' },
],
"nl": [
{ key: 'wat', 'value': 'wat ', 'type': 'vraag' },
{ key: 'wat is', 'value': 'wat is ', 'type': 'vraag' },
{ key: 'hoe', 'value': 'hoe ', 'type': 'vraag' },
{ key: 'wanneer', 'value': 'wanneer ', 'type': 'vraag' },
{ key: 'welke', 'value': 'welke ', 'type': 'vraag' },
{ key: 'waarom', 'value': 'waarom ', 'type': 'vraag' },
],
"en": [
{ key: 'what', 'value': 'what ', 'type': 'vraag' },
{ key: 'what is', 'value': 'what is ', 'type': 'vraag' },
{ key: 'how', 'value': 'how ', 'type': 'vraag' },
{ key: 'when', 'value': 'when ', 'type': 'vraag' },
{ key: 'which', 'value': 'which ', 'type': 'vraag' },
{ key: 'why', 'value': 'why ', 'type': 'vraag' },
]
}
var letters = [
{ key: 'a', 'value': ' a' },
{ key: 'b', 'value': ' b' },
{ key: 'c', 'value': ' c' },
{ key: 'd', 'value': ' d' },
{ key: 'e', 'value': ' e' },
{ key: 'f', 'value': ' f' },
{ key: 'g', 'value': ' g' },
{ key: 'h', 'value': ' h' },
{ key: 'i', 'value': ' i' },
{ key: 'j', 'value': ' j' },
{ key: 'k', 'value': ' k' },
{ key: 'l', 'value': ' l' },
{ key: 'm', 'value': ' m' },
{ key: 'n', 'value': ' n' },
{ key: 'o', 'value': ' o' },
{ key: 'p', 'value': ' p' },
{ key: 'q', 'value': ' q' },
{ key: 'r', 'value': ' r' },
{ key: 's', 'value': ' s' },
{ key: 't', 'value': ' t' },
{ key: 'u', 'value': ' u' },
{ key: 'v', 'value': ' v' },
{ key: 'w', 'value': ' w' },
{ key: 'x', 'value': ' x' },
{ key: 'y', 'value': ' y' },
{ key: 'z', 'value': ' z' },
]
$scope.letters = lang[$rootScope.user.site.locale.lang].concat(letters);
var current = { 'key': '', value: '' }
$scope.fnTrackKeyword = function(kw) {
$http.post('/rest/rank-tracker/add', {
keywords: kw,
websiteid: h.siteId()
}).then(function successCallback(res) {
});
}
$scope.fnExploreKeyword = function(q) {
$scope.q = q;
$scope.showsuggesties = true;
$scope.suggest.result = [];
current = { 'key': 'base', value: '' }
$http.get('/rest/keywordtool/get', {
params: {
q: $scope.q,
l: 'long',
}
}).then(function successCallback(res) {
$scope.suggest.result['base'] = res.data;
});
$scope.kwplanner = false;
var next = false;
var go = false;
var mbreak = true;
$http.get('/rest/googlexads/keywordplanner', {
params: {
q: $scope.q,
cc: $scope.user.site.locale.cc,
lc: $scope.user.site.locale.lc,
}
}).then(function successCallback(res) {
$scope.kwplanner = res.data;
});
angular.forEach($scope.letters, function(value, key) {
if (value.type == 'vraag') {
$http.get('/rest/keywordtool/get', {
params: {
q: value.value + $scope.q,
cc: $scope.user.site.locale.cc,
lc: $scope.user.site.locale.lc,
}
}).then(function successCallback(res) {
if (res.data[1]) {
$scope.suggest.result[value.key] = res.data;
}
});
} else {
$http.get('/rest/keywordtool/get', {
params: {
q: $scope.q + value.value,
cc: $scope.user.site.locale.cc,
lc: $scope.user.site.locale.lc,
}
}).then(function successCallback(res) {
if (res.data[1]) {
$scope.suggest.result[value.key] = res.data;
}
});
}
});
}
$scope.fnDownload = function(text) {
var text = '';
for (var i in $scope.suggest.result) {
var res = $scope.suggest.result[i];
for (var y in res) {
var woord = res[y];
if (woord.check) {
console.log(woord);
text = text + woord.r + "\r\n";
}
}
}
for (var i in $scope.kwplanner) {
if ($scope.kwplanner[i].check) {
text = text + $scope.kwplanner[i].keyword + " (" + $scope.kwplanner[i].vol + "," + $scope.kwplanner[i].seo + "," + $scope.kwplanner[i].cpc + ")\r\n";
}
}
var element = document.createElement('a');
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
element.setAttribute('download', 'zoekwoord suggesties voor ' + $scope.q + '.txt');
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
}
]);
app.controller('onpagestatus', ['$scope', '$timeout', '$http', '$rootScope', '$location', '$filter', 'h',
function($scope, $timeout, $http, $rootScope, $location, $filter, h) {
$scope.page = {};
var _cb = {
getstarted: function() {
$scope.page.include = 'index.getstarted';
},
crawling: function() {
$scope.page.crawling = true;
$scope.page.include = 'index.list';
},
ready: function() {
$scope.page.include = 'index.list';
}
}
var timeout = 5000
var getStatus = function() {
if ($rootScope.onpagestatus && $rootScope.onpagestatus.data.status == 'done') {
_cb[$rootScope.onpagestatus.cb]($rootScope.onpagestatus.data)
} else {
$http.get('/rest/onpage/status', {
params: {
websiteid: h.siteId(),
}
}).then(function successCallback(res) {
$rootScope.onpagestatus = res.data;
_cb[res.data.cb](res.data);
if ($rootScope.onpagestatus && $rootScope.onpagestatus.data.status == 'crawling') {
$scope.$broadcast('refreshonpagelist');
$timeout.cancel($rootScope.to);
$rootScope.to = $timeout(function() {
timeout = timeout * 1.2;
getStatus();
}, timeout);
}
});
}
}
getStatus();
$scope.fnCrawl = function() {
$http.get('/rest/onpage/crawl', {
params: {
websiteid: h.siteId(),
}
}).then(function successCallback(res) {
$rootScope.onpagestatus.data.status = 'crawling';
$timeout(function() {
getStatus();
}, 2000);
$location.path('/onpage-seo/all');
});
}
$scope.fnEmpty = function() {
$http.get('/rest/onpage/empty', {
params: {
websiteid: h.siteId(),
}
});
}
}
]);
app.filter('zeroplus', function() {
return function(items, timingevent) {
return items.reduce(function(acc, cur) {
if (typeof cur.properties == 'object' && typeof cur.properties.timing == 'object' && cur.properties.timing[timingevent] > 0) {
acc.push(cur);
}
return acc;
}, []);
};
});
app.controller('onpagelist', ['$scope', '$timeout', '$http', '$rootScope', '$filter', 'h',
function($scope, $timeout, $http, $rootScope, $filter, h) {
$scope.page = { 'curllabel': '', 'newurl': $rootScope.user.site.domain + '/' };
$scope.page.table = {
'curpage': 0,
'itemsperpage': 34,
'offset': 0,
'rulefilter': 'all',
'filter': {},
'min': { 'opi': 100, 'score': 100 },
'order': { 'k': 'url', 'r': false },
'fnOrder': function(k, b) {
this.order.r = (k == this.order.k) ? !this.order.r : b;
this.order.k = k;
},
fnSetOffset: function() {
this.offset = this.itemsperpage * (this.curpage - 1);
},
fnFilterProperty: function() {
var pages = angular.copy($rootScope._pages);
$scope.pages = $filter('filter')(pages, $scope.page.table.filter);
}
}
$scope.fnPctChange = function(o, n) {
if (n == 0) {
return '0%';
}
var pct = ((n - o) / o) * 100;
var npct = $filter('number')(pct, 2);
if(!isFinite(npct)){
npct = 100;
}
if (pct < 0) {
return '' + npct + '%';
}
return '+ ' + npct + '%';r
}
var fnSpeed = function(pages) {
var t = {};
var s = {};
// min max
pages.forEach(function(page, k) {
if (typeof page.properties.timing != 'undefined' && page.properties.timing != null && page.properties.timing.ttfb) {
var _otiming = page.properties.timing;
delete _otiming.cls;
Object.keys(_otiming).forEach(function(timingevent, n) {
s[timingevent] = s[timingevent] || []
if (_otiming[timingevent] > 0) {
s[timingevent].push(_otiming[timingevent])
}
})
}
})
for (timingevent in s) {
var v = s[timingevent];
var min = 0;
var max = Math.max(...v);
var step = Math.round((max - min) / 18);
if (step == 0) {
step = 0.1;
}
var oinit = {}
for (var i = min; i < max; i = i + step) {
oinit[Math.round(i / step) * step] = 0;
}
t[timingevent] = v.reduce(function(acc, cur) {
acc[Math.round(cur / step) * step] = acc[Math.round(cur / step) * step] + 1;
return acc;
}, oinit)
}
// get events from keys
$scope.timingevents = Object.keys(t);
var colors = h.colors()
// create charts
$scope.charts = {};
Object.keys(t).forEach(function(timingevent, k) {
var data = Object.keys(t[timingevent]).map(function(a) {
return { 'timing': a, 'pages': t[timingevent][a] }
})
$scope.charts[timingevent] = {
data: data,
type: 'serial',
categoryField: 'timing',
rotate: false,
legend: {
enabled: false
},
categoryAxis: {
gridPosition: "start",
parseDates: false,
labelRotation: 0,
gridThickness: 0,
labelFunction: function(value, valueText, axis) { return value + 'ms' },
},
valueAxes: [{
position: "left",
axisAlpha: 0,
labelsEnabled: true,
dashLength: 4,
color: '#dedede',
}],
graphs: [{
fillColorsField: "color",
balloonText: "" + timingevent + "
[[category]]ms:
[[value]] pages",
type: "column",
columnWidth: 0.90,
title: "Zoekwoord waarde",
valueField: 'pages',
fillAlphas: 1,
lineColor: colors[k],
autoColor: true,
}],
}
})
}
// AI-crawlers: status per bot voor de site en de pagina's met een blokkade
$scope.oAiBots = {
'mode': 'crawlers',
'loading': false,
'data': null,
init: function(refresh) {
var self = this;
self.loading = true;
$http.get('/rest/onpage/aibots', {
params: {
websiteid: h.siteId(),
refresh: refresh ? 1 : 0
}
}).then(function successCallback(res) {
self.data = res.data;
self.rows = self.fnRows(res.data).filter(function(r) {
return self.mode == 'crawlers' ? r.blocked.length > 0 : r.score !== null;
});
self.loading = false;
}, function errorCallback() {
self.loading = false;
});
},
fnBlocked: function(type) {
return (this.data && this.data.bots || []).filter(function(b) {
return b.type == type && (b.robots_pages > 0 || b.server_blocked);
});
},
// één rij per pagina: AI-signalen en geblokkeerde AI-bots samen, zoals de paginatabel van de scan
'rows': [],
'table': {
'order': '-score', 'filter': { 'url': '' }, 'level': '',
// paginering zoals de paginatabel van de scan
'curpage': 1, 'itemsperpage': 34, 'offset': 0,
fnSetOffset: function() {
this.offset = this.itemsperpage * (this.curpage - 1);
},
fnReset: function() {
this.curpage = 1;
this.offset = 0;
}
},
fnRows: function(data) {
var map = {};
var rows = [];
var row = function(p) {
var id = p._id.$oid;
if (!map[id]) {
map[id] = { '_id': p._id, 'url': p.url, 'score': null, 'level': null, 'top': [], 'blocked': [], 'search': false };
rows.push(map[id]);
}
return map[id];
};
((data.aicontent && data.aicontent.pages) || []).forEach(function(p) {
var r = row(p);
r.score = p.score;
r.level = p.level;
r.top = p.top;
});
(data.pages || []).forEach(function(p) {
var r = row(p);
r.blocked = p.blocked;
r.search = p.search;
});
return rows;
},
fnOrder: function(key) {
this.table.order = (this.table.order == '-' + key) ? key : '-' + key;
this.table.fnReset();
},
fnLevel: function(r) {
var level = $scope.oAiBots.table.level;
return !level || r.level == level;
},
// status van een bot in één woord: robots.txt, server of toegestaan
fnBotStatus: function(b) {
if (b.robots_home) { return 'robots_site'; }
if (b.server_checked && this.data.conclusive && b.server_blocked) { return 'server'; }
if (b.robots_pages > 0) { return 'robots_pages'; }
return 'allowed';
}
};
// calculare rules and scores
var fnDuplicates = function(pages) {
var duplicates = {};
for (var i in pages) {
for (var y in pages[i]['compare']) {
duplicates[y] = duplicates[y] || {};
duplicates[y][pages[i]['compare'][y]] = duplicates[y][pages[i]['compare'][y]] || { 'name': pages[i]['compare'][y], 'count': 0, 'pages': [] };
duplicates[y][pages[i]['compare'][y]].count++;
duplicates[y][pages[i]['compare'][y]].pages.push({ 'serps': pages[i].serps, 'url': pages[i].url, 'properties': pages[i].properties, '_id': pages[i]._id });
}
}
// remove single counts in compare
for (var i in duplicates) {
for (var y in duplicates[i]) {
if (duplicates[i][y].count <= 1) {
delete duplicates[i][y];
}
}
}
var x = {}
for (var i in duplicates) {
x[i] = Object.values(duplicates[i])
}
$scope.duplicates = x;
}
// assistent
var fnAssistent = function(pages) {
$http.get('/rest/onpage/weights').then(function successCallback(weights) {
var issues = [];
for (var i in pages) {
for (var y in pages[i]['rules']) {
if (!pages[i]['rules'][y]) {
if (pages[i]['properties']['pagerank'] && pages[i]['properties']['opi'] && weights.data[y]) {
issues.push({ 'help': false, 'page': pages[i], 'weight': parseFloat(weights.data[y]['f'] * (200 + pages[i]['properties']['pagerank']) * (200 + pages[i]['properties']['opi'])), 'rule': y, 'f': weights.data[y]['f'] })
}
}
}
}
$scope.issues = issues;
});
}
// alerts
$scope.oAlerts = {
init: function() {
$scope.page.notifications = 'pending';
this.getSettings();
$timeout(function() { $scope.oAlerts.firebase.init(); }, 4000)
},
firebase: {
'config': {
apiKey: "AIzaSyAKgRy2MQF2OUPh-WpUYMWOU6M_XijIMxg",
authDomain: "marketingtracer-73fb0.firebaseapp.com",
databaseURL: "https://marketingtracer-73fb0.firebaseio.com",
projectId: "marketingtracer-73fb0",
storageBucket: "marketingtracer-73fb0.appspot.com",
messagingSenderId: "769511864713",
appId: "1:769511864713:web:340f1f811287abb766c958"
},
'init': function() {
firebase.initializeApp(this.config);
this.messaging = firebase.messaging();
this.messaging.usePublicVapidKey("BDRyazo-zYOixCGZOS-ZI87KPiGfDCCFr5J-GMvydQkBVXOU9RaV8dolUZt_9RT1ZXk2WQ54lwKulSXn-r_B3UY");
if (!("Notification" in window)) {
$scope.page.notifications = 'notenabled';
} else if (Notification.permission == "granted") {
this.getToken();
} else {
$scope.page.notifications = 'notgranted';
}
},
'getToken': function() {
this.messaging.getToken().then(function(token) {
$scope.token = token;
console.log($scope.alertnotifications);
if ($scope.alertnotifications.indexOf(token) > -1) {
$scope.page.notifications = 'granted';
} else {
$scope.page.notifications = 'available';
}
$scope.$apply();
console.log("token is : ", token)
})
},
unsubscribe: function() {
$scope.page.notifications = 'available';
$http.post('/rest/onpage/alertsettings.notifications.pull', {
websiteid: h.siteId(),
'token': $scope.token
});
},
subscribe: function() {
$scope.page.notifications = 'granted';
$http.post('/rest/onpage/alertsettings.notifications.save', {
websiteid: h.siteId(),
'token': $scope.token
});
},
'requestPermission': function() {
this.messaging
.requestPermission()
.then(function() {
console.log("Notification permission granted.");
$scope.page.notifications = 'granted';
$scope.$apply();
// get the token in the form of promise
return messaging.getToken()
})
.then(function(token) {
// console.log("token is : ", token)
$http.post('/rest/onpage/alertsettings.notifications.save', {
websiteid: h.siteId(),
'token': token
});
})
.catch(function(err) {
$scope.page.notifications = 'notenabled';
//console.log("Unable to get permission to notify.", err);
});
this.messaging.onMessage(function(payload) {
var notification = new Notification(payload.notification.title, payload.notification);
console.log("Message received. ", payload);
});
},
},
getSettings: function() {
// hardcoded ruleset
$scope.alertrules = [
{ 'rule': 'title_change' },
{ 'rule': 'pfirst_change' },
{ 'rule': 'metadescription_change' },
{ 'rule': 'h1_change' },
{ 'rule': 'title_removed' },
{ 'rule': 'h1_removed' },
{ 'rule': 'metadescription_removed' },
{ 'rule': 'not_indexable' },
{ 'rule': 'status_change' },
{ 'rule': 'total_score_change' },
{ 'rule': 'lighthouse_fail_change' },
];
// users, names and settings
$http.get('/rest/sites/get', {
params: {
'websiteid': h.siteId(),
}
}).then(function successCallback(res) {
if (res.data._id) {
$scope.user.site.users = res.data.users;
$scope.user.site.names = res.data.names;
$scope.alertnotifications = res.data.alertnotifications || [];
$scope.alertsettings = angular.extend({
'title_change': { 'sens': 0, 'users': [], 'active': false },
'pfirst_change': { 'sens': 0, 'users': [], 'active': false },
'metadescription_change': { 'sens': 0, 'users': [], 'active': false },
'h1_change': { 'sens': 0, 'users': [], 'active': false },
'title_removed': { 'sens': 0, 'users': [], 'active': false },
'h1_removed': { 'sens': 0, 'users': [], 'active': false },
'metadescription_removed': { 'sens': 0, 'users': [], 'active': false },
}, res.data.alertsettings);
}
});
},
saveSettings: function() {
$http.post('/rest/onpage/alertsettings.save', {
websiteid: h.siteId(),
'alertsettings': $scope.alertsettings
});
},
addUser: function(userid, rulename) {
var count = 0;
$scope.alertsettings[rulename].users = $scope.alertsettings[rulename].users || [];
for (var i = 0; i < $scope.alertsettings[rulename].users.length; i++) {
if ($scope.alertsettings[rulename].users[i].$oid == userid.$oid) {
$scope.alertsettings[rulename].users.splice(i, 1);
count = count + 1;
}
}
if (count == 0) {
$scope.alertsettings[rulename].users.push(userid);
}
this.saveSettings();
}
}
// calculare rules and scores
// welke view hoort bij het adres. Problemen, één probleem, Pagina's en Wijzigingen zijn de SEO-audit-overzichten
// (index.audit.html, onpage.audit.js, 2026-10-29); die laden hun eigen tellingen en staan er meteen.
var AUDIT = { rules: true, pages: true, changes: true };
$scope.auditView = function () { return !!AUDIT[$scope.view]; };
var fnView = function() {
if ($scope.viewrule) {
return 'pages';
}
var other = { assistent: 'assistent', duplicates: 'duplicates', alerts: 'alerts', changes: 'changes', speed: 'speed', aibots: 'aibots', 'ai-detectie': 'aibots' };
return other[$scope.viewrulelabel] || 'rules';
};
var fnInit = function() {
$scope.view = fnView();
if ($scope.view == 'assistent') {
fnAssistent($rootScope._pages);
} else if ($scope.view == 'duplicates') {
fnDuplicates($rootScope._pages);
} else if ($scope.view == 'alerts') {
$scope.oAlerts.init();
$scope.oDigest.load();
} else if ($scope.view == 'speed') {
fnSpeed($rootScope._pages);
} else if ($scope.view == 'aibots') {
// Arjen (2026-10-29): twee pagina's, AI-crawlers (blokkades) en AI-detectie (AI-signalen per pagina)
$scope.oAiBots.mode = $scope.viewrulelabel == 'aibots' ? 'crawlers' : 'detection';
$scope.oAiBots.init();
}
}
// SEO-audit: elke maandag een mail met wat er veranderde, per gebruiker aan of uit (onpage/digest, cron/audit.digest)
$scope.oDigest = {
on: false,
loaded: false,
load: function() {
var self = this;
$http.get('/rest/onpage/digest', { params: { websiteid: h.siteId() } }).then(function(res) {
self.on = !!res.data.on;
self.loaded = true;
});
},
save: function() {
var self = this;
$http.post('/rest/onpage/digest', { websiteid: h.siteId(), on: self.on }).then(function(res) {
self.on = !!res.data.on;
});
}
};
$scope.$on('refreshonpagelist', function(e) {
fnIndexList();
});
$scope.fnStar = function(curpage){
curpage.properties.star = (curpage.properties.star == 1)?0:1;;
$http.post('/rest/onpage/page.save', {
websiteid: h.siteId(),
pageid: curpage._id.$oid,
fields: { 'properties.star': curpage.properties.star }
});
//$http.post("/rest/rank-tracker/edit", angular.extend({ 'meta.star': !ranking.meta.star, fields: ['meta.star'] }, fnSingle.getParams(ranking))).then(function successCallback(res) { $scope.getKeywords(); })
}
// get list
var fnIndexList = function() {
$scope.page.table.fnOrder('properties.opi', true)
//allways get rule list
$http.get('/rest/onpage/rules', { 'params': { 'websiteid': h.siteId(), 'lang': $scope.user.site.locale.lang } }).then(function successCallback(res) {
angular.forEach(res.data.rules, function(v, k) {
v.enabled = !v.disabled;
})
$scope.onpage = res.data;
// get pages and historu of cache
if ($rootScope._pages && $rootScope.onpagestatus.data.status == 'done') {
$scope.pages = angular.copy($rootScope._pages);
$scope.history = angular.copy($rootScope._history);
fnInit();
} else {
$http.get('/rest/onpage/list', {
params: {
websiteid: h.siteId(),
}
}).then(function successCallback(res) {
$rootScope._pages = res.data.data;
$rootScope._history = res.data.history;
$scope.pages = angular.copy($rootScope._pages);
$scope.history = angular.copy($rootScope._history);
fnInit();
});
}
});
}
if ($scope.custominit) {
$scope.viewrule = $scope.custominit.viewrule;
$scope.viewrulelabel = $scope.custominit.viewrulelabel;
};
$scope.view = fnView();
fnIndexList();
$scope.fnScanByUrl = function() {
$scope.fnGoto('/rest/onpage/page.create?websiteid=' + h.siteId() + '&url=' + $scope.page.newurl);
}
}
]);
// SEO-audit: de overzichtslijsten in de nieuwe stijl (2026-10-29): Problemen (/onpage-seo/all, per soort
// /onpage-seo/