<commit_before>/* global require, module */
var EmberApp = require('ember-cli/lib/broccoli/ember-app');
var Babel  = require('ember-cli-babel/node_modules/broccoli-babel-transpiler');
var Funnel  = require('ember-cli/node_modules/broccoli-funnel');
var p            = require('ember-cli/node_modules/ember-cli-preprocess-registry/preprocessors');
var mergeTrees    = require('ember-cli/lib/broccoli/merge-trees');

var preprocessTemplates = p.preprocessTemplates;

module.exports = function(defaults) {
  var app = new EmberApp(defaults, {
    // Add options here
  });

  // Use `app.import` to add additional libraries to the generated
  // output files.
  //
  // If you need to use different assets in different
  // environments, specify an object as the first parameter. That
  // object's keys should be the environment name and the values
  // should be the asset to use in that environment.
  //
  // If the library that you are including contains AMD or ES6
  // modules that you would like to import into your application
  // please specify an object with the list of modules as keys
  // along with the exports of each module as its value.

  app.initializeAddons();
  app.name='demo-app';

  var addonAppTrees = app.addonTreesFor('app');
  var mergedApp  = mergeTrees(addonAppTrees.concat(), {
    overwrite: true,
    annotation: 'TreeMerger (app)'
  });

  var appTree = Funnel(mergedApp, {
    srcDir: '/',
    destDir: app.name,
    annotation: 'ProcessedAppTree'
  });

  var addonTrees = app.addonTreesFor('templates');
  var mergedTemplates = mergeTrees(addonTrees, {
    overwrite: true,
    annotation: 'TreeMerger (templates)'
  });

  var addonTemplates = new Funnel(mergedTemplates, {
    srcDir: '/',
    destDir: app.name + '/templates',
    annotation: 'ProcessedTemplateTree'
  });

  var templates = app.addonPreprocessTree('template', addonTemplates);
  var templatesTree = app.addonPostprocessTree('template', preprocessTemplates(templates, {
    registry: app.registry,
    annotation: 'TreeMerger (pod & standard templates)'
  }));

  var addonTrees = mergeTrees(app.addonTreesFor('addon').concat(app.addonTreesFor('vendor')));

  var addonES6 = new Funnel(addonTrees, {
    srcDir: 'modules',
    allowEmpty: true,
    annotation: 'Funnel: Addon JS'
  });

  var addonReexports = new Funnel(addonTrees, {
    srcDir: 'reexports',
    allowEmpty: true,
    annotation: 'Funnel: Addon Re-exports'
  });

  var transpiledTemplatesTree  = new Babel(templatesTree, app._prunedBabelOptions());
  var transpiledAppTree = new Babel(appTree, app._prunedBabelOptions());
  var transpiledAddonTree = new Babel(addonES6, app._prunedBabelOptions());

  var reexportsAndTranspiledAddonTree = mergeTrees([
    transpiledAddonTree,
    transpiledTemplatesTree,
    addonReexports
  ], {
    annotation: 'TreeMerger: (re-exports)'
  });

  var addonVendorJSTree = app.concatFiles(mergeTrees(app.addonTreesFor('vendor')), {
    inputFiles: ['**/*.js'],
  });

  return mergeTrees([
    app.concatFiles(mergeTrees(app.addonTreesFor('styles').concat(addonTrees)), {
      inputFiles: ['**/*.css'],
      outputFile: '/addons.css',
      allowNone: true,
      annotation: 'Concat: Addon CSS'
    }),

    app.concatFiles(mergeTrees([transpiledAppTree, reexportsAndTranspiledAddonTree, addonVendorJSTree]), {
      inputFiles: ['**/*.js'],
      outputFile: '/addons.js',
      allowNone: true,
      annotation: 'Concat: Addon JS'
    })
  ]);

};
<commit_msg>So much hackerage<commit_after>/* global require, module */
var EmberApp = require('ember-cli/lib/broccoli/ember-app');
var Babel  = require('ember-cli-babel/node_modules/broccoli-babel-transpiler');
var Funnel  = require('ember-cli/node_modules/broccoli-funnel');
var p            = require('ember-cli/node_modules/ember-cli-preprocess-registry/preprocessors');
var mergeTrees    = require('ember-cli/lib/broccoli/merge-trees');

var preprocessTemplates = p.preprocessTemplates;

module.exports = function(defaults) {
  var app = new EmberApp(defaults, {
    // Add options here
  });

  // Use `app.import` to add additional libraries to the generated
  // output files.
  //
  // If you need to use different assets in different
  // environments, specify an object as the first parameter. That
  // object's keys should be the environment name and the values
  // should be the asset to use in that environment.
  //
  // If the library that you are including contains AMD or ES6
  // modules that you would like to import into your application
  // please specify an object with the list of modules as keys
  // along with the exports of each module as its value.

  app.initializeAddons();
  app.name='demo-app';

  var addonAppTrees = app.addonTreesFor('app');
  var mergedApp  = mergeTrees(addonAppTrees.concat(), {
    overwrite: true,
    annotation: 'TreeMerger (app)'
  });

  var appTree = Funnel(mergedApp, {
    srcDir: '/',
    destDir: app.name,
    annotation: 'ProcessedAppTree'
  });

  var addonTrees = app.addonTreesFor('templates');
  var mergedTemplates = mergeTrees(addonTrees, {
    overwrite: true,
    annotation: 'TreeMerger (templates)'
  });

  var addonTemplates = new Funnel(mergedTemplates, {
    srcDir: '/',
    destDir: app.name + '/templates',
    annotation: 'ProcessedTemplateTree'
  });

  var templates = app.addonPreprocessTree('template', addonTemplates);
  var templatesTree = app.addonPostprocessTree('template', preprocessTemplates(templates, {
    registry: app.registry,
    annotation: 'TreeMerger (pod & standard templates)'
  }));

  var addonTrees = mergeTrees(app.addonTreesFor('addon').concat(app.addonTreesFor('vendor')));

  var addonES6 = new Funnel(addonTrees, {
    srcDir: 'modules',
    allowEmpty: true,
    annotation: 'Funnel: Addon JS'
  });

  var addonReexports = new Funnel(addonTrees, {
    srcDir: 'reexports',
    allowEmpty: true,
    annotation: 'Funnel: Addon Re-exports'
  });

  var transpiledTemplatesTree  = new Babel(templatesTree, app._prunedBabelOptions());
  var transpiledAppTree = new Babel(appTree, app._prunedBabelOptions());
  var transpiledAddonTree = new Babel(addonES6, app._prunedBabelOptions());

  var reexportsAndTranspiledAddonTree = mergeTrees([
    transpiledAddonTree,
    transpiledTemplatesTree,
    addonReexports
  ], {
    annotation: 'TreeMerger: (re-exports)'
  });

  var bowerTree = new Funnel(app.trees.bower, {
    srcDir: '/',
    destDir: app.bowerDirectory + '/',
    exclude: [
      '**/ember/**'
    ],
    annotation: 'Funnel (bower)'
  });

  var vendorTree = new Funnel(mergeTrees(app.addonTreesFor('vendor')), {
    srcDir: '/',
    destDir: 'vendor/',
    annotation: 'Funnel (vendor)',
    exclude: [
      '**/jquery/**'
    ]
  });

  var addonVendorJSTree = app.concatFiles(mergeTrees([bowerTree, vendorTree]), {
    inputFiles: ['**/*.js'],
    allowNone: true,
    header: ";(function() { ",
    footer: "}());",
    outputFile: '/addons-vendor.js',
  });

  return mergeTrees([
    app.concatFiles(mergeTrees(app.addonTreesFor('styles').concat(addonTrees)), {
      inputFiles: ['**/*.css'],
      outputFile: '/addons.css',
      allowNone: true,
      annotation: 'Concat: Addon CSS'
    }),

    app.concatFiles(mergeTrees([addonVendorJSTree, transpiledAppTree, reexportsAndTranspiledAddonTree]), {
      inputFiles: ['**/*.js'],
      outputFile: '/addons.js',
      allowNone: true,
      annotation: 'Concat: Addon JS'
    })
  ]);

};
<|endoftext|>


<commit_before>/**
 * ---- Advanced Custom Fields Complex Titles ----
 *
 * Create complex, custom styled headlines with per-word or per-phrase styling
 * This code assumes you're using Roots/Sage as your starter theme.
 *
 *  Documentation:
 *  This script assumes you have the following ACF fields set up in the following heierarchy:
 *  -- Title Groups (Repeater field)
 *  -- -- Headline Elements (Repeater field)
 *  -- -- -- Word or Phrase (Text field)
 *  -- -- -- [Additional fields per style you wish to apply to the headline element]
*/

/**
 * Get the closest matching descendents of an element
 * @return object
 */
(function($) {
    $.fn.closest_descendents = function(filter) {
        var $found = $(),
            $currentSet = this.children(); // Current place
        while ($currentSet.length) {
            $found = $currentSet.filter(filter);
            if ($found.length) { break; }  // At least one match: break loop
            // Get all children of the current set
            $currentSet = $currentSet.children();
        }
        return $found; // Return first match of the collection
    };
})(jQuery);

