first commit
This commit is contained in:
11
Resources/Private/.htaccess
Normal file
11
Resources/Private/.htaccess
Normal 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>
|
30
Resources/Private/Language/locallang.xlf
Normal file
30
Resources/Private/Language/locallang.xlf
Normal 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>
|
23
Resources/Private/Layouts/Default.html
Normal file
23
Resources/Private/Layouts/Default.html
Normal 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" />
|
15
Resources/Private/Partials/ListItem.html
Normal file
15
Resources/Private/Partials/ListItem.html
Normal 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);">×</a>
|
||||
</li>
|
||||
|
||||
</html>
|
34
Resources/Private/Templates/Bookmarks/Index.html
Normal file
34
Resources/Private/Templates/Bookmarks/Index.html
Normal 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>
|
162
Resources/Public/Scripts/JavaScript/bookmark_pages.js
Normal file
162
Resources/Public/Scripts/JavaScript/bookmark_pages.js
Normal 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);
|
Reference in New Issue
Block a user