Skip to content

Commit

Permalink
Tidying up in support of adding hooks and secrets merge
Browse files Browse the repository at this point in the history
  • Loading branch information
aaclayton committed Dec 1, 2021
1 parent bc54041 commit 2ad30ad
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 62 deletions.
3 changes: 1 addition & 2 deletions lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@

"WA.ButtonImportAll": "Import All",
"WA.ButtonSyncAll": "Sync All",
"WA.ButtonSecretInfo": "This article has some secrets. You will need a complementary module if you want to toggle secrets",
"WA.ButtonVisibilityHide": "Hide from players",
"WA.ButtonVisibilityDisplay": "Display to players",
"WA.ButtonToggleDraft": "Display Drafts",
Expand All @@ -37,4 +36,4 @@

"WA.Header.GeneralDetails": "General Details",
"WA.Header.Seeded": "Secrets"
}
}
123 changes: 84 additions & 39 deletions module/framework.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,35 +107,85 @@ export async function importArticle(articleId, {notify=true, options={}}={}) {
// Format Article content
const content = getArticleContent(article);

// Update an existing Journal Entry
// Update an existing JournalEntry, or create a new one
let entry = game.journal.find(e => e.getFlag("world-anvil", "articleId") === articleId);
if ( entry ) {
if ( entry ) return _updateExistingEntry(entry, article, content, options);
return _createNewEntry(article, content, options)

Hooks.callAll(`WAUpdateJournalEntry`, entry, content);
}

await entry.update({
name: article.title,
content: content.html,
img: content.img,
"flags.world-anvil": content.waFlags
});
if ( notify ) ui.notifications.info(`Refreshed World Anvil article ${article.title}`);
return entry;
}
/* -------------------------------------------- */

// Determine the Folder which contains this article
const folder = await getCategoryFolder(article.category);
/**
* Update an existing JournalEntry document using the contents of an Article
* @param {JournalEntry} entry The JournalEntry to update
* @param {Article} article The original Article
* @param {ParsedArticleResult} content The parsed article content
* @param {DocumentModificationContext} options Entry update options
* @returns {Promise<JournalEntry>} The updated entry
* @private
*/
async function _updateExistingEntry(entry, article, content, options) {
/**
* A hook event that fires when the user is updating an existing JournalEntry from a WorldAnvil article.
* @function WAUpdateJournalEntry
* @memberof hookEvents
* @param {JournalEntry} entry The JournalEntry document being updated
* @param {Article} article The original Article
* @param {ParsedArticleResult} content The parsed article content
*/
Hooks.callAll(`WAUpdateJournalEntry`, entry, content);

// Update the entry
await entry.update({
name: article.title,
content: content.html,
img: content.img,
"flags.world-anvil": content.waFlags
});

// Notify and return
if ( notify ) ui.notifications.info(`Refreshed World Anvil article ${article.title}`);
return entry;
}

/* -------------------------------------------- */

/**
* Create a new JournalEntry document using the contents of an Article
* @param {Article} article The original Article
* @param {ParsedArticleResult} content The parsed article content
* @returns {Promise<JournalEntry>} The created entry
* @param {DocumentModificationContext} options Entry creation options
* @returns {Promise<JournalEntry>} The created entry
* @private
*/
async function _createNewEntry(article, content, options) {

// Create a new Journal Entry
Hooks.callAll(`WACreateJournalEntry`, entry, content);
// Get or create the appropriate folder
const folder = await getCategoryFolder(article.category);

entry = await JournalEntry.create({
// Define the data to import
const entryData = {
name: article.title,
content: content.html,
img: content.img,
folder: folder.id,
"flags.world-anvil": content.waFlags
}, options);
}

/**
* A hook event that fires when the user is creating a new JournalEntry from a WorldAnvil article.
* @function WACreateJournalEntry
* @memberof hookEvents
* @param {JournalEntryData} entryData The JournalEntry data which will be created
* @param {Article} article The original Article
* @param {ParsedArticleResult} content The parsed article content
*/
Hooks.callAll(`WACreateJournalEntry`, entryData, article, content);

// Create the entry, notify, and return
const entry = await JournalEntry.create(entryData, options);
if ( notify ) ui.notifications.info(`Imported World Anvil article ${article.title}`);
return entry;
}
Expand Down Expand Up @@ -187,8 +237,10 @@ export function getArticleContent(article) {
for ( let [id, section] of filteredEntries ) {

// Each section data are stored inside a separated div
const isSecretSection = secretSectionIds.includes(id);
const cssClass = ARTICLE_CSS_CLASSES.ALL_PARTS + " " + ( isSecretSection ? ARTICLE_CSS_CLASSES.SECRET_SECTION : ARTICLE_CSS_CLASSES.PUBLIC_SECTION );
const cssClass = [
ARTICLE_CSS_CLASSES.ALL_PARTS,
secretSectionIds.includes(id) ? ARTICLE_CSS_CLASSES.SECRET_SECTION : ARTICLE_CSS_CLASSES.PUBLIC_SECTION
].join(" ");
sections += `<section data-section-id="${id}" class="${cssClass}">`;

// Title can be replaced by a localized name if the section id has been handled
Expand All @@ -212,22 +264,16 @@ export function getArticleContent(article) {
}
}

// Article relations
// Add all article relations into an aside section
let aside = "";
if ( article.relations ) {

for ( let [id, section] of Object.entries(article.relations) ) {

if( !section.items ) { continue; } // Some relations, like timelines, have no .items attribute. => Skipped
if( fromHooks.handledRelations.includes(id) ) { continue; }

const title = section.title || id.titleCase();
const items = section.items instanceof Array ? section.items: [section.items]; // Items can be one or many
const relations = items.map(i => `<span data-article-id="${i.id}" data-template="${i.type}">${i.title}</span>`);

aside += `<dt>${title}:</dt><dd>${relations.join(", ")}</dd>`
}

if( aside ) { aside = `<aside><dl>${aside}</dl></aside>`; }
}

Expand Down Expand Up @@ -291,31 +337,30 @@ export function getArticleContent(article) {
img: image,
waFlags: waFlags
}
/**
* A hook event that fires when a WorldAnvil article is parsed
* @function WACreateJournalEntry
* @memberof hookEvents
* @param {Article} article The original Article
* @param {ParsedArticleResult} parsedData The parsed article content
*/
Hooks.callAll(`WAParseArticle`, article, parsedData);

return parsedData;
}

