Skip to content

Commit

Permalink
Merge pull request #8 from Financial-Times/spoor_impl
Browse files Browse the repository at this point in the history
Spoor impl
  • Loading branch information
constantology authored Sep 6, 2017
2 parents 6e01eb7 + 3b1d7c6 commit 7d2d265
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 17 deletions.
1 change: 1 addition & 0 deletions bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"next-session-client": "^2.3.3",
"o-buttons": ">=4.0.0 <6",
"o-overlay": "^2.0.0",
"o-tracking": "^1.1.8",
"superstore": "^2.1.0"
},
"resolutions": {
Expand Down
18 changes: 18 additions & 0 deletions src/js/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ export const ATTR_ACTION = 'data-action';
export const ATTR_CONTENT_ID = 'data-content-id';
export const ATTR_CONTENT_TYPE = 'data-content-type';
export const ATTR_SYNDICATED = 'data-syndicated';
export const ATTR_TRACKABLE = 'data-trackable';
export const ATTR_TRACKABLE_VALUE = 'syn-icon';

export const CSS_CLASS_PREFIX = 'n-syndication';
export const CSS_CLASS_REPUBLISHING_BUTTON = 'download-button';
Expand All @@ -13,6 +15,7 @@ export const CSS_SELECTOR_CONTENT_ID = `[${ATTR_CONTENT_ID}]`;
export const CSS_SELECTOR_NOT_SYNDICATED = `:not([${ATTR_SYNDICATED}="true"])`;
export const CSS_SELECTOR_REPUBLISHING_BTN = `${CSS_SELECTOR_CONTENT_ID}[${ATTR_SYNDICATED}="true"].${CSS_CLASS_REPUBLISHING_BUTTON}`;
export const CSS_SELECTOR_SYNDATION_ICON = `${CSS_SELECTOR_CONTENT_ID}[${ATTR_SYNDICATED}="true"].${CSS_CLASS_PREFIX}-icon`;
export const CSS_SELECTOR_TRACKABLE = `[${ATTR_TRACKABLE}]`;

export const DATA_ID_PROPERTY = 'id';

Expand Down Expand Up @@ -64,6 +67,21 @@ export const SYNDICATION_INSERTION_RULES = {
'main.video': { fn: 'querySelector', slc: '.video__title' },
'li.o-teaser__related-item': {}
};

export const TRACKING = {
CATEGORY: 'syndication',
DATA: {
context: {
app: 'Syndication'
},
system: {
product: 'Syndication',
source: 'o-tracking'
}
},
URI: 'https://spoor-api.ft.com/px.gif'
};

//export const URI_PREFIX_DOWNLOAD = '/syndication/download';
export const URI_PREFIX_DOWNLOAD = `${location.port ? '' : 'https://dl.syndication.ft.com'}/syndication/download`;

Expand Down
5 changes: 4 additions & 1 deletion src/js/iconify.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {
ATTR_CONTENT_ID,
ATTR_CONTENT_TYPE,
ATTR_SYNDICATED,
ATTR_TRACKABLE,
ATTR_TRACKABLE_VALUE,
CSS_CLASS_PREFIX,
CSS_SELECTOR_CONTENT_ID,
CSS_SELECTOR_NOT_SYNDICATED, DATA_ID_PROPERTY,
Expand All @@ -32,7 +34,7 @@ function init () {
}

function createElement (item) {
return toElement(`<button class="${CSS_CLASS_PREFIX}-icon ${CSS_CLASS_PREFIX}-icon-state-${String(item.canBeSyndicated).toLowerCase()}" ${ATTR_CONTENT_ID}="${item[DATA_ID_PROPERTY]}" ${ATTR_CONTENT_TYPE}="${item.type}" ${ATTR_SYNDICATED}="true" data-message-code="${item.messageCode}" type="button"></button>`);
return toElement(`<button class="${CSS_CLASS_PREFIX}-icon ${CSS_CLASS_PREFIX}-icon-state-${String(item.canBeSyndicated).toLowerCase()}" ${ATTR_CONTENT_ID}="${item[DATA_ID_PROPERTY]}" ${ATTR_CONTENT_TYPE}="${item.type}" ${ATTR_SYNDICATED}="true" ${ATTR_TRACKABLE}="${ATTR_TRACKABLE_VALUE}" data-message-code="${item.messageCode}" type="button"></button>`);
}

function findElementToSyndicate (el) {
Expand Down Expand Up @@ -92,6 +94,7 @@ function syndicateElement (item, el) {
element.prepend(createElement(item));

element.setAttribute(ATTR_CONTENT_TYPE, item.type);
// element.setAttribute(ATTR_TRACKABLE, ATTR_TRACKABLE_VALUE);
}

if (element !== el) {
Expand Down
50 changes: 46 additions & 4 deletions src/js/modal-download.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
'use strict';

import { broadcast } from 'n-ui-foundations';
//import tracking from 'o-tracking';
import { listenTo } from 'o-viewport';
import Superstore from 'superstore';

import {
ATTR_ACTION,
ATTR_TRACKABLE,
CSS_CLASS_PREFIX,
CSS_SELECTOR_ACTION_DOWNLOAD,
CSS_SELECTOR_ACTION_SAVE,
Expand All @@ -17,6 +19,7 @@ import {
MAX_LOCAL_FORMAT_TIME_MS,
MESSAGES,
MS_DELAY_HIDE,
TRACKING,
URI_PREFIX_DOWNLOAD,
URI_PREFIX_SAVE
} from './config';
Expand All @@ -30,17 +33,34 @@ let OVERLAY_FRAGMENT;
let OVERLAY_MODAL_ELEMENT;
let OVERLAY_SHADOW_ELEMENT;
let DOWNLOAD_FORMAT;
let USER_DATA;

function init () {
function init (flags, user) {
addEventListener('click', actionModalFromClick, true);

addEventListener('keyup', actionModalFromKeyboard, true);
addEventListener('resize', reposition, true);

listenTo('resize');

USER_DATA = user;
}

function actionModalFromClick (evt) {
const item = getItemByHTMLElement(evt.target);

const trackingEvent = {};
trackingEvent.category = TRACKING.CATEGORY;
trackingEvent.contractID = USER_DATA.contract_id;
trackingEvent.referrer = location.href;
trackingEvent.action = evt.target.getAttribute(ATTR_TRACKABLE);

if (item) {
trackingEvent.message = item.messageCode;
trackingEvent.article_id = item[DATA_ID_PROPERTY];
trackingEvent.syndication_content = item.type;
}

if (evt.target.matches(CSS_SELECTOR_SYNDATION_ICON)) {
show(evt);
}
Expand Down Expand Up @@ -74,13 +94,24 @@ function actionModalFromClick (evt) {
}
}
}

broadcast('oTracking.event', trackingEvent);
}

function actionModalFromKeyboard (evt) {
switch (evt.key) {
case 'Escape' :
hide();

const trackingEvent = {};

trackingEvent.category = TRACKING.CATEGORY;
trackingEvent.contractID = USER_DATA.contract_id;
trackingEvent.referrer = location.href;
trackingEvent.action = 'close-syndication-modal';

broadcast('oTracking.event', trackingEvent);

break;
case ' ' : case 'Enter' :
if (evt.target.matches(CSS_SELECTOR_SYNDATION_ICON)) {
Expand All @@ -89,6 +120,7 @@ function actionModalFromKeyboard (evt) {

break;
}

}

function createElement (item) {
Expand All @@ -99,8 +131,16 @@ function createElement (item) {
let saveButtonState = item.saved === true ? 'disabled' : '';
let saveHref = generateSaveURI(item[DATA_ID_PROPERTY]);
let message;
let trackableValue = 'download-item';
let wordCount = '';

if (location.pathname.includes('/download')) {
trackableValue = 'redownload';
}
else if (location.pathname.includes('/save')) {
trackableValue = 'download-saved-item';
}

if (item.canBeSyndicated === 'verify') {
downloadButtonState = 'disabled';
message = MESSAGES.MSG_2200;
Expand Down Expand Up @@ -137,6 +177,8 @@ function createElement (item) {
message = MESSAGES.MSG_2000;
}

// item.messageCode = message;

if (downloadButtonState === 'disabled') {
downloadHref = '#';
downloadText += ' unavailable';
Expand All @@ -149,15 +191,15 @@ function createElement (item) {
let frag = toElement(`<div class="${CSS_CLASS_PREFIX}-modal-shadow"></div>
<div class="${CSS_CLASS_PREFIX}-modal ${CSS_CLASS_PREFIX}-modal-${item.type}" role="dialog" aria-labelledby="${LABEL_ARIA_OVERLAY} ${item.title}" tabindex="0">
<header class="${CSS_CLASS_PREFIX}-modal-heading">
<a class="${CSS_CLASS_PREFIX}-modal-close" data-action="close" role="button" href="#" aria-label="Close" title="Close" tabindex="0"></a>
<a class="${CSS_CLASS_PREFIX}-modal-close" data-action="close" ${ATTR_TRACKABLE}="close-syndication-modal" role="button" href="#" aria-label="Close" title="Close" tabindex="0"></a>
<span role="heading" class="${CSS_CLASS_PREFIX}-modal-title">${item.title}</span>
</header>
<section class=" ${CSS_CLASS_PREFIX}-modal-content">
${wordCount}
${message}
<div class="${CSS_CLASS_PREFIX}-actions" data-content-id="${item[DATA_ID_PROPERTY]}">
<a class="${CSS_CLASS_PREFIX}-action" data-action="save" ${saveButtonState} href="${saveHref}">${saveText}</a>
<a class="${CSS_CLASS_PREFIX}-action" data-action="download" ${downloadButtonState} href="${downloadHref}">${downloadText}</a>
<a class="${CSS_CLASS_PREFIX}-action" data-action="save" ${saveButtonState} ${ATTR_TRACKABLE}="save-for-later" href="${saveHref}">${saveText}</a>
<a class="${CSS_CLASS_PREFIX}-action" data-action="download" ${downloadButtonState} ${ATTR_TRACKABLE}="${trackableValue}" href="${downloadHref}">${downloadText}</a>
</div>
</section>
</div>`);
Expand Down
21 changes: 19 additions & 2 deletions src/js/navigation.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
'use strict';

import { $ } from 'n-ui-foundations';
import { $, broadcast } from 'n-ui-foundations';
//import tracking from 'o-tracking';

function init () {
let USER_DATA;

function init (flags, user) {
insertNavItem('#o-header-nav-desktop', '[data-trackable="My Account" i]', '.o-header__nav-link');

insertNavItem('#o-header-drawer', '[data-trackable="Portfolio" i]', '.o-header__drawer-menu-link');

USER_DATA = user;
}

function insertNavItem (selectorContainer, selectorInsertionPoint, selectorLink) {
Expand All @@ -15,6 +20,8 @@ function insertNavItem (selectorContainer, selectorInsertionPoint, selectorLink)

const elNavItem = elInsertionPoint.cloneNode(true);

elNavItem.setAttribute('data-trackable', 'syndication');

const elNavItemLink = elNavItem.querySelector(selectorLink);

elNavItemLink.classList.add('n-syndication-republishing');
Expand All @@ -24,6 +31,16 @@ function insertNavItem (selectorContainer, selectorInsertionPoint, selectorLink)

elInsertionPoint.insertAdjacentElement('afterend', elNavItem);

elNavItemLink.addEventListener('click', (evt) => {
broadcast('oTracking.event', {
category: 'syndication',
action: 'republish',
contractID: USER_DATA.contract_id,
referrer: location.href,
url: evt.target.href || evt.target.getAttribute('href')
});
});

return { container: elCt, item: elNavItem };
}

Expand Down
8 changes: 4 additions & 4 deletions src/js/redux.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,17 @@ function init (flags, user) {
}

function _init (flags, user) {
if (user.migrated !== true && !flags.get('syndicationRedux')) {
if (user && user.migrated !== true && !flags.get('syndicationRedux')) {
return;
}

initNavigation();
initNavigation(flags, user);

initDataStore(flags);

initIconify(flags);
initIconify(flags, user);

initDownloadModal(flags);
initDownloadModal(flags, user);
}

export { init };
57 changes: 51 additions & 6 deletions src/js/republishing.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,61 @@
'use strict';

import { broadcast } from 'n-ui-foundations';
//import tracking from 'o-tracking';

import getUserStatus from './get-user-status';
import { init as initDataStore } from './data-store';
import { init as initDownloadModal } from './modal-download';
import { TRACKING } from './config';

function init (flags, user) {
if (user) {
_init(flags, user);
}
else {
getUserStatus().then(user => {
_init(flags, user);
});
}
}

function init (flags) {
if (typeof window.republishingInitData !== 'function') {
window.republishingInitData = function () {};
function _init (flags, user) {
if (!location.pathname.includes('/contract')) {
if (typeof window.republishingInitData !== 'function') {
window.republishingInitData = function () {};
}

initDataStore(flags, window.republishingInitData());

initDownloadModal(flags, user);
}

initDataStore(flags, window.republishingInitData());
track(flags, user);
}

function track (flags, user) {
const config = JSON.parse(JSON.stringify(TRACKING.DATA));
config.context.contractID = user.contract_id;
config.context.appVersion = user.app.version;

// broadcast('oTracking.page', config);
broadcast('oTracking.page', {
app: TRACKING.DATA.context.app,
appVersion: user.app.version,
contractID: user.contract_id
});

initDownloadModal(flags);
// tracking.init({
// server: TRACKING.URI
// });
//
// tracking.page({
// app: `${TRACKING.DATA.context.app}.simple`,
// appVersion: user.app.version,
// contractID: user.contract_id
// }, () => {});
//
// tracking.page(config, () => {});
}

export { init };
export { init, track };

0 comments on commit 7d2d265

Please sign in to comment.