jQuery(document).ready(function($) {

    /**
     * Script configuration
     */

            // Configure the ACF field names you used when setting up fields
            var groups              = "build_title";            // Field id of the groups repeater field
            var groups_layout       = "acfct-layoutfield-alignment";    // Groups layout options must be in an ACF tab. Field id of the layout tab.
            var repeater            = "title";                  // Field id of the repeater field containing headline elements
            var layout              = "title_layout";           // Field id layout select field for the overall headline style
            var word                = "word_or_phrase";         // Field id containing the word to be styled in the preview area
            var draggable           = false;                    // Should elements be draggable, and thus positioned absolutely?

            // Configure HTML to be used in the preview area (this should marginally match the HTML used on the front-end)
            var header_tag                  = "h1";
            var layout_tag                  = "header";
            var layout_class                = "complex-title";
            var preview_area_placeholder    = ".acf-field-acfct-placeholder";   // Class or ID of ACF "Message" field placeholder to be replaced with preview area.
            var preview_area                = "div";
            var preview_area_class          = "acf-complex-titles-preview-area";

            var layout_basename         = "complex-title-layout complex-layout-";

            var group_basename          = "complex-title-group";
            var group_class             = group_basename;

            var class_basename          = "complex-title-element";
            var element_class           = class_basename;

            // Dont change anything below this line
            var preview_element_path    = '.' + preview_area_class + ' ' + header_tag;
            var fields_to_watch         = 'input, select, input[type=checkbox], input[type=radio]';

    /**
     * Update layout classes
     */
    function updateLayout( theClass ) {
        // Remove all the front-end classes so we can re-apply them all correctly
        $('.' + preview_area_class + ' ' + layout_tag).removeClass().addClass( layout_class + ' ' + layout_basename + theClass );
    }

    /**
     * Function to update elements in the preview area when the appropriate title field is changed
     */
    function updateElement(group, $el) {
        $el.each( function() {
            var index       = $el.index();
            var element     = $( preview_element_path + ' [data-group=' + group + ']' + ' span[data-index=' + index + ']');
            var text        = ' ' + $(this).find('[data-name=' + word + ']').find('input').val();

            // Remove all the front-end classes so we can re-apply them all correctly
            $(element).attr('class',
               function(i, c){
                  return c.replace(/(^|\s)complex-title-\S+/g, '');
               });

            // Update the actual text
            $(element).html(text);

            $(this).find(fields_to_watch).each( function() {
                var thisclass       = '';
                var thisvalue       = '';
                var thisstyle       = '';

                if($(this).closest('.acf-field').data('type') === 'true_false') {
                    if($(this).is(':checked')) {
                        thisclass       = $(this).closest('.acf-field').data('name');
                    }
                }
                else if($(this).closest('.acf-field').data('type') === 'select') {
                    thisclass           = $(this).closest('.acf-field').data('name') + '-' + $(this).val();
                }
                else if($(this).closest('.acf-field').data('type') === 'input') {
                    thisvalue           = $(this).closest('.acf-field').data('name');
                    thisstyle           = $(this).val();
                }
                else if($(this).closest('.acf-field').data('type') === 'color_picker') {
                    thisstyle             = $(this).closest('.acf-field').data('name');
                    thisvalue             = $(this).val();
                    if( !thisvalue ) {
                        thisvalue = '';
                    }

                }

                // Apply style or class
                $(element).addClass(class_basename);
                if( thisclass !== word && thisclass.length > 0 ) {
                    //console.log(thisclass);
                    $(element).addClass(class_basename + '-' + thisclass);
                }
                if( thisstyle !== '' ) {
                    $(element).css(thisstyle, thisvalue);
                }
            });
        });
    }

    /**
     * Function to update groups in the preview area when the appropriate title field is changed
     */
    function updateGroup($el) {
        $el.each( function() {
            var index       = $el.index();
            var element     = $( preview_element_path + ' [data-group=' + index + ']');

            // Remove all the front-end classes so we can re-apply them all correctly
            $(element).attr('class',
               function(i, c){
                  return c.replace(/(^|\s)complex-title-\S+/g, '');
               });

            $(this).find('[data-key=' + groups_layout + ']').find(fields_to_watch).each( function() {
                var thisclass       = '';
                var thisvalue       = '';
                var thisstyle       = '';

                if($(this).closest('.acf-field').data('type') === 'true_false') {
                    if($(this).is(':checked')) {
                        thisclass       = $(this).closest('.acf-field').data('name');
                    }
                }
                else if($(this).closest('.acf-field').data('type') === 'select') {
                    thisclass           = $(this).closest('.acf-field').data('name') + '-' + $(this).val();
                }
                else if($(this).closest('.acf-field').data('type') === 'input') {
                    thisvalue           = $(this).closest('.acf-field').data('name');
                    thisstyle           = $(this).val();
                }
                else if($(this).closest('.acf-field').data('type') === 'color_picker') {
                    thisstyle             = $(this).closest('.acf-field').data('name');
                    thisvalue             = $(this).val();
                    if( !thisvalue ) {
                        thisvalue = '';
                    }

                }

                // Apply style or class
                $(element).addClass(group_basename);
                if( thisclass !== word && thisclass.length > 0 ) {
                    //console.log(thisclass);
                    $(element).addClass(group_basename + '-' + thisclass);
                }
                if( thisstyle !== '' ) {
                    $(element).css(thisstyle, thisvalue);
                }
            });
        });
    }

    /**
     * Function to append headline preview
     */
    function appendPreview( $el ) {
        if(! $el.closest('.acf-clone').length ) {
            $el.find('.' + preview_area_class).remove();
            $el.prepend( '<' + preview_area + ' class="' + preview_area_class + '"><' + layout_tag + ' class="' + layout_class + '"><' + header_tag + '></' + header_tag + '></' + layout_tag + '></' + preview_area + '>' );
            $el.find('.acf-label, .acf-input').hide();
            updateLayout( $el.closest('.acf-fields').find('[data-name="' + layout + '"] select').val() );
        }
    }

    /**
     * Function to add elements to the preview area
     */
    function appendElements( group, $el, skipIndex ) {
        index           = parseInt($el.index());
        skipIndex       = parseInt(skipIndex);
        if(index >= 0) {
            // console.log(group);
            // Remove the element if it already exists
            $( preview_element_path + ' [data-group=' + group + ']' + ' [data-index=' + index + ']').remove();
            //Check whether we just removed this element from the repeating field. If we did, then adjust the element index
            if(index !== skipIndex) {
                if(index >= skipIndex) {
                    index = index-1;
                }
                // Then create the element in the preview area
                var element_number          = index;
                var classes                 = element_class + " " + element_class + "-" + element_number;
                //console.log(classes);
                // Add all elements with their current settings.
                $el.each( function() {
                    $( preview_element_path + ' [data-group=' + group + ']').append('');
                    updateElement(group, $(this));
                });

            }
        }
    }

    /**
     * Function to add groups in the preview area
     */
    function appendGroups( $el) {
				index           = parseInt($el.index());
        if(index >= 0) {
        // Remove the element if it already exists
          // Then create the element in the preview area
          var group_number            = index;
          var classes                 = group_basename;
          //console.log(classes);
          // Add all elements with their current settings.
          $el.each( function() {
              $( preview_element_path ).append('');
              updateGroup($el);
              $(this).find('[data-name="' + repeater + '"]').each( function() {
                  $(this).find('.acf-row').each( function( index ) {
                      if(!$(this).hasClass('acf-clone')) {
                          appendElements( group_number, $(this) );
                      }
                  });
              });
          });
        }
    }

    /**
     * Watch for changes to ACF fields fields in repeaters and update the the preview area
     */
    function watchElements() {
        $('[data-name="' + repeater + '"]').on( 'input change', fields_to_watch, function() {
            updateElement( $(this).parents('.acf-row').last().index(), $(this).closest('.acf-row') );
        });
    }

    function watchGroups() {
        $('[data-key="' + groups_layout + '"]').on( 'input change', fields_to_watch, function() {
            updateGroup( $(this).parents('.acf-row').last() );
        });
    }

    /**
     * Watch for changes to the layout fields and update the the preview area
     */
    function watchLayout() {
        $('[data-name="' + layout + '"]').on( 'change', fields_to_watch, function() {
            updateLayout( $(this).val() );
        });
    }

    /**
     * Initialize title groups in preview area
     */
    function groupsInit() {
        $('[data-name="' + groups + '"]').each( function() {
            $(this).closest_descendents('.acf-row').each( function() {
                if(!$(this).hasClass('acf-clone')) {
                    appendGroups( $(this) );
                }
            });
        });
    }

    /**
     * Initialize title elements in preview area
     */
    function headlinesInit() {
        $(preview_area_placeholder).each( function() {
            appendPreview($(this));
        });
        groupsInit();
        watchElements();
        watchGroups();
        watchLayout();
    }

    /**
     * Initialize all groups and elements when the page loads
     */
    headlinesInit();

    /**
     * Update all elements and groups
     */
    function updateAllElements() {
				$( preview_element_path + ' .complex-titles-to-be-removed').remove();
        groupsInit();
    }

    /**
     * Function to remove an element from the preview area when the ACF repeater row is removed
     */
    function removeElements(group, $el) {
        skipIndex = $el.index();
        if(skipIndex >= 0) {
            appendElements( group, $el, skipIndex );
            setTimeout(updateAllElements, 1000);
        }
    }

    /**
     * Function to remove a group from the preview area when the ACF repeater row is removed
     */
    function removeGroups() {
			$( preview_element_path + ' [data-group]').addClass('complex-titles-to-be-removed');
			setTimeout(updateAllElements, 1000);
    }

    /**
     * Listen for the creation of new repeater rows and create new elements in
     * preview area when new rows are added
     */
    if(typeof acf !== 'undefined') {
        acf.add_action('append', function( $el ){
            headlinesInit();
        });
    }

    /**
     * Listen for drag-and-drop events and re-initialize the preview when one
     * occurs.
     */
    if(typeof acf !== 'undefined') {
        acf.add_action('sortstop', function( $el ){
            headlinesInit();
        });
    }

    /**
     * Listen for rows being removed, remove and re-index preview area elements accordingly
     */
    if(typeof acf !== 'undefined') {
        acf.add_action('remove', function( $el ){
            console.log($el);
            var group   = $el.parents('.acf-row').last().index();
            if ( $el.parents('.acf-field-repeater').data('name') == groups) {
                removeGroups();
            } else {
                removeElements(group, $el);
            }
        });
    }

});
<commit_msg>Refactor to remove bolted-on state, use actual current index to address, update, and remove preview elements; when it doubt, repaint entire preview<commit_after>/**
 * ---- Advanced Custom Fields Complex Titles ----
 *
 * Create complex, custom styled headlines with per-word or per-phrase styling
 * This code assumes you're using Roots/Sage as your starter theme.
 *
 *  Documentation:
 *  This script assumes you have the following ACF fields set up in the following heierarchy:
 *  -- Title Groups (Repeater field)
 *  -- -- Headline Elements (Repeater field)
 *  -- -- -- Word or Phrase (Text field)
 *  -- -- -- [Additional fields per style you wish to apply to the headline element]
*/

/**
 * Get the closest matching descendents of an element
 * @return object
 */
