fixed Uncaught IndexSizeError bug

fixed Uncaught IndexSizeError bug

<style src="./style.css" scoped></style>
<template src="./template.html"></template>

<script>
    export default {
        props: {
            src: {
                type: String,
                required: true
            },
            disabledVolume: {
                type: Boolean,
                default: !volumeChangeSupported()
            },
            loop: Boolean,
            poster: String,
            autoplay: Boolean,
            controls: Boolean,
            width: [String, Number],
            height: [String, Number],
            disabledFullScreen: Boolean
        },
        data() {
            return {
                state: {
                    volume: 1,
                    totalTime: 0,
                    error: false,
                    ended: false,
                    currentTime: 0,
                    playing: false,
                    fullScreen: false
                },
                showPoster: false,
                preloadProgress: 0,
                playingProgress: 0,
                isDragProgressBar: false
            }
        },
        computed: {
            showError() {
                return this.state.error
            },
            videoElementRef() {
                return this.$refs.video
            },
            sourceElementRef() {
                return this.$refs.source
            },
            preloadProgressRate() {
                return {width: `${this.preloadProgress}%`}
            },
            size() {
                return {width: `${this.width}px`, height: `${this.height}px`}
            }
        },
        methods: {
            play() {
                if(this.ended){
                    this.ended = false
                    this.state.currentTime = 0
                }

                this.showPoster = false
                this.state.playing = true
                this.videoElementRef.play()
            },
            pause() {
                this.state.playing = false
                this.videoElementRef.pause()
            },
            changeZoom() {
                this.state.fullScreen = !this.state.fullScreen
            },
            changeVolume() {
                this.state.volume = Number(!this.state.volume)
                this.videoElementRef.volume = this.state.volume
                this.videoElementRef.volume = 0
            },
            durationChangeEvent(e) {
                this.state.totalTime = parseInt(e.target.duration, 10) * 1000
            },
            timeUpdateEvent(e) {
                this.state.currentTime = parseInt(e.target.currentTime, 10) * 1000

                if(!this.isDragProgressBar){
                    this.playingProgress = parseInt(e.target.currentTime * 100000 / this.videoElementRef.duration, 10)
                }
            },
            endedEvent(e) {
                this.ended = true
                this.state.playing = false
                this.videoElementRef.removeEventListener('progress', this.progressEvent, false)
                this.loop && this.play()
            },
            errorEvent(e) {
                this.state.error = true
            },
            progressEvent(e) {
                if(this.videoElementRef.buffered.length) {
                    this.preloadProgress = (this.videoElementRef.buffered.end(0) / this.videoElementRef.duration) * 100
                }
            },
            volumeChangeEvent(e) {
                console.log(e)
            },
            startDragProgressBar() {
                this.isDragProgressBar = true
            },
            stopDragProgressBar() {
                this.isDragProgressBar = false
                this.videoElementRef.currentTime = Math.floor(this.playingProgress * (this.videoElementRef.duration / 100000))
            }
        },
        mounted() {
            this.videoElementRef.addEventListener('ended', this.endedEvent, false)
            this.sourceElementRef.addEventListener('error', this.errorEvent, false)
            this.videoElementRef.addEventListener('progress', this.progressEvent, false)
            this.videoElementRef.addEventListener('timeupdate', this.timeUpdateEvent, false)
            this.videoElementRef.addEventListener('volumechange', this.volumeChangeEvent, false)
            this.videoElementRef.addEventListener('durationchange', this.durationChangeEvent, false)

            this.showPoster = Boolean(this.poster)
            this.autoplay && this.play()
        },
        destroyed() {
            this.videoElementRef.removeEventListener('ended', this.endedEvent, false)
            this.sourceElementRef.removeEventListener('error', this.errorEvent, false)
            this.videoElementRef.removeEventListener('progress', this.progressEvent, false)
            this.videoElementRef.removeEventListener('timeupdate', this.timeUpdateEvent, false)
            this.videoElementRef.removeEventListener('volumechange', this.volumeChangeEvent, false)
            this.videoElementRef.removeEventListener('durationchange', this.durationChangeEvent, false)
        },
        filters: {
            format(time) {
                let hours, minutes, seconds

                time = new Date(time)
                seconds = time.getUTCSeconds()
                hours = `${time.getUTCHours()}:`
                minutes = `${time.getUTCMinutes()}:`

                return `${hours === '0:' ? '' : hours}${minutes}${seconds  < 10 ? '0' + seconds : seconds}`
            }
        }
    }

    function volumeChangeSupported() {
        return !(/ipad|iphone|ipod|android|blackberry|windows ce|windows phone|webos|playbook/.exec(navigator.userAgent.toLowerCase()))
    }
</script>

<style src="./style.css" scoped></style>
<template src="./template.html"></template>

<script>
    export default {
        props: {
            src: {
                type: String,
                required: true
            },
            disabledVolume: {
                type: Boolean,
                default: !volumeChangeSupported()
            },
            loop: Boolean,
            poster: String,
            autoplay: Boolean,
            controls: Boolean,
            width: [String, Number],
            height: [String, Number],
            disabledFullScreen: Boolean
        },
        data() {
            return {
                state: {
                    volume: 1,
                    totalTime: 0,
                    error: false,
                    ended: false,
                    currentTime: 0,
                    playing: false,
                    fullScreen: false
                },
                showPoster: false,
                preloadProgress: 0,
                playingProgress: 0,
                isDragProgressBar: false
            }
        },
        computed: {
            showError() {
                return this.state.error
            },
            videoElementRef() {
                return this.$refs.video
            },
            sourceElementRef() {
                return this.$refs.source
            },
            preloadProgressRate() {
                return {width: `${this.preloadProgress}%`}
            },
            size() {
                return {width: `${this.width}px`, height: `${this.height}px`}
            }
        },
        methods: {
            play() {
                if(this.ended){
                    this.ended = false
                    this.state.currentTime = 0
                }

                this.showPoster = false
                this.state.playing = true
                this.videoElementRef.play()
            },
            pause() {
                this.state.playing = false
                this.videoElementRef.pause()
            },
            changeZoom() {
                this.state.fullScreen = !this.state.fullScreen
            },
            changeVolume() {
                this.state.volume = Number(!this.state.volume)
                this.videoElementRef.volume = this.state.volume
                this.videoElementRef.volume = 0
            },
            durationChangeEvent(e) {
                this.state.totalTime = parseInt(e.target.duration, 10) * 1000
            },
            timeUpdateEvent(e) {
                this.state.currentTime = parseInt(e.target.currentTime, 10) * 1000

                if(!this.isDragProgressBar){
                    this.playingProgress = parseInt(e.target.currentTime * 100000 / this.videoElementRef.duration, 10)
                }
            },
            endedEvent(e) {
                this.ended = true
                this.state.playing = false
                this.videoElementRef.removeEventListener('progress', this.progressEvent, false)
                this.loop && this.play()
            },
            errorEvent(e) {
                this.state.error = true
            },
            progressEvent(e) {
                this.preloadProgress = (this.videoElementRef.buffered.end(this.videoElementRef.buffered.length - 1) / this.videoElementRef.duration) * 100
            },
            volumeChangeEvent(e) {
                console.log(e)
            },
            startDragProgressBar() {
                this.isDragProgressBar = true
            },
            stopDragProgressBar() {
                this.isDragProgressBar = false
                this.videoElementRef.currentTime = Math.floor(this.playingProgress * (this.videoElementRef.duration / 100000))
            }
        },
        mounted() {
            this.videoElementRef.addEventListener('ended', this.endedEvent, false)
            this.sourceElementRef.addEventListener('error', this.errorEvent, false)
            this.videoElementRef.addEventListener('progress', this.progressEvent, false)
            this.videoElementRef.addEventListener('timeupdate', this.timeUpdateEvent, false)
            this.videoElementRef.addEventListener('volumechange', this.volumeChangeEvent, false)
            this.videoElementRef.addEventListener('durationchange', this.durationChangeEvent, false)

            this.showPoster = Boolean(this.poster)
            this.autoplay && this.play()
        },
        destroyed() {
            this.videoElementRef.removeEventListener('ended', this.endedEvent, false)
            this.sourceElementRef.removeEventListener('error', this.errorEvent, false)
            this.videoElementRef.removeEventListener('progress', this.progressEvent, false)
            this.videoElementRef.removeEventListener('timeupdate', this.timeUpdateEvent, false)
            this.videoElementRef.removeEventListener('volumechange', this.volumeChangeEvent, false)
            this.videoElementRef.removeEventListener('durationchange', this.durationChangeEvent, false)
        },
        filters: {
            format(time) {
                let hours, minutes, seconds

                time = new Date(time)
                seconds = time.getUTCSeconds()
                hours = `${time.getUTCHours()}:`
                minutes = `${time.getUTCMinutes()}:`

                return `${hours === '0:' ? '' : hours}${minutes}${seconds  < 10 ? '0' + seconds : seconds}`
            }
        }
    }

    function volumeChangeSupported() {
        return !(/ipad|iphone|ipod|android|blackberry|windows ce|windows phone|webos|playbook/.exec(navigator.userAgent.toLowerCase()))
    }
</script>


feat: add dutch to language switcher

feat: add dutch to language switcher

<template lang='pug'>
  .nav.ml-auto
    button.nav-link(v-for='lang in languages' @click='Select(lang.code)') {{ lang.code }}
</template>

<script>
  // TODO: Implement solution that doesn't require importing Vue for live reload
  import Vue from 'vue'

  export default {
    components: {
      language: {
        props: ['code']
      }
    },
    data () {
      return {
        lang: this.$lang,
        languages: [
          {
            code: 'EN'
          },
          {
            code: 'JA'
          },
          {
            code: 'NL'
          }
        ],
        Select: langNew => {
          console.info(`[HB]: Language set to ${langNew}`)
          Vue.config.lang = langNew.toLowerCase()
          this.$cookie.set('lang', langNew.toLowerCase())
        }
      }
    }
  }
</script>

<style lang='sass' scoped>
  @import ~styles/variables

  .nav
    position: relative
    top: 2px

  button
    flex: 0 1 auto
    cursor: pointer
    color: rgba($white, .7)
    background: transparent
    border: 0
    padding: .5em .5rem
    font-size: .75rem

    &:hover
      color: $white
</style>

<template lang='pug'>
  .nav.ml-auto
    button.nav-link(v-for='lang in languages' @click='Select(lang.code)') {{ lang.code }}
</template>

<script>
  // TODO: Implement solution that doesn't require importing Vue for live reload
  import Vue from 'vue'

  export default {
    components: {
      language: {
        props: ['code']
      }
    },
    data () {
      return {
        lang: this.$lang,
        languages: [
          {
            code: 'EN'
          },
          {
            code: 'JA'
          }
        ],
        Select: langNew => {
          console.info(`[HB]: Language set to ${langNew}`)
          Vue.config.lang = langNew.toLowerCase()
          this.$cookie.set('lang', langNew.toLowerCase())
        }
      }
    }
  }
</script>

<style lang='sass' scoped>
  @import ~styles/variables

  .nav
    position: relative
    top: 2px

  button
    flex: 0 1 auto
    cursor: pointer
    color: rgba($white, .7)
    background: transparent
    border: 0
    padding: .5em .5rem
    font-size: .75rem

    &:hover
      color: $white
</style>


fix: jobs shown as referenced in general !null query

