so git will not detect the change in case, delete the file as a workaround

<!-- thanks to petejohanson for this implementation -->

<template>
  <aside class="mdc-temporary-drawer mdc-typography" :class="classes">
    <nav ref="drawer" class="mdc-temporary-drawer__drawer">

      <div class="mdc-temporary-drawer__toolbar-spacer" v-if="$slots['toolbar-spacer'] || toolbarSpacer">
        <slot name="toolbar-spacer"/>
      </div>

      <header class="mdc-temporary-drawer__header" v-if="$slots.header">
        <slot name="header"/>
      </header>

      <slot/>
    </nav>
  </aside>
</template>

<script lang="babel">
  import { MDCTemporaryDrawerFoundation } from '@material/drawer'
  import * as utils from '@material/drawer/util'

  export default {
    props: ['toolbarSpacer'],
    methods: {
      open () {
        this.foundation.open()
      }
    },
    data () {
      return {
        classes: {},
        changeHandlers: [],
        foundation: null
      }
    },
    mounted () {
      const {FOCUSABLE_ELEMENTS, OPACITY_VAR_NAME} = MDCTemporaryDrawerFoundation.strings

      let vm = this
      this.foundation = new MDCTemporaryDrawerFoundation({
        addClass (className) {
          vm.$set(vm.classes, className, true)
        },
        removeClass (className) {
          vm.$delete(vm.classes, className)
        },
        hasClass (className) {
          return Boolean(vm.classes[className]) || (vm.$el && vm.$el.classList.contains(className))
        },
        hasNecessaryDom () {
          return Boolean(vm.$refs.drawer)
        },
        registerInteractionHandler (evt, handler) {
          vm.$el.addEventListener(evt, handler)
        },
        deregisterInteractionHandler (evt, handler) {
          vm.$el.removeEventListener(evt, handler)
        },
        registerDrawerInteractionHandler (evt, handler) {
          vm.$refs.drawer.addEventListener(evt, handler)
        },
        deregisterDrawerInteractionHandler (evt, handler) {
          vm.$refs.drawer.removeEventListener(evt, handler)
        },
        registerTransitionEndHandler (handler) {
          vm.$refs.drawer.addEventListener('transitionend', handler)
        },
        deregisterTransitionEndHandler (handler) {
          vm.$refs.drawer.removeEventListener('transitionend', handler)
        },
        registerDocumentKeydownHandler (handler) {
          document.addEventListener('keydown', handler)
        },
        deregisterDocumentKeydownHandler (handler) {
          document.removeEventListener('keydown', handler)
        },
        getDrawerWidth () {
          return vm.$refs.drawer.clientWidth
        },
        setTranslateX (value) {
          vm.$refs.drawer.style.setProperty(
            utils.getTransformPropertyName(),
            value === null ? null : `translateX(${value}px)`
          )
        },
        updateCssVariable (value) {
          vm.$el.style.setProperty(OPACITY_VAR_NAME, value)
        },
        getFocusableElements () {
          return vm.$refs.drawer.querySelectorAll(FOCUSABLE_ELEMENTS)
        },
        saveElementTabState (el) {
          utils.saveElementTabState(el)
        },
        restoreElementTabState (el) {
          utils.restoreElementTabState(el)
        },
        makeElementUntabbable (el) {
          el.setAttribute('tabindex', -1)
        },
        isRtl () {
          /* global getComputedStyle */
          return getComputedStyle(vm.$el).getPropertyValue('direction') === 'rtl'
        }
      })
      this.foundation.init()
    },
    beforeDestroy () {
      this.foundation.destroy()
    }
  }
</script>


Fixed ESLint

Fixed ESLint

<template>

            <input
                type="text"
                v-model="query"
                :class="[prefixCls + '-input']"
                :placeholder="showPlaceholder ? placeholder : ''"
                :style="inputStyle"
                :disabled="disabled"
                @blur="this.focus = false"
                @focus="this.focus = true"
                v-el:input>

        <Dropdown v-show="visible && !(notFound && !!!notFoundText)" transition="slide-up" v-ref:dropdown>

{{ notFoundText }}

<slot></slot>

        </Dropdown>

</template>


Show servererror text

Show servererror text

<template>
  <v-alert v-if="serverError"
           text outlined
           color="red darken-2" icon="mdi-alert-circle">
    <template v-if="!!serverError.name || !!serverError.response ">

Validation error:

            {{ name }}:
              {{ message }},

        {{ serverError.message }}

    </template>
    <template v-else>
      {{ serverError }}
    </template>
  </v-alert>
</template>

<template>
  <v-alert v-if="serverError" color="red">

Validation error:

          {{ name }}:

            {{ message }},

      {{ serverError.message }}

  </v-alert>
</template>


use strToDayjs to read registrationDate

use strToDayjs to read registrationDate

<template>
  <uw-card
    v-if="student && shouldDisplayAtAll && (!loaded || hasDataToDisplay)"
    :loaded="loaded"
    :errored="errored"
    :errored-show="!isSummerReg || (isSummerReg && period === 'A')"
  >
    <template #card-heading>

        Registration: {{ quarter }} {{ year }}

        {{ forQuarter }} Registration

    </template>
    <template #card-body>
      <uw-est-reg-date :est-reg-data="estRegData" />
      <uw-holds
        v-if="regHoldsNotices && regHoldsNotices.length"
        :reg-holds-notices="regHoldsNotices"
        :is-my-plan-peak-load="myPlanPeakLoad"
      />

            {{ pendingMajors.length > 1 ? 'Majors' : 'Major' }}
            Beginning

            {{ quarter }}

              {{ major.degree_abbr }}

            {{ pendingMinors.length > 1 ? 'Minors' : 'Minor' }}
            Beginning

            {{ quarter }}

              {{ minor.abbr }}

      <uw-myplan
        v-if="!myPlanPeakLoad && myPlanData !== null"
        :my-plan-data="myPlanData || {}"
        :year="year"
        :quarter="quarter"
      />

      <uw-resources
        :my-plan-data="myPlanData || {}"
        :registration-is-open="
          estRegData.noticeMyRegIsOpen ||
            (!estRegData.hasEstRegDataNotice && regPeriod1Started)
        "
        :next-term-year="year"
        :next-term-quarter="quarter"
        :pre-reg-notices="preRegNotices"
      />

      <uw-fin-aid
        v-if="finAidNotices && finAidNotices.length && isSummerReg"
        :fin-aid-notices="finAidNotices"
      />
    </template>
  </uw-card>
</template>


chore: 👷 fix PR comment

chore: 👷 fix PR comment

<template>
  <v-sheet max-width="600px" class="pa-2">

    <confirmation-values-container :items="valueItems" class="mb-5" />

    <confirmation-summary-block :items="summaryItems">
      <template #rightColItem0>

          {{ feeFormatted }}
          {{ network.type.currencyName }}/
          ~${{ txFeeUsd }}

      </template>
      <template #rightColItem1>

          {{ totalFee }}
          {{ network.type.currencyName }}/
          ~${{ totalFeeUSD }}

      </template>
    </confirmation-summary-block>
  </v-sheet>
</template>


Check for isBlogHome with computed property.

* Trying to set it in a created() hook was causing issues with generated static site.

<template>

        <ArticlePreview :article="featuredArticle" :featured="true" />

        <ArticlePreview :article="article" :featured="false" />

      <Paginator :article-count="articleCount"
                 :start-page="startPage"
                 :root-segment="rootSegment"
                 :per-page="perPage"
      />

</template>


fix #173

fix #173

<template>

            Create a room

          <button type="button" class="close" data-dismiss="modal" aria-label="Close">
            ×
          </button>

                private

                public

            <message-compose
              class="border-0"
              create-channel-mode
              @submit="dismiss"
              @foundChannel="dismiss"
            />

            <channel-compose
              class="border-0"
              @submit="dismiss"
            />

</template>


OPEN-62: Code style.

OPEN-62: Code style.

(cherry picked from commit 6db9a7d)

<template>

                {{ closinghours ? 'Gesloten' : 'Geldig'
                    }} {{ options.freq == RRule.DAILY ? 'van' : 'op' }}
                <pikaday class="form-control inp-startDate" v-model="eventStartDate" :options="pikadayStart"/>

                tot en met
                <pikaday class="form-control inp-until" v-model="eventUntil" :options="pikadayUntil"/>

                tot en met...

×

                Regelmaat

                    <select v-model="optionFreq" class="form-control">
                        <option :value="RRule.YEARLY">Jaarlijks</option>
                        <option :value="RRule.MONTHLY">Maandelijks</option>
                        <option :value="RRule.WEEKLY">Wekelijks</option>
                        <option :value="RRule.DAILY">Dagelijks</option>
                    </select>

                    <select v-model="optionInterval" class="form-control">
                        <option :value="null">elke maand</option>
                        <option :value="2">tweemaandelijks</option>
                        <option :value="3">elk kwartaal</option>
                        <option :value="4">viermaandelijks</option>
                    </select>

                    <select v-model="optionInterval" class="form-control">
                        <option :value="null">elke week</option>
                        <option :value="2">tweewekelijks</option>
                        <option :value="3">driewekelijks</option>
                        <option :value="4">vierwekelijks</option>
                    </select>

                    <select v-model="optionInterval" class="form-control">
                        <option :value="null">elke dag</option>
                        <option :value="2">om de dag</option>
                        <option :value="3">om de drie dagen</option>
                        <option :value="4">om de vier dagen</option>
                        <option :value="5">om de vijf dagen</option>
                        <option :value="6">om de zes dagen</option>
                    </select>

                        <input type="radio" :name="event.start_date" v-model="weekOrMonth" value="monthday"
                               class="pull-left">
                        op

                        {{ eventStartDayMonth }}

                        <input type="radio" :name="event.start_date" v-model="weekOrMonth" value="weekday"
                               class="pull-left">
                        op de

                        <select v-model="optionBysetpos" class="form-control">
                            <option value="-" disabled></option>
                            <option value="1">eerste</option>
                            <option value="2">tweede</option>
                            <option value="3">derde</option>
                            <option value="4">vierde</option>
                            <option value="-2">voorlaatste</option>
                            <option value="-1">laatste</option>
                        </select>

                        <select v-model="optionByweekday" class="form-control">
                            <option value="0">maandag</option>
                            <option value="1">dinsdag</option>
                            <option value="2">woensdag</option>
                            <option value="3">donderdag</option>
                            <option value="4">vrijdag</option>
                            <option value="5">zaterdag</option>
                            <option value="6">zondag</option>
                            <option value="0,1,2,3,4,5,6">dag</option>
                            <option value="0,1,2,3,4">weekdag</option>
                            <option value="5,6">weekenddag</option>
                        </select>

                        <select v-model="options.bymonth" class="form-control">
                            <option v-for="(month, index) in fullMonths" :value="index + 1">{{ month }}</option>
                        </select>

                        <input type="radio" :name="event.start_date" v-model="weekOrMonth" value="monthday"
                               class="pull-left">
                        op dag

                        {{ eventStartDayMonth.slice(0, 2) }}

                        <input type="radio" :name="event.start_date" v-model="weekOrMonth" value="weekday"
                               class="pull-left">
                        op de

                        <select v-model="optionBysetpos" class="form-control">
                            <option value="-" disabled></option>
                            <option value="1">eerste</option>
                            <option value="2">tweede</option>
                            <option value="3">derde</option>
                            <option value="4">vierde</option>
                            <option value="-2">voorlaatste</option>
                            <option value="-1">laatste</option>
                        </select>

                        <select v-model="optionByweekday" class="form-control">
                            <option value="0">maandag</option>
                            <option value="1">dinsdag</option>
                            <option value="2">woensdag</option>
                            <option value="3">donderdag</option>
                            <option value="4">vrijdag</option>
                            <option value="5">zaterdag</option>
                            <option value="6">zondag</option>
                            <option value="0,1,2,3,4,5,6">dag</option>
                            <option value="0,1,2,3,4">weekdag</option>
                            <option value="5,6">weekend</option>
                        </select>

 eventEndTime }">
                    <multi-day-select :options="fullDays" v-model="optionByweekday"></multi-day-select>

            van
            <input type="text" class="form-control control-time inp-startTime" v-model.lazy="eventStartTime"
                   placeholder="_ _ : _ _">
            tot
            <input type="text" class="form-control control-time inp-endTime" v-model.lazy="eventEndTime"
                   placeholder="_ _ : _ _">

                    hele dag gesloten

