<commit_before><template>

  <CoreFullscreen
    ref="slideshowRenderer"
    class="slideshow-renderer"
    :style="{ height: contentHeight }"
    @changeFullscreen="isInFullscreen = $event"
  >
    <UiIconButton
      class="btn"
      :ariaLabel="isInFullscreen ? $tr('exitFullscreen') : $tr('enterFullscreen')"
      color="primary"
      size="small"
      @click="$refs.slideshowRenderer.toggleFullscreen()"
    >
      <mat-svg v-if="isInFullscreen" name="fullscreen_exit" category="navigation" />
      <mat-svg v-else name="fullscreen" category="navigation" />
    </UiIconButton>
    <Hooper v-if="slides" @slide="handleSlide" @loaded="setHooperListWidth">
      <Slide v-for="slide in slides" :key="slide.id">
        <div
          class="slideshow-slide-image"
          :style="{
            height: `calc(100% - ${captionHeight}px)`
          }"
        >
          <img
            :src="slide.storage_url"
            :aria-labelledby="slideTextId(slide.id)"
          >
        </div>
        <div :id="slideTextId(slide.id)" class="hidden-descriptive-text">
          {{ slide.descriptive_text || slide.caption }}
        </div>
        <div :ref="slide.id" class="caption">
          {{ slide.caption }}
        </div>
      </Slide>
      <HooperNavigation
        slot="hooper-addons"
        :class="{'hooper-navigation-fullscreen' : isInFullscreen}"
      />
      <HooperPagination slot="hooper-addons" />
    </Hooper>
  </CoreFullscreen>

</template>


