Implemented loading custom CSS and templates, implemented google analytics
This commit is contained in:
parent
9fb8eada9f
commit
ae5d23bd2c
11 changed files with 159 additions and 13 deletions
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "laine",
|
"name": "laine",
|
||||||
"version": "0.0.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"components-bootstrap": "~3.1.1",
|
"components-bootstrap": "~3.1.1",
|
||||||
|
|
|
@ -38,7 +38,8 @@ var requireJsRuntimeConfig = vm.runInNewContext(fs.readFileSync('src/app/require
|
||||||
'components/year-page/year-page',
|
'components/year-page/year-page',
|
||||||
'components/month-page/month-page',
|
'components/month-page/month-page',
|
||||||
'components/post-page/post-page',
|
'components/post-page/post-page',
|
||||||
'components/config-service/config-service'
|
'components/config-service/config-service',
|
||||||
|
'components/template-service/template-service'
|
||||||
],
|
],
|
||||||
insertRequire: ['app/startup'],
|
insertRequire: ['app/startup'],
|
||||||
bundles: {
|
bundles: {
|
||||||
|
|
|
@ -1,4 +1,12 @@
|
||||||
define(["knockout", "crossroads", "hasher", "./routes"], function(ko, crossroads, hasher, routes) {
|
define(
|
||||||
|
[
|
||||||
|
"knockout",
|
||||||
|
"crossroads",
|
||||||
|
"hasher",
|
||||||
|
"./routes",
|
||||||
|
"../components/config-service/config-service",
|
||||||
|
"../components/ga-service/ga-service"
|
||||||
|
], function(ko, crossroads, hasher, routes, configService, gaService) {
|
||||||
|
|
||||||
// This module configures crossroads.js, a routing library. If you prefer, you
|
// This module configures crossroads.js, a routing library. If you prefer, you
|
||||||
// can use any other routing library (or none at all) as Knockout is designed to
|
// can use any other routing library (or none at all) as Knockout is designed to
|
||||||
|
@ -14,6 +22,8 @@ define(["knockout", "crossroads", "hasher", "./routes"], function(ko, crossroads
|
||||||
|
|
||||||
function Router(config) {
|
function Router(config) {
|
||||||
var currentRoute = this.currentRoute = ko.observable({});
|
var currentRoute = this.currentRoute = ko.observable({});
|
||||||
|
this.crossroads = crossroads;
|
||||||
|
this.hasher = hasher;
|
||||||
|
|
||||||
ko.utils.arrayForEach(config.routes, function(route) {
|
ko.utils.arrayForEach(config.routes, function(route) {
|
||||||
var addedRoute = crossroads.addRoute(route.url, function(requestParams) {
|
var addedRoute = crossroads.addRoute(route.url, function(requestParams) {
|
||||||
|
@ -29,7 +39,15 @@ define(["knockout", "crossroads", "hasher", "./routes"], function(ko, crossroads
|
||||||
}
|
}
|
||||||
|
|
||||||
function activateCrossroads() {
|
function activateCrossroads() {
|
||||||
function parseHash(newHash, oldHash) { crossroads.parse(newHash); }
|
function parseHash(newHash, oldHash) {
|
||||||
|
crossroads.parse(newHash);
|
||||||
|
|
||||||
|
// Send google analytics page event if it's enabled
|
||||||
|
if (configService.useGa) {
|
||||||
|
gaService.sendPageEvent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
crossroads.normalizeFn = crossroads.NORM_AS_OBJECT;
|
crossroads.normalizeFn = crossroads.NORM_AS_OBJECT;
|
||||||
hasher.prependHash = '!';
|
hasher.prependHash = '!';
|
||||||
hasher.initialized.add(parseHash);
|
hasher.initialized.add(parseHash);
|
||||||
|
|
|
@ -61,7 +61,3 @@ define([], function() {
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,10 @@ define(['jquery', 'knockout', './router', 'marked', 'bootstrap', 'knockout-proje
|
||||||
|
|
||||||
ko.components.register('config-service', { require: 'components/config-service/config-service' });
|
ko.components.register('config-service', { require: 'components/config-service/config-service' });
|
||||||
|
|
||||||
|
ko.components.register('template-service', { require: 'components/template-service/template-service' });
|
||||||
|
|
||||||
|
ko.components.register('ga-service', { require: 'components/ga-service/ga-service' });
|
||||||
|
|
||||||
// [Scaffolded component registrations will be inserted here. To retain this feature, don't remove this comment.]
|
// [Scaffolded component registrations will be inserted here. To retain this feature, don't remove this comment.]
|
||||||
|
|
||||||
// Set Markdown parser options
|
// Set Markdown parser options
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
define(['knockout', '../../app/routes', '../../app/router', 'hasher'],
|
define(['knockout'],
|
||||||
function(ko, routes, router, hasher) {
|
function(ko) {
|
||||||
|
|
||||||
function ConfigService() {
|
function ConfigService() {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
@ -9,6 +9,18 @@ define(['knockout', '../../app/routes', '../../app/router', 'hasher'],
|
||||||
|
|
||||||
document.title = self.blogName;
|
document.title = self.blogName;
|
||||||
self.baseTitle = self.blogName;
|
self.baseTitle = self.blogName;
|
||||||
|
|
||||||
|
// Load custom CSS if specified
|
||||||
|
if (self.customCss) {
|
||||||
|
var head = document.getElementsByTagName('head')[0];
|
||||||
|
var link = document.createElement('link');
|
||||||
|
link.id = 'laine-custom-css';
|
||||||
|
link.rel = 'stylesheet';
|
||||||
|
link.type = 'text/css';
|
||||||
|
link.href = self.customCss;
|
||||||
|
link.media = 'all';
|
||||||
|
head.appendChild(link);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This runs when the component is torn down. Put here any logic necessary to clean up,
|
// This runs when the component is torn down. Put here any logic necessary to clean up,
|
||||||
|
|
34
src/components/ga-service/ga-service.js
Normal file
34
src/components/ga-service/ga-service.js
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
define(
|
||||||
|
[
|
||||||
|
'knockout',
|
||||||
|
'../config-service/config-service'
|
||||||
|
], function(ko, configService) {
|
||||||
|
|
||||||
|
function GaService() {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
// The GA object that can be used in other components
|
||||||
|
self.ga = null;
|
||||||
|
|
||||||
|
if (configService.useGa) {
|
||||||
|
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||||
|
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||||
|
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||||
|
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||||
|
|
||||||
|
ga('create', configService.webPropertyID, 'auto');
|
||||||
|
self.ga = ga;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.sendPageEvent = function() {
|
||||||
|
self.ga('send', 'pageview');
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// This runs when the component is torn down. Put here any logic necessary to clean up,
|
||||||
|
// for example cancelling setTimeouts or disposing Knockout subscriptions/computeds.
|
||||||
|
GaService.prototype.dispose = function() { };
|
||||||
|
|
||||||
|
return new GaService();
|
||||||
|
|
||||||
|
});
|
|
@ -1,4 +1,10 @@
|
||||||
define(['knockout', '../db/db'], function(ko, DB) {
|
define(
|
||||||
|
[
|
||||||
|
'knockout',
|
||||||
|
'../db/db',
|
||||||
|
'../config-service/config-service',
|
||||||
|
'../template-service/template-service'
|
||||||
|
], function(ko, DB, configService, templateService) {
|
||||||
|
|
||||||
function GenericRoute() {
|
function GenericRoute() {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
@ -14,6 +20,16 @@ define(['knockout', '../db/db'], function(ko, DB) {
|
||||||
page(parseInt(route.pageNumber, 10));
|
page(parseInt(route.pageNumber, 10));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.resolveTemplate = function(originalTemplate, templateName) {
|
||||||
|
if (templateName in configService.customTemplates
|
||||||
|
&& configService.customTemplates[templateName]) {
|
||||||
|
return templateService.loadTemplate(templateName, configService.customTemplates[templateName]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return originalTemplate;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This runs when the component is torn down. Put here any logic necessary to clean up,
|
// This runs when the component is torn down. Put here any logic necessary to clean up,
|
||||||
|
|
|
@ -1,4 +1,10 @@
|
||||||
define(['knockout', 'text!./home.html', '../generic-route/generic-route', '../db/db'],
|
define(
|
||||||
|
[
|
||||||
|
'knockout',
|
||||||
|
'text!./home.html',
|
||||||
|
'../generic-route/generic-route',
|
||||||
|
'../db/db'
|
||||||
|
],
|
||||||
function(ko, templateMarkup, GR, DB) {
|
function(ko, templateMarkup, GR, DB) {
|
||||||
|
|
||||||
function HomePage(route) {
|
function HomePage(route) {
|
||||||
|
@ -15,6 +21,8 @@ define(['knockout', 'text!./home.html', '../generic-route/generic-route', '../db
|
||||||
// for example cancelling setTimeouts or disposing Knockout subscriptions/computeds.
|
// for example cancelling setTimeouts or disposing Knockout subscriptions/computeds.
|
||||||
HomePage.prototype.dispose = function() {};
|
HomePage.prototype.dispose = function() {};
|
||||||
|
|
||||||
|
templateMarkup = GR.resolveTemplate(templateMarkup, 'home');
|
||||||
|
|
||||||
return { viewModel: HomePage, template: templateMarkup };
|
return { viewModel: HomePage, template: templateMarkup };
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
32
src/components/template-service/template-service.js
Normal file
32
src/components/template-service/template-service.js
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
define(['knockout'], function(ko) {
|
||||||
|
|
||||||
|
function TemplateService() {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
self.templateStore = {};
|
||||||
|
|
||||||
|
self.loadTemplate = function(templateName, templateUrl) {
|
||||||
|
if (templateName in self.templateStore) {
|
||||||
|
return self.templateStore[templateName];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var html = $.ajax(templateUrl, {
|
||||||
|
// We need to set async false to receive the template before rendering
|
||||||
|
// starts
|
||||||
|
async: false,
|
||||||
|
dataType: 'html'
|
||||||
|
}).responseText;
|
||||||
|
|
||||||
|
self.templateStore[templateName] = html;
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// This runs when the component is torn down. Put here any logic necessary to clean up,
|
||||||
|
// for example cancelling setTimeouts or disposing Knockout subscriptions/computeds.
|
||||||
|
TemplateService.prototype.dispose = function() { };
|
||||||
|
|
||||||
|
return new TemplateService();
|
||||||
|
|
||||||
|
});
|
|
@ -18,5 +18,30 @@ LAINE_CONFIG = {
|
||||||
pageCommenting: false,
|
pageCommenting: false,
|
||||||
|
|
||||||
// Posts shown per page
|
// Posts shown per page
|
||||||
postsPerPage: 5
|
postsPerPage: 5,
|
||||||
|
|
||||||
|
|
||||||
|
// GOOGLE ANALYTICS
|
||||||
|
useGa: false, // Set to true to use Google Analytics
|
||||||
|
webPropertyID: '', // Your Google Analytics UA-XXXX-Y code
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// CUSTOM TEMPLATE AND CSS OVERRIDES
|
||||||
|
|
||||||
|
// To load a custom CSS file, insert the file name below
|
||||||
|
customCss: '',
|
||||||
|
|
||||||
|
// To replace builtin templates with custom teplates, insert the file names
|
||||||
|
// below in the correct places. The paths should be relative to the
|
||||||
|
// index.html path.
|
||||||
|
customTemplates: {
|
||||||
|
navbar: '', // Navigation bar
|
||||||
|
home: '', // Home page
|
||||||
|
post: '', // Single post/page
|
||||||
|
pagination: '', // A list of posts with included pagination
|
||||||
|
year: '', // Year archives
|
||||||
|
month: '', // Month archives
|
||||||
|
tag: '' // Tag archives
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
Reference in a new issue