×

                    <button type="button" class="btn btn-link" @click="$emit('add-event', prop, event)"
                            :disabled="$root.isRecreatex">+ Voeg meer dagen toe
                    </button>

 eventEndTime }">
                    van
                    <input type="text" class="form-control control-time inp-startTime" v-model.lazy="eventStartTime"
                           placeholder="_ _ : _ _">
                    tot
                    <input type="text" class="form-control control-time inp-endTime" v-model.lazy="eventEndTime"
                           placeholder="_ _ : _ _">

×

            gewone lijst van dagen

</template>

<template>

        {{ closinghours ? 'Gesloten' : 'Geldig' }} {{ options.freq==RRule.DAILY ? 'van' : 'op' }}
        <pikaday class="form-control inp-startDate" v-model="eventStartDate" :options="pikadayStart" />

        tot en met
        <pikaday class="form-control inp-until" v-model="eventUntil" :options="pikadayUntil" />

        tot en met...

×

        Regelmaat

          <select v-model="optionFreq" class="form-control">
            <option :value="RRule.YEARLY">Jaarlijks</option>
            <option :value="RRule.MONTHLY">Maandelijks</option>
            <option :value="RRule.WEEKLY">Wekelijks</option>
            <option :value="RRule.DAILY">Dagelijks</option>
          </select>

          <select v-model="optionInterval" class="form-control">
            <option :value="null">elke maand</option>
            <option :value="2">tweemaandelijks</option>
            <option :value="3">elk kwartaal</option>
            <option :value="4">viermaandelijks</option>
          </select>

          <select v-model="optionInterval" class="form-control">
            <option :value="null">elke week</option>
            <option :value="2">tweewekelijks</option>
            <option :value="3">driewekelijks</option>
            <option :value="4">vierwekelijks</option>
          </select>

          <select v-model="optionInterval" class="form-control">
            <option :value="null">elke dag</option>
            <option :value="2">om de dag</option>
            <option :value="3">om de drie dagen</option>
            <option :value="4">om de vier dagen</option>
            <option :value="5">om de vijf dagen</option>
            <option :value="6">om de zes dagen</option>
          </select>

            <input type="radio" :name="event.start_date" v-model="weekOrMonth" value="monthday" class="pull-left">
            op

            {{ eventStartDayMonth }}

            <input type="radio" :name="event.start_date" v-model="weekOrMonth" value="weekday" class="pull-left">
            op de

            <select v-model="optionBysetpos" class="form-control">
              <option value="-" disabled></option>
              <option value="1">eerste</option>
              <option value="2">tweede</option>
              <option value="3">derde</option>
              <option value="4">vierde</option>
              <option value="-2">voorlaatste</option>
              <option value="-1">laatste</option>
            </select>

            <select v-model="optionByweekday" class="form-control">
              <option value="0">maandag</option>
              <option value="1">dinsdag</option>
              <option value="2">woensdag</option>
              <option value="3">donderdag</option>
              <option value="4">vrijdag</option>
              <option value="5">zaterdag</option>
              <option value="6">zondag</option>
              <option value="0,1,2,3,4,5,6">dag</option>
              <option value="0,1,2,3,4">weekdag</option>
              <option value="5,6">weekenddag</option>
            </select>

            <select v-model="options.bymonth" class="form-control">
              <option v-for="(month, index) in fullMonths" :value="index + 1">{{ month }}</option>
            </select>

            <input type="radio" :name="event.start_date" v-model="weekOrMonth" value="monthday" class="pull-left">
            op dag

            {{ eventStartDayMonth.slice(0, 2) }}

            <input type="radio" :name="event.start_date" v-model="weekOrMonth" value="weekday" class="pull-left">
            op de

            <select v-model="optionBysetpos" class="form-control">
              <option value="-" disabled></option>
              <option value="1">eerste</option>
              <option value="2">tweede</option>
              <option value="3">derde</option>
              <option value="4">vierde</option>
              <option value="-2">voorlaatste</option>
              <option value="-1">laatste</option>
            </select>

            <select v-model="optionByweekday" class="form-control">
              <option value="0">maandag</option>
              <option value="1">dinsdag</option>
              <option value="2">woensdag</option>
              <option value="3">donderdag</option>
              <option value="4">vrijdag</option>
              <option value="5">zaterdag</option>
              <option value="6">zondag</option>
              <option value="0,1,2,3,4,5,6">dag</option>
              <option value="0,1,2,3,4">weekdag</option>
              <option value="5,6">weekend</option>
            </select>

 eventEndTime }">
          <multi-day-select :options="fullDays" v-model="optionByweekday"></multi-day-select>

            van
            <input type="text" class="form-control control-time inp-startTime" v-model.lazy="eventStartTime" placeholder="_ _ : _ _">
            tot
            <input type="text" class="form-control control-time inp-endTime" v-model.lazy="eventEndTime" placeholder="_ _ : _ _">

          hele dag gesloten

×

          <button type="button" class="btn btn-link" @click="$emit('add-event', prop, event)" :disabled="$root.isRecreatex">+ Voeg meer dagen toe</button>

 eventEndTime }">
          van
          <input type="text" class="form-control control-time inp-startTime" v-model.lazy="eventStartTime" placeholder="_ _ : _ _">
          tot
          <input type="text" class="form-control control-time inp-endTime" v-model.lazy="eventEndTime" placeholder="_ _ : _ _">

×

      gewone lijst van dagen

</template>


fix: 🐛 ens missing provider

fix: 🐛 ens missing provider

<template>
  <div>
    <mew-address-select
      ref="addressSelect"
      :resolved-addr="resolvedAddr"
      :copy-tooltip="$t('common.copy')"
      :save-tooltip="$t('common.save')"
      :enable-save-address="enableSave"
      :label="addrLabel"
      :items="addressBookWithMyAddress"
      :placeholder="$t('sendTx.enter-addr')"
      :success-toast="$t('sendTx.success.title')"
      :is-valid-address="isValidAddress"
      :show-copy="isValidAddress"
      :error-messages="errorMessages"
      @saveAddress="toggleOverlay"
      @input="setAddress"
    />
    <!-- add and edit the address book -->
    <mew-overlay
      :footer="{
        text: 'Need help?',
        linkTitle: 'Contact support',
        link: 'mailto:support@myetherwallet.com'
      }"
      :title="$t('interface.address-book.add-addr')"
      :show-overlay="addMode"
      :close="toggleOverlay"
      content-size="xlarge"
    >
      <address-book-add-edit
        :to-address="inputAddr"
        mode="add"
        @back="toggleOverlay"
      />
    </mew-overlay>
  </div>
</template>

<script>
import { isAddress } from '@/core/helpers/addressUtils';
import { mapGetters, mapState } from 'vuex';
import NameResolver from '@/modules/name-resolver/index';
import AddressBookAddEdit from './components/AddressBookAddEdit';
import { isObject, throttle } from 'lodash';
import { toChecksumAddress } from '@/core/helpers/addressUtils';
import WAValidator from 'multicoin-address-validator';

const USER_INPUT_TYPES = {
  typed: 'TYPED',
  selected: 'SELECTED',
  resolved: 'RESOLVED'
};

export default {
  components: {
    AddressBookAddEdit
  },
  props: {
    isValidAddressFunc: {
      type: Function,
      default: isAddress
    },
    isHomePage: {
      type: Boolean,
      default: false
    },
    label: {
      type: String,
      default: ''
    },
    currency: {
      type: String,
      default: 'ETH'
    },
    preselectCurrWalletAdr: {
      type: Boolean,
      default: false
    },
    enableSaveAddress: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      addMode: false,
      resolvedAddr: '',
      inputAddr: '',
      nameResolver: null,
      isValidAddress: false,
      loadedAddressValidation: false
    };
  },

  computed: {
    ...mapState('addressBook', ['addressBookStore']),
    ...mapGetters('global', ['network']),
    ...mapState('wallet', ['web3', 'address']),
    errorMessages() {
      if (!this.isValidAddress && this.loadedAddressValidation) {
        return this.$t('interface.address-book.validations.invalid-address');
      }
      if (!this.inputAddr && this.loadedAddressValidation) {
        return this.$t('interface.address-book.validations.addr-required');
      }
      return '';
    },
    addressBookWithMyAddress() {
      return this.isHomePage
        ? [
            {
              address: '0xDECAF9CD2367cdbb726E904cD6397eDFcAe6068D',
              currency: 'ETH',
              nickname: 'MEW Donations',
              resolverAddr: '0xDECAF9CD2367cdbb726E904cD6397eDFcAe6068D'
            }
          ]
        : this.address
        ? [
            {
              address: toChecksumAddress(this.address),
              nickname: 'My Address',
              resolverAddr: ''
            }
          ].concat(this.addressBookStore)
        : [
            {
              address: toChecksumAddress(this.address),
              nickname: 'My Address',
              resolverAddr: ''
            }
          ];
    },
    enableSave() {
      return this.isHomePage
        ? false
        : this.isValidAddress && this.enableSaveAddress;
    },
    addrLabel() {
      return this.label === '' ? this.$t('sendTx.to-addr') : this.label;
    }
  },
  watch: {
    web3() {
      if (this.network.type.ens && this.web3.currentProvider) {
        this.nameResolver = new NameResolver(this.network, this.web3);
      } else {
        this.nameResolver = null;
      }
    }
  },
  mounted() {
    if (this.network.type.ens && this.web3.currentProvider)
      this.nameResolver = new NameResolver(this.network, this.web3);
    if (this.isHomePage) {
      this.setDonationAddress();
    }
    if (this.preselectCurrWalletAdr) {
      this.$refs.addressSelect.selectAddress(this.addressBookWithMyAddress[0]);
      this.setAddress(
        toChecksumAddress(this.address),
        USER_INPUT_TYPES.selected
      );
    }
  },
  methods: {
    /**
     * Checks if address is valid
     * and sets the address value
     */
    async setAddress(value, inputType) {
      if (typeof value === 'string') {
        if (
          this.currency.toLowerCase() ===
          this.network.type.currencyName.toLowerCase()
        ) {
          /**
           * Checks if user typed or selected an address from dropdown
           */
          const typeVal =
            inputType === USER_INPUT_TYPES.typed
              ? value
              : this.addressBookWithMyAddress.find(item => {
                  return value.toLowerCase() === item.address.toLowerCase();
                });
          this.inputAddr = value;
          this.resolvedAddr = '';
          /**
           * Checks if the address is valid
           */
          const isAddValid = this.isValidAddressFunc(this.inputAddr);
          if (isAddValid instanceof Promise) {
            const validation = await isAddValid;
            this.isValidAddress = validation;
          } else {
            this.isValidAddress = isAddValid;
          }
          this.loadedAddressValidation = !this.isValidAddress ? false : true;

          /**
           * @emits setAddress
           */
          this.$emit('setAddress', value, this.isValidAddress, {
            type: inputType,
            value: isObject(typeVal) ? typeVal.nickname : typeVal
          });
          if (!this.isValidAddress) {
            this.resolveName();
          }
        } else {
          const currencyExists = WAValidator.findCurrency(
            this.currency.toLowerCase()
          );
          if (currencyExists) {
            const validate = WAValidator.validate(
              value,
              this.currency.toLowerCase()
            );
            if (validate) {
              this.inputAddr = value;
              this.isValidAddress = true;
            } else {
              this.isValidAddress = false;
            }
            this.loadedAddressValidation = true;
            /**
             * @emits setAddress
             */
            this.$emit('setAddress', value, this.isValidAddress, {
              type: inputType,
              value: value
            });
          } else {
            this.isValidAddress = false;
            this.loadedAddressValidation = true;
            this.$emit('setAddress', value, this.isValidAddress, {
              type: inputType,
              value: value
            });
          }
        }
      }
    },
    // is used from the parent context
    // eslint-disable-next-line
    clear() {
      this.addMode = false;
      this.resolvedAddr = '';
      this.inputAddr = '';
      this.nameResolver = null;
      this.isValidAddress = false;
      this.loadedAddressValidation = false;
      this.$refs.addressSelect.clear();
      this.$emit('setAddress', this.resolvedAddr, this.isValidAddress, {
        type: USER_INPUT_TYPES.typed,
        value: this.inputAddr
      });

      // Calls setups from mounted
      if (this.network.type.ens)
        this.nameResolver = new NameResolver(this.network, this.web3);
      if (this.isHomePage) {
        this.setDonationAddress();
      }
    },
    /**
     * Sets selected address to be MEW donation address
     * only happens on home page
     */
    setDonationAddress() {
      this.$refs.addressSelect.selectAddress(this.addressBookWithMyAddress[0]);
    },
    toggleOverlay() {
      this.addMode = !this.addMode;
    },
    /**
     * Resolves name and @returns address
     */
    resolveName: throttle(async function () {
      if (this.nameResolver) {
        try {
          await this.nameResolver.resolveName(this.inputAddr).then(addr => {
            this.resolvedAddr = addr;
            this.isValidAddress = true;
            this.loadedAddressValidation = true;
            this.$emit('setAddress', this.resolvedAddr, this.isValidAddress, {
              type: USER_INPUT_TYPES.resolved,
              value: this.inputAddr
            });
          });
        } catch (e) {
          this.loadedAddressValidation = true;
        }
      }
    }, 500)
  }
};
</script>

<template>
  <div>
    <mew-address-select
      ref="addressSelect"
      :resolved-addr="resolvedAddr"
      :copy-tooltip="$t('common.copy')"
      :save-tooltip="$t('common.save')"
      :enable-save-address="enableSave"
      :label="addrLabel"
      :items="addressBookWithMyAddress"
      :placeholder="$t('sendTx.enter-addr')"
      :success-toast="$t('sendTx.success.title')"
      :is-valid-address="isValidAddress"
      :show-copy="isValidAddress"
      :error-messages="errorMessages"
      @saveAddress="toggleOverlay"
      @input="setAddress"
    />
    <!-- add and edit the address book -->
    <mew-overlay
      :footer="{
        text: 'Need help?',
        linkTitle: 'Contact support',
        link: 'mailto:support@myetherwallet.com'
      }"
      :title="$t('interface.address-book.add-addr')"
      :show-overlay="addMode"
      :close="toggleOverlay"
      content-size="xlarge"
    >
      <address-book-add-edit
        :to-address="inputAddr"
        mode="add"
        @back="toggleOverlay"
      />
    </mew-overlay>
  </div>
</template>

<script>
import { isAddress } from '@/core/helpers/addressUtils';
import { mapGetters, mapState } from 'vuex';
import NameResolver from '@/modules/name-resolver/index';
import AddressBookAddEdit from './components/AddressBookAddEdit';
import { isObject, throttle } from 'lodash';
import { toChecksumAddress } from '@/core/helpers/addressUtils';
import WAValidator from 'multicoin-address-validator';

const USER_INPUT_TYPES = {
  typed: 'TYPED',
  selected: 'SELECTED',
  resolved: 'RESOLVED'
};

export default {
  components: {
    AddressBookAddEdit
  },
  props: {
    isValidAddressFunc: {
      type: Function,
      default: isAddress
    },
    isHomePage: {
      type: Boolean,
      default: false
    },
    label: {
      type: String,
      default: ''
    },
    currency: {
      type: String,
      default: 'ETH'
    },
    preselectCurrWalletAdr: {
      type: Boolean,
      default: false
    },
    enableSaveAddress: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      addMode: false,
      resolvedAddr: '',
      inputAddr: '',
      nameResolver: null,
      isValidAddress: false,
      loadedAddressValidation: false
    };
  },

  computed: {
    ...mapState('addressBook', ['addressBookStore']),
    ...mapGetters('global', ['network']),
    ...mapState('wallet', ['web3', 'address']),
    errorMessages() {
      if (!this.isValidAddress && this.loadedAddressValidation) {
        return this.$t('interface.address-book.validations.invalid-address');
      }
      if (!this.inputAddr && this.loadedAddressValidation) {
        return this.$t('interface.address-book.validations.addr-required');
      }
      return '';
    },
    addressBookWithMyAddress() {
      return this.isHomePage
        ? [
            {
              address: '0xDECAF9CD2367cdbb726E904cD6397eDFcAe6068D',
              currency: 'ETH',
              nickname: 'MEW Donations',
              resolverAddr: '0xDECAF9CD2367cdbb726E904cD6397eDFcAe6068D'
            }
          ]
        : this.address
        ? [
            {
              address: toChecksumAddress(this.address),
              nickname: 'My Address',
              resolverAddr: ''
            }
          ].concat(this.addressBookStore)
        : [
            {
              address: toChecksumAddress(this.address),
              nickname: 'My Address',
              resolverAddr: ''
            }
          ];
    },
    enableSave() {
      return this.isHomePage
        ? false
        : this.isValidAddress && this.enableSaveAddress;
    },
    addrLabel() {
      return this.label === '' ? this.$t('sendTx.to-addr') : this.label;
    }
  },
  watch: {
    web3() {
      if (this.network.type.ens) {
        this.nameResolver = new NameResolver(this.network, this.web3);
      } else {
        this.nameResolver = null;
      }
    }
  },
  mounted() {
    if (this.network.type.ens)
      this.nameResolver = new NameResolver(this.network, this.web3);
    if (this.isHomePage) {
      this.setDonationAddress();
    }
    if (this.preselectCurrWalletAdr) {
      this.$refs.addressSelect.selectAddress(this.addressBookWithMyAddress[0]);
      this.setAddress(
        toChecksumAddress(this.address),
        USER_INPUT_TYPES.selected
      );
    }
  },
  methods: {
    /**
     * Checks if address is valid
     * and sets the address value
     */
    async setAddress(value, inputType) {
      if (typeof value === 'string') {
        if (
          this.currency.toLowerCase() ===
          this.network.type.currencyName.toLowerCase()
        ) {
          /**
           * Checks if user typed or selected an address from dropdown
           */
          const typeVal =
            inputType === USER_INPUT_TYPES.typed
              ? value
              : this.addressBookWithMyAddress.find(item => {
                  return value.toLowerCase() === item.address.toLowerCase();
                });
          this.inputAddr = value;
          this.resolvedAddr = '';
          /**
           * Checks if the address is valid
           */
          const isAddValid = this.isValidAddressFunc(this.inputAddr);
          if (isAddValid instanceof Promise) {
            const validation = await isAddValid;
            this.isValidAddress = validation;
          } else {
            this.isValidAddress = isAddValid;
          }
          this.loadedAddressValidation = !this.isValidAddress ? false : true;

          /**
           * @emits setAddress
           */
          this.$emit('setAddress', value, this.isValidAddress, {
            type: inputType,
            value: isObject(typeVal) ? typeVal.nickname : typeVal
          });
          if (!this.isValidAddress) {
            this.resolveName();
          }
        } else {
          const currencyExists = WAValidator.findCurrency(
            this.currency.toLowerCase()
          );
          if (currencyExists) {
            const validate = WAValidator.validate(
              value,
              this.currency.toLowerCase()
            );
            if (validate) {
              this.inputAddr = value;
              this.isValidAddress = true;
            } else {
              this.isValidAddress = false;
            }
            this.loadedAddressValidation = true;
            /**
             * @emits setAddress
             */
            this.$emit('setAddress', value, this.isValidAddress, {
              type: inputType,
              value: value
            });
          } else {
            this.isValidAddress = false;
            this.loadedAddressValidation = true;
            this.$emit('setAddress', value, this.isValidAddress, {
              type: inputType,
              value: value
            });
          }
        }
      }
    },
    // is used from the parent context
    // eslint-disable-next-line
    clear() {
      this.addMode = false;
      this.resolvedAddr = '';
      this.inputAddr = '';
      this.nameResolver = null;
      this.isValidAddress = false;
      this.loadedAddressValidation = false;
      this.$refs.addressSelect.clear();
      this.$emit('setAddress', this.resolvedAddr, this.isValidAddress, {
        type: USER_INPUT_TYPES.typed,
        value: this.inputAddr
      });

      // Calls setups from mounted
      if (this.network.type.ens)
        this.nameResolver = new NameResolver(this.network, this.web3);
      if (this.isHomePage) {
        this.setDonationAddress();
      }
    },
    /**
     * Sets selected address to be MEW donation address
     * only happens on home page
     */
    setDonationAddress() {
      this.$refs.addressSelect.selectAddress(this.addressBookWithMyAddress[0]);
    },
    toggleOverlay() {
      this.addMode = !this.addMode;
    },
    /**
     * Resolves name and @returns address
     */
    resolveName: throttle(async function () {
      if (this.nameResolver) {
        try {
          await this.nameResolver.resolveName(this.inputAddr).then(addr => {
            this.resolvedAddr = addr;
            this.isValidAddress = true;
            this.loadedAddressValidation = true;
            this.$emit('setAddress', this.resolvedAddr, this.isValidAddress, {
              type: USER_INPUT_TYPES.resolved,
              value: this.inputAddr
            });
          });
        } catch (e) {
          this.loadedAddressValidation = true;
        }
      }
    }, 500)
  }
};
</script>


deconflictification

deconflictification

<template>

    <overlay v-if="overlayActive"/>
    <loader/>

      <microcart/>
      <search-panel/>
      <wishlist/>
      <sidebar-menu/>

      <slot/>

      <notification/>
      <sign-up/>
      <newsletter-popup/>
      <cookie-notification/>
      <offline-badge/>
      <modal-switcher/>
      <order-confirmation :orders-data="ordersData"/>

    <vue-progress-bar />

