Skip to content

Commit

Permalink
Draft preliminary interactive article linking
Browse files Browse the repository at this point in the history
  • Loading branch information
sethlu committed Sep 9, 2017
1 parent 07e5fcd commit 5ffbd6d
Show file tree
Hide file tree
Showing 9 changed files with 407 additions and 4 deletions.
36 changes: 34 additions & 2 deletions app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ <h2 data-ica-discussion-predicate="title" data-ica-discussion="title"></h2>
</section>
<div class="response-control">
<a data-ica-action="edit-response">Edit</a>
<a data-ica-action="insert">Insert</a>
<a data-ica-action="publish-response">Publish</a>
<a data-ica-action="unpublish-response">Unpublish</a>
<a data-ica-action="discard-edit-response">Discard Changes</a>
Expand Down Expand Up @@ -375,13 +376,44 @@ <h2 data-ica-notification="title"></h2>
<section class="prompt-container">
<h2 data-ica-prompt="title"></h2>
<p data-ica-prompt="message"></p>
<section class="actions">
</section>
<section class="actions"></section>
</section>
</div>
</div>
</template>
</div>
<template id="template-prompt-jointsource">
<div class="prompt">
<article class="prompt-card">
<header class="prompt-header">
<h2>Link to articles</h2>
<section class="topbar-container">
<div class="topbar">
<nav>
<ul>
<li><a data-ica-for-subview="conversations">Conversations</a></li>
<li><a data-ica-for-subview="discussions">Discussions</a></li>
</ul>
</nav>
</div>
</section>
</header>
<section class="prompt-explore-container">
<div data-ica-subview="conversations" hidden>
<div class="explore"></div>
<div class="spinner"></div>
</div>
<div data-ica-subview="discussions" hidden>
<div class="explore"></div>
<div class="spinner"></div>
</div>
</section>
<section class="prompt-actions-container">
<section class="actions"></section>
</section>
</article>
</div>
</template>
<!-- Begin main -->
<header class="topbar-container app-header">
<div class="topbar" data-ica-width-multiple="300">
Expand Down
1 change: 1 addition & 0 deletions images/icon-tick.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion scripts.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

"scripts/jointsources/JointSource.js",
"scripts/jointsources/JointSourceController.js",
"scripts/jointsources/JointSourcesHandler.js",
"scripts/jointsources/Source.js",
"scripts/jointsources/SourceController.js",
"scripts/jointsources/BlobFileSource.js",
Expand Down Expand Up @@ -61,7 +62,6 @@
"scripts/map/MapConversationVideoSourceController.js",
"scripts/map/MapDiscussionController.js",
"scripts/map/MapResponseController.js",

"scripts/map/explore/ExploreRefereesController.js",
"scripts/map/explore/ExploreHiddenRefereesController.js",

Expand All @@ -81,6 +81,8 @@
"scripts/prompts/PromptController.js",
"scripts/prompts/BasicPrompt.js",
"scripts/prompts/BasicPromptController.js",
"scripts/prompts/JointSourcePromptController.js",
"scripts/prompts/explore/ExploreJointSourceSelectionController.js",

"scripts/AudioHandler.js",

Expand Down
31 changes: 31 additions & 0 deletions scripts/jointsources/JointSourcesHandler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

let JointSourcesHandler = Handler.createComponent("JointSourcesHandler");

JointSourcesHandler.defineAlias("content", "jointSources");

JointSourcesHandler.defineMethod("init", function init(content = []) {
return [content];
});

JointSourcesHandler.defineMethod("add", function (jointSource) {
if (this.jointSources.indexOf(jointSource) < 0) {
this.jointSources.push(jointSource);
}
});

JointSourcesHandler.defineMethod("remove", function (jointSource) {
let index = this.jointSources.indexOf(jointSource);
if (index > -1) {
this.jointSources.splice(index, 1);
}
});