<template>

                 0 && pagination.total > pagination.max" class="text-muted">
                  {{pagination.offset+1}}
                  -

                  {{pagination.offset+reports.length}}

                of

                  <span class="summary-count" :class="{ 'text-primary': pagination.total < 1, 'text-info': pagination.total > 0 }" v-if="pagination.total>=0">
                    {{pagination.total}}

                  {{$tc('execution',pagination.total>0?pagination.total:0)}}

          <activity-filter v-model="query" :event-bus="eventBus" :opts="filterOpts" v-if="showFilters"></activity-filter>

              <input type=checkbox id=auto-refresh v-model=autorefresh />
              {{$t('Auto refresh')}}

            0 && showBulkDelete">

                  <i18n path="bulk.selected.count">
                    {{bulkSelectedIds.length}}
                  </i18n>

                      <i18n path="select.all"/>

                      <i18n path="select.none"/>

                  <btn size="xs" type="danger" class="btn-fill"
                        :disabled="bulkSelectedIds.length<1"
                        @click="showBulkEditConfirm=true">
                      <i18n path="delete.selected.executions"/>
                  </btn>

                      <i18n path="cancel.bulk.delete"/>

              <btn size="xs" type="secondary" v-if="auth.deleteExec && !bulkEditMode" @click="bulkEditMode=true">
                  {{$t('bulk.delete')}}
              </btn>

    <modal  v-model="showBulkEditCleanSelections" id="cleanselections" :title="$t('Clear bulk selection')">

      <i18n tag="p" path="clearselected.confirm.text">
        {{bulkSelectedIds.length}}
      </i18n>

        <btn data-dismiss="modal">{{$t('cancel')}}</btn>
        <button type="submit"
                class="btn btn-default  "
                data-dismiss="modal"
                @click="bulkEditDeselectAll">
            {{$t('Only shown executions')}}
        </button>
        <button class="btn btn-danger "
                data-dismiss="modal"
                @click="bulkEditDeselectAllPages">
            {{$t('all')}}
        </button>

    </modal>

    <modal v-model="showBulkEditConfirm" id="bulkexecdelete" :title="$t('Bulk Delete Executions')">
      <i18n tag="p" path="delete.confirm.text">
        {{bulkSelectedIds.length}}
        {{$tc('execution',bulkSelectedIds.length)}}
      </i18n>

          <btn @click="showBulkEditConfirm=false">
              {{$t('cancel')}}
          </btn>
          <btn type="danger"
                @click="performBulkDelete"
                data-dismiss="modal">
              {{$t('Delete Selected')}}
          </btn>

    </modal>

    <modal v-model="showBulkEditResults" id="bulkexecdeleteresult" :title="$t('Bulk Delete Executions: Results')" >

                        {{$t('Requesting bulk delete, please wait.')}}

 0"
                        class="text-info">

                        <i18n path="bulkresult.attempted.text" tag="p" >
                          {{bulkEditResults.requestCount}}
                        </i18n>

 0"
                        class="text-success">

                        <i18n path="bulkresult.success.text" tag="p" >
                          {{bulkEditResults.successCount}}
                        </i18n>

 0"
                            class="text-warning">

                        <i18n path="bulkresult.failed.text" tag="p" >
                          {{bulkEditResults.failedCount}}
                        </i18n>

 0">

{{message}}

{{bulkEditError}}

                <btn @click="showBulkEditResults=false">{{$t('close')}}</btn>

    </modal>

0" class="running-executions">

                <input
                type="checkbox"
                name="bulk_edit"
                :value="exec.id"
                v-model="bulkSelectedIds"
                class="_defaultInput"/>

                      <progress-bar v-if="exec.status == 'scheduled'" :value="100" striped  type="default" label :label-text="$t('job.execution.starting.0',[runningStartedDisplay(exec.dateStarted.date)])" />
                      <progress-bar v-else-if="exec.job && exec.job.averageDuration" :value="jobDurationPercentage(exec)" striped active type="info" label min-width/>
                      <progress-bar v-else-if="exec.dateStarted.date" :value="100" striped active type="info" label :label-text="$t('running')" />

                    <i18n path="by" default="by"/>
                    {{exec.user}}

                    {{exec.job.name}}

                          {{key}}:
                          {{value}}

                    {{exec.description}}

                    #{{exec.id}}

0">

                {{ $tc('info.newexecutions.since.0', sincecount) }}

 0">

                <input
                type="checkbox"
                name="bulk_edit"
                :value="rpt.executionId"
                v-model="bulkSelectedIds"
                class="_defaultInput"/>

                        {{rpt.dateCompleted | moment(momentJobFormat)}}

                        {{rpt.dateCompleted | moment('calendar',null)}}

                        {{rpt.dateCompleted | moment('from','now')}}

                0">{{rpt.node.failed}} {{$t('failed')}}
                0">{{rpt.node.succeeded}} {{$t('ok')}}

                <i18n path="by" default="by"/>
                {{rpt.user}}

                    {{rpt.jobName}}

                    {{rpt.executionString}}

                    {{$t('Referenced')}}

                      {{$t('job.has.been.deleted.0',[rpt.jobName])}}

                    {{rpt.execution.status}}

                        {{key}}:
                        {{value}}

                {{rpt.execution.argString}}

                #{{rpt.executionId}}

    <div v-if="reports.length < 1 " class="loading-area">

          {{$t('results.empty.text')}}

        <div class="loading-text" v-if="loading && lastDate<0">

          {{$t('Loading...')}}

          {{$t('error.message.0',[loadError])}}

    <offset-pagination
          :pagination="pagination"
          @change="changePageOffset($event)"
          :disabled="loading"
          :showPrefix="false"
        >
        </offset-pagination>

</template>


Fix frontend navbar style

Fix frontend navbar style

<template>

            {{ $t("components.navbar.help") }}

            {{ $t("components.navbar.vpn.download") }}

            {{ $t("components.navbar.admin") }}

            {{ user.name }} [{{ user.role }}]

    <Help />

</template>


Add link to the publications of a classfiication

<template>

        Type {{cls.productionClassificationType}}
        Periode {{cls.productionClassificationCulturePeople}}
        Heerser {{cls.productionClassificationRulerNation}}
        Datering {{ vC(cls.startDate) }} - {{ vC(cls.endDate, cls.startDate) }}

        Referentie:

          {{ singlePub.publicationTitle }}

        Referenties:

          {{ pub.publicationTitle }}

         {{cls.agree}} vondstexpert{{cls.agree===1?' is':'s zijn'}} het eens met deze classificatie

         {{cls.disagree}} vondstexpert{{cls.disagree===1?' is':'s zijn'}} het oneens met deze classificatie

        <button class="btn" :class="{green:cls.me==='agree'}" @click.stop="agree"></button>
        <button class="btn" :class="{red:cls.me==='disagree'}" @click.stop="disagree"></button>

        Opgesteld
        door {{creator}}
        <time v-if="cls.created_at" :title="cls.created_at">op {{cls.created_at | fromDate}}</time>
        <time v-if="cls.updated_at!==cls.created_at" :title="cls.updated_at" style="margin-left:1em">update op {{cls.updated_at | fromDate}}</time>

        <button class="btn" @click.prevent.stop="rm" v-if="$root.user.administrator"></button>

</template>

<template>

        Type {{cls.productionClassificationType}}
        Periode {{cls.productionClassificationCulturePeople}}
        Heerser {{cls.productionClassificationRulerNation}}
        Datering {{ vC(cls.startDate) }} - {{ vC(cls.endDate, cls.startDate) }}

        Referentie:

        Referenties:

         {{cls.agree}} vondstexpert{{cls.agree===1?' is':'s zijn'}} het eens met deze classificatie

         {{cls.disagree}} vondstexpert{{cls.disagree===1?' is':'s zijn'}} het oneens met deze classificatie

        <button class="btn" :class="{green:cls.me==='agree'}" @click.stop="agree"></button>
        <button class="btn" :class="{red:cls.me==='disagree'}" @click.stop="disagree"></button>

        Opgesteld
        door {{creator}}
        <time v-if="cls.created_at" :title="cls.created_at">op {{cls.created_at | fromDate}}</time>
        <time v-if="cls.updated_at!==cls.created_at" :title="cls.updated_at" style="margin-left:1em">update op {{cls.updated_at | fromDate}}</time>

        <button class="btn" @click.prevent.stop="rm" v-if="$root.user.administrator"></button>

</template>


move progress bar to top, so it is more visible

<template>

        <transition name="fade">
            <div class="progress mb-2" style="height: 1px;" v-if="progress<100">

                    {{progress}}

        </transition>

</template>

<template>

        <transition name="fade">
            <div class="progress" style="height: 1px;" v-if="progress<100">

                    {{progress}}

        </transition>

</template>


fix error

fix error

<template>

  Head position correct

  Your face is off the camera

					<Countdown timespan="300" style=""></Countdown>

			<Webcam style="visibility:hidden; position:absolute"/>

		<question v-if="totalCount > 0 && mode == 'question' " v-on:action="changeView($event)"></question>
		<review v-if="mode == 'review' " v-on:action="changeView($event)"></review>

</template>


Reset canDisplay on previews on destroy

Reset canDisplay on previews on destroy

<template>

			<template v-if="link.type === 'link'">

							{{ link.head }}

						<button
							v-if="showMoreButton"
							:aria-expanded="isContentShown"
							:aria-label="moreButtonLabel"
							class="more"
							@click="onMoreClick"
						></button>

						{{ link.body }}

			</template>
			<template v-else-if="link.type === 'image'">

			</template>
			<template v-else-if="link.type === 'video'">
				<video
					preload="metadata"
					controls
					@canplay="onPreviewReady">
					<source
						:src="link.media"
						:type="link.mediaType">
				</video>
			</template>
			<template v-else-if="link.type === 'audio'">
				<audio
					controls
					preload="metadata"
					@canplay="onPreviewReady">
					<source
						:src="link.media"
						:type="link.mediaType">
				</audio>
			</template>
			<template v-else-if="link.type === 'error'">

					This image is larger than {{ link.maxSize | friendlysize }} and cannot be
					previewed.
					Click here
					to open it in a new window.

				<template v-else-if="link.error === 'message'">

							A preview could not be loaded.
							Click here
							to open it in a new window.

{{ link.message }}

					<button
						:aria-expanded="isContentShown"
						:aria-label="moreButtonLabel"
						class="more"
						@click="onMoreClick"
					></button>
				</template>
			</template>

</template>


[Fix] Update Episode view with the response body

<template>

    <Toolbar :title="episode.name">

        <button class="material-icons mdc-toolbar__icon mdc-ripple-surface" arial-label="Edit" v-on:click="editEpisode">edit</button>
        <time v-if="episode.started">{{ timePlayed | formatTime }}</time>
        <button v-if="episode.started && !episode.ended" class="material-icons mdc-toolbar__icon mdc-ripple-surface" arial-label="Stop" v-on:click="stopEpisode(episode)">stop</button>
        <button v-else class="material-icons mdc-toolbar__icon mdc-ripple-surface" arial-label="Playing" v-on:click="startEpisode(episode)">play_arrow</button>

    </Toolbar>

      <EpisodeDialog></EpisodeDialog>

        <TopicDialog></TopicDialog>
        <draggable
          v-if="topics.length > 0"
          element="ul"
          v-model="topics"
          :options="dragOptions"
          @change="itemMoved"
          class="topics mdc-list mdc-list--avatar-list mdc-list--two-line">
          <transition-group name="fade">
            <TopicCard v-for="topic in topics" :key="topic._id" :topic="topic" ></TopicCard>
          </transition-group>
        </draggable>
        <EmptyState v-else></EmptyState>
        <button class="mdc-fab material-icons fab" aria-label="add" data-mdc-auto-init="MDCRipple" v-on:click="addTopic">

            add

        </button>

</template>

<template>

    <Toolbar :title="episode.name">

        <button class="material-icons mdc-toolbar__icon mdc-ripple-surface" arial-label="Edit" v-on:click="editEpisode">edit</button>
        <time v-if="episode.started" :style="{ }">{{ timePlayed | formatTime }}</time>
        <button v-if="episode.started !== null && episode.ended === null" class="material-icons mdc-toolbar__icon mdc-ripple-surface" arial-label="Stop" v-on:click="stopEpisode(episode)">stop</button>
        <button v-else class="material-icons mdc-toolbar__icon mdc-ripple-surface" arial-label="Playing" v-on:click="startEpisode(episode)">play_arrow</button>

    </Toolbar>

      <EpisodeDialog></EpisodeDialog>

        <TopicDialog></TopicDialog>
        <draggable
          v-if="topics.length > 0"
          element="ul"
          v-model="topics"
          :options="dragOptions"
          @change="itemMoved"
          class="topics mdc-list mdc-list--avatar-list mdc-list--two-line">
          <transition-group name="fade">
            <TopicCard v-for="topic in topics" :key="topic._id" :topic="topic" ></TopicCard>
          </transition-group>
        </draggable>
        <EmptyState v-else></EmptyState>
        <button class="mdc-fab material-icons fab" aria-label="add" data-mdc-auto-init="MDCRipple" v-on:click="addTopic">

            add

        </button>

</template>


docs(Modal): optimize words

docs(Modal): optimize words

<template>

Modal 弹出框

Confirm

    <example demo="message/modal5"></example>

基础调用

    <example demo="message/modal6"></example>

全屏的Modal

    <example demo="message/modal12"></example>

自定义操作按钮

    <example demo="message/modal7"></example>

点击遮罩无法关闭

    <example demo="message/modal3"></example>

垂直居中的弹出框

    <example demo="message/modal4"></example>

无遮罩弹出框

    <example demo="message/modal2"></example>

有分割线的弹出框

    <example demo="message/modal9"></example>

Js的Modal调用组件

使用js调用弹出的组件式Modal，这样不仅方便参数的使用，还可以将js代码集成调用。

    <example demo="message/modal11"></example>

弹出框中使用的代码

    <codes src="/message/modalTest.vue" type="html"></codes>

Modal 参数

        参数
        说明
        类型
        可选值
        默认值

        hasCloseIcon
        是否有关闭的Icon
        Boolean
        -
        false

        hasMask
        是否有遮罩层
        Boolean
        -
        true

        content
        设定内容，目前只支持js定义
        String
        -
        -

        width
        设定宽度，目前只支持js定义
        Number
        -

        hasDivider
        是否有线条分割头部以及尾部
        Boolean
        -
        全局配置modal.hasDivider

        closeOnMask
        是否点击遮罩层关闭modal
        Boolean
        -
        true

        middle
        是否垂直居中展示
        Boolean
        -
        false

        fullScreen
        是否全屏
        Boolean
        -
        false

        buttons
        设定底层按钮，目前只支持js定义
        Array
        -
        ['cancel']

        events
        事件监听
        Object
        -
        -

        className
        自定义class
        String
        -
        -

</template>

<template>

Modal 弹出框

Confirm

    <example demo="message/modal5"></example>

基础调用

    <example demo="message/modal6"></example>

全屏的Modal

    <example demo="message/modal12"></example>

自定义操作按钮

    <example demo="message/modal7"></example>

点击遮罩无法关闭

    <example demo="message/modal3"></example>

垂直居中的弹出框

    <example demo="message/modal4"></example>

无遮罩弹出框

    <example demo="message/modal2"></example>

有分割线的弹出框

    <example demo="message/modal9"></example>

Js的Modal调用组件

使用js调用弹出的组件式Modal，这样不仅方便参数的使用，还可以将js代码集成调用。

    <example demo="message/modal11"></example>

弹出框中使用的代码

    <codes src="/message/modalTest.vue" type="html"></codes>

Modal 参数

        参数
        说明
        类型
        可选值
        默认值

        hasCloseIcon
        是否有关闭的Icon
        Boolean
        -
        false

        hasMask
        是否有遮罩层
        Boolean
        -
        true

        content
        设定内容
        String
        -
        -

        width
        设定宽度
        Number
        -

        hasDivider
        是否有线条分割头部以及尾部
        Boolean
        -
        全局配置modal.hasDivider

        closeOnMask
        是否点击遮罩层关闭modal
        Boolean
        -
        true

        middle
        是否垂直居中展示
        Boolean
        -
        false

        fullScreen
        是否全屏
        Boolean
        -
        false

        buttons
        设定底层按钮
        Array
        -
        ['cancel']

        events
        事件监听
        Object
        -
        -

        className
        自定义class
        String
        -
        -

</template>


Add modal note

Add modal note

<template>

Modal

Classic modal overlay to include any content you may need

            <button class="button is-primary is-medium" @click="isImageModalActive = true">Launch image modal</button>
            <button class="button is-primary is-medium" @click="isCardModalActive = true">Launch card modal</button>

John Smith

@johnsmith

                        Lorem ipsum dolor sit amet, consectetur adipiscing elit.
                        Phasellus nec iaculis mauris. @bulmaio.
                        #css #responsive

                        11:09 PM - 1 Jan 2016

{{ template1 | pre }}

Component Modal

A modal with an injected component. When you want to close the Modal, emit a 'close' event — this.$emit('close') — from the component.

The component will receive all props from the props object.

            <button class="button is-primary is-medium" @click="isComponentModalActive = true">Launch component modal</button>

{{ template2 | pre }}

{{ code2 | pre }}

ModalForm component

Note: You should't mutate a prop directly, this is just an example.

{{ component | pre }}

Programmatically opening

            <button class="button is-primary is-medium" @click="imageModal">Launch image modal</button>
            <button class="button is-primary is-medium" @click="cardModal">Launch card modal</button>

{{ code3 | pre }}

Programmatically opening Component Modal

            Note: You won't have access to Vue main instance ($store, $router, Buefy components, etc)
            from the component when opening programmatically. Use the non-programmatic Modal for that.

A modal with an injected component. When you want to close the Modal, emit a 'close' event — this.$emit('close') — from the component.

The component will receive all props from the props object.

            <button class="button is-primary is-medium" @click="componentModal">Launch component modal</button>

{{ code4 | pre }}

API

                    <template scope="props">

                            {{ props.row.type }}

                    </template>

                    <template scope="props">

                    </template>

</template>

<template>

Modal

Classic modal overlay to include any content you may need

            <button class="button is-primary is-medium" @click="isImageModalActive = true">Launch image modal</button>
            <button class="button is-primary is-medium" @click="isCardModalActive = true">Launch card modal</button>

John Smith

@johnsmith

                        Lorem ipsum dolor sit amet, consectetur adipiscing elit.
                        Phasellus nec iaculis mauris. @bulmaio.
                        #css #responsive

                        11:09 PM - 1 Jan 2016

{{ template1 | pre }}

Component Modal

A modal with an injected component. When you want to close the Modal, emit a 'close' event — this.$emit('close') — from the component.

The component will receive all props from the props object.

            <button class="button is-primary is-medium" @click="isComponentModalActive = true">Launch component modal</button>

{{ template2 | pre }}

{{ code2 | pre }}

ModalForm component

Note: You should't mutate a prop directly, this is just an example.

{{ component | pre }}

Programmatically opening

            <button class="button is-primary is-medium" @click="imageModal">Launch image modal</button>
            <button class="button is-primary is-medium" @click="cardModal">Launch card modal</button>

{{ code3 | pre }}

Programmatically opening Component Modal

            Note: You won't have access to Vue main instance ($store, $router, etc) from the component when opening programmatically.

A modal with an injected component. When you want to close the Modal, emit a 'close' event — this.$emit('close') — from the component.

The component will receive all props from the props object.

            <button class="button is-primary is-medium" @click="componentModal">Launch component modal</button>

{{ code4 | pre }}

API

                    <template scope="props">

                            {{ props.row.type }}

                    </template>

                    <template scope="props">

                    </template>

</template>


Improve readability

Improve readability

<template>

<slot name="icon"></slot>

		<slot></slot>
		<slot name="title"></slot>

<slot name="prefix"></slot>

		<template v-if="type != 'file'">
			<input v-if="debounce" ref="input"
				v-debounce="500"
				:type="type"
				v-model.lazy="v"
				:disabled="disabled"
				:required="required"
				:readonly="readonly"
				:placeholder="placeholder"
				:pattern="pattern"
				:autocomplete="autocomplete"
				:spellcheck="spellcheck"
				@focus="focused = true"
				@blur="focused = false"
				@keydown="$emit('keydown', $event)"
			>
			<input v-else ref="input"
				:type="type"
				v-model="v"
				:disabled="disabled"
				:required="required"
				:readonly="readonly"
				:placeholder="placeholder"
				:pattern="pattern"
				:autocomplete="autocomplete"
				:spellcheck="spellcheck"
				@focus="focused = true"
				@blur="focused = false"
				@keydown="$emit('keydown', $event)"
			>
		</template>
		<template v-else>
			<input ref="input"
				type="text"
				:value="filePlaceholder"
				readonly
				@click="chooseFile"
			>
			<input ref="file"
				type="file"
				:value="value"
				@change="onChangeFile"
			>
		</template>

<slot name="suffix"></slot>

			<fa :icon="['fa', 'eye']"/> {{ $t('@.show-password') }}
			<fa :icon="['far', 'eye-slash']"/> {{ $t('@.hide-password') }}

<slot name="desc"></slot>

</template>


remove now un-needed code from the gettingStarted page

<template>

You're already on your way to creating a pwa!

        We've had a look over your site and it's looking good.
        You've already got a manifest, which forms the base of a PWA,
        but we highly recommend you add some features like
        Service Workers to make the experience even better for your users.

Your App Results

      <GoodPWA :isHttps="true" :allGoodWithText="true" />

</template>


Show color picker on 'custom color' checker

<template>

          App Image Generator

 Quickly and easily create app icons for various platforms in the right size and format

        <form id="imageFileInputForm" enctype="multipart/form-data" role="form" ref="form">

                Image Details

                Specify the image details below.

                  Input Image

                      {{labelFileName}}

                  <input id="fileName" name="fileName" class="l-hidden" type="file" ref="fileName" @change="changeLabel" />

                Padding
                <input class="pwa-generator-input pwa-generator-input--hassmall" name="padding" type="number" value="0.3" min="0" step="any" />
                0 is no padding, 1 is 100% of the source image. 0.3 is a typical value for most icons

                Background Color

                    <input type="radio" name="colorOption" class="colorOption" checked="checked" @click="clickColorOption" value="0" />
                    Transparent

                    <input type="radio" name="colorOption" class="colorOption" value="1" @click="clickColorOption"/>
                    Custom color

                    <input class="pwa-generator-input pwa-generator-input--tiny input-color" type="color" />
                    <input class="pwa-generator-input pwa-generator-input--small pwa-generator-input--hassmall" placeholder="#000000" name="color" id="color" type="text" />
                    <input type="hidden" name="colorChanged" id="colorChanged" value="0" />
                    Choose a color for the background (leave blank to default to the pixel at the top left)

                  Platforms

