Created
January 18, 2019 10:49
-
-
Save Insayt/2ddb94ea188a2d76cb1a71c56f4008a5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<div class="add-task"> | |
<div class="card"> | |
<div class="card-body"> | |
<form @submit.prevent="savePost"> | |
<div class="add-task-form"> | |
<div class="add-task-form__left"> | |
<div class="upload-file" | |
:class="{ disabled: finalImages.length >= 10 || (stories && finalImages.length >= 1), '_full': stories }"> | |
<label for="exampleFormControlFile1"> | |
<div class="upload-file__drop" ref="fileform" :class="{higlight: higlightFileDrop}"> | |
<div class="upload-file__drop-zone" @drop.prevent="onFileChange" | |
@dragover.prevent></div> | |
<img class="upload-file__icon" src="/i/icons/drop-icon.svg" | |
v-show="!higlightFileDrop"> | |
<img class="upload-file__icon" src="/i/icons/drop-icon-blue.svg" | |
v-show="higlightFileDrop"> | |
<div class="upload-file__drop-title">Перетащите фото и видео</div> | |
<div class="upload-file__drop-or" v-show="!higlightFileDrop">или</div> | |
<div class="t-button upload-file__drop-btn" v-show="!higlightFileDrop"> | |
<span class="t-button__name"> | |
Выберите файл | |
</span> | |
</div> | |
</div> | |
</label> | |
<input | |
type="file" | |
accept="image/*, video/*" | |
class="form-control-file" | |
id="exampleFormControlFile1" | |
@change="onFileChange" | |
> | |
</div> | |
<div class="post-info" v-if="!stories"> | |
<div class="add-task-form__text-wrap"> | |
<div class="add-task-form__emoji"> | |
<emoji-picker :onClick="handleEmojiPicker"/> | |
<span class="icon-smile"></span> | |
</div> | |
<textarea | |
class="text-field _dark-color post-text" | |
placeholder="Введите описание поста" | |
maxlength="2000" | |
v-model="text" | |
wrap="soft" | |
></textarea> | |
</div> | |
<div class="count-badge-wrap"> | |
<span class="count-badge-wrap__item"> | |
<span class="count-badge">{{ symbols }}</span> симоволов осталось. | |
</span> | |
<span class="count-badge-wrap__item"> | |
<span class="count-badge">{{ hashtags }}</span> хэштегов осталось | |
</span> | |
</div> | |
</div> | |
</div> | |
<div class="add-task-form__right"> | |
<div class="form-group"> | |
<datetime | |
v-if="showCalendar" | |
v-model="datetime" | |
type="datetime" | |
class="theme-inline" | |
:inline="true" | |
:zone="timezone" | |
:phrases="{ok: 'Ок', cancel: 'Отмена'}" | |
:min-datetime="new Date().toISOString()" | |
></datetime> | |
</div> | |
</div> | |
</div> | |
<div class="preview-photos"> | |
<div class="add-task-image-wrap" v-for="(item, $index) in finalImages"> | |
<div class="add-task-image-wrap__content" v-if="item.type === 'image'" | |
:style="{ backgroundImage: 'url(' + item.src + ')' }"> | |
<button class="add-task-image__delete" @click.prevent="removeImage($index)"> | |
<span>×</span> | |
</button> | |
</div> | |
<div class="add-task-image-wrap__content" v-if="item.type === 'video'"> | |
<video class="add-task-video" :src="item.src"></video> | |
<button class="add-task-image__delete" @click.prevent="removeImage($index)"> | |
<span>×</span> | |
</button> | |
</div> | |
</div> | |
<div v-if="finalImagesLoading"> | |
<div id="floatingCirclesG"> | |
<div class="f_circleG" id="frotateG_01"></div> | |
<div class="f_circleG" id="frotateG_02"></div> | |
<div class="f_circleG" id="frotateG_03"></div> | |
<div class="f_circleG" id="frotateG_04"></div> | |
<div class="f_circleG" id="frotateG_05"></div> | |
<div class="f_circleG" id="frotateG_06"></div> | |
<div class="f_circleG" id="frotateG_07"></div> | |
<div class="f_circleG" id="frotateG_08"></div> | |
</div> | |
</div> | |
</div> | |
<div class="controls-mobile"> | |
<div class="add-task-form__text-wrap _mobile" v-if="!stories"> | |
<div class="add-task-form__emoji"> | |
<emoji-picker :onClick="handleEmojiPicker"/> | |
<span class="icon-smile"></span> | |
</div> | |
<textarea | |
class="text-field _dark-color post-text_mobile" | |
placeholder="Введите описание поста" | |
maxlength="2200" | |
v-model="text" | |
></textarea> | |
</div> | |
<div class="form-group"> | |
<datetime | |
v-if="showCalendar" | |
v-model="datetime" | |
type="datetime" | |
class="theme-inline" | |
:inline="true" | |
:zone="timezone" | |
:phrases="{ok: 'Ок', cancel: 'Отмена'}" | |
:min-datetime="new Date().toISOString()" | |
></datetime> | |
</div> | |
</div> | |
<div class="add-task-bottom"> | |
<form class="form-inline" v-if="!stories"> | |
<t-onoff v-model="isDelete" secondary>Автоудаление поста через | |
<t-help>При необходимости выставите автоудаление поста через N времени. То есть, после | |
выкладки поста в профиль, он будет удален через определенное время. Очень актуально | |
для рекламных постов | |
</t-help> | |
</t-onoff> | |
<input :disabled="!isDelete" v-model.number="deletenum" min="1" type="number" | |
class="text-field"> | |
<div class="t-select"> | |
<select :disabled="!isDelete" v-model="deleteRange" class="t-select__select"> | |
<option value="minutes">{{ declOfNum(deletenum, ['минуту', 'минуты', 'минут']) }} | |
</option> | |
<option value="hours">{{ declOfNum(deletenum, ['час', 'часа', 'часов']) }}</option> | |
<option value="days">{{ declOfNum(deletenum, ['день', 'дня', 'дней']) }}</option> | |
<option value="week">{{ declOfNum(deletenum, ['неделю', 'недели', 'недель']) }} | |
</option> | |
</select> | |
</div> | |
<span class="geo-button" @click="openGeoModal"> | |
<span v-if="!selectedGeo.title">Укажите место</span> | |
<span v-if="selectedGeo.title">{{ selectedGeo.title }}</span> | |
<span class="geo-button__close" @click.stop="deleteGeo" | |
v-if="selectedGeo.title">×</span> | |
</span> | |
</form> | |
<button type="button" class="pull-right t-button _grey" @click.prevent.stop="cancelEditMode" | |
v-if="editMode"> | |
<span class="t-button__name">Отмена</span> | |
</button> | |
<button type="submit" class="pull-right t-button" | |
:disabled="!finalImages.length || !datetime || saveProcess || hashtags < 0"> | |
<span class="t-button__name" v-if="!editMode && !stories">Запланировать пост</span> | |
<span class="t-button__name" v-if="!editMode && stories">Запланировать сторис</span> | |
<span class="t-button__name" v-if="editMode">Отредактировать</span> | |
</button> | |
</div> | |
</form> | |
</div> | |
</div> | |
<b-modal ref="geoModalRef" | |
hide-footer | |
title="Укажите геолокацию поста" | |
class="geo-modal" | |
> | |
<div> | |
<t-selector class="geo-modal__list" :items="geoViews" v-model="geoViewType"></t-selector> | |
<div class="geo-bar__form"> | |
<div class="geo-bar__form__l-column"> | |
<div class="fieldset"> | |
<div class="fieldset__control"> | |
<t-input placeholder="Укажите город или населенный пункт" icon="www" ref="geoinput" | |
id="googlesuggest"></t-input> | |
</div> | |
</div> | |
<div class="fieldset"> | |
<div class="fieldset__control"> | |
<t-input v-model="hash_tag_input" placeholder="Укажите название места" icon="pin" | |
ref="placesinput" @input="fbSearch"></t-input> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div class="geo-bar__list founded-list" :class="{'_visible': geoViewType === 'list'}" | |
v-if="fbgeofound.length"> | |
<template v-for="geotag in fbgeofound"> | |
<div class="founded-list__item" :class="{ _active: geotag.id === preSelectedGeo.id }"> | |
<div class="founded-list__name">{{geotag.title}}, {{geotag.address}}</div> | |
<div class="founded-list__add"><span class="cta-icon icon-plus" | |
@click="addToGeo(geotag)"></span></div> | |
</div> | |
</template> | |
</div> | |
<div class="geo-bar__map" :class="{'_visible': geoViewType === 'map'}"> | |
<p> | |
<span v-if="preSelectedGeo.title">Выбранно место: {{ preSelectedGeo.title }}, {{ preSelectedGeo.address }}</span> | |
</p> | |
<div class="gmap" id="gmap" ref="geomap"></div> | |
</div> | |
<button class="t-button _block" @click="addFinalGeo"> | |
<span class="t-button__name">Добавить геолокацию</span> | |
</button> | |
</div> | |
</b-modal> | |
<b-modal ref="myModalRef" | |
no-close-on-backdrop | |
size="lg" | |
hide-footer | |
title="Загрузка" | |
@shown="modalShow" | |
@hidden="modalHide" | |
> | |
<div v-if="uploadStep === 1"> | |
<div class="crop-wrapper"> | |
<div class="crop-alert" v-if="video.file"> | |
Видео длинее 1 минуты будут автоматически обрезаны | |
</div> | |
<div class="add-task-image-wrap"> | |
<img id="croppr" class="add-task-image"> | |
</div> | |
<div class="mt-1" v-if="!finalImages.length && !stories"> | |
Соотношение сторон: | |
<div class="mt-1"> | |
<button class="t-button _medium _secondary" @click="setAspectRatio(1)"> | |
<span class="t-button__name">1:1</span> | |
</button> | |
<button class="t-button _medium _secondary" @click="setAspectRatio(16 / 9)"> | |
<span class="t-button__name">16:9</span> | |
</button> | |
<button class="t-button _medium _secondary" @click="setAspectRatio(8 / 10)"> | |
<span class="t-button__name">8:10</span> | |
</button> | |
</div> | |
</div> | |
</div> | |
<button class="mt-2 pull-right t-button _medium" @click="cropImage"> | |
<span class="t-button__name">Дальше</span> | |
</button> | |
<div class="clearfix"></div> | |
</div> | |
<div v-if="uploadStep === 2"> | |
<button class="filter-btn t-button _medium" @click="applyFilter('normal')"> | |
<span class="t-button__name">Без фильтра</span> | |
</button> | |
<button class="filter-btn t-button _medium" @click="applyFilter('clarendon')"> | |
<span class="t-button__name">Clarendon</span> | |
</button> | |
<button class="filter-btn t-button _medium" @click="applyFilter('juno')"> | |
<span class="t-button__name">Juno</span> | |
</button> | |
<button class="filter-btn t-button _medium" @click="applyFilter('lark')"> | |
<span class="t-button__name">Lark</span> | |
</button> | |
<button class="filter-btn t-button _medium" @click="applyFilter('ludwig')"> | |
<span class="t-button__name">Ludwig</span> | |
</button> | |
<button class="filter-btn t-button _medium" @click="applyFilter('gingham')"> | |
<span class="t-button__name">Gingham</span> | |
</button> | |
<button class="filter-btn t-button _medium" @click="applyFilter('valencia')"> | |
<span class="t-button__name">Valencia</span> | |
</button> | |
<button class="filter-btn t-button _medium" @click="applyFilter('xpro2')"> | |
<span class="t-button__name">X-Pro-2</span> | |
</button> | |
<button class="filter-btn t-button _medium" @click="applyFilter('lofi')"> | |
<span class="t-button__name">Lo-Fi</span> | |
</button> | |
<button class="filter-btn t-button _medium" @click="applyFilter('amaro')"> | |
<span class="t-button__name">Amaro</span> | |
</button> | |
<button class="filter-btn t-button _medium" @click="applyFilter('brooklyn')"> | |
<span class="t-button__name">Brooklyn</span> | |
</button> | |
<button class="filter-btn t-button _medium" @click="applyFilter('willow')"> | |
<span class="t-button__name">Willow</span> | |
</button> | |
<div class="image-filter-wrap"> | |
<img id="image-filter" class="cropped-image" :src="croppedImage"> | |
</div> | |
<button class="mt-2 pull-right t-button _medium" @click="saveImage"> | |
<span class="t-button__name">Сохранить</span> | |
</button> | |
<div class="clearfix"></div> | |
</div> | |
</b-modal> | |
<video hidden id="t-video" controls></video> | |
<canvas hidden id="t-canvas"></canvas> | |
</div> | |
</template> | |
<script> | |
import {DateTime} from 'luxon'; | |
import Cropper from 'cropperjs'; | |
import axios from 'axios'; | |
import config from 'config'; | |
import debounce from 'lodash/debounce'; | |
import GoogleMapsApiLoader from 'google-maps-api-loader'; | |
const MAX_POST_SIZE = 2000; | |
const MAX_HASH_TAGS = 30; | |
let base64; | |
export default { | |
props: ['stories'], | |
components: {DateTime}, | |
data: () => ({ | |
editMode: false, | |
text: '', | |
video: { | |
file: null, | |
base64: null | |
}, | |
croppedImage: '', | |
filteredImage: '', | |
finalImages: [], | |
datetime: new Date().toISOString(), | |
isDelete: false, | |
datedel: '', | |
deletenum: 1, | |
formData: new FormData(), | |
cropper: {}, | |
uploadStep: 1, | |
aspectRatio: 1, | |
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, | |
deleteRange: 'minutes', | |
finalImagesLoading: false, | |
firebaseId: null, | |
saveProcess: false, | |
higlightFileDrop: false, | |
showCalendar: true, | |
hash_tag_input: '', | |
geoViews: [ | |
{name: 'Списком', icon: 'list', value: 'list'}, | |
{name: 'На карте', icon: 'pin', value: 'map'} | |
], | |
geoViewType: 'list', | |
google: null, | |
map: null, | |
fbgeofound: [], | |
fbWindows: [], | |
initPosition: { | |
lat: 55.755826, | |
lng: 37.6173 | |
}, | |
preSelectedGeo: {}, | |
selectedGeo: {} | |
}), | |
mounted () { | |
this.$bus.$on('edit-post', (post, isNew) => { | |
if (isNew) { | |
this.datetime = DateTime.fromMillis(post.timestamp).toISO(); | |
this.showCalendar = false; | |
this.$nextTick(() => { | |
this.showCalendar = true; | |
}); | |
return; | |
} | |
this.text = post.text; | |
this.finalImages = post.media; | |
this.timezone = post.timezone; | |
this.datetime = DateTime.fromMillis(post.datetime, {zone: post.timezone}).toISO(); | |
if (post.location) { | |
this.selectedGeo = { | |
title: post.location.name, | |
lat: post.location.lat, | |
lng: post.location.lng, | |
facebook_places_id: post.facebook_places_id, | |
location: post.location | |
}; | |
} | |
if (post.deletenum) { | |
this.isDelete = true; | |
this.datedel = post.datedel; | |
this.deletenum = post.deletenum; | |
this.deleteRange = post.deleteRange; | |
} | |
this.firebaseId = post.id; | |
this.editMode = true; | |
this.showCalendar = false; | |
setTimeout(() => { | |
this.showCalendar = true; | |
}) | |
}); | |
['dragenter', 'dragover'].forEach(eventName => { | |
this.$refs.fileform.addEventListener(eventName, () => { | |
this.higlightFileDrop = true; | |
}, false) | |
}); | |
GoogleMapsApiLoader({ | |
libraries: ['places'], | |
apiKey: config.googleApi, | |
language: 'ru', | |
}).then(google => { | |
this.google = google; | |
this.initMap(); | |
}); | |
$('.modal-content').on('click', this.delegateMapClick); | |
}, | |
beforeDestroy () { | |
this.$bus.$off('edit-post'); | |
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => { | |
this.$refs.fileform.removeEventListener(eventName) | |
}); | |
$('.modal-content').off('click', this.delegateMapClick); | |
}, | |
watch: { | |
geoViewType (newVal) { | |
if (newVal === 'map') { | |
this.$nextTick(() => { | |
this.initMap(); | |
this.fbSearchPlaces(); | |
}); | |
} | |
} | |
}, | |
computed: { | |
accountKey () { | |
return this.$store.getters['route']['params']['accountKey']; | |
}, | |
userId () { | |
return this.$store.getters['user/id']; | |
}, | |
symbols () { | |
return MAX_POST_SIZE - this.text.length; | |
}, | |
hashtags () { | |
let hashTags = this.text.match(/(^|\W)(#[A-Za-zА-яа-я0-9_\d][\w-]*)/g) || []; | |
return MAX_HASH_TAGS - hashTags.length; | |
}, | |
account () { | |
return this.$store.getters['user/accounts'][this.accountKey]; | |
} | |
}, | |
methods: { | |
deleteGeo () { | |
this.preSelectedGeo = {}; | |
this.selectedGeo = {}; | |
this.hash_tag_input = ''; | |
this.fbWindows = []; | |
this.fbgeofound = []; | |
$('#googlesuggest').val(''); | |
}, | |
addFinalGeo () { | |
this.selectedGeo = Object.assign({}, this.preSelectedGeo); | |
this.$refs.geoModalRef.hide(); | |
}, | |
openGeoModal () { | |
this.$refs.geoModalRef.show(); | |
}, | |
delegateMapClick (e) { | |
if (e.target.classList.contains('place-iw') && e.target.getAttribute('data-id')) { | |
this.addToGeo(this.mapPoints[e.target.getAttribute('data-id')]); | |
} | |
}, | |
addToGeo (geotag) { | |
this.preSelectedGeo = geotag; | |
}, | |
drawMap () { | |
this.$nextTick(() => { | |
this.map = new this.google.maps.Map(document.getElementById('gmap'), { | |
center: this.initPosition, | |
zoom: 10, | |
}); | |
}); | |
}, | |
initMap () { | |
if (!this.map) { | |
this.drawMap(); | |
const autocomplete = new this.google.maps.places.Autocomplete(document.getElementById('googlesuggest'), { | |
types: ['geocode'] | |
}); | |
autocomplete.addListener('place_changed', () => { | |
let place = autocomplete.getPlace(); | |
if (place.id) { | |
const location = place.geometry.location; | |
this.initPosition = {lat: location.lat(), lng: location.lng()}; | |
this.map.setCenter(this.initPosition); | |
} | |
}); | |
} else { | |
this.drawMap(); | |
} | |
}, | |
fbSearch: debounce(function () { | |
this.fbSearchPlaces(); | |
}, 500), | |
fbSearchPlaces () { | |
if (this.$refs.placesinput && this.$refs.placesinput.value.length >= 2) { | |
this.timer = new Date().getTime(); | |
const query = this.$refs.placesinput.value; | |
let distance = parseInt(156543.03392 * Math.cos(this.map.getCenter().lat() * Math.PI / 180) / Math.pow(2, this.map.getZoom()) * 250, 10); | |
if (distance < 350) distance = 350; | |
const payload = { | |
cookies: this.account.cookies, | |
proxy: this.$store.getters['user/currentAccountProxy'], | |
query, | |
lat: this.map.getCenter().lat(), | |
lng: this.map.getCenter().lng(), | |
}; | |
this.$store.dispatch('services/fbSearch', payload).then(result => { | |
const places = result; | |
this.fbWindows.forEach(item => item.close()); | |
this.fbWindows = []; | |
this.fbgeofound = []; | |
let minLat = this.map.getCenter().lat(); | |
let maxLat = this.map.getCenter().lat(); | |
let minLng = this.map.getCenter().lng(); | |
let maxLng = this.map.getCenter().lng(); | |
this.mapPoints = {}; | |
places.map(item => { | |
const {mediaBundles, subtitle, ...rest} = item; | |
return rest; | |
}).forEach(place => { | |
if (place && place.lat && place.lng && place.title) { | |
this.mapPoints[String(place.id)] = place; | |
let infowindow = new this.google.maps.InfoWindow({ | |
content: `<div class="place-iw" data-id="${place.id}">${place.title}, ${place.address}</div>`, | |
position: {lat: place.lat, lng: place.lng}, | |
disableAutoPan: true, | |
}); | |
this.fbgeofound.push(place); | |
infowindow.open(this.map); | |
this.fbWindows.push(infowindow); | |
} | |
}); | |
}); | |
} | |
}, | |
handleEmojiPicker (emoji) { | |
this.text += emoji; | |
}, | |
setAspectRatio (ratio) { | |
this.aspectRatio = ratio; | |
this.cropper.setAspectRatio(ratio); | |
}, | |
cancelEditMode () { | |
this.text = ''; | |
this.finalImages = []; | |
this.timezone = 'Europe/Moscow'; | |
this.datetime = ''; | |
this.datedel = ''; | |
this.isDelete = false; | |
this.deletenum = 1; | |
this.deleteRange = 'minutes'; | |
this.firebaseId = null; | |
this.editMode = false; | |
this.selectedGeo = {}; | |
this.clearPostInfo(); | |
}, | |
declOfNum (number, titles) { | |
const cases = [2, 0, 1, 1, 1, 2]; | |
return titles[(number % 100 > 4 && number % 100 < 20) ? 2 : cases[(number % 10 < 5) ? number % 10 : 5]]; | |
}, | |
onFileChange (e) { | |
const files = e.target.files || e.dataTransfer.files; | |
if (!files.length) | |
return; | |
if (files[0].type.indexOf('video') !== -1) { | |
this.createVideo(files[0]); | |
} else { | |
this.createImage(files[0]) | |
} | |
}, | |
createVideo (file) { | |
const video = URL.createObjectURL(file); | |
if (this.stories) { | |
this.aspectRatio = 9 / 16; | |
} | |
let $video = document.getElementById('t-video'); | |
$video.src = video; | |
$video.oncanplay = () => { | |
let $canvas = document.getElementById('t-canvas'); | |
$canvas.width = $video.videoWidth; | |
$canvas.height = $video.videoHeight; | |
$canvas.getContext('2d').drawImage($video, 0, 0, $video.videoWidth, $video.videoHeight); | |
base64 = $canvas.toDataURL('image/png'); | |
this.video.file = file; | |
this.$refs.myModalRef.show(); | |
URL.revokeObjectURL(video); | |
}; | |
}, | |
createImage (file) { | |
if (this.stories) { | |
this.aspectRatio = 9 / 16; | |
} | |
const reader = new FileReader(); | |
reader.onload = (e) => { | |
base64 = e.target.result; | |
this.$refs.myModalRef.show(); | |
}; | |
reader.readAsDataURL(file) | |
}, | |
removeImage: function (index) { | |
this.finalImages.splice(index, 1); | |
if (!this.finalImages.length) { | |
this.aspectRatio = 1; | |
} | |
}, | |
savePost () { | |
if (this.hashtags < 0) { | |
this.$swal('Ошибка!', 'Колличество хэштегов должно быть не больше 30', 'error'); | |
return; | |
} | |
this.saveProcess = true; | |
let task = {}; | |
task.datetime = Date.parse(this.datetime); | |
if (this.isDelete && this.deletenum) { | |
let deletePlus = {}; | |
deletePlus[this.deleteRange] = this.deletenum; | |
let deleteTimeFinal = DateTime.fromISO(this.datetime).plus(deletePlus); | |
task.datedel = Date.parse(deleteTimeFinal.toISO()); | |
task.deletenum = this.deletenum; | |
task.deleteRange = this.deleteRange; | |
} | |
if (this.stories) { | |
task.is_stories = true; | |
} | |
if (this.selectedGeo.title) { | |
task.location = this.selectedGeo.location; | |
} else { | |
task.location = null; | |
} | |
task.text = this.text.replace(/(?:\r\n|\r|\n)/g, '⠀\n'); | |
task.timezone = this.timezone; | |
task.media = this.finalImages; | |
axios.post(config.autopostingApiUrl + '/api/create-task', { | |
task: task, | |
user: { | |
id: this.userId, | |
accountKey: this.accountKey | |
} | |
}).then((res) => { | |
this.saveProcess = false; | |
this.$swal('Отлично!', this.stories ? 'Сторис запланирован' : 'Ваш пост сохранен', 'success'); | |
let task = res.data; | |
if (!this.editMode) { | |
this.$store.dispatch('user/addTask', {task, accountKey: this.accountKey}).then(() => { | |
console.log('add task!'); | |
}).catch(e => { | |
console.log(error); | |
}); | |
} else { | |
this.$store.dispatch('user/updateTask', { | |
task, | |
taskKey: this.firebaseId, | |
accountKey: this.accountKey | |
}).then(() => { | |
console.log('add task!'); | |
}).catch(e => { | |
console.log(error); | |
}); | |
} | |
this.datetime = ''; | |
this.datedel = ''; | |
this.formData = new FormData(); | |
this.finalImages = []; | |
this.text = ''; | |
this.deleteRange = 'minutes'; | |
this.deletenum = 1; | |
this.isDelete = false; | |
this.editMode = false; | |
this.deleteGeo(); | |
this.clearPostInfo(); | |
}).catch((e) => { | |
this.saveProcess = false; | |
console.error(e); | |
}) | |
}, | |
saveImage () { | |
this.$refs.myModalRef.hide(); | |
let photoForm = new FormData(); | |
fetch(this.filteredImage) | |
.then(res => res.blob()) | |
.then(blob => { | |
photoForm.append('photo', blob); | |
this.finalImagesLoading = true; | |
axios.post(config.autopostingApiUrl + '/api/crop-photo', photoForm) | |
.then((res) => { | |
this.finalImages.push(res.data); | |
this.finalImagesLoading = false; | |
}) | |
.catch(() => { | |
this.finalImagesLoading = false; | |
}) | |
}) | |
}, | |
clearPostInfo () { | |
document.getElementById('exampleFormControlFile1').value = ''; | |
this.croppedImage = ''; | |
this.filteredImage = ''; | |
if (typeof this.cropper.destroy === 'function') { | |
this.cropper.destroy(); | |
} | |
this.cropper = {}; | |
if (!this.finalImages.length && !this.finalImagesLoading) { | |
this.aspectRatio = 1; | |
} | |
}, | |
modalHide () { | |
this.uploadStep = 1; | |
this.clearPostInfo(); | |
}, | |
modalShow () { | |
setTimeout(() => { | |
const image = document.getElementById('croppr'); | |
let settings = {}; | |
settings.viewMode = 1; | |
settings.aspectRatio = this.aspectRatio; | |
image.src = base64; | |
this.cropper = new Cropper(image, settings); | |
}, 500) | |
}, | |
cropImage () { | |
if (this.video.file) { | |
this.cropVideoOnServer(this.cropper.getData()); | |
this.$refs.myModalRef.hide(); | |
} else { | |
this.croppedImage = this.cropper.getCroppedCanvas().toDataURL('image/png'); | |
this.uploadStep = 2; | |
setTimeout(() => { | |
this.applyFilter('normal'); | |
}, 100); | |
} | |
}, | |
cropVideoOnServer (cropData) { | |
let videoFormData = new FormData(); | |
videoFormData.append('video', this.video.file); | |
for (let key in cropData) { | |
videoFormData.append(key, cropData[key]); | |
} | |
this.finalImagesLoading = true; | |
axios.post(config.autopostingApiUrl + '/api/crop-video', videoFormData) | |
.then((res) => { | |
this.finalImages.push(res.data); | |
this.video = {}; | |
base64 = ''; | |
this.finalImagesLoading = false; | |
}) | |
.catch(() => { | |
this.finalImagesLoading = false; | |
}) | |
}, | |
applyFilter (filter) { | |
const imageDOM = document.getElementById('image-filter'); | |
let imgObj = new Image(); | |
imgObj.src = this.croppedImage; | |
let filteredImage = filterous.importImage(imgObj, {}) | |
.applyInstaFilter(filter) | |
.renderHtml(imageDOM); | |
this.filteredImage = filteredImage.canvas.toDataURL(); | |
} | |
} | |
} | |
</script> | |
<style scoped lang="stylus"> | |
$desktopSm = 1024px | |
$tablet = 880px | |
$tabletSm = 768px | |
#circularG { | |
margin-right: 10px | |
} | |
.count-badge { | |
background-color: #ff8c00; | |
color: white; | |
font-weight: bold | |
padding 5px 10px | |
border-radius 3px | |
} | |
.count-badge-wrap { | |
&__item { | |
display: block | |
margin-bottom 20px | |
@media (max-width: $tabletSm) { | |
margin-top 15px | |
} | |
} | |
} | |
.crop-alert { | |
margin-bottom 10px; | |
} | |
.add-task-bottom { | |
.t-button { | |
min-width 90px | |
} | |
@media (max-width: $tabletSm) { | |
.t-button { | |
width 100% | |
} | |
} | |
.form-inline { | |
flex-wrap wrap | |
@media (max-width: $tabletSm) { | |
margin-bottom 20px | |
justify-content space-between | |
} | |
} | |
.t-select { | |
width auto | |
} | |
} | |
.controls-mobile { | |
display none | |
@media (max-width: $tabletSm) { | |
display block | |
.post-text_mobile { | |
border-radius 3px; | |
height: 150px | |
margin-bottom 10px | |
} | |
.form-group:nth-child(2) { | |
margin-bottom 10px | |
} | |
} | |
} | |
.preview-photos { | |
display: flex; | |
align-items: center; | |
flex-wrap: wrap; | |
padding-top 30px; | |
padding-bottom: 30px | |
@media (max-width: $tablet) { | |
padding-top 20px; | |
padding-bottom: 10px | |
} | |
@media (max-width: $tabletSm) { | |
padding-top 10px | |
} | |
.add-task-image-wrap { | |
border-radius: 3px; | |
margin-right: 10px; | |
margin-bottom: 10px; | |
width: 100px; | |
height: 100px | |
overflow hidden | |
@media (max-width: $desktopSm) { | |
width: calc(16.9vw - 10px) | |
height: calc(16.9vw - 10px) | |
} | |
@media (max-width: $tablet) { | |
width: 15.1vw | |
height: 15.1vw | |
&:nth-child(5n) { | |
margin-right 0 | |
} | |
} | |
@media (max-width: $tabletSm) { | |
width: 35.3vw; | |
height: 35.3vw | |
&:nth-child(5) { | |
margin-right 10px | |
} | |
&:nth-child(2n) { | |
margin-right 0 | |
} | |
} | |
&__content { | |
width: 100% | |
height 100% | |
background-size: cover | |
background-position: center | |
background-color: #f3f3f3 | |
} | |
img { | |
width: 100%; | |
} | |
video { | |
height: 100% | |
} | |
} | |
} | |
.filter-btn { | |
margin-bottom: 5px; | |
@media (max-width: $tablet) { | |
min-height: 30px; | |
} | |
} | |
.image-filter-wrap { | |
text-align: center; | |
margin-top: 15px; | |
} | |
.cropped-image { | |
max-width: 100%; | |
max-height: 300px; | |
} | |
.add-task-image { | |
max-height: 300px; | |
&__delete { | |
position: absolute; | |
right: 5px; | |
top: 5px; | |
cursor: pointer; | |
border-radius: 3px; | |
border: none; | |
font-size: 20px; | |
line-height: normal; | |
padding: 0 5px; | |
color: #989898; | |
span { | |
position: relative; | |
top: -1px; | |
} | |
} | |
} | |
.add-task-video { | |
max-height: 300px; | |
min-width: 100%; | |
} | |
.add-task-image-wrap { | |
text-align: center; | |
position: relative; | |
} | |
.inst-ava { | |
width: 50px; | |
border-radius: 50%; | |
margin-right: 15px; | |
} | |
.post-info { | |
width 100% | |
} | |
.post-text { | |
border-radius 3px; | |
height: 250px | |
padding-right: 50px | |
margin-bottom: 10px | |
@media (max-width: $tablet) { | |
display none | |
} | |
} | |
.upload-file { | |
@media (max-width: $tablet) { | |
width 100% | |
} | |
input[type="file"] { | |
display: none; | |
} | |
label { | |
width: 100%; | |
} | |
&__icon { | |
max-width: 80px | |
} | |
&__drop { | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
width: 250px | |
height: 250px | |
border-radius: 3px; | |
border: 1px dashed #CECECE; | |
margin-right: 30px | |
flex-wrap: wrap; | |
padding: 30px | |
position relative | |
@media (max-width: $tablet) { | |
width 100% | |
} | |
@media (max-width: $tabletSm) { | |
height 150px | |
} | |
&-zone { | |
position absolute | |
left: 0 | |
right: 0 | |
top: 0 | |
bottom: 0 | |
} | |
&-img { | |
} | |
&-title { | |
width: 100% | |
text-align: center | |
font-size: 14px | |
color: #989898 | |
margin-top: 18px | |
@media (max-width: $tablet) { | |
display none | |
} | |
} | |
&-or { | |
width 100% | |
text-align: center | |
font-size: 14px | |
color: #D8D8D8 | |
margin-top: 15px | |
display flex | |
align-items center | |
@media (max-width: $tablet) { | |
display none | |
} | |
&:before { | |
display block | |
content: '' | |
height 1px | |
width 100% | |
background-color #EBEBEB | |
margin-right: 5px | |
} | |
&:after { | |
display block | |
content: '' | |
height 1px | |
width 100% | |
background-color #EBEBEB | |
margin-left: 5px | |
} | |
} | |
&-btn { | |
min-height: 40px | |
min-width: 180px | |
margin-top: 15px | |
@media (max-width: $tablet) { | |
min-height: 30px | |
width 100% | |
} | |
} | |
&.higlight { | |
background-color #F8FAFF | |
border-color #4680FE | |
.upload-file__drop-title { | |
color #000000 | |
margin-top 0 | |
} | |
rder-color #4680FE | |
.upload-file__icon { | |
margin-top 0 | |
margin-bottom -60px | |
@media (max-width: $tablet) { | |
margin-bottom 0 | |
} | |
} | |
} | |
} | |
&.disabled { | |
pointer-events: none; | |
.upload-file__drop { | |
cursor: not-allowed; | |
pointer-events: none; | |
border: 1px solid lightgray; | |
color: lightgray; | |
} | |
} | |
&._full { | |
width: 100% | |
.upload-file__drop { | |
width 100% | |
} | |
} | |
} | |
#croppr { | |
max-width: 100%; | |
} | |
.delete-num { | |
max-width: 80px; | |
} | |
.add-task-form { | |
display flex | |
justify-content space-between | |
&__emoji { | |
position: absolute; | |
background: #fff; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
color: #989898; | |
font-size: 20px; | |
width: 40px; | |
height: 40px; | |
right: 10px; | |
bottom: 10px; | |
@media (max-width: $tabletSm) { | |
bottom 20px | |
} | |
.emoji-picker { | |
position: absolute; | |
width: 100%; | |
height: 100%; | |
cursor: pointer; | |
} | |
} | |
&__text-wrap { | |
position relative | |
display flex | |
width 100% | |
max-height 250px | |
margin-bottom 10px | |
@media (max-width: $tabletSm) { | |
display none | |
} | |
&._mobile { | |
@media (max-width: $tabletSm) { | |
display block | |
} | |
} | |
} | |
&__left { | |
display: flex; | |
width: 100%; | |
justify-content: space-between; | |
margin-right: 30px | |
@media (max-width: $tablet) { | |
width 50% | |
} | |
@media (max-width: $tabletSm) { | |
width: 100% | |
margin-right 0 | |
flex-wrap wrap | |
} | |
} | |
&__right { | |
color: #585858 | |
@media (max-width: $tablet) { | |
width 50% | |
} | |
@media (max-width: $tabletSm) { | |
display none | |
} | |
.form-group { | |
margin-bottom 10px | |
} | |
.t-select__select { | |
margin-top: 5px | |
} | |
} | |
} | |
.post-info { | |
width 100% | |
} | |
.geo-button { | |
height 50px | |
border 1px solid #D2D2D2 | |
border-radius 3px | |
padding 13px 18px | |
display flex | |
justify-content center | |
align-items center | |
color #989898 | |
margin-left 20px | |
cursor pointer | |
position relative | |
&__icon { | |
width 15px | |
margin-left 10px | |
} | |
&__close { | |
width: 30px; | |
height: 30px; | |
background: lightgrey; | |
text-align: center; | |
position: absolute; | |
right: -10px; | |
top: -10px; | |
font-size: 18px; | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
z-index: 1; | |
border-radius: 3px; | |
padding-top: 1px; | |
} | |
span { | |
max-width 150px | |
overflow hidden | |
display block | |
word-break break-all | |
white-space pre | |
} | |
} | |
</style> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment