Skip to content

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
  • Loading branch information
Benjaneer authored Jun 19, 2023
1 parent 555964a commit ae2b472
Show file tree
Hide file tree
Showing 12 changed files with 346 additions and 30 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# An Addon for Storyteller
This addon for the StoryTeller module adds three single page journal styles, and adds a page style background to the editor.
Note: the Table of Contents is only loaded for the journal owner(s), also to prevent peaking the click to open is disabled on images for worn and ragged styles
Note: the Table of Contents is only loaded for the journal owner(s)

![image](https://github.com/Benjaneer/storyteller-addon-singlesheet/assets/9536408/6944f7e9-420b-4332-b915-03e712a72998)

Expand Down
8 changes: 0 additions & 8 deletions css/single-sheet-clean.css
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,3 @@
-webkit-mask-repeat: no-repeat;
-webkit-mask-position: center;
}

.single-sheet.clean .journal-entry-page.image figure img {
-webkit-mask-image: none;
}

.single-sheet.worn .journal-entry-page.image figure img {
pointer-events: none;
}
8 changes: 0 additions & 8 deletions css/single-sheet-ragged.css
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,3 @@
-webkit-mask-repeat: no-repeat;
-webkit-mask-position: center;
}

.single-sheet.ragged .journal-entry-page.image figure img {
-webkit-mask-image: none;
}

.single-sheet.ragged .journal-entry-page.image figure img {
pointer-events: none;
}
8 changes: 0 additions & 8 deletions css/single-sheet-worn.css
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,3 @@
-webkit-mask-repeat: no-repeat;
-webkit-mask-position: center;
}

.single-sheet.worn .journal-entry-page.image figure img {
-webkit-mask-image: none;
}

.single-sheet.worn .journal-entry-page.image figure img {
pointer-events: none;
}
11 changes: 11 additions & 0 deletions css/storyteller-addon-disableimageopen.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.single-sheet.clean .journal-entry-page.image.dontopen figure img {
pointer-events: none;
}

.single-sheet.worn .journal-entry-page.image.dontopen figure img {
pointer-events: none;
}

.single-sheet.ragged .journal-entry-page.image.dontopen figure img {
pointer-events: none;
}
2 changes: 2 additions & 0 deletions css/storyteller-addon-singlesheet.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
@import "editor.css";
@import "storyteller-addon-toc.css";
@import "storyteller-addon-scrollbar.css";
@import "storyteller-addon-disableimageopen.css";
@import "single-sheet-clean.css";
@import "single-sheet-worn.css";
@import "single-sheet-ragged.css";
Expand Down Expand Up @@ -120,4 +121,5 @@ nav.storyteller-nav.tabs {
max-height: 100%;
object-fit: contain;
position: center;
-webkit-mask-image: none;
}
7 changes: 6 additions & 1 deletion lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,10 @@

"STORYTELLER_ADDON_SINGLE.SingleSheet": "Single sheet (clean)",
"STORYTELLER_ADDON_SINGLE.SingleSheetWorn": "Single sheet (worn)",
"STORYTELLER_ADDON_SINGLE.SingleSheetRagged": "Single sheet (ragged)"
"STORYTELLER_ADDON_SINGLE.SingleSheetRagged": "Single sheet (ragged)",

"STORYTELLER_ADDON_SINGLE.Settings.DontOpenImages": "Don't open images on click",
"STORYTELLER_ADDON_SINGLE.Settings.DontOpenImagesHint": "Check to prevent single sheet images from opening on user click. Default: true",
"STORYTELLER_ADDON_SINGLE.Settings.ImageBackground": "Image Background",
"STORYTELLER_ADDON_SINGLE.Settings.ImageBackgroundHint": "Should image pages in singlesheets have a page background (uncheck to remove page background). Note that other pages in the stack (pages of the same journal entry) may be seen behind if the image is not the only page of the journal."
}
43 changes: 42 additions & 1 deletion main.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
import {SingleSheet} from "./sheets/single-sheet.js";
import {SingleSheet} from "./sheets/single-sheet-clean.js";
import {SingleSheetWorn} from "./sheets/single-sheet-worn.js";
import {SingleSheetRagged} from "./sheets/single-sheet-ragged.js";