</template>

<template>

    <overlay v-if="overlayActive"/>
    <loader/>

      <microcart/>
      <search-panel/>
      <wishlist >
      <sidebar-menu/>

      <slot/>

      <notification/>
      <sign-up/>
      <newsletter-popup/>
      <cookie-notification/>
      <offline-badge/>
      <modal-switcher/>
      <order-confirmation :orders-data="ordersData"/>

    <vue-progress-bar />

</template>


Only show box when key is generated

Only show box when key is generated

<template>

            <img class="arrow" :src="`${baseUrl}/assets/images/temp/back_arrow.png`"/>Back to your profile

Settings

API Key

                     Your API key is used in Halite Client tools for authentication.

                     Note: Once you close this page, you will not be able to retrieve that key again. You will need to generate a new one.

                <form>
                    <input v-if="api_key" style="color: black; max-width: 400px" type="text" class="form-control" readonly :value="api_key"/>
                    <button class="btn-ha btn-ha-md" style="margin-top:20px;" v-on:click="fetchApiKey">Generate API Key</button>
                </form>

Bot Settings

                <form v-on:submit.prevent="submit" class="create-account-form">

                      Enable GPUs for your current bot
                       <v-select
                            label="label"
                            v-model="selected_gpu_state"
                            :options="gpu_states">
                        </v-select>

Email Settings

                    <form v-on:submit.prevent="submit" class="create-account-form">

                                To manage your email preferences, click the relevant link at the bottom of any Halite email.

                    </form>

                    Cancel
                    <button type="submit" class="btn-ha">Save Settings</button>
                </form>

</template>

<template>

            <img class="arrow" :src="`${baseUrl}/assets/images/temp/back_arrow.png`"/>Back to your profile

Settings

API Key

                     Your API key is used in Halite Client tools for authentication.

                     Note: Once you close this page, you will not be able to retrieve that key again. You will need to generate a new one.

                <form>
                    <input style="color: black; max-width: 400px" type="text" class="form-control" readonly :value="api_key"/>
                    <button class="btn-ha btn-ha-md" style="margin-top:20px;" v-on:click="fetchApiKey">Generate API Key</button>
                </form>

Bot Settings

                <form v-on:submit.prevent="submit" class="create-account-form">

                      Enable GPUs for your current bot
                       <v-select
                            label="label"
                            v-model="selected_gpu_state"
                            :options="gpu_states">
                        </v-select>

Email Settings

                    <form v-on:submit.prevent="submit" class="create-account-form">

                                To manage your email preferences, click the relevant link at the bottom of any Halite email.

                    </form>

                    Cancel
                    <button type="submit" class="btn-ha">Save Settings</button>
                </form>

</template>


Improve usability

Improve usability

<template>

 0">

			<div class="img" :style="{ backgroundImage: `url(${ ctx.img })` }">

<fa icon="spinner" pulse/>{{ ctx.name }}

				{{ $t('waiting') }}<mk-ellipsis/>
				{{ String(Math.floor(ctx.progress.value / 1024)).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,') }}KB / {{ String(Math.floor(ctx.progress.max / 1024)).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,') }}KB
				{{ Math.floor((ctx.progress.value / ctx.progress.max) * 100) }}

			<progress v-if="ctx.progress != undefined && ctx.progress.value != ctx.progress.max" :value="ctx.progress.value" :max="ctx.progress.max"></progress>

</template>


add example image back again

add example image back again

<template>

	<router-link :to="{name: 'Test'}">Go To Test</router-link>

{{ msg }}

Essential Links

Core Docs

Forum

Gitter Chat

Twitter

Docs for This Template

Ecosystem

vue-router

vuex

vue-loader

awesome-vue

</template>


移除无用内容

移除无用内容

<template>

请大家每周五下班前按要求填写周报，若每月有3次未按要求填写周报，考虑月浮动奖罚，以做规范手段。

周报的目的：

对自己本周工作进行一个如实总结。

方便部门管理者、各小组负责人了解团队的整体运行情况。

请大家跳出自我的角度，多从管理者的角度、团队的角度考虑问题，就能理解其中的必要性。

      <fieldset>
        <legend>基本信息</legend>

{{user.groupName}} - {{user.username}}

      </fieldset>
      <fieldset>
        <legend>工作内容</legend>

        <FormItem label="类型" style="margin-top:10px; margin-bottom:0px;">
          <RadioGroup v-model="type">

              {{item.text}}

          </RadioGroup>
        </FormItem>

{{item.text}}：{{item.info}}

        <FormItem :label="currType.text" prop="content">

        </FormItem>

          {{currType.explain}}

        <FormItem :label="timeLabel.title" prop="time">
          <InputNumber :max="100" :min="0.1" :step="1" v-model="data.time"></InputNumber>
        </FormItem>

        添加并重置
      </fieldset>

      <fieldset>
        <legend>事项列表</legend>

      </fieldset>

      <fieldset>
        <legend>汇总</legend>

              姓名
              工作内容
              任务耗时
              学习耗时
              沟通耗时
              其他

              {{user.username}}

                    {{item.content}} （{{item.time}}小时）

              {{taskTime | getInt}}
              {{studyTime | getInt}}
              {{communicationTime | getInt}}

                    {{item.content}} （{{item.time}}小时）

                无

        <i-button type="primary" @click="addToCloud" :disabled="reportList.length < 1" :loading="isSaving">提交到云端
      </fieldset>

</template>


Corrigindo data no modal de confirmação

Corrigindo data no modal de confirmação

<template>

      Agendamento de Provas

Clique numa disciplina abaixo para começar a agendar

            {{ disciplina.descricao }}
            Pendente

Prova Agendada

            Cancelar Agendamento

              <select :id="'select-' + disciplina.codigo" class="browser-default" v-model="unidadeSelecionada" v-on:change="exibicaoDaListaDeHorarios(disciplina.codigo)">
                <option value="" disabled>Unidade:</option>
                <option v-for="unidade in disciplina.unidades" v-bind:value="unidade">
                  {{ unidade.descrição }}
                </option>
              </select>

                      Data
                      Horario
                      Sala

                      {{ horario.data | dataFormatada }}
                       {{ horario.data | horarioFormatado }}
                       {{ horario.sala }}

Confirmar Agendamento?

            Disciplina: {{ selecaoExibidaNoModal.disciplinaSelecionada }}
 Unidade: {{ selecaoExibidaNoModal.unidadeSelecionada
            }}

 Data:{{teste}}
 Sala: {{ selecaoExibidaNoModal.salaSelecionada }}

          Confirmar
          Cancelar

Cancelar Agendamento?

            Disciplina: {{ selecaoExibidaNoModal.disciplinaSelecionada }}
 Unidade: {{ selecaoExibidaNoModal.unidadeSelecionada
            }}

 Data: {{ selecaoExibidaNoModal.dataSelecionada }}
 Sala: {{ selecaoExibidaNoModal.salaSelecionada }}

          Confirmar
          Voltar

</template>

<template>

      Agendamento de Provas

Clique numa disciplina abaixo para começar a agendar

            {{ disciplina.descricao }}
            Pendente

Prova Agendada

            Cancelar Agendamento

              <select :id="'select-' + disciplina.codigo" class="browser-default" v-model="unidadeSelecionada" v-on:change="exibicaoDaListaDeHorarios(disciplina.codigo)">
                <option value="" disabled>Unidade:</option>
                <option v-for="unidade in disciplina.unidades" v-bind:value="unidade">
                  {{ unidade.descrição }}
                </option>
              </select>

                      Data
                      Horario
                      Sala

                      {{ horario.data | dataFormatada }}
                       {{ horario.data | horarioFormatado }}
                       Sala {{ horario.sala }}

Confirmar Agendamento?

            Disciplina: {{ selecaoExibidaNoModal.disciplinaSelecionada }}
 Unidade: {{ selecaoExibidaNoModal.unidadeSelecionada
            }}

 Data: {{ selecaoExibidaNoModal.dataSelecionada }}
 Sala: {{ selecaoExibidaNoModal.salaSelecionada }}

          Confirmar
          Cancelar

Cancelar Agendamento?

            Disciplina: {{ selecaoExibidaNoModal.disciplinaSelecionada }}
 Unidade: {{ selecaoExibidaNoModal.unidadeSelecionada
            }}

 Data: {{ selecaoExibidaNoModal.dataSelecionada }}
 Sala: {{ selecaoExibidaNoModal.salaSelecionada }}

          Confirmar
          Voltar

</template>


delete mode first version implemented

delete mode first version implemented

<template>
  <svg width="100%" height="100%" @click="clickSVG" @dblclick="resetPathStartingPoint">
    <circle v-for="n in nodes"
      :cx="n.x" :cy="n.y" r="10" :key="'n' + n.id" :nodeId="n.id"
      @click="nodeClick" @mousedown="startDragNode"
      class="circle" :stroke="dotStroke" :fill="dotFill" />
    <line v-for="l in lineLinks" :x1="l.x1" :y1="l.y1" :x2="l.x2" :y2="l.y2" :style="lineStyle" :key="l.x1+l.y1"/>
  </svg>
</template>
<script>

const BUILD = 1
const MOVE = 2
const DELETE = 3

