mirror of https://github.com/nextcloud/bookmarks
enh(references): Implement a reference provider and a front-end widget for bookmarks
Signed-off-by: Marcel Klehr <mklehr@gmx.net>
This commit is contained in:
parent
4fc23b3f6d
commit
41c030ddf1
|
@ -23,6 +23,7 @@ use OCA\Bookmarks\Flow\CreateBookmark;
|
|||
use OCA\Bookmarks\Hooks\BeforeTemplateRenderedListener;
|
||||
use OCA\Bookmarks\Hooks\UserGroupListener;
|
||||
use OCA\Bookmarks\Middleware\ExceptionMiddleware;
|
||||
use OCA\Bookmarks\Reference\BookmarkReferenceProvider;
|
||||
use OCA\Bookmarks\Search\Provider;
|
||||
use OCA\Bookmarks\Service\TreeCacheManager;
|
||||
use OCP\AppFramework\App;
|
||||
|
@ -30,6 +31,7 @@ use OCP\AppFramework\Bootstrap\IBootContext;
|
|||
use OCP\AppFramework\Bootstrap\IBootstrap;
|
||||
use OCP\AppFramework\Bootstrap\IRegistrationContext;
|
||||
use OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent;
|
||||
use OCP\Collaboration\Reference\RenderReferenceEvent;
|
||||
use OCP\Collaboration\Resources\IProviderManager;
|
||||
use OCP\EventDispatcher\IEventDispatcher;
|
||||
use OCP\Group\Events\UserAddedEvent;
|
||||
|
@ -45,6 +47,14 @@ class Application extends App implements IBootstrap {
|
|||
|
||||
public function __construct() {
|
||||
parent::__construct(self::APP_ID);
|
||||
|
||||
// TODO move this back to ::register after fixing the autoload issue
|
||||
// (and use a listener class)
|
||||
$container = $this->getContainer();
|
||||
$eventDispatcher = $container->get(IEventDispatcher::class);
|
||||
$eventDispatcher->addListener(RenderReferenceEvent::class, function () {
|
||||
Util::addScript(self::APP_ID, self::APP_ID . '-references');
|
||||
});
|
||||
}
|
||||
|
||||
public function register(IRegistrationContext $context): void {
|
||||
|
@ -64,6 +74,8 @@ class Application extends App implements IBootstrap {
|
|||
$context->registerDashboardWidget(Recent::class);
|
||||
$context->registerDashboardWidget(Frequent::class);
|
||||
|
||||
$context->registerReferenceProvider(BookmarkReferenceProvider::class);
|
||||
|
||||
$context->registerEventListener(CreateEvent::class, TreeCacheManager::class);
|
||||
$context->registerEventListener(UpdateEvent::class, TreeCacheManager::class);
|
||||
$context->registerEventListener(BeforeDeleteEvent::class, TreeCacheManager::class);
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
<?php
|
||||
/*
|
||||
* @copyright Copyright (c) 2022 Julien Veyssier <eneiluj@posteo.net>
|
||||
*
|
||||
* @author Julien Veyssier <eneiluj@posteo.net>
|
||||
* @author The Nextcloud Bookmarks contributors
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or later. See the COPYING file.
|
||||
*/
|
||||
|
||||
namespace OCA\Bookmarks\Reference;
|
||||
|
||||
use OCA\Bookmarks\AppInfo\Application;
|
||||
use OCA\Bookmarks\Exception\UrlParseError;
|
||||
use OCA\Bookmarks\Service\Authorizer;
|
||||
use OCA\Bookmarks\Service\BookmarkService;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use OCP\Collaboration\Reference\ADiscoverableReferenceProvider;
|
||||
use OCP\Collaboration\Reference\IReference;
|
||||
use OCP\Collaboration\Reference\ISearchableReferenceProvider;
|
||||
use OCP\Collaboration\Reference\Reference;
|
||||
use OCP\IL10N;
|
||||
use OCP\IURLGenerator;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class BookmarkReferenceProvider extends ADiscoverableReferenceProvider implements ISearchableReferenceProvider {
|
||||
private ?string $userId;
|
||||
private IL10N $l10n;
|
||||
private IURLGenerator $urlGenerator;
|
||||
private BookmarkService $bookmarkService;
|
||||
private Authorizer $authorizer;
|
||||
|
||||
public function __construct(IL10N $l10n, ?string $userId, IURLGenerator $urlGenerator, BookmarkService $bookmarkService, Authorizer $authorizer) {
|
||||
$this->userId = $userId;
|
||||
$this->l10n = $l10n;
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
$this->bookmarkService = $bookmarkService;
|
||||
$this->authorizer = $authorizer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getId(): string {
|
||||
return Application::APP_ID . '-ref-bookmarks';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getTitle(): string {
|
||||
return $this->l10n->t('Bookmarks');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getOrder(): int {
|
||||
return 10;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getIconUrl(): string {
|
||||
return $this->urlGenerator->getAbsoluteURL(
|
||||
$this->urlGenerator->imagePath(Application::APP_ID, 'bookmarks-black.svg')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getSupportedSearchProviderIds(): array {
|
||||
return [
|
||||
'bookmarks',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function matchReference(string $referenceText): bool {
|
||||
\OC::$server->get(LoggerInterface::class)->warning('MATCH REFERENCE');
|
||||
$start = $this->urlGenerator->getAbsoluteURL('/apps/' . Application::APP_ID);
|
||||
$startIndex = $this->urlGenerator->getAbsoluteURL('/index.php/apps/' . Application::APP_ID);
|
||||
|
||||
// link example: https://nextcloud.local/index.php/apps/deck/#/board/2/card/11
|
||||
$noIndexMatch = preg_match('/^' . preg_quote($start, '/') . '\/bookmarks\/[0-9]+$/', $referenceText) !== false;
|
||||
$indexMatch = preg_match('/^' . preg_quote($startIndex, '/') . '\/bookmarks\/[0-9]+$/', $referenceText) !== false;
|
||||
|
||||
if ($noIndexMatch || $indexMatch) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->bookmarkService->findByUrl($this->userId, $referenceText);
|
||||
return true;
|
||||
} catch (UrlParseError|DoesNotExistException $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function resolveReference(string $referenceText): ?IReference {
|
||||
if (!$this->matchReference($referenceText)) {
|
||||
return null;
|
||||
}
|
||||
$id = $this->getBookmarkId($referenceText);
|
||||
if ($id === null) {
|
||||
try {
|
||||
$bookmark = $this->bookmarkService->findByUrl($this->userId, $referenceText);
|
||||
} catch (UrlParseError|DoesNotExistException $e) {
|
||||
return null;
|
||||
}
|
||||
}else{
|
||||
$bookmark = $this->bookmarkService->findById((int)$id);
|
||||
}
|
||||
if ($bookmark === null) {
|
||||
return null;
|
||||
}
|
||||
if (!Authorizer::hasPermission(Authorizer::PERM_READ, $this->authorizer->getUserPermissionsForBookmark($this->userId, (int)$id))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @var IReference $reference */
|
||||
$reference = new Reference($referenceText);
|
||||
$reference->setRichObject(Application::APP_ID . '-bookmark', [
|
||||
'id' => $id,
|
||||
'bookmark' => $bookmark->toArray(),
|
||||
]);
|
||||
|
||||
return $reference;
|
||||
}
|
||||
|
||||
private function getBookmarkId(string $url): ?string {
|
||||
$start = $this->urlGenerator->getAbsoluteURL('/apps/' . Application::APP_ID);
|
||||
$startIndex = $this->urlGenerator->getAbsoluteURL('/index.php/apps/' . Application::APP_ID);
|
||||
|
||||
preg_match('/^' . preg_quote($start, '/') . '\/bookmarks\/([0-9]+)$/', $url, $matches);
|
||||
if ($matches && count($matches) > 1) {
|
||||
return $matches[1];
|
||||
}
|
||||
|
||||
preg_match('/^' . preg_quote($startIndex, '/') . '\/bookmarks\/([0-9]+)$/', $url, $matches2);
|
||||
if ($matches2 && count($matches2) > 1) {
|
||||
return $matches2[1];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getCachePrefix(string $referenceId): string {
|
||||
$id = $this->getBookmarkId($referenceId);
|
||||
return $id ?? $referenceId;
|
||||
}
|
||||
|
||||
public function getCacheKey(string $referenceId): ?string {
|
||||
return $this->userId ?? '';
|
||||
}
|
||||
}
|
|
@ -413,6 +413,18 @@ class BookmarkService {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @return Bookmark|null
|
||||
*/
|
||||
public function findById(int $id) : ?Bookmark {
|
||||
try {
|
||||
return $this->bookmarkMapper->find($id);
|
||||
} catch (DoesNotExistException|MultipleObjectsReturnedException $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $userId
|
||||
* @param string $url
|
||||
|
|
|
@ -14,9 +14,11 @@
|
|||
"@nextcloud/dialogs": "^3.2.0",
|
||||
"@nextcloud/event-bus": "^3.0.2",
|
||||
"@nextcloud/initial-state": "^2.0.0",
|
||||
"@nextcloud/l10n": "^2.1.0",
|
||||
"@nextcloud/router": "^2.0.0",
|
||||
"@nextcloud/vue": "^7.8.0",
|
||||
"@nextcloud/vue-dashboard": "^2.0.1",
|
||||
"@nextcloud/vue-richtext": "^2.1.0-beta.6",
|
||||
"async-parallel": "^1.2.3",
|
||||
"clone-deep": "^4.0.1",
|
||||
"humanize-duration": "^3.28.0",
|
||||
|
@ -2075,6 +2077,15 @@
|
|||
"npm": "^7.0.0 || ^8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@nextcloud/dialogs/node_modules/@nextcloud/l10n": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/l10n/-/l10n-1.6.0.tgz",
|
||||
"integrity": "sha512-aKGlgrwN9OiafN791sYus0shfwNeU3PlrH6Oi9ISma6iJSvN6a8aJM8WGKCJ9pqBaTR5PrDuckuM/WnybBWb6A==",
|
||||
"dependencies": {
|
||||
"core-js": "^3.6.4",
|
||||
"node-gettext": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@nextcloud/dialogs/node_modules/@nextcloud/typings": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/typings/-/typings-1.5.0.tgz",
|
||||
|
@ -2182,12 +2193,18 @@
|
|||
"integrity": "sha512-xmNP30v/RnkJ2z1HcuEo7YfcLJJa+FdWTwgNldXHOlMeMbl/ESpsGkWL2sULrhYurz64L0JpfwEdi/cHcmyuZQ=="
|
||||
},
|
||||
"node_modules/@nextcloud/l10n": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/l10n/-/l10n-1.6.0.tgz",
|
||||
"integrity": "sha512-aKGlgrwN9OiafN791sYus0shfwNeU3PlrH6Oi9ISma6iJSvN6a8aJM8WGKCJ9pqBaTR5PrDuckuM/WnybBWb6A==",
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/l10n/-/l10n-2.1.0.tgz",
|
||||
"integrity": "sha512-rToqXwxcsDTcijvSdgyJAKuOuW7XggDYH00/t3GN5HzO1lNNnVtOj7cc5WmiTknciM+En2oVSMFIUPs6HehjVQ==",
|
||||
"dependencies": {
|
||||
"core-js": "^3.6.4",
|
||||
"@nextcloud/router": "^2.0.0",
|
||||
"dompurify": "^2.4.1",
|
||||
"escape-html": "^1.0.3",
|
||||
"node-gettext": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.0.0",
|
||||
"npm": "^7.0.0 || ^8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@nextcloud/logger": {
|
||||
|
@ -2378,6 +2395,15 @@
|
|||
"semver": "^7.3.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@nextcloud/vue-dashboard/node_modules/@nextcloud/l10n": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/l10n/-/l10n-1.6.0.tgz",
|
||||
"integrity": "sha512-aKGlgrwN9OiafN791sYus0shfwNeU3PlrH6Oi9ISma6iJSvN6a8aJM8WGKCJ9pqBaTR5PrDuckuM/WnybBWb6A==",
|
||||
"dependencies": {
|
||||
"core-js": "^3.6.4",
|
||||
"node-gettext": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@nextcloud/vue-dashboard/node_modules/@nextcloud/router": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/router/-/router-1.2.0.tgz",
|
||||
|
@ -2540,6 +2566,28 @@
|
|||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
},
|
||||
"node_modules/@nextcloud/vue-richtext": {
|
||||
"version": "2.1.0-beta.6",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/vue-richtext/-/vue-richtext-2.1.0-beta.6.tgz",
|
||||
"integrity": "sha512-LIhBCpFEfimUCHlPuhRADwTDXwOf4SASaQLYowofwvFfqTBjYi/TZdQfP4UBPaVFP2aKssOxuZ3HT83Z77ROAw==",
|
||||
"dependencies": {
|
||||
"@nextcloud/axios": "^2.0.0",
|
||||
"@nextcloud/event-bus": "^3.0.2",
|
||||
"@nextcloud/initial-state": "^2.0.0",
|
||||
"@nextcloud/router": "^2.0.0",
|
||||
"@nextcloud/vue": "^7.5.0",
|
||||
"clone": "^2.1.2",
|
||||
"vue": "^2.7.8",
|
||||
"vue-material-design-icons": "^5.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0",
|
||||
"npm": ">=7.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "^2.7.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@nextcloud/vue-select": {
|
||||
"version": "3.22.2",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/vue-select/-/vue-select-3.22.2.tgz",
|
||||
|
@ -2585,21 +2633,6 @@
|
|||
"node-gettext": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@nextcloud/vue/node_modules/@nextcloud/l10n": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/l10n/-/l10n-2.0.1.tgz",
|
||||
"integrity": "sha512-vTzsYUdNNJhDmdQS5pOhv+tdqGhjzI+iWZMQgM19rcpFo9MDFrcK/bQBIgcQypJjqSmNlP62M9CMVTm4fIwlsA==",
|
||||
"dependencies": {
|
||||
"@nextcloud/router": "^2.0.0",
|
||||
"dompurify": "^2.4.1",
|
||||
"escape-html": "^1.0.3",
|
||||
"node-gettext": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.0.0",
|
||||
"npm": "^7.0.0 || ^8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@nextcloud/vue/node_modules/@nextcloud/typings": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/typings/-/typings-1.6.0.tgz",
|
||||
|
|
|
@ -26,9 +26,11 @@
|
|||
"@nextcloud/dialogs": "^3.2.0",
|
||||
"@nextcloud/event-bus": "^3.0.2",
|
||||
"@nextcloud/initial-state": "^2.0.0",
|
||||
"@nextcloud/l10n": "^2.1.0",
|
||||
"@nextcloud/router": "^2.0.0",
|
||||
"@nextcloud/vue": "^7.8.0",
|
||||
"@nextcloud/vue-dashboard": "^2.0.1",
|
||||
"@nextcloud/vue-richtext": "^2.1.0-beta.6",
|
||||
"async-parallel": "^1.2.3",
|
||||
"clone-deep": "^4.0.1",
|
||||
"humanize-duration": "^3.28.0",
|
||||
|
|
|
@ -0,0 +1,174 @@
|
|||
<!--
|
||||
- @author 2022 Julien Veyssier <julien-nc@posteo.net>
|
||||
- @author 2022 Marcel Klehr <mklehr@gmx.net>
|
||||
-
|
||||
- @license GNU AGPL version 3 or any later version
|
||||
-
|
||||
- This program is free software: you can redistribute it and/or modify
|
||||
- it under the terms of the GNU Affero General Public License as
|
||||
- published by the Free Software Foundation, either version 3 of the
|
||||
- License, or (at your option) any later version.
|
||||
-
|
||||
- This program is distributed in the hope that it will be useful,
|
||||
- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
- GNU Affero General Public License for more details.
|
||||
-
|
||||
- You should have received a copy of the GNU Affero General Public License
|
||||
- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div class="bookmarks-bookmark-reference">
|
||||
<div class="line">
|
||||
<a :href="bookmarkLink" target="_blank" class="link">
|
||||
<BookmarksIcon :size="14" class="title-icon" />
|
||||
<small>{{ addedDate }}</small>
|
||||
</a>
|
||||
</div>
|
||||
<div class="line title">
|
||||
<strong>
|
||||
<a :href="url"
|
||||
target="_blank"
|
||||
class="link">
|
||||
<figure class="icon" :style="{ backgroundImage: 'url(' + iconUrl + ')' }" />
|
||||
{{ bookmark.title }}
|
||||
</a>
|
||||
</strong>
|
||||
</div>
|
||||
<div class="line">
|
||||
<small>{{ content }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import BookmarksIcon from './icons/BookmarksIcon.vue'
|
||||
import { generateUrl } from '@nextcloud/router'
|
||||
import humanizeDuration from 'humanize-duration'
|
||||
|
||||
const MAX_RELATIVE_DATE = 1000 * 60 * 60 * 24 * 7 // one week
|
||||
|
||||
export default {
|
||||
name: 'BookmarkReferenceWidget',
|
||||
components: {
|
||||
BookmarksIcon,
|
||||
},
|
||||
props: {
|
||||
richObjectType: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
richObject: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
accessible: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
shortDescription: true,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
bookmark() {
|
||||
return this.richObject.bookmark
|
||||
},
|
||||
bookmarkLink() {
|
||||
return generateUrl('/apps/bookmarks/bookmarks/{bookmarkId}', { bookmarkId: this.bookmark.id })
|
||||
},
|
||||
apiUrl() {
|
||||
return generateUrl('/apps/bookmarks')
|
||||
},
|
||||
iconUrl() {
|
||||
return (
|
||||
this.apiUrl
|
||||
+ '/bookmark/'
|
||||
+ this.bookmark.id
|
||||
+ '/favicon'
|
||||
)
|
||||
},
|
||||
imageUrl() {
|
||||
return (
|
||||
this.apiUrl
|
||||
+ '/bookmark/'
|
||||
+ this.bookmark.id
|
||||
+ '/image'
|
||||
)
|
||||
},
|
||||
url() {
|
||||
return this.bookmark.url
|
||||
},
|
||||
addedDate() {
|
||||
const date = new Date(Number(this.bookmark.added) * 1000)
|
||||
const age = Date.now() - date
|
||||
if (age < MAX_RELATIVE_DATE) {
|
||||
const duration = humanizeDuration(age, {
|
||||
language: OC.getLanguage().split('-')[0],
|
||||
units: ['d', 'h', 'm', 's'],
|
||||
largest: 1,
|
||||
round: true,
|
||||
})
|
||||
return this.t('bookmarks', 'Bookmarked {time} ago', { time: duration })
|
||||
} else {
|
||||
return this.t('bookmarks', 'Bookmarked on {date}', { date: date.toLocaleDateString() })
|
||||
}
|
||||
},
|
||||
content() {
|
||||
const length = 250
|
||||
return this.bookmark?.textContent?.trim()?.slice(0, length) || this.bookmark.description?.trim()?.slice(0, length)
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.bookmarks-bookmark-reference {
|
||||
width: 100%;
|
||||
white-space: normal;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.bookmarks-bookmark-reference .editor__content {
|
||||
width: calc(100% - 24px);
|
||||
}
|
||||
|
||||
.bookmarks-bookmark-reference .link {
|
||||
text-decoration: underline;
|
||||
color: var(--color-main-text) !important;
|
||||
padding: 0 !important;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.bookmarks-bookmark-reference .line {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.bookmarks-bookmark-reference .title {
|
||||
font-size: 2em;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 5px;
|
||||
height: 31px;
|
||||
overflow-y: hidden;
|
||||
line-height: 1;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.bookmarks-bookmark-reference .spacer {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.bookmarks-bookmark-reference .icon {
|
||||
display: inline-block;
|
||||
height: 25px;
|
||||
width: 25px;
|
||||
background-size: cover;
|
||||
margin-right: 5px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,46 @@
|
|||
<template>
|
||||
<span :aria-hidden="!title"
|
||||
:aria-label="title"
|
||||
class="material-design-icon bookmarks-icon"
|
||||
role="img"
|
||||
v-bind="$attrs"
|
||||
@click="$emit('click', $event)">
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
:fill="fillColor"
|
||||
:height="size"
|
||||
:width="size"
|
||||
viewBox="0 0 32 32">
|
||||
<g transform="translate(0,16)"
|
||||
fill="#fff">
|
||||
<path d="m16-14c0.94487 0 3.9911 7.9919 4.7555 8.5752 0.76441 0.5833 8.9427 1.1565 9.2346 2.1003 0.29198 0.9438-6.0036 6.4562-6.2956 7.4-0.29198 0.9438 2.3984 9.2899 1.6339 9.8732-0.764 0.583-8.383-4.002-9.328-4.002-0.94487 0-8.5641 4.585-9.3285 4.0017-0.7644-0.584 1.9259-8.9297 1.6339-9.8735s-6.5875-6.4562-6.2956-7.4c0.292-0.9438 8.4702-1.517 9.2342-2.1003 0.765-0.5833 3.811-8.5752 4.756-8.5752z"
|
||||
style="fill:#000000" />
|
||||
<path opacity=".3"
|
||||
d="m88-14c0.94487 0 3.9911 7.9919 4.7555 8.5752 0.76441 0.5833 8.9427 1.1565 9.2346 2.1003 0.29198 0.9438-6.0036 6.4562-6.2956 7.4-0.29198 0.9438 2.3984 9.2899 1.6339 9.8732-0.764 0.583-8.383-4.002-9.328-4.002-0.94487 0-8.5641 4.585-9.3285 4.0017-0.76441-0.5833 1.9259-8.9294 1.6339-9.8732-0.29198-0.9438-6.5875-6.4562-6.2956-7.4 0.29198-0.9438 8.4702-1.517 9.2346-2.1003 0.76441-0.5833 3.8106-8.5752 4.7555-8.5752z" />
|
||||
<path opacity=".7"
|
||||
d="m34.344 13.406c-0.172 0.088-0.315 0.187-0.344 0.282-0.28187 0.91113 5.5814 6.0441 6.25 7.25 0.06311-0.4005 0.10474-0.73846 0.0625-0.875-0.24735-0.79953-4.7593-4.8544-5.9688-6.6562zm27.312 0c-1.2095 1.8019-5.7214 5.8567-5.9688 6.6562-0.04224 0.13654-0.00061 0.4745 0.0625 0.875 0.66855-1.2059 6.5319-6.3389 6.25-7.25-0.0292-0.09438-0.17213-0.1939-0.34375-0.28125zm-13.656 12.532c-0.94487 0-8.5793 4.5833-9.3438 4-0.03185-0.0243-0.04218-0.07484-0.0625-0.125-0.06113 0.57179-0.08345 1.0136 0.0625 1.125 0.76442 0.5833 8.3989-4 9.3438-4 0.94487 0 8.5793 4.5833 9.3438 4 0.14595-0.11137 0.12363-0.55321 0.0625-1.125-0.02032 0.05016-0.03065 0.1007-0.0625 0.125-0.76441 0.5833-8.3989-4-9.3438-4z"
|
||||
transform="translate(0,-16)" />
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'BookmarksIcon',
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
fillColor: {
|
||||
type: String,
|
||||
default: 'currentColor',
|
||||
},
|
||||
size: {
|
||||
type: Number,
|
||||
default: 24,
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2023. The Nextcloud Bookmarks contributors.
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or later. See the COPYING file.
|
||||
*/
|
||||
|
||||
// with nc/vue 7.8.0, if we remove this, nothing works...
|
||||
import {} from '@nextcloud/vue-richtext'
|
||||
|
||||
import { registerWidget } from '@nextcloud/vue/dist/Components/NcRichText.js'
|
||||
import Vue from 'vue'
|
||||
import BookmarkReferenceWidget from './components/BookmarkReferenceWidget.vue'
|
||||
|
||||
import { translate, translatePlural } from '@nextcloud/l10n'
|
||||
|
||||
__webpack_nonce__ = btoa(OC.requestToken) // eslint-disable-line
|
||||
__webpack_public_path__ = OC.linkTo('bookmarks', 'js/') // eslint-disable-line
|
||||
|
||||
Vue.prototype.t = translate
|
||||
Vue.prototype.n = translatePlural
|
||||
Vue.prototype.OC = window.OC
|
||||
Vue.prototype.OCA = window.OCA
|
||||
|
||||
registerWidget('bookmarks-bookmark', (el, { richObjectType, richObject, accessible }) => {
|
||||
// trick to change the wrapper element size, otherwise it always is 100%
|
||||
// which is not very nice with a simple card
|
||||
el.parentNode.style['max-width'] = '400px'
|
||||
el.parentNode.style['margin-left'] = '0'
|
||||
el.parentNode.style['margin-right'] = '0'
|
||||
|
||||
const Widget = Vue.extend(BookmarkReferenceWidget)
|
||||
new Widget({
|
||||
propsData: {
|
||||
richObjectType,
|
||||
richObject,
|
||||
accessible,
|
||||
},
|
||||
}).$mount(el)
|
||||
})
|
|
@ -9,3 +9,4 @@ webpackConfig.entry.flow = path.join(__dirname, 'src', 'flow.js')
|
|||
webpackConfig.entry.dashboard = path.join(__dirname, 'src', 'dashboard.js')
|
||||
webpackConfig.entry.talk = path.join(__dirname, 'src', 'talk.js')
|
||||
webpackConfig.entry.collections = path.join(__dirname, 'src', 'collections.js')
|
||||
webpackConfig.entry.references = path.join(__dirname, 'src', 'references.js')
|
||||
|
|
Loading…
Reference in New Issue