(function($) {
    $.fn.closest_descendents = function(filter) {
        var $found = $(),
            $currentSet = this.children(); // Current place
        while ($currentSet.length) {
            $found = $currentSet.filter(filter);
            if ($found.length) { break; }  // At least one match: break loop
            // Get all children of the current set
            $currentSet = $currentSet.children();
        }
        return $found; // Return first match of the collection
    };
})(jQuery);

jQuery(document).ready(function($) {

    /**
     * Script configuration
     */

            // Configure the ACF field names you used when setting up fields
            var groups              = "build_title";            // Field id of the groups repeater field
            var groups_layout       = "acfct-layoutfield-alignment";    // Groups layout options must be in an ACF tab. Field id of the layout tab.
            var repeater            = "title";                  // Field id of the repeater field containing headline elements
            var layout              = "title_layout";           // Field id layout select field for the overall headline style
            var word                = "word_or_phrase";         // Field id containing the word to be styled in the preview area
            var draggable           = false;                    // Should elements be draggable, and thus positioned absolutely?

            // Configure HTML to be used in the preview area (this should marginally match the HTML used on the front-end)
            var header_tag                  = "h1";
            var layout_tag                  = "header";
            var layout_class                = "complex-title";
            var preview_area_placeholder    = ".acf-field-acfct-placeholder";   // Class or ID of ACF "Message" field placeholder to be replaced with preview area.
            var preview_area                = "div";
            var preview_area_class          = "acf-complex-titles-preview-area";

            var layout_basename         = "complex-title-layout complex-layout-";

            var group_basename          = "complex-title-group";
            var group_class             = group_basename;

            var class_basename          = "complex-title-element";
            var element_class           = class_basename;

            // Dont change anything below this line
            var preview_element_path    = '.' + preview_area_class + ' ' + header_tag;
            var fields_to_watch         = 'input, select, input[type=checkbox], input[type=radio]';

    /**
     * Update layout classes
     */
    function updateLayout( theClass ) {
        // Remove all the front-end classes so we can re-apply them all correctly
        $('.' + preview_area_class + ' ' + layout_tag).removeClass().addClass( layout_class + ' ' + layout_basename + theClass );
    }

    /**
     * Function to update elements in the preview area when the appropriate title field is changed
     */
    function updateElement(group, $el) {
        $el.each( function() {
            var index       = parseInt($el.index());
            var element     = $( preview_element_path + ' [data-group]').eq(group).children('[data-index]').eq(index);
            var text        = ' ' + $(this).find('[data-name=' + word + ']').find('input').val();

            // Remove all the front-end classes so we can re-apply them all correctly
            $(element).attr('class',
               function(i, c){
                  return c.replace(/(^|\s)complex-title-\S+/g, '');
               });

            // Update the actual text
            $(element).html(text);

            $(this).find(fields_to_watch).each( function() {
                var thisclass       = '';
                var thisvalue       = '';
                var thisstyle       = '';

                if($(this).closest('.acf-field').data('type') === 'true_false') {
                    if($(this).is(':checked')) {
                        thisclass       = $(this).closest('.acf-field').data('name');
                    }
                }
                else if($(this).closest('.acf-field').data('type') === 'select') {
                    thisclass           = $(this).closest('.acf-field').data('name') + '-' + $(this).val();
                }
                else if($(this).closest('.acf-field').data('type') === 'input') {
                    thisvalue           = $(this).closest('.acf-field').data('name');
                    thisstyle           = $(this).val();
                }
                else if($(this).closest('.acf-field').data('type') === 'color_picker') {
                    thisstyle             = $(this).closest('.acf-field').data('name');
                    thisvalue             = $(this).val();
                    if( !thisvalue ) {
                        thisvalue = '';
                    }

                }

                // Apply style or class
                $(element).addClass(class_basename);
                if( thisclass !== word && thisclass.length > 0 ) {
                    //console.log(thisclass);
                    $(element).addClass(class_basename + '-' + thisclass);
                }
                if( thisstyle !== '' ) {
                    $(element).css(thisstyle, thisvalue);
                }
            });
        });
    }

    /**
     * Function to update groups in the preview area when the appropriate title field is changed
     */
    function updateGroup($el) {
        $el.each( function() {
            var index       = $el.index();
            var element     = $( preview_element_path + ' [data-group=' + index + ']');

            // Remove all the front-end classes so we can re-apply them all correctly
            $(element).attr('class',
               function(i, c){
                  return c.replace(/(^|\s)complex-title-\S+/g, '');
               });

            $(this).find('[data-key=' + groups_layout + ']').find(fields_to_watch).each( function() {
                var thisclass       = '';
                var thisvalue       = '';
                var thisstyle       = '';

                if($(this).closest('.acf-field').data('type') === 'true_false') {
                    if($(this).is(':checked')) {
                        thisclass       = $(this).closest('.acf-field').data('name');
                    }
                }
                else if($(this).closest('.acf-field').data('type') === 'select') {
                    thisclass           = $(this).closest('.acf-field').data('name') + '-' + $(this).val();
                }
                else if($(this).closest('.acf-field').data('type') === 'input') {
                    thisvalue           = $(this).closest('.acf-field').data('name');
                    thisstyle           = $(this).val();
                }
                else if($(this).closest('.acf-field').data('type') === 'color_picker') {
                    thisstyle             = $(this).closest('.acf-field').data('name');
                    thisvalue             = $(this).val();
                    if( !thisvalue ) {
                        thisvalue = '';
                    }

                }

                // Apply style or class
                $(element).addClass(group_basename);
                if( thisclass !== word && thisclass.length > 0 ) {
                    //console.log(thisclass);
                    $(element).addClass(group_basename + '-' + thisclass);
                }
                if( thisstyle !== '' ) {
                    $(element).css(thisstyle, thisvalue);
                }
            });
        });
    }

    /**
     * Function to append headline preview
     */
    function appendPreview( $el ) {
        if(! $el.closest('.acf-clone').length ) {
            $el.find('.' + preview_area_class).remove();
            $el.prepend( '<' + preview_area + ' class="' + preview_area_class + '"><' + layout_tag + ' class="' + layout_class + '"><' + header_tag + '></' + header_tag + '></' + layout_tag + '></' + preview_area + '>' );
            $el.find('.acf-label, .acf-input').hide();
            updateLayout( $el.closest('.acf-fields').find('[data-name="' + layout + '"] select').val() );
        }
    }

    /**
     * Function to add elements to the preview area
     */
    function appendElement( group, $el ) {
        index  = parseInt($el.index());
        if(index >= 0) {

					var classes = element_class + " " + element_class + "-" + index;

            // Add all elements with their current settings.
            $el.each( function() {
                $( preview_element_path + ' [data-group]').eq(group).append('');
                updateElement(group, $(this));
            });
        }
    }

    /**
     * Function to add groups in the preview area
     */
    function appendGroups( $el) {
				index           = parseInt($el.index());
        if(index >= 0) {
        // Remove the element if it already exists
          // Then create the element in the preview area
          var group = index;
          var classes = group_basename;
          //console.log(classes);
          // Add all elements with their current settings.
          $el.each( function() {
              $( preview_element_path ).append('');
              updateGroup($el);
              $(this).find('[data-name="' + repeater + '"]').each( function() {
                  $(this).find('.acf-row').each( function( index ) {
                      if(!$(this).hasClass('acf-clone')) {
                          appendElement( group, $(this) );
                      }
                  });
              });
          });
        }
    }

    /**
     * Watch for changes to ACF fields fields in repeaters and update the the preview area
     */
    function watchElements() {
        $('[data-name="' + repeater + '"]').on( 'input change', fields_to_watch, function() {
					groupsInit();
        });
    }

    function watchGroups() {
        $('[data-key="' + groups_layout + '"]').on( 'input change', fields_to_watch, function() {
					groupsInit();
        });
    }

    /**
     * Watch for changes to the layout fields and update the the preview area
     */
    function watchLayout() {
        $('[data-name="' + layout + '"]').on( 'change', fields_to_watch, function() {
            updateLayout( $(this).val() );
        });
    }

    /**
     * Initialize title groups in preview area
     */
    function groupsInit() {
        $('[data-name="' + groups + '"]').each( function() {
            $(this).closest_descendents('.acf-row').each( function() {
                if(!$(this).hasClass('acf-clone')) {
                    appendGroups( $(this) );
                }
            });
        });
    }

    /**
     * Initialize title elements in preview area
     */
    function headlinesInit() {
        $(preview_area_placeholder).each( function() {
            appendPreview($(this));
        });
        groupsInit();
        watchElements();
        watchGroups();
        watchLayout();
    }

    /**
     * Initialize all groups and elements when the page loads
     */
    headlinesInit();

    /**
     * Function to remove an element from the preview area when the ACF repeater row is removed
     */
    function removeElement(group, remove) {
			$( preview_element_path + ' [data-group]').eq(group).children().eq(remove).remove();
    }

    /**
     * Function to remove a group from the preview area when the ACF repeater row is removed
     */
    function removeGroup(remove) {
			// Remove preview group with the index of the row just removed.
			$( preview_element_path + ' [data-group]').eq(remove).remove();
    }

    /**
     * Listen for the creation of new repeater rows and create new elements in
     * preview area when new rows are added
     */
    if(typeof acf !== 'undefined') {
        acf.add_action('append', function( $el ){
            headlinesInit();
        });
    }

    /**
     * Listen for drag-and-drop events and re-initialize the preview when one
     * occurs.
     */
    if(typeof acf !== 'undefined') {
        acf.add_action('sortstop', function( $el ){
            headlinesInit();
        });
    }

    /**
     * Listen for rows being removed, remove and re-index preview area elements accordingly
     */
    if(typeof acf !== 'undefined') {
        acf.add_action('remove', function( $el ){

						// Get the index of the row removed
            var remove   = $el.index();

						// If the removed immediate repeater parent is NOT the
						// groups repeater, get the parent repeater's index so we can
						// be sure to remove the right element from the right group
						if($el.closest('.acf-field-repeater').data('name') != groups) {
							var group = $el.parents('.acf-row').index();
						}
            if ($el.closest('.acf-field-repeater').data('name') == groups) {
                // If the row was a title group, remove the whole row
								removeGroup(group);
            } else {
                removeElement(group, remove);
            }
        });
    }

});
<|endoftext|>


