(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' },
},
copernica: {
Placeholder: { name: '', typefilter: 'number', filtercomparator: 0 },
subject: { name: 'Subject', typefilter: 'number', filtercomparator: 0 },
type: { name: 'Type', typefilter: 'string' },
destinations: { name: 'Destinations', typefilter: 'number', filtercomparator: 0 },
abuses: { name: 'Abuses', typefilter: 'number', filtercomparator: 0 },
clicks: { name: 'Clicks', typefilter: 'number', filtercomparator: 0 },
uniqueclicks: { name: 'Unique Clicks', typefilter: 'number', filtercomparator: 0 },
deliveries: { name: 'Deliveries', typefilter: 'number', filtercomparator: 0 },
errors: { name: 'Errors', typefilter: 'number', filtercomparator: 0 },
impressions: { name: 'Impressions', typefilter: 'number', filtercomparator: 0 },
uniqueimpressions: { name: 'Unique Impressions', typefilter: 'number', filtercomparator: 0 },
retries: { name: 'Retries', typefilter: 'number', filtercomparator: 0 },
unsubscribes: { name: 'Unsubscribes', typefilter: 'number', filtercomparator: 0 },
},
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' },
}
}
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();
}
}
};
}
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: 'view/home/index.html?r=' + r,
nav: 'dashboard'
})
/* help*/
.when('/help', {
title: 'Help',
templateUrl: 'view/help/index.html?r=' + r,
nav: 'help'
})
/* onpage seo*/
.when('/onpage-seo', {
title: 'ONPAGE',
templateUrl: 'view/onpage/index.status.html?r=' + r,
nav: 'onpage'
})
.when('/onpage-seo/scan/:pageid', {
title: 'ONPAGE SCAN',
templateUrl: 'view/onpage/scan.html?r=' + r,
nav: 'onpage',
controller: function($scope, $routeParams) {
$scope.pageid = $routeParams.pageid;
},
})
.when('/onpage-seo/:viewrulelabel', {
title: 'ONPAGE',
templateUrl: 'view/onpage/index.status.html?r=' + r,
nav: 'onpage',
controller: function($scope, $routeParams) {
$scope.viewrulelabel = $routeParams.viewrulelabel;
},
})
.when('/onpage-seo/:viewrulelabel/:viewrule', {
title: 'ONPAGE',
templateUrl: 'view/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: 'view/content/index.html?r=' + r,
nav: 'content'
})
.when('/content/:modelid', {
title: 'Content Intelligence',
templateUrl: 'view/content/model.html?r=' + r,
nav: 'content',
controller: function($scope, $routeParams) {
$scope.modelid = $routeParams.modelid;
},
})
/* linkbuilding*/
.when('/linkbuilding/assistant', {
title: 'Linkbuilding',
templateUrl: 'view/linkbuilding/assistant.html?r=' + r,
nav: 'linkbuilding'
})
.when('/linkbuilding/template', {
title: 'Linkbuilding',
templateUrl: 'view/linkbuilding/template.html?r=' + r,
nav: 'linkbuilding'
})
.when('/linkbuilding/wizzard', {
title: 'Linkbuilding',
templateUrl: 'view/linkbuilding/wizzard.html?r=' + r,
nav: 'linkbuilding'
})
.when('/linkbuilding/manager', {
title: 'Linkbuilding',
templateUrl: 'view/linkbuilding/manager.html?r=' + r,
nav: 'linkbuilding'
})
/* reports*/
.when('/analytics/:report/:view', {
title: 'SITES',
templateUrl: 'view/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: 'view/api/analytics4.html?r=' + r,
nav: 'analytics4',
controller: function($scope, $routeParams) {
$scope.urlreport = $routeParams.report;
$scope.urlview = $routeParams.view;
},
})
.when('/searchconsole/:report/:view', {
title: 'SEARCHCONSOLE',
templateUrl: 'view/api/searchconsole.html?r=' + r,
nav: 'tools',
controller: function($scope, $routeParams) {
$scope.urlreport = $routeParams.report;
$scope.urlview = $routeParams.view;
},
})
.when('/youtube/:report/:view', {
title: 'youtube',
templateUrl: 'view/api/youtube.html?r=' + r,
nav: 'tools',
controller: function($scope, $routeParams) {
$scope.urlreport = $routeParams.report;
$scope.urlview = $routeParams.view;
},
})
.when('/searchconsole/:report/:view/:filter', {
title: 'SEARCHCONSOLE',
templateUrl: 'view/api/searchconsole.html?r=' + r,
nav: 'tools',
controller: function($scope, $routeParams) {
$scope.urlreport = $routeParams.report;
$scope.urlview = $routeParams.view;
$scope.urlfilter = $routeParams.filter;
},
})
.when('/mailchimp/:report/:view', {
title: 'mailchimp',
templateUrl: 'view/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: 'view/api/mailchimp.html?r=' + r,
nav: 'tools',
controller: function($scope, $routeParams) {
$scope.urlreport = $routeParams.report;
$scope.urlview = $routeParams.view;
$scope.urlfilter = $routeParams.filter;
},
})
.when('/copernica/:report/:view', {
title: 'copernica',
templateUrl: 'view/api/copernica.html?r=' + r,
nav: 'tools',
controller: function($scope, $routeParams) {
$scope.urlreport = $routeParams.report;
$scope.urlview = $routeParams.view;
},
})
.when('/copernica/:report/:view/:filter', {
title: 'copernica',
templateUrl: 'view/api/copernica.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: 'view/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: 'view/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: 'view/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: 'view/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: 'view/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: 'view/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: 'view/api/mybusiness.html?r=' + r,
nav: 'tools',
controller: function($scope, $routeParams) {
$scope.urlreport = $routeParams.report;
$scope.urlview = $routeParams.view;
},
})
.when('/planning', {
title: 'planning',
templateUrl: 'view/planning/index.html?r=' + r,
nav: 'planning',
})
.when('/site', {
title: 'SITES',
templateUrl: 'view/site/index.html?r=' + r,
nav: 'sites',
})
.when('/site/upgrade/:orderstate', {
title: 'SITES',
templateUrl: 'view/site/upgrade.html?r=' + r,
nav: 'sites',
controller: function($scope, $routeParams) {
$scope.orderstate = $routeParams.orderstate;
},
allowguest: true
})
.when('/site/upgrade', {
title: 'SITES',
templateUrl: 'view/site/upgrade.html?r=' + r,
nav: 'sites',
allowguest: true
})
.when('/sites', {
title: 'SITES',
templateUrl: 'view/sites/index.html?r=' + r,
nav: 'sites',
})
.when('/sites/new', {
title: 'Add a new site',
templateUrl: 'view/sites/first.html?r=' + r,
nav: 'sites',
})
.when('/rank-tracker', {
title: 'Rank Tracker',
templateUrl: 'view/rank-tracker/index.html?r=' + r,
nav: 'ranktracker',
})
.when('/rank-tracker/competitors', {
title: 'Rank Tracker - Competitors',
templateUrl: 'view/rank-tracker/competitors.html?r=' + r,
nav: 'ranktracker',
})
.when('/rank-tracker/insights', {
title: 'Rank Tracker - Insights',
templateUrl: 'view/rank-tracker/insights.html?r=' + r,
nav: 'ranktracker',
})
.when('/keywordtool', {
title: 'Rank Tracker',
templateUrl: 'view/keywordtool/index.html?r=' + r,
nav: 'keywordtool',
})
.when('/insights', {
title: 'Insights',
templateUrl: 'view/insights/index.html?r=' + r,
nav: 'insights',
})
.when('/insights/:report', {
title: 'Insights',
templateUrl: 'view/insights/index.html?r=' + r,
nav: 'tools',
controller: function($scope, $routeParams) {
$scope.urlreport = $routeParams.report;
},
})
/*report*/
.when('/report', {
title: 'Report',
templateUrl: 'view/report/index.html?r=' + r,
nav: 'report',
})
.when('/report/:report_id', {
title: 'Report',
templateUrl: 'view/report/report.html?r=' + r,
nav: 'report',
controller: function($scope, $routeParams) {
$scope.report_id = $routeParams.report_id;
},
})
.when('/reportpage/:key', {
title: 'Report',
templateUrl: 'view/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: 'view/sites/first.html?r=' + r,
nav: 'sites',
allowguest: true,
})
.when('/user/login', {
title: 'LOGIN',
allowguest: true,
nav: 'user',
class: 'fullscreen',
templateUrl: 'view/user/login.html?r=' + r,
})
.when('/user', {
title: 'USER',
nav: 'user',
templateUrl: 'view/user/index.html?r=' + r,
})
.when('/user/register', {
title: 'LOGIN',
nav: 'user',
class: 'fullscreen',
templateUrl: 'view/user/register.html?r=' + r,
allowguest: true,
})
.when('/user/recover', {
title: 'RECOVER PASSWORD',
templateUrl: 'view/user/recover.html?r=' + r,
nav: 'user',
class: 'fullscreen',
allowguest: true,
})
.when('/settings/reseller', {
title: 'RESELLER',
templateUrl: 'view/reseller/index.html?r=' + r,
nav: 'user',
allowguest: true,
})
.when('/settings/site', {
title: 'RESELLER',
templateUrl: 'view/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');
//}
}
if (typeof $window?.gtag === 'function') {
$window.gtag('config', 'UA-44422450-8', { 'page_path': $location.path() });
$window.gtag('event', 'page_view');
}
$rootScope.app.meta = { nav: $route.current.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 = 'view/' + 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();
});
});
}
$scope.fnSitesDropdown = function(site) {
$rootScope.app.sitesdropdown = !$rootScope.app.sitesdropdown;
}
$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://pdfssl1.seoserver.nl/engels/page.php?website_id=' + h.siteId() + '&reseller_id=' + $scope.user.reseller._id.$oid + '&key=' + res.data.k)
/*$http.get('https://pdfssl1.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);
});*/
});
}
}
]);
app.controller('home', ['$scope', '$timeout', '$http', '$rootScope', '$filter', 'h',
function($scope, $timeout, $http, $rootScope, $filter, h) {
//if ($rootScope.user.firstrun) {
if ($rootScope.user.firstrun) {
$scope.fnModal('home/modal.firstrun');
}
$scope.fnCloseFirstRun = function() {
$http.get('/rest/user/firstrun.set');
$rootScope.user.firstrun = false;
$scope.fnCloseModal();
}
$scope.pagecharts = {};
$scope.curtemplate = {};
$scope.colors = h.colors();
$scope.page = {
'widgets': [{
'type': 'analytics_timeline',
'metrics': ['sessions', 'users', 'pageviews', 'pageviewsPerSession', 'avgSessionDuration', 'percentNewSessions', 'bounceRate', 'goalCompletionsAll', 'goalValueAll', 'goalConversionRateAll', 'uniquePageviews', 'avgTimeOnPage', 'entrances', 'exitRate', 'pageValue', 'transactions', 'uniquePurchases', 'totalValue', 'revenuePerTransaction', 'itemQuantity', 'itemsPerPurchase'],
'metric': 'sessions',
'colspan': 6
}, {
'type': 'analytics_chart',
'dimensions': ['channelGrouping', 'keyword', 'source', 'country', 'userAgeBracket', 'userGender', 'socialNetwork', 'deviceCategory', 'adMatchedQuery', 'productName', 'productCategory', 'pagePath', 'landingPagePath', 'exitPagePath'],
'dimension': 'landingPagePath',
'charts': ['pie', 'bar', 'progress'],
'chart': 'bar',
'metrics': ['sessions', 'users', 'pageviews', 'pageviewsPerSession', 'avgSessionDuration', 'percentNewSessions', 'bounceRate', 'goalCompletionsAll', 'goalValueAll', 'goalConversionRateAll', 'uniquePageviews', 'avgTimeOnPage', 'entrances', 'exitRate', 'pageValue', 'transactions', 'uniquePurchases', 'totalValue', 'revenuePerTransaction', 'itemQuantity', 'itemsPerPurchase'],
'metric': 'sessions',
'colspan': 6
},
{
'type': 'analytics4_timeline',
'class': 'mt-4',
'metrics': ['sessions', 'totalUsers', 'screenPageViews', 'screenPageViewsPerSession', 'averageSessionDuration', 'newUsers', 'bounceRate', 'eventCount', 'eventCountPerUser'],
'metric': 'sessions',
'colspan': 6
},
{
'type': 'searchconsole_timeline',
'class': 'mt-4',
'metrics': ['clicks', 'ctr', 'position', 'impressions'],
'metric': 'clicks',
'colspan': 6
}, {
'type': 'searchconsole_chart',
'dimensions': ['query', 'page', 'country', 'device'],
'dimension': 'query',
'charts': ['pie', 'bar', 'progress'],
'chart': 'bar',
'metrics': ['clicks', 'ctr', 'position', 'impressions'],
'metric': 'clicks',
'colspan': 6
}, {
'type': 'searchconsole_keywords',
'colspan': 6
}, {
'type': 'googleads_timeline',
'class': 'mt-4',
'metrics': ['Clicks', 'Impressions', 'Cost', 'AverageCpc', 'Ctr', 'Conversions', 'CostPerConversion', 'ConversionRate', 'ConversionValue', 'SearchImpressionShare', 'SearchAbsoluteTopImpressionShare', 'roas'],
'metric': 'Clicks',
'colspan': 6
}, {
'type': 'googleads_performance_chart',
'dimensions': ['CampaignName', 'AdGroupName', 'Query'],
'dimension': 'CampaignName',
'charts': ['pie', 'bar', 'progress'],
'chart': 'bar',
'metrics': ['Clicks', 'Impressions', 'Cost', 'AverageCpc', 'Ctr', 'Conversions', 'CostPerConversion', 'ConversionRate', 'ConversionValue', 'SearchImpressionShare', 'SearchAbsoluteTopImpressionShare', 'roas'],
'metric': 'Clicks',
'colspan': 6
}, {
'type': 'googleads_conversion_chart',
'dimensions': ['ConversionTypeName'],
'dimension': 'ConversionTypeName',
'charts': ['pie', 'bar', 'progress'],
'chart': 'bar',
'metrics': ['Conversions', 'CostPerConversion', 'ConversionRate', 'ConversionValue'],
'metric': 'Conversions',
'colspan': 6
}, {
'type': 'facebookinsights_timeline',
'class': 'mt-4',
'metrics': ['page_fans_total', 'page_impressions', 'engagements'],
'metric': 'page_fans_total',
'colspan': 6
}, {
'type': 'facebookads_timeline',
'metrics': ['clicks', 'impressions', 'cpc', 'cpm', 'spend', 'ctr'],
'metric': 'clicks',
'colspan': 6
}, {
'type': 'ranktracer',
'class': 'mt-4',
'colspan': 6
}, {
'type': 'onpage_seo',
'colspan': 12
}, {
'type': 'onpage_changes',
'colspan': 6
}, {
'type': 'onpage_changes_donut',
'colspan': 6
}],
'widths': [
{ 'colspan': 3, 'width': '25%' },
{ 'colspan': 4, 'width': '33%' },
{ 'colspan': 6, 'width': '50%' },
{ 'colspan': 8, 'width': '66%' },
{ 'colspan': 9, 'width': '75%' },
{ 'colspan': 12, 'width': '100%' },
]
}
$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.do = function(obj, method, param) {
if (obj == 'fnWidgets') {
fnWidgets[method](param);
} else if (obj == 'fnTemplates') {
fnTemplates[method](param);
}
}
var fnTemplates = {
list: function() {
$http.get('/rest/home/template.list', {
params: {
websiteid: h.siteId(),
}
}).then(function successCallback(res) {
$scope.templates = res.data;
});
},
use: function(widgets) {
$scope.widgets = widgets;
fnWidgets.save();
$scope.fnCloseModal();
},
create: function() {
var cleanwidgets = angular.copy($scope.widgets).map(function(c) {
delete c.widget;
return c;
})
$scope.curtemplate.widgets = cleanwidgets;
$http.post('/rest/home/template.save', { websiteid: h.siteId(), 'template': $scope.curtemplate }).then(function successCallback(res) {
$scope.fnCloseModal();
});
},
save: function(template) {
var cleanwidgets = angular.copy($scope.widgets).map(function(c) {
delete c.widget;
return c;
})
template.widgets = cleanwidgets;
template.name = ($scope.curtemplate.name) ? $scope.curtemplate.name : template.name;
template.description = ($scope.curtemplate.description) ? $scope.curtemplate.description : template.description;
$http.post('/rest/home/template.save', { websiteid: h.siteId(), 'template': template }).then(function successCallback(res) {
$scope.fnCloseModal();
});
},
delete: function(template) {
$http.post('/rest/home/template.delete', template).then(function successCallback(res) {
$scope.fnCloseModal();
});
},
}
var fnWidgets = {
'add': function(widget) {
$http.post('/rest/home/widget.add', angular.extend({ websiteid: h.siteId() }, widget)).then(function successCallback(res) {
$scope.fnCloseModal();
fnWidgets.list();
$scope.page.edit = false;
});
},
'save': function() {
$http.post('/rest/home/widgets.save', angular.extend({ websiteid: h.siteId() }, { 'widgets': $scope.widgets })).then(function successCallback(res) {
$scope.fnCloseModal();
fnWidgets.list();
$scope.page.edit = false;
});
},
'delete': function(widget) {
angular.forEach($scope.widgets, function(v, k) {
if (v.k == widget.k) {
$scope.widgets.splice(k, 1);
fnWidgets.save();
}
})
},
'reorder': function(o) {
o.widget.order = o.widget.order - 0.1;
angular.forEach($filter('orderBy')($scope.widgets, 'order', false), function(v, k) {
v.order = k + 1;
});
},
'pre_add': function() {
fnTemplates.list();
$scope.fnModal('home/modal.widgets');
},
'pre_edit': function() {
$scope.page.edit = true;
},
'list': function() {
$http.get('/rest/home/widgets.list', {
params: {
websiteid: h.siteId(),
}
}).then(function successCallback(res) {
if (res.data.length == 0) {
res.data = [
{ "type": "onpage_seo", "metric": null, 'colspan': 12, 'order': 1, 'k': 'k1' },
{ "type": "analytics4_timeline", "metric": "sessions", 'colspan': 4, 'order': 2, 'k': 'k2' },
{ "type": "onpage_changes", "metric": null, 'colspan': 4, 'order': 3, 'k': 'k3' },
{ "type": "searchconsole_keywords", "metric": null, 'colspan': 4, 'order': 4, 'k': 'k4' },
{ "type": "searchconsole_timeline", "metric": 'clicks', 'colspan': 6, 'order': 5, 'k': 'k5' },
{ "type": "ranktracer", "metric": null, 'colspan': 6, 'order': 6, 'k': 'k6' },
];
}
$scope.widgets = res.data;
angular.forEach($scope.widgets, function(v, k) {
fnWidgetGenerator[v.type](v);
})
});
}
}
fnWidgets.list();
var _charts = {
init: function(type, dataset, dimension, metric, dateformat) {
return _charts[type](dataset, dimension, metric, dateformat);
},
progress: function(dataset, dimension, metric) {
return $filter('orderBy')(dataset, metric, true).slice(0, 5);
},
bar: function(dataset, dimension, metric) {
dataset = $filter('orderBy')(dataset, metric, true).slice(0, 8);
//inject color attribute with value
if (typeof dataset != undefined) {
for (var i = 0; i < dataset.length; i++) { dataset[i].color = $scope.colors[i]; }
}
return {
data: dataset.slice(0, 6),
type: 'serial',
categoryField: dimension,
rotate: false,
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,
}],
}
},
pie: function(dataset, dimension, metric) {
dataset = $filter('orderBy')(dataset, metric, true).slice(0, 12);
return {
data: dataset.slice(0, 9),
type: 'pie',
categoryField: dimension,
"precision": 0,
"decimalSeparator": ",",
"thousandsSeparator": ".",
legend: {
enabled: false,
position: 'right',
autoMargins: false,
marginRight: 100,
},
titleField: dimension,
valueField: metric,
labelRadius: 5,
radius: '42%',
innerRadius: '60%',
labelText: '[[title]]',
}
},
timeline(dataset, dimension, metric, dateformat) {
return {
data: dataset,
type: 'serial',
categoryField: dimension,
rotate: false,
dataDateFormat: dateformat,
categoryAxis: { gridPosition: "start", parseDates: true, gridThickness: 0 },
valueAxes: [{ position: "left", axisAlpha: 0, labelsEnabled: true, dashLength: 4, color: '#dedede', }],
graphs: [{
'balloonText': "Amount
[[value]]",
"bullet": "round",
"bulletBorderAlpha": 1,
"bulletColor": "#FFFFFF",
"useLineColorForBulletBorder": true,
"fillAlphas": 0.3,
"lineThickness": 2,
"lineAlpha": 1,
"bulletSize": 7,
"title": "Expenses",
"valueField": metric,
'lineColor': fnWidgetGenerator.color()
}],
}
}
}
var fnWidgetGenerator = {
i: -1,
'color': function(i) {
var colors = h.colors();
fnWidgetGenerator.i += 1;
return colors[fnWidgetGenerator.i];
},
'analytics_timeline': function(widget) {
$http.get('/rest/analytics/v4', {
params: { 't':'123','dimension': 'date', 'end': 'TODAY', 'metrics': widget.metric, 'start': '30DAYSAGO', websiteid: h.siteId(), }
}).then(function successCallback(res) {
widget.widget = _charts.init('timeline', res.data.data, 'ga:date', widget.metric, 'YYYYMMDD')
widget.widget.action = res.data.action;
});
},
'analytics4_timeline': function(widget) {
$http.get('/rest/analytics4/report', {
params: { 't':'123','dimension': 'date', 'end': 'TODAY', 'metrics': widget.metric, 'start': '30DAYSAGO', websiteid: h.siteId(), }
}).then(function successCallback(res) {
widget.widget = _charts.init('timeline', res.data.data, 'date', widget.metric, 'YYYYMMDD')
widget.widget.action = res.data.action;
});
},
'analytics_chart': function(widget) {
$http.get('/rest/analytics/v4', {
params: { 'dimension': widget.dimension, 'end': 'TODAY', 'metrics': widget.metric, 'start': '30DAYSAGO', websiteid: h.siteId() }
}).then(function successCallback(res) {
widget.widget = _charts.init(widget.chart, res.data.data, 'ga:' + widget.dimension, widget.metric)
widget.widget.action = res.data.action;
});
},
'googleads_timeline': function(widget) {
$http.get('/rest/googlexads/report', {
params: { 'dimension': 'Date', 'end': 'TODAY', 'metrics': widget.metric, 'start': '30DAYSAGO', websiteid: h.siteId(), 'report': 'ACCOUNT_PERFORMANCE_REPORT' }
}).then(function successCallback(res) {
widget.widget = _charts.init('timeline', res.data.data, 'Date', widget.metric, 'YYYY-MM-DD')
widget.widget.action = res.data.action;
});
},
'googleads_performance_chart': function(widget) {
var report = { 'CampaignName': 'CAMPAIGN_PERFORMANCE_REPORT', 'AdGroupName': 'ADGROUP_PERFORMANCE_REPORT', 'Query': 'SEARCH_QUERY_PERFORMANCE_REPORT' };
$http.get('/rest/googlexads/report', {
params: { 'dimension': widget.dimension, 'end': 'TODAY', 'metrics': widget.metric, 'start': '30DAYSAGO', websiteid: h.siteId(), 'report': report[widget.dimension] }
}).then(function successCallback(res) {
widget.widget = _charts.init(widget.chart, res.data.data, widget.dimension, widget.metric)
widget.widget.action = res.data.action;
});
},
'googleads_conversion_chart': function(widget) {
$http.get('/rest/googlexads/report', {
params: { 'dimension': widget.dimension, 'end': 'TODAY', 'metrics': widget.metric, 'start': '30DAYSAGO', websiteid: h.siteId(), 'report': 'ACCOUNT_PERFORMANCE_REPORT' }
}).then(function successCallback(res) {
widget.widget = _charts.init(widget.chart, res.data.data, widget.dimension, widget.metric)
widget.widget.action = res.data.action;
});
},
'facebookinsights_timeline': function(widget) {
$http.get('/rest/facebookinsights/report', {
params: { 'dimension': 'date', 'end': 'TODAY', 'start': '30DAYSAGO', websiteid: h.siteId(), 'endpoint': 'insights', 'report': 'timeline' }
}).then(function successCallback(res) {
if (widget.metric == 'engagements') {
var data = res.data.sets[widget.metric].data.reduce(function(acc, cur) {
if (cur.type == 'engagements') {
acc.push({ 'change': cur.value, 'date': cur.date });
}
return acc;
}, []);
} else {
var data = res.data.sets[widget.metric].data
}
widget.widget = _charts.init('timeline', data, 'date', 'change', 'YYYY-MM-DD')
widget.widget.action = res.data.action;
});
},
'facebookads_timeline': function(widget) {
$http.get('/rest/facebookads/report', {
params: { 'dimension': 'date', 'end': 'TODAY', 'start': '30DAYSAGO', websiteid: h.siteId(), 'level': 'account', 'endpoint': 'insights', 'metrics': widget.metric }
}).then(function successCallback(res) {
widget.widget = _charts.init('timeline', res.data.data, 'date', widget.metric, 'YYYY-MM-DD')
widget.widget.action = res.data.action;
});
},
'onpage_changes': function(widget) {
$http.get('/rest/onpage/rules', { 'params': { 'lang': $scope.user.site.locale.lang } }).then(function successCallback(res) {
$scope.onpage = res.data;
$http.get('/rest/onpage/changes', {
params: {
websiteid: h.siteId(),
}
}).then(function successCallback(res) {
widget.widget = res.data.data;
});
});
},
'onpage_changes_donut': function(widget) {
$http.get('/rest/onpage/changes', { 'params': { websiteid: h.siteId() } }).then(function successCallback(res) {
var stats = [{ 'label': 'change', 'value': 0, 'color': '#808080' }, { 'label': 'done', 'value': 0, 'color': '#4caf50' }, { 'label': 'issue', 'value': 0, 'color': '#ff9800' }];
for (var i in res.data.data) {
if (res.data.data[i].r === true) {
stats[1].value += 1;
} else if (res.data.data[i].r === false) {
stats[2].value += 1;
} else {
stats[0].value += 1;
}
}
widget.widget = { data: stats, type: 'pie', marginLeft: 0, marginRight: 0, marginTop: 10, categoryField: 'label', "precision": 0, "decimalSeparator": ",", "thousandsSeparator": ".", legend: { enabled: false, position: 'right', autoMargins: false, marginRight: 100, }, titleField: 'label', valueField: 'value', "colorField": "color", labelRadius: 5, radius: '42%', innerRadius: '60%', labelText: '[[label]]', }
});
},
'onpage_seo': function(widget) {
$http.get('/rest/onpage/list', {
params: {
websiteid: h.siteId(),
}
}).then(function successCallback(res) {
widget.widget = res.data;
widget.widget.avg = { 'all': 0, 'technical': 0, 'content': 0, 'mobile': 0, 'indexability': 0 }
if(widget.widget.history){
var l = widget.widget.history.length;
angular.forEach(widget.widget.history, function(value, key) {
widget.widget.avg['all'] += value.all / l
widget.widget.avg['technical'] += value.technical / l
widget.widget.avg['content'] += value.content / l
widget.widget.avg['mobile'] += value.mobile / l
widget.widget.avg['indexability'] += value.indexability / l
});
}
});
},
'ranktracer': function(widget) {
$http.get('/rest/rank-tracker/list', {
params: {
websiteid: h.siteId(),
}
}).then(function successCallback(res) {
for (var i in res.data) {
res.data[i].summary.google.pos = res.data[i].summary.google.pos || 100
res.data[i].summary.googlemobile.pos = res.data[i].summary.googlemobile.pos || 100
res.data[i].health = 100 - ((res.data[i].summary.google.worst - res.data[i].summary.google.pos + .5) / (res.data[i].summary.google.worst - res.data[i].summary.google.best)) * 100;
}
widget.widget = res.data;
});
},
'searchconsole_keywords': function(widget) {
$http.get('/rest/searchconsole/report', {
params: { 'dimension': 'query', 'end': 'TODAY', 'metrics': 'clicks,ctr,position,impressions', 'start': '30DAYSAGO', 'report': 'searchAnalytics', websiteid: h.siteId(), }
}).then(function successCallback(res) {
widget.widget = res.data;
});
},
'searchconsole_chart': function(widget) {
$http.get('/rest/searchconsole/report', {
params: { 'dimension': widget.dimension, 'end': 'TODAY', 'metrics': widget.metric, 'start': '30DAYSAGO', websiteid: h.siteId(), }
}).then(function successCallback(res) {
widget.widget = _charts.init(widget.chart, res.data.data, widget.dimension, widget.metric);
widget.widget.action = res.data.action;
});
},
'searchconsole_timeline': function(widget) {
$http.get('/rest/searchconsole/report', {
params: { 't':'123','dimension': 'date', 'end': 'TODAY', 'metrics': widget.metric, 'start': '30DAYSAGO', websiteid: h.siteId(), 'report': 'searchAnalytics' }
}).then(function successCallback(res) {
widget.widget = _charts.init('timeline', res.data.data, 'date', widget.metric, 'YYYY-MM-DD')
widget.widget.action = res.data.action;
});
},
};
}
]);
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('