<commit_before><template>

  <div>
    <div v-if="viewAllText">
      {{ text }}
    </div>
    <div v-else ref="shaveEl">
      {{ text }}
    </div>
    <div
      v-if="showViewMore && (textIsTruncated || viewAllText)"
      class="show-more"
    >
      <KButton
        appearance="basic-link"
        :text="viewAllText ? $tr('viewLessButtonPrompt') : coreString('viewMoreAction')"
        @click.stop.prevent="viewAllText = !viewAllText"
      />
    </div>
  </div>

</template>


<script>

  import shave from 'shave';
  import debounce from 'lodash/debounce';
  import responsiveElementMixin from 'kolibri.coreVue.mixins.responsiveElementMixin';
  import commonCoreStrings from 'kolibri.coreVue.mixins.commonCoreStrings';

  export default {
    name: 'TextTruncator',
    mixins: [commonCoreStrings, responsiveElementMixin],
    props: {
      text: {
        type: String,
        required: true,
      },
      maxHeight: {
        type: Number,
        required: true,
        validator(value) {
          return value > 0;
        },
      },
      showViewMore: {
        type: Boolean,
        required: false,
        default: false,
      },
    },
    data() {
      return {
        textIsTruncated: false,
        viewAllText: false,
      };
    },
    computed: {
      currentDimensions() {
        return {
          text: this.text,
          maxHeight: this.maxHeight,
          elementWidth: this.elementWidth,
          elementHeight: this.elementHeight,
        };
      },
      debouncedHandleUpdate() {
        return debounce(this.handleUpdate, 50);
      },
    },
    watch: {
      currentDimensions() {
        this.debouncedHandleUpdate();
      },
    },
    methods: {
      handleUpdate() {
        // TODO make "View Less" disappear when user expands window
        // and text isn't truncated any more.
        shave(this.$refs.shaveEl, this.maxHeight);
        this.$nextTick(() => {
          this.textIsTruncated = Boolean(this.$el.querySelector('.js-shave'));
        });
      },
    },
    $trs: {
      viewLessButtonPrompt: 'View less',
    },
  };

</script>


<style lang="scss" scoped>

  .show-more {
    margin-top: 8px;
    text-align: right;
  }

</style><commit_msg>feat: dynamically add title on shaved text<commit_after><template>

  <div>
    <div v-if="viewAllText">
      {{ text }}
    </div>
    <div v-else ref="shaveEl">
      {{ text }}
    </div>
    <div
      v-if="showViewMore && (textIsTruncated || viewAllText)"
      class="show-more"
    >
      <KButton
        appearance="basic-link"
        :text="viewAllText ? $tr('viewLessButtonPrompt') : coreString('viewMoreAction')"
        @click.stop.prevent="viewAllText = !viewAllText"
      />
    </div>
  </div>

</template>


<script>

  import shave from 'shave';
  import debounce from 'lodash/debounce';
  import responsiveElementMixin from 'kolibri.coreVue.mixins.responsiveElementMixin';
  import commonCoreStrings from 'kolibri.coreVue.mixins.commonCoreStrings';

  export default {
    name: 'TextTruncator',
    mixins: [commonCoreStrings, responsiveElementMixin],
    props: {
      text: {
        type: String,
        required: true,
      },
      maxHeight: {
        type: Number,
        required: true,
        validator(value) {
          return value > 0;
        },
      },
      showViewMore: {
        type: Boolean,
        required: false,
        default: false,
      },
    },
    data() {
      return {
        textIsTruncated: false,
        viewAllText: false,
      };
    },
    computed: {
      currentDimensions() {
        return {
          text: this.text,
          maxHeight: this.maxHeight,
          elementWidth: this.elementWidth,
          elementHeight: this.elementHeight,
        };
      },
      debouncedHandleUpdate() {
        return debounce(this.handleUpdate, 50);
      },
    },
    watch: {
      currentDimensions() {
        this.debouncedHandleUpdate();
      },
    },
    methods: {
      handleUpdate() {
        // TODO make "View Less" disappear when user expands window
        // and text isn't truncated any more.
        shave(this.$refs.shaveEl, this.maxHeight);
        this.$nextTick(() => {
          this.textIsTruncated = Boolean(this.$el.querySelector('.js-shave'));
          // set title attribute for shaved text but
          // skip if a title already exists
          if (this.textIsTruncated && !this.$refs.shaveEl.title)
            this.$refs.shaveEl.setAttribute('title', this.text);
          // if the text is not shaved and a title has been previously set,
          // remove it
          else if (!this.textIsTruncated && this.$refs.shaveEl.title)
            this.$refs.shaveEl.removeAttribute('title');
        });
      },
    },
    $trs: {
      viewLessButtonPrompt: 'View less',
    },
  };

</script>


<style lang="scss" scoped>

  .show-more {
    margin-top: 8px;
    text-align: right;
  }

</style>
{'fraction_non_alphanumeric': 0.13047001620745544, 'fraction_numerical': 0.0016207455429497568, 'mean_word_length': 2.028834355828221, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3306073', 'n_tokens_mistral': 1553, 'n_tokens_neox': 1518, 'n_words': 307}