<commit_before>'use strict';
/**
 * 文章相关
 */

const model = require('../model');
const url = require('url');
const utils = require('../utils');
let Article = model.Article;
let ArticleSort = model.ArticleSort;
let Sort = model.Sort;

/**
 * 直接 url.parse(ctx.request.url, true).query;
 * 结果是 { page: '1', size: '10', name: '顺' }
 * 1.支持中文
 * 2.由于是通过url传递参数，因此参数全是字符。使用时需要强转
 * @param ctx
 * @param next
 */
var fn_article_list_get = async(ctx, next) => {
    let params = url.parse(ctx.request.url, true).query;
    let currentPage = params.page * 1 || 1;
    if (currentPage <= 0) {
        currentPage = 1;
    }
    let pageSize = params.size * 1 || 10;
    if (pageSize <= 0) {
        pageSize = 10;
    }
    let type = params.type || '0';
    let articleList;
    /**
     * 多取出一个，方便判断是否还有更多。
     */
    if (type === '0') {
        articleList = await Article.findAll({
            limit: pageSize + 1,
            offset: (currentPage - 1) * pageSize,
            order: [['updatedAt', 'DESC']],
            attributes: ['id', 'title', 'des', 'userId']
        });
    } else {
        articleList = await ArticleSort.findAll({
            limit: pageSize + 1,
            offset: (currentPage - 1) * pageSize,
            where: {
                sortId: type
            },
            attributes: ['sortId'],
            include: {
                model: Article,
                order: [['updatedAt', 'DESC']],
                attributes: ['id', 'title', 'des', 'userId']
            }
        });
        let articleListTemp = [];
        for (let i = 0; i < articleList.length; i++) {
            let temp = {};
            temp.title = articleList[i].article.title;
            temp.des = articleList[i].article.des;
            temp.userId = articleList[i].article.userId;
            articleListTemp[i] = temp;
        }
        articleList = articleListTemp;
    }
    if (articleList.length < pageSize + 1) {
        ctx.rest(articleList, false);
    } else {
        ctx.rest(articleList.slice(0, pageSize), true);
    }
};

var fn_article_get = async(ctx, next) => {
    let params = url.parse(ctx.request.url, true).query;
    var article = await Article.findOne({
        where: {
            id: params.id || '0'
        }
    });
    console.log(params.id);
    ctx.rest(article);
};

var fn_article_post = async(ctx, next) => {
    let article = {};
    article.title = ctx.request.body.title || '';
    article.des = ctx.request.body.des || '';
    article.content = ctx.request.body.content || '';
    article.userId = ctx.request.body.userId || 1;
    var sorts = ctx.request.body.articleType || [0];
    let result = await Article.create({
        title: article.title,
        des: article.des,
        content: article.content,
        userId: article.userId
    });
    if (typeof sorts === "string") {
        sorts = utils.strToArray(sorts);
    }
    for (let sort in sorts) {
        ArticleSort.create({
            articleId: result.id,
            sortId: parseInt(sort, 0)
        });
    }
    ctx.rest(result);
};

var fn_article_put = async(ctx, next) => {
    let article = {};
    article.id = ctx.request.body.id || '';
    article.title = ctx.request.body.title || '';
    article.des = ctx.request.body.des || '';
    article.content = ctx.request.body.content || '';
    article.userId = ctx.request.body.userId || 1;
    let sorts = ctx.request.body.articleType || [0];
    await Article.update(
        {
            title: article.title,
            des: article.des,
            content: article.content,
            updatedAt: Date.now()
        },
        {
            where: {id: article.id}
        }
    );
    await ArticleSort.destroy(
        {where: {articleId: article.id}}
    );
    if (typeof sorts === "string") {
        sorts = utils.strToArray(sorts);
    }
    for (let sort in sorts) {
        ArticleSort.create({
            articleId: article.id,
            sortId: parseInt(sort, 0)
        });
    }
    ctx.rest(article);
};

var fn_sort_get = async(ctx, next) => {
    var result = await Sort.findAll({
        attributes: ['id', 'name']
    });
    ctx.rest(result);
};

module.exports = {
    'GET /api/list': fn_article_list_get,
    'GET /api/article': fn_article_get,
    'GET /api/sort': fn_sort_get,
    'POST /api/article': fn_article_post,
    'PUT /api/article': fn_article_put
};<commit_msg>update coed<commit_after>'use strict';
/**
 * 文章相关
 */

const model = require('../model');
const url = require('url');
const utils = require('../utils');
let Article = model.Article;
let ArticleSort = model.ArticleSort;
let Sort = model.Sort;

/**
 * 直接 url.parse(ctx.request.url, true).query;
 * 结果是 { page: '1', size: '10', name: '顺' }
 * 1.支持中文
 * 2.由于是通过url传递参数，因此参数全是字符。使用时需要强转
 * @param ctx
 * @param next
 */
var fn_article_list_get = async(ctx, next) => {
    let params = url.parse(ctx.request.url, true).query;
    let currentPage = params.page * 1 || 1;
    if (currentPage <= 0) {
        currentPage = 1;
    }
    let pageSize = params.size * 1 || 10;
    if (pageSize <= 0) {
        pageSize = 10;
    }
    let type = params.type || '0';
    let articleList;
    /**
     * 多取出一个，方便判断是否还有更多。
     */
    if (type === '0') {
        articleList = await Article.findAll({
            limit: pageSize + 1,
            offset: (currentPage - 1) * pageSize,
            order: [['updatedAt', 'DESC']],
            attributes: ['id', 'title', 'des', 'userId']
        });
    } else {
        articleList = await ArticleSort.findAll({
            limit: pageSize + 1,
            offset: (currentPage - 1) * pageSize,
            where: {
                sortId: type
            },
            attributes: ['sortId'],
            include: {
                model: Article,
                order: [['updatedAt', 'DESC']],
                attributes: ['id', 'title', 'des', 'userId']
            }
        });
        let articleListTemp = [];
        for (let i = 0; i < articleList.length; i++) {
            let temp = {};
            temp.id = articleList[i].article.id;
            temp.title = articleList[i].article.title;
            temp.des = articleList[i].article.des;
            temp.userId = articleList[i].article.userId;
            articleListTemp[i] = temp;
        }
        articleList = articleListTemp;
    }
    if (articleList.length < pageSize + 1) {
        ctx.rest(articleList, false);
    } else {
        ctx.rest(articleList.slice(0, pageSize), true);
    }
};

var fn_article_get = async(ctx, next) => {
    let params = url.parse(ctx.request.url, true).query;
    var article = await Article.findOne({
        where: {
            id: params.id || '0'
        }
    });
    console.log(params.id);
    ctx.rest(article);
};

var fn_article_post = async(ctx, next) => {
    let article = {};
    article.title = ctx.request.body.title || '';
    article.des = ctx.request.body.des || '';
    article.content = ctx.request.body.content || '';
    article.userId = ctx.request.body.userId || 1;
    var sorts = ctx.request.body.articleType || [0];
    let result = await Article.create({
        title: article.title,
        des: article.des,
        content: article.content,
        userId: article.userId
    });
    if (typeof sorts === "string") {
        sorts = utils.strToArray(sorts);
    }
    for (let sort in sorts) {
        ArticleSort.create({
            articleId: result.id,
            sortId: parseInt(sort, 0)
        });
    }
    ctx.rest(result);
};

var fn_article_put = async(ctx, next) => {
    let article = {};
    article.id = ctx.request.body.id || '';
    article.title = ctx.request.body.title || '';
    article.des = ctx.request.body.des || '';
    article.content = ctx.request.body.content || '';
    article.userId = ctx.request.body.userId || 1;
    let sorts = ctx.request.body.articleType || [0];
    await Article.update(
        {
            title: article.title,
            des: article.des,
            content: article.content,
            updatedAt: Date.now()
        },
        {
            where: {id: article.id}
        }
    );
    await ArticleSort.destroy(
        {where: {articleId: article.id}}
    );
    if (typeof sorts === "string") {
        sorts = utils.strToArray(sorts);
    }
    for (let sort in sorts) {
        ArticleSort.create({
            articleId: article.id,
            sortId: parseInt(sort, 0)
        });
    }
    ctx.rest(article);
};

var fn_sort_get = async(ctx, next) => {
    var result = await Sort.findAll({
        attributes: ['id', 'name']
    });
    ctx.rest(result);
};

module.exports = {
    'GET /api/list': fn_article_list_get,
    'GET /api/article': fn_article_get,
    'GET /api/sort': fn_sort_get,
    'POST /api/article': fn_article_post,
    'PUT /api/article': fn_article_put
};<|endoftext|>


