<commit_before>// TIMELINE Module

// Load templates
const timelineTemplate = require('../templates/playlist-timeline.hbs');

/**
 * Timeline contructor
 * @param {object} container - the container to render the timeline to
 * @param {object =} [options] - Timeline options
 */
let PlaylistTimeline = function(container) {
    this.DOMObject = container;
};

/**
 * Render Timeline and the layout
 * @param {Object} layout - the layout object to be rendered
 */
PlaylistTimeline.prototype.render = function(layout) {

    // Render timeline template
    const html = timelineTemplate(pE.playlist);

    // Append html to the main div
    this.DOMObject.html(html);

    // Enable select for each widget
    this.DOMObject.find('.playlist-widget.selectable:not(.ui-sortable)').click(function(e) {
        e.stopPropagation();
        pE.selectObject($(this));
    });

    this.DOMObject.find('.playlist-widget').droppable({
        greedy: true,
        accept: function(el) {
            return ($(this).hasClass('editable') && $(el).attr('drop-to') === 'widget') ||
                ($(this).hasClass('permissionsModifiable') && $(el).attr('drop-to') === 'all' && $(el).data('subType') === 'permissions');
        },
        drop: function(event, ui) {
            pE.playlist.addElement(event.target, ui.draggable[0]);
        }
    });

    // Handle widget attached audio click
    this.DOMObject.find('.playlist-widget.editable .editProperty').click(function(e) {
        e.stopPropagation();

        const widget = pE.getElementByTypeAndId($(this).parents('.playlist-widget').data('type'), $(this).parents('.playlist-widget').attr('id'), $(this).parents('.playlist-widget').data('widgetRegion'));

        widget.editPropertyForm($(this).data('property'), $(this).data('propertyType'));
    });

    this.DOMObject.find('.playlist-widget').contextmenu(function(ev) {
        
        if($(ev.currentTarget).is('.editable, .deletable, .permissionsModifiable')) {
            // Open context menu
            pE.openContextMenu(ev.currentTarget, {
                x: ev.pageX,
                y: ev.pageY
            });
        }

        // Prevent browser menu to open
        return false;
    });

    // Save order function with debounce
    var saveOrderFunc = _.debounce(function() {
        pE.saveOrder();
        pE.timeline.DOMObject.find('#unsaved').hide();
        pE.timeline.DOMObject.find('#saved').show();
    }, 1000);

    // Sortable widgets
    this.DOMObject.find('#timeline-container').sortable({
        start: function(event, ui) {
            pE.timeline.DOMObject.find('#unsaved').hide();
            saveOrderFunc.cancel();
        },
        stop: function(event, ui) {
            pE.timeline.DOMObject.find('#unsaved').show();<commit_msg>OSX-729 Playlist Editor: Timeline sort Firefox fix<commit_after>// TIMELINE Module

// Load templates
const timelineTemplate = require('../templates/playlist-timeline.hbs');

/**
 * Timeline contructor
 * @param {object} container - the container to render the timeline to
 * @param {object =} [options] - Timeline options
 */
let PlaylistTimeline = function(container) {
    this.DOMObject = container;
};

/**
 * Render Timeline and the layout
 */
PlaylistTimeline.prototype.render = function() {

    // Render timeline template
    const html = timelineTemplate(pE.playlist);

    // Append html to the main div
    this.DOMObject.html(html);

    // Enable select for each widget
    this.DOMObject.find('.playlist-widget.selectable').click(function(e) {
        e.stopPropagation();
        if(!$(this).hasClass('to-be-saved')) {
            pE.selectObject($(this));
        }
    });

    this.DOMObject.find('.playlist-widget').droppable({
        greedy: true,
        accept: function(el) {
            return ($(this).hasClass('editable') && $(el).attr('drop-to') === 'widget') ||
                ($(this).hasClass('permissionsModifiable') && $(el).attr('drop-to') === 'all' && $(el).data('subType') === 'permissions');
        },
        drop: function(event, ui) {
            pE.playlist.addElement(event.target, ui.draggable[0]);
        }
    });

    // Handle widget attached audio click
    this.DOMObject.find('.playlist-widget.editable .editProperty').click(function(e) {
        e.stopPropagation();

        const widget = pE.getElementByTypeAndId($(this).parents('.playlist-widget').data('type'), $(this).parents('.playlist-widget').attr('id'), $(this).parents('.playlist-widget').data('widgetRegion'));

        widget.editPropertyForm($(this).data('property'), $(this).data('propertyType'));
    });

    this.DOMObject.find('.playlist-widget').contextmenu(function(ev) {
        
        if($(ev.currentTarget).is('.editable, .deletable, .permissionsModifiable')) {
            // Open context menu
            pE.openContextMenu(ev.currentTarget, {
                x: ev.pageX,
                y: ev.pageY
            });
        }

        // Prevent browser menu to open
        return false;
    });

    // Save order function with debounce
    var saveOrderFunc = _.debounce(function() {
        pE.saveOrder();
        pE.timeline.DOMObject.find('#unsaved').hide();
        pE.timeline.DOMObject.find('#saved').show();
    }, 1000);

    // Sortable widgets
    this.DOMObject.find('#timeline-container').sortable({
        start: function(event, ui) {
            pE.timeline.DOMObject.find('#unsaved').hide();
            saveOrderFunc.cancel();
        },
        stop: function(event, ui) {
            // Mark target as "to be saved"
            $(ui.item).addClass('to-be-saved');

            pE.timeline.DOMObject.find('#unsaved').show();
{'fraction_non_alphanumeric': 0.1677864214992928, 'fraction_numerical': 0.0022984441301272984, 'mean_word_length': 2.6686121919584953, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, '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': '5315068', 'n_tokens_mistral': 1677, 'n_tokens_neox': 1633, 'n_words': 292}