Hooks.on("init", () => {
registerSettings()
// game.StoryTeller = new StoryTeller()
// game.StoryTeller.init()

// console.log("Storyteller | Init");

// if (game.settings.get('storyteller-addon-singlesheet', 'dontOpen')) {
// disableImageOpen() //storyteller-addon-disableimageopen.css
// }
});

Hooks.on("ready", () => {
/* Use this method at hook "ready" to register your journal style. */
game.StoryTeller.registerAddonSheet({
Expand Down Expand Up @@ -33,6 +45,27 @@ Hooks.on("ready", () => {
console.log("Storyteller addon singlesheet | Ready")
});

function registerSettings() {
//https://foundryvtt.com/api/v10/classes/client.ClientSettings.html#register
game.settings.register('storyteller-addon-singlesheet', 'background', {
name: game.i18n.localize('STORYTELLER_ADDON_SINGLE.Settings.ImageBackground'),
hint: game.i18n.localize('STORYTELLER_ADDON_SINGLE.Settings.ImageBackgroundHint'),
scope: "world",
type: Boolean,
default: true,
config: true
});

game.settings.register('storyteller-addon-singlesheet', 'dontOpen', {
name: game.i18n.localize('STORYTELLER_ADDON_SINGLE.Settings.DontOpenImages'),
hint: game.i18n.localize('STORYTELLER_ADDON_SINGLE.Settings.DontOpenImagesHint'),
scope: "world",
type: Boolean,
default: true,
config: true
});
}

Handlebars.registerHelper("offset", function(value)
{
return parseInt(value) + 1;
Expand All @@ -41,3 +74,11 @@ Handlebars.registerHelper("offset", function(value)
Handlebars.registerHelper('getIdByIndex', function(array, index) {
return array[index].id;
});

Handlebars.registerHelper('getDontOpen', function() {
let addClass = "";
if (game.settings.get('storyteller-addon-singlesheet', 'dontOpen')) {
addClass = "dontopen";
}
return addClass;
});
211 changes: 211 additions & 0 deletions sheets/single-sheet-clean.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
const bookSizeCorrection = 1
const bookWidth = 695
const bookHeight = 937

/* I recommend inheriting from the StorySheet class, but if you know what you're doing, you can use anything. */
export class SingleSheet extends JournalSheet {
pageFlip = "modules/storyteller/sounds/paper-flip.mp3"

static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
baseApplication: 'JournalSheet',
/* One of the most important lines, here you can add classes that will apply to the entire Journal window. */
classes: ["sheet", "single-sheet", "clean", "storyteller-addon-singlesheet"],
/* This file contains the html markup code, in case you need a more complex design style. For example, without page turning. */
template: 'modules/storyteller-addon-singlesheet/templates/single-sheet.html',
width: getBookWidth(),
height: getBookHeight(),
resizable: false,
closeOnSubmit: false,
submitOnClose: true,
});
}

sound() {
if (game.settings.get('storyteller', 'bookOpenSound')) {
AudioHelper.play({src: this.pageFlip, volume: 0.8, autoplay: true, loop: false}, false);
}
}

/** @inheritdoc */
async _render(force, options = {}) {
this.sound()
await super._render(force, options);

let data = this.getData().data
let startPage = 1
let savedPage = getPage(data._id)

$('#story-' + data._id).turn({
duration: 500,
page: savedPage >= 1 ? savedPage : startPage,
acceleration: true,
display: 'single',
// autoCenter: true,
turnCorners: "bl,br",
elevation: 300,
when: {
turned: function (e, page) {
setPage(data._id, page)
}
}
});

if (options.pageId != undefined) {
this.goToPage(options.pageId);
};
}

styleImage(storyId) {
let images = document.querySelectorAll('.single-sheet .page-num .journal-entry-page.image');
if(images.length > 0) {
images.forEach((image) => {
let pageClass=image.parentElement.className;
let pageQuery = storyId + ' .' + pageClass.replaceAll(' ','.');
$(pageQuery).css("overflow", "hidden");
if(!game.settings.get('storyteller-addon-singlesheet', 'background')) {
$(pageQuery).css("background-image", "none");
$(pageQuery + ' .journal-entry-page').css("-webkit-mask-image", "url(./modules/storyteller-addon-singlesheet/img/clean_mask.webp)");
};
});
};
}

/**
* Update child views inside the main sheet.
* @returns {Promise<void>}
* @protected
*/
async _renderPageViews() {
for ( const pageNode of this.element[0].querySelectorAll(".journal-entry-page") ) {
const id = pageNode.dataset.pageId;
if ( !id ) continue;
const edit = pageNode.querySelector(":scope > .edit-container");
const sheet = this.getPageSheet(id);
const data = await sheet.getData();
const view = await sheet._renderInner(data);
pageNode.replaceChildren(...view.get());
if ( edit ) pageNode.appendChild(edit);
sheet._activateCoreListeners(view.parent());
sheet.activateListeners(view);
await this._renderHeadings(pageNode, sheet.toc);
for ( const cls of sheet.constructor._getInheritanceChain() ) {
Hooks.callAll(`render${cls.name}`, sheet, view, data);
}
}

this.styleImage('#' + this.element[0].querySelectorAll(".scrollable.pages")[0].id);
}

/** @inheritdoc */
async _updateObject(event, formData) {
if (formData.img === "") {
formData.img = this.object.data.img
}
return super._updateObject(event, formData);
}

/** @inheritdoc */
_getHeaderButtons() {
const buttons = super._getHeaderButtons();

if (game.user.isGM) {
buttons.unshift({
label: "STORYTELLER.CopyID",
class: "switch-copyid",
icon: "fas fa-crosshairs",
onclick: ev => this._onCopyID(ev)
})
}

return buttons;
}

async _onShowPlayers(event) {
event.preventDefault();
await this.submit();
return this.object.show(this._sheetMode, true);
}

_onConfigureStory(event) {
let story = $(event.target).closest(".window-app.story-sheet")
let pageRightImage = story.find('.page-inner.image')
let pageRightSettings = story.find('.page-inner.settings')
pageRightImage.toggleClass("hidden")
pageRightSettings.toggleClass("hidden")
}

_onCopyID(event) {
const text = `game.StoryTeller.showStoryByIDToAll("` + this.object.id + `")`
let aux = document.createElement("input");
aux.setAttribute("value", text);
document.body.appendChild(aux);
aux.select();
document.execCommand("copy");
document.body.removeChild(aux);

ui.notifications.info(game.i18n.format("STORYTELLER.CopyIDMessage", {
mode: "text",
title: "Info",
which: "authorized"
}));
}

/** Меняем анимацию скрытия книги */
/** @inheritdoc */
async close(options = {}) {
let el = this.element;
super.close(options)
return new Promise(resolve => {
el.fadeOut(200, () => {
el.remove();

// Clean up data
this._element = null;
delete ui.windows[this.appId];
this._minimized = false;
this._scrollPositions = null;
this._state = Application.RENDER_STATES.CLOSED;
resolve();
});
});
}

goToPage(pageId) {
let targetPage = document.querySelector('.pagelookup li[data-page-id="' + pageId + '"]');
let targetPageNum = Number(targetPage.getAttribute("page"));
let pageList = targetPage.closest(".journal-entry-pages").children[1];
let journalId = pageList.getAttribute("id").split('-')[1];
let curentPageNum = $('#story-' + journalId).turn("page");
$('#story-' + journalId).turn("page", targetPageNum+1);
}
}

function sleep(milliseconds) {
const date = Date.now();
let currentDate = null;
do {
currentDate = Date.now();
} while (currentDate - date < milliseconds);
}

function getBookWidth() {
let height = getBookHeight()
return (bookWidth / bookHeight) * height
}

function getBookHeight() {
let bookSize = game.settings.get('storyteller', 'size') / 100
return window.innerHeight * bookSize * bookSizeCorrection
}

async function setPage(id, page) {
let pages = game.settings.get('storyteller', 'pages')
pages[id] = page
await game.settings.set('storyteller', 'pages', pages)
}

function getPage(id) {
let pages = game.settings.get('storyteller', 'pages')
return pages[id]
}
Loading

0 comments on commit ae2b472

Please sign in to comment.