Select the platforms to generate images for.

(*) windows platform generates images for Windows 8.1 and Windows Phone 8.1 apps.

                      <input type="checkbox" name="platform" value="windows10" v-model="platforms">
                      windows10

                      <input type="checkbox" name="platform" value="windows" v-model="platforms">
                      windows *

                      <input type="checkbox" name="platform" value="android"
                        v-model="platforms">
                      android

                      <input type="checkbox" name="platform" value="ios" v-model="platforms">
                      ios

                      <input type="checkbox" name="platform" value="chrome" v-model="platforms">
                      chrome

                      <input type="checkbox" name="platform" value="firefox" v-model="platforms">
                      firefox

                    <button id="selectPlatforms" @click.prevent="checkAll" class="pwa-button pwa-button--simple">
                      Select/Clear All
                    </button>

                <button class="pwa-button" id="downloadButton" ref="downloadButton" v-on:click.prevent="useAPI"
                :disabled='disableDownload'> Download
                </button>

        </form>

</template>

<template>

          App Image Generator

 Quickly and easily create app icons for various platforms in the right size and format

        <form id="imageFileInputForm" enctype="multipart/form-data" role="form" ref="form">

                Image Details

                Specify the image details below.

                  Input Image

                      {{labelFileName}}

                  <input id="fileName" name="fileName" class="l-hidden" type="file" ref="fileName" @change="changeLabel" />

                Padding
                <input class="pwa-generator-input pwa-generator-input--hassmall" name="padding" type="number" value="0.3" min="0" step="any" />
                0 is no padding, 1 is 100% of the source image. 0.3 is a typical value for most icons

                Background Color

                    <input type="radio" name="colorOption" class="colorOption" checked="checked" value="0" />
                    Transparent

                    <input type="radio" name="colorOption" class="colorOption" value="1" />
                    Custom color

                    <input class="pwa-generator-input pwa-generator-input--tiny input-color" type="color" />
                    <input class="pwa-generator-input pwa-generator-input--small pwa-generator-input--hassmall" placeholder="#000000" name="color" id="color" type="text" />
                    <input type="hidden" name="colorChanged" id="colorChanged" value="0" />
                    Choose a color for the background (leave blank to default to the pixel at the top left)

                  Platforms

Select the platforms to generate images for.

(*) windows platform generates images for Windows 8.1 and Windows Phone 8.1 apps.

                      <input type="checkbox" name="platform" value="windows10" v-model="platforms">
                      windows10

                      <input type="checkbox" name="platform" value="windows" v-model="platforms">
                      windows *

                      <input type="checkbox" name="platform" value="android"
                        v-model="platforms">
                      android

                      <input type="checkbox" name="platform" value="ios" v-model="platforms">
                      ios

                      <input type="checkbox" name="platform" value="chrome" v-model="platforms">
                      chrome

                      <input type="checkbox" name="platform" value="firefox" v-model="platforms">
                      firefox

                    <button id="selectPlatforms" @click.prevent="checkAll" class="pwa-button pwa-button--simple">
                      Select/Clear All
                    </button>

                <button class="pwa-button" id="downloadButton" ref="downloadButton" v-on:click.prevent="useAPI"
                :disabled='disableDownload'> Download
                </button>

        </form>

</template>


Удаление лишнего пробела в чтениях

Удаление лишнего пробела в чтениях

<template>

  <transition name="fade">

          <button class="btn btn-default" @click="toggleLabels()">{{ toggleLabelsText }}</button>
          <button class="btn btn-default" @click="shuffleAll()">Перемешать все</button>
          <button class="btn btn-default" @click="toggleBurned()" v-if="!guest">{{ toggleBurnedText }}</button>

          <template v-for="(collection, lvl) in filteredElements" v-if="collection.length">
            <a class="badge badge-secondary f16 ja-shadow-light mr-1 mb-1" :href="`#level-${lvl}`">
              {{ lvl }}

          </template>

      <template v-for="(collection, lvl) in filteredElements" v-if="collection.length">
        <a :name="`level-${lvl}`">

            Уровень {{ lvl }}
            Словарные слова
            {{ collection.length }}

            <button class="btn btn-default" @click="toggleLabels()" v-if="level > 0">{{ toggleLabelsText }}</button>
            <button class="btn btn-default" @click="shuffleLevel(lvl)">Перемешать</button>
            <button class="btn btn-default" @click="toggleBurned()" v-if="level > 0 && !guest">{{ toggleBurnedText }}</button>

          <template v-for="row in collection">

              {{ row.character }}

            ？
            <div class="text-muted"
                 :class="{ invisible: !labels && !revealed.includes(row.id), 'mt-3 mt-md-0': labels }"
                 :id="`kana-${row.id}`"
            >

                【{{ kana }}】

            <div :class="{ invisible: !labels && !revealed.includes(row.id), 'mb-4 mb-md-0': row.burned }"
                 :id="`meaning-${row.id}`"
            >{{ row.meaning }}

              <svg class="svg-icon svg-flame" viewBox="0 0 12 16" width="16" height="16"><path d="M5.05.31c.81 2.17.41 3.38-.52 4.31C3.55 5.67 1.98 6.45.9 7.98c-1.45 2.05-1.7 6.53 3.53 7.7-2.2-1.16-2.67-4.52-.3-6.61-.61 2.03.53 3.33 1.94 2.86 1.39-.47 2.3.53 2.27 1.67-.02.78-.31 1.44-1.13 1.81 3.42-.59 4.78-3.42 4.78-5.56 0-2.84-2.53-3.22-1.25-5.61-1.52.13-2.03 1.13-1.89 2.75.09 1.08-1.02 1.8-1.86 1.33-.67-.41-.66-1.19-.06-1.78C8.18 5.31 8.68 2.45 5.05.32L5.03.3l.02.01z"/></svg>

          </template>

      </template>

  </transition>

</template>


Improved rooms layout on mobile screen

Improved rooms layout on mobile screen

<template>

      direct  messages
      <router-link
        to="/create-private-room"
        class="icon-plus-squared"
        title="Create direct room"
      />

      <room-users-private
        v-for="room in privateRooms"
        :key="room.id"
        :room="room"
      />

      rooms
      <router-link
        to="/create-public-room"
        class="icon-plus-squared"
        title="Create public room"
      />

      <room-users-public
        v-for="room in publicRooms"
        :key="room.id"
        :room="room"
      />

      {{ onlineText }}
      <router-link
        :to="`/invite-user/${activeRoomId}`"
        class="icon-user-plus"
        title="Add user to current active channel"
      />

      <room-users-user
        v-for="user in usersArray"
        :key="user.id"
        :user="user"
      />

</template>


Removed exact to prevent button state as not active, when title is changed

<template>

    <v-app-bar v-if="$vuetify.breakpoint.smAndUp" app
               clipped-left
               color="blue-grey darken-4" dark>
      <logo>
        <v-btn :to="campRoute(camp(), 'program')" class="justify-start px-2"
               text
               width="216">
          <v-toolbar-title>
            {{ camp().title | loading('Camp wird geladen…') }}
          </v-toolbar-title>
        </v-btn>
      </logo>

      <v-toolbar-items>
        <v-btn :to="campRoute(camp(), 'collaborators')" text>
          <v-icon :left="$vuetify.breakpoint.mdAndUp">mdi-account-group</v-icon>
          Team
        </v-btn>
        <v-btn :to="campRoute(camp(), 'admin')" text>
          <v-icon :left="$vuetify.breakpoint.mdAndUp">mdi-cogs</v-icon>
          Admin
        </v-btn>
      </v-toolbar-items>
      <v-spacer />
      <desktop-search />

    </v-app-bar>
    <v-bottom-navigation v-else app
                         fixed grow>
      <v-btn>
        Material
        <v-icon>mdi-package-variant</v-icon>
      </v-btn>
      <v-btn>
        Tasks
        <v-icon>mdi-format-list-checks</v-icon>
      </v-btn>
      <v-btn :to="{name: 'camp/program'}">
        Camp
        <v-icon large>mdi-tent</v-icon>
      </v-btn>
      <v-btn :to="{name: 'camp/collaborators'}" exact>
        Team
        <v-icon>mdi-account-group</v-icon>
      </v-btn>
      <v-btn :to="{name: 'camp/admin'}">
        Admin
        <v-icon>mdi-cogs</v-icon>
      </v-btn>
    </v-bottom-navigation>

</template>

<template>

    <v-app-bar v-if="$vuetify.breakpoint.smAndUp" app
               clipped-left
               color="blue-grey darken-4" dark>
      <logo>
        <v-btn :to="campRoute(camp(), 'program')" class="justify-start px-2"
               text
               width="216">
          <v-toolbar-title>
            {{ camp().title | loading('Camp wird geladen…') }}
          </v-toolbar-title>
        </v-btn>
      </logo>

      <v-toolbar-items>
        <v-btn :to="campRoute(camp(), 'collaborators')" text>
          <v-icon :left="$vuetify.breakpoint.mdAndUp">mdi-account-group</v-icon>
          Team
        </v-btn>
        <v-btn :to="campRoute(camp(), 'admin')" exact text>
          <v-icon :left="$vuetify.breakpoint.mdAndUp">mdi-cogs</v-icon>
          Admin
        </v-btn>
      </v-toolbar-items>
      <v-spacer />
      <desktop-search />

    </v-app-bar>
    <v-bottom-navigation v-else app
                         fixed grow>
      <v-btn>
        Material
        <v-icon>mdi-package-variant</v-icon>
      </v-btn>
      <v-btn>
        Tasks
        <v-icon>mdi-format-list-checks</v-icon>
      </v-btn>
      <v-btn :to="{name: 'camp/program'}">
        Camp
        <v-icon large>mdi-tent</v-icon>
      </v-btn>
      <v-btn :to="{name: 'camp/collaborators'}" exact>
        Team
        <v-icon>mdi-account-group</v-icon>
      </v-btn>
      <v-btn :to="{name: 'camp/admin'}">
        Admin
        <v-icon>mdi-cogs</v-icon>
      </v-btn>
    </v-bottom-navigation>

</template>


zmiana nazwy metody zgodna z jej przeznaczeniem

<template>

        <a @click="toggleTag({ name: tag })" class="suggest" :title="`Dodaj tag '${tag}'`">

          {{ tag }}

          {{ tag.name }}

    <input
      v-model="searchText"
      :style="`width: ${inputWidth}`"
      :placeholder="placeholder"
      @keyup.space="filter"
      @keyup.enter.prevent="filter"
      @keyup.esc="dropdown.toggleDropdown(false)"
      @keyup.up.prevent="dropdown.goUp"
      @keyup.down.prevent="dropdown.goDown"
      ref="input"
      type="text"
      tabindex="4"
      autocomplete="off"
      name="tags"
    >

    <vue-dropdown :items="filteredTags" @select="toggleTag" :default-index="-1" ref="dropdown" class="tag-dropdown mt-2">
      <template v-slot:item="slot">
        {{ slot.item.name }}
        ×{{ slot.item.topics }}
      </template>
    </vue-dropdown>

</template>

