501 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Vue
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			501 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Vue
		
	
	
		
			Executable File
		
	
	
	
	
<template>
 | 
						|
    <article v-if="document">
 | 
						|
        <header>
 | 
						|
            <div class="icons">
 | 
						|
                <img v-bind:src="document.favicon" />
 | 
						|
            </div>
 | 
						|
 | 
						|
            <h1>{{ document.title }}</h1>
 | 
						|
 | 
						|
            <div class="badges">
 | 
						|
                <div
 | 
						|
                    class="badge default"
 | 
						|
                    v-if="document.feed_item_states_count > 0"
 | 
						|
                >
 | 
						|
                    {{ document.feed_item_states_count }}
 | 
						|
                </div>
 | 
						|
            </div>
 | 
						|
            <div class="tools">
 | 
						|
                <button
 | 
						|
                    v-if="document.feed_item_states_count > 0"
 | 
						|
                    class="info"
 | 
						|
                    v-on:click="onMarkAsReadClicked"
 | 
						|
                    v-bind:title="__('Mark as read')"
 | 
						|
                >
 | 
						|
                    <svg fill="currentColor" width="16" height="16">
 | 
						|
                        <use v-bind:xlink:href="icon('unread_items')" />
 | 
						|
                    </svg>
 | 
						|
                    <span class="hidden xl:inline-block">
 | 
						|
                        {{ __("Mark as read") }}
 | 
						|
                    </span>
 | 
						|
                </button>
 | 
						|
                <a
 | 
						|
                    class="button info"
 | 
						|
                    v-bind:href="url"
 | 
						|
                    rel="noopener noreferrer"
 | 
						|
                    v-on:click.left.stop.prevent="
 | 
						|
                        openDocument({
 | 
						|
                            document: document,
 | 
						|
                        })
 | 
						|
                    "
 | 
						|
                    v-on:click.middle.exact="
 | 
						|
                        incrementVisits({
 | 
						|
                            document: document,
 | 
						|
                        })
 | 
						|
                    "
 | 
						|
                    v-bind:title="__('Open')"
 | 
						|
                >
 | 
						|
                    <svg fill="currentColor" width="16" height="16">
 | 
						|
                        <use v-bind:xlink:href="icon('open')" />
 | 
						|
                    </svg>
 | 
						|
                    <span class="hidden xl:inline-block">
 | 
						|
                        {{ __("Open") }}
 | 
						|
                    </span>
 | 
						|
                </a>
 | 
						|
                <button
 | 
						|
                    class="info"
 | 
						|
                    v-on:click="onShareClicked"
 | 
						|
                    v-bind:title="__('Share')"
 | 
						|
                >
 | 
						|
                    <svg fill="currentColor" width="16" height="16">
 | 
						|
                        <use v-bind:xlink:href="icon('share')" />
 | 
						|
                    </svg>
 | 
						|
                    <span class="hidden xl:inline-block">
 | 
						|
                        {{ __("Share") }}
 | 
						|
                    </span>
 | 
						|
                </button>
 | 
						|
            </div>
 | 
						|
        </header>
 | 
						|
 | 
						|
        <div class="body">
 | 
						|
            <div
 | 
						|
                class="cyca-prose"
 | 
						|
                v-if="document.description"
 | 
						|
                v-html="document.description"
 | 
						|
            ></div>
 | 
						|
 | 
						|
            <stateful-details name="document_details" class="details-block">
 | 
						|
                <summary>{{ __("Details") }}</summary>
 | 
						|
                <div class="vertical list striped items-rounded compact">
 | 
						|
                    <div class="list-item">
 | 
						|
                        <div class="list-item-title">{{ __("Real URL") }}</div>
 | 
						|
                        <div class="list-item-value">
 | 
						|
                            <a
 | 
						|
                                v-bind:href="document.url"
 | 
						|
                                rel="noopener noreferrer"
 | 
						|
                                v-on:click.left.stop.prevent="
 | 
						|
                                    openDocument({
 | 
						|
                                        document: document,
 | 
						|
                                    })
 | 
						|
                                "
 | 
						|
                                class="readable"
 | 
						|
                                v-html="document.ascii_url"
 | 
						|
                            ></a>
 | 
						|
                        </div>
 | 
						|
                    </div>
 | 
						|
 | 
						|
                    <div class="list-item" v-if="document.visits">
 | 
						|
                        <div class="list-item-title">{{ __("Visits") }}</div>
 | 
						|
                        <div class="list-item-value">
 | 
						|
                            {{ document.visits }}
 | 
						|
                        </div>
 | 
						|
                    </div>
 | 
						|
 | 
						|
                    <div class="list-item">
 | 
						|
                        <div class="list-item-title">
 | 
						|
                            {{ __("Date of document's last check") }}
 | 
						|
                        </div>
 | 
						|
                        <div class="list-item-value">
 | 
						|
                            <date-time
 | 
						|
                                v-bind:datetime="document.checked_at"
 | 
						|
                                v-bind:calendar="true"
 | 
						|
                            ></date-time>
 | 
						|
                        </div>
 | 
						|
                    </div>
 | 
						|
 | 
						|
                    <div
 | 
						|
                        class="list-item"
 | 
						|
                        v-if="dupplicateInFolders.length > 0"
 | 
						|
                    >
 | 
						|
                        <div class="list-item-title">
 | 
						|
                            {{ __("Also exists in") }}
 | 
						|
                        </div>
 | 
						|
                        <div class="list-item-value">
 | 
						|
                            <div
 | 
						|
                                v-for="dupplicateInFolder in dupplicateInFolders"
 | 
						|
                                v-bind:key="dupplicateInFolder.id"
 | 
						|
                                v-on:click="
 | 
						|
                                    $emit(
 | 
						|
                                        'folder-selected',
 | 
						|
                                        dupplicateInFolder.id,
 | 
						|
                                        dupplicateInFolder.group_id
 | 
						|
                                    )
 | 
						|
                                "
 | 
						|
                                v-html="dupplicateInFolder.breadcrumbs"
 | 
						|
                                class="cursor-pointer mb-1"
 | 
						|
                            ></div>
 | 
						|
                        </div>
 | 
						|
                    </div>
 | 
						|
                </div>
 | 
						|
            </stateful-details>
 | 
						|
 | 
						|
            <stateful-details
 | 
						|
                name="feeds_details"
 | 
						|
                class="details-block"
 | 
						|
                v-if="document.feeds.length > 0"
 | 
						|
            >
 | 
						|
                <summary>{{ __("Feeds") }}</summary>
 | 
						|
 | 
						|
                <div class="list vertical striped items-rounded">
 | 
						|
                    <div v-for="feed in document.feeds" v-bind:key="feed.id">
 | 
						|
                        <div class="list-item">
 | 
						|
                            <div class="icons">
 | 
						|
                                <img v-bind:src="feed.favicon" />
 | 
						|
                            </div>
 | 
						|
                            <div class="list-item-text">{{ feed.title }}</div>
 | 
						|
                            <div class="badges">
 | 
						|
                                <button
 | 
						|
                                    class="success"
 | 
						|
                                    v-if="feed.is_ignored"
 | 
						|
                                    v-on:click="follow(feed)"
 | 
						|
                                >
 | 
						|
                                    <svg
 | 
						|
                                        fill="currentColor"
 | 
						|
                                        width="16"
 | 
						|
                                        height="16"
 | 
						|
                                    >
 | 
						|
                                        <use v-bind:xlink:href="icon('join')" />
 | 
						|
                                    </svg>
 | 
						|
                                    <span>
 | 
						|
                                        {{ __("Follow") }}
 | 
						|
                                    </span>
 | 
						|
                                </button>
 | 
						|
                                <button
 | 
						|
                                    class="danger"
 | 
						|
                                    v-if="!feed.is_ignored"
 | 
						|
                                    v-on:click="ignore(feed)"
 | 
						|
                                >
 | 
						|
                                    <svg
 | 
						|
                                        fill="currentColor"
 | 
						|
                                        width="16"
 | 
						|
                                        height="16"
 | 
						|
                                    >
 | 
						|
                                        <use
 | 
						|
                                            v-bind:xlink:href="icon('cancel')"
 | 
						|
                                        />
 | 
						|
                                    </svg>
 | 
						|
                                    <span>
 | 
						|
                                        {{ __("Ignore") }}
 | 
						|
                                    </span>
 | 
						|
                                </button>
 | 
						|
                            </div>
 | 
						|
                        </div>
 | 
						|
 | 
						|
                        <div
 | 
						|
                            class="vertical list striped items-rounded compact mt-2 alt"
 | 
						|
                        >
 | 
						|
                            <div class="list-item" v-if="feed.description">
 | 
						|
                                <div v-html="feed.description"></div>
 | 
						|
                            </div>
 | 
						|
                            <div class="list-item">
 | 
						|
                                <div class="list-item-title">
 | 
						|
                                    {{ __("Real URL") }}
 | 
						|
                                </div>
 | 
						|
                                <div class="list-item-value">
 | 
						|
                                    <div
 | 
						|
                                        class="readable"
 | 
						|
                                        v-html="feed.ascii_url"
 | 
						|
                                    ></div>
 | 
						|
                                </div>
 | 
						|
                            </div>
 | 
						|
                            <div class="list-item">
 | 
						|
                                <div class="list-item-title">
 | 
						|
                                    {{ __("Date of document's last check") }}
 | 
						|
                                </div>
 | 
						|
                                <div class="list-item-value">
 | 
						|
                                    <date-time
 | 
						|
                                        v-bind:datetime="feed.checked_at"
 | 
						|
                                        v-bind:calendar="true"
 | 
						|
                                    ></date-time>
 | 
						|
                                </div>
 | 
						|
                            </div>
 | 
						|
                            <div class="list-item" v-if="feed.error">
 | 
						|
                                <div class="list-item-title">
 | 
						|
                                    {{ __("Error") }}
 | 
						|
                                </div>
 | 
						|
                                <div class="list-item-value text-red-500">
 | 
						|
                                    {{ feed.error }}
 | 
						|
                                </div>
 | 
						|
                            </div>
 | 
						|
                        </div>
 | 
						|
                    </div>
 | 
						|
                </div>
 | 
						|
            </stateful-details>
 | 
						|
 | 
						|
            <stateful-details
 | 
						|
                class="details-block"
 | 
						|
                name="document_meta_data_details"
 | 
						|
                v-if="document.meta_data"
 | 
						|
            >
 | 
						|
                <summary>{{ __("Metadata") }}</summary>
 | 
						|
                <meta-data-browser
 | 
						|
                    class="vertical list striped items-rounded compact"
 | 
						|
                    v-bind:meta-data="document.meta_data"
 | 
						|
                ></meta-data-browser>
 | 
						|
            </stateful-details>
 | 
						|
 | 
						|
            <stateful-details
 | 
						|
                name="http_response_details"
 | 
						|
                class="details-block"
 | 
						|
            >
 | 
						|
                <summary class="list-item">{{ __("HTTP response") }}</summary>
 | 
						|
                <div class="vertical list striped items-rounded compact">
 | 
						|
                    <div class="list-item">
 | 
						|
                        <div class="list-item-title">
 | 
						|
                            {{ __("HTTP Status Code") }}
 | 
						|
                        </div>
 | 
						|
                        <div
 | 
						|
                            class="list-item-value flex items-center space-x-2"
 | 
						|
                            v-bind:class="statusClass"
 | 
						|
                        >
 | 
						|
                            <span v-if="statusIcon">
 | 
						|
                                <svg fill="currentColor" width="16" height="16">
 | 
						|
                                    <use v-bind:xlink:href="icon(statusIcon)" />
 | 
						|
                                </svg>
 | 
						|
                            </span>
 | 
						|
                            <span>{{ document.http_status_code }}</span>
 | 
						|
                            <span>{{ document.http_status_text }}</span>
 | 
						|
                        </div>
 | 
						|
                    </div>
 | 
						|
 | 
						|
                    <div class="list-item" v-if="document.mimetype">
 | 
						|
                        <div class="list-item-title">
 | 
						|
                            {{ __("MIME type") }}
 | 
						|
                        </div>
 | 
						|
                        <div class="list-item-value">
 | 
						|
                            {{ document.mimetype }}
 | 
						|
                        </div>
 | 
						|
                    </div>
 | 
						|
 | 
						|
                    <stateful-details
 | 
						|
                        name="document_response_details"
 | 
						|
                        class="list-item"
 | 
						|
                    >
 | 
						|
                        <summary>
 | 
						|
                            {{ __("Response details") }}
 | 
						|
                        </summary>
 | 
						|
                        <meta-data-browser
 | 
						|
                            class="vertical list striped items-rounded compact alt"
 | 
						|
                            v-bind:meta-data="document.response"
 | 
						|
                            parent-name="document_response"
 | 
						|
                        ></meta-data-browser>
 | 
						|
                    </stateful-details>
 | 
						|
                </div>
 | 
						|
            </stateful-details>
 | 
						|
 | 
						|
            <div
 | 
						|
                class="mt-6"
 | 
						|
                v-if="
 | 
						|
                    selectedFolder.type !== 'unread_items' &&
 | 
						|
                    selectedFolder.user_permissions.can_delete_document
 | 
						|
                "
 | 
						|
            >
 | 
						|
                <button class="danger" v-on:click="onDeleteDocument">
 | 
						|
                    <svg fill="currentColor" width="16" height="16">
 | 
						|
                        <use v-bind:xlink:href="icon('trash')" />
 | 
						|
                    </svg>
 | 
						|
                    <span>
 | 
						|
                        {{ __("Delete") }}
 | 
						|
                    </span>
 | 
						|
                </button>
 | 
						|
            </div>
 | 
						|
        </div>
 | 
						|
    </article>
 | 
						|