<script>

  import orderBy from 'lodash/orderBy';

  import themeMixin from 'kolibri.coreVue.mixins.themeMixin';
  import contentRendererMixin from 'kolibri.coreVue.mixins.contentRendererMixin';
  import responsiveElement from 'kolibri.coreVue.mixins.responsiveElement';
  import responsiveWindow from 'kolibri.coreVue.mixins.responsiveWindow';

  import UiIconButton from 'kolibri.coreVue.components.UiIconButton';
  import CoreFullscreen from 'kolibri.coreVue.components.CoreFullscreen';
  import {
    Hooper,
    Slide,
    Navigation as HooperNavigation,
    Pagination as HooperPagination,
  } from 'hooper';
  import { checksumFromFile } from '../utils.js';
  import '../../styles/custom-hooper.css';

  export default {
    name: 'SlideshowRendererComponent',
    components: {
      UiIconButton,
      CoreFullscreen,
      Hooper,
      Slide,
      HooperPagination,
      HooperNavigation,
    },
    mixins: [contentRendererMixin, themeMixin, responsiveElement, responsiveWindow],
    props: {
      defaultFile: {
        type: Object,
        default: () => {},
        validator(file) {
          // File must have a storage_url
          if (file.hasOwnProperty('storage_url')) {
            // Ensure the file is a JSON file because the defaultFile is the manifest.
            return /json$/.test(file.storage_url);
          } else {
            return false;
          }
        },
      },
      files: {
        type: Array,
        default: () => [],
        validator(files) {
          let isValid = true;
          // Ensure we receive a non-empty array.
          if (files.length === 0) {
            return false;
          } else {
            // Check each file to have a storage_url
            files.forEach(file => {
              if (!file.hasOwnProperty('storage_url')) {
                isValid = false;
              }
            });
          }
          return isValid;
        },
      },
    },
    data: () => ({
      isInFullscreen: false,
      manifest: {},
      slides: null,
      currentSlide: null,
    }),
    computed: {
      slideshowImages: function() {
        const files = this.files;
        return files.filter(file => file.preset != 'Slideshow Manifest');
      },
      captionHeight: function() {
        return 30 + (this.currentSlide ? this.$refs[this.currentSlide.id][0].clientHeight : 0);
      },
      contentHeight: function() {
        return window.innerHeight * 0.7 + 'px';
      },
    },
    mounted() {
      /*
        Using the manifest file, get the JSON from the manifest, then
        use the manifest JSON to get all slide images and metadata.
      */
      fetch(this.defaultFile.storage_url, { method: 'GET' })
        .then(response => {
          return response.status === 200 ? response.json() : {};<commit_msg>use constant for comparing presets<commit_after><template>

  <CoreFullscreen
    ref="slideshowRenderer"
    class="slideshow-renderer"
    :style="{ height: contentHeight }"
    @changeFullscreen="isInFullscreen = $event"
  >
    <UiIconButton
      class="btn"
      :ariaLabel="isInFullscreen ? $tr('exitFullscreen') : $tr('enterFullscreen')"
      color="primary"
      size="small"
      @click="$refs.slideshowRenderer.toggleFullscreen()"
    >
      <mat-svg v-if="isInFullscreen" name="fullscreen_exit" category="navigation" />
      <mat-svg v-else name="fullscreen" category="navigation" />
    </UiIconButton>
    <Hooper v-if="slides" @slide="handleSlide" @loaded="setHooperListWidth">
      <Slide v-for="slide in slides" :key="slide.id">
        <div
          class="slideshow-slide-image"
          :style="{
            height: `calc(100% - ${captionHeight}px)`
          }"
        >
          <img
            :src="slide.storage_url"
            :aria-labelledby="slideTextId(slide.id)"
          >
        </div>
        <div :id="slideTextId(slide.id)" class="hidden-descriptive-text">
          {{ slide.descriptive_text || slide.caption }}
        </div>
        <div :ref="slide.id" class="caption">
          {{ slide.caption }}
        </div>
      </Slide>
      <HooperNavigation
        slot="hooper-addons"
        :class="{'hooper-navigation-fullscreen' : isInFullscreen}"
      />
      <HooperPagination slot="hooper-addons" />
    </Hooper>
  </CoreFullscreen>

</template>


<script>

  import orderBy from 'lodash/orderBy';

  import themeMixin from 'kolibri.coreVue.mixins.themeMixin';
  import contentRendererMixin from 'kolibri.coreVue.mixins.contentRendererMixin';
  import responsiveElement from 'kolibri.coreVue.mixins.responsiveElement';
  import responsiveWindow from 'kolibri.coreVue.mixins.responsiveWindow';

  import UiIconButton from 'kolibri.coreVue.components.UiIconButton';
  import CoreFullscreen from 'kolibri.coreVue.components.CoreFullscreen';
  import {
    Hooper,
    Slide,
    Navigation as HooperNavigation,
    Pagination as HooperPagination,
  } from 'hooper';
  import { checksumFromFile } from '../utils.js';
  import '../../styles/custom-hooper.css';

  const presets = {
    slideshow_manifest: 'Slideshow Manifest',
  };

  export default {
    name: 'SlideshowRendererComponent',
    components: {
      UiIconButton,
      CoreFullscreen,
      Hooper,
      Slide,
      HooperPagination,
      HooperNavigation,
    },
    mixins: [contentRendererMixin, themeMixin, responsiveElement, responsiveWindow],
    props: {
      defaultFile: {
        type: Object,
        default: () => {},
        validator(file) {
          // File must have a storage_url
          if (file.hasOwnProperty('storage_url')) {
            // Ensure the file is a JSON file because the defaultFile is the manifest.
            return /json$/.test(file.storage_url);
          } else {
            return false;
          }
        },
      },
      files: {
        type: Array,
        default: () => [],
        validator(files) {
          let isValid = true;
          // Ensure we receive a non-empty array.
          if (files.length === 0) {
            return false;
          } else {
            // Check each file to have a storage_url
            files.forEach(file => {
              if (!file.hasOwnProperty('storage_url')) {
                isValid = false;
              }
            });
          }
          return isValid;
        },
      },
    },
    data: () => ({
      isInFullscreen: false,
      manifest: {},
      slides: null,
      currentSlide: null,
    }),
    computed: {
      slideshowImages: function() {
        const files = this.files;
        return files.filter(file => file.preset != presets.slideshow_manifest);
      },
      captionHeight: function() {
        return 30 + (this.currentSlide ? this.$refs[this.currentSlide.id][0].clientHeight : 0);
      },
      contentHeight: function() {
        return window.innerHeight * 0.7 + 'px';
      },
    },
    mounted() {
      /*
        Using the manifest file, get the JSON from the manifest, then
        use the manifest JSON to get all slide images and metadata.
      */
      fetch(this.defaultFile.storage_url, { method: 'GET' })
        .then(response => {
          return response.status === 200 ? response.json() : {};
{'fraction_non_alphanumeric': 0.1286488981193031, 'fraction_numerical': 0.0029998846198223145, 'mean_word_length': 2.212750185322461, 'pattern_counts': {'":': 0, '<': 47, '<?xml version=': 0, '>': 59, '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': '1568920', 'n_tokens_mistral': 2615, 'n_tokens_neox': 2566, 'n_words': 520}