<template>

        <a @click="toggleTag({ name: tag })" class="suggest" :title="`Dodaj tag '${tag}'`">

          {{ tag }}

          {{ tag.name }}

    <input
      v-model="searchText"
      :style="`width: ${inputWidth}`"
      :placeholder="placeholder"
      @keyup.space="validateTag"
      @keyup.enter.prevent="validateTag"
      @keyup.esc="dropdown.toggleDropdown(false)"
      @keyup.up.prevent="dropdown.goUp"
      @keyup.down.prevent="dropdown.goDown"
      ref="input"
      type="text"
      tabindex="4"
      autocomplete="off"
      name="tags"
    >

    <vue-dropdown :items="filteredTags" @select="toggleTag" :default-index="-1" ref="dropdown" class="tag-dropdown mt-2">
      <template v-slot:item="slot">
        {{ slot.item.name }}
        ×{{ slot.item.topics }}
      </template>
    </vue-dropdown>

</template>


Update frontend/src/views/Camps.vue

Update frontend/src/views/Camps.vue

Co-authored-by: Carlo Beltrame <69088b01848c9e171296e8a6c10279802a3a8a84@beltra.me>

<template>
  <v-container fluid>
    <content-card :title="$tc('views.camps.title', camps.items.length)" max-width="800">
      <v-list class="py-0">
        <template v-if="camps._meta.loading">
          <v-skeleton-loader type="list-item-two-line" height="64" />
          <v-skeleton-loader type="list-item-two-line" height="64" />
        </template>
        <v-list-item
          v-for="camp in camps.items"
          :key="camp.id"
          two-line>
          <v-list-item-content @click.prevent="goToCamp(camp)">
            <v-list-item-title>{{ camp.title }}</v-list-item-title>
            <v-list-item-subtitle>
              {{ camp.name }} - {{ camp.campType().organization().name }}
            </v-list-item-subtitle>
          </v-list-item-content>
          <v-list-item-action>
            <dialog-entity-delete :entity="camp">
              <template v-slot:activator="{ on }">
                <button-delete @click.prevent="on.click" />
              </template>
              {{ $tc('components.dialog.dialogEntityDelete.warningText') }}

{{ camp.title }}"

            </dialog-entity-delete>
          </v-list-item-action>
        </v-list-item>
        <v-divider />
        <v-list-item>
          <v-list-item-content />
          <v-list-item-action>
            <button-add
              icon="mdi-plus"
              :to="{ name: 'camps/create' }">
              {{ $tc('views.camps.create') }}
            </button-add>
          </v-list-item-action>
        </v-list-item>
      </v-list>
    </content-card>
  </v-container>
</template>


Fix info widgets icons

Fix info widgets icons

<template>

      <vuestic-widget class="info-widget">

              59

{{'dashboard.elements' | translate}}

      </vuestic-widget>

      <vuestic-widget class="info-widget">

              12

{{'dashboard.versions' | translate}}

      </vuestic-widget>

      <vuestic-widget class="info-widget brand-danger">

                425

Commits

              <vuestic-progress-bar type="circle" ref="circleProgress" :colorName="'white'" :backgroundColorName="'danger'"
                            :startColorName="'danger'"></vuestic-progress-bar>

      </vuestic-widget>

      <vuestic-widget class="info-widget brand-info">

              5

{{'dashboard.teamMembers' | translate}}

      </vuestic-widget>

</template>


[playlists] Keep drawing mode when selecting a preview

<template>

      {{ $t('playlists.client_playlist') }}

      {{ playlist.name }}

    <button-simple
      @click="$emit('show-add-entities')"
      class="playlist-button add-entities-button flexrow-item"
      icon="plus"
      :text="addEntitiesText"
      v-if="isCurrentUserManager && !isAddingEntity"
    />
    <button-simple
      @click="$emit('edit-clicked')"
      class="edit-button playlist-button flexrow-item"
      :title="$t('playlists.actions.edit')"
      icon="edit"
      v-if="isCurrentUserManager"
    />
    <button-simple
      @click="showDeleteModal"
      class="delete-button playlist-button flexrow-item"
      :title="$t('playlists.actions.delete')"
      icon="delete"
      v-if="isCurrentUserManager"
    />

      <raw-video-player
        ref="raw-player-comparison"
        class="raw-player"
        :style="{
          position: isComparisonOverlay ? 'absolute': 'static'
        }"
        :entities="entityListToCompare"
        :is-repeating="isRepeating"
        :muted="true"
        :full-screen="fullScreen"
        name="comparison"
        v-show="isComparing && isCurrentPreviewMovie &&
                isMovieComparison && !isLoading"
      />

           It's not a picture preview

      <raw-video-player
        ref="raw-player"
        class="raw-player"
        :style="{
          position: isComparisonOverlay ? 'absolute': 'static',
          opacity: overlayOpacity
        }"
        :entities="entityList"
        :is-repeating="isRepeating"
        :muted="isMuted"
        :full-screen="fullScreen"
        @repeat="onVideoRepeated"
        @metadata-loaded="onMetadataLoaded"
        @entity-change="onPlayerEntityChange"
        @time-update="onTimeUpdate"
        @max-duration-update="onMaxDurationUpdate"
        v-show="isCurrentPreviewMovie && !isLoading"
      />

          <download-icon class="icon" />

            {{ $t('tasks.download_pdf_file', {extension: extension}) }}

        <spinner />

        <canvas
          id="playlist-annotation-canvas"
          ref="annotation-canvas"
          class="canvas"
        >
        </canvas>

    <task-info
      ref="task-info"
      :class="{
        'flexrow-item': true,
        'task-info-column': true,
        'hidden': isCommentsHidden
      }"
      :task="task"
      :is-preview="false"
    />

      <progress
        ref="progress"
        value="0"
        min="0"
        @click="onProgressBarClicked"
      >

      </progress>

  <annotation-bar
    class="playlist-annotations"
    ref="playlist-annotation"
    :annotations="annotations"
    :max-duration-raw="maxDurationRaw"
    @select-annotation="loadAnnotation"
    v-show="isCurrentPreviewMovie && playlist.id && !isAddingEntity"
  />

    <button-simple
      class="button playlist-button flexrow-item"
      @click="onPlayPreviousEntityClicked"
      :title="$t('playlists.actions.previous_shot')"
      icon="back"
    />
    <button-simple
      class="playlist-button flexrow-item"
      @click="onPlayNextEntityClicked"
      :title="$t('playlists.actions.next_shot')"
      icon="forward"
    />

      {{ entityList.length > 0 ? playingEntityIndex + 1 : 0 }}

    /

      {{ entityList.length }}

 1"
    >
      <button-simple
        class="button playlist-button flexrow-item"
        icon="left"
        :title="$t('playlists.actions.files_previous')"
        @click="onPreviousPreviewClicked"
      />

        {{ currentPreviewIndex + 1 }} / {{ currentEntityPreviewLength }}

      <button-simple
        class="button playlist-button flexrow-item"
        icon="right"
        :title="$t('playlists.actions.files_next')"
        @click="onNextPreviewClicked"
      />

        <arrow-up-right-icon class="icon is-small" />

      <button-simple
        class="button playlist-button flexrow-item"
        @click="onPlayClicked"
        :title="$t('playlists.actions.play')"
        icon="play"
        v-if="!isPlaying"
      />
      <button-simple
        class="button playlist-button flexrow-item"
        @click="onPlayClicked"
        :title="$t('playlists.actions.pause')"
        icon="pause"
        v-else
      />
      <button-simple
        class="button playlist-button flexrow-item"
        @click="onSpeedClicked"
        :title="$t('playlists.actions.speed')"
        text="x1.00"
        v-if="speed === 3"
      />
      <button-simple
        class="button playlist-button flexrow-item"
        @click="onSpeedClicked"
        :title="$t('playlists.actions.speed')"
        text="x0.50"
        v-else-if="speed === 2"
      />
      <button-simple
        class="button playlist-button flexrow-item"
        @click="onSpeedClicked"
        :title="$t('playlists.actions.speed')"
        text="x0.25"
        v-else
      />

      <button-simple
        class="flexrow-item playlist-button"
        :title="$t('playlists.actions.unmute')"
        icon="soundoff"
        @click="onToggleSoundClicked"
        v-if="isMuted"
      />
      <button-simple
        class="flexrow-item playlist-button"
        :title="$t('playlists.actions.mute')"
        icon="soundon"
        @click="onToggleSoundClicked"
        v-else
      />

      <button-simple
        class="button playlist-button flexrow-item"
        :active="isRepeating"
        :title="$t('playlists.actions.looping')"
        icon="repeat"
        @click="onRepeatClicked"
      />

        {{ currentTime }}

      /

        {{ maxDuration }}

        ({{ currentFrame }})

      <button-simple
        class="button playlist-button flexrow-item"
        @click="onPreviousFrameClicked"
        :title="$t('playlists.actions.previous_frame')"
        icon="left"
      />
      <button-simple
        class="button playlist-button flexrow-item"
        @click="onNextFrameClicked"
        :title="$t('playlists.actions.next_frame')"
        icon="right"
      />

      <button-simple
        :class="{
          'comparison-button': true,
          'flexrow-item': true,
          'playlist-button': true,
          active: isComparing
        }"
        :title="$t('playlists.actions.split_screen')"
        icon="compare"
        @click="onCompareClicked"
        v-if="taskTypeOptions && taskTypeOptions.length > 0"
      />

        <combobox
          class="playlist-button flexrow-item comparison-list"
          :options="taskTypeOptions"
          v-model="taskTypeToCompare"
          v-if="isComparing"
        />
        <combobox
          class="playlist-button flexrow-item comparison-list"
          :options="revisionOptions"
          v-model="revisionToCompare"
          v-if="isComparing"
        />
        <combobox
          class="playlist-button flexrow-item comparison-list"
          :options="comparisonModeOptions"
          v-model="comparisonMode"
          v-if="isComparing"
        />

 1
            "
          >
          <button-simple
            class="button playlist-button flexrow-item"
            icon="left"
            @click="onPreviousComparisonPictureClicked"
          />

          {{ currentComparisonPreviewIndex + 1 }} / {{ currentComparisonPreviewLength }}

          <button-simple
            class="button playlist-button flexrow-item"
            icon="right"
            @click="onNextComparisonPictureClicked"
          />

    <button-simple
      @click="$emit('save-clicked')"
      class="playlist-button flexrow-item"
      :title="$t('playlists.actions.save_playlist')"
      icon="save"
      v-if="isCurrentUserManager && tempMode"
    />

      <button-simple
        class="playlist-button flexrow-item"
        icon="undo"
        :title="$t('playlists.actions.annotation_undo')"
        @click="undoLastAction"
      />

      <button-simple
        class="playlist-button flexrow-item"
        :title="$t('playlists.actions.annotation_redo')"
        icon="redo"
        @click="redoLastAction"
      />

      <transition name="slide">

          <color-picker
            :isOpen="isShowingPalette"
            :color="this.textColor"
            :palette="this.palette"
            @TogglePalette="onPickColor"
            @change="onChangeTextColor"
          />

      </transition>
      <button-simple
        :class="{
          'playlist-button': true,
          'flexrow-item': true,
          active: isTyping
        }"
        :title="$t('playlists.actions.annotation_text')"
        @click="onTypeClicked"
        icon="type"
      />

      <transition name="slide">

          <pencil-picker
            :isOpen="isShowingPencilPalette"
            :pencil="pencil"
            :sizes="this.pencilPalette"
            @toggle-palette="onPickPencil"
            @change="onChangePencil"
          />

          <color-picker
            :isOpen="isShowingPalette"
            :color="this.color"
            :palette="this.palette"
            @TogglePalette="onPickColor"
            @change="onChangeColor"
          />

      </transition>
      <button-simple
        :class="{
          'playlist-button': true,
          'flexrow-item': true,
          active: isDrawing
        }"
        :title="$t('playlists.actions.annotation_draw')"
        @click="onAnnotateClicked"
        icon="pencil"
      />
      <button-simple
        class="playlist-button flexrow-item"
        icon="remove"
        :title="$t('playlists.actions.annotation_delete')"
        @click="onDeleteClicked"
      />

    <button-simple
      class="playlist-button flexrow-item"
      :title="$t('playlists.actions.change_task_type')"
      icon="layers"
      @click="showTaskTypeModal"
      v-if="!tempMode"
    />
    <button-simple
      class="button playlist-button flexrow-item"
      :title="$t('playlists.actions.comments')"
      @click="onCommentClicked"
      icon="comment"
    />
    <button-simple
      class="playlist-button flexrow-item"
      :title="$t('playlists.actions.entity_list')"
      @click="onFilmClicked"
      icon="film"
    />

        {{ $t('playlists.download_zip') }}

        {{ $t('playlists.download_csv') }}

        {{ $t('playlists.build_mp4') }}

        {{ $t('playlists.no_build') }}

            {{ $t('playlists.available_build') }}

              {{ $t('playlists.building') }}

              {{ $t('playlists.failed') }}

              {{ formatDate(job.created_at) }}

            <spinner
              class="build-spinner"
              v-if="job.status === 'running'"
            />
            <button
              class="delete-job-button"
              @click="onRemoveBuildJob(job)"
            >
              x
            </button>

      <button-simple
        class="playlist-button"
        :title="$t('playlists.actions.download')"
        icon="download"
        @click="toggleDlButtons"
      />

    <button-simple
      class="button playlist-button flexrow-item"
      :title="$t('playlists.actions.fullscreen')"
      @click="onFullscreenClicked"
      icon="maximize"
      v-if="isFullScreenEnabled"
    />

    <spinner class="spinner" v-if="isLoading" />

      <playlisted-entity
        :ref="'entity-' + index"
        :index="index"
        :entity="entity"
        :is-playing="playingEntityIndex === index"
        @play-click="playEntity"
        @remove-entity="removeEntity"
        @preview-changed="onPreviewChanged"
        @entity-dropped="onEntityDropped"
      />

  <delete-modal
    :active="modals.delete"
    :is-loading="loading.deletePlaylist"
    :is-error="errors.deletePlaylist"
    :text="deleteText"
    :error-text="$t('playlists.delete_error')"
    @confirm="confirmRemovePlaylist"
    @cancel="hideDeleteModal"
  />

  <select-task-type-modal
    :active="modals.taskType"
    :task-type-list="entityTaskTypes"
    @confirm="confirmChangeTaskType"
    @cancel="hideTaskTypeModal"
  />

