%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /home/dopla/www/wp-content/plugins/ml-slider/admin/assets/js/app/settings/pages/
Upload File :
Create Path :
Current File : /home/dopla/www/wp-content/plugins/ml-slider/admin/assets/js/app/settings/pages/Import.vue

<template>
<div>
	<split-layout>
		<template slot="header">{{ __('Import', 'ml-slider') }}</template>
		<template slot="description">
			{{ __('Easily import slideshows generated by MetaSlider. This requires a file generated from the Export tab.', 'ml-slider') }}
		</template>
		<template slot="fields">
			<file-button name="import" accept=".json" @loaded="loadSlideshowsFromFile" :disabled="processing">
				<template slot="header">{{ __('Load slideshows', 'ml-slider') }}</template>
				<template slot="description">{{ sprintf(__('If you have an export file, you may upload it here to be processed. Information about each slideshow will be presented below. You will be able to confirm before importing.', 'ml-slider'), slideshowsToImport) }}</template>
				<template v-if="importing" slot="button">{{ __('Importing...', 'ml-slider') }}</template>
				<template v-else-if="processing" slot="button">{{ __('Processing...', 'ml-slider') }}</template>
				<template v-else slot="button">
					<svg class="w-5 -ml-1 pr-1" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" />
                    </svg>
                    {{ __('Upload file', 'ml-slider') }}
				</template>
			</file-button>
		</template>
	</split-layout>
	<split-layout
		v-if="Object.keys(slideshowsList).length"
		:loading="importing || processing">
		<template slot="header">{{ __('Slideshows', 'ml-slider') }}</template>
		<template slot="description">
			<pre>
{{ sprintf(__('Date: %s', 'ml-slider'), fileDate()) }}
{{ sprintf(__('Version: v%s', 'ml-slider'), metadata.version) }}
			</pre>
				<div v-if="!procesingImages && !missingImages.length">
					{{ __('All images required to import are accounted for.', 'ml-slider') }}
				</div>
			<transition name="settings-fade" mode="in-out">
				<div v-if="!procesingImages && missingImages.length">
					<h4>{{ __('The following images were not found:', 'ml-slider') }}</h4>
					<div>
						<div v-for="slideshow in missingImages" :key="slideshow">
							<p class="font-bold underline mb-1">
								{{ slideshowsList[slideshow].title }}
							</p>
							<ul class="mb-4">
								<li
									v-for="slide in slidesMissingImages(slideshow)"
									:key="slide.original_id"
									class="mb-0">
									{{ slide.image ? slide.image : __('No image name provided' , 'ml-slider') }}
								</li>
							</ul>
						</div>
					</div>
				</div>
			</transition>
		</template>
		<template slot="description3">
			<transition name="settings-fade" mode="in-out">
				<div v-if="!procesingImages && missingImages.length">
					{{ __('Note: You can still import slideshows that contain missing images. You will just need to manually update or delete these slides from their individual slideshow edit pages.', 'ml-slider') }}
				</div>
			</transition>
		</template>
		<template slot="fields">
			<div class="mb-10">
				<action-button
					@click="importSlideshows"
					:disabled="!slideshowsToImport.length">
					<template slot="header">{{ sprintf(__('Import %s slideshows', 'ml-slider'), slideshowsToImport.length) }}</template>
					<template slot="description">{{ __('Select the slideshows you wish to import below, then press here to import them.', 'ml-slider') }}</template>
					<template slot="button">{{ __('Import', 'ml-slider') }}</template>
				</action-button>
				<switch-single-input
					v-if="Object.keys(slideshowsList).length > 10"
					:value="slideshowsToImport.length > 0"
					@change="toggleSlideshowsToImport($event)">
					<template slot="header">{{ __('Toggle all slideshows') }}</template>
					<template slot="description">{{ __('Select or deselect all slideshows') }}</template>
				</switch-single-input>
			</div>
			<template v-for="(slideshow, index) in slideshowsList">
				<switch-single-input
					:key="index"
					v-model="slideshowsListSelection[index]"
					class="transition-all duration-150 ease-linear"
					:style="{ filter: slideshowsListSelection[index] ? 'none' : 'grayscale(1)' }">
					<template slot="header">
						<input
							:value="slideshow.title || 'Title not found'"
							class="-ml-2 hover:bg-gray-lighter hover:border border-gray-light px-2 py-1 text-lg"
							@change="slideshowsList[index].title = $event.target.value">
					</template>
					<template slot="description">
						<div v-if="slideshow.slides" class="pl-3 inline-flex flex-row-reverse justify-end relative z-0 overflow-hidden">
							<div
								v-for="slide in slideshow.slides"
								:key="slide.original_id"
								class="relative -ml-3 z-30 inline-block h-12 w-12 text-white border border-gray-light shadow-solid rounded-full">
								<div
									v-if="'post_feed' === slide.meta['ml-slider_type']"
									class="bg-blue border border-blue flex items-center justify-center text-lg text-white rounded-full h-full tipsy-tooltip-top"
									:original-title="__('Post Feed slide', 'ml-slider')"
									:title="__('Post Feed slide', 'ml-slider')">
									P
								</div>
								<div
									v-else-if="'external' === slide.meta['ml-slider_type']"
									class="bg-blue-light border border-blue-light flex items-center justify-center text-lg text-white rounded-full h-full tipsy-tooltip-top"
									:original-title="__('External slide', 'ml-slider')"
									:title="__('External slide', 'ml-slider')">
									E
								</div>
								<div
									v-else-if="!slide.id && !procesingImages"
									:style="{ 'animation-delay': [(500 * index * Math.random()) + 'ms'] }"
									class="gradient border border-white rounded-full h-full flex justify-center items-center text-red tipsy-tooltip-top"
									:original-title="sprintf(__('Image not found<br>%s', 'ml-slider'), slide.image)"
									:title="sprintf(__('Image not found<br>%s', 'ml-slider'), slide.image)">
									x
								</div>
								<div
									v-else-if="!slide.id"
									:style="{ 'animation-delay': [(500 * index * Math.random()) + 'ms'] }"
									class="gradient border border-white text-white rounded-full h-full"/>
								<img
									v-else :src="imageThumbnails[slide.id]"
									class="gradient border border-white rounded-full h-full inline-block"
									alt="">

							</div>
							<div class="relative -ml-3 z-50 inline-block bg-gray-lighter flex items-center justify-center text-lg text-gray-dark h-12 w-12 rounded-full shadow-solid border border-gray-light">
								{{ slideshow.slides.length }}
							</div>
						</div>
						<div v-else>
							{{ __('No slides found', 'ml-slider') }}
						</div>
					</template>
				</switch-single-input>
			</template>
		</template>
	</split-layout>
