<commit_before>apos.define('apostrophe-modal', {

  extend: 'apostrophe-context',

  afterConstruct: function(self) {

    apos.ui.globalBusy(true);

    return async.series([
      self.getSource,
      function(callback) {
        self.saving = false;
        self.enableGlobalEventsOnce();
        self.enableLifecycleEvents();
        self.overrideFormSubmission();
        self.captureTitle();
        self.captureControls();
        self.captureInstructions();
        self.resetEl();
        self.setSelfReference();
        self.enableButtonEvents();
        self.enableBreadcrumbEvents();
        return setImmediate(callback);
      },
      self.beforeShow
    ], function(err) {
      apos.ui.globalBusy(false);
      if (err && self.$el) {
        self.hide();
      }
      if (err) {
        apos.log(err);
        return;
      }
      self.show();
      self.afterShow();
    });
  },

  construct: function(self, options) {

    if (options.$view) {
      self.$view = options.$view;
    }

    self.body = options.body;
    self.$body = $('body');

    self.getSource = function(callback) {
      return self.html(options.source, self.body || {}, function(html) {
        self.$el = $(html);
        return callback(null);
      }, function(err) {
        return callback(err);
      });
    };

    self.enableGlobalEventsOnce = function() {
      if (!apos.modalSupport.initialized) {
        apos.modalSupport.initialized = true;
        // Just ONE event handler for the escape key so we don't have
        // modals falling all over themselves to hide each other
        // consecutively.

        // Escape key should dismiss the top modal, if any

        $(document).on({
          'keydown.aposModal': function(e) {
            if (e.keyCode === 27) {
              apos.modalSupport.cancelTopModal();
              return false;
            }
          },
          'click.aposModal': function(e) {
            if (e.target.className === 'apos-modal-blackout') {
              apos.modalSupport.cancelTopModal();
              return false;
            }
          }
        });
      }
    };

    self.disableGlobalEvents = function() {
      // Leggo of the keyboard when there are no modals!
      // We can reinstall the handler when it's relevant.
      // Fewer event handlers all the time = better performance

      apos.modalSupport.initialized = false;
      $(document).off('keydown.aposModal');
      $(document).off('click.aposModal');
    };

    self.enableButtonEvents = function() {
      self.$controls.on('click', '[data-cancel]', function() {
        return self.cancel();
      });

      self.$controls.on('click', '[data-save]', function() {
        var $button = $(this);
        self.save(function(err) {
          if (err) {
            return;
          }
          if ($button.is('[data-next]')) {
            // Up to you to implement this by setting
            // this nonexistent method in your subclass. Should
            // create another instance of [whatever]
            self.next();
          }
        });
        return false;
      });
    };

    self.enableBreadcrumbEvents = function() {
      self.$el.on('click', '[data-modal-breadcrumb]:first .apos-modal-breadcrumb-item', function() {
        var $item = $(this);
        var index = $item.data('aposBreadcrumbIndex');
        var slides = self.getSlides();
        var cancels = slides.length - index - 1;
        cancelUntilCurrent(null);
        function cancelUntilCurrent(err) {
          if (err) {
            // The user decided not to cancel at some level
            return;
          }
          if (!cancels) {
            return;
          }
          cancels--;
          self.getLastSlide().cancel(cancelUntilCurrent);
        }
      });
    };

    self.captureTitle = function() {
      self.title = self.$el.find('[data-modal-title]:first').text();
    };

    self.captureControls = function() {
      self.$controls = self.$el.find('[data-modal-controls]:first');
    };

    self.captureInstructions = function() {
      self.$instructions = self.$el.find('[data-modal-instructions]:first');
    };

    // If we are planning to slide, then we need to reset self.$el to
    // the data-modal-content element because it will be moved out
    // of self.$el and event handlers counting on self.$el would
    // no longer work. -<NAME>

    self.resetEl = function() {
      if (self.options.transition !== 'slide') {
        return;
      }

      if (!self.getSlideableAncestorEl()) {
        return;
      }

      self.$shell = self.$el;
      var $content = self.$el.find('[data-modal-content]:first');<commit_msg>when entering a title for new pages or new pieces, the slug field auto populates to a slugified version of the title entered by the user<commit_after>apos.define('apostrophe-modal', {

  extend: 'apostrophe-context',

  afterConstruct: function(self) {

    apos.ui.globalBusy(true);

    return async.series([
      self.getSource,
      function(callback) {
        self.saving = false;
        self.enableGlobalEventsOnce();
        self.enableLifecycleEvents();
        self.overrideFormSubmission();
        self.captureTitle();
        self.captureControls();
        self.captureInstructions();
        self.resetEl();
        self.setSelfReference();
        self.enableButtonEvents();
        self.enableBreadcrumbEvents();
        return setImmediate(callback);
      },
      self.beforeShow,
      function(callback) {
        self.enableSlugifyTitle();
        return setImmediate(callback);
      }
    ], function(err) {
      apos.ui.globalBusy(false);
      if (err && self.$el) {
        self.hide();
      }
      if (err) {
        apos.log(err);
        return;
      }
      self.show();
      self.afterShow();
    });
  },

  construct: function(self, options) {

    if (options.$view) {
      self.$view = options.$view;
    }

    self.body = options.body;
    self.$body = $('body');

    self.getSource = function(callback) {
      return self.html(options.source, self.body || {}, function(html) {
        self.$el = $(html);
        return callback(null);
      }, function(err) {
        return callback(err);
      });
    };

    self.enableGlobalEventsOnce = function() {
      if (!apos.modalSupport.initialized) {
        apos.modalSupport.initialized = true;
        // Just ONE event handler for the escape key so we don't have
        // modals falling all over themselves to hide each other
        // consecutively.

        // Escape key should dismiss the top modal, if any

        $(document).on({
          'keydown.aposModal': function(e) {
            if (e.keyCode === 27) {
              apos.modalSupport.cancelTopModal();
              return false;
            }
          },
          'click.aposModal': function(e) {
            if (e.target.className === 'apos-modal-blackout') {
              apos.modalSupport.cancelTopModal();
              return false;
            }
          }
        });
      }
    };

    self.disableGlobalEvents = function() {
      // Leggo of the keyboard when there are no modals!
      // We can reinstall the handler when it's relevant.
      // Fewer event handlers all the time = better performance

      apos.modalSupport.initialized = false;
      $(document).off('keydown.aposModal');
      $(document).off('click.aposModal');
    };

    self.enableButtonEvents = function() {
      self.$controls.on('click', '[data-cancel]', function() {
        return self.cancel();
      });

      self.$controls.on('click', '[data-save]', function() {
        var $button = $(this);
        self.save(function(err) {
          if (err) {
            return;
          }
          if ($button.is('[data-next]')) {
            // Up to you to implement this by setting
            // this nonexistent method in your subclass. Should
            // create another instance of [whatever]
            self.next();
          }
        });
        return false;
      });
    };

    self.enableBreadcrumbEvents = function() {
      self.$el.on('click', '[data-modal-breadcrumb]:first .apos-modal-breadcrumb-item', function() {
        var $item = $(this);
        var index = $item.data('aposBreadcrumbIndex');
        var slides = self.getSlides();
        var cancels = slides.length - index - 1;
        cancelUntilCurrent(null);
        function cancelUntilCurrent(err) {
          if (err) {
            // The user decided not to cancel at some level
            return;
          }
          if (!cancels) {
            return;
          }
          cancels--;
          self.getLastSlide().cancel(cancelUntilCurrent);
        }
      });
    };

    self.enableSlugifyTitle = function() {
      // If a slug has not yet been specified, make sure
      // the field automatically populates itself as a
      // slugified version of the title.
      var $form = self.$el.find('[data-apos-form]');
      var $slug = $form.find('[name="slug"]');
      var $title = $form.find('[name="title"]');
      var val = $slug.val();

      $title.on('keyup', function(e) {
        $slug.val(val.replace(/[^\/]*$/, apos.utils.slugify($title.val())));
      });   
    }

    self.captureTitle = function() {
      self.title = self.$el.find('[data-modal-title]:first').text();
    };

    self.captureControls = function() {
      self.$controls = self.$el.find('[data-modal-controls]:first');
    };

    self.captureInstructions = function() {
      self.$instructions = self.$el.find('[data-modal-instructions]:first');
    };

    // If we are planning to slide, then we need to reset self.$el to
    // the data-modal-content element because it will be moved out
    // of self.$el and event handlers counting on self.$el would
    // no longer work. -<NAME> Matt

    self.resetEl = function() {
      if (self.options.transition !== 'slide') {
        return;
      }

      if (!self.getSlideableAncestorEl()) {
        return;
      }

      self.$shell = self.$el;
      var $content = self.$el.find('[data-modal-content]:first');
{'fraction_non_alphanumeric': 0.13914509570564315, 'fraction_numerical': 0.0005950609937518596, 'mean_word_length': 1.9641387419165197, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, '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': '2359889', 'n_tokens_mistral': 2896, 'n_tokens_neox': 2841, 'n_words': 647}