<commit_before>/**
 Copyright (c) 2008-2010 Ricardo Quesada
 Copyright (c) 2011-2012 cocos2d-x.org
 Copyright (c) 2013-2014 Chukong Technologies Inc.
 Copyright (c) 2008, Luke Benstead.
 All rights reserved.

 Redistribution and use in source and binary forms, with or without modification,
 are permitted provided that the following conditions are met:

 Redistributions of source code must retain the above copyright notice,
 this list of conditions and the following disclaimer.
 Redistributions in binary form must reproduce the above copyright notice,
 this list of conditions and the following disclaimer in the documentation
 and/or other materials provided with the distribution.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

(function(cc) {
    cc.math.Vec4 = function (x, y, z, w) {
        if (x && y === undefined) {
            this.x = x.x;
            this.y = x.y;
            this.z = x.z;
            this.w = x.w;
        } else {
            this.x = x || 0;
            this.y = y || 0;
            this.z = z || 0;
            this.w = w || 0;
        }
    };
    cc.kmVec4 = cc.math.Vec4;
    var proto = cc.math.Vec4.prototype;

    proto.fill = function (x, y, z, w) {     //=cc.kmVec4Fill
        if (x && y === undefined) {
            this.x = x.x;
            this.y = x.y;
            this.z = x.z;
            this.w = x.w;
        } else {
            this.x = x;
            this.y = y;
            this.z = z;
            this.w = w;
        }
    };

    proto.add = function(vec) {    //cc.kmVec4Add
        if(!vec)
            return this;
        this.x += vec.x;
        this.y += vec.y;
        this.z += vec.z;
        this.w += vec.w;
        return this;
    };

    proto.dot = function(vec){           //cc.kmVec4Dot
        return ( this.x * vec.x + this.y * vec.y + this.z * vec.z + this.w * vec.w );
    };

    proto.length = function(){    //=cc.kmVec4Length
        return Math.sqrt(cc.math.square(this.x) + cc.math.square(this.y) + cc.math.square(this.z) + cc.math.square(this.w));
    };

    proto.lengthSq = function(){     //=cc.kmVec4LengthSq
        return cc.math.square(this.x) + cc.math.square(this.y) + cc.math.square(this.z) + cc.math.square(this.w);
    };

    proto.lerp = function(vec, t){    //= cc.kmVec4Lerp
        //not implemented
        return this;
    };

    proto.normalize = function() {   // cc.kmVec4Normalize
        var l = 1.0 / this.length();
        this.x *= l;
        this.y *= l;
        this.z *= l;
        this.w *= l;
        return this;
    };

    proto.scale = function(scale){  //= cc.kmVec4Scale
        /// Scales a vector to the required length. This performs a Normalize before multiplying by S.
        this.normalize();
        this.x *= scale;
        this.y *= scale;
        this.z *= scale;
        this.w *= scale;
        return this;
    };

    proto.subtract = function(vec) {
        this.x -= vec.x;
        this.y -= vec.y;
        this.z -= vec.z;
        this.w -= vec.w;
    };

    proto.transform = function(mat4) {
        var x = this.x, y = this.y, z = this.z, w = this.w, mat = mat4.mat;
        this.x = x * mat[0] + y * mat[4] + z * mat[8] + w * mat[12];
        this.y = x * mat[1] + y * mat[5] + z * mat[9] + w * mat[13];
        this.z = x * mat[2] + y * mat[6] + z * mat[10] + w * mat[14];
        this.w = x * mat[3] + y * mat[7] + z * mat[11] + w * mat[15];
        return this;
    };

    cc.math.Vec4.transformArray = function(vecArray, mat4){
        var retArray = [];
        for (var i = 0; i < vecArray.length; i++) {
            var selVec = new cc.math.Vec4(vecArray[i]);
            selVec.transform(mat4);
            retArray.push(selVec);
        }
        return retArray;
    };

    proto.equals = function(vec){              //=cc.kmVec4AreEqual
       var EPSILON = cc.math.EPSILON;
        return (this.x < vec.x + EPSILON && this.x > vec.x - EPSILON) &&
            (this.y < vec.y + EPSILON && this.y > vec.y - EPSILON) &&
            (this.z < vec.z + EPSILON && this.z > vec.z - EPSILON) &&
            (this.w < vec.w + EPSILON && this.w > vec.w - EPSILON);
    };

    proto.assignFrom = function(vec) {      //= cc.kmVec4Assign
        this.x = vec.x;
        this.y = vec.y;
        this.z = vec.z;
        this.w = vec.w;
        return this;
    };

    proto.toTypeArray = function(){      //cc.kmVec4ToTypeArray
        var tyArr = new Float32Array(4);
        tyArr[0] = this.x;
        tyArr[1] = this.y;
        tyArr[2] = this.z;
        tyArr[3] = this.w;
        return tyArr;
    };
})(cc);

<commit_msg>cleanup<commit_after><|endoftext|>


<commit_before>/**
 * Created by Andrew on 9/12/2015.
 */