export default {
  data () {
    return {
      nodes: [],            // graphSample.nodes,
      links: [],            // graphSample.links,
      isSplitting: false,
      lastId: -1,           // used to assign id to new nodes
      prevNodeId: -1,       // last node from which a link will be constructed
      dotStroke: 'blue',    // dot stroke, as appears in the svg
      dotFill: 'blue',      // dot fill color
      mode: BUILD,          // current mode of the component
      lastMouseX: 0,        // contains the information about the last values
      lastMouseY: 0,        // of the mouse position
      beingDragId: -1,      // who is being dragged
      isDragging: false,    // says if we are currently dragging something
      lineStyle: 'stroke:rgb(0,0,255);stroke-width:3',
      isEditing: true
    }
  },
  methods: {
    startDragNode (event) {
      if (this.mode !== MOVE) {
        return
      }
      // set the on mouse move listener
      window.addEventListener('mousemove', this.moveNode)
      window.addEventListener('mouseup', this.stopDragNode)
      // set the dragging mode
      this.isDragging = true
      // and save the mouse coordinates
      this.lastMouseX = event.offsetX
      this.lastMouseY = event.offsetY
      // set which node is starting to drag
      const nodeId = parseInt(event.target.getAttribute('nodeId'))
      this.beingDragId = nodeId
      console.log('[DEBUG] Starting to drag')
    },
    moveNode (event) {
      if (this.mode !== MOVE || !this.isDragging) {
        return
      }
      // get how much we move from the last mouse event
      const dx = event.offsetX - this.lastMouseX
      const dy = event.offsetY - this.lastMouseY
      // save mouse position for the next movement
      this.lastMouseX = event.offsetX
      this.lastMouseY = event.offsetY
      // move the node
      this.shiftNode(this.beingDragId, dx, dy)
    },
    shiftNode (nodeId, dx, dy) {
      // get the node to shift
      for (let i = 0; i < this.nodes.length; i++) {
        let node = this.nodes[i]
        if (node.id === nodeId) {
          node.x += dx
          node.y += dy
          break
        }
      }
    },
    stopDragNode (event) {
      if (this.mode !== MOVE) {
        return
      }
      // set the dragging mode
      this.isDragging = false
      this.beingDragId = -1
      window.removeEventListener('mousemove', this.moveNode)
      window.removeEventListener('mouseup', this.stopDragNode)
    },
    // called when a node is clicked
    nodeClick (event) {
      const nodeClikedId = parseInt(event.target.getAttribute('nodeId'))
      console.log('[INFO] node clicked', nodeClikedId)
      switch (this.mode) {
        case BUILD:
          this.linkWithLastCreate(nodeClikedId)
          break
        case DELETE:
          this.deleteNode(nodeClikedId)
          break
        default:
          break
      }
      event.stopPropagation()
    },
    // delete a node given its id
    deleteNode (id) {
      console.log('[INFO] delete node', id)
      // remove the node from the node list
      this.nodes = this.nodes.filter(n => n.id !== id)
      // remove the links associated to the node
      this.links = this.links.filter(l => id !== l.from && id !== l.to)
    },
    // join node to the last one
    linkWithLastCreate (nodeClikedId) {
      // here we reset the previous node id such that new path
      // will start from here
      if (this.prevNodeId !== -1) {
        console.log('[INFO] Joining nodes...')
        this.createLink(this.prevNodeId, nodeClikedId)
      }
      this.prevNodeId = nodeClikedId
      this.isSplitting = true
    },
    // create a new node and add it to the node list
    createNode (x, y) {
      // TEST
      if (this.lastId > 4) {
        console.log('[DEBUG] SWITCHING TO MODE DELETE')
        this.mode = DELETE
      }
      // END TEST
      // we update the id store
      this.lastId++
      const newNode = {
        id: this.lastId,
        x,
        y
      }
      // adding the new node to nodes list
      this.nodes.push(newNode)
      return newNode
    },
    // adds a new link given the from and to nodes id
    createLink (from, to) {
      this.links.push({from, to})
    },
    clickSVG (event) {
      if (!this.isEditing || this.mode !== BUILD) {
        return
      }
      const newNode = this.createNode(event.offsetX, event.offsetY)
      console.log('[INFO] adding a new node', newNode)

      // if preNode is -1 this means that this node is a starting point
      // so at this time we don't add any link
      if (this.prevNodeId !== -1) {
        this.createLink(this.prevNodeId, newNode.id)
      }

      if (this.isSplitting) {
        // the previous node id was already set
        this.isSplitting = false
      }
      this.prevNodeId = this.lastId
    },
    resetPathStartingPoint (event) {
      console.log('[INFO] reseting starting point of the path')
      this.prevNodeId = -1
    }
  },
  computed: {
    lineLinks () {
      return this.links.map(l => {
        const n1 = this.nodes.filter(n => n.id === l.from)[0]
        const n2 = this.nodes.filter(n => n.id === l.to)[0]
        return {
          x1: n1.x,
          y1: n1.y,
          x2: n2.x,
          y2: n2.y
        }
      })
    }
  },
  watch: {
    links () {
      return this.links.map(l => {
        const n1 = this.nodes.filter(n => n.id === l.from)[0]
        const n2 = this.nodes.filter(n => n.id === l.to)[0]
        return {
          x1: n1.x,
          y1: n1.y,
          x2: n2.x,
          y2: n2.y
        }
      })
    }
  }
}
</script>

<style scoped>
@keyframes zoom {
    0%   {stroke-width: 2}
    100% {stroke-width: 20}
}
.circle {
	stroke-width: 1;
	stroke-linecap: round;
}
.circle:hover {
  stroke-width: 16px;
  cursor: pointer;
}
</style>

<template>
  <svg width="100%" height="100%" @click="clickNode" @dblclick="resetPathStartingPoint">
    <circle v-for="n in nodes"
      :cx="n.x" :cy="n.y" r="10" :key="'n' + n.id" :nodeId="n.id"
      @click="nodeClick" @mousedown="startDragNode"
      class="circle" :stroke="dotStroke" :fill="dotFill" />
    <line v-for="l in lineLinks" :x1="l.x1" :y1="l.y1" :x2="l.x2" :y2="l.y2" :style="lineStyle" :key="l.x1+l.y1"/>
  </svg>
</template>
<script>

const BUILD = 1
const MOVE = 2
// const DELETE = 3

export default {
  data () {
    return {
      nodes: [],            // graphSample.nodes,
      links: [],            // graphSample.links,
      isSplitting: false,
      lastId: -1,           // used to assign id to new nodes
      prevNodeId: -1,       // last node from which a link will be constructed
      dotStroke: 'blue',    // dot stroke, as appears in the svg
      dotFill: 'blue',      // dot fill color
      mode: BUILD,          // current mode of the component
      lastMouseX: 0,        // contains the information about the last values
      lastMouseY: 0,        // of the mouse position
      beingDragId: -1,      // who is being dragged
      isDragging: false,    // says if we are currently dragging something
      lineStyle: 'stroke:rgb(0,0,255);stroke-width:3',
      isEditing: true
    }
  },
  methods: {
    startDragNode (event) {
      if (this.mode !== MOVE) {
        return
      }
      // set the on mouse move listener
      window.addEventListener('mousemove', this.moveNode)
      window.addEventListener('mouseup', this.stopDragNode)
      // set the dragging mode
      this.isDragging = true
      // and save the mouse coordinates
      this.lastMouseX = event.offsetX
      this.lastMouseY = event.offsetY
      // set which node is starting to drag
      const nodeId = parseInt(event.target.getAttribute('nodeId'))
      this.beingDragId = nodeId
      console.log('[DEBUG] Starting to drag')
    },
    moveNode (event) {
      if (this.mode !== MOVE || !this.isDragging) {
        return
      }
      // get how much we move from the last mouse event
      const dx = event.offsetX - this.lastMouseX
      const dy = event.offsetY - this.lastMouseY
      // save mouse position for the next movement
      this.lastMouseX = event.offsetX
      this.lastMouseY = event.offsetY
      // move the node
      this.shiftNode(this.beingDragId, dx, dy)
    },
    shiftNode (nodeId, dx, dy) {
      // get the node to shift
      for (let i = 0; i < this.nodes.length; i++) {
        let node = this.nodes[i]
        if (node.id === nodeId) {
          node.x += dx
          node.y += dy
          break
        }
      }
    },
    stopDragNode (event) {
      if (this.mode !== MOVE) {
        return
      }
      // set the dragging mode
      this.isDragging = false
      this.beingDragId = -1
      window.removeEventListener('mousemove', this.moveNode)
      window.removeEventListener('mouseup', this.stopDragNode)
    },
    nodeClick (event) {
      if (this.mode === BUILD) {
        const nodeClikedId = parseInt(event.target.getAttribute('nodeId'))
        console.log('[INFO] node clicked', nodeClikedId)
        // here we reset the previous node id such that new path
        // will start from here
        if (this.prevNodeId !== -1) {
          console.log('[INFO] Joining nodes...')
          this.createLink(this.prevNodeId, nodeClikedId)
        }
        this.prevNodeId = nodeClikedId
        this.isSplitting = true
        event.stopPropagation()
      }
    },
    // create a new node and add it to the node list
    createNode (x, y) {
      // TEST
      if (this.lastId > 4) {
        console.log('[DEBUG] SWITCHING TO MODE MOVE')
        this.mode = MOVE
      }
      // END TEST
      // we update the id store
      this.lastId++
      const newNode = {
        id: this.lastId,
        x,
        y
      }
      // adding the new node to nodes list
      this.nodes.push(newNode)
      return newNode
    },
    // adds a new link given the from and to nodes id
    createLink (from, to) {
      this.links.push({from, to})
    },
    clickNode (event) {
      if (!this.isEditing || this.mode !== BUILD) {
        return
      }
      const newNode = this.createNode(event.offsetX, event.offsetY)
      console.log('[INFO] adding a new node', newNode)

      // if preNode is -1 this means that this node is a starting point
      // so at this time we don't add any link
      if (this.prevNodeId !== -1) {
        this.createLink(this.prevNodeId, newNode.id)
      }

      if (this.isSplitting) {
        // the previous node id was already set
        this.isSplitting = false
      }
      this.prevNodeId = this.lastId
    },
    resetPathStartingPoint (event) {
      console.log('[INFO] reseting starting point of the path')
      this.prevNodeId = -1
    }
  },
  computed: {
    lineLinks () {
      return this.links.map(l => {
        const n1 = this.nodes.filter(n => n.id === l.from)[0]
        const n2 = this.nodes.filter(n => n.id === l.to)[0]
        return {
          x1: n1.x,
          y1: n1.y,
          x2: n2.x,
          y2: n2.y
        }
      })
    }
  },
  watch: {
    links () {
      return this.links.map(l => {
        const n1 = this.nodes.filter(n => n.id === l.from)[0]
        const n2 = this.nodes.filter(n => n.id === l.to)[0]
        return {
          x1: n1.x,
          y1: n1.y,
          x2: n2.x,
          y2: n2.y
        }
      })
    }
  }
}
</script>

<style scoped>
@keyframes zoom {
    0%   {stroke-width: 2}
    100% {stroke-width: 20}
}
.circle {
	stroke-width: 1;
	stroke-linecap: round;
}
.circle:hover {
  stroke-width: 16px;
  cursor: pointer;
}
</style>


refactor(patreon): remove on example pages

<template lang="pug">
  doc-view(
    :toc="toc"
    :id="folder"
  )
    template(slot-scope="{ namespace }")
      section(v-if="usage")#usage
        section-head(value="Generic.Pages.usage")
        example(
          :new-in="usage.new"
          :file="`${folder}/${usage.file}`"
          :inverted="usage.inverted"
          :has-inverted="!usage.uninverted"
          :id="`usage-${-1}`"
          :key="usage.file"
          :desc="usage.desc"
        )

      section#api
        section-head(value="Generic.Pages.api")
        v-card
          v-tabs(
            v-model="tab"
            color="grey lighten-3"
            slider-color="primary"
          )
            template(v-for="(tab, i) in computedTabs")
              v-tab(
                :key="i"
                :href="`#${tab}`"
              ) {{ tab.replace(/([A-Z])/g, ' $1') }}
          v-card-title
            v-select(
              label="Component"
              hide-details
              single-line
              v-bind:items="components"
              v-model="current"
              auto
              :disabled="components.length < 2"
            )
            v-spacer
            v-spacer.hidden-sm-and-down
            v-text-field(
              append-icon="search"
              label="Search..."
              single-line
              hide-details
              v-model="search"
            )
          v-tabs-items(touchless v-model="tab").white
            v-tab-item(
              v-for="(tabItem, i) in computedTabs"
              :id="tabItem"
              :key="i"
            )
              v-card(flat v-if="hasTab(tabItem)")
                parameters(
                  :headers="headers[tabItem]"
                  :items="currentApi[tabItem]"
                  :namespace="namespace"
                  :search="search"
                  :target="current"
                  :type="tabItem"
                  :key="`${tabItem}${namespace}${current}`"
                )

      section(v-if="supplemental.length > 0")#supplemental
        section-head(value="Generic.Pages.supplemental")
        component(
          v-for="sup in supplemental"
          :key="sup"
          :is="sup"
        )

      slot(name="top")
      section(v-if="examples.length > 1")#examples
        section-head(value="Generic.Pages.examples")
        template(v-for="(example, i) in examples.slice(1)")
          example(
            :header="`${example.header}`"
            :new-in="example.new"
            :file="`${folder}/${example.file}`"
            :inverted="example.inverted"
            :has-inverted="!example.uninverted"
            :id="`example-${camelCaseToDash(example.file)}`"
            :key="example.file"
            :desc="example.desc"
          )
      section-head {{ $t('Generic.Pages.examples') }}

      slot