</template>


Fix messages increasing heght when hovering them

Signed-off-by: Marco Ambrosini <3397c7e210a9d1588196cfebb12b2c6b133f6934@pm.me>

<docs>
This component displays the text inside the message component and can be used for
the main body of the message as well as a quote.
</docs>

<template>

		<Quote v-if="parent" v-bind="quote" />

{{ actorDisplayName }}

				<component
					:is="getComponentInstanceForMessagePart(block.type)"
					v-for="(block, i) in parsedMessage"
					:key="i"
					:data="block.data" />

					{{ messageTime }}

				<Actions v-show="showActions" class="message__main__right__actions">
					<ActionButton
						icon="icon-reply"
						:close-after-click="true"
						@click.stop="handleReply">
						Reply
					</ActionButton>
					<ActionButton
						icon="icon-delete"
						:close-after-click="true"
						@click.stop="handleDelete">
						Delete
					</ActionButton>
				</Actions>

</template>


No actions on temporary messages

No actions on temporary messages

Signed-off-by: Joas Schilling <ab43a7c9cb5b2380afc4ddf8b3e2583169b39a02@schilljs.com>

<docs>
This component displays the text inside the message component and can be used for
the main body of the message as well as a quote.
</docs>

<template>
	<li
		:id="`message_${id}`"
		ref="message"
		:data-message-id="id"
		:data-seen="seen"
		:data-next-message-id="nextMessageId"
		:data-previous-message-id="previousMessageId"
		class="message">

				{{ actorDisplayName }}

					<Quote v-if="parent" :parent-id="parent" v-bind="quote" />

						{{ message }}

					<RichText :text="message" :arguments="richParameters" :autolink="true" />
					<CallButton />

					<RichText :text="message" :arguments="richParameters" :autolink="true" />

					<Quote v-if="parent" :parent-id="parent" v-bind="quote" />
					<RichText :text="message" :arguments="richParameters" :autolink="true" />

					{{ messageTime }}

						<button
							v-if="sendingErrorCanRetry && showReloadButton"
							class="nc-button nc-button__main--dark"
							@click="handleRetry">
							<Reload
								decorative
								title=""
								:size="16" />
						</button>
						<AlertCircle v-else
							decorative
							title=""
							:size="16" />

						<CheckAll decorative
							title=""
							:size="16" />

						<Check decorative
							title=""
							:size="16" />

						<Actions
							v-show="isReplyable">
							<ActionButton
								icon="icon-reply"
								@click.stop="handleReply">
								{{ t('spreed', 'Reply') }}
							</ActionButton>
						</Actions>
						<Actions
							:force-menu="true"
							container="#content-vue">
							<ActionButton
								v-if="isPrivateReplyable"
								icon="icon-user"
								:close-after-click="true"
								@click.stop="handlePrivateReply">
								{{ t('spreed', 'Reply privately') }}
							</ActionButton>
							<ActionButton
								icon="icon-external"
								:close-after-click="true"
								@click.stop.prevent="handleCopyMessageLink">
								{{ t('spreed', 'Copy message link') }}
							</ActionButton>
							<ActionButton
								:close-after-click="true"
								@click.stop="handleMarkAsUnread">
								{{ t('spreed', 'Mark as unread') }}
							</ActionButton>
							<ActionSeparator v-if="messageActions.length > 0" />
							<template
								v-for="action in messageActions">
								<ActionButton
									:key="action.label"
									:icon="action.icon"
									:close-after-click="true"
									@click="action.callback(messageAPIData)">
									{{ action.label }}
								</ActionButton>
							</template>
							<template v-if="isDeleteable">
								<ActionSeparator />
								<ActionButton
									icon="icon-delete"
									:close-after-click="true"
									@click.stop="handleDelete">
									{{ t('spreed', 'Delete') }}
								</ActionButton>
							</template>
						</Actions>

				{{ t('spreed', 'Unread messages') }}

</template>


Warn the user in case of errors

Warn the user in case of errors

Signed-off-by: Marco Ambrosini <3397c7e210a9d1588196cfebb12b2c6b133f6934@pm.me>

<template>

		<button
			v-if="!isRecording"
			v-tooltip.auto="{
				content: startRecordingTooltip,
				delay: tooltipDelay,
			}"
			class="audio-recorder__trigger nc-button nc-button__main"
			@click="start">
			<Microphone
				:size="16"
				title=""
				decorative />
		</button>

			<button
				v-tooltip.auto="{
					content: abortRecordingTooltip,
					delay: tooltipDelay,
				}"
				class="audio-recorder__stop nc-button nc-button__main"
				@click="abortRecording">
				<Close
					:size="16"
					title=""
					decorative />
			</button>

					{{ parsedRecordTime }}

			<button
				v-tooltip.auto="{
					content: stopRecordingTooltip,
					delay: tooltipDelay,
				}"
				class="audio-recorder__trigger nc-button nc-button__main"
				:class="{'audio-recorder__trigger--recording': isRecording}"
				@click="stop">
				<Check
					:size="16"
					title=""
					decorative />
			</button>

</template>


修改user, testGrid无法查询的问题

修改user, testGrid无法查询的问题

<template>

现在使用json-server的模拟数据，模拟后端api.

    {{queryUrl}}|page:{{page}}
    <filter-pane :filters="filters" :sort-fields.sync="gridColumns" :sort-key.sync="sortKey" :order.sync="order" v-on:search="search"></filter-pane>
    <grid :data="gridData" :columns="gridColumns" :is-show-action="isShowAction" :actions="actions" :sort-key.sync="sortKey" :order.sync="order">
    </grid>
    <pagination :page.sync="page" :page-size.sync="pageSize" :page-size-list="pageSizeList" :records="records"></pagination>

</template>


fix: check if currentwallet is defined before checking for contact (#770)

<template>
  <MenuNavigation
    :id="activeWallet.address"
    ref="MenuNavigation"
    :class="{
      'WalletSidebar--slim': isSlim,
      'WalletSidebar--full': !isSlim
    }"
    class="WalletSidebar justify-start pt-0 overflow-y-auto"
    @input="onSelect"
  >

    <MenuNavigationItem
      v-if="selectableWallets.length === 0 && !isSlim"
      id="placeholder"
      :is-disabled="true"
      class="WalletSidebar__wallet opacity-37.5 select-none"
    >

        <WalletIdenticonPlaceholder
          :size="50"
          class="WalletSidebar__wallet__identicon flex-no-shrink"
        />

            {{ $t('PAGES.DASHBOARD.ADD_WALLET') }}

            {{ formatter_networkCurrency(0, 2) }}

    </MenuNavigationItem>

    <MenuNavigationItem
      v-if="isLoadingLedger"
      id="isLoadingLedger"
      :is-disabled="true"
      class="WalletSidebar__wallet__ledger-loader select-none"
    >

        <Loader />

          {{ $t('WALLET_SIDEBAR.LOADING_LEDGER') }}

    </MenuNavigationItem>

    <MenuNavigationItem
      v-for="wallet in selectableWallets"
      :id="wallet.id"
      :key="wallet.id"
      class="WalletSidebar__wallet"
    >

        <WalletIdenticon
          :size="50"
          :value="wallet.address"
          class="WalletSidebar__wallet__identicon flex-no-shrink"
        />

            {{ wallet_name(wallet.address) || wallet_truncate(wallet.address, isSlim ? 6 : 24) }}

            {{ formatter_networkCurrency(wallet.balance, 2) }}

    </MenuNavigationItem>
  </MenuNavigation>
</template>


更新样式模式～使其全局唯一化。

更新样式模式～使其全局唯一化。

<template>
  <form class="form-horizontal" :class="$style.container" @submit.prevent="submit">

      标题

        <input type="text" class="form-control" id="site-title" aria-describedby="site-title-help-block" placeholder="输入网站标题" v-model="title">

        网站标题，将在网页中显示在title的基本信息。也是搜索引擎为搜录做筛选标题的重要信息。

      关键词

        <input type="text" class="form-control" id="site-keywords" aria-describedby="site-keywords-help-block" placeholder="网站关键词" v-model="keywords">

        网站关键词，是通过搜索引擎检索网站的重要信息，多个关键词使用英文半角符号“,”分割。

      描述

        <input type="text" class="form-control" id="site-description" aria-describedby="site-description-help-block" placeholder="网站描述" v-model="description">

        描述用于简单的介绍站点，在搜索引擎中用于搜索结果的概述。

      ICP 备案信息

        <input type="text" class="form-control" id="site-icp" aria-describedby="site-icp-help-block" placeholder="网站描述" v-model="icp">

        填写 ICP 备案的信息，例如: 浙ICP备xxxxxxxx号

        <button v-if="loadding" class="btn btn-primary" disabled="disabled">

        </button>
        <button v-else-if="error" @click.prevent="requestSiteInfo" class="btn btn-danger">{{ error_message }}</button>
        <button v-else type="submit" class="btn btn-primary">{{ message }}</button>

  </form>