var playlist = {

    scanPaths: '',
    scanningActive: false,
    scanFilters: '',
    size: 0,
    activePlaylistName: '',
    activePlaylistID: -1,
    activeTr: null,
    bind: function() {
        $('#dropdown').on('show', function(event, dropdownData) {
            playlist.activeTr = $(dropdownData.trigger).closest("tr");
        }).on('hide', function(event, dropdownData) {
            playlist.activeTr = null;
        });
        $('#createPlaylistButton').click(function(e) {
            var idClicked = e.target.id;
            playlist.createPlaylist();
        });
        $('#deletPlaylistButton').click(function(e) {
            if (typeof deletePlaylist == 'function') {
                var $switchPageSpeed = 100;
                var index = playlist.activePlaylistID;
                deletePlaylist(index);

                $('#playlist-' + index).remove();
                $('#playlistAddTo-' + index).remove();
                window.activeViewPort = "collection";
                $('#discover').fadeOut($switchPageSpeed);
                $('#playlist').fadeOut($switchPageSpeed);
                $('#nav-discover').removeClass('active');
                $('.playlist-study a').removeClass('active');
                $(this).addClass('active');
                $('#collection').fadeIn($switchPageSpeed);

            }
        });
        $('#addToCollection').click(function(e) {
            var url = $(playlist.activeTr).data("value");
            var songName = $(playlist.activeTr).data("songName");
            var artistName = $(playlist.activeTr).data("artistName");
            downloader.downloadSong(songName, artistName, url);
        });
        $('#renamePlaylistButton').click(function(e) {
            var id = playlist.activePlaylistID;
            var playListName = $('#inputRenamePlaylist').val();
                if (typeof renamePlaylist == 'function') {
                    renamePlaylist(playListName, id);
                    playListName.activePlaylistName = playListName;
                    $('#activePlaylistTitle').text(playListName);
                    $('#inputRenamePlaylist').val(playListName);
                    $('.modalPlaylistName').text(playListName);
                    $( "#playlist-" + id ).find( "span" ).text(playListName);
                }
        });

    },
    formatPlaylistTime: function(a, c, e) {
        d = 60;
        s = [" seconds", " mins", " hrs"];
        return (t = [a, (0 | a / d) * d, (0 | a / d / d) * d * d].map(function(a, b, f) {
            p = (a - (0 | f[b + 1])) / Math.pow(d, b);
            return e && 1 > b ? "" : c && !p ? "" : p + s[b] + ". "
        }).reverse().join(""))

    },
    populatePlaylist: function(data) {
        var decoded = atob(data);
        var jsonData = JSON.parse(decoded);
        var playlistSize = jsonData.results.length;
        var totalTime = playlist.formatPlaylistTime(jsonData.totalTime);
        $('#playlistInfo').text(playlistSize + " songs in playlist, " + totalTime);
        for (var k = 0; k < 4; k++) {
            aurousScript("#playlistCover" + k).attr("src", "assets/img/noalbumart.png");
        }

        var t = $('#playlistResult').DataTable();
        t.clear().draw();
        for (var i = 0; i < jsonData.results.length; i++) {
            var obj = jsonData.results[i];
            var songId = obj.id;
            var title = obj.title;
            var artist = obj.artist;
            var album = obj.album;
            var albumArt = obj.albumArt;
            var rawDuration = obj.duration;
            var duration = aurousScript.player.toTime(rawDuration);
            var link = obj.link;
            artist = utils.replaceAll(decodeURIComponent(artist), "+", " ");
            title = utils.replaceAll(decodeURIComponent(title), "+", " ");
            album = utils.replaceAll(decodeURIComponent(album), "+", " ");
            link = utils.decodeHtml(link);
            playlist.appendPlaylistRow(songId, albumArt, duration, album, title, artist, link);

            if (i < 4) {
                aurousScript("#playlistCover" + i).attr("src", albumArt);
            }

        }
    },
    appendPlaylistRow: function(songId, albumArt, duration, album, title, artist, link) {
        link = utils.decodeHtml(link);
        var id = songId;
        var t = $('#playlistResult').DataTable();

        t.row.add([
            '<button class="btn btn-transparent control-show">add</button> <button class="btn btn-transparent">play_arrow<\/i><\/a></button>'.format(id),
            title,
            artist,
            album,
            duration
        ]).index();

        t.row(id - 1).draw();

        aurousScript("#playlist-row-icon-" + id).closest('td').addClass("result-control");
        var parent = aurousScript("#playlist-row-icon-" + id).closest('tr');
        parent.attr('playlist-data-id', id);
        parent.attr('playlist-data-value', link);
        parent.attr('playlist-data-album-art', albumArt);
        parent.attr('playlist-data-song-name', title);
        parent.attr('playlist-data-artist-name', artist);
        playlist.bindRow(id, title, artist, albumArt, link);
    },
    bindRow: function(id, title, artist, albumArt, link) {

        aurousScript("#playlist-row-icon-" + id).on("click", function() {
            if (window.previousPlaylist !== undefined) {
                window.previousPlaylist.removeClass("result-now-playing");
                aurousScript("#playlist-row-icon-" + window.previousPlaylistId).html("play_arrow");
            }
            var parent = aurousScript(this).closest('tr');
            parent.addClass("result-now-playing");
            var id = parent.attr('playlist-data-id');
            window.currentPlaylistId = id;
            aurousScript("#playlist-row-icon-" + id).html("pause");

            var url = parent.attr('playlist-data-value');
            aurousScript.player.changeMedia(title, artist, albumArt, url);
            aurousScript("#playerPause").show();
            aurousScript("#playerPlay").hide();
            window.previousPlaylist = parent;
            window.previousPlaylistId = id;

        });
    },
    createPlaylist: function() {
        var playListName = $('#inputAddPlaylist').val();
        if (!utils.isEmpty(playListName)) {
            if (typeof createLocalPlaylist == 'function') {
                createLocalPlaylist(playListName);
                var index = playlist.size + 1;
                var html = '
play_arrow{0}
'.format(playListName, index);
                $('#playlistContainer').append(html);
                var item = '
{0}
'.format(playListName, index);
                $("#appendPlaylist").after(item);
                playlist.bindPlaylist(playListName, index);

            }
        }
    },
    bindPlaylist: function(name, index) {

        $("#playlistAddTo-" + index).click(function(event) {
            var songId = playlist.activeTr.attr("collection-data-id");
            if (typeof addSongToPlaylist == 'function') {

                if (window.activeViewPort == "search") {
                    var url = playlist.activeTr.data("value");
                    var artist = playlist.activeTr.data("artist-name");
                    var songName = playlist.activeTr.data("song-name");
                    downloader.downloadToPlaylist(songName, artist, url,index);
                } else if (window.activeViewPort == "artist") {
                    songId = playlist.activeTr.attr("artist-data-id");
                    addSongToPlaylist(songId, index);
                } else if (window.activeViewPort == "album") {
                    songId = playlist.activeTr.attr("album-data-id");
                    addSongToPlaylist(songId, index);
                } else {
                    addSongToPlaylist(songId, index);
                }
            }
        });

        $('#playlist-' + index).click(function(event) {
            var $switchPageSpeed = 100;
            $('#discover').fadeOut($switchPageSpeed);
            $('#collection').fadeOut($switchPageSpeed);
            $('#nav-discover').removeClass('active');
            $('#nav-collection').removeClass('active');
            $(this).find('a').addClass('active');
            $('#playlist').fadeIn($switchPageSpeed);
            $('#activePlaylistTitle').text(name);
            $("#playlist-" + index).find("i").text("pause");
            $("#playlist-" + playlist.activePlaylistID).find("i").text("play_arrow");
            playlist.activePlaylistName = name;
            playlist.activePlaylistID = index;

            $('#inputRenamePlaylist').val(name);

            $('.modalPlaylistName').text(name);

            if (typeof loadSongsInPlaylist == 'function') {
                loadSongsInPlaylist(index);
            }
            window.activeViewPort = "playlist";
            event.preventDefault();
        });
    },
    loadLocalPlaylist: function(data) {
        $('#playlistContainer').html('

chevron_right
PLAYLIST
');
        var decoded = atob(data);
        var jsonData = JSON.parse(decoded);
        for (var i = 0; i < jsonData.results.length; i++) {

            var obj = jsonData.results[i];
            var name = obj.name;
            var id = obj.id;
            playlist.size = id;
            name = utils.replaceAll(decodeURIComponent(name), "+", " ");
            var html = '
play_arrow{0}
'.format(name, id);
            $('#playlistContainer').append(html);
            var item = '
{0}
'.format(name, id);
            $("#appendPlaylist").after(item);
            playlist.bindPlaylist(name, id);
        }
    },
    addToPlaylist: function() {

    },
    completeScanning: function() {
        mediaScanner.scanningActive = false;
        alertify.success("Media Scanned from Disk");
    }
};
<commit_msg>Playlist name input cleared after playlist created.<commit_after>/**
 * Created by Andrew on 9/12/2015.
 */
var playlist = {

    scanPaths: '',
    scanningActive: false,
    scanFilters: '',
    size: 0,
    activePlaylistName: '',
    activePlaylistID: -1,
    activeTr: null,
    bind: function() {
        $('#dropdown').on('show', function(event, dropdownData) {
            playlist.activeTr = $(dropdownData.trigger).closest("tr");
        }).on('hide', function(event, dropdownData) {
            playlist.activeTr = null;
        });
        $('#createPlaylistButton').click(function(e) {
            var idClicked = e.target.id;
            playlist.createPlaylist();
        });
        $('#deletPlaylistButton').click(function(e) {
            if (typeof deletePlaylist == 'function') {
                var $switchPageSpeed = 100;
                var index = playlist.activePlaylistID;
                deletePlaylist(index);

                $('#playlist-' + index).remove();
                $('#playlistAddTo-' + index).remove();
                window.activeViewPort = "collection";
                $('#discover').fadeOut($switchPageSpeed);
                $('#playlist').fadeOut($switchPageSpeed);
                $('#nav-discover').removeClass('active');
                $('.playlist-study a').removeClass('active');
                $(this).addClass('active');
                $('#collection').fadeIn($switchPageSpeed);

            }
        });
        $('#addToCollection').click(function(e) {
            var url = $(playlist.activeTr).data("value");
            var songName = $(playlist.activeTr).data("songName");
            var artistName = $(playlist.activeTr).data("artistName");
            downloader.downloadSong(songName, artistName, url);
        });
        $('#renamePlaylistButton').click(function(e) {
            var id = playlist.activePlaylistID;
            var playListName = $('#inputRenamePlaylist').val();
                if (typeof renamePlaylist == 'function') {
                    renamePlaylist(playListName, id);
                    playListName.activePlaylistName = playListName;
                    $('#activePlaylistTitle').text(playListName);
                    $('#inputRenamePlaylist').val(playListName);
                    $('.modalPlaylistName').text(playListName);
                    $( "#playlist-" + id ).find( "span" ).text(playListName);
                }
        });

    },
    formatPlaylistTime: function(a, c, e) {
        d = 60;
        s = [" seconds", " mins", " hrs"];
        return (t = [a, (0 | a / d) * d, (0 | a / d / d) * d * d].map(function(a, b, f) {
            p = (a - (0 | f[b + 1])) / Math.pow(d, b);
            return e && 1 > b ? "" : c && !p ? "" : p + s[b] + ". "
        }).reverse().join(""))

    },
    populatePlaylist: function(data) {
        var decoded = atob(data);
        var jsonData = JSON.parse(decoded);
        var playlistSize = jsonData.results.length;
        var totalTime = playlist.formatPlaylistTime(jsonData.totalTime);
        $('#playlistInfo').text(playlistSize + " songs in playlist, " + totalTime);
        for (var k = 0; k < 4; k++) {
            aurousScript("#playlistCover" + k).attr("src", "assets/img/noalbumart.png");
        }

        var t = $('#playlistResult').DataTable();
        t.clear().draw();
        for (var i = 0; i < jsonData.results.length; i++) {
            var obj = jsonData.results[i];
            var songId = obj.id;
            var title = obj.title;
            var artist = obj.artist;
            var album = obj.album;
            var albumArt = obj.albumArt;
            var rawDuration = obj.duration;
            var duration = aurousScript.player.toTime(rawDuration);
            var link = obj.link;
            artist = utils.replaceAll(decodeURIComponent(artist), "+", " ");
            title = utils.replaceAll(decodeURIComponent(title), "+", " ");
            album = utils.replaceAll(decodeURIComponent(album), "+", " ");
            link = utils.decodeHtml(link);
            playlist.appendPlaylistRow(songId, albumArt, duration, album, title, artist, link);

            if (i < 4) {
                aurousScript("#playlistCover" + i).attr("src", albumArt);
            }

        }
    },
    appendPlaylistRow: function(songId, albumArt, duration, album, title, artist, link) {
        link = utils.decodeHtml(link);
        var id = songId;
        var t = $('#playlistResult').DataTable();

        t.row.add([
            '<button class="btn btn-transparent control-show">add</button> <button class="btn btn-transparent">play_arrow<\/i><\/a></button>'.format(id),
            title,
            artist,
            album,
            duration
        ]).index();

        t.row(id - 1).draw();

        aurousScript("#playlist-row-icon-" + id).closest('td').addClass("result-control");
        var parent = aurousScript("#playlist-row-icon-" + id).closest('tr');
        parent.attr('playlist-data-id', id);
        parent.attr('playlist-data-value', link);
        parent.attr('playlist-data-album-art', albumArt);
        parent.attr('playlist-data-song-name', title);
        parent.attr('playlist-data-artist-name', artist);
        playlist.bindRow(id, title, artist, albumArt, link);
    },
    bindRow: function(id, title, artist, albumArt, link) {

        aurousScript("#playlist-row-icon-" + id).on("click", function() {
            if (window.previousPlaylist !== undefined) {
                window.previousPlaylist.removeClass("result-now-playing");
                aurousScript("#playlist-row-icon-" + window.previousPlaylistId).html("play_arrow");
            }
            var parent = aurousScript(this).closest('tr');
            parent.addClass("result-now-playing");
            var id = parent.attr('playlist-data-id');
            window.currentPlaylistId = id;
            aurousScript("#playlist-row-icon-" + id).html("pause");

            var url = parent.attr('playlist-data-value');
            aurousScript.player.changeMedia(title, artist, albumArt, url);
            aurousScript("#playerPause").show();
            aurousScript("#playerPlay").hide();
            window.previousPlaylist = parent;
            window.previousPlaylistId = id;

        });
    },
    createPlaylist: function() {
        var input = $('#inputAddPlaylist');
        var playListName = input.val();
        if (!utils.isEmpty(playListName)) {
            if (typeof createLocalPlaylist == 'function') {
                createLocalPlaylist(playListName);
                var index = playlist.size + 1;
                var html = '
play_arrow{0}
'.format(playListName, index);
                $('#playlistContainer').append(html);
                var item = '
{0}
'.format(playListName, index);
                $("#appendPlaylist").after(item);
                playlist.bindPlaylist(playListName, index);
            }
        }
		input.val("");
    },
    bindPlaylist: function(name, index) {

        $("#playlistAddTo-" + index).click(function(event) {
            var songId = playlist.activeTr.attr("collection-data-id");
            if (typeof addSongToPlaylist == 'function') {

                if (window.activeViewPort == "search") {
                    var url = playlist.activeTr.data("value");
                    var artist = playlist.activeTr.data("artist-name");
                    var songName = playlist.activeTr.data("song-name");
                    downloader.downloadToPlaylist(songName, artist, url,index);
                } else if (window.activeViewPort == "artist") {
                    songId = playlist.activeTr.attr("artist-data-id");
                    addSongToPlaylist(songId, index);
                } else if (window.activeViewPort == "album") {
                    songId = playlist.activeTr.attr("album-data-id");
                    addSongToPlaylist(songId, index);
                } else {
                    addSongToPlaylist(songId, index);
                }
            }
        });

        $('#playlist-' + index).click(function(event) {
            var $switchPageSpeed = 100;
            $('#discover').fadeOut($switchPageSpeed);
            $('#collection').fadeOut($switchPageSpeed);
            $('#nav-discover').removeClass('active');
            $('#nav-collection').removeClass('active');
            $(this).find('a').addClass('active');
            $('#playlist').fadeIn($switchPageSpeed);
            $('#activePlaylistTitle').text(name);
            $("#playlist-" + index).find("i").text("pause");
            $("#playlist-" + playlist.activePlaylistID).find("i").text("play_arrow");
            playlist.activePlaylistName = name;
            playlist.activePlaylistID = index;

            $('#inputRenamePlaylist').val(name);

            $('.modalPlaylistName').text(name);

            if (typeof loadSongsInPlaylist == 'function') {
                loadSongsInPlaylist(index);
            }
            window.activeViewPort = "playlist";
            event.preventDefault();
        });
    },
    loadLocalPlaylist: function(data) {
        $('#playlistContainer').html('

chevron_right
PLAYLIST
');
        var decoded = atob(data);
        var jsonData = JSON.parse(decoded);
        for (var i = 0; i < jsonData.results.length; i++) {

            var obj = jsonData.results[i];
            var name = obj.name;
            var id = obj.id;
            playlist.size = id;
            name = utils.replaceAll(decodeURIComponent(name), "+", " ");
            var html = '
play_arrow{0}
'.format(name, id);
            $('#playlistContainer').append(html);
            var item = '
{0}
'.format(name, id);
            $("#appendPlaylist").after(item);
            playlist.bindPlaylist(name, id);
        }
    },
    addToPlaylist: function() {

    },
    completeScanning: function() {
        mediaScanner.scanningActive = false;
        alertify.success("Media Scanned from Disk");
    }
};
<|endoftext|>


<commit_before>import axios from "@agir/lib/utils/axios";
import React, {
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
} from "react";
import { useHistory, useLocation } from "react-router-dom";
import styled from "styled-components";
import useSWR from "swr";

import style from "@agir/front/genericComponents/_variables.scss";

import { validateData } from "./eventForm.config";
import { routeConfig } from "@agir/front/app/routes.config";

import Button from "@agir/front/genericComponents/Button";
import Spacer from "@agir/front/genericComponents/Spacer";

import NameField from "./NameField";
import OrganizerGroupField from "./OrganizerGroupField";
import DateField from "./DateField";
import ForUsersField from "./ForUsersField";
import SubtypeField from "./SubtypeField";
import LocationField from "./LocationField";
import ContactField from "./ContactField";
import OnlineUrlField from "./OnlineUrlField";

const StyledGlobalError = styled.p`
  padding: 0 0 1rem;
  margin: 0;
  font-size: 1rem;
  text-align: center;
  color: ${style.redNSP};
`;
const StyledForm = styled.form`
  padding-bottom: 3rem;

  fieldset {
    margin: 0;
    padding: 0;

    legend {
      font-size: 1rem;
      line-height: 1.5;
      font-weight: 400;
      margin: 0;
      padding-bottom: 1.5rem;

      strong {
        display: block;
        font-size: 1.5rem;
        line-height: 1.6;
        font-weight: 500;
      }

      em {
        text-decoration: underline;
        font-style: normal;
      }
    }
  }

  & > ${Button} {
    display: block;
    margin: 0;
    width: 100%;
    justify-content: center;
  }

  & > ${Button} + p {
    padding: 1rem 0;
    font-size: 0.813rem;
    text-align: center;
  }
`;
import { DEFAULT_FORM_DATA } from "./eventForm.config";

const formatErrors = (errors, fields = DEFAULT_FORM_DATA) => {
  if (typeof errors !== "object") {
    return errors;
  }
  return Object.entries(errors).reduce(
    (errors, [field, error]) => ({
      ...errors,
      [typeof fields[field] !== "undefined" ? field : "global"]: Array.isArray(
        error
      )
        ? error[0]
        : formatErrors(error, fields[field]),
    }),
    {}
  );
};

const createEvent = async (data) => {
  const result = {
    data: null,
    errors: null,
  };
  const url = "/api/evenements/creer/";
  const body = {
    ...data,
    subtype: data.subtype && data.subtype.id,
    organizerGroup: data.organizerGroup && data.organizerGroup.id,
  };

  try {
    const response = await axios.post(url, body);
    result.data = response.data;
  } catch (e) {
    result.errors = (e.response && e.response.data) || { global: e.message };
  }

  if (result.errors && typeof result.errors === "object") {
    result.errors = formatErrors(result.errors);
  }

  return result;
};

const useEventFormOptions = () => {
  const { data: eventOptions } = useSWR(`/api/evenements/options/`);

  const organizerGroup = useMemo(() => {
    if (eventOptions && Array.isArray(eventOptions.organizerGroup)) {
      return [
        ...eventOptions.organizerGroup.map((group) => ({
          ...group,
          label: group.name,
          value: group.id,
        })),
        {
          id: null,
          value: null,
          label: "À titre individuel",
          contact: eventOptions.defaultContact,
        },
      ];
    }
  }, [eventOptions]);

  return eventOptions
    ? {
        ...eventOptions,
        organizerGroup,
      }
    : {};
};

const EventForm = () => {
  const [formData, setFormData] = useState(DEFAULT_FORM_DATA);
  const [errors, setErrors] = useState({});
  const [isLoading, setIsLoading] = useState(false);
  const [newEventPk, setNewEventPk] = useState(null);

  const history = useHistory();
  const { search } = useLocation();
  const options = useEventFormOptions();

  const nameRef = useRef(null);
  const organizerGroupRef = useRef(null);
  const dateRef = useRef(null);
  const forUsersRef = useRef(null);
  const subtypeRef = useRef(null);
  const onlineUrlRef = useRef(null);
  const locationRef = useRef(null);
  const contactRef = useRef(null);

  const updateValue = useCallback((name, value) => {
    setErrors((state) => ({
      ...state,
      [name]: undefined,
    }));
    setFormData((state) => ({
      ...state,
      [name]: value,
    }));
  }, []);

  const updateNestedValue = useCallback((parentName, name, value) => {
    setErrors((state) => {
      if (!state[parentName] || !state[parentName][name]) {
        return state;
      }
      const newState = { ...state };
      if (Object.keys(newState[parentName]).length > 1) {
        newState[parentName] = { ...newState[parentName] };
        delete newState[parentName][name];
      } else {
        newState[parentName] = undefined;
      }
      return newState;
    });
    setFormData((state) => ({
      ...state,
      [parentName]: {
        ...(state[parentName] || {}),
        [name]: value,
        isDefault: false,
      },
    }));
  }, []);

  const updateDate = useCallback((startTime, endTime) => {
    setErrors((state) => ({
      ...state,
      startTime: undefined,
      endTime: undefined,
    }));
    setFormData((state) => ({
      ...state,
      startTime,
      endTime,
    }));
  }, []);

  useEffect(() => {
    if (formData.contact.isDefault && formData.organizerGroup) {
      const contact = formData.organizerGroup.contact
        ? Object.keys(DEFAULT_FORM_DATA.contact).reduce(
            (result, key) => ({
              ...result,
              [key]:
                formData.organizerGroup.contact[key] ||
                DEFAULT_FORM_DATA.contact[key],
            }),
            {}
          )
        : DEFAULT_FORM_DATA.contact;
      setErrors((state) => ({
        ...state,
        contact: undefined,
      }));
      setFormData((state) => ({
        ...state,
        contact,
      }));
    }

    if (formData.location.isDefault && formData.organizerGroup) {
      const location = formData.organizerGroup.location
        ? Object.keys(DEFAULT_FORM_DATA.location).reduce(
            (result, key) => ({
              ...result,
              [key]:
                formData.organizerGroup.location[key] ||
                DEFAULT_FORM_DATA.location[key],
            }),
            {}
          )
        : DEFAULT_FORM_DATA.location;
      setErrors((state) => ({
        ...state,
        location: undefined,
      }));
      setFormData((state) => ({
        ...state,
        location,
      }));
    }
  }, [
    formData.location.isDefault,
    formData.contact.isDefault,
    formData.organizerGroup,
  ]);
  const scrollToError = useCallback((errors) => {
    if (
      typeof window === "undefined" ||
      !errors ||
      Object.values(errors).filter(Boolean).length === 0
    ) {
      return;
    }
    let scrollTarget = null;
    switch (true) {
      case !!(errors["name"] && nameRef.current):
        scrollTarget = nameRef.current;
        break;
      case !!(errors["organizerGroup"] && organizerGroupRef.current):
        scrollTarget = organizerGroupRef.current;
        break;
      case !!((errors["startTime"] || errors["endTime"]) && dateRef.current):
        scrollTarget = dateRef.current;
        break;
      case !!(errors["forUsers"] && forUsersRef.current):
        scrollTarget = forUsersRef.current;
        break;
      case !!(errors["subtype"] && subtypeRef.current):
        scrollTarget = subtypeRef.current;
        break;
      case !!(errors["onlineUrl"] && onlineUrlRef.current):
        scrollTarget = onlineUrlRef.current;
        break;
      case !!(errors["location"] && locationRef.current):
        scrollTarget = locationRef.current;
        break;
      case !!(errors["contact"] && contactRef.current):
        scrollTarget = contactRef.current;
        break;
    }
    if (scrollTarget) {
      window.scrollTo({
        top: scrollTarget.offsetTop - 100,
      });
    }
  }, []);

  const handleSubmit = useCallback(
    async (e) => {
      e.preventDefault();
      setErrors({});
      const errors = validateData(formData);
      if (errors) {
        setErrors(errors);
        scrollToError(errors);
        return;
      }
      setIsLoading(true);
      const result = await createEvent(formData);
      setIsLoading(false);
      if (result.errors) {
        setErrors(result.errors);
        scrollToError(result.errors);
        return;
      }
      if (!result.data || !result.data.id) {
        setErrors({ global: "Une erreur est survenue" });
        return;
      }
      setNewEventPk(result.data.id);
    },
    [formData, scrollToError]
  );

  useEffect(() => {
    if (newEventPk) {
      const route = routeConfig.eventDetails.getLink({ eventPk: newEventPk });
      history.push(route);
    }
  }, [history, newEventPk]);

  useEffect(() => {
    if (!search) {
      return;
    }
    const params = new URLSearchParams(search);
    if (
      !formData.organizerGroup &&
      params.get("group") &&
      options.organizerGroup
    ) {
      const organizerGroup = options.organizerGroup.find(
        (g) => g.id === params.get("group")
      );
      organizerGroup &&
        setFormData((state) => ({
          ...state,
          organizerGroup,
        }));
    }
    if (!formData.subtype && params.get("subtype") && options.subtype) {
      const subtype = options.subtype.find(
        (g) => g.label === params.get("subtype")
      );
      subtype &&
        setFormData((state) => ({
          ...state,
          subtype,
        }));
    }
  }, [search, options, formData]);

  useEffect(() => {
    if (
      options &&
      options.organizerGroup &&
      options.organizerGroup.length === 1 &&
      !formData.organizerGroup
    ) {
      setFormData((state) => ({
        ...state,
        organizerGroup: options.organizerGroup[0],
      }));
    }
  }, [options, formData]);

  return (

      )}
      <Button disabled={isLoading} type="submit" color="secondary" block>
        Créer l'événement
      </Button>

        Vous pourrez modifier ces informations après la création de l’événement.

    </StyledForm>
  );
};
export default EventForm;
<commit_msg>styles: move onlineUrlField in top of location<commit_after>import axios from "@agir/lib/utils/axios";
import React, {
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
} from "react";
import { useHistory, useLocation } from "react-router-dom";
import styled from "styled-components";
import useSWR from "swr";