</template>

<script>
  import api from '@/api/api'
  // Utilities
  import { camel } from '@/util/helpers'

  export default {
    inheritAttrs: false,

    props: {
      data: {
        type: Object,
        default: () => ({})
      }
    },

    data () {
      return {
        api,
        current: null,
        id: '',
        headers: {
          props: [
            { value: 'name', align: 'left', size: 3 },
            { value: 'default', align: 'left', size: 6 },
            { value: 'type', align: 'right', size: 3 }
          ],
          slots: [
            { value: 'name', align: 'left' }
          ],
          scopedSlots: [
            { value: 'name', align: 'left', size: 3 },
            { value: 'props', align: 'right', size: 9 }
          ],
          events: [
            { value: 'name', align: 'left' },
            { value: 'value', align: 'right' }
          ],
          functions: [
            { value: 'name', align: 'left' },
            { value: 'signature', align: 'right' }
          ],
          functional: [
            { value: 'name', align: 'left' },
            { value: 'description', align: 'left' }
          ],
          options: [
            { value: 'name', align: 'left', size: 3 },
            { value: 'default', align: 'left', size: 3 },
            { value: 'type', align: 'right' }
          ]
        },
        search: null,
        tab: null,
        tabs: ['props', 'slots', 'scopedSlots', 'params', 'events', 'functions', 'functional', 'options']
      }
    },

    computed: {
      components () {
        let components = (this.data.components || []).slice()

        if (this.data.component) {
          components.unshift(this.data.component)
        }

        return components
      },
      computedTabs () {
        return this.tabs.filter(tab => (this.currentApi[tab] || []).length > 0)
      },
      currentApi () {
        return this.api[this.current] || {
          props: [],
          slots: [],
          scopedSlots: [],
          params: [],
          events: [],
          funtions: [],
          functional: [],
          options: []
        }
      },
      examples () {
        const examples = this.data.examples || {}

        return Object.keys(examples).map(key => {
          return Object.assign({
            file: key
          }, examples[key])
        })
      },
      folder () {
        return this.data.folder || this.$route.params.component
      },
      namespace () {
        const component = camel(this.$route.params.component)
        const section = camel(this.$route.params.section)

        return `${section}.${component}`
      },
      supplemental () {
        const namespace = `${this.namespace}.supplemental`
        return this.$te(namespace)
          ? this.$t(namespace)
          : this.$te(namespace, 'en')
            ? this.$t(namespace, 'en')
            : []
      },
      toc () {
        return this.$t(this.data.toc || `Generic.Pages.toc`)
      },
      usage () {
        return this.examples.slice(0, 1).shift()
      }
    },

    watch: {
      currentApi () {
        if (this.currentApi.hasOwnProperty(this.tab) &&
          this.currentApi[this.tab].length > 0
        ) return

        for (let tab of ['props', 'slots']) {
          if (this.currentApi[tab].length > 0) {
            this.tab = tab
            break
          }
        }
      }
    },

    created () {
      if (this.components.length) {
        this.current = this.components[0]
      }
    },

    methods: {
      hasTab (tab) {
        return (this.currentApi[tab] || []).length > 0
      },
      camelCaseToDash (str) {
        return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()
      }
    }
  }
</script>

<template lang="pug">
  doc-view(
    :toc="toc"
    :id="folder"
  )
    template(slot-scope="{ namespace }")
      section(v-if="usage")#usage
        section-head(value="Generic.Pages.usage")
        example(
          :new-in="usage.new"
          :file="`${folder}/${usage.file}`"
          :inverted="usage.inverted"
          :has-inverted="!usage.uninverted"
          :id="`usage-${-1}`"
          :key="usage.file"
          :desc="usage.desc"
        )

      section#api
        section-head(value="Generic.Pages.api")
        v-card
          v-tabs(
            v-model="tab"
            color="grey lighten-3"
            slider-color="primary"
          )
            template(v-for="(tab, i) in computedTabs")
              v-tab(
                :key="i"
                :href="`#${tab}`"
              ) {{ tab.replace(/([A-Z])/g, ' $1') }}
          v-card-title
            v-select(
              label="Component"
              hide-details
              single-line
              v-bind:items="components"
              v-model="current"
              auto
              :disabled="components.length < 2"
            )
            v-spacer
            v-spacer.hidden-sm-and-down
            v-text-field(
              append-icon="search"
              label="Search..."
              single-line
              hide-details
              v-model="search"
            )
          v-tabs-items(touchless v-model="tab").white
            v-tab-item(
              v-for="(tabItem, i) in computedTabs"
              :id="tabItem"
              :key="i"
            )
              v-card(flat v-if="hasTab(tabItem)")
                parameters(
                  :headers="headers[tabItem]"
                  :items="currentApi[tabItem]"
                  :namespace="namespace"
                  :search="search"
                  :target="current"
                  :type="tabItem"
                  :key="`${tabItem}${namespace}${current}`"
                )

      section(v-if="supplemental.length > 0")#supplemental
        section-head(value="Generic.Pages.supplemental")
        component(
          v-for="sup in supplemental"
          :key="sup"
          :is="sup"
        )

      slot(name="top")
      section(v-if="examples.length > 1")#examples
        section-head(value="Generic.Pages.examples")
        template(v-for="(example, i) in examples.slice(1)")
          support-vuetify(v-if="i === 5" :key="i")
          example(
            :header="`${example.header}`"
            :new-in="example.new"
            :file="`${folder}/${example.file}`"
            :inverted="example.inverted"
            :has-inverted="!example.uninverted"
            :id="`example-${camelCaseToDash(example.file)}`"
            :key="example.file"
            :desc="example.desc"
          )
      section-head {{ $t('Generic.Pages.examples') }}

      slot
</template>

<script>
  import api from '@/api/api'
  // Utilities
  import { camel } from '@/util/helpers'

  export default {
    inheritAttrs: false,

    props: {
      data: {
        type: Object,
        default: () => ({})
      }
    },

    data () {
      return {
        api,
        current: null,
        id: '',
        headers: {
          props: [
            { value: 'name', align: 'left', size: 3 },
            { value: 'default', align: 'left', size: 6 },
            { value: 'type', align: 'right', size: 3 }
          ],
          slots: [
            { value: 'name', align: 'left' }
          ],
          scopedSlots: [
            { value: 'name', align: 'left', size: 3 },
            { value: 'props', align: 'right', size: 9 }
          ],
          events: [
            { value: 'name', align: 'left' },
            { value: 'value', align: 'right' }
          ],
          functions: [
            { value: 'name', align: 'left' },
            { value: 'signature', align: 'right' }
          ],
          functional: [
            { value: 'name', align: 'left' },
            { value: 'description', align: 'left' }
          ],
          options: [
            { value: 'name', align: 'left', size: 3 },
            { value: 'default', align: 'left', size: 3 },
            { value: 'type', align: 'right' }
          ]
        },
        search: null,
        tab: null,
        tabs: ['props', 'slots', 'scopedSlots', 'params', 'events', 'functions', 'functional', 'options']
      }
    },

    computed: {
      components () {
        let components = (this.data.components || []).slice()

        if (this.data.component) {
          components.unshift(this.data.component)
        }

        return components
      },
      computedTabs () {
        return this.tabs.filter(tab => (this.currentApi[tab] || []).length > 0)
      },
      currentApi () {
        return this.api[this.current] || {
          props: [],
          slots: [],
          scopedSlots: [],
          params: [],
          events: [],
          funtions: [],
          functional: [],
          options: []
        }
      },
      examples () {
        const examples = this.data.examples || {}

        return Object.keys(examples).map(key => {
          return Object.assign({
            file: key
          }, examples[key])
        })
      },
      folder () {
        return this.data.folder || this.$route.params.component
      },
      namespace () {
        const component = camel(this.$route.params.component)
        const section = camel(this.$route.params.section)

        return `${section}.${component}`
      },
      supplemental () {
        const namespace = `${this.namespace}.supplemental`
        return this.$te(namespace)
          ? this.$t(namespace)
          : this.$te(namespace, 'en')
            ? this.$t(namespace, 'en')
            : []
      },
      toc () {
        return this.$t(this.data.toc || `Generic.Pages.toc`)
      },
      usage () {
        return this.examples.slice(0, 1).shift()
      }
    },

    watch: {
      currentApi () {
        if (this.currentApi.hasOwnProperty(this.tab) &&
          this.currentApi[this.tab].length > 0
        ) return

        for (let tab of ['props', 'slots']) {
          if (this.currentApi[tab].length > 0) {
            this.tab = tab
            break
          }
        }
      }
    },

    created () {
      if (this.components.length) {
        this.current = this.components[0]
      }
    },

    methods: {
      hasTab (tab) {
        return (this.currentApi[tab] || []).length > 0
      },
      camelCaseToDash (str) {
        return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()
      }
    }
  }
</script>


Removed icon to invite user to answer question.

<template>

{{$t('pages:question.askUserAnswerQuestion.title')}}

{{$t('pages:question.askUserAnswerQuestion.description')}}

            <v-tooltip bottom>
                <template v-slot:activator="{ on }">

                </template>
                {{$t('pages:question.askUserAnswerQuestion.whatsAppButton')}}
            </v-tooltip>
            <v-tooltip bottom>
                <template v-slot:activator="{ on }">

                </template>
                {{$t('pages:question.askUserAnswerQuestion.telegramButton')}}
            </v-tooltip>

        <invite-user-to-answer-question-dialog v-if="showInviteUserToAnswerQuestionDialog"
                                               :question-id="$route.params.questionId"
                                               @close-dialog="showInviteUserToAnswerQuestionDialog = false">
        </invite-user-to-answer-question-dialog>

</template>

<template>

{{$t('pages:question.askUserAnswerQuestion.title')}}

{{$t('pages:question.askUserAnswerQuestion.description')}}

            <v-tooltip bottom>
                <template v-slot:activator="{ on }">

                </template>
                {{$t('pages:question.askUserAnswerQuestion.dumondaMeButton')}}
            </v-tooltip>
            <v-tooltip bottom>
                <template v-slot:activator="{ on }">

                </template>
                {{$t('pages:question.askUserAnswerQuestion.whatsAppButton')}}
            </v-tooltip>
            <v-tooltip bottom>
                <template v-slot:activator="{ on }">

                </template>
                {{$t('pages:question.askUserAnswerQuestion.telegramButton')}}
            </v-tooltip>

        <invite-user-to-answer-question-dialog v-if="showInviteUserToAnswerQuestionDialog"
                                               :question-id="$route.params.questionId"
                                               @close-dialog="showInviteUserToAnswerQuestionDialog = false">
        </invite-user-to-answer-question-dialog>

</template>


Added color legend

Added color legend

<template>

        <loading-overlay v-show="loading"></loading-overlay>

Manage

