<commit_before>import React, { PropTypes } from 'react';
import styles from './TherapistPicker.css';
import withStyles from '../../decorators/withStyles';

@withStyles(styles)
class TherapistPicker extends React.Component {

  static propTypes = {
    therapists: React.PropTypes.array.isRequired,  /* an array of {name: .. , telephone: .. , id: .. } therapist objects */
  };

  state = { therapistSlected : false };

  selectTherapist = function(e){
    e.preventDefault();
    this.setState({ therapistSlected : true})
  }

  render() {
    var therapistSelectionForm = (
      <form onSubmit={this.selectTherapist.bind(this)}>

Please select a therapist:

        {this.props.therapists.map(function(therapist){
          return (

              {therapist.name}
              {therapist.tel}
              <input className="Therapist-selector" type="radio" name="therapist" value={therapist.id} required/>

          );
        })}

        <input type="submit" value="Choose Therapist"/>
      </form>
    );

    return (

          {this.state.therapistSlected === false ? therapistSelectionForm : (
Thank You for choosing a therapist
) }

    );
  }

}

export default TherapistPicker;
<commit_msg>Update TherapistPicker.js<commit_after>import React, { PropTypes } from 'react';
import styles from './TherapistPicker.css';
import withStyles from '../../decorators/withStyles';

@withStyles(styles)
class TherapistPicker extends React.Component {

  static propTypes = {
    therapists: React.PropTypes.array.isRequired,  /* an array of {name: .. , telephone: .. , id: .. } therapist objects */
  };

  state = { therapistSlected : false };

  selectTherapist = function(e){
    e.preventDefault();
    this.setState({ therapistSlected : true})
  }

  render() {
    var therapistSelectionForm = (
      <form onSubmit={this.selectTherapist.bind(this)}>

Please select a therapist:

        {this.props.therapists.map(function(therapist){
          return (

              {therapist.name}
              {therapist.tel}
              <input className="Therapist__selector" type="radio" name="therapist" value={therapist.id} required/>

          );
        })}

        <input type="submit" value="Choose Therapist"/>
      </form>
    );

    return (

          {this.state.therapistSlected === false ? therapistSelectionForm : (
Thank You for choosing a therapist
) }

    );
  }

}

export default TherapistPicker;
<|endoftext|>


<commit_before>/**
 * homepage.js - Homepage tests.
 */

var x = require('casper').selectXPath;
casper.options.viewportSize = {width: 1920, height: 961};
casper.on('page.error', function(msg, trace) {
    this.echo('Error: ' + msg, 'ERROR');
    for(var i=0; i<trace.length; i++) {
        var step = trace[i];
        this.echo('   ' + step.file + ' (line ' + step.line + ')', 'ERROR');
    }
});

casper.on('remote.message', function(message) {
    this.echo('Message: ' + message);
});

casper.test.begin('Tests homepage structure', function suite(test) {

    casper.start('http://web', function() {

        test.assertTitle("TestProject", "Title is correct");

        casper.wait(2000);

        test.assertVisible('h2');
    });

    casper.run(function() {

        test.done();
    });
});<commit_msg>Add more comments to the CasperJS test<commit_after>/**
 * homepage.js - Homepage tests.
 */

var x = require('casper').selectXPath;
casper.options.viewportSize = {width: 1920, height: 961};
casper.on('page.error', function(msg, trace) {
    this.echo('Error: ' + msg, 'ERROR');
    for(var i=0; i<trace.length; i++) {
        var step = trace[i];
        this.echo('   ' + step.file + ' (line ' + step.line + ')', 'ERROR');
    }
});

casper.on('remote.message', function(message) {
    this.echo('Message: ' + message);
});

casper.test.begin('Tests homepage structure', function suite(test) {

    casper.start('http://web', function() {

        // This works because the title is set in the "parent" template.
        test.assertTitle("TestProject", "Title is correct");

        casper.wait(2000);

        // This fails, I'm guessing because the h2 is only in the "child" template,
        // it seems that CasperJS doesn't render the angular2 app correctly
        // and the child route templates are not injected into the page correctly.
        test.assertVisible('h2');
    });

    casper.run(function() {

        test.done();
    });
});<|endoftext|>


<commit_before>$(document).on('turbolinks:load', function() {
  $('.dropdown-button').dropdown()
  $('.modal').modal()
  $('.collapsible').collapsible()
})

$(document).on('turbolinks:before-cache', function() {
  $('.dropdown-content').css('display', 'none')
  $('.modal').modal('destroy')
  $('.collapsible').collapsible('destroy')
  $('.dropdown-button').dropdown('destroy')
})

$(document).on('turbolinks:before-render', function(event) {
  $(event.originalEvent.data.newBody).find('[data-turbolinks-update]').each(function() {
    var elem_id = $(this).attr('id'),
        elem_value = $(this).text()
    document.getElementById(elem_id).textContent = elem_value
  })
})
<commit_msg>Prevent scrolling on modal open<commit_after>$(document).on('turbolinks:load', function() {
  $('.dropdown-button').dropdown()
  $('.modal').modal({preventScrolling: false})
  $('.collapsible').collapsible()
})

$(document).on('turbolinks:before-cache', function() {
  $('.dropdown-content').css('display', 'none')
  $('.modal').modal('destroy')
  $('.collapsible').collapsible('destroy')
  $('.dropdown-button').dropdown('destroy')
})

$(document).on('turbolinks:before-render', function(event) {
  $(event.originalEvent.data.newBody).find('[data-turbolinks-update]').each(function() {
    var elem_id = $(this).attr('id'),
        elem_value = $(this).text()
    document.getElementById(elem_id).textContent = elem_value
  })
})
<|endoftext|>


<commit_before>/**
 * @author Steve Cassidy
 */
 $(document).ready(function() {
     configure_edit();
     //disable_edit();
     $('#enable_edit').click(toggle_edit);

     var tagApi = $("#taginput").tagsManager({
         tagsContainer: "#tagcontainer"
     });

     var tagEngine = new Bloodhound({
        datumTokenizer: function(d) { return Bloodhound.tokenizers.whitespace(d.name); },
        queryTokenizer: Bloodhound.tokenizers.whitespace,
        name: 'tags',
        prefetch: {
            url : '/dictionary/ajax/tags',
            filter: function(list) {
                     return $.map(list, function(tag) { return { name: tag }; });
            }
        }
     });

     tagEngine.initialize();

     $("#taginput").typeahead(null, {displayKey: 'name', source: tagEngine.ttAdapter()}).on('typeahead:selected', function (e, d) {

      tagApi.tagsManager("pushTag", d.value);

    });

     /*
     $('#delete_video').confirm({
        msg:'Delete this video?',
        timeout:3000
     });
     */

    // setup requried for Ajax POST
    function csrfSafeMethod(method) {
        // these HTTP methods do not require CSRF protection
        return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
    }

    $.ajaxSetup({
        crossDomain: false, // obviates need for sameOrigin test
        beforeSend: function(xhr, settings) {
            if (!csrfSafeMethod(settings.type)) {
                xhr.setRequestHeader("X-CSRFToken", csrf_token);
            }
        }
    });

    ajaxifyTagForm();

 });

function disable_edit() {
    $('.edit').editable('disable');
    $('.edit').css('color', 'black');
    $('#edit_message').text('');
    $('.editform').hide();
};

function enable_edit() {
    $('.edit').editable('enable');
    $('.edit').css('color', 'red');
    $('#edit_message').text('Click on red text to edit  ');
    $('.editform').show();
};

function toggle_edit() {
    if ($('#enable_edit').hasClass('edit_enabled')) {
        disable_edit();
        $('#enable_edit').removeClass('edit_enabled');
        $('#enable_edit').text('Enable Edit');
    } else {
        enable_edit();
        $('#enable_edit').addClass('edit_enabled');
        $('#enable_edit').text('Disable Edit');
    }
}

function configure_edit() {
     $('.edit_text').editable(edit_post_url, {
         submitdata  : {'csrfmiddlewaretoken': csrf_token},
         indicator : 'Saving...',
         tooltip   : 'Click to edit...',
         placeholder : 'No Value Set',
         cancel    : 'Cancel',
         submit    : 'OK'
     });
     $('.edit_area').editable(edit_post_url, {
         submitdata  : {'csrfmiddlewaretoken': csrf_token},
         type      : 'textarea',
         cancel    : 'Cancel',
         submit    : 'OK',
         placeholder : 'No Value Set',
         tooltip   : 'Click to edit...'
     });
     $('.edit_role').editable(edit_post_url, {
         submitdata  : {'csrfmiddlewaretoken': csrf_token},
         type      : 'select',
         data      : definition_role_choices,
         cancel    : 'Cancel',
         submit    : 'OK',
         placeholder : 'No Value Set',
         tooltip   : 'Click to edit...'
     });
     $('.edit_language').editable(edit_post_url, {
         submitdata  : {'csrfmiddlewaretoken': csrf_token},
         type      : 'multiselect',
         data      : languages,
         cancel    : 'Cancel',
         submit    : 'OK',
         placeholder : 'No Value Set',
         tooltip   : 'Click to edit...'
     });
     $('.edit_dialect').editable(edit_post_url, {
         submitdata  : {'csrfmiddlewaretoken': csrf_token},
         type      : 'multiselect',
         data      : dialects,
         cancel    : 'Cancel',
         submit    : 'OK',
         placeholder : 'No Value Set',
         tooltip   : 'Click to edit...'
     });
     $('.edit_check').editable(edit_post_url, {
         submitdata  : {'csrfmiddlewaretoken': csrf_token},
         type      : 'checkbox',
         cancel    : 'Cancel',
         submit    : 'OK',
         placeholder : 'No Value Set',
         tooltip   : 'Click to edit...',
         checkbox: { trueValue: 'Yes', falseValue: 'No' }
     });

     $('.edit_handshape').editable(edit_post_url, {
         submitdata  : {'csrfmiddlewaretoken': csrf_token},
         type      : 'select',
         data      : handshape_choices,
         cancel    : 'Cancel',
         submit    : 'OK',
         placeholder : 'No Value Set',
         tooltip   : 'Click to edit...'
     });
     $('.edit_location').editable(edit_post_url, {
         submitdata  : {'csrfmiddlewaretoken': csrf_token},
         type      : 'select',
         data      : location_choices,
         cancel    : 'Cancel',
         submit    : 'OK',
         placeholder : 'No Value Set',
         tooltip   : 'Click to edit...'
     });
     $('.edit_palm').editable(edit_post_url, {
         submitdata  : {'csrfmiddlewaretoken': csrf_token},
         type      : 'select',
         data      : palm_orientation_choices,
         cancel    : 'Cancel',
         submit    : 'OK',
         placeholder : 'No Value Set',
         tooltip   : 'Click to edit...'
     });
     $('.edit_relori').editable(edit_post_url, {
         submitdata  : {'csrfmiddlewaretoken': csrf_token},
         type      : 'select',
         data      : relative_orientation_choices,
         cancel    : 'Cancel',
         submit    : 'OK',
         placeholder : 'No Value Set',
         tooltip   : 'Click to edit...'
     });
     $('.edit_sec_location').editable(edit_post_url, {
         submitdata  : {'csrfmiddlewaretoken': csrf_token},
         type      : 'select',
         data      : secondary_location_choices,
         cancel    : 'Cancel',
         submit    : 'OK',
         placeholder : 'No Value Set',
         tooltip   : 'Click to edit...'
     });
}