</template>

<template>
  <form class="form-horizontal app-setting-base-container" @submit.prevent="submit">

      标题

        <input type="text" class="form-control" id="site-title" aria-describedby="site-title-help-block" placeholder="输入网站标题" v-model="title">

        网站标题，将在网页中显示在title的基本信息。也是搜索引擎为搜录做筛选标题的重要信息。

      关键词

        <input type="text" class="form-control" id="site-keywords" aria-describedby="site-keywords-help-block" placeholder="网站关键词" v-model="keywords">

        网站关键词，是通过搜索引擎检索网站的重要信息，多个关键词使用英文半角符号“,”分割。

      描述

        <input type="text" class="form-control" id="site-description" aria-describedby="site-description-help-block" placeholder="网站描述" v-model="description">

        描述用于简单的介绍站点，在搜索引擎中用于搜索结果的概述。

      ICP 备案信息

        <input type="text" class="form-control" id="site-icp" aria-describedby="site-icp-help-block" placeholder="网站描述" v-model="icp">

        填写 ICP 备案的信息，例如: 浙ICP备xxxxxxxx号

        <button v-if="loadding" class="btn btn-primary" disabled="disabled">

        </button>
        <button v-else-if="error" @click.prevent="requestSiteInfo" class="btn btn-danger">{{ error_message }}</button>
        <button v-else type="submit" class="btn btn-primary">{{ message }}</button>

  </form>
</template>


removed one of the hardcoded example links

<template>

	<back-bar :title="title" />

			<el-tag type="danger">Call-to-action</el-tag>

			<el-tag type="success">Key links</el-tag>

</template>

<template>

	<back-bar :title="title" />

			<el-tag type="danger">Call-to-action</el-tag>

			<el-tag type="success">Site search</el-tag>

			<el-tag type="success">Key links</el-tag>

</template>


WIP https://github.com/kalisio/kdk/issues/6

<template>

      <template v-for="link in links">

            {{ $t(link.label) }}

      </template>

</template>

<template>

      <template v-for="link in links">

            {{ link.label }}

      </template>

</template>


selecting the first slice containing nodule area

<template>

          <template v-for="(nodule, index) in nodules">
            <nodule :nodule="nodule"
                    :index="index"
                    :selectedIndex="selectedIndex"
                    v-on:selected="selected"
                    :key="index">
              <annotate v-if="annotate" :nodule="nodule" :areaCoordinates="areaCoordinates"
                        :index="index" slot="add-on-editor">
              </annotate>
            </nodule>
          </template>

No nodules available.

      <open-dicom :view="viewerData" :showAreaSelect="true" :areaCoordinates="areaCoordinates"></open-dicom>

</template>


Return an empty object as default via ES6 func

VMapFilters disclaimer prop


Add “channel” icon to SelectContentPage

Add “channel” icon to SelectContentPage

<template>

          <KLabeledIcon>
            <KIcon slot="icon" channel />
            {{ channel.name }}
          </KLabeledIcon>

        <UiIcon
          v-if="channel.public === false"
          class="lock-icon"
        >
          <mat-svg name="lock_open" category="action" />
        </UiIcon>

        {{ $tr('version', { version: versionNumber }) }}

        {{ channel.description }}

        {{ $tr('resourcesCol') }}
        {{ $tr('sizeCol') }}

        {{ $tr('totalSizeRow') }}
        {{ $tr('resourceCount', { count: channel.total_resources || 0 }) }}
        {{ bytesForHumans(channel.total_file_size || 0) }}

        {{ $tr('onDeviceRow') }}
        {{ $tr('resourceCount', { count: channel.on_device_resources || 0 }) }}
        {{ bytesForHumans(channel.on_device_file_size || 0) }}

</template>

<template>

          {{ channel.name }}

        <UiIcon
          v-if="channel.public === false"
          class="lock-icon"
        >
          <mat-svg name="lock_open" category="action" />
        </UiIcon>

        {{ $tr('version', { version: versionNumber }) }}

        {{ channel.description }}

        {{ $tr('resourcesCol') }}
        {{ $tr('sizeCol') }}

        {{ $tr('totalSizeRow') }}
        {{ $tr('resourceCount', { count: channel.total_resources || 0 }) }}
        {{ bytesForHumans(channel.total_file_size || 0) }}

        {{ $tr('onDeviceRow') }}
        {{ $tr('resourceCount', { count: channel.on_device_resources || 0 }) }}
        {{ bytesForHumans(channel.on_device_file_size || 0) }}

</template>


Fix perftest popover to be rendered

Fix perftest popover to be rendered

<template>

            <button @click.prevent="downloadCSV" class="download-csv btn btn-primary float-right">

            </button>

                <h6 v-text="`${i18n('perfTest.report.header.meantime')} (ms)`">

                <h6 v-text="`${i18n('perfTest.report.header.meantimeToFirstByte')} (ms)`">

                <template v-for="(data, index) in userDefinedData">

                    <div class="chart" :id="`user-defined-chart-${index}`">

                </template>

</template>


resolved html flash <br/> in validation messages issue

<template>
    <div :class="typeClass" v-show="show" v-html="body">
        {{ body }}
    </div>
</template>

<script>
export default {
  props: ["message", "type"],

  data() {
    return {
      body: "",
      typeClass: "",
      show: false
    };
  },

  created() {
    var context = this;
    if (this.message && this.type) {
      this.flash(this.message, this.type);
    }

    window.events.$on("flash", function(message, type) {
      context.flash(message, type);
    });
  },

  methods: {
    flash(message, type) {

        if (! type) {
            type = "info";
        }

        this.body = message;
        this.typeClass = "alert alert-" + type;
        this.show = true;

        this.hide();
    },

    hide() {
      setTimeout(() => {
        this.show = false;
      }, 3000);
    }
  }
};
</script>

<template>
    <div :class="typeClass" v-show="show">
        {{ body }}
    </div>
</template>

<script>
export default {
  props: ["message", "type"],

  data() {
    return {
      body: "",
      typeClass: "",
      show: false
    };
  },

  created() {
    var context = this;
    if (this.message && this.type) {
      this.flash(this.message, this.type);
    }

    window.events.$on("flash", function(message, type) {
      context.flash(message, type);
    });
  },

  methods: {
    flash(message, type) {

        if (! type) {
            type = "info";
        }

        this.body = message;
        this.typeClass = "alert alert-" + type;
        this.show = true;

        this.hide();
    },

    hide() {
      setTimeout(() => {
        this.show = false;
      }, 3000);
    }
  }
};
</script>


Fix the flash component

Fix the flash component

Don’t let it slip beneath the footer

<template>
	<transition name="fade">

			Success! {{ body }}

	</transition>
</template>


Use computed for playlist/favorite url

Use computed for playlist/favorite url

<template>
  <li @dblclick.prevent="edit" :class="['playlist', type, editing ? 'editing' : '']">
    <a :href="playlistUrl"
      @dragleave="removeDroppableState"
      @dragover.prevent="allowDrop"
      @drop.stop.prevent="handleDrop"
      :class="{ active: active }"
    >{{ playlist.name }}</a>

    <input type="text"
      @keyup.esc="cancelEdit"
      @keyup.enter="update"
      @blur="update"
      v-model="playlist.name"
      v-koel-focus="editing"
      required
    >
  </li>
</template>

<script>
import $ from 'jquery';

import { event } from '../../../utils';
import { songStore, playlistStore, favoriteStore } from '../../../stores';

export default {
  props: ['playlist', 'type'],

  data() {
    return {
      newName: '',
      editing: false,
      active: false,
    };
  },

  computed: {
    /**
     * Determine if the current menu item is the "Favorites" one.
     *
     * @return {Boolean}
     */
    isFavorites() {
      return this.type === 'favorites';
    },

    playlistUrl() {
      return this.isFavorites ? '/#!/favorites' : `/#!/playlist/${this.playlist.id}`;
    },
  },

  methods: {
    /**
     * Show the form to edit the playlist.
     */
    edit() {
      if (this.isFavorites) {
        return;
      }

      this.beforeEditCache = this.playlist.name;
      this.editing = true;
    },

    /**
     * Update the playlist's name.
     */
    update() {
      if (this.isFavorites || !this.editing) {
        return;
      }

      this.editing = false;

      this.playlist.name = this.playlist.name.trim();
      if (!this.playlist.name) {
        this.playlist.name = this.beforeEditCache;
        return;
      }

      playlistStore.update(this.playlist);
    },

    /**
     * Cancel editing.
     */
    cancelEdit() {
      this.editing = false;
      this.playlist.name = this.beforeEditCache;
    },

    /**
     * Remove the droppable state when a dragleave event occurs on the playlist's DOM element.
     *
     * @param {Object} e The dragleave event.
     */
    removeDroppableState(e) {
      $(e.target).removeClass('droppable');
    },

    /**
     * Add a "droppable" class and set the drop effect when an item is dragged over the playlist's
     * DOM element.
     *
     * @param {Object} e The dragover event.
     */
    allowDrop(e) {
      $(e.target).addClass('droppable');
      e.dataTransfer.dropEffect = 'move';

      return false;
    },

    /**
     * Handle songs dropped to our favorite or playlist menu item.
     *
     * @param  {Object}   e    The event
     *
     * @return {Boolean}
     */
    handleDrop(e) {
      this.removeDroppableState(e);

      if (!e.dataTransfer.getData('application/x-koel.text+plain')) {
        return false;
      }

      const songs = songStore.byIds(e.dataTransfer.getData('application/x-koel.text+plain').split(','));

      if (!songs.length) {
        return false;
      }

      if (this.type === 'favorites') {
        favoriteStore.like(songs);
      } else {
        playlistStore.addSongs(this.playlist, songs);
      }

      return false;
    },
  },

  created() {
    event.on('main-content-view:load', (view, playlist) => {
      if (view === 'favorites') {
        this.active = this.isFavorites;
      } else if (view === 'playlist') {
        this.active = this.playlist === playlist;
      } else {
        this.active = false;
      }
    });
  },
};
</script>

<style lang="sass" scoped>
@import "../../../../sass/partials/_vars.scss";
@import "../../../../sass/partials/_mixins.scss";

.playlist {
  user-select: none;

  a {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;

    span {
      pointer-events: none;
    }

    &::before {
      content: "\f0f6";
    }
  }

  &.favorites a::before {
    content: "\f004";
    color: $colorHeart;
  }

  input {
    display: none;

    width: calc(100% - 32px);
    margin: 5px 16px;
  }

  &.editing {
    a {
      display: none !important;
    }

    input {
      display: block;
    }
  }
}
</style>

<template>
  <li @dblclick.prevent="edit" :class="['playlist', type, editing ? 'editing' : '']">
    <a :href="isFavorites ? '/#!/favorites' : `/#!/playlist/${playlist.id}`"
      @dragleave="removeDroppableState"
      @dragover.prevent="allowDrop"
      @drop.stop.prevent="handleDrop"
      :class="{ active: active }"
    >{{ playlist.name }}</a>

    <input type="text"
      @keyup.esc="cancelEdit"
      @keyup.enter="update"
      @blur="update"
      v-model="playlist.name"
      v-koel-focus="editing"
      required
    >
  </li>
</template>

<script>
import $ from 'jquery';

import { event } from '../../../utils';
import { songStore, playlistStore, favoriteStore } from '../../../stores';