import style from "@agir/front/genericComponents/_variables.scss";

import { validateData } from "./eventForm.config";
import { routeConfig } from "@agir/front/app/routes.config";

import Button from "@agir/front/genericComponents/Button";
import Spacer from "@agir/front/genericComponents/Spacer";

import NameField from "./NameField";
import OrganizerGroupField from "./OrganizerGroupField";
import DateField from "./DateField";
import ForUsersField from "./ForUsersField";
import SubtypeField from "./SubtypeField";
import LocationField from "./LocationField";
import ContactField from "./ContactField";
import OnlineUrlField from "./OnlineUrlField";

const StyledGlobalError = styled.p`
  padding: 0 0 1rem;
  margin: 0;
  font-size: 1rem;
  text-align: center;
  color: ${style.redNSP};
`;
const StyledForm = styled.form`
  padding-bottom: 3rem;

  fieldset {
    margin: 0;
    padding: 0;

    legend {
      font-size: 1rem;
      line-height: 1.5;
      font-weight: 400;
      margin: 0;
      padding-bottom: 1.5rem;

      strong {
        display: block;
        font-size: 1.5rem;
        line-height: 1.6;
        font-weight: 500;
      }

      em {
        text-decoration: underline;
        font-style: normal;
      }
    }
  }

  & > ${Button} {
    display: block;
    margin: 0;
    width: 100%;
    justify-content: center;
  }

  & > ${Button} + p {
    padding: 1rem 0;
    font-size: 0.813rem;
    text-align: center;
  }
`;
import { DEFAULT_FORM_DATA } from "./eventForm.config";