/*
 * http://stackoverflow.com/questions/1597756/is-there-a-jquery-jeditable-multi-select-plugin
 */

$.editable.addInputType("multiselect", {
    element: function (settings, original) {
        var select = $('<select multiple="multiple" />');

        if (settings.width != 'none') { select.width(settings.width); }
        if (settings.size) { select.attr('size', settings.size); }

        $(this).append(select);
        return (select);
    },
    content: function (data, settings, original) {
        /* If it is string assume it is json. */
        if (String == data.constructor) {
            eval('var json = ' + data);
        } else {
            /* Otherwise assume it is a hash already. */
            var json = data;
        }
        for (var key in json) {
            if (!json.hasOwnProperty(key)) {
                continue;
            }
            if ('selected' == key) {
                continue;
            }
            var option = $('<option />').val(key).append(json[key]);
            $('select', this).append(option);
        }

        if ($(this).val() == json['selected'] ||
                            $(this).html() == $.trim(original.revert)) {
            $(this).attr('selected', 'selected');
        }

        /* Loop option again to set selected. IE needed this... */
        $('select', this).children().each(function () {
            if (json.selected) {
                var option = $(this);
                $.each(json.selected, function (index, value) {
                    if (option.val() == value) {
                        option.attr('selected', 'selected');
                    }
                });
            } else {
                if (original.revert.indexOf($(this).html()) != -1)
                    $(this).attr('selected', 'selected');
            }
        });
    }
});

function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie != '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) { // >
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) == (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}

function ajaxifyTagForm() {
    // ajax form submission for tag addition and deletion
    $('.tagdelete').click(function() {
        var action = $(this).attr('href');
        var tagid = $(this).attr('id');
        var tagelement = $(this).parents('.tagli');

        $.post(action,
              {tag: tagid, 'delete': "True" },
               function(data) {
                    if (data == 'deleted') {
                        // remove the tag from the page
                       tagelement.remove();
                    }
               });

        return false;
    });

    $('#tagaddform').submit(function(){
        $.post($(this).attr('action'), $(this).serialize(),
                function(data) {
                   // response is a new tag list
                   $('#tags').replaceWith(data);
                   ajaxifyTagForm();
               });
        return false;
    });
}

      <commit_msg>disable edit by default<commit_after>/**
 * @author Steve Cassidy
 */
 $(document).ready(function() {
     configure_edit();
     disable_edit();
     $('#enable_edit').click(toggle_edit);

     var tagApi = $("#taginput").tagsManager({
         tagsContainer: "#tagcontainer"
     });

     var tagEngine = new Bloodhound({
        datumTokenizer: function(d) { return Bloodhound.tokenizers.whitespace(d.name); },
        queryTokenizer: Bloodhound.tokenizers.whitespace,
        name: 'tags',
        prefetch: {
            url : '/dictionary/ajax/tags',
            filter: function(list) {
                     return $.map(list, function(tag) { return { name: tag }; });
            }
        }
     });

     tagEngine.initialize();

     $("#taginput").typeahead(null, {displayKey: 'name', source: tagEngine.ttAdapter()}).on('typeahead:selected', function (e, d) {

      tagApi.tagsManager("pushTag", d.value);

    });

     /*
     $('#delete_video').confirm({
        msg:'Delete this video?',
        timeout:3000
     });
     */

    // setup requried for Ajax POST
    function csrfSafeMethod(method) {
        // these HTTP methods do not require CSRF protection
        return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
    }

    $.ajaxSetup({
        crossDomain: false, // obviates need for sameOrigin test
        beforeSend: function(xhr, settings) {
            if (!csrfSafeMethod(settings.type)) {
                xhr.setRequestHeader("X-CSRFToken", csrf_token);
            }
        }
    });

    ajaxifyTagForm();

 });

function disable_edit() {
    $('.edit').editable('disable');
    $('.edit').css('color', 'black');
    $('#edit_message').text('');
    $('.editform').hide();
};

function enable_edit() {
    $('.edit').editable('enable');
    $('.edit').css('color', 'red');
    $('#edit_message').text('Click on red text to edit  ');
    $('.editform').show();
};

function toggle_edit() {
    if ($('#enable_edit').hasClass('edit_enabled')) {
        disable_edit();
        $('#enable_edit').removeClass('edit_enabled');
        $('#enable_edit').text('Enable Edit');
    } else {
        enable_edit();
        $('#enable_edit').addClass('edit_enabled');
        $('#enable_edit').text('Disable Edit');
    }
}

function configure_edit() {
     $('.edit_text').editable(edit_post_url, {
         submitdata  : {'csrfmiddlewaretoken': csrf_token},
         indicator : 'Saving...',
         tooltip   : 'Click to edit...',
         placeholder : 'No Value Set',
         cancel    : 'Cancel',
         submit    : 'OK'
     });
     $('.edit_area').editable(edit_post_url, {
         submitdata  : {'csrfmiddlewaretoken': csrf_token},
         type      : 'textarea',
         cancel    : 'Cancel',
         submit    : 'OK',
         placeholder : 'No Value Set',
         tooltip   : 'Click to edit...'
     });
     $('.edit_role').editable(edit_post_url, {
         submitdata  : {'csrfmiddlewaretoken': csrf_token},
         type      : 'select',
         data      : definition_role_choices,
         cancel    : 'Cancel',
         submit    : 'OK',
         placeholder : 'No Value Set',
         tooltip   : 'Click to edit...'
     });
     $('.edit_language').editable(edit_post_url, {
         submitdata  : {'csrfmiddlewaretoken': csrf_token},
         type      : 'multiselect',
         data      : languages,
         cancel    : 'Cancel',
         submit    : 'OK',
         placeholder : 'No Value Set',
         tooltip   : 'Click to edit...'
     });
     $('.edit_dialect').editable(edit_post_url, {
         submitdata  : {'csrfmiddlewaretoken': csrf_token},
         type      : 'multiselect',
         data      : dialects,
         cancel    : 'Cancel',
         submit    : 'OK',
         placeholder : 'No Value Set',
         tooltip   : 'Click to edit...'
     });
     $('.edit_check').editable(edit_post_url, {
         submitdata  : {'csrfmiddlewaretoken': csrf_token},
         type      : 'checkbox',
         cancel    : 'Cancel',
         submit    : 'OK',
         placeholder : 'No Value Set',
         tooltip   : 'Click to edit...',
         checkbox: { trueValue: 'Yes', falseValue: 'No' }
     });

     $('.edit_handshape').editable(edit_post_url, {
         submitdata  : {'csrfmiddlewaretoken': csrf_token},
         type      : 'select',
         data      : handshape_choices,
         cancel    : 'Cancel',
         submit    : 'OK',
         placeholder : 'No Value Set',
         tooltip   : 'Click to edit...'
     });
     $('.edit_location').editable(edit_post_url, {
         submitdata  : {'csrfmiddlewaretoken': csrf_token},
         type      : 'select',
         data      : location_choices,
         cancel    : 'Cancel',
         submit    : 'OK',
         placeholder : 'No Value Set',
         tooltip   : 'Click to edit...'
     });
     $('.edit_palm').editable(edit_post_url, {
         submitdata  : {'csrfmiddlewaretoken': csrf_token},
         type      : 'select',
         data      : palm_orientation_choices,
         cancel    : 'Cancel',
         submit    : 'OK',
         placeholder : 'No Value Set',
         tooltip   : 'Click to edit...'
     });
     $('.edit_relori').editable(edit_post_url, {
         submitdata  : {'csrfmiddlewaretoken': csrf_token},
         type      : 'select',
         data      : relative_orientation_choices,
         cancel    : 'Cancel',
         submit    : 'OK',
         placeholder : 'No Value Set',
         tooltip   : 'Click to edit...'
     });
     $('.edit_sec_location').editable(edit_post_url, {
         submitdata  : {'csrfmiddlewaretoken': csrf_token},
         type      : 'select',
         data      : secondary_location_choices,
         cancel    : 'Cancel',
         submit    : 'OK',
         placeholder : 'No Value Set',
         tooltip   : 'Click to edit...'
     });
}

/*
 * http://stackoverflow.com/questions/1597756/is-there-a-jquery-jeditable-multi-select-plugin
 */

$.editable.addInputType("multiselect", {
    element: function (settings, original) {
        var select = $('<select multiple="multiple" />');

        if (settings.width != 'none') { select.width(settings.width); }
        if (settings.size) { select.attr('size', settings.size); }

        $(this).append(select);
        return (select);
    },
    content: function (data, settings, original) {
        /* If it is string assume it is json. */
        if (String == data.constructor) {
            eval('var json = ' + data);
        } else {
            /* Otherwise assume it is a hash already. */
            var json = data;
        }
        for (var key in json) {
            if (!json.hasOwnProperty(key)) {
                continue;
            }
            if ('selected' == key) {
                continue;
            }
            var option = $('<option />').val(key).append(json[key]);
            $('select', this).append(option);
        }

        if ($(this).val() == json['selected'] ||
                            $(this).html() == $.trim(original.revert)) {
            $(this).attr('selected', 'selected');
        }

        /* Loop option again to set selected. IE needed this... */
        $('select', this).children().each(function () {
            if (json.selected) {
                var option = $(this);
                $.each(json.selected, function (index, value) {
                    if (option.val() == value) {
                        option.attr('selected', 'selected');
                    }
                });
            } else {
                if (original.revert.indexOf($(this).html()) != -1)
                    $(this).attr('selected', 'selected');
            }
        });
    }
});

function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie != '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) { // >
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) == (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}

function ajaxifyTagForm() {
    // ajax form submission for tag addition and deletion
    $('.tagdelete').click(function() {
        var action = $(this).attr('href');
        var tagid = $(this).attr('id');
        var tagelement = $(this).parents('.tagli');

        $.post(action,
              {tag: tagid, 'delete': "True" },
               function(data) {
                    if (data == 'deleted') {
                        // remove the tag from the page
                       tagelement.remove();
                    }
               });

        return false;
    });

    $('#tagaddform').submit(function(){
        $.post($(this).attr('action'), $(this).serialize(),
                function(data) {
                   // response is a new tag list
                   $('#tags').replaceWith(data);
                   ajaxifyTagForm();
               });
        return false;
    });
}

      <|endoftext|>


<commit_before>'use strict';

class SvgSlides {
  constructor (options) {
    var self = this;

    this._options = {};
    Object.keys(SvgSlides.defaultOptions).forEach(function (key) {
      var value;

      if (options && options[key]) {
        value = options[key];
      } else {
        value = SvgSlides.defaultOptions[key];
      }

      self._options[key] = value;
    });

    this._error = this.options.logger.error;
    this._info = this.options.logger.info;
    this._debug = this.options.logger.debug;
  }

  static get actions () {
    return {
      firstSlide: function () {
        this.currentSlideIndex = 0;
      },
      lastSlide: function () {
        this.currentSlideIndex = this.slides.length - 1;
      },
      nextSlide: function () {
        this.currentSlideIndex++;
      },
      overview: function () {
        this.transitionTo(this.rootNodeSelection.node());
      },
      previousSlide () {
        this.currentSlideIndex--;
      }
    };
  }

  get currentSlide () {
    if ((0 <= this.currentSlideIndex) && (this.currentSlideIndex < this.slides.length)) {
      return this.slides[this.currentSlideIndex];
    } else {
      return this.rootNodeSelection.node();
    }
  }

