vue-kompo
Version:
Laravel Vue components for Rapid Application Development
419 lines (339 loc) • 14.3 kB
JavaScript
import KompoAxios from './KompoAxios'
import Alert from './Alert'
import TurboClick from './TurboClick'
export default class Action {
constructor(action, vue){
this.actionConfig = action.config
this.vue = vue
this.warningConfirmed = false
this.actionType = action.actionType
this.interactions = action.interactions
this.$_kAxios = new KompoAxios(this)
}
$_config(key){
return this.actionConfig[key] || null
}
run(parameters){
if(!this.actionType)
return
var actionFunction = this.actionType + 'Action'
this[actionFunction](
parameters ? parameters.response : null,
parameters ? parameters.parentAction : null,
parameters ? parameters.payload : null
)
}
axiosRequestAction(r, p, payload){
this.vue.$_state({ loading: true })
this.vue.$kompo.vlToggleSubmit(this.vue.kompoid, false) //disable submit while loading
let additionalPayload = this.getParentKomponentFormData()
let checkedItemIds = this.vue.$_config('withCheckedItemIds') ? this.getParentKomponentInfo().data : null
this.$_kAxios.$_actionAxiosRequest(payload, Object.assign(additionalPayload || {}, checkedItemIds || {}))
.then(r => {
this.vue.$_state({ loading: false })
this.vue.$kompo.vlToggleSubmit(this.vue.kompoid, true)
this.vue.$_runInteractionsOfType(this, 'success', r)
}).catch(e => {
this.vue.$_state({ loading: false })
this.handleErrorInteraction(e)
})
}
getParentKomponentFormData(){
if(!this.vue.$_config('withAllFormValues') && !this.$_config('withAllFormValues')){
return
}
let parentKomponentInfo = this.getParentKomponentInfo()
return parentKomponentInfo.jsonFormData || parentKomponentInfo.data
}
submitFormAction(){
this.vue.$_state({ loading: true })
this.vue.$_state({ isSuccess: false })
this.vue.$_state({ hasError: false })
let parentKomponentInfo = this.getParentKomponentInfo()
if(!parentKomponentInfo.canSubmit){
setTimeout( () => { this.submitFormAction() }, 100)
return
}
this.vue.$kompo.vlPreSubmit(this.vue.kompoid)
if(!parentKomponentInfo.url)
return
this.$_kAxios.$_submitFormAction(
parentKomponentInfo.url,
parentKomponentInfo.method,
parentKomponentInfo.action,
Object.assign(parentKomponentInfo.jsonFormData, this.$_config('submitPayload') || {})
)
.then(r => {
this.vue.$_state({ loading: false })
this.vue.$_state({ isSuccess: true })
this.vue.$kompo.vlSubmitSuccess(this.vue.kompoid, r, this.vue)
this.vue.$_runInteractionsOfType(this, 'success', r)
})
.catch(e => {
this.vue.$_state({ loading: false })
this.vue.$_state({ hasError: true })
if (e instanceof axios.Cancel) {return;}
if(e.response.status == 449){
let message = e.response.data.message || e.response.data
if(_.isString(message)){
if(confirm(message)){
this.warningConfirmed = true
this.submitFormAction()
}
}else{
this.fillModalNewAction(e.response, () => {
this.warningConfirmed = true
this.submitFormAction()
})
}
}else{
this.vue.$kompo.vlSubmitError(this.vue.kompoid, e)
if (e.response.status !== 422) //handled in vlSubmitError
this.handleErrorInteraction(e)
}
})
}
browseQueryAction(){
this.runKompoInfoSpecifications('$_browseMany', 'vlLoadItems')
}
refreshKomponentAction(){
this.runKompoInfoSpecifications('$_refreshMany', 'vlRefreshKomponent', true)
}
sortQueryAction(){
this.vue.$_state({
activeSort: true,
loading: true
})
if(this.vue.customBeforeSort)
this.vue.customBeforeSort()
this.vue.$kompo.vlSort(this.vue.kompoid, this.vue.$_sortValue, this.vue.$_elKompoId)
}
emitFromAction(response){
let emitPayload = _.isEmpty(this.getPayloadFor('emitPayload')) ? null : this.getPayloadFor('emitPayload')
this.vue.$_vlEmitFrom(this.$_config('event'), emitPayload || (response ? response.data : null))
this.vue.$_runInteractionsOfType(this, 'success')
}
emitDirectAction(response){
let emitPayload = _.isEmpty(this.getPayloadFor('emitPayload')) ? null : this.getPayloadFor('emitPayload')
this.vue.$emit(this.$_config('event'), emitPayload || (response ? response.data : null))
this.vue.$_runInteractionsOfType(this, 'success')
}
emitRootAction(response){
let emitPayload = _.isEmpty(this.getPayloadFor('emitPayload')) ? null : this.getPayloadFor('emitPayload')
this.vue.$kompo.vlEmitRoot(this.$_config('event'), emitPayload || (response ? response.data : null))
this.vue.$_runInteractionsOfType(this, 'success')
}
toggleElementAction(){
if(this.$_config('toggleId')){
this.vue.$kompo.vlToggle(this.vue.kompoid, this.$_config('toggleId'))
}
this.vue.$_runInteractionsOfType(this, 'success')
}
hideSelfAction(){
this.vue.$_toggleSelf()
}
runJsAction(response){
const jsFunction = this.$_config('jsFunction')
this.vue.$nextTick(() => { //yep, run it if you find it
if (!jsFunction) {
return;
}
if (jsFunction.substr(0, 7) == '() => {') {
let toExecutre = eval(jsFunction)
toExecutre(response)
return;
}
if(window[jsFunction])
window[jsFunction](response)
if(this.vue[jsFunction]) //never used yet but maybe one day. The idea is interesting
this.vue[jsFunction](response)
})
}
scrollToAction(){
var VueScrollTo = require('vue-scrollto')
setTimeout(() => this.vue.$scrollTo(
this.$_config('scrollSelector'),
this.$_config('scrollDuration'),
this.$_config('scrollOptions'),
), this.$_config('timeoutDuration') || 500)
}
toggleClassAction(){
this.vue.$_toggleClass(this.$_config('toggleClass'))
this.vue.$_runInteractionsOfType(this, 'success')
}
addClassAction(){
this.vue.$_addClass(this.$_config('addClass'))
this.vue.$_runInteractionsOfType(this, 'success')
}
removeClassAction(){
this.vue.$_removeClass(this.$_config('removeClass'))
this.vue.$_runInteractionsOfType(this, 'success')
}
removeSelfAction(){
this.vue.$kompo.vlRemoveItem(this.vue.kompoid, this.vue.index)
this.vue.$_runInteractionsOfType(this, 'success')
}
setHistoryAction(){
let historyUrl = this.$_config('setHistory')
window.history.pushState({url: historyUrl}, "", historyUrl)
window.onpopstate = function(e) {location.reload()} //for back button
this.vue.$_runInteractionsOfType(this, 'success')
}
fillModalNewAction(response, confirmFunc){
this.vue.$kompo.vlFillModal(response, this.vue.kompoid, {
confirmFunc: confirmFunc,
warnBeforeClose: this.vue.$_config('warnBeforeClose'),
refreshParent: this.vue.$_config('refreshParent'),
closeAfterSubmit: this.vue.$_config('keepOpen') === true ? false : this.vue.$_config('refreshParent'),
closeLastModal: this.vue.$_config('closeLastModal'),
})
}
fillModalAction(response, confirmFunc){
var modalName = this.$_config('modalName') || (this.vue.kompoid ? 'modal'+this.vue.kompoid : 'vlDefaultModal')
var panelId = this.$_config('panelId') || (this.vue.kompoid ? 'modal'+this.vue.kompoid : 'vlDefaultModal')
//New addition: use modalInsertAction to refresh parent Komponent and close modal (replicate edit/addlink behavior)
if (this.vue.$_config('refreshParent')) {
this.modalInsertAction(response)
return
}
this.vue.$kompo.vlModalShow(modalName, true, this.vue.$_config('warnBeforeClose'), confirmFunc)
this.vue.$nextTick( () => {
this.vue.$kompo.vlFillPanel(panelId, response.data.message || response.data)
})
}
closeModalAction(response){
this.vue.$kompo.vlModalClose('modal'+this.$_config('closeModalName'))
this.vue.$_runInteractionsOfType(this, 'success')
}
modalInsertAction(response){
this.vue.$kompo.vlFillModal(response, this.vue.kompoid, {
confirmFunc: null,
warnBeforeClose: this.vue.$_config('warnBeforeClose'),
refreshParent: true,
closeAfterSubmit: !this.vue.$_config('keepOpen'),
index: this.vue.index, //not used yet
})
}
fillPanelAction(response, parentAction){
this.vue.$kompo.vlFillPanel(this.$_config('panelId'), response.data, {
included: this.$_config('included') || parentAction.$_config('included'),
refreshParent: this.vue.$_config('refreshParent'),
resetAfterSubmit: (this.vue.$_config('keepOpen') === true) ? false : this.vue.$_config('refreshParent'),
})
this.vue.$_runInteractionsOfType(this, 'success')
}
fillDrawerAction(response){
this.vue.$kompo.vlFillDrawer(response, this.vue.kompoid, {
warnBeforeClose: this.vue.$_config('warnBeforeClose'),
refreshParent: this.vue.$_config('refreshParent'),
closeAfterSubmit: (this.vue.$_config('keepOpen') === true) ? false : this.vue.$_config('refreshParent'),
})
}
closeDrawerAction(){
this.vue.$kompo.vlCloseDrawer()
}
fillPopupAction(response){
this.vue.$kompo.vlFillPopup(response, {
draggable: this.$_config('draggable'),
resizable: this.$_config('resizable'),
})
}
closePopupAction(){
this.vue.$kompo.vlClosePopup()
}
addAlertAction(){
new Alert().asObject(this.$_config('alert')).emitFrom(this.vue)
}
fillAlertAction(response){
new Alert().asObject({
...this.$_config('alert'),
message: response.data.message || response.data,
}).emitFrom(this.vue)
this.vue.$_runInteractionsOfType(this, 'success')
}
redirectAction(response){
if(this.$_config('redirectUrl') === true){
setTimeout( () => { this.redirect(response.request.responseURL) }, 300)
}else if(this.$_config('redirectUrl')){
setTimeout( () => { this.redirect(this.$_config('redirectUrl')) }, 300)
}
}
/* internal */
redirect(url){
if(this.vue.component && this.vue.component.turbo){
new TurboClick(this.vue.$vnode, url).trigger()
}else{
window.location.href = url
}
}
getPayloadFor(payloadKey) {
return Object.assign(
this.$_config(payloadKey) || {},
this.vue.$_getJsonValue || {}
)
}
getFormData(jsonFormData) {
var formData = new FormData()
for ( var key in jsonFormData ) {
formData.append(key, jsonFormData[key])
}
if(this.warningConfirmed)
formData.append('kompoConfirmed', this.warningConfirmed)
return formData
}
handleErrorInteraction(e){
if(this.vue.$_hasInteractionsOfType(this, 'error')){
this.vue.$_runInteractionsOfType(this, 'error', e.response) //Errors need a .response to be like the success response
}else{
this.$_kAxios.$_handleAjaxError(e)
}
}
getParentKomponentInfo(kompoid, resetFilters){
let usedKompoId = kompoid || this.vue.kompoid
this.vue.$kompo.vlRequestKomponentInfo(usedKompoId, this.vue.$_elKompoId, {
page: this.$_config('page'),
resetFilters: resetFilters,
})
return this.vue.parentKomponentInfo[usedKompoId]
}
/* utils */
getAsArray(data, fallback){
return data ? (_.isArray(data) ? data : [data]) : [fallback]
}
getKompoInfoSpecifications(resetFilters){
var specifications = []
this.getAsArray(this.$_config('kompoid'), this.vue.kompoid).forEach(kompoid => {
if(!kompoid)
return
let parentKomponentInfo = this.getParentKomponentInfo(kompoid, resetFilters)
if(parentKomponentInfo)
specifications.push({
kompoid: kompoid,
data: Object.assign(parentKomponentInfo.data || {}, this.$_config('ajaxPayload') || {}),
kompoinfo: parentKomponentInfo.kompoinfo,
page: parentKomponentInfo.page,
sort: parentKomponentInfo.sort,
})
})
return specifications
}
runKompoInfoSpecifications(axiosRequestFunc, komponentFillFunc, resetFilters){
this.vue.$_state({ loading: true })
let specifications = this.getKompoInfoSpecifications(resetFilters)
if(!specifications.length){
this.vue.$_state({ loading: false })
return
}
this.$_kAxios[axiosRequestFunc](this.$_config('route'), specifications)
.then(r => {
this.vue.$_state({ loading: false })
Object.keys(r.data).forEach((kompoid) => {
this.vue.$kompo[komponentFillFunc](kompoid, r.data[kompoid])
})
this.vue.$_runInteractionsOfType(this, 'success')
}).catch(e => {
this.vue.$_state({ loading: false })
this.handleErrorInteraction(e)
})
}
}