Students

        <alert type="danger" v-bind:message="errorMessage" v-bind:show="errorMessage" v-on:close="errorMessage = ''"></alert>

                    <input type="text" class="form-control input-block" placeholder="Search students" v-model="query" v-on:keyup.enter="handleSearch">

                <select class="m-l-s" v-model="limit" v-on:change="handleRefresh()">
                    <option v-bind:value="15">Show 15 items</option>
                    <option v-bind:value="25">Show 25 items</option>
                    <option v-bind:value="50">Show 50 items</option>
                </select>

                    <router-link to="/manage/students/import" class="btn btn-primary-outline">Import</router-link>
                    Export

                <select v-model="actionMode">
                    <option v-bind:value="1">With selected items only:</option>
                    <option v-bind:value="2">With all matching items:</option>
                </select>

                    Publish
                    Unpublish

                        <input type="checkbox" ref="selectAll" v-on:change="handleSelectAll">

                        Program
                        Satisfaction
                        Student Coach
                        Cohort
                        Year
                        Goal

                        Published

                        <input type="checkbox" class="select-row">

                            <router-link v-bind:to="'/manage/students/' + item.id">{{ item.student_number }}</router-link>

                        {{ _.truncate(item.display_name, {length: 30}) }}
                        {{ _.truncate(item.program_name, {length: 30}) }}
                        {{ item.program_satisfaction }}
                        {{ item.first_year_mentor }}
                        {{ item.cohort }}
                        {{ item.year }}
                        {{ (item.year === 1) ? item.first_year_credits_goal : item.second_year_credits_goal }}

                            = 54 EC expected" v-if="item.second_year_credits_expected >= 54">
                            = 30 EC expected" v-else-if="item.second_year_credits_expected >= 30">
                            <i class="fa fa-circle" style="color: red;" title="< 30 EC expected" v-else>

                        No results

        <pagination v-bind:pagination="pagination" v-on:goToPage="handleGoToPage"></pagination>

</template>

<template>

        <loading-overlay v-show="loading"></loading-overlay>

Manage

Students

        <alert type="danger" v-bind:message="errorMessage" v-bind:show="errorMessage" v-on:close="errorMessage = ''"></alert>

                    <input type="text" class="form-control input-block" placeholder="Search students" v-model="query" v-on:keyup.enter="handleSearch">

                <select class="m-l-s" v-model="limit" v-on:change="handleRefresh()">
                    <option v-bind:value="15">Show 15 items</option>
                    <option v-bind:value="25">Show 25 items</option>
                    <option v-bind:value="50">Show 50 items</option>
                </select>

                    <router-link to="/manage/students/import" class="btn btn-primary-outline">Import</router-link>
                    Export

                <select v-model="actionMode">
                    <option v-bind:value="1">With selected items only:</option>
                    <option v-bind:value="2">With all matching items:</option>
                </select>

                    Publish
                    Unpublish

                        <input type="checkbox" ref="selectAll" v-on:change="handleSelectAll">

                        Program
                        Satisfaction
                        Student Coach
                        Cohort
                        Year
                        Goal

                        Published

                        <input type="checkbox" class="select-row">

                            <router-link v-bind:to="'/manage/students/' + item.id">{{ item.student_number }}</router-link>

                        {{ _.truncate(item.display_name, {length: 30}) }}
                        {{ _.truncate(item.program_name, {length: 30}) }}
                        {{ item.program_satisfaction }}
                        {{ item.first_year_mentor }}
                        {{ item.cohort }}
                        {{ item.year }}
                        {{ (item.year === 1) ? item.first_year_credits_goal : item.second_year_credits_goal }}

                            = 54">
                            = 30">

                        No results

        <pagination v-bind:pagination="pagination" v-on:goToPage="handleGoToPage"></pagination>

</template>


Fix duplicated disconnected dialog (Fix #5782) (#5790)

* Fix #5782
fix duplicated disconnected dialog

* fix

<template>

			<transition name="header" mode="out-in" appear>
				<button class="_button back" v-if="canBack" @click="back()"><fa :icon="faChevronLeft"/></button>
			</transition>
			<transition name="header" mode="out-in" appear>

						<portal-target name="avatar" slim/>

<portal-target name="icon" slim/><portal-target name="title" slim/>

						<portal-target name="header" slim/>

			</transition>

			<fa :icon="faSearch"/>
			<input type="search" class="search" :placeholder="$t('search')" v-model="searchQuery" v-autocomplete="{ model: 'searchQuery' }" :disabled="searchWait" @keypress="searchKeypress"/>
			<button v-if="$store.getters.isSignedIn" class="post _buttonPrimary" @click="post()"><fa :icon="faPencilAlt"/></button>

			<button class="item _button account" @click="openAccountMenu" v-if="$store.getters.isSignedIn">
				<mk-avatar :user="$store.state.i" class="avatar"/><mk-acct class="text" :user="$store.state.i"/>
			</button>
			<router-link class="item" active-class="active" to="/" exact v-if="$store.getters.isSignedIn">
				<fa :icon="faHome" fixed-width/>{{ $t('timeline') }}
			</router-link>
			<router-link class="item" active-class="active" to="/" exact v-else>
				<fa :icon="faHome" fixed-width/>{{ $t('home') }}
			</router-link>
			<router-link class="item" active-class="active" to="/featured">
				<fa :icon="faFireAlt" fixed-width/>{{ $t('featured') }}
			</router-link>
			<router-link class="item" active-class="active" to="/explore">
				<fa :icon="faHashtag" fixed-width/>{{ $t('explore') }}
			</router-link>
			<button class="item _button" @click="notificationsOpen = !notificationsOpen" ref="notificationButton" v-if="$store.getters.isSignedIn">
				<fa :icon="faBell" fixed-width/>{{ $t('notifications') }}
				<fa :icon="faCircle"/>
			</button>
			<router-link class="item" active-class="active" to="/my/messaging" v-if="$store.getters.isSignedIn">
				<fa :icon="faComments" fixed-width/>{{ $t('messaging') }}
				<fa :icon="faCircle"/>
			</router-link>
			<router-link class="item" active-class="active" to="/my/follow-requests" v-if="$store.getters.isSignedIn && $store.state.i.isLocked">
				<fa :icon="faUserClock" fixed-width/>{{ $t('followRequests') }}
				<fa :icon="faCircle"/>
			</router-link>
			<router-link class="item" active-class="active" to="/my/drive" v-if="$store.getters.isSignedIn">
				<fa :icon="faCloud" fixed-width/>{{ $t('drive') }}
			</router-link>
			<router-link class="item" active-class="active" to="/announcements">
				<fa :icon="faBroadcastTower" fixed-width/>{{ $t('announcements') }}
				<fa :icon="faCircle"/>
			</router-link>
			<button class="item _button" :class="{ active: $route.path === '/instance' || $route.path.startsWith('/instance/') }" v-if="$store.getters.isSignedIn && ($store.state.i.isAdmin || $store.state.i.isModerator)" @click="oepnInstanceMenu">
				<fa :icon="faServer" fixed-width/>{{ $t('instance') }}
			</button>
			<button class="item _button" @click="search()">
				<fa :icon="faSearch" fixed-width/>{{ $t('search') }}
			</button>
			<button class="item _button" @click="more">
				<fa :icon="faEllipsisH" fixed-width/>{{ $t('more') }}
				<fa :icon="faCircle"/>
			</button>

				<transition name="page" mode="out-in">
					<router-view></router-view>
				</transition>

				<router-link to="/">{{ host }}</router-link>
				Powered by Misskey

				<template v-if="enableWidgets && $store.getters.isSignedIn">
					<template v-if="widgetsEditMode">
						<mk-button primary @click="addWidget" class="add"><fa :icon="faPlus"/></mk-button>
						<x-draggable
							:list="widgets"
							handle=".handle"
							animation="150"
							class="sortable"
							@sort="onWidgetSort"
						>

									<fa :icon="faBars"/>{{ widget.name }}<button class="remove" @click="removeWidget(widget)"><fa :icon="faTimes"/></button>

									<component :is="`mkw-${widget.name}`" :widget="widget" :ref="widget.id" :is-customize-mode="true"/>

						</x-draggable>
					</template>
					<template v-else>
						<component class="widget" v-for="widget in widgets" :is="`mkw-${widget.name}`" :key="widget.id" :ref="widget.id" :widget="widget"/>
					</template>
					<button ref="widgetsEditButton" v-if="widgetsEditMode" class="_button edit" @click="widgetsEditMode = false">{{ $t('exitEdit') }}</button>
					<button ref="widgetsEditButton" v-else class="_button edit" @click="widgetsEditMode = true">{{ $t('editWidgets') }}</button>
				</template>

		<button v-if="$store.getters.isSignedIn" class="button nav _button" @click="showNav" ref="navButton"><fa :icon="faBars"/><fa :icon="faCircle"/></button>
		<button v-if="$store.getters.isSignedIn" class="button home _button" :disabled="$route.path === '/'" @click="$router.push('/')"><fa :icon="faHome"/></button>
		<button v-if="$store.getters.isSignedIn" class="button notifications _button" @click="notificationsOpen = !notificationsOpen" ref="notificationButton2"><fa :icon="notificationsOpen ? faTimes : faBell"/><fa :icon="faCircle"/></button>
		<button v-if="$store.getters.isSignedIn" class="button post _buttonPrimary" @click="post()"><fa :icon="faPencilAlt"/></button>

	<button v-if="$store.getters.isSignedIn" class="post _buttonPrimary" @click="post()"><fa :icon="faPencilAlt"/></button>

	<transition name="zoom-in-top">
		<x-notifications v-if="notificationsOpen" class="notifications" ref="notifications"/>
	</transition>

</template>


Use is_leaf to describe isTopic

Use is_leaf to describe isTopic

Co-authored-by: marcellamaki <f4483dcbc483416e2e56ae197e390fbe0a767439@learningequality.org>

<template>

  <router-link :to="link" :class="$computedClass({ ':focus': $coreOutline })">

        <CardThumbnail
          :isMobile="isMobile"
          :contentNode="content"
        />

          <LearningActivityLabel
            :contentNode="content"
            :labelAfter="true"
            :hideDuration="!isMobile"
            condensed
          />

          <TextTruncator
            :text="content.title"
            :maxHeight="maxTitleHeight"
          />

          <TextTruncator
            :text="content.description"
            :maxHeight="maxDescriptionHeight"
          />

 {{ coreString(displayCategoryAndLevelMetadata) }}

        <KButton
          v-if="!isMobile && content.copies && content.copies.length"
          appearance="basic-link"
          class="copies"
          :style="{ color: $themeTokens.text }"
          :text="coreString('copies', { num: content.copies.length })"
          @click.prevent="$emit('openCopiesModal', content.copies)"
        />

              {{ bookmarkCreated }}

            <ProgressBar :contentNode="content" />

          <CoachContentLabel
            v-if="isUserLoggedIn && !isLearner && content.num_coach_contents"
            class="coach-footer-icon"
            :value="content.num_coach_contents"
            :isTopic="!content.is_leaf"
          />
          <KIconButton
            v-for="(value, key) in footerIcons"
            :key="key"
            :icon="key"
            size="mini"
            :color="$themePalette.grey.v_400"
            :ariaLabel="coreString(value)"
            :tooltip="coreString(value)"
            @click.prevent="$emit(value)"
          />

  </router-link>

</template>

<template>

  <router-link :to="link" :class="$computedClass({ ':focus': $coreOutline })">

        <CardThumbnail
          :isMobile="isMobile"
          :contentNode="content"
        />

          <LearningActivityLabel
            :contentNode="content"
            :labelAfter="true"
            :hideDuration="!isMobile"
            condensed
          />

          <TextTruncator
            :text="content.title"
            :maxHeight="maxTitleHeight"
          />

          <TextTruncator
            :text="content.description"
            :maxHeight="maxDescriptionHeight"
          />

 {{ coreString(displayCategoryAndLevelMetadata) }}

        <KButton
          v-if="!isMobile && content.copies && content.copies.length"
          appearance="basic-link"
          class="copies"
          :style="{ color: $themeTokens.text }"
          :text="coreString('copies', { num: content.copies.length })"
          @click.prevent="$emit('openCopiesModal', content.copies)"
        />

              {{ bookmarkCreated }}

            <ProgressBar :contentNode="content" />

          <CoachContentLabel
            v-if="isUserLoggedIn && !isLearner && content.num_coach_contents"
            class="coach-footer-icon"
            :value="content.num_coach_contents"
            :isTopic="content.num_coach_contents >= 1"
          />
          <KIconButton
            v-for="(value, key) in footerIcons"
            :key="key"
            :icon="key"
            size="mini"
            :color="$themePalette.grey.v_400"
            :ariaLabel="coreString(value)"
            :tooltip="coreString(value)"
            @click.prevent="$emit(value)"
          />

  </router-link>

</template>


Update test app

Update test app

<template>
  <div id="app">
    <VlMap
      ref="map"
      data-projection="EPSG:4326">
      <VlView
        ref="view"
        :center="center"
        :zoom="zoom"
        @update:center="centerChanged"
        @update:zoom="zoomChanged" />

      <VlLayerTile>
        <VlSourceOsm />
      </VlLayerTile>
    </VlMap>
  </div>
</template>

<script>
  export default {
    name: 'App',
    data () {
      let center = [0, 0]
      let zoom = 3
      const urlVals = this.parseUrl()
      if (urlVals) {
        center = urlVals.center
        zoom = urlVals.zoom
      }

      return {
        center,
        zoom,
        rotation: 0,
      }
    },
    methods: {
      centerChanged (center) {
        this.center = center
        this.updateUrl()
      },
      zoomChanged (zoom) {
        this.zoom = zoom
        this.updateUrl()
      },
      updateUrl () {
        const url = new URL(window.location.href)
        url.hash = `#${this.center[0]},${this.center[1]},${this.zoom}`
        window.location.href = url.href
      },
      parseUrl () {
        const url = new URL(window.location.href)
        const hash = url.hash.slice(1)
        if (!hash) return

        const arr = hash.split(',').map(v => Number(v.trim()))
        return {
          center: [arr[0], arr[1]],
          zoom: arr[2],
        }
      },
    },
  }
</script>

<style lang="scss" rel="stylesheet/scss">
  @import "~ol/ol";

  html, body, #app {
    width: 100%;
    height: 100%;
    margin: 0;
    box-sizing: border-box;
    font-family: Helvetica, Arial, sans-serif;
    overflow: hidden;

    * {
      box-sizing: border-box;
    }
  }
