diff --git a/justpy/templates/js/vue/html_component.js b/justpy/templates/js/vue/html_component.js index f816b0ae..7ff26cfd 100644 --- a/justpy/templates/js/vue/html_component.js +++ b/justpy/templates/js/vue/html_component.js @@ -175,44 +175,52 @@ Vue.component('html_component', { }; element.addEventListener('animationend', event_func); }), + /** + * Transition function that is called on page updates + */ transitionFunction: (function () { - let el = this.$refs['r' + this.$props.jp_props.id]; const props = this.$props.jp_props; + let el = this.$refs['r' + props.id]; if (el.$el) el = el.$el; - const class_list = props.classes.trim().replace(/\s\s+/g, ' ').split(' '); + const class_list = this._getCssClassNamesFromString(props.classes); // Transition change from hidden to not hidden - if (props.transition.enter && this.previous_display == 'none' && (!class_list.includes('hidden'))) { - - let enter_list = props.transition.enter.trim().replace(/\s\s+/g, ' ').split(' '); - let enter_start_list = props.transition.enter_start.trim().replace(/\s\s+/g, ' ').split(' '); - let enter_end_list = props.transition.enter_end.trim().replace(/\s\s+/g, ' ').split(' '); + if (props.transition.enter && this.previous_display === 'none' && (!class_list.includes('hidden'))) { + let enter_list = this._getCssClassNamesFromString(props.transition.enter); + let enter_start_list = this._getCssClassNamesFromString(props.transition.enter_start); + let enter_end_list = this._getCssClassNamesFromString(props.transition.enter_end); + // initialize transition el.classList.add(...enter_start_list); setTimeout(function () { + // start transition el.classList.remove(...enter_start_list); el.classList.add(...enter_list); el.classList.add(...enter_end_list); let event_func = function () { + // teardown transition (after completing the transition remove event listener and transition classes) el.removeEventListener('transitionend', event_func); el.classList.remove(...enter_list); el.classList.remove(...enter_end_list); }; el.addEventListener('transitionend', event_func); - }, 3); + }, 30); } // Transition change from not hidden to hidden - else if (props.transition.leave && this.previous_display != 'none' && (class_list.includes('hidden'))) { - let leave_list = props.transition.leave.trim().replace(/\s\s+/g, ' ').split(' '); - let leave_start_list = props.transition.leave_start.trim().replace(/\s\s+/g, ' ').split(' '); - let leave_end_list = props.transition.leave_end.trim().replace(/\s\s+/g, ' ').split(' '); + else if (props.transition.leave && this.previous_display !== 'none' && (class_list.includes('hidden'))) { + let leave_list = this._getCssClassNamesFromString(props.transition.leave); + let leave_start_list = this._getCssClassNamesFromString(props.transition.leave_start); + let leave_end_list = this._getCssClassNamesFromString(props.transition.leave_end); + // initialize transition el.classList.add(...leave_start_list); el.classList.remove('hidden'); setTimeout(function () { + // start transition el.classList.remove(...leave_start_list); el.classList.add(...leave_list); el.classList.add(...leave_end_list); let event_func = function () { + // teardown transition el.removeEventListener('transitionend', event_func); el.classList.remove(...leave_list); el.classList.remove(...leave_end_list); @@ -220,20 +228,37 @@ Vue.component('html_component', { }; el.addEventListener('transitionend', event_func); - }, 3); + }, 30); } }), + /** + * Get list of CSS class names from string + * by splitting the string on whitespace + * @param {string} value - string with multiple CSS class names + * + * @return list of strings + */ + _getCssClassNamesFromString: (function (value){ + let cssClasses = null; + if (typeof value === "string"){ + cssClasses = value.trim().replace(/\s\s+/g, ' ').split(' '); + } + return cssClasses; + }), + /** + * Transition function called on page load + */ transitionLoadFunction: (function () { let el = this.$refs['r' + this.$props.jp_props.id]; const props = this.$props.jp_props; if (el.$el) el = el.$el; - const class_list = props.classes.trim().replace(/\s\s+/g, ' ').split(' '); + const class_list = this._getCssClassNamesFromString(props.classes); - let load_list = props.transition.load.trim().replace(/\s\s+/g, ' ').split(' '); - let load_start_list = props.transition.load_start.trim().replace(/\s\s+/g, ' ').split(' '); - let load_end_list = props.transition.load_end.trim().replace(/\s\s+/g, ' ').split(' '); + let load_list = this._getCssClassNamesFromString(props.transition.load); + let load_start_list = this._getCssClassNamesFromString(props.transition.load_start); + let load_end_list = this._getCssClassNamesFromString(props.transition.load_end); el.classList.add(...load_start_list); setTimeout(function () { @@ -246,7 +271,7 @@ Vue.component('html_component', { el.classList.remove(...load_list); }; el.addEventListener('transitionend', event_func); - }, 3) + }, 30) }) },