Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ module.exports = {
UI: true,
Utils: true,
Viewer: true,
SocialAnnotationsService: true,
SocialAnnotationsModel: true,
SocialAnnotationsUI: true,
},
"rules": {
// 2 == error, 1 == warning, 0 == off
Expand Down
14 changes: 13 additions & 1 deletion docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,14 @@
<div class="top-message online-status-message bg-green" id="online-status" hidden>Online</div>
<div class="top-message offline-status-message bg-orange" id="offline-status" hidden>Offline</div>
<div class="top-message upload-btn bg-green" id="upload-to-drive" hidden>Upload to drive</div>
<div class="top-message upload-btn bg-green" id="update-version" hidden>Update version</div>
<div class="top-message toggle-annotations-btn bg-green" id="toggle-annotations" hidden>Toggle annotations</div>
<div id="social-annotations-container" hidden>

<div id="add-annotation-container">
<button id="add-annotation" class="btn btn--s btn--green">+</button>
<textarea id="annotation-text" rows="3" cols="40"></textarea>
</div>
</div>
</div>
<div class="welcome w-100 sans-serif bg-white" id="dropbox">
<h1 class="f2 f-subheadline-ns mb0">
Expand Down Expand Up @@ -73,11 +80,16 @@ <h3 class="f4 br3 br--top black-60 pv2 mb0">Wanna compare traces?</h3>
<script src="service-worker.js"></script>
<script src="https://chrome-devtools-frontend.appspot.com/serve_file/@14fe0c24836876e87295c3bd65f8482cffd3de73/inspector.js" id="devtoolsscript"></script>
<script src="https://apis.google.com/js/client.js" defer></script>
<script src="https://apis.google.com/js/api.js" defer></script>
<script src="https://gstatic.com/realtime/realtime-client-utils.js" defer></script>
<script src="utils.js" defer></script>
<script src="auth.js" defer></script>
<script src="dev_tools.js" defer></script>
<script src="sync_view.js" defer></script>
<script src="storage.js" defer></script>
<script src="social_annotations/model.js" defer></script>
<script src="social_annotations/service.js" defer></script>
<script src="social_annotations/ui.js" defer></script>
<script src="timeline_viewer.js" defer></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
Expand Down
2 changes: 1 addition & 1 deletion docs/service-worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
/* eslint-disable indent, no-unused-vars, no-multiple-empty-lines, max-nested-callbacks, space-before-function-paren, quotes, comma-spacing */
'use strict';

var precacheConfig = [["Images/toolbarButtonGlyphs.png","d71330d9fb3d9263767c817a5b341fd3"],["auth.js","d0ed441e6b64a852212cf47854e6767d"],["dev_tools.js","c102a6e37ab44a83c9c231cd575e0760"],["google8b1867cdabba50ce.html","6f460bcd31c3a7f9d1c5cb2da7b6b3d1"],["index.html","59e8e5748b087e2d1023f25796cb5ae9"],["storage.js","6b0886705bddd680239cd78326fcceb0"],["styles.css","f267be94df6c3a39f5216486ed794174"],["sync_view.js","523d71b6a5d776cad1bb81b4d25f9814"],["timeline_viewer.js","b52bcb6d7b5494fee6f448761791f91e"],["utils.js","b7c8184f9d70ebddb2e6fddb371e5331"]];
var precacheConfig = [["Images/toolbarButtonGlyphs.png","d71330d9fb3d9263767c817a5b341fd3"],["auth.js","d0ed441e6b64a852212cf47854e6767d"],["dev_tools.js","c102a6e37ab44a83c9c231cd575e0760"],["google8b1867cdabba50ce.html","6f460bcd31c3a7f9d1c5cb2da7b6b3d1"],["index.html","fc7b33b52a72a56c11561c246c3dc6d7"],["storage.js","681af70b70466cccee901aef2eb73b94"],["styles.css","d12f682d40288a2808fec8e14bc688d8"],["sync_view.js","523d71b6a5d776cad1bb81b4d25f9814"],["timeline_viewer.js","daa90eea9fbf1aa975b257da894ede40"],["utils.js","dde3388ab1edde4098c2f92b17a3b3b1"]];
var cacheName = 'sw-precache-v3-sw-precache-' + (self.registration ? self.registration.scope : '');


Expand Down
22 changes: 22 additions & 0 deletions docs/social_annotations/model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
'use strict';

// eslint-disable-next-line no-unused-vars
class SocialAnnotationsModel {
static get realtimeModelProperty() {
return 'annotations';
}

addAnnotation(text) {
if (!text.length) return;
this.annotations.push({
id: Utils.generateID(),
author: 'Anonymous',
date: Date.now(),
text: text
});
}

getAnnotations() {
return this.annotations.asArray();
}
}
82 changes: 82 additions & 0 deletions docs/social_annotations/service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
'use strict';

// eslint-disable-next-line no-unused-vars
class SocialAnnotationsService {
constructor() {
this.realtimeUtils = new utils.RealtimeUtils({clientId: GoogleAuth.clientId});
this.storage = new GoogleDrive();
this.socialAnnotationsUI = new SocialAnnotationsUI();
this.socialAnnotations = null;

this.socialAnnotationsUI.addAnnotationsBtn.addEventListener('click', _ => {
this.socialAnnotations.addAnnotation(this.socialAnnotationsUI.annotationText);
this.socialAnnotationsUI.clearAnnottionText();
});
}

get urlParamName() {
return 'annotationId';
}

get realtimeModelProperty() {
return SocialAnnotationsModel.realtimeModelProperty;
}

get realtimeStorageName() {
return 'timeline-viewer-annotations';
}

authRealtimeUtils() {
this.realtimeUtils.authorize(response => {
if (response.error) {
throw response.error;
}
this.socialAnnotationsUI.showToggleAnnotationsBtn();
this.start();
}, false);
}

start() {
gapi.drive.realtime.custom.registerType(SocialAnnotationsModel, 'SocialAnnotationsModel');
SocialAnnotationsModel.prototype[this.realtimeModelProperty] = gapi.drive.realtime.custom.collaborativeField(this.realtimeModelProperty);

const id = this.realtimeUtils.getParam(this.urlParamName);
if (id) {
// Load the document id from the URL
this.realtimeUtils.load(id.replace('/', ''), this.onLoad.bind(this), this.onInitialize.bind(this));
} else {
// Create a new document, add it to the URL
this.realtimeUtils.createRealtimeFile(this.realtimeStorageName, createResponse => {
if (createResponse.error) {
throw createResponse.error;
}
this.storage.insertPermission(createResponse.id).then(_ => {
// @fixme it's just to up and runing it
const params = new URL(location.href).searchParams;
const timelineUrl = params.get('loadTimelineFromURL');
window.history.pushState(null, null, `?loadTimelineFromURL=${timelineUrl}&${this.urlParamName}=${createResponse.id}`);
this.realtimeUtils.load(createResponse.id, this.onLoad.bind(this), this.onInitialize.bind(this));
});
});
}
}

onInitialize(model) {
const socialAnnotationsModel = model.create(SocialAnnotationsModel);
model.getRoot().set('socialAnnotationsModel', socialAnnotationsModel);
socialAnnotationsModel[this.realtimeModelProperty] = model.createList();
}

onLoad(doc) {
const model = doc.getModel();
this.socialAnnotations = model.getRoot().get('socialAnnotationsModel');
const annotations = this.socialAnnotations.getAnnotations();
if (annotations.length) {
this.socialAnnotationsUI.renderAnnotations(annotations);
}

this.socialAnnotations[this.realtimeModelProperty].addEventListener(gapi.drive.realtime.EventType.VALUES_ADDED, event => {
this.socialAnnotationsUI.renderAnnotations(event.values);
});
}
}
72 changes: 72 additions & 0 deletions docs/social_annotations/ui.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
'use strict';

// eslint-disable-next-line no-unused-vars
class SocialAnnotationsUI {
constructor() {
this.attachListeners();
}

get container() {
return document.getElementById('social-annotations-container');
}

get toggleAnnotationsBtn() {
return document.getElementById('toggle-annotations');
}

get addAnnotationsBtn() {
return document.getElementById('add-annotation');
}

get annotationField() {
return document.getElementById('annotation-text');
}

get annotationText() {
return this.annotationField.value;
}

get annotationTemplate() {
return `
<div class="annotation" id="annotation-%id%">
<p class="text">%text%</p>
<span class="author">Author: %author%</span>
<span class="date">Added: %date%</span>
</div>`;
}

attachListeners() {
this.toggleAnnotationsBtn.addEventListener('click', this.toggleAnnotations.bind(this));
}

showToggleAnnotationsBtn() {
this.toggleAnnotationsBtn.hidden = false;
}

toggleAnnotations() {
this.container.hidden = !this.container.hidden;
}

renderAnnotations(annotations) {
const nodes = document.createDocumentFragment();
for (const annotation of annotations) {
nodes.appendChild(this.getAnnotationNode(annotation));
}
this.container.appendChild(nodes);
}

getAnnotationNode(annotation) {
const parser = new DOMParser();
const tpl = Utils.renderTemplate(this.annotationTemplate, {
id: annotation.id,
text: annotation.text,
author: annotation.author,
date: (new Date(annotation.date)).toUTCString(),
});
return parser.parseFromString(tpl, 'text/xml').firstChild;
}

clearAnnottionText() {
this.annotationField.value = '';
}
}
2 changes: 2 additions & 0 deletions docs/storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class GoogleDrive {
constructor() {
this.utils = new Utils();
}

uploadData(fileName = `Timeline-data-${Date.now()}`, data) {
const contentType = 'application/octet-stream';

Expand Down Expand Up @@ -51,6 +52,7 @@ class GoogleDrive {
});
return new Promise(resolve => request.execute(resolve));
}

insertPermission(fileId, type = 'anyone', role = 'writer') {
const url = new URL(`https://www.googleapis.com/drive/v2/files/${fileId}/permissions`);
const body = {
Expand Down
47 changes: 46 additions & 1 deletion docs/styles.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions docs/timeline_viewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class Viewer {
this.utils = new Utils();
this.devTools = new DevTools({viewerInstance: this});
this.gdrive = new GoogleDrive({viewerInstance: this});
this.socialAnnotations = new SocialAnnotationsService();

this.attachEventListeners();

Expand All @@ -56,6 +57,7 @@ class Viewer {
this.devTools.init();

if (!this.welcomeView) {
this.socialAnnotations.authRealtimeUtils();
this.makeDevToolsVisible(true);
}
}
Expand Down
15 changes: 15 additions & 0 deletions docs/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

// eslint-disable-next-line no-unused-vars
class Utils {

fetch(url, params, CORSFlag = false) {
if (CORSFlag) {
return this.doCORSRequest(url, params.method, params.body, params.addRequestHeaders, params.onprogress);
} else {
return fetch(url, params);
}
}

doCORSRequest(url, method='GET', body, addRequestHeaders, onprogress) {
return new Promise((resolve, reject) => {
// Use an XHR rather than fetch so we can have progress events
Expand All @@ -28,4 +30,17 @@ class Utils {
xhr.send(body);
});
}

static generateID() {
return Math.random().toString(36).substr(2, 9);
}

static renderTemplate(template, data) {
for (const prop in data) {
if (Object.prototype.hasOwnProperty.call(data, prop)) {
template = template.replace(`%${prop}%`, data[prop]);
}
}
return template;
}
}