@ -1,197 +1,234 @@
< template >
< div >
< input type = "file" name= "media" class = " d-none file-input" multiple= " " v -bind :accept ="config.uploader.media_types" >
< input type = "file" id= "pf-dz" name= "media" class = " w-100 h-100 d-none file-input" draggable= "true" multiple= " true " v -bind :accept ="config.uploader.media_types" >
< div class = "timeline" >
< div class = "card status-card card-md-rounded-0 ">
< div class = "card status-card card-md-rounded-0 w-100 h-100" style = "display:flex; ">
< div class = "card-header d-inline-flex align-items-center bg-white" >
< img v -bind :src ="profile.avatar" width = "32px" height = "32px" style = "border-radius: 32px;" class = "box-shadow" >
< a class = "username font-weight-bold pl-2 text-dark" v -bind :href ="profile.url" >
{ { profile . username } }
< / a >
< div >
< a v-if ="page == 1" href="#" @click.prevent="closeModal()" class="font-weight-bold text-decoration-none text-muted" >
< i class = "fas fa-times fa-lg" > < / i >
< span class = "font-weight-bold mb-0" > { { pageTitle } } < / span >
< / a >
< span v-else >
< span >
< a class = "text-lighter text-decoration-none mr-3" href = "#" @click.prevent ="goBack()" > < i class = "fas fa-long-arrow-alt-left fa-lg" > < / i > < / a >
< / span >
< span class = "font-weight-bold mb-0" > { { pageTitle } } < / span >
< / span >
< / div >
< div class = "text-right" style = "flex-grow:1;" >
< div class = "dropdown" >
< button class = "btn btn-link text-dark no-caret dropdown-toggle" type = "button" data -toggle = " dropdown " aria -haspopup = " true " aria -expanded = " false " title = "Post options" >
< span class = "fas fa-ellipsis-v fa-lg text-muted" > < / span >
< / button >
< div class = "dropdown-menu dropdown-menu-right" aria -labelledby = " dropdownMenuButton " >
< div class = "dropdown-item small font-weight-bold" v -on :click ="createCollection" > Create Collection < / div >
< div class = "dropdown-divider" > < / div >
< div class = "dropdown-item small font-weight-bold" v -on :click ="about" > About < / div >
< div class = "dropdown-item small font-weight-bold" v -on :click ="closeModal" > Close < / div >
<!-- < a v-if ="page > 1" class="font-weight-bold text-decoration-none" href="#" @click.prevent="page--" > Back < / a > - - >
< span v-if ="pageLoading" >
< div class = "spinner-border spinner-border-sm" role = "status" >
< span class = "sr-only" > Loading ... < / span >
< / div >
< / div >
< / span >
< a v-if ="!pageLoading && (page > 1 && page <= 3) || (page == 1 && ids.length != 0)" class="font-weight-bold text-decoration-none" href="#" @click.prevent="nextPage" > Next < / a >
< a v-if ="!pageLoading && page == 4" class="font-weight-bold text-decoration-none" href="#" @click.prevent="compose" > Post < / a >
< / div >
< / div >
< div class = "postPresenterContainer" >
< div v-if ="uploading" >
< div class = "w-100 h-100 bg-light py-5" style = "border-bottom: 1px solid #f1f1f1" >
< div class = "p-5" >
< b -progress :value ="uploadProgress" :max ="100" striped :animated ="true" > < / b - p r o g r e s s >
< p class = "text-center mb-0 font-weight-bold" > Uploading ... ( { { uploadProgress } } % ) < / p >
< / div >
< div class = "card-body p-0 border-top" >
< div v-if ="page == 1" class="w-100 h-100 d-flex justify-content-center align-items-center" style="min-height: 400px;" >
< div class = "text-center" >
< p >
< a class = "btn btn-primary font-weight-bold" href = "/i/compose" > Compose Post < / a >
< / p >
< hr >
< p >
< button type = "button" class = "btn btn-outline-primary font-weight-bold" @click.prevent ="addMedia" > Compose Post < sup > BETA < / sup > < / button >
< / p >
< p >
< button class = "btn btn-outline-primary font-weight-bold" @click.prevent ="createCollection" > New Collection < / button >
< / p >
<!-- < p >
< button class = "btn btn-outline-primary font-weight-bold" @click.prevent ="showAddToStoryCard()" > Add To My Story < / button >
< / p > -- >
< p >
< a class = "font-weight-bold" href = "/site/help" > Need Help ? < / a >
< / p >
< p class = "text-muted mb-0 small text-center" > Formats : < b > { { acceptedFormats ( ) } } < / b > up to < b > { { maxSize ( ) } } < / b > < / p >
< p class = "text-muted mb-0 small text-center" > Albums can contain up to < b > { { config . uploader . album _limit } } < / b > photos or videos < / p >
< / div >
< / div >
< div v-else >
< div v-if ="ids.length > 0 && ids.length != config.uploader.album_limit" class="card-header py-2 bg-primary m-2 rounded cursor-pointer" v-on:click="addMedia($event)" >
< p class = "text-center mb-0 font-weight-bold text-white" > < i class = "fas fa-plus mr-1" > < / i > Add Photo < / p >
< / div >
< div v-if ="ids.length == 0" class="w-100 h-100 bg-light py-5 cursor-pointer" style="border-bottom: 1px solid #f1f1f1" v-on:click="addMedia($event)" >
< div class = "p-5" >
< p class = "text-center font-weight-bold" > { { composeMessage ( ) } } < / p >
< p class = "text-muted mb-0 small text-center" > Accepted Formats : < b > { { acceptedFormats ( ) } } < / b > < / p >
< p class = "text-muted mb-0 small text-center" > Max File Size : < b > { { maxSize ( ) } } < / b > < / p >
< p class = "text-muted mb-0 small text-center" > Albums can contain up to < b > { { config . uploader . album _limit } } < / b > photos or videos < / p >
< / div >
< / div >
< div v-if ="page == 2" class="w-100 h-100" >
< div v-if ="ids.length > 0" >
< b -carousel id = "p-carousel "
style = "text-shadow: 1px 1px 2px #333; "
controls
indicators
background = "#ffffff "
: interval= "0 "
v - model = "carouselCursor "
< vue -cropper
ref = "cropper"
: relativeZoom = "cropper.zoom"
: aspectRatio = "cropper.aspectRatio"
: viewMode = "cropper.viewMode"
: zoomable = "cropper.zoomable"
: rotatable = "true"
: src = "media[0].url"
>
< b -carousel -slide v-if ="ids.length > 0" v-for="(preview, index) in media" :key="'preview_media_'+index" >
< div slot = "img" :class ="[media[index].filter_class?media[index].filter_class:'']" style = "display:flex;min-height: 320px;align-items: center;" >
< img class = "d-block img-fluid w-100" :src ="preview.url" :alt ="preview.description" :title ="preview.description" >
< / div >
< / b - c a r o u s e l - s l i d e >
< / b - c a r o u s e l >
< / v u e - c r o p p e r >
< / div >
< / div >
< div v-if ="page == 3" class="w-100 h-100" >
< div slot = "img" style = "display:flex;min-height: 420px;align-items: center;" >
< img : class = "'d-block img-fluid w-100 ' + [media[carouselCursor].filter_class?media[carouselCursor].filter_class:'']" :src ="media[carouselCursor].url" :alt ="media[carouselCursor].description" :title ="media[carouselCursor].description" >
< / div >
< div v-if ="ids.length > 0 && media[carouselCursor].type == 'Image'" class="bg-dark align-items-center" >
< hr >
< div v-if ="ids.length > 0 && media[carouselCursor].type == 'Image'" class="align-items-center px-2 pt-2" >
< ul class = "nav media-drawer-filters text-center" >
< li class = "nav-item" >
< div class = "p-1 pt-3" >
< img :src ="media[carouselCursor].url" width = "100px" height = "60px" v -on : click.prevent = " toggleFilter ( $ event , null ) " class = "cursor-pointer" >
< / div >
< a : class = "[media[carouselCursor].filter_class == null ? 'nav-link text- white active' : 'nav-link text-muted']" href = "#" v -on : click.prevent = " toggleFilter ( $ event , null ) " > No Filter < / a >
< a : class = "[media[carouselCursor].filter_class == null ? 'nav-link text- primary active' : 'nav-link text-muted']" href = "#" v -on : click.prevent = " toggleFilter ( $ event , null ) " > No Filter < / a >
< / li >
< li class = "nav-item" v-for ="(filter, index) in filters" >
< div class = "p-1 pt-3" >
< img :src ="media[carouselCursor].url" width = "100px" height = "60px" :class ="filter[1]" v -on : click.prevent = " toggleFilter ( $ event , filter [ 1 ] ) " >
< / div >
< a : class = "[media[carouselCursor].filter_class == filter[1] ? 'nav-link text- white active' : 'nav-link text-muted']" href = "#" v -on : click.prevent = " toggleFilter ( $ event , filter [ 1 ] ) " > { { filter [ 0 ] } } < / a >
< a : class = "[media[carouselCursor].filter_class == filter[1] ? 'nav-link text- primary active' : 'nav-link text-muted']" href = "#" v -on : click.prevent = " toggleFilter ( $ event , filter [ 1 ] ) " > { { filter [ 0 ] } } < / a >
< / li >
< / ul >
< / div >
< / div >
< div v-if ="ids.length > 0 && ['Image', 'Video'].indexOf(media[carouselCursor].type) != -1" class="bg-lighter p-2 row" >
< div v-if ="media[carouselCursor].type == 'Image'" class="col-12" >
< div class = "form-group" >
< input type = "text" class = "form-control" v-model ="media[carouselCursor].alt" placeholder="Optional image description" >
< / div >
< div class = "form-group" >
< input type = "text" class = "form-control" v-model ="media[carouselCursor].license" placeholder="Optional media license" >
< div v-if ="page == 4" class="w-100 h-100" >
< div class = "border-bottom mt-2" >
< div class = "media px-3" >
< img :src ="media[0].url" width = "42px" height = "42px" : class = "[media[0].filter_class?'mr-2 ' + media[0].filter_class:'mr-2']" >
< div class = "media-body" >
< div class = "form-group" >
< label class = "font-weight-bold text-muted small d-none" > Caption < / label >
< textarea class = "form-control border-0 rounded-0 no-focus" rows = "2" placeholder = "Write a caption..." style = "resize:none" v-model ="composeText" > < / textarea >
< / div >
< / div >
< / div >
< / div >
<!-- < div class = "col-6 pt-2" >
< button class = "btn btn-outline-secondary btn-sm mr-1" > < i class = "fas fa-map-marker-alt" > < / i > < / button >
< button class = "btn btn-outline-secondary btn-sm" > < i class = "fas fa-tools" > < / i > < / button >
< / div > -- >
< div class = "col-12 text-right pt-2" >
< button class = "btn btn-outline-danger btn-sm font-weight-bold mr-1" v -on :click ="deleteMedia()" > Delete Media < / button >
< div class = "border-bottom" >
< p class = "px-4 mb-0 py-2 cursor-pointer" @click ="showTagCard()" > Tag people < / p >
< / div >
< div class = "border-bottom" >
< p class = "px-4 mb-0 py-2 cursor-pointer" @click ="showLocationCard()" v-if ="!place" > Add location < / p >
< p v -else class = "px-4 mb-0 py-2" >
< span class = "text-lighter" > Location : < / span > { { place . name } } , { { place . country } }
< span class = "float-right" >
< a href = "#" @click.prevent ="showLocationCard()" class = "text-muted font-weight-bold small mr-2" > Change < / a >
< a href = "#" @ click.prevent = " place = false " class = "text-muted font-weight-bold small" > Remove < / a >
< / span >
< / p >
< / div >
< div class = "border-bottom" >
< p class = "px-4 mb-0 py-2" >
< span class = "text-lighter" > Visibility : < / span > { { visibilityTag } }
< span class = "float-right" >
< a href = "#" @click.prevent ="showVisibilityCard()" class = "text-muted font-weight-bold small mr-2" > Change < / a >
< / span >
< / p >
< / div >
< div style = "min-height: 200px;" >
< p class = "px-4 mb-0 py-2 small font-weight-bold text-muted cursor-pointer" @click ="showAdvancedSettingsCard()" > Advanced settings < / p >
< / div >
< / div >
< / div >
< div class = "card-body p-0 border-top" >
< div class = "caption" >
< textarea class = "form-control mb-0 border-0 rounded-0" rows = "3" placeholder = "Add an optional caption" v-model ="composeText" > < / textarea >
< div v-if ="page == 'tagPeople'" class="w-100 h-100 p-3" >
< p class = "text-center lead text-muted mb-0 py-5" > This feature is not available yet . < / p >
< / div >
< div v-if ="page == 'addLocation'" class="w-100 h-100 p-3" >
< p class = "mb-0" > Add Location < / p >
< autocomplete
: search = "locationSearch"
placeholder = "Search locations ..."
aria - label = "Search locations ..."
: get - result - value = "getResultValue"
@ submit = "onSubmitLocation"
>
< / autocomplete >
< / div >
< / div >
< div class = "card-footer" >
< div class = "d-flex justify-content-between align-items-center" >
< div >
< div class = "custom-control custom-switch d-inline mr-3" >
< input type = "checkbox" class = "custom-control-input" id = "nsfwToggle" v-model ="nsfw" >
< label class = "custom-control-label small font-weight-bold text-muted pt-1" for = "nsfwToggle" > NSFW < / label >
< div v-if ="page == 'advancedSettings'" class="w-100 h-100" >
< div class = "list-group list-group-flush" >
< div class = "list-group-item d-flex justify-content-between" >
< div >
< div class = "text-dark " > Turn off commenting < / div >
< p class = "text-muted small mb-0" > Disables comments for this post , you can change this later . < / p >
< / div >
< div >
< div class = "custom-control custom-switch" style = "z-index: 9999;" >
< input type = "checkbox" class = "custom-control-input" id = "asdisablecomments" v-model ="commentsDisabled" >
< label class = "custom-control-label" for = "asdisablecomments" > < / label >
< / div >
< / div >
< / div >
< div class = "dropdown d-inline" >
< button class = "btn btn-outline-secondary btn-sm py-0 dropdown-toggle" type = "button" id = "visibility" data -toggle = " dropdown " aria -haspopup = " true " aria -expanded = " false " >
{ { visibility [ 0 ] . toUpperCase ( ) + visibility . slice ( 1 ) } }
< / button >
< div class = "dropdown-menu" aria -labelledby = " visibility " style = "width: 200px;" >
< a : class = "[visibility=='public'?'dropdown-item active':'dropdown-item']" href = "#" data -id = " public " data -title = " Public " v -on : click.prevent = " visibility = 'public' " >
< div class = "row" >
< div class = "d-none d-block-sm col-sm-2 px-0 text-center" >
< i class = "fas fa-globe" > < / i >
< / div >
< div class = "col-12 col-sm-10 pl-2" >
< p class = "font-weight-bold mb-0" > Public < / p >
< p class = "small mb-0" > Anyone can see < / p >
< / div >
< / div >
< / a >
< a : class = "[visibility=='private'?'dropdown-item active':'dropdown-item']" href = "#" data -id = " private " data -title = " Followers Only " v -on : click.prevent = " visibility = 'private' " >
< div class = "row" >
< div class = "d-none d-block-sm col-sm-2 px-0 text-center" >
< i class = "fas fa-lock" > < / i >
< / div >
< div class = "col-12 col-sm-10 pl-2" >
< p class = "font-weight-bold mb-0" > Followers Only < / p >
< p class = "small mb-0" > Only followers can see < / p >
< / div >
< / div >
< / a >
< a : class = "[visibility=='unlisted'?'dropdown-item active':'dropdown-item']" href = "#" data -id = " private " data -title = " Unlisted " v -on : click.prevent = " visibility = 'unlisted' " >
< div class = "row" >
< div class = "d-none d-block-sm col-sm-2 px-0 text-center" >
< i class = "fas fa-lock" > < / i >
< / div >
< div class = "col-12 col-sm-10 pl-2" >
< p class = "font-weight-bold mb-0" > Unlisted < / p >
< p class = "small mb-0" > Not listed on public timelines < / p >
< / div >
< / div >
< / a >
<!-- < a class = "dropdown-item" href = "#" data -id = " circle " data -title = " Circle " >
< div class = "row" >
< div class = "col-12 col-sm-2 px-0 text-center" >
< i class = "far fa-circle" > < / i >
< / div >
< div class = "col-12 col-sm-10 pl-2" >
< p class = "font-weight-bold mb-0" > Circle < / p >
< p class = "small mb-0" > Select a circle < / p >
< / div >
< / div >
< / a >
< a class = "dropdown-item" href = "#" data -id = " direct " data -title = " Direct Message " >
< div class = "row" >
< div class = "col-12 col-sm-2 px-0 text-center" >
< i class = "fas fa-envelope" > < / i >
< / div >
< div class = "col-12 col-sm-10 pl-2" >
< p class = "font-weight-bold mb-0" > Direct Message < / p >
< p class = "small mb-0" > Recipients only < / p >
< / div >
< / div >
< / a > -- >
< div class = "list-group-item d-flex justify-content-between" >
< div >
< div class = "text-dark " > Contains NSFW Media < / div >
< / div >
< div >
< div class = "custom-control custom-switch" style = "z-index: 9999;" >
< input type = "checkbox" class = "custom-control-input" id = "asnsfw" v-model ="nsfw" >
< label class = "custom-control-label" for = "asnsfw" > < / label >
< / div >
< / div >
< / div >
< a class = "list-group-item" @ click.prevent = " page = 'altText' " >
< div class = "text-dark" > Write alt text < / div >
< p class = "text-muted small mb-0" > Alt text describes your photos for people with visual impairments . < / p >
< / a >
< a href = "#" class = "list-group-item" @ click.prevent = " page = 'addToCollection' " >
< div class = "text-dark" > Add to Collection < / div >
< p class = "text-muted small mb-0" > Add this post to a collection . < / p >
< / a >
< a href = "#" class = "list-group-item" @ click.prevent = " page = 'schedulePost' " >
< div class = "text-dark" > Schedule < / div >
< p class = "text-muted small mb-0" > Schedule post for a future date . < / p >
< / a >
< a href = "#" class = "list-group-item" @ click.prevent = " page = 'mediaMetadata' " >
< div class = "text-dark" > Metadata < / div >
< p class = "text-muted small mb-0" > Manage media exif and metadata . < / p >
< / a >
< / div >
< div class = "small text-muted font-weight-bold" >
{ { composeText . length } } / { { config . uploader . max _caption _length } }
< / div >
< div v-if ="page == 'visibility'" class="w-100 h-100" >
< div class = "list-group list-group-flush" >
< div : class = "'list-group-item lead cursor-pointer ' + [visibility == 'public'?'text-primary':'']" @click ="toggleVisibility('public')" > Public < / div >
< div : class = "'list-group-item lead cursor-pointer ' + [visibility == 'unlisted'?'text-primary':'']" @click ="toggleVisibility('unlisted')" > Unlisted < / div >
< div : class = "'list-group-item lead cursor-pointer ' + [visibility == 'private'?'text-primary':'']" @click ="toggleVisibility('private')" > Followers Only < / div >
< / div >
< div class = "pl-md-5" >
<!-- < div class = "btn-group" >
< button type = "button" class = "btn btn-primary btn-sm font-weight-bold" v -on :click ="compose()" > { { composeState [ 0 ] . toUpperCase ( ) + composeState . slice ( 1 ) } } < / button >
< button type = "button" class = "btn btn-primary btn-sm dropdown-toggle dropdown-toggle-split" data -toggle = " dropdown " aria -haspopup = " true " aria -expanded = " false " >
< span class = "sr-only" > Toggle Dropdown < / span >
< / button >
< div class = "dropdown-menu dropdown-menu-right" >
< a : class = "[composeState == 'publish' ?'dropdown-item font-weight-bold active':'dropdown-item font-weight-bold ']" href = "#" v -on : click.prevent = " composeState = 'publish' " > Publish now < / a >
< ! - - < a : class = "[composeState == 'draft' ?'dropdown-item font-weight-bold active':'dropdown-item font-weight-bold ']" href = "#" v -on : click.prevent = " composeState = 'draft' " > Save as draft < / a >
< a : class = "[composeState == 'schedule' ?'dropdown-item font-weight-bold active':'dropdown-item font-weight-bold ']" href = "#" v -on : click.prevent = " composeState = 'schedule' " > Schedule for later < / a >
< div class = "dropdown-divider" > < / div >
< a : class = "[composeState == 'delete' ?'dropdown-item font-weight-bold active':'dropdown-item font-weight-bold ']" href = "#" v -on : click.prevent = " composeState = 'delete' " > Delete < / a > - - >
< / div >
< / div > -- >
< button class = "btn btn-primary btn-sm font-weight-bold px-3" v -on :click ="compose()" > Publish < / button >
< / div >
< div v-if ="page == 'altText'" class="w-100 h-100 p-3" >
< p class = "text-center lead text-muted mb-0 py-5" > This feature is not available yet . < / p >
< / div >
< div v-if ="page == 'addToCollection'" class="w-100 h-100 p-3" >
< p class = "text-center lead text-muted mb-0 py-5" > This feature is not available yet . < / p >
< / div >
< div v-if ="page == 'schedulePost'" class="w-100 h-100 p-3" >
< p class = "text-center lead text-muted mb-0 py-5" > This feature is not available yet . < / p >
< / div >
< div v-if ="page == 'mediaMetadata'" class="w-100 h-100 p-3" >
< p class = "text-center lead text-muted mb-0 py-5" > This feature is not available yet . < / p >
< / div >
< div v-if ="page == 'addToStory'" class="w-100 h-100 p-3" >
< p class = "text-center lead text-muted mb-0 py-5" > This feature is not available yet . < / p >
< / div >
< / div >
<!-- card - footers -- >
< div v-if ="page == 2" class="card-footer bg-white d-flex justify-content-between" >
< div >
< button type = "button" class = "btn btn-outline-secondary" @click ="rotate" > < i class = "fas fa-undo" > < / i > < / button >
< / div >
< div >
< div class = "d-inline-block button-group" >
< button : class = "'btn font-weight-bold ' + [cropper.aspectRatio == 16/9 ? 'btn-primary':'btn-light']" @click.prevent ="changeAspect(16/9)" > 16 : 9 < / button >
< button : class = "'btn font-weight-bold ' + [cropper.aspectRatio == 4/3 ? 'btn-primary':'btn-light']" @click.prevent ="changeAspect(4/3)" > 4 : 3 < / button >
< button : class = "'btn font-weight-bold ' + [cropper.aspectRatio == 3/2 ? 'btn-primary':'btn-light']" @click.prevent ="changeAspect(3/2)" > 3 : 2 < / button >
< button : class = "'btn font-weight-bold ' + [cropper.aspectRatio == 1 ? 'btn-primary':'btn-light']" @click.prevent ="changeAspect(1)" > 1 : 1 < / button >
< button : class = "'btn font-weight-bold ' + [cropper.aspectRatio == 2/3 ? 'btn-primary':'btn-light']" @click.prevent ="changeAspect(2/3)" > 2 : 3 < / button >
< / div >
< / div >
< / div >
@ -219,12 +256,36 @@
display : none ;
}
}
. no - focus {
border - color : none ;
outline : 0 ;
box - shadow : none ;
}
a . list - group - item {
text - decoration : none ;
}
a . list - group - item : hover {
text - decoration : none ;
background - color : # f8f9fa ! important ;
}
< / style >
< script type = "text/javascript" >
import VueCropper from 'vue-cropperjs' ;
import 'cropperjs/dist/cropper.css' ;
import Autocomplete from '@trevoreyre/autocomplete-vue'
import '@trevoreyre/autocomplete-vue/dist/style.css'
export default {
components : {
VueCropper ,
Autocomplete
} ,
data ( ) {
return {
config : window . App . config ,
pageLoading : false ,
profile : { } ,
composeText : '' ,
composeTextLength : 0 ,
@ -233,12 +294,37 @@ export default {
ids : [ ] ,
media : [ ] ,
carouselCursor : 0 ,
visibility : 'public' ,
mediaDrawer : false ,
composeState : 'publish' ,
uploading : false ,
uploadProgress : 0 ,
composeType : false
uploadProgress : 100 ,
composeType : false ,
page : 1 ,
composeState : 'publish' ,
visibility : 'public' ,
visibilityTag : 'Public' ,
nsfw : false ,
place : false ,
commentsDisabled : false ,
pageTitle : '' ,
cropper : {
aspectRatio : 1 ,
viewMode : 1 ,
zoomable : true ,
zoom : 0
} ,
taggedUsernames : false ,
namedPages : [
'tagPeople' ,
'addLocation' ,
'advancedSettings' ,
'visibility' ,
'altText' ,
'addToCollection' ,
'schedulePost' ,
'mediaMetadata' ,
'addToStory'
]
}
} ,
@ -294,9 +380,20 @@ export default {
} ,
methods : {
fetchConfig ( ) {
axios . get ( '/api/v2/config' ) . then ( res => {
this . config = res . data ;
window . pixelfed . config = window . pixelfed . config || res . data ;
if ( this . config . uploader . media _types . includes ( 'video/mp4' ) == false ) {
this . composeType = 'post'
}
} ) ;
} ,
fetchProfile ( ) {
axios . get ( '/api/v1/accounts/verify_credentials' ) . then ( res => {
this . profile = res . data ;
window . pixelfed . currentUser = res . data ;
if ( res . data . locked == true ) {
this . visibility = 'private' ;
}
@ -315,51 +412,88 @@ export default {
mediaWatcher ( ) {
let self = this ;
$ ( document ) . on ( 'change' , '.file-input' , function ( e ) {
let io = document . querySelector ( '.file-input' ) ;
Array . prototype . forEach . call ( io . files , function ( io , i ) {
self . uploading = true ;
if ( self . media && self . media . length + i >= self . config . uploader . album _limit ) {
swal ( 'Error' , 'You can only upload ' + self . config . uploader . album _limit + ' photos per album' , 'error' ) ;
return ;
}
let type = io . type ;
let acceptedMimes = self . config . uploader . media _types . split ( ',' ) ;
let validated = $ . inArray ( type , acceptedMimes ) ;
if ( validated == - 1 ) {
swal ( 'Invalid File Type' , 'The file you are trying to add is not a valid mime type. Please upload a ' + self . config . uploader . media _types + ' only.' , 'error' ) ;
return ;
}
self . mediaDragAndDrop ( ) ;
$ ( document ) . on ( 'change' , '#pf-dz' , function ( e ) {
self . mediaUpload ( ) ;
} ) ;
} ,
let form = new FormData ( ) ;
form . append ( 'file' , io ) ;
mediaUpload ( ) {
let self = this ;
self . uploading = true ;
let io = document . querySelector ( '#pf-dz' ) ;
Array . prototype . forEach . call ( io . files , function ( io , i ) {
if ( self . media && self . media . length + i >= self . config . uploader . album _limit ) {
swal ( 'Error' , 'You can only upload ' + self . config . uploader . album _limit + ' photos per album' , 'error' ) ;
return ;
}
let type = io . type ;
let acceptedMimes = self . config . uploader . media _types . split ( ',' ) ;
let validated = $ . inArray ( type , acceptedMimes ) ;
if ( validated == - 1 ) {
swal ( 'Invalid File Type' , 'The file you are trying to add is not a valid mime type. Please upload a ' + self . config . uploader . media _types + ' only.' , 'error' ) ;
return ;
}
let xhrConfig = {
onUploadProgress : function ( e ) {
let progress = Math . round ( ( e . loaded * 100 ) / e . total ) ;
self . uploadProgress = progress ;
}
} ;
let form = new FormData ( ) ;
form . append ( 'file' , io ) ;
axios . post ( '/api/v1/media' , form , xhrConfig )
. then ( function ( e ) {
self . uploadProgress = 100 ;
self . ids . push ( e . data . id ) ;
self . media . push ( e . data ) ;
setTimeout ( function ( ) {
self . uploading = false ;
} , 1000 ) ;
} ) . catch ( function ( e ) {
let xhrConfig = {
onUploadProgress : function ( e ) {
let progress = Math . round ( ( e . loaded * 100 ) / e . total ) ;
self . uploadProgress = progress ;
}
} ;
axios . post ( '/api/v1/media' , form , xhrConfig )
. then ( function ( e ) {
self . uploadProgress = 100 ;
self . ids . push ( e . data . id ) ;
self . media . push ( e . data ) ;
self . page = 2 ;
setTimeout ( function ( ) {
self . uploading = false ;
io . value = null ;
swal ( 'Oops, something went wrong!' , 'An unexpected error occurred.' , 'error' ) ;
} ) ;
} , 1000 ) ;
} ) . catch ( function ( e ) {
self . uploading = false ;
io . value = null ;
s elf. uploadProgress = 0 ;
s wal( 'Oops, something went wrong!' , 'An unexpected error occurred.' , 'error' ) ;
} ) ;
io . value = null ;
self . uploadProgress = 0 ;
} ) ;
} ,
mediaDragAndDrop ( ) {
let self = this ;
let pdz = document . getElementById ( 'content' ) ;
function allowDrag ( e ) {
e . dataTransfer . dropEffect = 'copy' ;
e . preventDefault ( ) ;
}
function handleDrop ( e ) {
e . preventDefault ( ) ;
let dz = document . querySelector ( '#pf-dz' ) ;
dz . files = e . dataTransfer . files ;
$ ( '#composeModal' ) . modal ( 'show' ) ;
self . mediaUpload ( ) ;
}
window . addEventListener ( 'dragenter' , function ( e ) {
} ) ;
pdz . addEventListener ( 'dragenter' , allowDrag ) ;
pdz . addEventListener ( 'dragover' , allowDrag ) ;
pdz . addEventListener ( 'dragleave' , function ( e ) {
/ /
} ) ;
pdz . addEventListener ( 'drop' , handleDrop ) ;
} ,
toggleFilter ( e , filter ) {
this . media [ this . carouselCursor ] . filter _class = filter ;
} ,
@ -446,18 +580,15 @@ export default {
media : this . media ,
caption : this . composeText ,
visibility : this . visibility ,
cw : this . nsfw
cw : this . nsfw ,
comments _disabled : this . commentsDisabled ,
place : this . place
} ;
axios . post ( '/api/v2/status/compose' , data )
axios . post ( '/api/ local /status/compose', data )
. then ( res => {
let data = res . data ;
window . location . href = data ;
} ) . catch ( err => {
let res = err . response . data ;
if ( res . message == 'Too Many Attempts.' ) {
swal ( 'You\'re posting too much!' , 'We only allow 50 posts per hour or 100 per day. If you\'ve reached that limit, please try again later. If you think this is an error, please contact an administrator.' , 'error' ) ;
return ;
}
swal ( 'Oops, something went wrong!' , 'An unexpected error occurred.' , 'error' ) ;
} ) ;
return ;
@ -507,6 +638,45 @@ export default {
window . location . href = '/i/collections/create' ;
} ,
nextPage ( ) {
switch ( this . page ) {
case 1 :
this . page = 3 ;
break ;
case 2 :
this . pageLoading = true ;
let self = this ;
this . $refs . cropper . getCroppedCanvas ( ) . toBlob ( function ( blob ) {
let data = new FormData ( ) ;
data . append ( 'file' , blob ) ;
let url = '/api/local/compose/media/update/' + self . ids [ self . carouselCursor ] ;
axios . post ( url , data ) . then ( res => {
self . media [ self . carouselCursor ] . url = res . data . url ;
self . pageLoading = false ;
self . page ++ ;
} ) . catch ( err => {
} ) ;
} ) ;
break ;
case 3 :
case 4 :
this . page ++ ;
break ;
}
} ,
rotate ( ) {
this . $refs . cropper . rotate ( 90 ) ;
} ,
changeAspect ( ratio ) {
this . cropper . aspectRatio = ratio ;
this . $refs . cropper . setAspectRatio ( ratio ) ;
} ,
maxSize ( ) {
let limit = this . config . uploader . max _photo _size ;
return limit / 1000 + ' MB' ;
@ -517,6 +687,75 @@ export default {
return formats . split ( ',' ) . map ( f => {
return ' ' + f . split ( '/' ) [ 1 ] ;
} ) . toString ( ) ;
} ,
showTagCard ( ) {
this . pageTitle = 'Tag People' ;
this . page = 'tagPeople' ;
} ,
showLocationCard ( ) {
this . pageTitle = 'Add Location' ;
this . page = 'addLocation' ;
} ,
showAdvancedSettingsCard ( ) {
this . pageTitle = 'Advanced Settings' ;
this . page = 'advancedSettings' ;
} ,
locationSearch ( input ) {
if ( input . length < 1 ) { return [ ] ; } ;
let results = [ ] ;
return axios . get ( '/api/local/compose/location/search' , {
params : {
q : input
}
} ) . then ( res => {
return res . data ;
} ) ;
} ,
getResultValue ( result ) {
return result . name + ', ' + result . country
} ,
onSubmitLocation ( result ) {
this . place = result ;
this . pageTitle = '' ;
this . page = 4 ;
return ;
} ,
goBack ( ) {
this . pageTitle = '' ;
if ( this . page == 'addToStory' ) {
this . page = 1 ;
} else {
this . namedPages . indexOf ( this . page ) != - 1 ? this . page = 4 : this . page -- ;
}
} ,
showVisibilityCard ( ) {
this . pageTitle = 'Post Visibility' ;
this . page = 'visibility' ;
} ,
showAddToStoryCard ( ) {
this . pageTitle = 'Add to Story' ;
this . page = 'addToStory' ;
} ,
toggleVisibility ( state ) {
let tags = {
public : 'Public' ,
private : 'Followers Only' ,
unlisted : 'Unlisted'
}
this . visibility = state ;
this . visibilityTag = tags [ state ] ;
this . pageTitle = '' ;
this . page = 4 ;
}
}
}