first commit

This commit is contained in:
Sven Wappler
2021-08-16 16:15:21 +02:00
commit fde2759722
32 changed files with 1841 additions and 0 deletions

View File

@@ -0,0 +1,11 @@
# Apache < 2.3
<IfModule !mod_authz_core.c>
Order allow,deny
Deny from all
Satisfy All
</IfModule>
# Apache >= 2.3
<IfModule mod_authz_core.c>
Require all denied
</IfModule>

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<xliff version="1.0">
<file source-language="en" datatype="plaintext" original="messages" date="2021-04-21T09:11:39Z"
product-name="ws_bookmark_pages">
<header/>
<body>
<trans-unit id="yes">
<source>Yes</source>
</trans-unit>
<trans-unit id="default">
<source>Default</source>
</trans-unit>
<trans-unit id="alternative">
<source>Alternative</source>
</trans-unit>
<trans-unit id="bookmarkThisPage">
<source>Bookmark this page</source>
</trans-unit>
<trans-unit id="ff.isComplementary">
<source>Is complementary</source>
</trans-unit>
<trans-unit id="ff.isComplementary.description">
<source>In case the plugin is rendered more times on a page this option should be set for all instances except the first one.</source>
</trans-unit>
<trans-unit id="ff.listType">
<source>List type</source>
</trans-unit>
</body>
</file>
</xliff>

View File

@@ -0,0 +1,23 @@
<f:if condition="{settings.isComplementary as integer} === 1">
<f:then>
<div class="bookmark-pages">
<f:render section="main" />
</div>
</f:then>
<f:else>
<div class="bookmark-pages"
data-settings='{settings -> f:format.json()}'
data-bookmark='{bookmark -> f:format.json()}'
data-add-ajaxuri="{t:uri.ajaxAction(action: 'bookmark')}"
data-remove-ajaxuri="{t:uri.ajaxAction(action: 'delete')}"
data-update-ajaxuri="{t:uri.ajaxAction(action: 'listEntries')}"
id="bookmarks">
<f:render section="main" />
<template id="bookmark-template">
<f:render partial="ListItem" arguments="{bookmark: bookmark}" />
</template>
</div>
</f:else>
</f:if>
<f:asset.script identifier="bookmarkPages" src="EXT:ws_bookmark_pages/Resources/Public/Scripts/JavaScript/ws_bookmark_pages.js" />

View File

@@ -0,0 +1,15 @@
<html data-namespace-typo3-fluid="true"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://xsd.helmut-hummel.de/ns/TYPO3/CMS/Fluid/ViewHelpers"
xmlns:t="http://typo3.org/ns/Helhum/TyposcriptRendering/ViewHelpers">
<li>
<f:comment>
For the content to be substituted correctly the text link needs to have the class `bookmark-link`
and the remove item the data attribute `data-remove` assigned to.
</f:comment>
<f:link.external class="bookmark-link" title="{bookmark.title}" uri="{bookmark.url}">{bookmark.title}</f:link.external>
<a class="action-button bookmark-ajax-submit" data-remove="{bookmark.id}" href="javascript:void(0);">&times;</a>
</li>
</html>

View File

@@ -0,0 +1,34 @@
<html data-namespace-typo3-fluid="true"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://xsd.helmut-hummel.de/ns/TYPO3/CMS/Fluid/ViewHelpers"
xmlns:t="http://typo3.org/ns/Helhum/TyposcriptRendering/ViewHelpers">
<f:layout name="Default"/>
<f:section name="main">
<f:if condition="{settings.listType} === 'alternative'">
<f:then>
<f:comment>Render alternative list</f:comment>
<f:render section="BookmarkList" />
</f:then>
<f:else>
<f:comment>Render default list</f:comment>
<f:render section="BookmarkList" />
<f:comment>you may put this into your page template:</f:comment>
<div class="bookmark-pages">
<p><a class="bookmark-ajax-submit bookmark-this-page" href="javascript:void(0);">Bookmark page in templates</a></p>
<p><a class="bookmark-ajax-submit remove-this-page" href="javascript:void(0);">Remove page from bookmark</a></p>
</div>
</f:else>
</f:if>
</f:section>
<f:section name="BookmarkList">
<h4>Bookmarks</h4>
<p><a class="bookmark-ajax-submit bookmark-this-page" href="javascript:void(0);" title="{f:translate(key: 'bookmarkThisPage')}">{f:translate(key: 'bookmarkThisPage')}</a></p>
<ul class="menu vertical bookmarks-list">
<f:comment>List is loaded asynchronously</f:comment>
</ul>
</f:section>
</html>

View File

@@ -0,0 +1,162 @@
(function ($) {
const settings = {
_$bookmarks: null,
_$listItemTemplate: null,
// If set bookmarks are stored locally in localStorage
_storeLocal: false,
// Time in seconds during which the bookmarks are valid hence not queried from server
_localStorageTTL: 3600,
init () {
this._$bookmarks = $('#bookmarks');
this._$listItemTemplate = $($('#bookmark-template').html().trim());
// Assign settings defined by host
let pluginSettings = this._$bookmarks.data('settings');
if (typeof pluginSettings !== 'object') {
return;
}
if (pluginSettings.storeLocal !== 'undefined') {
this._storeLocal = Boolean(parseInt(pluginSettings.storeLocal));
}
if (pluginSettings.localStorageTTL !== 'undefined') {
this._localStorageTTL = parseInt(pluginSettings.localStorageTTL);
}
},
get updateAjaxUri () { return this._$bookmarks.data('update-ajaxuri'); },
get addAjaxUri () { return this._$bookmarks.data('add-ajaxuri') },
get removeAjaxUri () { return this._$bookmarks.data('remove-ajaxuri') },
get currentBookmark () { return this._$bookmarks.data('bookmark') },
get $listItemTemplate () { return this._$listItemTemplate },
get storeLocal() { return this._storeLocal; },
get localStorageTTL() { return this._localStorageTTL }
}
const storage = {
/**
* @return JSON object from bookmarks list held in local storage from browser
*/
get list() {
return JSON.parse(localStorage.getItem('txBookmarkPagesBookmarks')) ?? {};
},
/**
* @param bookmarks Array from bookmarks
*/
set list(bookmarks) {
if (settings.storeLocal) {
localStorage.setItem('txBookmarkPagesBookmarks', JSON.stringify(bookmarks));
localStorage.setItem('txBookmarkPagesTimestamp', Date.now());
localStorage.setItem('txBookmarkPagesReload', '0');
}
},
/**
* @return {boolean}
*/
get isOutdated() {
// Check storage age
let $expired = true;
let timestamp = localStorage.getItem('txBookmarkPagesTimestamp');
if (timestamp) {
$expired = ((Date.now() - timestamp) / 1000) > settings.localStorageTTL;
}
// Check if a reload is requested
let $reloadRequested = Boolean(parseInt(localStorage.getItem('txBookmarkPagesReload')));
return $expired || $reloadRequested;
},
containsBookmark (bookmark) {
return typeof this.list[bookmark.id] === 'object';
}
}
const assistant = {
updateLinks () {
if (storage.containsBookmark(settings.currentBookmark)) {
$('.bookmark-this-page').addClass('is-bookmarked');
} else {
$('.bookmark-this-page').removeClass('is-bookmarked');
}
},
/**
* Ajax callback function to update the bookmarks list and the links to bookmark a page.
*
* @param ajaxResult Object with properties `list` and `isBookmarked`
*/
listQueryHandler (ajaxResult) {
this.initList(ajaxResult.bookmarks);
storage.list = ajaxResult.bookmarks;
this.updateLinks();
},
ajax (url, data = {}) {
data = {...data, 'tx_wsbookmarkpages_bookmarks[localBookmarks]': storage.list}
$.ajax({
url: url,
type: 'post',
data: data
}).done($.proxy(this.listQueryHandler, this));
},
initList (bookmarks) {
let $bookmarksList = $('.bookmarks-list');
$bookmarksList.empty();
Object.values(bookmarks).forEach(bookmark => {
let $item = settings.$listItemTemplate.clone();
$('.bookmark-link', $item)
.attr('title', bookmark.title)
.attr('href', bookmark.url)
.text(bookmark.title);
$('.bookmark-ajax-submit', $item).data('remove', bookmark.id)
$bookmarksList.append($item);
});
},
initListFromStorage () {
let bookmarks = storage.list;
this.initList(bookmarks);
}
}
const bookmarks = {
init () {
if (settings.storeLocal && !storage.isOutdated) {
assistant.initListFromStorage();
assistant.updateLinks();
} else {
assistant.ajax(settings.updateAjaxUri);
}
},
add () {
assistant.ajax(settings.addAjaxUri);
},
remove (removeID) {
assistant.ajax(
settings.removeAjaxUri,
{'tx_wsbookmarkpages_bookmarks[id]': removeID ?? settings.currentBookmark.id}
);
}
}
/**
* Bind event handlers and initialize the app when DOM is ready
*/
$(function () {
// doing it this way:
// $('.bookmark-ajax-submit').on('click', function (event) {
// would not work for initially hidden elements
$('.bookmark-pages').on('click', '.bookmark-ajax-submit', function (event) {
event.preventDefault();
let $this = $(this),
removeID = $(this).data('remove');
if ($this.hasClass('bookmark-this-page')){
bookmarks.add();
} else if ($this.hasClass('remove-this-page')) {
bookmarks.remove()
} else if (removeID) {
bookmarks.remove(removeID)
}
});
// Initialize the app
settings.init();
bookmarks.init();
});
})(jQuery);