  get currentSlideIndex () {
    return this._currentSlideIndex;
  }

  set currentSlideIndex (newSlideIndex) {
    if (this.slides.length === 0) {
      newSlideIndex = null;
    }

    if (newSlideIndex < 0) {
      newSlideIndex = 0;
    }

    if (newSlideIndex > this.slides.length - 1) {
      newSlideIndex = this.slides.length - 1;
    }

    this._currentSlideIndex = newSlideIndex;
    this.transitionTo(this.currentSlide);
  }

  static get defaultOptions () {
    var keyBindings = new Map();
    keyBindings.set('ArrowLeft', SvgSlides.actions.previousSlide);
    keyBindings.set('ArrowRight', SvgSlides.actions.nextSlide);
    keyBindings.set('Left', SvgSlides.actions.previousSlide);
    keyBindings.set('End', SvgSlides.actions.lastSlide);
    keyBindings.set('Escape', SvgSlides.actions.overview);
    keyBindings.set('Home', SvgSlides.actions.firstSlide);
    keyBindings.set('Right', SvgSlides.actions.nextSlide);
    keyBindings.set('Space', SvgSlides.actions.nextSlide);
    keyBindings.set('U+001B', SvgSlides.actions.overview);

    return {
      keyBindings: keyBindings,
      logger: {
        debug: function () {
          // ignore
        },
        info: function (message) {
          console.log(message);
        },
        error: function (message) {
          console.error(message);
        }
      },
      rootNodeSelector: 'svg',
      slideSelector: '[id^=slide_]',
      sortSlidesBy: 'id',
      zoomFactor: 1.25
    };
  }

  handleEvent (event) {
    switch (event.type) {
      case 'click':
        return this.onClick(event);
      case 'hashchange':
        return this.onHashChange(event);
      case 'keydown':
        return this.onKeyDown(event);
      case 'load':
        return this.onLoad(event);
      case 'wheel':
        return this.onMouseWheel(event);
    }
  }

  onClick (event) {
    var slideIndex = this.slides.indexOf(event.target);
    if (slideIndex > -1) {
      this.currentSlideIndex = slideIndex;
    }
  }

  onHashChange () {
    var hash = window.location.hash || '';
    var slideId = hash.replace(/^#/, '');

    var matchingSlides = this.slides.filter(function (slide) {
      return (slide.id === slideId);
    });

    if (matchingSlides.length === 0) {
      this._error(`No slide found with id "${slideId}"!`);
      this.currentSlideIndex = 0;
      return;
    }

    if (matchingSlides.length > 1) {
      this._error(`More than one slide found with id "${slideId}", using the first one!`);
    }

    var newSlideIndex = this.slides.indexOf(matchingSlides[0]);
    if (newSlideIndex != this.currentSlideIndex) {
      this.currentSlideIndex = newSlideIndex;
    }
  }

  onKeyDown (event) {
    var key = event.code || event.keyIdentifier;
    var keyBindings = this.options.keyBindings;

    var keyBinding;
    if (keyBindings instanceof Map) {
      keyBinding = keyBindings.get(key);
    } else {
      keyBinding = keyBindings[key];
    }

    if (keyBinding) {
      keyBinding.call(this);
    } else {
      this._debug(`No keybinding for ${key}`);
    }
  }

  onLoad () {
    this._info('Powered by d3 v' + d3.version);
    this._rootNodeSelection = d3.select(this.options.rootNodeSelector);
    this.rootNodeSelection.attr('preserveAspectRatio', 'xMidYMid meet');
    this.rootNodeSelection.attr('width', '100%');
    this.rootNodeSelection.attr('height', '100%');
    this.rootNodeSelection.attr('zoomAndPan', 'disable'); // sadly this is not supported by all browsers, so disable it for all

    var sortKey = this.options.sortSlidesBy;
    var slideComparator = function compare (firstSlide, secondSlide) {
      var firstSortKey = firstSlide[sortKey].toString();
      var secondSortKey = secondSlide[sortKey].toString();
      if (firstSortKey < secondSortKey) {
        return -1;
      } else if (firstSortKey > secondSortKey) {
        return 1;
      } else {
        return 0;
      }
    };

    this._slides = this.rootNodeSelection.selectAll(this.options.slideSelector)[0].sort(slideComparator);

    if (this.slides.length > 0) {
      var slideIds = this.slides.map(function (slide) {
        return slide.id;
      });
      this._info(`Found the following slides: ${slideIds}`);

      slideIds.forEach(function (slideId, currentIndex) {
        if (slideIds.indexOf(slideId) !== currentIndex) {
          this._error(`Found duplicate slide id: ${slideId}`);
        }
      });
    } else {
      this._error('Found no slides!');
    }

    window.addEventListener('click', this);
    window.addEventListener('hashchange', this);
    window.addEventListener('keydown', this);
    window.addEventListener('wheel', this);

    // start presentation
    this.currentSlideIndex = 0;
  }

  onMouseWheel (event) {
    var zoomFactor = this.options.zoomFactor;
    if (event.wheelDelta > 0) {
      this._debug('Zooming in');
      zoomFactor = 1 / zoomFactor;
    } else {
      this._debug('Zooming out');
    }

    var oldViewBox = this.rootNodeSelection.attr('viewBox').split(' ');
    oldViewBox = {
      left: parseInt(oldViewBox[0]),
      top: parseInt(oldViewBox[1]),
      width: parseInt(oldViewBox[2]),
      height: parseInt(oldViewBox[3])
    };

    var viewBox = {
      left: oldViewBox.left + (oldViewBox.width - oldViewBox.width * zoomFactor) / 2,
      top: oldViewBox.top + (oldViewBox.height - oldViewBox.height * zoomFactor) / 2,
      width: oldViewBox.width * zoomFactor,
      height: oldViewBox.height * zoomFactor
    };

    this._debug(`Setting viewBox to ${viewBox.left},${viewBox.top},${viewBox.width},${viewBox.height}...`);
    this.rootNodeSelection.attr('viewBox', `${viewBox.left} ${viewBox.top} ${viewBox.width} ${viewBox.height}`);
  }

  get options () {
    return this._options;
  }

  get rootNodeSelection () {
    return this._rootNodeSelection;
  }

  get slides () {
    return this._slides;
  }

  transitionTo (slide) {
    if (!slide || !(slide instanceof SVGElement)) {
      return;
    }

    if (this.slides.indexOf(slide) > -1) {
      this._info(`Transitioning to slide ${slide.id}...`);
      window.location.hash = `#${slide.id}`;
    } else if (slide === this.rootNodeSelection.node()) {
      this._debug(`Transitioning to overview...`);
    } else {
      this._error('Passed argument is neither slide nor overview!');
      return;
    }

    var boundingBox = slide.getBBox();
    var margin = {
      x: boundingBox.width / 100,
      y: boundingBox.height / 100
    };
    var viewBox = {
      left: boundingBox.x - margin.x,
      top: boundingBox.y - margin.y,
      width: boundingBox.width + 2 * margin.x,
      height: boundingBox.height + 2 * margin.y
    };

    this.rootNodeSelection.transition()
      .attr('viewBox', `${viewBox.left} ${viewBox.top} ${viewBox.width} ${viewBox.height}`);
  }
}
<commit_msg>use mapping for event callbacks<commit_after>'use strict';

class SvgSlides {
  constructor (options) {
    var self = this;

    this._options = {};
    Object.keys(SvgSlides.defaultOptions).forEach(function (key) {
      var value;

      if (options && options[key]) {
        value = options[key];
      } else {
        value = SvgSlides.defaultOptions[key];
      }

      self._options[key] = value;
    });

    this._error = this.options.logger.error;
    this._info = this.options.logger.info;
    this._debug = this.options.logger.debug;

    this._eventHandler = {
      'click': this.onClick,
      'hashchange': this.onHashChange,
      'keydown': this.onKeyDown,
      'load': this.onLoad,
      'wheel': this.onMouseWheel
    };
  }

  static get actions () {
    return {
      firstSlide: function () {
        this.currentSlideIndex = 0;
      },
      lastSlide: function () {
        this.currentSlideIndex = this.slides.length - 1;
      },
      nextSlide: function () {
        this.currentSlideIndex++;
      },
      overview: function () {
        this.transitionTo(this.rootNodeSelection.node());
      },
      previousSlide () {
        this.currentSlideIndex--;
      }
    };
  }

  get currentSlide () {
    if ((0 <= this.currentSlideIndex) && (this.currentSlideIndex < this.slides.length)) {
      return this.slides[this.currentSlideIndex];
    } else {
      return this.rootNodeSelection.node();
    }
  }

  get currentSlideIndex () {
    return this._currentSlideIndex;
  }

  set currentSlideIndex (newSlideIndex) {
    if (this.slides.length === 0) {
      newSlideIndex = null;
    }

    if (newSlideIndex < 0) {
      newSlideIndex = 0;
    }

    if (newSlideIndex > this.slides.length - 1) {
      newSlideIndex = this.slides.length - 1;
    }

    this._currentSlideIndex = newSlideIndex;
    this.transitionTo(this.currentSlide);
  }

  static get defaultOptions () {
    var keyBindings = new Map();
    keyBindings.set('ArrowLeft', SvgSlides.actions.previousSlide);
    keyBindings.set('ArrowRight', SvgSlides.actions.nextSlide);
    keyBindings.set('Left', SvgSlides.actions.previousSlide);
    keyBindings.set('End', SvgSlides.actions.lastSlide);
    keyBindings.set('Escape', SvgSlides.actions.overview);
    keyBindings.set('Home', SvgSlides.actions.firstSlide);
    keyBindings.set('Right', SvgSlides.actions.nextSlide);
    keyBindings.set('Space', SvgSlides.actions.nextSlide);
    keyBindings.set('U+001B', SvgSlides.actions.overview);

    return {
      keyBindings: keyBindings,
      logger: {
        debug: function () {
          // ignore
        },
        info: function (message) {
          console.log(message);
        },
        error: function (message) {
          console.error(message);
        }
      },
      rootNodeSelector: 'svg',
      slideSelector: '[id^=slide_]',
      sortSlidesBy: 'id',
      zoomFactor: 1.25
    };
  }

  handleEvent (event) {
    var handler = this._eventHandler[event.type];

    if (handler) {
      handler.call(this, event);
    } else {
      this._error(`No handler for event ${event.type}!`);
    }
  }

  onClick (event) {
    var slideIndex = this.slides.indexOf(event.target);
    if (slideIndex > -1) {
      this.currentSlideIndex = slideIndex;
    }
  }