/* -------------------------------------------- */

/**
* For some sectionId, the title will be retrieved from the module translations
* For some sectionId, the title will be retrieved from the module translations.
* Except for generalDetailsIds, which will all have 'WA.Header.GeneralDetails' for translation.
* @param {string} sectionId The id as retrieved via Object.entries
* @param {string} section The section content
* @returns The actual title
*/
function _getLocalizedTitle( sectionId, section ) {

// For each sectionId, we try to retrieve a matching translation.
// Except for generalDetailsIds, which will all have 'WA.Header.GeneralDetails' for translation
const generalDetailsIds = ['sidebarcontent', 'sidepanelcontenttop', 'sidepanelcontent', 'sidebarcontentbottom'];
const key = generalDetailsIds.includes(sectionId) ? "WA.Header.GeneralDetails" : "WA.Header." + sectionId.titleCase();

const localized = game.i18n.localize(key);
if( localized != key ) { // Meaning the translation was found
return localized;
}
return section.title || sectionId.titleCase();
const key = `WA.Header.${generalDetailsIds.includes(sectionId) ? "GeneralDetails" : sectionId.titleCase()}`;
return game.i18n.has(key) ? game.i18n.localize(key) : section.title || sectionId.titleCase();
}

/* -------------------------------------------- */
Expand Down
3 changes: 0 additions & 3 deletions module/journal.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,6 @@ export default class WorldAnvilBrowser extends Application {
// Check linked entry permissions
article.entry = entries.find(e => e.getFlag("world-anvil", "articleId") === article.id);
article.visibleByPlayers = article.entry?.data.permission.default >= CONST.ENTITY_PERMISSIONS.OBSERVER;

// For secrets
article.hasSecrets = article.entry?.getFlag("world-anvil", "hasSecrets") ?? false;

// Get the category to which the article belongs
const category = categories.get(article.category?.id) || uncategorized;
Expand Down
7 changes: 0 additions & 7 deletions templates/journal.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,6 @@
<h3 class="article-title">{{ this.title }}</h3>
<div class="controls">
{{#if this.entry }}

{{#if this.hasSecrets }}
<button type="button" class="world-anvil-control has-secret inactive" title="{{localize 'WA.ButtonSecretInfo'}}">
<i class="fas fa-lock"></i>
</button>
{{/if}}

{{#if this.visibleByPlayers }}
<button type="button" class="world-anvil-control" data-action="hide-entry" data-entry-id="{{ this.entry.id }}" title="{{ localize 'WA.ButtonVisibilityHide' }}">
<i class="far fa-eye"></i>
Expand Down
29 changes: 18 additions & 11 deletions wa.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,33 @@ import WorldAnvilConfig from "./module/config.js";
import WorldAnvilBrowser from "./module/journal.js";
import * as api from "./module/framework.js";

let module = undefined;

/**
* Initialization actions taken on Foundry Virtual Tabletop client init.
*/
Hooks.once("init", () => {
module = game.modules.get("world-anvil");

// Register settings menu
WorldAnvilConfig.registerSettings();

// Register the World Anvil module
const module = game.modules.get("world-anvil");
/**
* A singleton instance of the WorldAnvil client
* @type {WorldAnvil}
*/
module.anvil = new WorldAnvil();

// Register Applications
/**
* A singleton instance of the WorldAnvilBrowser UI for importing content
* @type {WorldAnvilBrowser}
*/
module.browser = new WorldAnvilBrowser();

/**
* A singleton instance of the WorldAnvilConfig UI for configuring account integration
* @type {WorldAnvilConfig}
*/
module.config = new WorldAnvilConfig();

// Register some helper functions
Expand All @@ -33,10 +45,7 @@ Hooks.once("init", () => {
*/
Hooks.once("ready", () => {
if ( !game.user.isGM ) return;

// Connect to World Anvil
const anvil = game.modules.get("world-anvil").anvil;
anvil.connect();
return module.anvil.connect();
});


Expand All @@ -49,8 +58,6 @@ Hooks.once("ready", () => {
Hooks.on("renderJournalDirectory", (app, html, data) => {
if ( !game.user.isGM ) return;

const module = game.modules.get("world-anvil");

// Add the World Anvil Button
const button = $(`<button type="button" id="world-anvil">
<img src="modules/world-anvil/icons/wa-icon.svg" title="${game.i18n.localize("WA.SidebarButton")}"/>
Expand Down Expand Up @@ -92,7 +99,7 @@ Hooks.on("renderJournalSheet", (app, html, data) => {
const sync = $(`<a class="wa-sync"><i class="fas fa-sync"></i>${game.i18n.localize("WA.Sync")}</a>`);
sync.on("click", event => {
event.preventDefault();
api.importArticle(articleId);
return api.importArticle(articleId);
});
title.after(sync);
}
Expand Down Expand Up @@ -128,4 +135,4 @@ Hooks.on("renderJournalSheet", (app, html, data) => {
}
return api.importArticle(articleId, {renderSheet: true});
});
});
});

0 comments on commit 2ad30ad

Please sign in to comment.