</div>
</template>

<script>
import { Image, Slideshow } from '../../api'
import Swal from 'sweetalert2'
import { default as SplitLayout } from '../layouts/_split'
import { default as SwitchSingle } from '../inputs/_switchSingle'
import { default as ActionButton } from '../inputs/_actionButton'
import { default as FileButton } from '../inputs/_fileButton'
import { default as fileDownload } from 'js-file-download'
import { DateTime  } from "luxon"
export default {
	components: {
		'split-layout' : SplitLayout,
		'switch-single-input' : SwitchSingle,
		'file-button' : FileButton,
		'action-button' : ActionButton,
	},
	computed: {
		slideshowsToImport() {
			if (!Object.keys(this.slideshowsListSelection).length) return []
			let ids = []
			Object.keys(this.slideshowsListSelection).forEach(slideshowId => {
				this.slideshowsListSelection[slideshowId] && ids.push(slideshowId)
			})
			return ids
		},
		missingImages() {
			// Only check slideshows they want to import
			return this.slideshowsToImport.filter(index => {
				if (!this.slideshowsList[index] || !this.slideshowsList[index].slides) return false
				let slides = this.slideshowsList[index].slides.filter(slide => {
					if (['external', 'post_feed'].indexOf(slide.meta['ml-slider_type']) > -1) return false
					return !slide.id
				})
				return slides.length
			})
		}
	},
	watch: {
		slideshowsList: {
			immediate: false,
			handler: function(slideshowsFromFile) {
				// TODO: check if any images are even missing IDs (only needed if they upload a new file)
				let images = []
				Object.keys(slideshowsFromFile).forEach(index => {
					if (this.slideshowsList[index].slides) {
						let imagesNames = this.slideshowsList[index].slides.map(slide => [slide.image, slide.image_alt])
						images.push(...imagesNames)
					}
				})
				if (images.length) {
					images = images.flat().filter(image => image.length)
					images = [...new Set(images)]
					images && this.findImages(images)
				}
			}
		},
	},
	props: {},
	data() {
		return {
			metadata: '',
			slideshowsList: {},
			slideshowsListSelection: {},
			imageThumbnails: {},
			processing: false,
			procesingImages: false,
			importing: false,
			userSawProcessingImagesMessage: false
		}
	},
	created() {},
	mounted() {},
	methods: {
		loadSlideshowsFromFile(data) {
			this.slideshowsList = {}
			this.slideshowsListSelection = {}

			// TODO: test with uploading different export file

			if (!data) {
				this.notifyWarning(
					'metaslider-importing-slideshows-bad-data',
					this.__('The data in this file does not appear to be valid.', 'ml-slider'), true)
			}
			this.processing = true

			try {
				data = JSON.parse(data)
				this.metadata = data.metadata
				delete data.metadata
				this.slideshowsList = data

				const slideshowsListSelection = {}
				for (const [key, slideshow] of Object.entries(this.slideshowsList)) {
					slideshowsListSelection[key] = true
				}
				this.slideshowsListSelection = slideshowsListSelection

				this.notifySuccess(
					'metaslider/all-slideshows-from-file-loaded',
					this.sprintf(
						this.__('Found %s slideshows', 'ml-slider'),
						Object.keys(this.slideshowsList).length
					), true)
			} catch (error) {
				this.slideshowsList = {}
				this.notifyError('metaslider/all-slideshows-from-file-error', error.message, true)
			}
			this.processing = false
		},
		findImages(filenames) {
			this.procesingImages = true
			Image.findIdFromFilename(JSON.stringify(filenames)).then(response => {
				const images = response.data.data

				// Create lookup table for thumbnails
				Object.keys(images).forEach(filename => {
					images[filename] && this.$set(this.imageThumbnails, images[filename].id, images[filename].thumbnail)
				})

				// Set the ID on the slides so they will be properly imported
				Object.keys(this.slideshowsList).forEach(slideshow => {
					if (this.slideshowsList[slideshow].slides) {
						Object.keys(this.slideshowsList[slideshow].slides).forEach(slide => {
							let filename = this.slideshowsList[slideshow].slides[slide].image
							let filenameAlt = this.slideshowsList[slideshow].slides[slide].image_alt
							if (images[filename]) {
								this.$set(this.slideshowsList[slideshow].slides[slide], 'id', images[filename].id)
							} else if (images[filenameAlt]) {
								this.$set(this.slideshowsList[slideshow].slides[slide], 'id', images[filenameAlt].id)
							}
						})
					}
				})
				this.procesingImages = false

				// Only show this if the user attempted to import while still processing
				if (this.userSawProcessingImagesMessage) {
					this.notifyInfo(
						'metaslider-finding-images-success',
						this.__('Image search complete', 'ml-slider'), true)
				}
			}).catch(error => {
				this.notifyError('metaslider/import-from-file-error', error, true)
			})
		},
		async importSlideshows() {
			if (this.procesingImages) {
				this.userSawProcessingImagesMessage = true
				this.notifyWarning(
					'metaslider-importing-slideshows-still-processing-images',
					this.__('We are still searching for your images. Please wait.', 'ml-slider'), true)
				return
			}

			if (!this.slideshowsToImport.length) {
				this.notifyWarning(
					'metaslider-importing-slideshows-no-slideshows',
					this.__('You have no slideshows to import', 'ml-slider'), true)
			}

			this.importing = true
			this.processing = true

			const slideshowData = []
			this.slideshowsToImport.forEach(key => {
				slideshowData.push(this.slideshowsList[key])
			})

			// If images are missing, give the user information and the choice to proceed
			const readyToImport = this.missingImages.length ? await Swal.fire({
				title: this.__('Some images are missing', 'ml-slider'),
				html: '<p class="text-base">' + this.__('When images are missing you will have to manually update or delete the slide after the import completes.', 'ml-slider') + '</p>',
				confirmButtonText: this.__('Continue', 'ml-slider'),
				showCancelButton: true,
				icon: 'warning',
				iconHtml: '<div class="dashicons dashicons-warning" style="transform: scale(3.5);"></div>',
				customClass: 'shadow-lg',
			}) : { value: true }

			// If the user clicked cancel
			if (!readyToImport.value) {
				this.importing = false
				this.processing = false
				return
			}

			this.notifyInfo(
				'metaslider-importing-slideshows',
				this.sprintf(
					this.__('Importing %s slideshows...', 'ml-slider'),
					this.slideshowsToImport.length
				), true)

			Slideshow.import(JSON.stringify([...slideshowData])).then(response => {
				this.notifySuccess(
					'metaslider-importing-slideshows-success',
					this.__('Import successful', 'ml-slider'), true)
			}).catch(error => {
				this.notifyError('metaslider/import-error', error, true)
			}).finally(() => {
				this.importing = false
				this.processing = false
			})
		},
		fileDate() {
			return DateTime.fromISO(new Date((this.metadata.date)).toISOString()).toFormat('yyyy/MM/dd')
		},
		randomBgColor() {
			const bgColors = ['bg-gray-dark', 'bg-gray-light', 'bg-gray-lighter', 'bg-gray-lightest']
			return bgColors[Math.floor(Math.random() * bgColors.length)]
		},
		slidesMissingImages(slideshow) {
			return this.slideshowsList[slideshow].slides.filter(slide => {
				if (['post_feed', 'external'].indexOf(slide.meta['ml-slider_type']) > -1) return false
				return !slide.id
			})
		},
		toggleSlideshowsToImport(state) {
			Object.keys(this.slideshowsListSelection).forEach(slideshow => this.slideshowsListSelection[slideshow] = state)
		},
	}
}
</script>
<style scoped>
.gradient {
    animation-duration: 3s;
    animation-fill-mode: forwards;
    animation-iteration-count: infinite;
    animation-name: placeHolderShimmer;
    animation-timing-function: linear;
    background: #f1f1f1;
    background: linear-gradient(to right, #f1f1f1 8%, #f8fafc 38%, #f1f1f1 54%);
    background-size: 1000px 640px;
    position: relative;
}
@keyframes placeHolderShimmer {
    0%{
        background-position: -468px 0
    }
    100%{
        background-position: 468px 0
    }
}
</style>

Zerion Mini Shell 1.0