  onHashChange () {
    var hash = window.location.hash || '';
    var slideId = hash.replace(/^#/, '');

    var matchingSlides = this.slides.filter(function (slide) {
      return (slide.id === slideId);
    });

    if (matchingSlides.length === 0) {
      this._error(`No slide found with id "${slideId}"!`);
      this.currentSlideIndex = 0;
      return;
    }

    if (matchingSlides.length > 1) {
      this._error(`More than one slide found with id "${slideId}", using the first one!`);
    }

    var newSlideIndex = this.slides.indexOf(matchingSlides[0]);
    if (newSlideIndex != this.currentSlideIndex) {
      this.currentSlideIndex = newSlideIndex;
    }
  }

  onKeyDown (event) {
    var key = event.code || event.keyIdentifier;
    var keyBindings = this.options.keyBindings;

    var keyBinding;
    if (keyBindings instanceof Map) {
      keyBinding = keyBindings.get(key);
    } else {
      keyBinding = keyBindings[key];
    }

    if (keyBinding) {
      keyBinding.call(this);
    } else {
      this._debug(`No keybinding for ${key}`);
    }
  }

  onLoad () {
    this._info('Powered by d3 v' + d3.version);
    this._rootNodeSelection = d3.select(this.options.rootNodeSelector);
    this.rootNodeSelection.attr('preserveAspectRatio', 'xMidYMid meet');
    this.rootNodeSelection.attr('width', '100%');
    this.rootNodeSelection.attr('height', '100%');
    this.rootNodeSelection.attr('zoomAndPan', 'disable'); // sadly this is not supported by all browsers, so disable it for all

    var sortKey = this.options.sortSlidesBy;
    var slideComparator = function compare (firstSlide, secondSlide) {
      var firstSortKey = firstSlide[sortKey].toString();
      var secondSortKey = secondSlide[sortKey].toString();
      if (firstSortKey < secondSortKey) {
        return -1;
      } else if (firstSortKey > secondSortKey) {
        return 1;
      } else {
        return 0;
      }
    };

    this._slides = this.rootNodeSelection.selectAll(this.options.slideSelector)[0].sort(slideComparator);

    if (this.slides.length > 0) {
      var slideIds = this.slides.map(function (slide) {
        return slide.id;
      });
      this._info(`Found the following slides: ${slideIds}`);

      slideIds.forEach(function (slideId, currentIndex) {
        if (slideIds.indexOf(slideId) !== currentIndex) {
          this._error(`Found duplicate slide id: ${slideId}`);
        }
      });
    } else {
      this._error('Found no slides!');
    }

    var self = this;
    Object.keys(this._eventHandler).forEach(function (eventType) {
      if (eventType !== 'load') {
        window.addEventListener(eventType, self);
      }
    });

    // start presentation
    this.currentSlideIndex = 0;
  }

  onMouseWheel (event) {
    var zoomFactor = this.options.zoomFactor;
    if (event.wheelDelta > 0) {
      this._debug('Zooming in');
      zoomFactor = 1 / zoomFactor;
    } else {
      this._debug('Zooming out');
    }

    var oldViewBox = this.rootNodeSelection.attr('viewBox').split(' ');
    oldViewBox = {
      left: parseInt(oldViewBox[0]),
      top: parseInt(oldViewBox[1]),
      width: parseInt(oldViewBox[2]),
      height: parseInt(oldViewBox[3])
    };

    var viewBox = {
      left: oldViewBox.left + (oldViewBox.width - oldViewBox.width * zoomFactor) / 2,
      top: oldViewBox.top + (oldViewBox.height - oldViewBox.height * zoomFactor) / 2,
      width: oldViewBox.width * zoomFactor,
      height: oldViewBox.height * zoomFactor
    };

    this._debug(`Setting viewBox to ${viewBox.left},${viewBox.top},${viewBox.width},${viewBox.height}...`);
    this.rootNodeSelection.attr('viewBox', `${viewBox.left} ${viewBox.top} ${viewBox.width} ${viewBox.height}`);
  }

  get options () {
    return this._options;
  }

  get rootNodeSelection () {
    return this._rootNodeSelection;
  }

  get slides () {
    return this._slides;
  }

  transitionTo (slide) {
    if (!slide || !(slide instanceof SVGElement)) {
      return;
    }

    if (this.slides.indexOf(slide) > -1) {
      this._info(`Transitioning to slide ${slide.id}...`);
      window.location.hash = `#${slide.id}`;
    } else if (slide === this.rootNodeSelection.node()) {
      this._debug(`Transitioning to overview...`);
    } else {
      this._error('Passed argument is neither slide nor overview!');
      return;
    }

    var boundingBox = slide.getBBox();
    var margin = {
      x: boundingBox.width / 100,
      y: boundingBox.height / 100
    };
    var viewBox = {
      left: boundingBox.x - margin.x,
      top: boundingBox.y - margin.y,
      width: boundingBox.width + 2 * margin.x,
      height: boundingBox.height + 2 * margin.y
    };

    this.rootNodeSelection.transition()
      .attr('viewBox', `${viewBox.left} ${viewBox.top} ${viewBox.width} ${viewBox.height}`);
  }
}
<|endoftext|>


<commit_before>/*
 * toggle.js
 *
 * dependencies: prototype.js, lowpro.js, effect.js
 *
 * --------------------------------------------------------------------------
 *
 * A LowPro and Prototype-based library with a collection of behaviors for
 * unobtrusively toggling the visibility of other elements via links,
 * checkboxes, radio buttons, and selects.
 *
 * To use you will need to install the following LowPro behaviors. If you are
 * using Rails, put this in "application.js":
 *
 *   Event.addBehavior({
 *     'a.toggle': Toggle.LinkBehavior(),
 *     'input.checkbox.toggle': Toggle.CheckboxBehavior(),
 *     'div.radio_group.toggle': Toggle.RadioGroupBehavior(),
 *     'select.toggle': Toggle.SelectBehavior()
 *   });
 *
 * Once the hooks are installed correctly, you should add a "rel" attribute
 * to each element that you want to use as a toggle trigger. Set the value
 * of the "rel" attribute to "toggle[id]" where id is equal to the ID of
 * the element that you want to toggle. You can toggle multiple elements by
 * separating the IDs with commas (like this: "toggle[id1,id2,id3]").
 *
 * For example, a link with a class of "toggle":
 *
 *   More
 *
 * will become a trigger for a div with an ID of "more". Checkboxes work in
 * the exact same manner. To use with a group of radio buttons, make sure
 * that all of the radio buttons are inside of a div with a class of
 * "radio_group toggle". Then set the "rel" attribute on each radio button
 * that should act as a toggle trigger. Selects work in a similar manner,
 * but the "rel" attribute should be set on each option element that should
 * toggle the visibility of an element or array of elements.
 *
 * Each of the included LowPro behaviors can be customized in various ways.
 * Check out the inline documentation for detailed usage information.
 *
 * Project Homepage: http://github.com/fivepointssolutions/togglejs
 *
 * --------------------------------------------------------------------------
 *
 * Copyright (c) 2007-2010, Five Points Solutions, Inc.
 * Copyright (c) 2010, John W. Long
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

var Toggle = {

  DefaultEffect: 'slide',
  DefaultEffectDuration: 0.25,

  EffectPairs: {
    'slide' : ['SlideDown','SlideUp'],
    'blind' : ['BlindDown','BlindUp'],
    'appear': ['Appear','Fade']
  },

  /**
   *  Toggle.extractAnchor(url) -> String
   *
   *  Utility function. Returns everything after the first "#" character in a
   *  string. Used to extract the anchor from a URL.
  **/
  extractAnchor: function(url) {
    var matches = String(url).match(/\#(.+)$/);
    if (matches) return matches[1];
  },

  /**
   *  Toggle.extractToggleObjects(string) -> Array
   *
   *  Utility function. Returns the associated toggle elements in a string. For
   *  string "toggle[one,two,three]" it will return the elements with IDs of
   *  "one", "two", and "three".
  **/
  extractToggleObjects: function(string) {
    var matches = String(string).match(/^toggle\[(.+)\]$/);
    if (matches) {
      var ids = matches[1].split(',');
      var elements = [];
      ids.each(function(id) { elements.push($(id)) });
      return elements;
    } else {
      return [];
    }
  },

  /**
   *  Toggle.toggle(elements, effect, options)
   *
   *  Utility function. Toggles an element or array of elements with effect
   *  and options. Similar to `Effect.toggle()`, but works with multiple
   *  elements and also supports setting effect to "none".
   *
   *  Parameters
   *  - elements: An element or array of elements to toggle
   *  - effect: This option specifies the effect that should be used when
   *    toggling. The default is "slide", but it can also be set to
   *    "blind", "appear", or "none".
   *  - options: The standard Effect options hash with the addition of
   *    beforeToggle and afterToggle events.
  **/
  toggle: function(elements, effect, options) {
    var elements = $A([elements]).flatten();
    var effect = (effect || Toggle.DefaultEffect).toLowerCase();
    var options = options || {};

    if (effect == 'none') {
      if (options.beforeStart) options.beforeStart();
      elements.invoke("toggle");
      if (options.afterFinish) options.afterFinish();
    } else {
      options.duration = options.duration || Toggle.DefaultEffectDuration;

      var effects = elements.map(function(e) {
        var element = $(e);
        var inOrOut = element.visible() ? 1 : 0;
        var name = Toggle.EffectPairs[effect][inOrOut];
        return new Effect[name](element, { sync: true });
      });

      new Effect.Parallel(effects, options);
    }
  },

  /**
   *  Toggle.show(elements, effect, options)
   *
   *  Utility function. Shows an element or array of elements with effect
   *  and options.
  **/
  show: function(elements, effect, options) {
    var elements = $([elements]).flatten();
    elements = elements.map(function(element) { return $(element) });
    elements = elements.reject(function(element) { return element.visible() });
    Toggle.toggle(elements, effect, options);
  },

  /**
   *  Toggle.hide(elements, effect, options)
   *
   *  Utility function. Hides an element or array of elements with effect
   *  and options.
  **/
  hide: function(elements, effect, options) {
    var elements = $([elements]).flatten();
    elements = elements.map(function(element) { return $(element) });
    elements = elements.reject(function(element) { return !element.visible() });
    Toggle.toggle(elements, effect, options);
  },

  /**
   *  Toggle.wrapElement(element)
   *
   *  Utility function. Wraps element with a div of class "toggle_wrapper"
   *  unless one already exists. Returns the "toggle_wrapper" for given
   *  element. This is necessary because effects only work properly on
   *  elements that do not have padding, borders, or margin.
  **/
  wrapElement: function(element) {
    var element = $(element);
    var parent = $(element.parentNode);
    if (parent.hasClassName('toggle_wrapper')) {
      return parent;
    } else {
      return element.wrap($div({'class': 'toggle_wrapper', 'style': 'display: none'}));
    }
  }
};

/**
 * class Toggle.LinkBehavior < Behavior
 *
 *  Allows a link to toggle the display of another element or array of
 *  elements on and off. Just set the <tt>rel</tt> attribute to
 *  "toggle[id1,id2,...]" on the link and the href of the link to the
 *  ID of the first element ("#id1").
 *
 *  Options
 *  - effect: This option specifies the effect that should be used when
 *    toggling. The default is "slide", but it can also be set to
 *    "blind", "appear", or "none".
 *  - onLoad: Called after the behavior is initialized. The function is
 *    automatically bound to the behavior (so "this" referes to the
 *    behavior).
 *  - beforeToggle: Called after the link is clicked, but before the effect is
 *    started. The link is passed as the first parameter and the
 *    function is automatically bound to the behavior (so "this"
 *    refers to the behavior).
 *  - afterToggle: Called after the effect is complete. The link is passed as
 *    the first parameter and the function is automatically bound
 *    to the behavior (so "this" refers to the behavior).
**/
Toggle.LinkBehavior = Behavior.create({
  initialize: function(options) {
    var options = options || {};

    this.effect = options.effect || Toggle.DefaultEffect;

    this.onLoad = options.onLoad || Prototype.emptyFunction;
    this.onLoad.bind(this);

    this.beforeToggle = options.beforeToggle || Prototype.emptyFunction;
    this.beforeToggle.bind(this);

    this.afterToggle = options.afterToggle || Prototype.emptyFunction;
    this.afterToggle.bind(this);

    var elements = Toggle.extractToggleObjects(this.element.readAttribute('rel'));
    this.toggleWrappers = elements.map(function(e) { return Toggle.wrapElement(e) });

    this.toggleID = Toggle.extractAnchor(this.element.href);
    this.element.behavior = this; // a bit of a hack
    Toggle.addLink(this.toggleID, this.element);

    this.onLoad(this.element);
  },

  onclick: function() {
    this.toggle();
    return false;
  },

  toggle: function() {
    Toggle.toggle(
      this.toggleWrappers,
      this.effect,
      {
        beforeStart: function() { this.beforeToggle(this.element) }.bind(this),
        afterFinish: function() { this.afterToggle(this.element) }.bind(this)
      }
    );
  }
});
Toggle.links = {};
Toggle.addLink = function(id, element) {
  this.links[id] = this.links[id] || $A();
  this.links[id].push(element);
};

// Automatically toggle associated element if anchor is equal to the ID of the
// link's associated element.
Event.observe(window, 'dom:loaded', function() {
  var anchor = Toggle.extractAnchor(window.location);
  var links = Toggle.links[anchor];
  if (links) {
    var behavior = links.first().behavior;
    behavior.onclick();
  }
});

/**
 * class Toggle.CheckboxBehavior < Behavior
 *
 *  Allows a the selection of a checkbox to toggle an element or group of
 *  elements on and off. Just set the `rel` attribute to "toggle[id1,id2,...]"
 *  on the checkbox.
 *
 *  Options
 *  - invert: When set to true the associated element is hidden when checked.
 *  - effect: This option specifies the effect that should be used when
 *    toggling. The default is "slide", but it can also be set to
 *    "blind", "appear", or "none".
**/
Toggle.CheckboxBehavior = Behavior.create({
  initialize: function(options) {
    var options = options || {};
    this.invert = options.invert;

    var elements = Toggle.extractToggleObjects(this.element.readAttribute('rel'));
    this.toggleWrappers = elements.map(function(e) { return Toggle.wrapElement(e) });

    this.effect = 'none';
    this.toggle();

    this.effect = options.effect || Toggle.DefaultEffect;
  },

  onclick: function(event) {
    this.toggle();
  },

  toggle: function() {
    var method, formElementMethod;

    if (this.invert) {
      method = this.element.checked ? 'hide' : 'show';
      formElementMethod = this.element.checked ? 'disable' : 'enable';
    } else {
      method = this.element.checked ? 'show' : 'hide';
      formElementMethod = this.element.checked ? 'enable' : 'disable';
    }

    Toggle[method](this.toggleWrappers, this.effect);

    // Disable/enable form elements based on whether the container is
    // visible or not.
    this.toggleWrappers.each(function(wrapper) {
      Form.getElements(wrapper).invoke(formElementMethod);
    });
  }
});

/**
 * class Toggle.RadioGroupBehavior < Behavior
 *
 *  Allows you to toggle elements based on the selection of a group of radio
 *  buttons. Just set the <tt>rel</tt> attribute to "toggle[id1,id2,...]" on
 *  each radio button. Radio buttons must be grouped inside a containing
 *  element to which the behavior is applied.
 *
 *  Options
 *  - effect: This option specifies the effect that should be used when
 *    toggling. The default is "slide", but it can also be set to
 *    "blind", "appear", or "none".
**/
Toggle.RadioGroupBehavior = Behavior.create({
  initialize: function(options) {
    var options = options || {};

    this.radioButtons = this.element.select('input[type=radio]');

    this.toggleWrapperIDs = $A();
    this.toggleWrapperIDsFor = {};

    this.radioButtons.each(function(radioButton) {
      var elements = Toggle.extractToggleObjects(radioButton.readAttribute('rel'))
      var ids = elements.invoke('identify');
      var wrapperIDs = elements.map(function(e) { return Toggle.wrapElement(e) }).invoke('identify');
      this.toggleWrapperIDsFor[radioButton.identify()] = wrapperIDs;
      this.toggleWrapperIDs.push(wrapperIDs);
      radioButton.observe('click', this.onRadioButtonClick.bind(this));
    }.bind(this));

    this.toggleWrapperIDs = this.toggleWrapperIDs.flatten().uniq()

    this.effect = "none";
    this.toggle();

    this.effect = options.effect || Toggle.DefaultEffect;
  },

  onRadioButtonClick: function(event) {
    this.toggle();
  },

  toggle: function() {
    var group = this.element;
    var radioButton = this.radioButtons.find(function(b) { return b.checked });
    var wrapperIDs = this.toggleWrapperIDsFor[radioButton.identify()];
    var partitioned = this.toggleWrapperIDs.partition(function(id) { return wrapperIDs.include(id) });
    Toggle.show(partitioned[0], this.effect);
    Toggle.hide(partitioned[1], this.effect);
  }
});

/**
 * class Toggle.SelectBehavior < Behavior
 *
 *  Allows you to toggle elements based on the selection of a combo box. Just
 *  set the <tt>rel</tt> attribute to "toggle[id1,id2,...]" on the each select
 *  option.
 *
 *  Options
 *  - effect: This option specifies the effect that should be used when
 *    toggling. The default is "slide", but it can also be set to
 *    "blind", "appear", or "none".
**/
Toggle.SelectBehavior = Behavior.create({
  initialize: function(options) {
    var options = options || {};

    var optionElements = this.element.select('option');

    this.toggleWrapperIDs = $A();
    this.toggleWrapperIDsFor = {};

    optionElements.each(function(optionElement) {
      var elements = Toggle.extractToggleObjects(optionElement.readAttribute('rel'))
      var wrapperIDs = elements.map(function(e) { return Toggle.wrapElement(e) }).invoke('identify');
      this.toggleWrapperIDsFor[optionElement.identify()] = wrapperIDs;
      this.toggleWrapperIDs.push(wrapperIDs);
    }.bind(this));

    this.toggleWrapperIDs = this.toggleWrapperIDs.flatten().uniq()

    this.effect = "none";
    this.toggle();

    this.effect = options.effect || Toggle.DefaultEffect;
  },

  onchange: function(event) {
    this.toggle();
  },

  toggle: function() {
    var combo = this.element;
    var option = $(combo.options[combo.selectedIndex]);
    var wrapperIDs = this.toggleWrapperIDsFor[option.identify()];
    var partitioned = this.toggleWrapperIDs.partition(function(id) { return wrapperIDs.include(id) });
    Toggle.show(partitioned[0], this.effect);
    Toggle.hide(partitioned[1], this.effect);
  }
});<commit_msg>Add missing semicolons.<commit_after>/*
 * toggle.js
 *
 * dependencies: prototype.js, lowpro.js, effect.js
 *
 * --------------------------------------------------------------------------
 *
 * A LowPro and Prototype-based library with a collection of behaviors for
 * unobtrusively toggling the visibility of other elements via links,
 * checkboxes, radio buttons, and selects.
 *
 * To use you will need to install the following LowPro behaviors. If you are
 * using Rails, put this in "application.js":
 *
 *   Event.addBehavior({
 *     'a.toggle': Toggle.LinkBehavior(),
 *     'input.checkbox.toggle': Toggle.CheckboxBehavior(),
 *     'div.radio_group.toggle': Toggle.RadioGroupBehavior(),
 *     'select.toggle': Toggle.SelectBehavior()
 *   });
 *
 * Once the hooks are installed correctly, you should add a "rel" attribute
 * to each element that you want to use as a toggle trigger. Set the value
 * of the "rel" attribute to "toggle[id]" where id is equal to the ID of
 * the element that you want to toggle. You can toggle multiple elements by
 * separating the IDs with commas (like this: "toggle[id1,id2,id3]").
 *
 * For example, a link with a class of "toggle":
 *
 *   More
 *
 * will become a trigger for a div with an ID of "more". Checkboxes work in
 * the exact same manner. To use with a group of radio buttons, make sure
 * that all of the radio buttons are inside of a div with a class of
 * "radio_group toggle". Then set the "rel" attribute on each radio button
 * that should act as a toggle trigger. Selects work in a similar manner,
 * but the "rel" attribute should be set on each option element that should
 * toggle the visibility of an element or array of elements.
 *
 * Each of the included LowPro behaviors can be customized in various ways.
 * Check out the inline documentation for detailed usage information.
 *
 * Project Homepage: http://github.com/fivepointssolutions/togglejs
 *
 * --------------------------------------------------------------------------
 *
 * Copyright (c) 2007-2010, Five Points Solutions, Inc.
 * Copyright (c) 2010, John W. Long
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

var Toggle = {

  DefaultEffect: 'slide',
  DefaultEffectDuration: 0.25,

  EffectPairs: {
    'slide' : ['SlideDown','SlideUp'],
    'blind' : ['BlindDown','BlindUp'],
    'appear': ['Appear','Fade']
  },

  /**
   *  Toggle.extractAnchor(url) -> String
   *
   *  Utility function. Returns everything after the first "#" character in a
   *  string. Used to extract the anchor from a URL.
  **/
  extractAnchor: function(url) {
    var matches = String(url).match(/\#(.+)$/);
    if (matches) return matches[1];
  },

  /**
   *  Toggle.extractToggleObjects(string) -> Array
   *
   *  Utility function. Returns the associated toggle elements in a string. For
   *  string "toggle[one,two,three]" it will return the elements with IDs of
   *  "one", "two", and "three".
  **/
  extractToggleObjects: function(string) {
    var matches = String(string).match(/^toggle\[(.+)\]$/);
    if (matches) {
      var ids = matches[1].split(',');
      var elements = [];
      ids.each(function(id) { elements.push($(id)); });
      return elements;
    } else {
      return [];
    }
  },

  /**
   *  Toggle.toggle(elements, effect, options)
   *
   *  Utility function. Toggles an element or array of elements with effect
   *  and options. Similar to `Effect.toggle()`, but works with multiple
   *  elements and also supports setting effect to "none".
   *
   *  Parameters
   *  - elements: An element or array of elements to toggle
   *  - effect: This option specifies the effect that should be used when
   *    toggling. The default is "slide", but it can also be set to
   *    "blind", "appear", or "none".
   *  - options: The standard Effect options hash with the addition of
   *    beforeToggle and afterToggle events.
  **/
  toggle: function(elements, effect, options) {
    var elements = $A([elements]).flatten();
    var effect = (effect || Toggle.DefaultEffect).toLowerCase();
    var options = options || {};

    if (effect == 'none') {
      if (options.beforeStart) options.beforeStart();
      elements.invoke("toggle");
      if (options.afterFinish) options.afterFinish();
    } else {
      options.duration = options.duration || Toggle.DefaultEffectDuration;

      var effects = elements.map(function(e) {
        var element = $(e);
        var inOrOut = element.visible() ? 1 : 0;
        var name = Toggle.EffectPairs[effect][inOrOut];
        return new Effect[name](element, { sync: true });
      });

      new Effect.Parallel(effects, options);
    }
  },

  /**
   *  Toggle.show(elements, effect, options)
   *
   *  Utility function. Shows an element or array of elements with effect
   *  and options.
  **/
  show: function(elements, effect, options) {
    var elements = $([elements]).flatten();
    elements = elements.map(function(element) { return $(element); });
    elements = elements.reject(function(element) { return element.visible(); });
    Toggle.toggle(elements, effect, options);
  },

  /**
   *  Toggle.hide(elements, effect, options)
   *
   *  Utility function. Hides an element or array of elements with effect
   *  and options.
  **/
  hide: function(elements, effect, options) {
    var elements = $([elements]).flatten();
    elements = elements.map(function(element) { return $(element); });
    elements = elements.reject(function(element) { return !element.visible(); });
    Toggle.toggle(elements, effect, options);
  },

  /**
   *  Toggle.wrapElement(element)
   *
   *  Utility function. Wraps element with a div of class "toggle_wrapper"
   *  unless one already exists. Returns the "toggle_wrapper" for given
   *  element. This is necessary because effects only work properly on
   *  elements that do not have padding, borders, or margin.
  **/
  wrapElement: function(element) {
    var element = $(element);
    var parent = $(element.parentNode);
    if (parent.hasClassName('toggle_wrapper')) {
      return parent;
    } else {
      return element.wrap($div({'class': 'toggle_wrapper', 'style': 'display: none'}));
    }
  }
};

/**
 * class Toggle.LinkBehavior < Behavior
 *
 *  Allows a link to toggle the display of another element or array of
 *  elements on and off. Just set the <tt>rel</tt> attribute to
 *  "toggle[id1,id2,...]" on the link and the href of the link to the
 *  ID of the first element ("#id1").
 *
 *  Options
 *  - effect: This option specifies the effect that should be used when
 *    toggling. The default is "slide", but it can also be set to
 *    "blind", "appear", or "none".
 *  - onLoad: Called after the behavior is initialized. The function is
 *    automatically bound to the behavior (so "this" referes to the
 *    behavior).
 *  - beforeToggle: Called after the link is clicked, but before the effect is
 *    started. The link is passed as the first parameter and the
 *    function is automatically bound to the behavior (so "this"
 *    refers to the behavior).
 *  - afterToggle: Called after the effect is complete. The link is passed as
 *    the first parameter and the function is automatically bound
 *    to the behavior (so "this" refers to the behavior).
**/
Toggle.LinkBehavior = Behavior.create({
  initialize: function(options) {
    var options = options || {};

    this.effect = options.effect || Toggle.DefaultEffect;

    this.onLoad = options.onLoad || Prototype.emptyFunction;
    this.onLoad.bind(this);

    this.beforeToggle = options.beforeToggle || Prototype.emptyFunction;
    this.beforeToggle.bind(this);

    this.afterToggle = options.afterToggle || Prototype.emptyFunction;
    this.afterToggle.bind(this);

    var elements = Toggle.extractToggleObjects(this.element.readAttribute('rel'));
    this.toggleWrappers = elements.map(function(e) { return Toggle.wrapElement(e); });

    this.toggleID = Toggle.extractAnchor(this.element.href);
    this.element.behavior = this; // a bit of a hack
    Toggle.addLink(this.toggleID, this.element);

    this.onLoad(this.element);
  },

  onclick: function() {
    this.toggle();
    return false;
  },

  toggle: function() {
    Toggle.toggle(
      this.toggleWrappers,
      this.effect,
      {
        beforeStart: function() { this.beforeToggle(this.element); }.bind(this),
        afterFinish: function() { this.afterToggle(this.element); }.bind(this)
      }
    );
  }
});
Toggle.links = {};
Toggle.addLink = function(id, element) {
  this.links[id] = this.links[id] || $A();
  this.links[id].push(element);
};

// Automatically toggle associated element if anchor is equal to the ID of the
// link's associated element.
Event.observe(window, 'dom:loaded', function() {
  var anchor = Toggle.extractAnchor(window.location);
  var links = Toggle.links[anchor];
  if (links) {
    var behavior = links.first().behavior;
    behavior.onclick();
  }
});

/**
 * class Toggle.CheckboxBehavior < Behavior
 *
 *  Allows a the selection of a checkbox to toggle an element or group of
 *  elements on and off. Just set the `rel` attribute to "toggle[id1,id2,...]"
 *  on the checkbox.
 *
 *  Options
 *  - invert: When set to true the associated element is hidden when checked.
 *  - effect: This option specifies the effect that should be used when
 *    toggling. The default is "slide", but it can also be set to
 *    "blind", "appear", or "none".
**/
Toggle.CheckboxBehavior = Behavior.create({
  initialize: function(options) {
    var options = options || {};
    this.invert = options.invert;

    var elements = Toggle.extractToggleObjects(this.element.readAttribute('rel'));
    this.toggleWrappers = elements.map(function(e) { return Toggle.wrapElement(e); });

    this.effect = 'none';
    this.toggle();

    this.effect = options.effect || Toggle.DefaultEffect;
  },

  onclick: function(event) {
    this.toggle();
  },

  toggle: function() {
    var method, formElementMethod;

    if (this.invert) {
      method = this.element.checked ? 'hide' : 'show';
      formElementMethod = this.element.checked ? 'disable' : 'enable';
    } else {
      method = this.element.checked ? 'show' : 'hide';
      formElementMethod = this.element.checked ? 'enable' : 'disable';
    }

    Toggle[method](this.toggleWrappers, this.effect);

    // Disable/enable form elements based on whether the container is
    // visible or not.
    this.toggleWrappers.each(function(wrapper) {
      Form.getElements(wrapper).invoke(formElementMethod);
    });
  }
});

/**
 * class Toggle.RadioGroupBehavior < Behavior
 *
 *  Allows you to toggle elements based on the selection of a group of radio
 *  buttons. Just set the <tt>rel</tt> attribute to "toggle[id1,id2,...]" on
 *  each radio button. Radio buttons must be grouped inside a containing
 *  element to which the behavior is applied.
 *
 *  Options
 *  - effect: This option specifies the effect that should be used when
 *    toggling. The default is "slide", but it can also be set to
 *    "blind", "appear", or "none".
**/
Toggle.RadioGroupBehavior = Behavior.create({
  initialize: function(options) {
    var options = options || {};

    this.radioButtons = this.element.select('input[type=radio]');

    this.toggleWrapperIDs = $A();
    this.toggleWrapperIDsFor = {};

    this.radioButtons.each(function(radioButton) {
      var elements = Toggle.extractToggleObjects(radioButton.readAttribute('rel'));
      var ids = elements.invoke('identify');
      var wrapperIDs = elements.map(function(e) { return Toggle.wrapElement(e); }).invoke('identify');
      this.toggleWrapperIDsFor[radioButton.identify()] = wrapperIDs;
      this.toggleWrapperIDs.push(wrapperIDs);
      radioButton.observe('click', this.onRadioButtonClick.bind(this));
    }.bind(this));

    this.toggleWrapperIDs = this.toggleWrapperIDs.flatten().uniq();

    this.effect = "none";
    this.toggle();

    this.effect = options.effect || Toggle.DefaultEffect;
  },

  onRadioButtonClick: function(event) {
    this.toggle();
  },

  toggle: function() {
    var group = this.element;
    var radioButton = this.radioButtons.find(function(b) { return b.checked; });
    var wrapperIDs = this.toggleWrapperIDsFor[radioButton.identify()];
    var partitioned = this.toggleWrapperIDs.partition(function(id) { return wrapperIDs.include(id); });
    Toggle.show(partitioned[0], this.effect);
    Toggle.hide(partitioned[1], this.effect);
  }
});

/**
 * class Toggle.SelectBehavior < Behavior
 *
 *  Allows you to toggle elements based on the selection of a combo box. Just
 *  set the <tt>rel</tt> attribute to "toggle[id1,id2,...]" on the each select
 *  option.
 *
 *  Options
 *  - effect: This option specifies the effect that should be used when
 *    toggling. The default is "slide", but it can also be set to
 *    "blind", "appear", or "none".
**/
Toggle.SelectBehavior = Behavior.create({
  initialize: function(options) {
    var options = options || {};

    var optionElements = this.element.select('option');

    this.toggleWrapperIDs = $A();
    this.toggleWrapperIDsFor = {};

    optionElements.each(function(optionElement) {
      var elements = Toggle.extractToggleObjects(optionElement.readAttribute('rel'));
      var wrapperIDs = elements.map(function(e) { return Toggle.wrapElement(e); }).invoke('identify');
      this.toggleWrapperIDsFor[optionElement.identify()] = wrapperIDs;
      this.toggleWrapperIDs.push(wrapperIDs);
    }.bind(this));

    this.toggleWrapperIDs = this.toggleWrapperIDs.flatten().uniq();

    this.effect = "none";
    this.toggle();

    this.effect = options.effect || Toggle.DefaultEffect;
  },

  onchange: function(event) {
    this.toggle();
  },

  toggle: function() {
    var combo = this.element;
    var option = $(combo.options[combo.selectedIndex]);
    var wrapperIDs = this.toggleWrapperIDsFor[option.identify()];
    var partitioned = this.toggleWrapperIDs.partition(function(id) { return wrapperIDs.include(id); });
    Toggle.show(partitioned[0], this.effect);
    Toggle.hide(partitioned[1], this.effect);
  }
});<|endoftext|>


<commit_before>module('users.timfelgentreff.babelsberg.testsuite').
requires('lively.TestFramework',
         'users.timfelgentreff.babelsberg.constraintinterpreter',
         'users.timfelgentreff.z3.CommandLineZ3').
toRun(function() {

TestCase.subclass('users.timfelgentreff.babelsberg.testsuite.SemanticsTests', {
    fieldEquals: function(o1, o2) {
        if (!o1) return false;
        if (!o2) return false;
        for (var key in o1) {
            if (key[0] !== "$" && key[0] !== "_") {
                if (typeof(o1[key]) == "object") {
                    this.fieldEquals(o2[key], o1[key]);
                } else {
                    if (o1[key] !== o2[key]) return false;
                }
            }
        }
        for (var key in o2) {
            if (typeof(o2[key]) == "object") {
                this.fieldEquals(o2[key], o1[key]);
            } else {
                if (o1[key] !== o2[key]) return false;
            }
        }
        return true;
    },
    one: function(self) {
        return 1.0
    },
    double: function(self) {
        return 2 * self;
    },
    Require_min_balance: function(self, acct, min) {
        always: { acct.balance > min }
    },
    Has_min_balance: function(self, acct, min) {
        return acct.balance > min;
    },
    Point: function(self, x, y) {
        return {x: x, y: y}
    },
    center: function(self) {
        return this.divPtScalar(this.addPt(self.upper_left, self.lower_right), 2);
    },
    addPt: function(self, other) {
        return this.Point(null, self.x + other.x, self.y + other.y);
    },
    divPtScalar: function(self, scale) {
        return this.Point(null, self.x / scale, self.y / scale);
    },
    ptEq: function(self, other) {
        return self.x == other.x && self.y == other.y
    },
    Test: function(self, i) {
        ctx = {i: i};
        bbb.always({
            priority: "medium",
            ctx: {
                ctx: ctx,
                _$_self: this.doitContext || this
            }
        }, function() {
            return ctx.i == 5;;
        });
        return ctx.i + 1
    },
    MutablePointNew: function(self, x, y) {
        return new Object({x: x, y: y});
    },
    WindowNew: function(self) {
        return new Object({window: true});
    },
    CircleNew: function(self) {
        return new Object({circle: true});
    },
    // TODO: others

INSERTHERE

});
});
<commit_msg>add remaining methods<commit_after>module('users.timfelgentreff.babelsberg.testsuite').
requires('lively.TestFramework',
         'users.timfelgentreff.babelsberg.constraintinterpreter',
         'users.timfelgentreff.z3.CommandLineZ3').
toRun(function() {

TestCase.subclass('users.timfelgentreff.babelsberg.testsuite.SemanticsTests', {
    fieldEquals: function(o1, o2) {
        if (!o1) return false;
        if (!o2) return false;
        for (var key in o1) {
            if (key[0] !== "$" && key[0] !== "_") {
                if (typeof(o1[key]) == "object") {
                    this.fieldEquals(o2[key], o1[key]);
                } else {
                    if (o1[key] !== o2[key]) return false;
                }
            }
        }
        for (var key in o2) {
            if (typeof(o2[key]) == "object") {
                this.fieldEquals(o2[key], o1[key]);
            } else {
                if (o1[key] !== o2[key]) return false;
            }
        }
        return true;
    },
    one: function(self) {
        return 1.0
    },
    double: function(self) {
        return 2 * self;
    },
    Require_min_balance: function(self, acct, min) {
        always: { acct.balance > min }
    },
    Has_min_balance: function(self, acct, min) {
        return acct.balance > min;
    },
    Point: function(self, x, y) {
        return {x: x, y: y}
    },
    center: function(self) {
        return this.divPtScalar(this.addPt(self.upper_left, self.lower_right), 2);
    },
    addPt: function(self, other) {
        return this.Point(null, self.x + other.x, self.y + other.y);
    },
    divPtScalar: function(self, scale) {
        return this.Point(null, self.x / scale, self.y / scale);
    },
    ptEq: function(self, other) {
        return self.x == other.x && self.y == other.y
    },
    Test: function(self, i) {
        ctx = {i: i};
        bbb.always({
            priority: "medium",
            ctx: {
                ctx: ctx,
                _$_self: this.doitContext || this
            }
        }, function() {
            return ctx.i == 5;;
        });
        return ctx.i + 1
    },
    MutablePointNew: function(self, x, y) {
        return new Object({x: x, y: y});
    },
    WindowNew: function(self) {
        return new Object({window: true});
    },
    CircleNew: function(self) {
        return new Object({circle: true});
    },
    MakeIdentical: function(self, a, b) {
        var ctx = {a: a, b: b};
        always: { ctx.a === ctx.b }
    },
    Testalwaysxequal5: function(self, x) {
        var ctx = {x: x};
        always: { ctx.x == 5 }
        return ctx.x;
    },
    Testalwaysaequalsbplus3: function(self, a, b) {
        var ctx = {a: a, b: b};
        always: { ctx.a == ctx.b + 3 }
        return ctx.a
    },
    Testipointxequals5: function(self, p) {
        var myp = {x: p.x, y: p.y};
        always: { myp.x == 5 }
        return myp;
    },
    Testpointxequals5: function(self, p) {
        always: { p.x == 5 }
        return p;
    },
    TestXGetsXPlus3ReturnX: function(self, x) {
        x = x + 3;
        return x;
    },

INSERTHERE

});
});
<|endoftext|>


<commit_before>/**
 * UndoManager.js
 *
 * Copyright 2009, Moxiecode Systems AB
 * Released under LGPL License.
 *
 * License: http://tinymce.moxiecode.com/license
 * Contributing: http://tinymce.moxiecode.com/contributing
 */

(function(tinymce) {
	var Dispatcher = tinymce.util.Dispatcher;

	/**
	 * This class handles the undo/redo history levels for the editor. Since the build in undo/redo has major drawbacks a custom one was needed.
	 *
	 * @class tinymce.UndoManager
	 */
	tinymce.UndoManager = function(editor) {
		var self, index = 0, data = [];

		function getContent() {
			return tinymce.trim(editor.getContent({format : 'raw', no_events : 1}));
		};

		return self = {
			/**
			 * State if the user is currently typing or not. This will add a typing operation into one undo
			 * level instead of one new level for each keystroke.
			 *
			 * @field {Boolean} typing
			 */
			typing : false,

			/**
			 * This event will fire each time a new undo level is added to the undo manager.
			 *
			 * @event onAdd
			 * @param {tinymce.UndoManager} sender UndoManager instance that got the new level.
			 * @param {Object} level The new level object containing a bookmark and contents.
			 */
			onAdd : new Dispatcher(self),

			/**
			 * This event will fire when the user make an undo of a change.
			 *
			 * @event onUndo
			 * @param {tinymce.UndoManager} sender UndoManager instance that got the new level.
			 * @param {Object} level The old level object containing a bookmark and contents.
			 */
			onUndo : new Dispatcher(self),

			/**
			 * This event will fire when the user make an redo of a change.
			 *
			 * @event onRedo
			 * @param {tinymce.UndoManager} sender UndoManager instance that got the new level.
			 * @param {Object} level The old level object containing a bookmark and contents.
			 */
			onRedo : new Dispatcher(self),

			/**
			 * Stores away a bookmark to be used when performing an undo action so that the selection is before
			 * the change has been made.
			 *
			 * @method beforeChange
			 */
			beforeChange : function() {
				// Set before bookmark on previous level
				if (data[index])
					data[index].beforeBookmark = editor.selection.getBookmark(2, true);
			},

			/**
			 * Adds a new undo level/snapshot to the undo list.
			 *
			 * @method add
			 * @param {Object} l Optional undo level object to add.
			 * @return {Object} Undo level that got added or null it a level wasn't needed.
			 */
			add : function(level) {
				var i, settings = editor.settings, lastLevel;

				level = level || {};
				level.content = getContent();

				// Add undo level if needed
				lastLevel = data[index];
				if (lastLevel && lastLevel.content == level.content)
					return null;

				// Time to compress
				if (settings.custom_undo_redo_levels) {
					if (data.length > settings.custom_undo_redo_levels) {
						for (i = 0; i < data.length - 1; i++)
							data[i] = data[i + 1];

						data.length--;
						index = data.length;
					}
				}

				// Get a non intrusive normalized bookmark
				level.bookmark = editor.selection.getBookmark(2, true);

				// Crop array if needed
				if (index < data.length - 1)
					data.length = index + 1;

				data.push(level);
				index = data.length - 1;

				self.onAdd.dispatch(self, level);
				editor.isNotDirty = 0;

				return level;
			},

			/**
			 * Undoes the last action.
			 *
			 * @method undo
			 * @return {Object} Undo level or null if no undo was performed.
			 */
			undo : function() {
				var level, i;

				if (self.typing) {
					self.add();
					self.typing = false;
				}

				if (index > 0) {
					level = data[--index];

					editor.setContent(level.content, {format : 'raw'});
					editor.selection.moveToBookmark(level.beforeBookmark);

					self.onUndo.dispatch(self, level);
				}

				return level;
			},

			/**
			 * Redoes the last action.
			 *
			 * @method redo
			 * @return {Object} Redo level or null if no redo was performed.
			 */
			redo : function() {
				var level;

				if (index < data.length - 1) {
					level = data[++index];

					editor.setContent(level.content, {format : 'raw'});
					editor.selection.moveToBookmark(level.bookmark);

					self.onRedo.dispatch(self, level);
				}

				return level;
			},

			/**
			 * Removes all undo levels.
			 *
			 * @method clear
			 */
			clear : function() {
				data = [];
				index = 0;
				self.typing = false;
			},

			/**
			 * Returns true/false if the undo manager has any undo levels.
			 *
			 * @method hasUndo
			 * @return {Boolean} true/false if the undo manager has any undo levels.
			 */
			hasUndo : function() {
				return index > 0 || this.typing;
			},

			/**
			 * Returns true/false if the undo manager has any redo levels.
			 *
			 * @method hasRedo
			 * @return {Boolean} true/false if the undo manager has any redo levels.
			 */
			hasRedo : function() {
				return index < data.length - 1 && !this.typing;
			}
		};
	};
})(tinymce);
<commit_msg>Fixed issue with bookmarks not being correct on a redo.<commit_after>/**
 * UndoManager.js
 *
 * Copyright 2009, Moxiecode Systems AB
 * Released under LGPL License.
 *
 * License: http://tinymce.moxiecode.com/license
 * Contributing: http://tinymce.moxiecode.com/contributing
 */

(function(tinymce) {
	var Dispatcher = tinymce.util.Dispatcher;

	/**
	 * This class handles the undo/redo history levels for the editor. Since the build in undo/redo has major drawbacks a custom one was needed.
	 *
	 * @class tinymce.UndoManager
	 */
	tinymce.UndoManager = function(editor) {
		var self, index = 0, data = [], beforeBookmark;

		function getContent() {
			return tinymce.trim(editor.getContent({format : 'raw', no_events : 1}));
		};

		return self = {
			/**
			 * State if the user is currently typing or not. This will add a typing operation into one undo
			 * level instead of one new level for each keystroke.
			 *
			 * @field {Boolean} typing
			 */
			typing : false,

			/**
			 * This event will fire each time a new undo level is added to the undo manager.
			 *
			 * @event onAdd
			 * @param {tinymce.UndoManager} sender UndoManager instance that got the new level.
			 * @param {Object} level The new level object containing a bookmark and contents.
			 */
			onAdd : new Dispatcher(self),

			/**
			 * This event will fire when the user make an undo of a change.
			 *
			 * @event onUndo
			 * @param {tinymce.UndoManager} sender UndoManager instance that got the new level.
			 * @param {Object} level The old level object containing a bookmark and contents.
			 */
			onUndo : new Dispatcher(self),

			/**
			 * This event will fire when the user make an redo of a change.
			 *
			 * @event onRedo
			 * @param {tinymce.UndoManager} sender UndoManager instance that got the new level.
			 * @param {Object} level The old level object containing a bookmark and contents.
			 */
			onRedo : new Dispatcher(self),

			/**
			 * Stores away a bookmark to be used when performing an undo action so that the selection is before
			 * the change has been made.
			 *
			 * @method beforeChange
			 */
			beforeChange : function() {
				beforeBookmark = editor.selection.getBookmark(2, true);
			},

			/**
			 * Adds a new undo level/snapshot to the undo list.
			 *
			 * @method add
			 * @param {Object} l Optional undo level object to add.
			 * @return {Object} Undo level that got added or null it a level wasn't needed.
			 */
			add : function(level) {
				var i, settings = editor.settings, lastLevel;

				level = level || {};
				level.content = getContent();

				// Add undo level if needed
				lastLevel = data[index];
				if (lastLevel && lastLevel.content == level.content)
					return null;

				// Set before bookmark on previous level
				if (data[index])
					data[index].beforeBookmark = beforeBookmark;

				// Time to compress
				if (settings.custom_undo_redo_levels) {
					if (data.length > settings.custom_undo_redo_levels) {
						for (i = 0; i < data.length - 1; i++)
							data[i] = data[i + 1];

						data.length--;
						index = data.length;
					}
				}

				// Get a non intrusive normalized bookmark
				level.bookmark = editor.selection.getBookmark(2, true);

				// Crop array if needed
				if (index < data.length - 1)
					data.length = index + 1;

				data.push(level);
				index = data.length - 1;

				self.onAdd.dispatch(self, level);
				editor.isNotDirty = 0;

				return level;
			},

			/**
			 * Undoes the last action.
			 *
			 * @method undo
			 * @return {Object} Undo level or null if no undo was performed.
			 */
			undo : function() {
				var level, i;

				if (self.typing) {
					self.add();
					self.typing = false;
				}

				if (index > 0) {
					level = data[--index];

					editor.setContent(level.content, {format : 'raw'});
					editor.selection.moveToBookmark(level.beforeBookmark);

					self.onUndo.dispatch(self, level);
				}

				return level;
			},

			/**
			 * Redoes the last action.
			 *
			 * @method redo
			 * @return {Object} Redo level or null if no redo was performed.
			 */
			redo : function() {
				var level;

				if (index < data.length - 1) {
					level = data[++index];

					editor.setContent(level.content, {format : 'raw'});
					editor.selection.moveToBookmark(level.bookmark);

					self.onRedo.dispatch(self, level);
				}

				return level;
			},

			/**
			 * Removes all undo levels.
			 *
			 * @method clear
			 */
			clear : function() {
				data = [];
				index = 0;
				self.typing = false;
			},

			/**
			 * Returns true/false if the undo manager has any undo levels.
			 *
			 * @method hasUndo
			 * @return {Boolean} true/false if the undo manager has any undo levels.
			 */
			hasUndo : function() {
				return index > 0 || this.typing;
			},

			/**
			 * Returns true/false if the undo manager has any redo levels.
			 *
			 * @method hasRedo
			 * @return {Boolean} true/false if the undo manager has any redo levels.
			 */
			hasRedo : function() {
				return index < data.length - 1 && !this.typing;
			}
		};
	};
})(tinymce);
<|endoftext|>


<commit_before>const {
  getMajor,
  isLessThan,
  rangify,
  sortVersions,
} = require('../../../../versioning/semver');

module.exports = {
  getRollbackUpdate,
};

function getRollbackUpdate(config, versions) {
  const { packageFile, depName, currentVersion } = config;
  const lessThanVersions = versions.filter(version =>
    isLessThan(version, currentVersion)
  );
  // istanbul ignore if
  if (!lessThanVersions.length) {
    logger.warn(
      { packageFile, depName, currentVersion },
      'Missing version has nothing to roll back to'
    );
    return [];
  }
  logger.info(
    { packageFile, depName, currentVersion },
    `Current version not found - rolling back`
  );
  lessThanVersions.sort(sortVersions);
  const toVersion = lessThanVersions.pop();
  let fromVersion;
  const newVersion = rangify(config, currentVersion, fromVersion, toVersion);
  return {
    type: 'rollback',
    branchName:
      '{{{branchPrefix}}}rollback-{{{depNameSanitized}}}-{{{newVersionMajor}}}.x',
    commitMessageAction: 'Roll back',
    isRollback: true,
    newVersion,
    newVersionMajor: getMajor(toVersion),
    semanticCommitType: 'fix',
    unpublishable: false,
  };
}
<commit_msg>logs: info not warn for no rollback<commit_after>const {
  getMajor,
  isLessThan,
  rangify,
  sortVersions,
} = require('../../../../versioning/semver');

module.exports = {
  getRollbackUpdate,
};

function getRollbackUpdate(config, versions) {
  const { packageFile, depName, currentVersion } = config;
  const lessThanVersions = versions.filter(version =>
    isLessThan(version, currentVersion)
  );
  // istanbul ignore if
  if (!lessThanVersions.length) {
    logger.info(
      { packageFile, depName, currentVersion },
      'Missing version has nothing to roll back to'
    );
    return [];
  }
  logger.info(
    { packageFile, depName, currentVersion },
    `Current version not found - rolling back`
  );
  lessThanVersions.sort(sortVersions);
  const toVersion = lessThanVersions.pop();
  let fromVersion;
  const newVersion = rangify(config, currentVersion, fromVersion, toVersion);
  return {
    type: 'rollback',
    branchName:
      '{{{branchPrefix}}}rollback-{{{depNameSanitized}}}-{{{newVersionMajor}}}.x',
    commitMessageAction: 'Roll back',
    isRollback: true,
    newVersion,
    newVersionMajor: getMajor(toVersion),
    semanticCommitType: 'fix',
    unpublishable: false,
  };
}
<|endoftext|>


<commit_before>'use strict'

const upload = require('multer')({dest: 'tmp/uploads'});
const imgur = require('imgur');
const path = require('path');
const fs = require('fs');

module.exports.index = (req, res) => {
    res.render('sendphoto');
};

module.exports.new = (req, res) => {
    let db;
    let imgurPath = '/Users/Micah/workspace/node-webserver/' + `${req.file.path}`;
    console.log(imgurPath);
    imgur.uploadFile(imgurPath)
        .then(function (json) {
            console.log(json.data.link);
            let imageLink = {
                link: json.data.link
            }
            db.collection('image').insertOne(imageLink, (err, result) => {
                console.log(imageLink);
            });
            fs.unlink(imgurPath, (err) => {
                if (err) throw err;
            });
        })
        .catch(function (err) {
            console.error(err.message);
        });
    res.send('
Thanks for sharing your photo!!
');
};
<commit_msg>commenting code<commit_after>'use strict'

const upload = require('multer')({dest: 'tmp/uploads'});
const imgur = require('imgur');
const path = require('path');
const fs = require('fs');

module.exports.index = (req, res) => {
    res.render('sendphoto');
};

module.exports.new = (req, res) => {
    let db;
    let imgurPath = '/Users/Micah/workspace/node-webserver/' + `${req.file.path}`;
    console.log(imgurPath);
    // Uploading image to imgur
    imgur.uploadFile(imgurPath)
        // it will resolve a promise with a link to the stored image
        .then(function (json) {
            // Promise returns link to image at imgur
            console.log(json.data.link);
            let imageLink = {
                link: json.data.link
            }
            // Storing image at mongodb
            db.collection('image').insertOne(imageLink, (err, result) => {
                console.log(imageLink);
            });
            // Removing image from local storage
            fs.unlink(imgurPath, (err) => {
                if (err) throw err;
            });
        })
        .catch(function (err) {
            console.error(err.message);
        });
    // Sending confirmation to DOM
    res.send('
Thanks for sharing your photo!!
');
};
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2018 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @fileoverview (Deprecated) Events fired as a result of UI actions in
 * Blockly's editor.
 * @author fraser@google.com (Neil Fraser)
 */
'use strict';

goog.provide('Blockly.Events.Ui');

goog.require('Blockly.Events');
goog.require('Blockly.Events.UiBase');
goog.require('Blockly.registry');
goog.require('Blockly.utils.object');

goog.requireType('Blockly.Block');

/**
 * Class for a UI event.
 * @param {?Blockly.Block=} opt_block The affected block.  Null for UI events
 *     that do not have an associated block.  Undefined for a blank event.
 * @param {string=} opt_element One of 'selected', 'comment', 'mutatorOpen',
 *     etc.
 * @param {*=} opt_oldValue Previous value of element.
 * @param {*=} opt_newValue New value of element.
 * @extends {Blockly.Events.UiBase}
 * @deprecated December 2020. Instead use a more specific UI event.
 * @constructor
 */
Blockly.Events.Ui = function(opt_block, opt_element, opt_oldValue,
    opt_newValue) {
  var workspaceId = opt_block ? opt_block.workspace.id : undefined;
  Blockly.Events.Ui.superClass_.constructor.call(this, workspaceId);

  this.blockId = opt_block ? opt_block.id : null;
  this.element = typeof opt_element == 'undefined' ? '' : opt_element;
  this.oldValue = typeof opt_oldValue == 'undefined' ? '' : opt_oldValue;
  this.newValue = typeof opt_newValue == 'undefined' ? '' : opt_newValue;
};
Blockly.utils.object.inherits(Blockly.Events.Ui, Blockly.Events.UiBase);

/**
 * Type of this event.
 * @type {string}
 */
Blockly.Events.Ui.prototype.type = Blockly.Events.UI;

/**
 * Encode the event as JSON.
 * @return {!Object} JSON representation.
 */
Blockly.Events.Ui.prototype.toJson = function() {
  var json = Blockly.Events.Ui.superClass_.toJson.call(this);
  json['element'] = this.element;
  if (this.newValue !== undefined) {
    json['newValue'] = this.newValue;
  }
  if (this.blockId) {
    json['blockId'] = this.blockId;
  }
  return json;
};

/**
 * Decode the JSON event.
 * @param {!Object} json JSON representation.
 */
Blockly.Events.Ui.prototype.fromJson = function(json) {
  Blockly.Events.Ui.superClass_.fromJson.call(this, json);
  this.element = json['element'];
  this.newValue = json['newValue'];
  this.blockId = json['blockId'];
};

Blockly.registry.register(Blockly.registry.Type.EVENT, Blockly.Events.UI,
    Blockly.Events.Ui);<commit_msg>Migrate core/events/events_ui.js to ES6 const/let<commit_after>/**
 * @license
 * Copyright 2018 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @fileoverview (Deprecated) Events fired as a result of UI actions in
 * Blockly's editor.
 * @author fraser@google.com (Neil Fraser)
 */
'use strict';

goog.provide('Blockly.Events.Ui');

goog.require('Blockly.Events');
goog.require('Blockly.Events.UiBase');
goog.require('Blockly.registry');
goog.require('Blockly.utils.object');

goog.requireType('Blockly.Block');

/**
 * Class for a UI event.
 * @param {?Blockly.Block=} opt_block The affected block.  Null for UI events
 *     that do not have an associated block.  Undefined for a blank event.
 * @param {string=} opt_element One of 'selected', 'comment', 'mutatorOpen',
 *     etc.
 * @param {*=} opt_oldValue Previous value of element.
 * @param {*=} opt_newValue New value of element.
 * @extends {Blockly.Events.UiBase}
 * @deprecated December 2020. Instead use a more specific UI event.
 * @constructor
 */
Blockly.Events.Ui = function(opt_block, opt_element, opt_oldValue,
    opt_newValue) {
  const workspaceId = opt_block ? opt_block.workspace.id : undefined;
  Blockly.Events.Ui.superClass_.constructor.call(this, workspaceId);

  this.blockId = opt_block ? opt_block.id : null;
  this.element = typeof opt_element == 'undefined' ? '' : opt_element;
  this.oldValue = typeof opt_oldValue == 'undefined' ? '' : opt_oldValue;
  this.newValue = typeof opt_newValue == 'undefined' ? '' : opt_newValue;
};
Blockly.utils.object.inherits(Blockly.Events.Ui, Blockly.Events.UiBase);

/**
 * Type of this event.
 * @type {string}
 */
Blockly.Events.Ui.prototype.type = Blockly.Events.UI;

/**
 * Encode the event as JSON.
 * @return {!Object} JSON representation.
 */
Blockly.Events.Ui.prototype.toJson = function() {
  const json = Blockly.Events.Ui.superClass_.toJson.call(this);
  json['element'] = this.element;
  if (this.newValue !== undefined) {
    json['newValue'] = this.newValue;
  }
  if (this.blockId) {
    json['blockId'] = this.blockId;
  }
  return json;
};

/**
 * Decode the JSON event.
 * @param {!Object} json JSON representation.
 */
Blockly.Events.Ui.prototype.fromJson = function(json) {
  Blockly.Events.Ui.superClass_.fromJson.call(this, json);
  this.element = json['element'];
  this.newValue = json['newValue'];
  this.blockId = json['blockId'];
};

Blockly.registry.register(Blockly.registry.Type.EVENT, Blockly.Events.UI,
    Blockly.Events.Ui);<|endoftext|>