Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interactive Article Linking #25

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
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
40 changes: 36 additions & 4 deletions app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,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 @@ -368,20 +369,51 @@ <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">
<div class="topbar-title-complex">
<a class="topbar-title-complex" href="/conversations" data-ica-for-view="conversations">
<h1 class="title">Many-to-Many</h1>
<p class="subtitle">Rethinking the Ethnographic Archive</p>
</div>
</a>
<nav>
<ul>
<li><a href="/conversations" data-ica-for-view="conversations">Explore Conversations</a></li>
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;
});
43 changes: 43 additions & 0 deletions scripts/map/MapResponseController.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,10 @@ MapResponseController.defineMethod("uninitModel", function uninitModel() {

// Edit/Publish

let insertElement = this.view.querySelector("[data-ica-action='insert']");
insertElement.addEventListener("click", insertOnClick);
insertElement.controller = this;

let editResponseElement = this.view.querySelector("[data-ica-action='edit-response']");
editResponseElement.addEventListener("click", editResponseOnClick);
editResponseElement.controller = this;
Expand Down Expand Up @@ -197,6 +201,7 @@ MapResponseController.defineMethod("uninitModel", function uninitModel() {
this.quill.enable(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='insert']").hidden = !this.lockingJointSource;
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);
this.view.querySelector("[data-ica-action='discard-edit-response']").hidden = !(this.lockingJointSource && this.response.responseId > 0);
Expand Down Expand Up @@ -287,6 +292,8 @@ MapResponseController.defineMethod("uninitModel", function uninitModel() {

this.view.querySelector("[data-ica-action='edit-response']").removeEventListener("click", editResponseOnClick);

this.view.querySelector("[data-ica-action='insert']").removeEventListener("click", insertOnClick);

this.view.querySelector("[data-ica-action='publish-response']").removeEventListener("click", publishResponseOnClick);

this.view.querySelector("[data-ica-action='unpublish-response']").removeEventListener("click", unpublishResponseOnClick);
Expand All @@ -309,6 +316,42 @@ MapResponseController.defineMethod("uninitModel", function uninitModel() {

}

function insertOnClick(event) {
event.preventDefault();

promptJointSourceSelection()
.then(function (jointSources) {
let quill = this.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.controller), function (err) {
console.warn(err);
});

}

function publishResponseOnClick(event) {
event.preventDefault();

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);
});
}
Loading