const formatErrors = (errors, fields = DEFAULT_FORM_DATA) => {
  if (typeof errors !== "object") {
    return errors;
  }
  return Object.entries(errors).reduce(
    (errors, [field, error]) => ({
      ...errors,
      [typeof fields[field] !== "undefined" ? field : "global"]: Array.isArray(
        error
      )
        ? error[0]
        : formatErrors(error, fields[field]),
    }),
    {}
  );
};

const createEvent = async (data) => {
  const result = {
    data: null,
    errors: null,
  };
  const url = "/api/evenements/creer/";
  const body = {
    ...data,
    subtype: data.subtype && data.subtype.id,
    organizerGroup: data.organizerGroup && data.organizerGroup.id,
  };

  try {
    const response = await axios.post(url, body);
    result.data = response.data;
  } catch (e) {
    result.errors = (e.response && e.response.data) || { global: e.message };
  }

  if (result.errors && typeof result.errors === "object") {
    result.errors = formatErrors(result.errors);
  }

  return result;
};

const useEventFormOptions = () => {
  const { data: eventOptions } = useSWR(`/api/evenements/options/`);

  const organizerGroup = useMemo(() => {
    if (eventOptions && Array.isArray(eventOptions.organizerGroup)) {
      return [
        ...eventOptions.organizerGroup.map((group) => ({
          ...group,
          label: group.name,
          value: group.id,
        })),
        {
          id: null,
          value: null,
          label: "À titre individuel",
          contact: eventOptions.defaultContact,
        },
      ];
    }
  }, [eventOptions]);

  return eventOptions
    ? {
        ...eventOptions,
        organizerGroup,
      }
    : {};
};

const EventForm = () => {
  const [formData, setFormData] = useState(DEFAULT_FORM_DATA);
  const [errors, setErrors] = useState({});
  const [isLoading, setIsLoading] = useState(false);
  const [newEventPk, setNewEventPk] = useState(null);

  const history = useHistory();
  const { search } = useLocation();
  const options = useEventFormOptions();

  const nameRef = useRef(null);
  const organizerGroupRef = useRef(null);
  const dateRef = useRef(null);
  const forUsersRef = useRef(null);
  const subtypeRef = useRef(null);
  const onlineUrlRef = useRef(null);
  const locationRef = useRef(null);
  const contactRef = useRef(null);

  const updateValue = useCallback((name, value) => {
    setErrors((state) => ({
      ...state,
      [name]: undefined,
    }));
    setFormData((state) => ({
      ...state,
      [name]: value,
    }));
  }, []);

  const updateNestedValue = useCallback((parentName, name, value) => {
    setErrors((state) => {
      if (!state[parentName] || !state[parentName][name]) {
        return state;
      }
      const newState = { ...state };
      if (Object.keys(newState[parentName]).length > 1) {
        newState[parentName] = { ...newState[parentName] };
        delete newState[parentName][name];
      } else {
        newState[parentName] = undefined;
      }
      return newState;
    });
    setFormData((state) => ({
      ...state,
      [parentName]: {
        ...(state[parentName] || {}),
        [name]: value,
        isDefault: false,
      },
    }));
  }, []);

  const updateDate = useCallback((startTime, endTime) => {
    setErrors((state) => ({
      ...state,
      startTime: undefined,
      endTime: undefined,
    }));
    setFormData((state) => ({
      ...state,
      startTime,
      endTime,
    }));
  }, []);

  useEffect(() => {
    if (formData.contact.isDefault && formData.organizerGroup) {
      const contact = formData.organizerGroup.contact
        ? Object.keys(DEFAULT_FORM_DATA.contact).reduce(
            (result, key) => ({
              ...result,
              [key]:
                formData.organizerGroup.contact[key] ||
                DEFAULT_FORM_DATA.contact[key],
            }),
            {}
          )
        : DEFAULT_FORM_DATA.contact;
      setErrors((state) => ({
        ...state,
        contact: undefined,
      }));
      setFormData((state) => ({
        ...state,
        contact,
      }));
    }

    if (formData.location.isDefault && formData.organizerGroup) {
      const location = formData.organizerGroup.location
        ? Object.keys(DEFAULT_FORM_DATA.location).reduce(
            (result, key) => ({
              ...result,
              [key]:
                formData.organizerGroup.location[key] ||
                DEFAULT_FORM_DATA.location[key],
            }),
            {}
          )
        : DEFAULT_FORM_DATA.location;
      setErrors((state) => ({
        ...state,
        location: undefined,
      }));
      setFormData((state) => ({
        ...state,
        location,
      }));
    }
  }, [
    formData.location.isDefault,
    formData.contact.isDefault,
    formData.organizerGroup,
  ]);
  const scrollToError = useCallback((errors) => {
    if (
      typeof window === "undefined" ||
      !errors ||
      Object.values(errors).filter(Boolean).length === 0
    ) {
      return;
    }
    let scrollTarget = null;
    switch (true) {
      case !!(errors["name"] && nameRef.current):
        scrollTarget = nameRef.current;
        break;
      case !!(errors["organizerGroup"] && organizerGroupRef.current):
        scrollTarget = organizerGroupRef.current;
        break;
      case !!((errors["startTime"] || errors["endTime"]) && dateRef.current):
        scrollTarget = dateRef.current;
        break;
      case !!(errors["forUsers"] && forUsersRef.current):
        scrollTarget = forUsersRef.current;
        break;
      case !!(errors["subtype"] && subtypeRef.current):
        scrollTarget = subtypeRef.current;
        break;
      case !!(errors["onlineUrl"] && onlineUrlRef.current):
        scrollTarget = onlineUrlRef.current;
        break;
      case !!(errors["location"] && locationRef.current):
        scrollTarget = locationRef.current;
        break;
      case !!(errors["contact"] && contactRef.current):
        scrollTarget = contactRef.current;
        break;
    }
    if (scrollTarget) {
      window.scrollTo({
        top: scrollTarget.offsetTop - 100,
      });
    }
  }, []);

  const handleSubmit = useCallback(
    async (e) => {
      e.preventDefault();
      setErrors({});
      const errors = validateData(formData);
      if (errors) {
        setErrors(errors);
        scrollToError(errors);
        return;
      }
      setIsLoading(true);
      const result = await createEvent(formData);
      setIsLoading(false);
      if (result.errors) {
        setErrors(result.errors);
        scrollToError(result.errors);
        return;
      }
      if (!result.data || !result.data.id) {
        setErrors({ global: "Une erreur est survenue" });
        return;
      }
      setNewEventPk(result.data.id);
    },
    [formData, scrollToError]
  );

  useEffect(() => {
    if (newEventPk) {
      const route = routeConfig.eventDetails.getLink({ eventPk: newEventPk });
      history.push(route);
    }
  }, [history, newEventPk]);

  useEffect(() => {
    if (!search) {
      return;
    }
    const params = new URLSearchParams(search);
    if (
      !formData.organizerGroup &&
      params.get("group") &&
      options.organizerGroup
    ) {
      const organizerGroup = options.organizerGroup.find(
        (g) => g.id === params.get("group")
      );
      organizerGroup &&
        setFormData((state) => ({
          ...state,
          organizerGroup,
        }));
    }
    if (!formData.subtype && params.get("subtype") && options.subtype) {
      const subtype = options.subtype.find(
        (g) => g.label === params.get("subtype")
      );
      subtype &&
        setFormData((state) => ({
          ...state,
          subtype,
        }));
    }
  }, [search, options, formData]);

  useEffect(() => {
    if (
      options &&
      options.organizerGroup &&
      options.organizerGroup.length === 1 &&
      !formData.organizerGroup
    ) {
      setFormData((state) => ({
        ...state,
        organizerGroup: options.organizerGroup[0],
      }));
    }
  }, [options, formData]);

  return (

      )}
      <Button disabled={isLoading} type="submit" color="secondary" block>
        Créer l'événement
      </Button>

        Vous pourrez modifier ces informations après la création de l’événement.

    </StyledForm>
  );
};
export default EventForm;
<|endoftext|>