</style>

<template>
  <div id="app">
    <VlMap
      :id.sync="mapId"
      ref="map"
      :data-projection.sync="dataProj">
      <VlView
        :id.sync="viewId"
        ref="view"
        :center.sync="center"
        :zoom.sync="zoom"
        :projection.sync="viewProj" />

      <VlLayerTile>
        <VlSourceOsm />
      </VlLayerTile>

      <VlLayerVector :declutter.sync="decl">
        <VlSourceVector :features.sync="features" />
        <VlStyle>
          <VlStyleStroke
            :width="2"
            color="black" />
          <VlStyleFill color="pink" />
          <VlStyleCircle :radius="5">
            <VlStyleStroke
              :width="2"
              color="black" />
            <VlStyleFill color="pink" />
          </VlStyleCircle>
        </VlStyle>
      </VlLayerVector>

      <VlInteractionSelect :condition="pointerMove">
        <VlStyleFunc :function="selectStyleFunc" />
      </VlInteractionSelect>
    </VlMap>
  </div>
</template>

<script>
  import { pointerMove } from 'ol/events/condition'
  import { createStyle } from '../src/ol-ext'

  export default {
    name: 'App',
    data () {
      return {
        center: [0, 40],
        zoom: 3,
        rotation: 0,
        features: [],
        mapId: 'qwerty',
        viewId: 'asdfg',
        dataProj: 'EPSG:4326',
        viewProj: 'EPSG:3857',
        decl: true,
      }
    },
    mounted () {
      setTimeout(() => {
        this.features = [
          {
            type: 'Feature',
            geometry: {
              type: 'Polygon',
              coordinates: [
                [
                  [10, 10],
                  [10, 20],
                  [20, 20],
                  [20, 10],
                  [10, 10],
                ],
              ],
            },
          },
          {
            type: 'Feature',
            geometry: {
              type: 'Point',
              coordinates: [-10, -10],
            },
          },
        ]
      }, 1000)
    },
    methods: {
      pointerMove,
      selectStyleFunc () {
        return createStyle({
          fillColor: 'green',
          strokeColor: 'black',
          strokeWidth: 3,
          imageRadius: 6,
          imageFillColor: 'green',
          imageStrokeColor: 'black',
          imageStrokeWidth: 3,
        })
      },
    },
  }
</script>

<style lang="scss" rel="stylesheet/scss">
  @import "~ol/ol";

  html, body, #app {
    width: 100%;
    height: 100%;
    margin: 0;
    box-sizing: border-box;
    font-family: Helvetica, Arial, sans-serif;
    overflow: hidden;

    * {
      box-sizing: border-box;
    }
  }
</style>


flexbox: Update demo

flexbox: Update demo

<template>

    <flexbox :gutter="0" class="vux-1px-b" v-for="list in components">
      <flexbox-item :span="1/3" v-for="component in list" class="cbox vux-1px-t" @click.native="go(component.name.toLowerCase())">

          {{component.name}}

      </flexbox-item>
    </flexbox>

</template>

<template>

    <keep-alive>
      <flexbox wrap="wrap" :gutter="0" class="vux-1px-b">
        <flexbox-item :span="1/3" v-for="component in components" class="cbox vux-1px-t" @click.native="go(component.name.toLowerCase())">

            {{component.name}}

        </flexbox-item>
      </flexbox>
    </keep-alive>

</template>


Work in progress

Work in progress

<template>

    <slot></slot>

{{title}}

          <slot name="content" v-if="!text"></slot>

</template>


remove temporary icon

remove temporary icon

<template>

      <modal v-model="tourSelectionModal" title="Available Tours" ref="modal">

              {{tourLoader.loader}}

                {{tour.name}}
                by {{tour.author}}

          <btn @click="tourSelectionModal=false">Close</btn>

      </modal>

</template>


advanced validation parameters

advanced validation parameters

<template>

        <transition name="fade" mode="out-in">
          <router-view :group="form" :v="$v.form" @input="(payload) => updateGroupData(payload)">
          </router-view>
        </transition>

          <p class="control" v-if="currentStep + 1 < config.steps.length">
            <button
              class="button is-success is-large"
              @click="next"
              id="nextBtn"
              :disabled="$v.steps[$route.name] && $v.steps[$route.name].$invalid"
            >
              <i18n>Next</i18n>

            </button>

            <button
              class="button is-success is-large"
              @click="submit"
              :disabled="$v.form.$invalid"
              id="finishBtn"
            >
              <i18n>Finish</i18n>

            </button>

            <button
              class="button is-light is-medium"
              @click="prev"
              :disabled="!this.currentStep"
              id="prevBtn"
            >
              <i18n>Back</i18n>
            </button>

            {{ errorMsg }}

</template>


docs(VWindow): update onboarding example (#14157)

<template>
  <v-card
    color="black"
    dark
    flat
    tile
  >
    <v-window v-model="onboarding">
      <v-window-item
        v-for="n in length"
        :key="`card-${n}`"
      >
        <v-card
          color="transparent"
          height="200"
        >
          <v-row
            class="fill-height"
            align="center"
            justify="center"
          >
            <v-card-text class="text-center">
              Transparent themed, for background-imaged slides. Background color black added for demonstration purposes.
            </v-card-text>
          </v-row>
        </v-card>
      </v-window-item>
    </v-window>

    <v-card-actions class="justify-space-between">
      <v-btn
        text
        @click="prev"
      >
        <v-icon>mdi-chevron-left</v-icon>
      </v-btn>
      <v-item-group
        v-model="onboarding"
        class="text-center"
        mandatory
      >
        <v-item
          v-for="n in length"
          :key="`btn-${n}`"
          v-slot="{ active, toggle }"
        >
          <v-btn
            :input-value="active"
            icon
            @click="toggle"
          >
            <v-icon>mdi-record</v-icon>
          </v-btn>
        </v-item>
      </v-item-group>
      <v-btn
        text
        @click="next"
      >
        <v-icon>mdi-chevron-right</v-icon>
      </v-btn>
    </v-card-actions>
  </v-card>
</template>

<script>
  export default {
    data: () => ({
      length: 3,
      onboarding: 0,
    }),

    methods: {
      next () {
        this.onboarding = this.onboarding + 1 === this.length
          ? 0
          : this.onboarding + 1
      },
      prev () {
        this.onboarding = this.onboarding - 1 < 0
          ? this.length - 1
          : this.onboarding - 1
      },
    },
  }
</script>

<template>
  <v-card
    color="black"
    dark
    flat
    tile
  >
    <v-window v-model="onboarding">
      <v-window-item
        v-for="n in length"
        :key="`card-${n}`"
      >
        <v-card
          color="transparent"
          height="200"
        >
          <v-row
            class="fill-height"
            align="center"
            justify="center"
          >
            <v-card-text>
              Transparent themed, for background-imaged slides. Background color black added for demonstration purposes.
            </v-card-text>
          </v-row>
        </v-card>
      </v-window-item>
    </v-window>

    <v-card-actions class="justify-space-between">
      <v-btn
        text
        @click="prev"
      >
        <v-icon>mdi-chevron-left</v-icon>
      </v-btn>
      <v-item-group
        v-model="onboarding"
        class="text-center"
        mandatory
      >
        <v-item
          v-for="n in length"
          :key="`btn-${n}`"
          v-slot="{ active, toggle }"
        >
          <v-btn
            :input-value="active"
            icon
            @click="toggle"
          >
            <v-icon>mdi-record</v-icon>
          </v-btn>
        </v-item>
      </v-item-group>
      <v-btn
        text
        @click="next"
      >
        <v-icon>mdi-chevron-right</v-icon>
      </v-btn>
    </v-card-actions>
  </v-card>
</template>

<script>
  export default {
    data: () => ({
      length: 3,
      onboarding: 0,
    }),

    methods: {
      next () {
        this.onboarding = this.onboarding + 1 === this.length
          ? 0
          : this.onboarding + 1
      },
      prev () {
        this.onboarding = this.onboarding - 1 < 0
          ? this.length - 1
          : this.onboarding - 1
      },
    },
  }
</script>


Improve UI for firefox

Improve UI for firefox

<template>
    <el-button round href="/login/google"
            @click="openGoogle"
            plain
            :size="size">

            Connect with your Google account

    </el-button>
</template>