<commit_before>/**
 * Views for the story viewer Backbone application
 */
Namespace('storybase.viewer');

// Container view for the viewer application.
// It delegates rendering and events for the entire app to views
// rendering more specific "widgets"
storybase.viewer.views.ViewerApp = Backbone.View.extend({
  options: {
    tocEl: '#toc .story-toc',
    tocButtonEl: '#toggle-toc',
    tocIconEl: '[class^="icon-"]',
    tocOpenClass: 'icon-caret-down',
    tocClosedClass: 'icon-caret-up'
  },

  events: function() {
    var events = {};
    events['click ' + this.options.tocButtonEl] = 'toggleToc';
    return events;
  },

  // Initialize the view
  initialize: function() {
    this.showingConnectedStory = false;
    this.sections = this.options.sections;
    this.story = this.options.story;
    this.navigationView = new storybase.viewer.views.StoryNavigation({
      sections: this.options.sections
    }); 
    // TODO: Decide whether to re-enable updating the section title in the
    // header
    //this.headerView = new storybase.viewer.views.StoryHeader();
    this.setSection(this.sections.at(0), {showActiveSection: false});
    _.bindAll(this, 'handleScroll');
    $(window).scroll(this.handleScroll);
  },

  // Add the view's container element to the DOM and render the sub-views
  render: function() {
    this.$el.addClass(this.elClass);
    this.$('footer').append(this.navigationView.el);
    this.navigationView.render();
    this.$('.summary').show();
    this.$('.section').show();
    return this;
  },

  // Update the active story section in the sub-views
  updateSubviewSections: function() {
    this.navigationView.setSection(this.activeSection);
    // TODO: Decide whether to re-enable updating the section title in the
    // header
    //this.headerView.setSection(this.activeSection);
  },

  // Show the active section
  showActiveSection: function() {
    throw "showActiveSection() is not implemented";
  },

  // Set the active story section
  setSection: function(section, options) {
    options = typeof options !== 'undefined' ? options : {};
    var showActiveSection = options.hasOwnProperty('showActiveSection') ? options.showActiveSection : true;
    this.activeSection = section;
    if (showActiveSection) {
      this.showActiveSection();
    }
    this.updateSubviewSections();
  },

  // Like setSection(), but takes a section ID as an argument instead of
  // a Section model instance object
  setSectionById: function(id) {
    this.setSection(this.sections.get(id));
  },

  // Convenience method to get the element for the active section
  activeSectionEl: function() {
      return this.activeSection ? this.$('#' + this.activeSection.id) : null;
  },

  // Event handler for scroll event
  handleScroll: function(e) {
    // Do nothing. Subclasses might want to implement this to do some work
  },

  toggleToc: function(evt) {
    var $tocEl = $(this.options.tocEl);
    $tocEl.slideToggle();
    $(evt.target).children(this.options.tocIconEl)
                 .toggleClass(this.options.tocOpenClass)
                 .toggleClass(this.options.tocClosedClass);<commit_msg>resize captions in viewer based on accompanying image width. addresses #469.<commit_after>/**
 * Views for the story viewer Backbone application
 */
Namespace('storybase.viewer');

// Container view for the viewer application.
// It delegates rendering and events for the entire app to views
// rendering more specific "widgets"
storybase.viewer.views.ViewerApp = Backbone.View.extend({
  options: {
    tocEl: '#toc .story-toc',
    tocButtonEl: '#toggle-toc',
    tocIconEl: '[class^="icon-"]',
    tocOpenClass: 'icon-caret-down',
    tocClosedClass: 'icon-caret-up'
  },

  events: function() {
    var events = {};
    events['click ' + this.options.tocButtonEl] = 'toggleToc';
    events['resize figure img'] = 'handleImgResize';
    return events;
  },

  // Initialize the view
  initialize: function() {
    this.showingConnectedStory = false;
    this.sections = this.options.sections;
    this.story = this.options.story;
    this.navigationView = new storybase.viewer.views.StoryNavigation({
      sections: this.options.sections
    }); 
    // TODO: Decide whether to re-enable updating the section title in the
    // header
    //this.headerView = new storybase.viewer.views.StoryHeader();
    this.setSection(this.sections.at(0), {showActiveSection: false});
    _.bindAll(this, 'handleScroll');
    $(window).scroll(this.handleScroll);
  },

  // Add the view's container element to the DOM and render the sub-views
  render: function() {
    this.$el.addClass(this.elClass);
    this.$('footer').append(this.navigationView.el);
    this.navigationView.render();
    this.$('.summary').show();
    this.$('.section').show();
    this.sizeFigCaptions();
    return this;
  },

  // Update the active story section in the sub-views
  updateSubviewSections: function() {
    this.navigationView.setSection(this.activeSection);
    // TODO: Decide whether to re-enable updating the section title in the
    // header
    //this.headerView.setSection(this.activeSection);
  },

  // Show the active section
  showActiveSection: function() {
    throw "showActiveSection() is not implemented";
  },

  // Set the active story section
  setSection: function(section, options) {
    options = typeof options !== 'undefined' ? options : {};
    var showActiveSection = options.hasOwnProperty('showActiveSection') ? options.showActiveSection : true;
    this.activeSection = section;
    if (showActiveSection) {
      this.showActiveSection();
    }
    this.updateSubviewSections();
  },

  // Like setSection(), but takes a section ID as an argument instead of
  // a Section model instance object
  setSectionById: function(id) {
    this.setSection(this.sections.get(id));
  },

  // Convenience method to get the element for the active section
  activeSectionEl: function() {
      return this.activeSection ? this.$('#' + this.activeSection.id) : null;
  },

  // Event handler for scroll event
  handleScroll: function(e) {
    // Do nothing. Subclasses might want to implement this to do some work
  },
  
  sizeFigCaptionForImg: function(imgEl) {
    $(imgEl).next('figcaption').width($(imgEl).width());
  },
  
  sizeFigCaptions: function() {
    // we don't seem to get load events on images
    // even under a hard refresh.
    var view = this;
    this.$('figure img').each(function() {
      if (this.width) {
        view.sizeFigCaptionForImg(this);
      }
      // however, set up a handler anyway.
      $(this).on('load', function() {
        view.sizeFigCaptionForImg(this);
      });
    });
  },
  
  handleImgResize: function(event) {
    this.sizeFigCaptionForImg(event.target);
  },

  toggleToc: function(evt) {
    var $tocEl = $(this.options.tocEl);
    $tocEl.slideToggle();
    $(evt.target).children(this.options.tocIconEl)
                 .toggleClass(this.options.tocOpenClass)
                 .toggleClass(this.options.tocClosedClass);
{'fraction_non_alphanumeric': 0.1309116809116809, 'fraction_numerical': 0.0007122507122507123, 'mean_word_length': 3.2784887263863496, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '88555', 'n_tokens_mistral': 2089, 'n_tokens_neox': 2018, 'n_words': 523}