</template>
 | 
						|
 | 
						|
<script>
 | 
						|
import { mapGetters, mapActions } from "vuex";
 | 
						|
import DateTime from "../DateTime";
 | 
						|
import StatefulDetails from "../StatefulDetails.vue";
 | 
						|
import MetaDataBrowser from "../MetaDataBrowser.vue";
 | 
						|
 | 
						|
export default {
 | 
						|
    components: { DateTime, StatefulDetails, MetaDataBrowser },
 | 
						|
    data: function () {
 | 
						|
        return {
 | 
						|
            dupplicateInFolders: [],
 | 
						|
            localStorage: localStorage,
 | 
						|
        };
 | 
						|
    },
 | 
						|
    computed: {
 | 
						|
        ...mapGetters({
 | 
						|
            document: "documents/selectedDocument",
 | 
						|
            selectedFolder: "folders/selectedFolder",
 | 
						|
            feeds: "feeds/feeds",
 | 
						|
        }),
 | 
						|
 | 
						|
        /**
 | 
						|
         * Return document's initial URL instead of the real URL, unless there
 | 
						|
         * is not attached bookmark
 | 
						|
         */
 | 
						|
        url: function () {
 | 
						|
            const self = this;
 | 
						|
 | 
						|
            return self.document.url;
 | 
						|
        },
 | 
						|
 | 
						|
        statusClass: function () {
 | 
						|
            const code = this.document.http_status_code;
 | 
						|
            let className = null;
 | 
						|
 | 
						|
            if (code === 0) {
 | 
						|
                className = "http-status-general-error";
 | 
						|
            } else if (code >= 100 && code <= 199) {
 | 
						|
                className = "http-status-info";
 | 
						|
            } else if (code >= 200 && code <= 299) {
 | 
						|
                className = "http-status-success";
 | 
						|
            } else if (code >= 300 && code <= 399) {
 | 
						|
                className = "http-status-redirection";
 | 
						|
            } else if (code >= 400 && code <= 499) {
 | 
						|
                className = "http-status-client-error";
 | 
						|
            } else if (code >= 500 && code <= 599) {
 | 
						|
                className = "http-status-server-error";
 | 
						|
            }
 | 
						|
 | 
						|
            return className;
 | 
						|
        },
 | 
						|
 | 
						|
        statusIcon: function () {
 | 
						|
            const code = this.document.http_status_code;
 | 
						|
            let icon = null;
 | 
						|
 | 
						|
            if (code === 0) {
 | 
						|
                icon = "error";
 | 
						|
            } else if (code >= 100 && code <= 199) {
 | 
						|
                icon = "info";
 | 
						|
            } else if (code >= 200 && code <= 299) {
 | 
						|
                icon = "success";
 | 
						|
            } else if (code >= 300 && code <= 399) {
 | 
						|
                icon = "redirect";
 | 
						|
            } else if (code >= 400 && code <= 499) {
 | 
						|
                icon = "warning";
 | 
						|
            } else if (code >= 500 && code <= 599) {
 | 
						|
                icon = "error";
 | 
						|
            }
 | 
						|
 | 
						|
            return icon;
 | 
						|
        },
 | 
						|
 | 
						|
        metaData: function () {
 | 
						|
            return collect(this.document.meta_data);
 | 
						|
        },
 | 
						|
    },
 | 
						|
    watch: {
 | 
						|
        document: function (document) {
 | 
						|
            const self = this;
 | 
						|
 | 
						|
            if (document && document.id) {
 | 
						|
                self.load(document).then(function () {
 | 
						|
                    self.findDupplicateInFolders();
 | 
						|
                });
 | 
						|
            }
 | 
						|
        },
 | 
						|
    },
 | 
						|
    mounted: function () {
 | 
						|
        const self = this;
 | 
						|
 | 
						|
        if (self.document && self.document.id) {
 | 
						|
            self.load(self.document).then(function () {
 | 
						|
                self.findDupplicateInFolders();
 | 
						|
            });
 | 
						|
        }
 | 
						|
    },
 | 
						|
    methods: {
 | 
						|
        ...mapActions({
 | 
						|
            incrementVisits: "documents/incrementVisits",
 | 
						|
            openDocument: "documents/openDocument",
 | 
						|
            ignoreFeed: "documents/ignoreFeed",
 | 
						|
            followFeed: "documents/followFeed",
 | 
						|
            load: "documents/load",
 | 
						|
        }),
 | 
						|
 | 
						|
        /**
 | 
						|
         * Filters dupplicates provided by the document by excluding current
 | 
						|
         * folder
 | 
						|
         */
 | 
						|
        findDupplicateInFolders: function () {
 | 
						|
            const self = this;
 | 
						|
 | 
						|
            const dupplicates = collect(self.document.dupplicates)
 | 
						|
                .reject((folder) => folder.id === self.selectedFolder.id)
 | 
						|
                .all();
 | 
						|
 | 
						|
            self.dupplicateInFolders = dupplicates;
 | 
						|
        },
 | 
						|
 | 
						|
        /**
 | 
						|
         * Mark as read button clicked
 | 
						|
         */
 | 
						|
        onMarkAsReadClicked: function () {
 | 
						|
            const self = this;
 | 
						|
 | 
						|
            self.$emit("feeditems-read", {
 | 
						|
                documents: [self.document.id],
 | 
						|
            });
 | 
						|
        },
 | 
						|
 | 
						|
        /**
 | 
						|
         * Delete button clicked
 | 
						|
         */
 | 
						|
        onDeleteDocument: function () {
 | 
						|
            const self = this;
 | 
						|
 | 
						|
            self.$emit("documents-deleted", {
 | 
						|
                folder: self.selectedFolder,
 | 
						|
                documents: [self.document],
 | 
						|
            });
 | 
						|
        },
 | 
						|
 | 
						|
        /**
 | 
						|
         * Share button clicked
 | 
						|
         */
 | 
						|
        onShareClicked: function () {
 | 
						|
            const self = this;
 | 
						|
            const sharedData = {
 | 
						|
                title: self.document.title,
 | 
						|
                text: self.document.description,
 | 
						|
                url: self.document.url,
 | 
						|
            };
 | 
						|
 | 
						|
            if (navigator.share) {
 | 
						|
                navigator.share(sharedData);
 | 
						|
            } else {
 | 
						|
                location.href =
 | 
						|
                    "mailto:?subject=" +
 | 
						|
                    sharedData.title +
 | 
						|
                    "&body=" +
 | 
						|
                    sharedData.url;
 | 
						|
            }
 | 
						|
        },
 | 
						|
 | 
						|
        /**
 | 
						|
         * Follow specified feed
 | 
						|
         */
 | 
						|
        follow: function (feed) {
 | 
						|
            const self = this;
 | 
						|
 | 
						|
            self.followFeed(feed);
 | 
						|
        },
 | 
						|
 | 
						|
        /**
 | 
						|
         * Ignore specified feed
 | 
						|
         */
 | 
						|
        ignore: function (feed) {
 | 
						|
            const self = this;
 | 
						|
 | 
						|
            self.ignoreFeed(feed);
 | 
						|
        },
 | 
						|
    },
 | 
						|
};
 | 
						|
</script>
 |