JointSourcesHandler.defineMethod("toggle", function (jointSource) {
let index = this.jointSources.indexOf(jointSource);
if (index > -1) {
this.jointSources.splice(index, 1);
return false;
}
this.jointSources.push(jointSource);
return true;
});
37 changes: 37 additions & 0 deletions scripts/map/MapResponseController.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,42 @@ MapResponseController.defineMethod("uninitModel", function uninitModel() {

// Edit/Publish

this.view.querySelector("[data-ica-action='insert']").addEventListener("click", function (event) {
event.preventDefault();

promptJointSourceSelection()
.then(function (jointSources) {
let quill = this.controller.quill;
let range = quill.getSelection(true);

if (!range) return; // Unable to find range

// Concatenate #jointSourceIds
let text = jointSources.map(function (jointSource) {
return "#" + jointSource.jointSourceId;
}).join(", ");

let ops = [];

// Remove selected text
if (range.index) ops.push({retain: range.index});
if (range.length) ops.push({delete: range.length});

// Add selected jointSource(s)
quill.insertText(range.index + range.length, text, "user");

// Update text
quill.updateContents(ops, "user");

// Refocus the selection to the end of insertion
quill.setSelection(range.index + range.length + text.length);

}.bind(this), function (err) {
console.warn(err);
});

}.bind(this.view));

let editResponseElement = this.view.querySelector("[data-ica-action='edit-response']");
editResponseElement.addEventListener("click", editResponseOnClick);
editResponseElement.controller = this;
Expand Down Expand Up @@ -196,6 +232,7 @@ MapResponseController.defineMethod("uninitModel", function uninitModel() {

this.quill.enable(this.lockingJointSource);

this.view.querySelector("[data-ica-action='insert']").hidden = !this.lockingJointSource;
this.view.querySelector("[data-ica-action='edit-response']").hidden = !(!this.jointSource.locked && this.response._authorId && this.response._authorId === ICA.accountId);
this.view.querySelector("[data-ica-action='publish-response']").hidden = !(this.lockingJointSource && this.response.message["0"] && this.response.message["0"] !== this.response._backup_message["0"]);
this.view.querySelector("[data-ica-action='unpublish-response']").hidden = !(!this.lockingJointSource && this.response.responseId > 0 && this.response._authorId && this.response._authorId === ICA.accountId);
Expand Down
138 changes: 138 additions & 0 deletions scripts/prompts/JointSourcePromptController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@

let JointSourcePromptController = PromptController.createComponent("JointSourcePromptController");

JointSourcePromptController.createViewFragment = function () {
return cloneTemplate("#template-prompt-jointsource");
};

JointSourcePromptController.defineMethod("initView", function initView() {
if (!this.view) return;

this.jointSourcesHandler = new JointSourcesHandler();

// Explore

// Conversations

this.exploreConversations = new Explore();
new ExploreJointSourceSelectionController(
this.exploreConversations,
this.view.querySelector("[data-ica-subview='conversations'] .explore")
).componentOf = this;

ICA.getConversations()
.then(function (conversations) {
this.exploreConversations.requestNext = conversations.requestNext;
this.exploreConversations.addItems(conversations);
this.exploreConversations.didUpdate();
}.bind(this), function (err) {
console.warn(err);
});

// Discussions

this.exploreDiscussions = new Explore();
new ExploreJointSourceSelectionController(
this.exploreDiscussions,
this.view.querySelector("[data-ica-subview='discussions'] .explore")
).componentOf = this;

ICA.getDiscussions()
.then(function (discussions) {
this.exploreDiscussions.requestNext = discussions.requestNext;
this.exploreDiscussions.addItems(discussions);
this.exploreDiscussions.didUpdate();
}.bind(this), function (err) {
console.warn(err);
});

// Pagination

new Routine(function () {
this.view.querySelectorAll(".conversations, .discussions").forEach(function (element) {
if (element.hidden) return;
element = element.querySelector(".explore");

let rect = element.getBoundingClientRect();
let explore = element.controller.explore;

if (rect.bottom < 2 * document.body.offsetHeight
&& explore.requestNext) {
// Need to load more content

console.count("Need to load more");
let requestNext = explore.requestNext;
explore.requestNext = undefined;

requestNext()
.then(function (conversations) {
explore.requestNext = conversations.requestNext;
explore.addItems(conversations);
explore.didUpdate();
}.bind(element), function (err) {
if (err instanceof ICA.APIResponse.EndOfResponse) {
// End of response
console.log("AppJointSourcesController: End of response");
} else {
// Critical error
console.error(err.message);
}
});

element.classList.toggle("loading", true);
} else {
element.classList.toggle("loading", false);
}
});
}.bind(this), 500, true)
.componentOf = this;

// View selection

this.view.querySelectorAll("[data-ica-for-subview]").forEach(function (element) {
let subview = getElementProperty(element, "for-subview");

element.addEventListener("click", function () {
event.preventDefault();

this.querySelectorAll("[data-ica-for-subview]").forEach(function (element) {
element.classList.toggle("active", getElementProperty(element, "for-subview") === subview);
});

this.querySelectorAll("[data-ica-subview]").forEach(function (element) {
element.hidden = getElementProperty(element, "subview") !== subview;
});
}.bind(this.view));
}.bind(this));

// Use first one as default
this.view.querySelector("[data-ica-for-subview]").click();

});

/***/

function promptJointSourceSelection() {
return new Promise(function (resolve, reject) {
let prompt = new Prompt([
new PromptAction(
"Cancel",
function () {
resolve([]);
}
),
new PromptAction(
"Select",
function () {
resolve(controller.jointSourcesHandler.jointSources);
},
true
)
]);

let fragment = JointSourcePromptController.createViewFragment();
let element = fragment.querySelector(".prompt");
document.body.appendChild(fragment);
let controller = new JointSourcePromptController(prompt, element);
});
}
78 changes: 78 additions & 0 deletions scripts/prompts/explore/ExploreJointSourceSelectionController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@

let ExploreJointSourceSelectionController = SingleModelController.createComponent("ExploreJointSourceSelectionController");

ExploreJointSourceSelectionController.defineAlias("model", "explore");

ExploreJointSourceSelectionController.defineMethod("initView", function initView() {
if (!this.view) return;

this.viewItems = [];

setElementProperty(this.view, "explore-id", this.explore.exploreId);
});

ExploreJointSourceSelectionController.defineMethod("updateView", function updateView() {
if (!this.view) return;

this.viewItems = this.viewItems.filter(function (item) {
if (this.explore.items.indexOf(item) > -1) return true;

var element = this.view.querySelector("[data-ica-jointsource-id='{0}']".format(item.jointSourceId));
if (element) {
element.controller.destroy(true);
}

return false;
}.bind(this));

this.explore.items.forEach(function (item) {

let Controller;
switch (item.constructor) {
case Conversation: Controller = ExploreConversationController; break;
case Discussion: Controller = ExploreDiscussionController; break;
default:
console.warn("Unhandled item:", item.constructor);
return;
}

let element = this.view.querySelector("[data-ica-jointsource-id='{0}']".format(item.jointSourceId));

// Check existing element
if (!element) {

// Create new view
let fragment = Controller.createViewFragment();
element = fragment.querySelector(".jointsource");
this.view.appendChild(fragment);

// Add event listener beforehand to so the controller would have a lower priority
element.addEventListener("click", function () {
event.preventDefault();
event.stopImmediatePropagation();

// Toggle selection
if (this.componentOf) {
let selected = this.componentOf.jointSourcesHandler.toggle(item);
element.classList.toggle("selected", selected);
}

}.bind(this));

let controller = new Controller(item, element);
controller.componentOf = this;

this.viewItems.push(item);

}

// element.classList.toggle("selected", !!this.componentOf.pinnedRefereeJointSources[item.jointSourceId]);

}.bind(this));
});

ExploreJointSourceSelectionController.defineMethod("uninitView", function initView() {
if (!this.view) return;

delete this.viewItems;
});
1 change: 1 addition & 0 deletions styles/_article.scss
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@
border: solid 1px rgba(#000, 0.10);
border-radius: 50%;
@include shadow(3);
z-index: 2;
}
}
}
Expand Down
Loading

0 comments on commit 5ffbd6d

Please sign in to comment.