migrate to vue3; autocomplete still needs work
This commit is contained in:
		@ -12,7 +12,7 @@ const App = {
 | 
			
		||||
        player() { return window.aircox.player; },
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    components: {AAutocomplete, AEpisode, APlayer, APlaylist, ASoundItem},
 | 
			
		||||
    components: {AAutocomplete, AEpisode, APlaylist, ASoundItem},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const PlayerApp = {
 | 
			
		||||
 | 
			
		||||
@ -34,16 +34,16 @@ export default class Builder {
 | 
			
		||||
     * @param {Boolean} [reset=False]: if True, force application recreation.
 | 
			
		||||
     * @return `app.mount`'s result.
 | 
			
		||||
     */
 | 
			
		||||
    mount({content=null, title=null, el=null, reset=false}={}) {
 | 
			
		||||
    mount({content=null, title=null, el=null, reset=false, props=null}={}) {
 | 
			
		||||
        try {
 | 
			
		||||
            this.unmount()
 | 
			
		||||
            
 | 
			
		||||
            let config = this.config
 | 
			
		||||
            if(el === null)
 | 
			
		||||
                el = config.el
 | 
			
		||||
                
 | 
			
		||||
            if(reset || !this.app)
 | 
			
		||||
                this.app = this.createApp({title,content,el,...config})
 | 
			
		||||
                this.app = this.createApp({title,content,el,...config}, props)
 | 
			
		||||
 | 
			
		||||
            this.vm = this.app.mount(el)
 | 
			
		||||
            window.scroll(0, 0)
 | 
			
		||||
            return this.vm
 | 
			
		||||
@ -53,7 +53,7 @@ export default class Builder {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    createApp({el, title=null, content=null, ...config}) {
 | 
			
		||||
    createApp({el, title=null, content=null, ...config}, props) {
 | 
			
		||||
        const container = document.querySelector(el)
 | 
			
		||||
        if(!container)
 | 
			
		||||
            throw `Error: can't get element ${el}`
 | 
			
		||||
@ -61,7 +61,7 @@ export default class Builder {
 | 
			
		||||
            container.innerHTML = content
 | 
			
		||||
        if(title)
 | 
			
		||||
            document.title = title
 | 
			
		||||
        return createApp(config)
 | 
			
		||||
        return createApp(config, props)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    unmount() {
 | 
			
		||||
 | 
			
		||||
@ -1,60 +1,74 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <div class="control">
 | 
			
		||||
        <Autocomplete ref="autocomplete" :data="data" :placeholder="placeholder" :field="field"
 | 
			
		||||
            :loading="isFetching" open-on-focus
 | 
			
		||||
            @typing="fetch" @select="object => onSelect(object)"
 | 
			
		||||
            >
 | 
			
		||||
        </Autocomplete>
 | 
			
		||||
        <input v-if="valueField" ref="value" type="hidden" :name="valueField"
 | 
			
		||||
            :value="selected && selected[valueAttr || valueField]" />
 | 
			
		||||
        <datalist :id="listId">
 | 
			
		||||
            <template v-for="item in items" :key="item.path">
 | 
			
		||||
                <option :value="item[field]"></option>
 | 
			
		||||
            </template>
 | 
			
		||||
        </datalist>
 | 
			
		||||
        <input type="text" :name="name" :placeholder="placeholder"
 | 
			
		||||
            :list="listId" @keyup="onKeyUp"/>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import debounce from 'lodash/debounce'
 | 
			
		||||
import {Autocomplete} from 'buefy/dist/components/autocomplete'
 | 
			
		||||
// import debounce from 'lodash/debounce'
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    props: {
 | 
			
		||||
        url: String,
 | 
			
		||||
        model: Function,
 | 
			
		||||
        placeholder: String,
 | 
			
		||||
        field: {type: String, default: 'value'},
 | 
			
		||||
        name: String,
 | 
			
		||||
        field: String,
 | 
			
		||||
        valueField: {type: String, default: 'id'},
 | 
			
		||||
        count: {type: Number, count: 10},
 | 
			
		||||
        valueAttr: String,
 | 
			
		||||
        valueField: String,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    data() {
 | 
			
		||||
        return {
 | 
			
		||||
            data: [],
 | 
			
		||||
            value: '',
 | 
			
		||||
            items: [],
 | 
			
		||||
            selected: null,
 | 
			
		||||
            isFetching: false,
 | 
			
		||||
            listId: `autocomplete-${ Math.random() }`.replace('.',''),
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    methods: {
 | 
			
		||||
        onSelect(option) {
 | 
			
		||||
            console.log('selected', option)
 | 
			
		||||
        select(option, value=null) {
 | 
			
		||||
            if(!option && value !== null)
 | 
			
		||||
                option = this.items.find(item => item[this.field] == value)
 | 
			
		||||
 | 
			
		||||
            this.selected = option
 | 
			
		||||
            this.$emit('select', option)
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        fetch: debounce(function(query) {
 | 
			
		||||
            if(!query)
 | 
			
		||||
        onKeyUp: function(event) {
 | 
			
		||||
            const value = event.target.value
 | 
			
		||||
            if(value === this.value)
 | 
			
		||||
                return
 | 
			
		||||
 | 
			
		||||
            if(value !== undefined && value !== null)
 | 
			
		||||
                this.value = value
 | 
			
		||||
                
 | 
			
		||||
            if(!value)
 | 
			
		||||
                return this.select(null)
 | 
			
		||||
 | 
			
		||||
            this.fetch(value)
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        fetch: function(query) {
 | 
			
		||||
            if(!query || this.isFetching)
 | 
			
		||||
                return
 | 
			
		||||
 | 
			
		||||
            this.isFetching = true
 | 
			
		||||
            this.model.fetchAll(this.url.replace('${query}', query))
 | 
			
		||||
                .then(data => {
 | 
			
		||||
                    this.data = data
 | 
			
		||||
                    this.isFetching = false
 | 
			
		||||
                }, data => { this.isFetching = false; Promise.reject(data) })
 | 
			
		||||
        }),
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    components: {
 | 
			
		||||
        Autocomplete,
 | 
			
		||||
            return this.model.fetch(this.url.replace('${query}', query), {many:true})
 | 
			
		||||
                .then(items => { this.items = items || []
 | 
			
		||||
                                 this.isFetching = false
 | 
			
		||||
                                 this.select(null, query)
 | 
			
		||||
                                 return items },
 | 
			
		||||
                      data => {this.isFetching = false; Promise.reject(data)})
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -15,6 +15,7 @@ import {Set} from './model'
 | 
			
		||||
 | 
			
		||||
import './styles.scss'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
window.aircox = {
 | 
			
		||||
    // main application
 | 
			
		||||
    builder: new Builder(App),
 | 
			
		||||
@ -25,9 +26,28 @@ window.aircox = {
 | 
			
		||||
    get playerApp() { return this.playerBuilder && this.playerBuilder.app },
 | 
			
		||||
    get player() { return this.playerBuilder.vm && this.playerBuilder.vm.$refs.player },
 | 
			
		||||
 | 
			
		||||
    Set: Set, Sound: Sound,
 | 
			
		||||
    Set, Sound,
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initialize main application and player.
 | 
			
		||||
     */
 | 
			
		||||
    init(props=null, {config=null, builder=null, initPlayer=true}={}) {
 | 
			
		||||
        builder = builder || this.builder
 | 
			
		||||
        this.builder = builder
 | 
			
		||||
        if(config)
 | 
			
		||||
            builder.config = config
 | 
			
		||||
        builder.title = document.title
 | 
			
		||||
        builder.mount({props})
 | 
			
		||||
 | 
			
		||||
        if(initPlayer) {
 | 
			
		||||
            let playerBuilder = this.playerBuilder
 | 
			
		||||
            playerBuilder.mount()
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
window.addEventListener('load', e => {
 | 
			
		||||
    const [app, player] = [aircox.builder, aircox.playerBuilder]
 | 
			
		||||
    app.title = document.title
 | 
			
		||||
@ -36,4 +56,5 @@ window.addEventListener('load', e => {
 | 
			
		||||
 | 
			
		||||
    player.mount()
 | 
			
		||||
})
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -20,7 +20,7 @@ export function getCsrf() {
 | 
			
		||||
// TODO: prevent duplicate simple fetch
 | 
			
		||||
export default class Model {
 | 
			
		||||
    constructor(data, {url=null}={}) {
 | 
			
		||||
        this.url = url;
 | 
			
		||||
        this.url = url || data.url_;
 | 
			
		||||
        this.commit(data);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -45,14 +45,24 @@ export default class Model {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static fromList(items, args=null) {
 | 
			
		||||
        return items ? items.map(d => new this(d, args)) : []
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Fetch item from server
 | 
			
		||||
     */
 | 
			
		||||
    static fetch(url, options=null, args=null) {
 | 
			
		||||
    static fetch(url, {many=false, ...options}={}, args={}) {
 | 
			
		||||
        options = this.getOptions(options)
 | 
			
		||||
        return fetch(url, options)
 | 
			
		||||
            .then(response => response.json())
 | 
			
		||||
            .then(data => new this(data, {url: url, ...args}));
 | 
			
		||||
        const request = fetch(url, options).then(response => response.json());
 | 
			
		||||
        if(many)
 | 
			
		||||
            return request.then(data => {
 | 
			
		||||
                if(!(data instanceof Array))
 | 
			
		||||
                    data = data.results
 | 
			
		||||
                return this.fromList(data, args)
 | 
			
		||||
            })
 | 
			
		||||
        else
 | 
			
		||||
            return request.then(data => new this(data, {url: url, ...args}));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -123,7 +133,7 @@ export class Set {
 | 
			
		||||
     * Fetch multiple items from server
 | 
			
		||||
     */
 | 
			
		||||
    static fetch(model, url, options=null, args=null) {
 | 
			
		||||
        options = this.getOptions(options)
 | 
			
		||||
        options = model.getOptions(options)
 | 
			
		||||
        return fetch(url, options)
 | 
			
		||||
            .then(response => response.json())
 | 
			
		||||
            .then(data => (data instanceof Array ? data : data.results)
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user