export default {
  props: ['playlist', 'type'],

  data() {
    return {
      newName: '',
      editing: false,
      active: false,
    };
  },

  computed: {
    /**
     * Determine if the current menu item is the "Favorites" one.
     *
     * @return {Boolean}
     */
    isFavorites() {
      return this.type === 'favorites';
    },
  },

  methods: {
    /**
     * Show the form to edit the playlist.
     */
    edit() {
      if (this.isFavorites) {
        return;
      }

      this.beforeEditCache = this.playlist.name;
      this.editing = true;
    },

    /**
     * Update the playlist's name.
     */
    update() {
      if (this.isFavorites || !this.editing) {
        return;
      }

      this.editing = false;

      this.playlist.name = this.playlist.name.trim();
      if (!this.playlist.name) {
        this.playlist.name = this.beforeEditCache;
        return;
      }

      playlistStore.update(this.playlist);
    },

    /**
     * Cancel editing.
     */
    cancelEdit() {
      this.editing = false;
      this.playlist.name = this.beforeEditCache;
    },

    /**
     * Remove the droppable state when a dragleave event occurs on the playlist's DOM element.
     *
     * @param {Object} e The dragleave event.
     */
    removeDroppableState(e) {
      $(e.target).removeClass('droppable');
    },

    /**
     * Add a "droppable" class and set the drop effect when an item is dragged over the playlist's
     * DOM element.
     *
     * @param {Object} e The dragover event.
     */
    allowDrop(e) {
      $(e.target).addClass('droppable');
      e.dataTransfer.dropEffect = 'move';

      return false;
    },

    /**
     * Handle songs dropped to our favorite or playlist menu item.
     *
     * @param  {Object}   e    The event
     *
     * @return {Boolean}
     */
    handleDrop(e) {
      this.removeDroppableState(e);

      if (!e.dataTransfer.getData('application/x-koel.text+plain')) {
        return false;
      }

      const songs = songStore.byIds(e.dataTransfer.getData('application/x-koel.text+plain').split(','));

      if (!songs.length) {
        return false;
      }

      if (this.type === 'favorites') {
        favoriteStore.like(songs);
      } else {
        playlistStore.addSongs(this.playlist, songs);
      }

      return false;
    },
  },

  created() {
    event.on('main-content-view:load', (view, playlist) => {
      if (view === 'favorites') {
        this.active = this.isFavorites;
      } else if (view === 'playlist') {
        this.active = this.playlist === playlist;
      } else {
        this.active = false;
      }
    });
  },
};
</script>

<style lang="sass" scoped>
@import "../../../../sass/partials/_vars.scss";
@import "../../../../sass/partials/_mixins.scss";

.playlist {
  user-select: none;

  a {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;

    span {
      pointer-events: none;
    }

    &::before {
      content: "\f0f6";
    }
  }

  &.favorites a::before {
    content: "\f004";
    color: $colorHeart;
  }

  input {
    display: none;

    width: calc(100% - 32px);
    margin: 5px 16px;
  }

  &.editing {
    a {
      display: none !important;
    }

    input {
      display: block;
    }
  }
}
</style>


ui: change feature copy to your gateway to the ethereum blockchain

<template>

      <v-sheet
        color="transparent"
        max-width="400px"
        class="mx-auto text-center"
      >

          Features

Your Gateway to the Ethereum Blockchain

      </v-sheet>

        <v-container>
          <mew-tabs
            class="mew-tabs-container d-flex align-center flex-column"
            :items="mewTabs"
            is-block
          >
            <template #tabContent1>
              <home-features-send class="mt-16 mb-10" />
            </template>
            <template #tabContent2>
              <home-features-swap class="mt-16 mb-10" />
            </template>
            <template #tabContent3>
              <home-features-dapps class="mt-16 mb-10" />
            </template>
            <template #tabContent4>
              <home-features-tokens class="mt-16 mb-10" />
            </template>
          </mew-tabs>
        </v-container>

      <v-container>
        <v-sheet color="transparent" max-width="500px" class="mx-auto">

            Features

Your Gateway to the Ethereum Blockchain

          <v-tabs v-model="mobileTab" fixed-tabs>
            <v-tab v-for="item in mobileItems" :key="item.tab">
              {{ item.tab }}
            </v-tab>
          </v-tabs>

          <v-tabs-items v-model="mobileTab">
            <v-tab-item v-for="item in mewTabs" :key="item.tab">

                <home-features-send v-if="item.name === 'Send'" />
                <home-features-swap v-if="item.name === 'Swap'" />
                <home-features-dapps v-if="item.name === 'Dapps'" />
                <home-features-tokens v-if="item.name === 'Tokens'" />

            </v-tab-item>
          </v-tabs-items>
        </v-sheet>
      </v-container>

</template>

<template>

      <v-sheet
        color="transparent"
        max-width="400px"
        class="mx-auto text-center"
      >

          Features

Your All-In-One Gateway to the Ethereum Blockchain

      </v-sheet>

        <v-container>
          <mew-tabs
            class="mew-tabs-container d-flex align-center flex-column"
            :items="mewTabs"
            is-block
          >
            <template #tabContent1>
              <home-features-send class="mt-16 mb-10" />
            </template>
            <template #tabContent2>
              <home-features-swap class="mt-16 mb-10" />
            </template>
            <template #tabContent3>
              <home-features-dapps class="mt-16 mb-10" />
            </template>
            <template #tabContent4>
              <home-features-tokens class="mt-16 mb-10" />
            </template>
          </mew-tabs>
        </v-container>

      <v-container>
        <v-sheet color="transparent" max-width="500px" class="mx-auto">

            Features

            Your All-In-One Gateway to the Ethereum Blockchain

          <v-tabs v-model="mobileTab" fixed-tabs>
            <v-tab v-for="item in mobileItems" :key="item.tab">
              {{ item.tab }}
            </v-tab>
          </v-tabs>

          <v-tabs-items v-model="mobileTab">
            <v-tab-item v-for="item in mewTabs" :key="item.tab">

                <home-features-send v-if="item.name === 'Send'" />
                <home-features-swap v-if="item.name === 'Swap'" />
                <home-features-dapps v-if="item.name === 'Dapps'" />
                <home-features-tokens v-if="item.name === 'Tokens'" />

            </v-tab-item>
          </v-tabs-items>
        </v-sheet>
      </v-container>

</template>


Add active-change event

Add active-change event


Fix typo

Fix typo

<template>

Channel Designations

                    {{designation}}

                <IndividualDesignation :designation="channel" :canDelete="canDelete()" @confirm="confirmDelete(channel)" />

            No channels assigned

            Assign Channel

                        Assign a Channel

                    <button class="delete" aria-label="close" @click="cancel()"></button>

                            Channel Name
                            <Autocomplete :serviceCall="serviceCall" placeholder="#general"
                                @select="selectedAutocomplete = $event" minimumChars="1" >

                                <template slot-scope="{entry}">
                                    #{{entry.name}}
                                </template>

                            </Autocomplete>

                            Designation

                                <select multiple v-model="designationCreationData.channelDesignations">
                                    <option v-for="designation in possibleDesignations" :key="designation"
                                            :disabled="channelHasDesignation(designation)">
                                        {{designation}}
                                    </option>
                                </select>

                        <button class="button" @click="cancel()">Cancel</button>

                        <button class="button is-success" :class="{'is-loading': createLoading}" @click="createAssignment()" :disabled="disableAssignButton()">Assign</button>

</template>

<template>

Channel Designations

                    {{designation}}

                <IndividualDesignation :designation="channel" :canDelete="canDelete()" @confirm="confirmDelete(channel)" />

            No channels assigned

            Assign Channel

                        Assign a Channel

                    <button class="delete" aria-label="close" @click="cancel()"></button>

                            Channel Name
                            <Autocomplete :serviceCall="serviceCall" placeholder="#general"
                                @select="selectedAutocomplete = $event" minimumChars="1" >

                                <template slot-scope="{entry}">
                                    #{{entry.name}}
                                </template>

                            </Autocomplete>

                            Designation

                                <select multiple v-model="designationCreationData.channelDesignations">
                                    <option v-for="designation in possibleDesignations" :key="designation"
                                            :disabled="channelHasDesignation(designation)">
                                        {{designation}}
                                    </option>
                                </select>

                        <button class="button" @click="cancel()">Cancel</button>

                        <button class="button is-success" :class="{'is-loading': createLoading}" @click="createAssignment()" :disable="disableAssignButton()">Assign</button>

</template>


Scope multiselect css

Scope multiselect css

This is polluting existing css class names

<template>

                {{ field.label||field.key }}

                    <input  v-model="field.value" type="text" :class="['form-control','input-sm','context_var_autocomplete']" size="100" @change="changeField(field)" >

{{field.desc}}

        <btn type="primary" @click="openNewField()">{{ $t('message.addField') }}</btn>

        <modal v-model="modalAddField" title="Add Field" ref="modal" id="modal-demo" ok-text="Save" :backdrop="true"
               :dismiss-btn="true"
               :keyboard="true"
               cancel-text="Close" append-to-body>

                <alert type="warning" v-if="duplicate">Warning! {{ $t('message.duplicated') }}.</alert>

                            {{ $t('message.select') }}

                              <multiselect v-model="selectedField" :options="customOptions"  track-by="label" label="label"
                                           :placeholder="$t('message.select' )">

                              </multiselect>

                            {{ $t('message.description') }}

                                <input type="text" v-model="newFieldDescription" :class="['form-control']">

{{ $t('message.empty') }}

                            {{ $t('message.fieldLabel') }}

                                <input type="text" v-model="newLabelField" :class="['form-control']">

                            {{ $t('message.fieldKey') }}

                                <input type="text" v-model="newField" :class="['form-control']">

                            {{ $t('message.description') }}

                                <input type="text" v-model="newFieldDescription" :class="['form-control']">

{{ $t('message.empty') }}

                <button type="button" class="btn btn-primary reset_page_confirm" @click="modalAddField=false">
                    {{ $t('message.cancel') }}
                </button>

                <button type="button" class="btn btn-primary reset_page_confirm" @click="addField()">
                    {{ $t('message.add') }}
                </button>

        </modal>

</template>


fix(h5): append=>appendChild #1175

fix(h5): append=>appendChild #1175

<template>
  <uni-picker
    @click.stop="_show"
    v-on="$listeners">

      <transition name="uni-fade">

      </transition>

取消

确定

        <v-uni-picker-view
          v-if="visible"
          :value.sync="valueArray"
          class="uni-picker-content">
          <v-uni-picker-view-column
            v-for="(range,index0) in rangeArray"
            :key="index0">

{{ typeof item==='object'?item[rangeKey]||'':item }}{{ units[index0]||'' }}

          </v-uni-picker-view-column>
        </v-uni-picker-view>

      <slot />

  </uni-picker>
</template>


Rafraîchir l'affichage des applications après la suppression d'une application

<template>

        Image
        Creation Date
        Actions

      <template v-for="item in containers">

          {{ item.imageName }}
          {{ item.creationDate }}

<button type='button' class="btn btn-raised btn-sm btn-warning button" :id="item.imageName" v-on:click="deleteapplication">Delete</button>

                      <button type="button" class="close" data-dismiss="modal" aria-hidden="true" v-on:click="cancelDeleteapplication">×</button>

Delete application

                        You will delete the {{ imageNameToDelete }} application.

                    An error was received : {{ messageErrorPull }}.

                      Cancel
                      Delete

      </template>

</template>