<commit_before>/* global _ */

import 'owl.carousel';
import * as ctrl from '../controllers';
import {waitForImagesToLoad, waitForAudioAndVideoToLoadMetadata} from 'core/helpers/waitForMediaToBeReady';


const carouselContainerSelector = '.sd-media-carousel__content';

/**
 * @ngdoc directive
 * @module superdesk.apps.authoring
 * @name sdItemCarousel
 *
 * @requires $timeout
 */
ItemCarouselDirective.$inject = ['$timeout'];
export function ItemCarouselDirective($timeout) {
    return {
        scope: {
            items: '=',
            item: '=',
            tabindex: '<',
            editable: '<',
            allowPicture: '<',
            allowVideo: '<',
            allowAudio: '<',
            save: '&',
            onchange: '&',
            maxUploads: '=',
        },
        transclude: true,
        templateUrl: 'scripts/apps/authoring/views/item-carousel.html',
        controller: ctrl.AssociationController,
        controllerAs: 'associations',
        link: function(scope, elem, attr, ctrl) {
            let carousel;
            let previousItemsString;

            /*
             * Initialize carousel after all content is loaded
             * otherwise carousel height is messed up
             */
            scope.$watch('items', (items) => {
                const itemsString = angular.toJson(items);

                // Don't execute if there are no items or they are the same as before
                if (!items || previousItemsString === itemsString) {
                    return false;
                }

                previousItemsString = itemsString;

                let field = _.find(items, (item) => !item[item.fieldId]);

                scope.rel = field ? field.fieldId : null;

                scope.carouselItems = _.sortBy(_.filter(items, (item) => item[item.fieldId]),
                    [(item) => item[item.fieldId].order]);

                scope.$applyAsync(() => {
                    // waiting for angular to render items

                    if (carousel) {
                        carousel.trigger('destroy.owl.carousel');
                    }

                    const carouselImages = Array.from(elem.get(0).querySelectorAll(`${carouselContainerSelector} img`));
                    const carouselAudiosAndVideos = Array.from(
                        elem.get(0).querySelectorAll(
                            `${carouselContainerSelector} video, ${carouselContainerSelector} audio`
                        )
                    );

                    if (items.length < 1 || (carouselImages.length + carouselAudiosAndVideos.length < 1)) {
                        return;
                    }

                    Promise.all([
                        waitForImagesToLoad(carouselImages),
                        waitForAudioAndVideoToLoadMetadata(carouselAudiosAndVideos),
                    ]).then(initCarousel);
                });
            });

            /*
             * Initialize carousel navigation
             */
            scope.navNext = () => carousel.trigger('next.owl.carousel');
            scope.navPrev = () => carousel.trigger('prev.owl.carousel');

            /*
             * Function for triggering thumbnail navigation
             */
            scope.goTo = (index) => {
                scope.crtIndex = index;
                carousel.trigger('to.owl.carousel', [index]);
            };
<commit_msg>fixed:media gallery -> when the last item is swiped the gallery disappears leaving only the arrows (SDESK-3658)<commit_after>/* global _ */

import 'owl.carousel';
import * as ctrl from '../controllers';
import {waitForImagesToLoad, waitForAudioAndVideoToLoadMetadata} from 'core/helpers/waitForMediaToBeReady';


const carouselContainerSelector = '.sd-media-carousel__content';

/**
 * @ngdoc directive
 * @module superdesk.apps.authoring
 * @name sdItemCarousel
 *
 * @requires $timeout
 */
ItemCarouselDirective.$inject = ['$timeout'];
export function ItemCarouselDirective($timeout) {
    return {
        scope: {
            items: '=',
            item: '=',
            tabindex: '<',
            editable: '<',
            allowPicture: '<',
            allowVideo: '<',
            allowAudio: '<',
            save: '&',
            onchange: '&',
            maxUploads: '=',
        },
        transclude: true,
        templateUrl: 'scripts/apps/authoring/views/item-carousel.html',
        controller: ctrl.AssociationController,
        controllerAs: 'associations',
        link: function(scope, elem, attr, ctrl) {
            let carousel;
            let previousItemsString;


            /*
             * Initialize carousel after all content is loaded
             * otherwise carousel height is messed up
             */
            scope.$watch('items', (items) => {
                const itemsString = angular.toJson(items);

                // Don't execute if there are no items or they are the same as before
                if (!items || previousItemsString === itemsString) {
                    return false;
                }

                scope.navCounter = 1;
                previousItemsString = itemsString;

                let field = _.find(items, (item) => !item[item.fieldId]);

                scope.rel = field ? field.fieldId : null;

                scope.carouselItems = _.sortBy(_.filter(items, (item) => item[item.fieldId]),
                    [(item) => item[item.fieldId].order]);


                scope.$applyAsync(() => {
                    // waiting for angular to render items

                    if (carousel) {
                        carousel.trigger('destroy.owl.carousel');
                    }

                    const carouselImages = Array.from(elem.get(0).querySelectorAll(`${carouselContainerSelector} img`));
                    const carouselAudiosAndVideos = Array.from(
                        elem.get(0).querySelectorAll(
                            `${carouselContainerSelector} video, ${carouselContainerSelector} audio`
                        )
                    );

                    if (items.length < 1 || (carouselImages.length + carouselAudiosAndVideos.length < 1)) {
                        return;
                    }

                    Promise.all([
                        waitForImagesToLoad(carouselImages),
                        waitForAudioAndVideoToLoadMetadata(carouselAudiosAndVideos),
                    ]).then(initCarousel);
                });
            });
            /*
             * Initialize carousel navigation
             */
            scope.navNext = () => {
                if (scope.navCounter < scope.carouselItems.length) {
                    carousel.trigger('next.owl.carousel');
                    scope.navCounter++;
                }
            };

            scope.navPrev = () => {
                if (scope.navCounter > 1) {
                    carousel.trigger('prev.owl.carousel');
                    scope.navCounter--;
                }
            };

            /*
             * Function for triggering thumbnail navigation
             */
            scope.goTo = (index) => {
                scope.crtIndex = index;
                scope.navCounter = index + 1;
                carousel.trigger('to.owl.carousel', [index]);
            };

{'fraction_non_alphanumeric': 0.11147585829571878, 'fraction_numerical': 0.002051702913418137, 'mean_word_length': 1.472776462631045, 'pattern_counts': {'":': 0, '<': 18, '<?xml version=': 0, '>': 21, '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': '5396734', 'n_tokens_mistral': 1877, 'n_tokens_neox': 1738, 'n_words': 358}