<commit_before>function AppPackageCalendar() {
}

/* ********************************************************** */

AppPackageCalendar.prototype = {
    delayed:false, // whether to load on start
    selectedDate:0,
    selectedTime:0,
    calId:0,
    moment:moment(),
    currentEvent:{},
  /* ********************************************************** */

    init:function() { //default function

       /*** set up calendar - project relationship ******/
        $('#calendar_id').change(function(){
            var cal_id=$(this).val();
            var project_option = false;
              for (var i =0 ; i<$.app.mc.allCalendars.length ; i++ )
                  if (cal_id == $.app.mc.allCalendars[i].calendar_id)
                      if ($.app.mc.allCalendars[i].project_option_id == $.app.mc.types_boolean.true)
                          project_option = true;

            $('#project_id').prop('disabled', ! project_option);

        });

        $('#booking-all_day_option_id').change(function(){
            var cal_id = $('#calendar_id').val();

            if (cal_id != 0 )
            {
              var r = $.app.cal.getCalendarRecord(cal_id);

            }
        });

        $('#delete-button').click(function(){
            $.app.cal.deleteEvent();
        });
        /*** set up tree view  ******/
        $('#tree').treeview({
            showCheckbox:true,
            data: $.app.mc.tree,
            highlightSelected: false,
            levels:0,
            showTags:true,
            onNodeChecked: function(event, data) {
              $.app.cal.subscribe(data);
            },
            onNodeUnchecked: function(event, data) {
              $.app.cal.unsubscribe(data);
            }
        });
         $('#project_id').prop('disabled', true);
        return true;

    	// do some init like set the fields to an initial value

    },
  /* ********************************************************** */
  deleteEvent: function(){
        if (! this.currentEvent.editable)
            return false;
        if (confirm('Click OK if you are sure.'))
        {
            var form = this.getDataForm();
            form.ee_id = this.currentEvent.event_entry_id;
            $.ajax({
              type: "POST",
              url: $.app.mc.deleteEventUri,
              data: form,
              success: function(data,status,xhr){
               var type= 'success';
               $('#full-calendar').fullCalendar('refetchEvents');
               $.app.cal.resetFields();
               $('#eventShowModal').modal('toggle');
               message = 'Event deleted';
               $.bootstrapGrowl(message , {'type':type}, 1000 );

              },
              dataType: 'json'
            });

        }

  },
  /* ********************************************************** */
  getDataForm:function(){
      return {
            '_csrf' : $.app.mc.csrfToken
          };
    } ,

  /* ********************************************************** */
  getCalendarRecord:function(cal_id)
  {
      var record = {};
      for(var i =0 ; i < $.app.mc.allCalendars.length;i++)
        if ($.app.mc.allCalendars[i].calendar_id == cal_id )
          record = $.app.mc.allCalendars[i];

      return record;

  },
  /* ********************************************************** */

  /* ********************************************************** */
    subscribe:function(data){
          var form = this.getDataForm();
          form.cal_id = data.cal_id;
          $.app.cal.calId = data.cal_id;
          $.ajax({
              type: "POST",
              url: $.app.mc.subscribeUri,
              data: form,
              success: function(data,status,xhr){
                 $('#full-calendar').fullCalendar('refetchEvents');
              },
              dataType: 'json'
            });
    },
  /* ********************************************************** */

    unsubscribe:function(data){
          var form = this.getDataForm();
          form.cal_id = data.cal_id;
          $.app.cal.calId = data.cal_id;
          $.ajax({
              type: "POST",
              url: $.app.mc.unsubscribeUri,
              data: form,
              success: function(data,status,xhr){
                  $('#full-calendar').fullCalendar('removeEvents', function(event) {
                        return event.cal_id == $.app.cal.calId;
              });

              },
              dataType: 'json'
            });
    },
  /* ********************************************************** */

    dayClick:function(date, jsEvent, view)
    {
        this.selectedDate = date.format('DD-MM-YYYY');
        this.selectedTime = date.format('LT')
        //$('#start_date').datetimepicker('date' , this.selectedDate);
        $('#start_date-disp').val(this.selectedDate);
        $('#start_date').val(this.selectedDate);
        $('#start_time').val(this.selectedTime);
        $('#end_time').val(date.add(1, 'hours').format('LT'));
        $('#booking-title').val('');
        $('#eventModal').modal();

    },
/* ********************************************************** */

/* ********************************************************** */
    eventMouseover:function(event, jsEvent, view,that)
    {

     var div = this._popoverDiv(event);
     $("body").append(div);
    $(that).mouseover(function(e) {
         // $(that).css('z-index', 10000);
          $('.popover').fadeIn('10');
          $('.popover').fadeTo('10', 1.9);
      }).mousemove(function(e) {
          $('.popover').css('top', e.pageY + 10);
          $('.popover').css('left', e.pageX + 20);
      }).mouseout(function(e){

      });

    },
/* ********************************************************** */

  eventMouseout:function(event, jsEvent, view)
    {
      $('.popover').remove();
    },
/* ********************************************************** */
  eventDrop:function(event, delta, revertFunc, jsEvent, ui, view )
  {

    cal = this.getCalendarRecord(event.calendar_id);
    event.start.add(event.start._data);
    event.end.add(event.end._data);
    var form = this._buildUpdateEventForm(event);

     $.ajax({
              type: "POST",
              url: $.app.mc.updateEventUri,
              data: form,
              success: function(data, textStatus, jqXHR){return $.app.cal._updateEvent( data, textStatus, jqXHR,revertFunc)},
              dataType: 'JSON'
            });

  },
  /* ********************************************************** */

  _buildUpdateEventForm: function(event)
  {
      var form ={};
      form.pk = this.getDataForm();
      form.pk.start_date = event.start.format($.app.mc.momentUkDateFormat);
      form.pk.start_time = event.start.format($.app.mc.momentUkTimeFormat);
      form.pk.end_date = event.end.format($.app.mc.momentUkDateFormat);
      form.pk.end_time = event.end.format($.app.mc.momentUkTimeFormat);
      form.pk.ee_id = event.event_entry_id;
      return form;
  },

  /* ********************************************************** */
  eventResize:function(event, delta, revertFunc, jsEvent, ui, view )
  {

    event.end.add(event.end._data);
    var form = this._buildUpdateEventForm(event);

    $.ajax({
              type: "POST",
              url: $.app.mc.updateEventUri,
              data: form,
              success: function(data, textStatus, jqXHR){return $.app.cal._updateEvent( data, textStatus, jqXHR,revertFunc)},
              dataType: 'JSON'
            });
  },
   /* ********************************************************** */
  resetFields: function()
    {
        $('#span-event-title').html('')
        $('#span-event-description').html('');
        $('#span-event-date').html('');
        $('#span-event-from').html('');
        $('#span-event-to').html('');

         $('#span-event-create').html('');
         $('#span-event-create-date').html('');
    },
  /* ********************************************************** */
  eventClick:function(event, jsEvent, view)
    {

        this.currentEvent = event;
        $('#span-event-title').editable('destroy');
        $('#span-event-description').editable('destroy');
        $('#span-event-calendar').editable('destroy');
         $('#span-event-project').editable('destroy');

        $('#span-event-title').html(event.title);
        $('#span-event-description').html(event.description);
        $('#span-event-date').html(moment(event.start).format('L'));
        $('#span-event-from').html(moment(event.start).format('HH:mm'));
        $('#span-event-to').html(moment(event.end).format('HH:mm'));

         $('#span-event-create').html(event.create_name);
         $('#span-event-create-date').html(event.created_at);

         if (event.editable)
            $('#delete-button').show();
         else
            $('#delete-button').hide();

        var form = this._buildUpdateEventForm(event).pk;
           $('#span-event-title').editable({
              type: 'text',
              value: event.title,
              pk: form,
              name:'title',
              placement:'bottom',
              url: $.app.mc.updateEventUri,
              title: 'Event title',
              disabled: ! (event.editable),
              success: function(response, newValue) {
                  $('#full-calendar').fullCalendar('refetchEvents');
              }
          });
           $('#span-event-description').editable({
              type: 'textarea',
              value: event.event_entry_description,
              pk: form,
              name:'description',
              placement:'bottom',
              url: $.app.mc.updateEventUri,
              disabled: ! (event.editable),
              title: 'Event description',
              success: function(response, newValue) {
                  $('#full-calendar').fullCalendar('refetchEvents');

              }
          });
           $('#span-event-calendar').editable({
              type: 'select',
              value: event.cal_id,
              pk: form,
              source: function()
              {
                  var a = [];
                  for (var i =0 ; i < $.app.mc.myCalendars.length ; i++ )
                    a.push({'value': $.app.mc.myCalendars[i].calendar_id , 'text':$.app.mc.myCalendars[i].calendar_title });
                  return a;
              },
              name:'calendar_id',
              placement:'bottom',
              url: $.app.mc.updateEventUri,
              disabled: ! (event.editable),
              title: 'Event Calendar',
              success: function(response, newValue) {
                    $.app.cal._eventClick(response, newValue)

              }
          });
           $('#span-event-project').editable({
              type: 'select',
              value: event.project_id,
              pk: form,
              source: function()
              {
                  var a = [];
                  for (var i =0 ; i < $.app.mc.myProjects.length ; i++ )
                    a.push({'value': $.app.mc.myProjects[i].project_id , 'text':$.app.mc.myProjects[i].project_title });
                  return a;
              },
              name:'project_id',
              placement:'bottom',
              url: $.app.mc.updateEventUri,
              disabled: ! (event.editable),
              title: 'Event Project',
              success: function(response, newValue) {
                    $.app.cal._eventClick(response, newValue)
              }
            });

             $('#span-event-date').editable({
                    type:'date',
                    placement:'bottom',
                    format: 'yyyy-mm-dd',
                    url: $.app.mc.updateEventUri,
                    disabled: true, //! (event.editable),
                    viewformat: 'dd/mm/yyyy',
                    success: function(response, newValue) {
                       $.app.cal._eventClick(response, newValue)
                    },
                    datepicker: {
                        weekStart: 1
                    }
              });

        $('#eventShowModal').modal();

    },
    /* ********************************************************** */

    /* ********************************************************** */
    _eventClick:function(response , newValue )
    {
           response = jQuery.parseJSON( response );
            if (response.error)
            {
              var title = 'There is a problem: ';
              var message = '';
              for(var i=0 ; i < response.message.length ; i++)
                  message += response.message[i] + '  ';

              $('#spanShowResponse').css('color','#990000');
              $('#spanShowTitle').html(title);
              $('#spanShowResponse').html(message);
            }
            else
                $('#full-calendar').fullCalendar('refetchEvents');

            return true;

    },
    /* ********************************************************** */
    createEvent: function ()
    {
           var values = {};
            $.each($('#frmBookingForm').serializeArray(), function(i, field) {
                values[field.name] = field.value;

            });
          $.ajax({
              type: "POST",
              url: $.app.mc.createEventUri,
              data: values,
              success: function(data, textStatus, jqXHR){return $.app.cal._createEvent( data, textStatus, jqXHR)},
              dataType: 'JSON'
            });
    } ,
/* ********************************************************** */
  _createEvent: function ( data, textStatus, jqXHR)
  {
    var response = '';
    var title = '';

    if (data.error)
    {
      title = 'There is a problem: ';
      for(var i=0 ; i < data.message.length ; i++)
        response += data.message[i] + '  ';
        $('#spanResponse').css('color','#990000');

    }
    if (! data.error)
    {
        $('#eventModal').modal('hide');
        $('#full-calendar').fullCalendar('renderEvent', data.message);
        response = 'Event updated.';
    }
    $('#spanTitle').html(title);
    $('#spanResponse').html(response);
  },
  /* ********************************************************** */
  _updateEvent: function ( data, textStatus, jqXHR,revertFunc)
  {
    var type= 'success';
    var message = '';
    for(var i =0 ; i < data.message.length ; i++)
        message += data.message[i];

    if (data.error)
    {
        type = 'danger'
        revertFunc();
    }
    else
        message = 'Event updated';
        $.bootstrapGrowl(message , {'type':type}, 1000 );

  },
/* ********************************************************** */

  drop:function(date, jsEvent, ui, resourceId , that)
  {

  },
  /* ********************************************************** */

  /* ********************************************************** */
  _popoverDiv:function(event)
  {
      var div = '';
      var start =moment(event.start).format('LT');
      var end = moment(event.end).format('LT');
      var date = moment(event.start).format('LL')
      div += '
';
      div += '
';
      div +=  date;
      div +=  ' ' + start + ' to ' + end;
      div += '
';
      div += '
';
      div += '
' + event.title +'
';

      div +=  'From: ' + start;
      div += ' to: '+ end ;
      div += '
';
      div += event.calendar_title;
      div += '
';
      div += event.project_collection_title;
      div += '
';
      div += '';
      div += 'Created by ' + event.create_name + ' on ' + event.created_at;
      div += '';
      div += '
';
      div += '
';

      return div;

  }

/* ********************************************************** */

};

$.app.cal = new AppPackageCalendar();

/* ********************************************************** */

<commit_msg>Tidied up some formatting with calendar event display<commit_after>function AppPackageCalendar() {
}

/* ********************************************************** */

AppPackageCalendar.prototype = {
    delayed:false, // whether to load on start
    selectedDate:0,
    selectedTime:0,
    calId:0,
    moment:moment(),
    currentEvent:{},
  /* ********************************************************** */

    init:function() { //default function

       /*** set up calendar - project relationship ******/
        $('#calendar_id').change(function(){
            var cal_id=$(this).val();
            var project_option = false;
              for (var i =0 ; i<$.app.mc.allCalendars.length ; i++ )
                  if (cal_id == $.app.mc.allCalendars[i].calendar_id)
                      if ($.app.mc.allCalendars[i].project_option_id == $.app.mc.types_boolean.true)
                          project_option = true;

            $('#project_id').prop('disabled', ! project_option);

        });

        $('#booking-all_day_option_id').change(function(){
            var cal_id = $('#calendar_id').val();

            if (cal_id != 0 )
            {
              var r = $.app.cal.getCalendarRecord(cal_id);

            }
        });

        $('#delete-button').click(function(){
            $.app.cal.deleteEvent();
        });
        /*** set up tree view  ******/
        $('#tree').treeview({
            showCheckbox:true,
            data: $.app.mc.tree,
            highlightSelected: false,
            levels:0,
            showTags:true,
            onNodeChecked: function(event, data) {
              $.app.cal.subscribe(data);
            },
            onNodeUnchecked: function(event, data) {
              $.app.cal.unsubscribe(data);
            }
        });
         $('#project_id').prop('disabled', true);
        return true;

    	// do some init like set the fields to an initial value

    },
  /* ********************************************************** */
  deleteEvent: function(){
        if (! this.currentEvent.editable)
            return false;
        if (confirm('Click OK if you are sure.'))
        {
            var form = this.getDataForm();
            form.ee_id = this.currentEvent.event_entry_id;
            $.ajax({
              type: "POST",
              url: $.app.mc.deleteEventUri,
              data: form,
              success: function(data,status,xhr){
               var type= 'success';
               $('#full-calendar').fullCalendar('refetchEvents');
               $.app.cal.resetFields();
               $('#eventShowModal').modal('toggle');
               message = 'Event deleted';
               $.bootstrapGrowl(message , {'type':type}, 1000 );

              },
              dataType: 'json'
            });

        }

  },
  /* ********************************************************** */
  getDataForm:function(){
      return {
            '_csrf' : $.app.mc.csrfToken
          };
    } ,

  /* ********************************************************** */
  getCalendarRecord:function(cal_id)
  {
      var record = {};
      for(var i =0 ; i < $.app.mc.allCalendars.length;i++)
        if ($.app.mc.allCalendars[i].calendar_id == cal_id )
          record = $.app.mc.allCalendars[i];

      return record;

  },
  /* ********************************************************** */

  /* ********************************************************** */
    subscribe:function(data){
          var form = this.getDataForm();
          form.cal_id = data.cal_id;
          $.app.cal.calId = data.cal_id;
          $.ajax({
              type: "POST",
              url: $.app.mc.subscribeUri,
              data: form,
              success: function(data,status,xhr){
                 $('#full-calendar').fullCalendar('refetchEvents');
              },
              dataType: 'json'
            });
    },
  /* ********************************************************** */

    unsubscribe:function(data){
          var form = this.getDataForm();
          form.cal_id = data.cal_id;
          $.app.cal.calId = data.cal_id;
          $.ajax({
              type: "POST",
              url: $.app.mc.unsubscribeUri,
              data: form,
              success: function(data,status,xhr){
                  $('#full-calendar').fullCalendar('removeEvents', function(event) {
                        return event.cal_id == $.app.cal.calId;
              });

              },
              dataType: 'json'
            });
    },
  /* ********************************************************** */

    dayClick:function(date, jsEvent, view)
    {
        this.selectedDate = date.format('DD-MM-YYYY');
        this.selectedTime = date.format('LT')
        //$('#start_date').datetimepicker('date' , this.selectedDate);
        $('#start_date-disp').val(this.selectedDate);
        $('#start_date').val(this.selectedDate);
        $('#start_time').val(this.selectedTime);
        $('#end_time').val(date.add(1, 'hours').format('LT'));
        $('#booking-title').val('');
        $('#eventModal').modal();

    },
/* ********************************************************** */

/* ********************************************************** */
    eventMouseover:function(event, jsEvent, view,that)
    {

     var div = this._popoverDiv(event);
     $("body").append(div);
    $(that).mouseover(function(e) {
         // $(that).css('z-index', 10000);
          $('.popover').fadeIn('10');
          $('.popover').fadeTo('10', 1.9);
      }).mousemove(function(e) {
          $('.popover').css('top', e.pageY + 10);
          $('.popover').css('left', e.pageX + 20);
      }).mouseout(function(e){

      });

    },
/* ********************************************************** */

  eventMouseout:function(event, jsEvent, view)
    {
      $('.popover').remove();
    },
/* ********************************************************** */
  eventDrop:function(event, delta, revertFunc, jsEvent, ui, view )
  {

    cal = this.getCalendarRecord(event.calendar_id);
    event.start.add(event.start._data);
    event.end.add(event.end._data);
    var form = this._buildUpdateEventForm(event);

     $.ajax({
              type: "POST",
              url: $.app.mc.updateEventUri,
              data: form,
              success: function(data, textStatus, jqXHR){return $.app.cal._updateEvent( data, textStatus, jqXHR,revertFunc)},
              dataType: 'JSON'
            });

  },
  /* ********************************************************** */

  _buildUpdateEventForm: function(event)
  {
      var form ={};
      form.pk = this.getDataForm();
      form.pk.start_date = event.start.format($.app.mc.momentUkDateFormat);
      form.pk.start_time = event.start.format($.app.mc.momentUkTimeFormat);
      form.pk.end_date = event.end.format($.app.mc.momentUkDateFormat);
      form.pk.end_time = event.end.format($.app.mc.momentUkTimeFormat);
      form.pk.ee_id = event.event_entry_id;
      return form;
  },

  /* ********************************************************** */
  eventResize:function(event, delta, revertFunc, jsEvent, ui, view )
  {

    event.end.add(event.end._data);
    var form = this._buildUpdateEventForm(event);

    $.ajax({
              type: "POST",
              url: $.app.mc.updateEventUri,
              data: form,
              success: function(data, textStatus, jqXHR){return $.app.cal._updateEvent( data, textStatus, jqXHR,revertFunc)},
              dataType: 'JSON'
            });
  },
   /* ********************************************************** */
  resetFields: function()
    {
        $('#span-event-title').html('')
        $('#span-event-description').html('');
        $('#span-event-date').html('');
        $('#span-event-from').html('');
        $('#span-event-to').html('');
        $('#eventShowModalLabel').html('');
        $('#span-event-create').html('');
        $('#span-event-create-date').html('');
    },
  /* ********************************************************** */
  eventClick:function(event, jsEvent, view)
    {

        this.currentEvent = event;

        $('#span-event-title').editable('destroy');
        $('#span-event-description').editable('destroy');
        $('#span-event-calendar').editable('destroy');
         $('#span-event-project').editable('destroy');

        $('#span-event-title').html(event.title);
        $('#span-event-description').html(event.description);
        $('#span-event-date').html(moment(event.start).format('L'));
        $('#span-event-from').html(moment(event.start).format('HH:mm'));
        $('#span-event-to').html(moment(event.end).format('HH:mm'));

         $('#span-event-create').html(event.create_name);
         $('#span-event-create-date').html(event.created_at);
         $('#eventShowModalLabel').html(event.title);
         if (event.editable)
            $('#delete-button').show();
         else
            $('#delete-button').hide();

        var form = this._buildUpdateEventForm(event).pk;
           $('#span-event-title').editable({
              type: 'text',
              value: event.title,
              pk: form,
              name:'title',
              placement:'bottom',
              url: $.app.mc.updateEventUri,
              title: 'Event title',
              disabled: ! (event.editable),
              success: function(response, newValue) {
                  $('#full-calendar').fullCalendar('refetchEvents');
              }
          });
           $('#span-event-description').editable({
              type: 'textarea',
              value: event.event_entry_description,
              pk: form,
              name:'description',
              placement:'bottom',
              url: $.app.mc.updateEventUri,
              disabled: ! (event.editable),
              title: 'Event description',
              success: function(response, newValue) {
                  $('#full-calendar').fullCalendar('refetchEvents');

              }
          });
           $('#span-event-calendar').editable({
              type: 'select',
              value: event.cal_id,
              pk: form,
              source: function()
              {
                  var a = [];
                  for (var i =0 ; i < $.app.mc.myCalendars.length ; i++ )
                    a.push({'value': $.app.mc.myCalendars[i].calendar_id , 'text':$.app.mc.myCalendars[i].calendar_title });
                  return a;
              },
              name:'calendar_id',
              placement:'bottom',
              url: $.app.mc.updateEventUri,
              disabled: ! (event.editable),
              title: 'Event Calendar',
              success: function(response, newValue) {
                    $.app.cal._eventClick(response, newValue)

              }
          });
           $('#span-event-project').editable({
              type: 'select',
              value: event.project_id,
              pk: form,
              source: function()
              {
                  var a = [];
                  for (var i =0 ; i < $.app.mc.myProjects.length ; i++ )
                    a.push({'value': $.app.mc.myProjects[i].project_id , 'text':$.app.mc.myProjects[i].project_title });
                  return a;
              },
              name:'project_id',
              placement:'bottom',
              url: $.app.mc.updateEventUri,
              disabled: ! (event.editable),
              title: 'Event Project',
              success: function(response, newValue) {
                    $.app.cal._eventClick(response, newValue)
              }
            });

             $('#span-event-date').editable({
                    type:'date',
                    placement:'bottom',
                    format: 'yyyy-mm-dd',
                    url: $.app.mc.updateEventUri,
                    disabled: true, //! (event.editable),
                    viewformat: 'dd/mm/yyyy',
                    success: function(response, newValue) {
                       $.app.cal._eventClick(response, newValue)
                    },
                    datepicker: {
                        weekStart: 1
                    }
              });

        $('#eventShowModal').modal();

    },
    /* ********************************************************** */

    /* ********************************************************** */
    _eventClick:function(response , newValue )
    {
           response = jQuery.parseJSON( response );
            if (response.error)
            {
              var title = 'There is a problem: ';
              var message = '';
              for(var i=0 ; i < response.message.length ; i++)
                  message += response.message[i] + '  ';

              $('#spanShowResponse').css('color','#990000');
              $('#spanShowTitle').html(title);
              $('#spanShowResponse').html(message);
            }
            else
                $('#full-calendar').fullCalendar('refetchEvents');

            return true;

    },
    /* ********************************************************** */
    createEvent: function ()
    {
           var values = {};
            $.each($('#frmBookingForm').serializeArray(), function(i, field) {
                values[field.name] = field.value;

            });
          $.ajax({
              type: "POST",
              url: $.app.mc.createEventUri,
              data: values,
              success: function(data, textStatus, jqXHR){return $.app.cal._createEvent( data, textStatus, jqXHR)},
              dataType: 'JSON'
            });
    } ,
/* ********************************************************** */
  _createEvent: function ( data, textStatus, jqXHR)
  {
    var response = '';
    var title = '';

    if (data.error)
    {
      title = 'There is a problem: ';
      for(var i=0 ; i < data.message.length ; i++)
        response += data.message[i] + '  ';
        $('#spanResponse').css('color','#990000');

    }
    if (! data.error)
    {
        $('#eventModal').modal('hide');
        $('#full-calendar').fullCalendar('renderEvent', data.message);
        response = 'Event updated.';
    }
    $('#spanTitle').html(title);
    $('#spanResponse').html(response);
  },
  /* ********************************************************** */
  _updateEvent: function ( data, textStatus, jqXHR,revertFunc)
  {
    var type= 'success';
    var message = '';
    for(var i =0 ; i < data.message.length ; i++)
        message += data.message[i];

    if (data.error)
    {
        type = 'danger'
        revertFunc();
    }
    else
        message = 'Event updated';
        $.bootstrapGrowl(message , {'type':type}, 1000 );

  },
/* ********************************************************** */

  drop:function(date, jsEvent, ui, resourceId , that)
  {

  },
  /* ********************************************************** */

  /* ********************************************************** */
  _popoverDiv:function(event)
  {
      var div = '';
      var start =moment(event.start).format('LT');
      var end = moment(event.end).format('LT');
      var date = moment(event.start).format('LL')
      div += '
';
      div += '
';
      div +=  date;
      div +=  ' ' + start + ' to ' + end;
      div += '
';
      div += '
';
      div += '
' + event.title +'
';

      div +=  'From: ' + start;
      div += ' to: '+ end ;
      div += '
';
      div += event.calendar_title;
      div += '
';
      div += event.project_collection_title;
      div += '
';
      div += '';
      div += 'Created by ' + event.create_name + ' on ' + event.created_at;
      div += '';
      div += '
';
      div += '
';

      return div;

  }

/* ********************************************************** */

};

$.app.cal = new AppPackageCalendar();

/* ********************************************************** */

<|endoftext|>


<commit_before>import event.Emitter as Emitter;

var DEFAULT_TILE_VALUES = {
		x: 0.5,
		y: 0.5,
		node: 0,
		right: 0,
		bottom: 0,
		rightTop: 0,
		rightBottom: 0,
		doodad: 0,
		doodadX: 0.5,
		doodadY: 0.5,
		friends: {
			x: '',
			y: '',
			width: 220,
			height: 120,
			r: 0,
			position: ''
		},
		tags: 'anything',
		text: '',
		title: '',
		id: '',
		position: ''
	};

exports = Class(Emitter, function (supr) {
	this.init = function (opts) {
		var data = {
				width: opts.width,
				height: opts.height,
				tileWidth: opts.tileWidth,
				tileHeight: opts.tileHeight,
				tileX: 0,
				tileY: 0
			};
		var grid = [];

		this._defaultTile = opts.defaultTile;
		this._map = this.createEmptyMap(opts.width, opts.height, opts.defaultTile);

		for (var y = 0; y < data.height; y++) {
			var gridLine = [];
			for (var x = 0; x < data.width; x++) {
				gridLine.push({
					node: 0,
					right: 0,
					bottom: 0,
					x: 0.5,
					y: 0.5
				});
			}
			grid.push(gridLine);
		}

		data.grid = grid;

		this._data = data;

		this._maxNodeId = 0;
		this._minNodeId = 999999;

		this._nodesByTag = {};
		this._nodesById = {};

		this._needsPopulate = false;

		try {
			var savedData = localStorage.getItem('MAP_DATA');
			if (savedData !== null) {
				this.load(JSON.parse(savedData));
			}
		} catch (error) {
		}
	};

	this.createEmptyMap = function (width, height, value) {
		var result = [];
		for (var y = 0; y < height; y++) {
			result[y] = [];
			for (var x = 0; x < width; x++) {
				result[y][x] = (height - y - 1) * width + x;
			}
		}
		return result;
	};

	this.update = function () {
		var data = this._data;
		var grid = data.grid;
		var width = data.width;
		var height = data.height;

		this._nodesByTag = {};

		for (var y = 0; y < height; y++) {
			for (var x = 0; x < width; x++) {
				var tile = grid[y][x];
				if ('tags' in tile) {
					var tags = tile.tags;
					tile.tileX = x;
					tile.tileY = y;
					for (var tag in tags) {
						if (this._nodesByTag[tag]) {
							this._nodesByTag[tag].push(tile);
						} else {
							this._nodesByTag[tag] = [tile];
						}
					}
				}
			}
		}
	};

	this.getMap = function () {
		return this._map;
	};

	this.getTileWidth = function () {
		return this._data.tileWidth;
	};

	this.getTileHeight = function () {
		return this._data.tileHeight;
	};

	this.getTileX = function () {
		return this._data.tileX;
	};

	this.getTileY = function () {
		return this._data.tileY;
	};

	this.getData = function (tileX, tileY) {
		return this._data;
	};

	this.getGrid = function (tileX, tileY) {
		if (tileY === undefined) {
			return this._grid;
		}
		return this._data.grid[tileY][tileX];
	};

	this.getNodesByTag = function (tag) {
		return this._nodesByTag[tag] || [];
	};

	this.getNodesById = function () {
		return this._nodesById;
	};

	this.getMaxNodeId = function () {
		return this._maxNodeId;
	};

	this.getMinNodeId = function () {
		return this._minNodeId;
	};

	this.addTagById = function (id, tag) {
		var tile = this._nodesById[id];
		if (tile) {
			if (!tile.tags) {
				tile.tags = {};
			}
			tile.tags[tag] = true;
			this.emit('UpdateTile', tile.tileX, tile.tileY);
		}
	};

	this.addFriends = function (id, views) {
		var tile = this._nodesById[id];
		if (tile) {
			tile.friends.views = views;
			this.emit('UpdateTile', tile.tileX, tile.tileY);
		}
	};

	this.removeFriends = function (id) {
		var tile = this._nodesById[id];
		if (tile) {
			tile.friends.views = [];
		}
	};

	this.removeTagById = function (id, tag) {
		var tile = this._nodesById[id];
		if (tile) {
			if (tile.tags) {
				delete tile.tags[tag];
			}
			this.emit('UpdateTile', tile.tileX, tile.tileY);
		}
	};

	this.removeTag = function (tag) {
		if (typeof tag === 'object') {
			var tags = tag;
			for (var id in this._nodesById) {
				var tile = this._nodesById[id];
				if (tile.tags) {
					var found = false;
					for (tag in tile.tags) {
						if (tags[tag]) {
							delete tile.tags[tag];
							found = true;
						}
					}
					found && this.emit('UpdateTile', tile.tileX, tile.tileY);
				}
			}
		} else {
			for (var id in this._nodesById) {
				var tile = this._nodesById[id];
				if (tile.tags && tile.tags[tag]) {
					delete tile.tags[tag];
					this.emit('UpdateTile', tile.tileX, tile.tileY);
				}
			}
		}
	};

	this.onSize = function (sizeX, sizeY) {
		this._maxX = this._data.width - sizeX;
		this._maxY = this._data.height - sizeY;
	};

	this.toJSON = function () {
		var map = this._map;
		var data = this._data;
		var grid = data.grid;
		var result = {
				tileWidth: this._data.tileWidth,
				tileHeight: this._data.tileHeight,
				width: data.width,
				height: data.height,
				grid: []
			};

		for (var y = 0; y < data.height; y++) {
			var gridLine = grid[y];
			var lastValue = null;
			var same = true;

			result.grid[y] = [];
			for (var x = 0; x < data.width; x++) {
				var tile = gridLine[x],
					saveTile = {},
					prop, temp;

				for (var i in tile) {
					if ((i in DEFAULT_TILE_VALUES) &&
						((DEFAULT_TILE_VALUES[i] === 'anything') || (tile[i] !== DEFAULT_TILE_VALUES[i]))) {
						// delete views for friends
						prop = tile[i];
						if (typeof prop === 'object') {
							temp = {};
							merge(temp, prop);
							delete temp.views;
							prop = temp;
						}
						saveTile[i] = prop;
					}
				}

				var mapValue = map[y][x];

				// If there's anything interesting then save the object...
				if (Object.keys(saveTile).length) {
					same = false; // If it's an object then save all values in this row...
					saveTile.map = mapValue;
					result.grid[y][x] = saveTile;
				} else { // If there's nothing interesting then save the background...
					result.grid[y][x] = mapValue;
					if (lastValue === null) {
						lastValue = mapValue;
					} else if (lastValue !== mapValue) {
						same = false;
					}
				}
			}

			// If all the items are numeric and the same then store a single value...
			if (same) {
				result.grid[y] = [lastValue];
			}
		}

		return result;
	};

	this.clear = function () {
		var data = this._data;
		var grid = data.grid;
		var map = this._map;

		for (var y = 0; y < data.height; y++) {
			var gridLine = grid[y];
			var mapLine = map[y];

			for (var x = 0; x < data.width; x++) {
				var tile = gridLine[x];
				tile.node = 0;
				tile.right = 0;
				tile.bottom = 0;
				tile.rightTop = 0;
				tile.rightBottom = 0;
				tile.x = 0.5;
				tile.y = 0.5;
				tile.title = '';
				tile.text = '';
				tile.tags = {};
				delete tile.friends;

				mapLine[x] = this._defaultTile;
			}
		}
	};

	this.load = function (data) {
		var map = this._map;
		var grid = data.grid;
		var width = data.width;
		var height = data.height;

		this._data.width = width;
		this._data.height = height;
		this._data.tileWidth = data.tileWidth;
		this._data.tileHeight = data.tileHeight;

		this._nodesByTag = {};
		this._nodesById = {};

		this._maxNodeId = 0;
		this._minNodeId = 999999;

		for (var y = 0; y < height; y++) {
			var gridLine = grid[y] || [];

			for (var x = 0; x < width; x++) {
				var len = gridLine.length || 1,
					tile = gridLine[Math.min(x, len - 1)];

				if (!tile) {
					map[y][x] = width * y + x;
					tile = {};
				} else if (typeof tile === 'number') { // If it's only a background then set the background and make a new tile...
					map[y][x] = tile;
					tile = {};
				} else {
					map[y][x] = tile.map;
				}
				for (var i in DEFAULT_TILE_VALUES) {
					// If there's no value and the value can't be "anything" then set the default:
					var value = DEFAULT_TILE_VALUES[i];
					if (typeof value === 'object') {
						if (!tile[i]) {
							tile[i] = {};
						}
						merge(tile[i], value);
					} else if (!(i in tile) && (value !== 'anything')) {
						tile[i] = value;
					}
				}
				delete tile.map;

				tile.tileX = x;
				tile.tileY = y;
				if (tile.tags) {
					var tags = tile.tags;
					for (var tag in tags) {
						if (this._nodesByTag[tag]) {
							this._nodesByTag[tag].push(tile);
						} else {
							this._nodesByTag[tag] = [tile];
						}
					}
				}

				if (('id' in tile) && ('x' in tile)) {
					var nodeId = parseInt(tile.id, 10);
					if (!isNaN(nodeId)) {
						this._minNodeId = Math.min(this._minNodeId, nodeId);
						this._maxNodeId = Math.max(this._maxNodeId, nodeId);
					}
					this._nodesById[tile.id] = tile;
				}

				this._data.grid[y][x] = tile;
			}

			// If the map was larger the remove the remaining part:
			while (this._data.grid[y].length > width) {
				this._data.grid[y].pop();
			}
			while (map[y].length > width) {
				map[y].pop();
			}
		}

		// If the map was larger the remove the remaining part:
		while (this._data.grid.length > height) {
			this._data.grid.pop();
		}
		while (map.length > height) {
			map.pop();
		}
	};
});
<commit_msg>Revert "no need to update on every tick"<commit_after>import event.Emitter as Emitter;

var DEFAULT_TILE_VALUES = {
		x: 0.5,
		y: 0.5,
		node: 0,
		right: 0,
		bottom: 0,
		rightTop: 0,
		rightBottom: 0,
		doodad: 0,
		doodadX: 0.5,
		doodadY: 0.5,
		friends: {
			x: '',
			y: '',
			width: 220,
			height: 120,
			r: 0,
			position: ''
		},
		tags: 'anything',
		text: '',
		title: '',
		id: '',
		position: ''
	};

exports = Class(Emitter, function (supr) {
	this.init = function (opts) {
		var data = {
				width: opts.width,
				height: opts.height,
				tileWidth: opts.tileWidth,
				tileHeight: opts.tileHeight,
				tileX: 0,
				tileY: 0
			};
		var grid = [];

		this._defaultTile = opts.defaultTile;
		this._map = this.createEmptyMap(opts.width, opts.height, opts.defaultTile);

		for (var y = 0; y < data.height; y++) {
			var gridLine = [];
			for (var x = 0; x < data.width; x++) {
				gridLine.push({
					node: 0,
					right: 0,
					bottom: 0,
					x: 0.5,
					y: 0.5
				});
			}
			grid.push(gridLine);
		}

		data.grid = grid;

		this._data = data;

		this._maxNodeId = 0;
		this._minNodeId = 999999;

		this._nodesByTag = {};
		this._nodesById = {};

		this._needsPopulate = false;

		try {
			var savedData = localStorage.getItem('MAP_DATA');
			if (savedData !== null) {
				this.load(JSON.parse(savedData));
			}
		} catch (error) {
		}
	};

	this.createEmptyMap = function (width, height, value) {
		var result = [];
		for (var y = 0; y < height; y++) {
			result[y] = [];
			for (var x = 0; x < width; x++) {
				result[y][x] = (height - y - 1) * width + x;
			}
		}
		return result;
	};

	this.tick = function (dt) {
		if (this._needsPopulate) {
			this._needsPopulate = false;
			this.emit('NeedsPopulate');
		}

		this.emit('Update', this._data);
	};

	this.update = function () {
		var data = this._data;
		var grid = data.grid;
		var width = data.width;
		var height = data.height;

		this._nodesByTag = {};

		for (var y = 0; y < height; y++) {
			for (var x = 0; x < width; x++) {
				var tile = grid[y][x];
				if ('tags' in tile) {
					var tags = tile.tags;
					tile.tileX = x;
					tile.tileY = y;
					for (var tag in tags) {
						if (this._nodesByTag[tag]) {
							this._nodesByTag[tag].push(tile);
						} else {
							this._nodesByTag[tag] = [tile];
						}
					}
				}
			}
		}
	};

	this.getMap = function () {
		return this._map;
	};

	this.getTileWidth = function () {
		return this._data.tileWidth;
	};

	this.getTileHeight = function () {
		return this._data.tileHeight;
	};

	this.getTileX = function () {
		return this._data.tileX;
	};

	this.getTileY = function () {
		return this._data.tileY;
	};

	this.getData = function (tileX, tileY) {
		return this._data;
	};

	this.getGrid = function (tileX, tileY) {
		if (tileY === undefined) {
			return this._grid;
		}
		return this._data.grid[tileY][tileX];
	};

	this.getNodesByTag = function (tag) {
		return this._nodesByTag[tag] || [];
	};

	this.getNodesById = function () {
		return this._nodesById;
	};

	this.getMaxNodeId = function () {
		return this._maxNodeId;
	};

	this.getMinNodeId = function () {
		return this._minNodeId;
	};

	this.addTagById = function (id, tag) {
		var tile = this._nodesById[id];
		if (tile) {
			if (!tile.tags) {
				tile.tags = {};
			}
			tile.tags[tag] = true;
			this.emit('UpdateTile', tile.tileX, tile.tileY);
		}
	};

	this.addFriends = function (id, views) {
		var tile = this._nodesById[id];
		if (tile) {
			tile.friends.views = views;
			this.emit('UpdateTile', tile.tileX, tile.tileY);
		}
	};

	this.removeFriends = function (id) {
		var tile = this._nodesById[id];
		if (tile) {
			tile.friends.views = [];
		}
	};

	this.removeTagById = function (id, tag) {
		var tile = this._nodesById[id];
		if (tile) {
			if (tile.tags) {
				delete tile.tags[tag];
			}
			this.emit('UpdateTile', tile.tileX, tile.tileY);
		}
	};

	this.removeTag = function (tag) {
		if (typeof tag === 'object') {
			var tags = tag;
			for (var id in this._nodesById) {
				var tile = this._nodesById[id];
				if (tile.tags) {
					var found = false;
					for (tag in tile.tags) {
						if (tags[tag]) {
							delete tile.tags[tag];
							found = true;
						}
					}
					found && this.emit('UpdateTile', tile.tileX, tile.tileY);
				}
			}
		} else {
			for (var id in this._nodesById) {
				var tile = this._nodesById[id];
				if (tile.tags && tile.tags[tag]) {
					delete tile.tags[tag];
					this.emit('UpdateTile', tile.tileX, tile.tileY);
				}
			}
		}
	};

	this.onSize = function (sizeX, sizeY) {
		this._maxX = this._data.width - sizeX;
		this._maxY = this._data.height - sizeY;
	};

	this.toJSON = function () {
		var map = this._map;
		var data = this._data;
		var grid = data.grid;
		var result = {
				tileWidth: this._data.tileWidth,
				tileHeight: this._data.tileHeight,
				width: data.width,
				height: data.height,
				grid: []
			};

		for (var y = 0; y < data.height; y++) {
			var gridLine = grid[y];
			var lastValue = null;
			var same = true;

			result.grid[y] = [];
			for (var x = 0; x < data.width; x++) {
				var tile = gridLine[x],
					saveTile = {},
					prop, temp;

				for (var i in tile) {
					if ((i in DEFAULT_TILE_VALUES) &&
						((DEFAULT_TILE_VALUES[i] === 'anything') || (tile[i] !== DEFAULT_TILE_VALUES[i]))) {
						// delete views for friends
						prop = tile[i];
						if (typeof prop === 'object') {
							temp = {};
							merge(temp, prop);
							delete temp.views;
							prop = temp;
						}
						saveTile[i] = prop;
					}
				}

				var mapValue = map[y][x];

				// If there's anything interesting then save the object...
				if (Object.keys(saveTile).length) {
					same = false; // If it's an object then save all values in this row...
					saveTile.map = mapValue;
					result.grid[y][x] = saveTile;
				} else { // If there's nothing interesting then save the background...
					result.grid[y][x] = mapValue;
					if (lastValue === null) {
						lastValue = mapValue;
					} else if (lastValue !== mapValue) {
						same = false;
					}
				}
			}

			// If all the items are numeric and the same then store a single value...
			if (same) {
				result.grid[y] = [lastValue];
			}
		}

		return result;
	};

	this.clear = function () {
		var data = this._data;
		var grid = data.grid;
		var map = this._map;

		for (var y = 0; y < data.height; y++) {
			var gridLine = grid[y];
			var mapLine = map[y];

			for (var x = 0; x < data.width; x++) {
				var tile = gridLine[x];
				tile.node = 0;
				tile.right = 0;
				tile.bottom = 0;
				tile.rightTop = 0;
				tile.rightBottom = 0;
				tile.x = 0.5;
				tile.y = 0.5;
				tile.title = '';
				tile.text = '';
				tile.tags = {};
				delete tile.friends;

				mapLine[x] = this._defaultTile;
			}
		}
	};

	this.load = function (data) {
		var map = this._map;
		var grid = data.grid;
		var width = data.width;
		var height = data.height;

		this._data.width = width;
		this._data.height = height;
		this._data.tileWidth = data.tileWidth;
		this._data.tileHeight = data.tileHeight;

		this._nodesByTag = {};
		this._nodesById = {};

		this._maxNodeId = 0;
		this._minNodeId = 999999;

		for (var y = 0; y < height; y++) {
			var gridLine = grid[y] || [];

			for (var x = 0; x < width; x++) {
				var len = gridLine.length || 1,
					tile = gridLine[Math.min(x, len - 1)];

				if (!tile) {
					map[y][x] = width * y + x;
					tile = {};
				} else if (typeof tile === 'number') { // If it's only a background then set the background and make a new tile...
					map[y][x] = tile;
					tile = {};
				} else {
					map[y][x] = tile.map;
				}
				for (var i in DEFAULT_TILE_VALUES) {
					// If there's no value and the value can't be "anything" then set the default:
					var value = DEFAULT_TILE_VALUES[i];
					if (typeof value === 'object') {
						if (!tile[i]) {
							tile[i] = {};
						}
						merge(tile[i], value);
					} else if (!(i in tile) && (value !== 'anything')) {
						tile[i] = value;
					}
				}
				delete tile.map;

				tile.tileX = x;
				tile.tileY = y;
				if (tile.tags) {
					var tags = tile.tags;
					for (var tag in tags) {
						if (this._nodesByTag[tag]) {
							this._nodesByTag[tag].push(tile);
						} else {
							this._nodesByTag[tag] = [tile];
						}
					}
				}

				if (('id' in tile) && ('x' in tile)) {
					var nodeId = parseInt(tile.id, 10);
					if (!isNaN(nodeId)) {
						this._minNodeId = Math.min(this._minNodeId, nodeId);
						this._maxNodeId = Math.max(this._maxNodeId, nodeId);
					}
					this._nodesById[tile.id] = tile;
				}

				this._data.grid[y][x] = tile;
			}

			// If the map was larger the remove the remaining part:
			while (this._data.grid[y].length > width) {
				this._data.grid[y].pop();
			}
			while (map[y].length > width) {
				map[y].pop();
			}
		}

		// If the map was larger the remove the remaining part:
		while (this._data.grid.length > height) {
			this._data.grid.pop();
		}
		while (map.length > height) {
			map.pop();
		}
	};
});
<|endoftext|>


<commit_before>var Backbone = require('backbone');
var Notifier = require('../../../../../javascripts/cartodb3/components/notifier/notifier.js');

describe('components/notifier/notifier-view', function () {
  var view;
  var editorModel;

  beforeAll(function () {
    editorModel = new Backbone.Model();
    editorModel.isEditing = function () {
      return false;
    };

    Notifier.init({
      editorModel: editorModel
    });
  });

  beforeEach(function () {
    jasmine.clock().install();
    view = Notifier.getView();
    view.render();

    Notifier.addNotification({
      id: 'foo',
      closable: false
    });
  });

  afterEach(function () {
    Notifier.getCollection().reset();
    jasmine.clock().uninstall();
  });

  it('should render properly', function () {
    expect(view.el).toBeDefined();
    expect(view.$('.Notifier-inner').length).toBe(1);
    expect(view.$('.Notifier-icon').length).toBe(0);
    expect(view.$('#foo').length).toBe(1);
  });

  it('should add subview properly', function () {
    Notifier.addNotification({
      id: 'bar'
    });
    expect(view.$('.Notifier-inner').length).toBe(2);
    expect(view.$('#foo').length).toBe(1);
    expect(view.$('#bar').length).toBe(1);
  });

  it('should remove subview properly', function () {
    Notifier.addNotification({
      id: 'bar'
    });
    Notifier.removeNotification('foo');

    expect(view.$('.Notifier-inner').length).toBe(1);
    expect(view.$('#bar').length).toBe(1);
    expect(view.$('#foo').length).toBe(0);
  });

  it('should update icon properly', function () {
    var model = Notifier.getNotification('foo');
    model.updateStatus('loading');

    expect(view.$('.Notifier-icon').length).toBe(1);
  });

  it('should update close button properly', function () {
    var model = Notifier.getNotification('foo');
    model.updateClosable(true);

    expect(view.$('.js-close').length).toBe(1);
    expect(view.$('.js-action').length).toBe(0);
  });

  it('should update button properly', function () {
    var model = Notifier.getNotification('foo');
    model.updateButton('OK');

    expect(view.$('.js-close').length).toBe(0);
    expect(view.$('.js-action').length).toBe(1);
  });

  it('should bind actions properly', function () {
    var callback = {
      fn: function () {}
    };

    spyOn(callback, 'fn');
    var model = Notifier.getNotification('foo');
    model.on('notification:close', callback.fn);
    model.on('notification:action', callback.fn);

    model.updateButton('OK');
    view.$('.js-action').trigger('click');
    expect(callback.fn).toHaveBeenCalled();

    model.updateClosable(true);
    view.$('.js-close').trigger('click');
    expect(callback.fn).toHaveBeenCalled();
  });

  it('should remove view on close properly', function () {
    var model = Notifier.getNotification('foo');
    model.updateClosable(true);
    view.$('.js-close').trigger('click');
    expect(view.$('.Notifier-inner').length).toBe(0);
  });

  it('should autoclose on success', function () {
    var model = Notifier.getNotification('foo');
    model.updateStatus('success');
    expect(view.$('.Notifier-inner').length).toBe(1);
    jasmine.clock().tick(10001);
    expect(view.$('.Notifier-inner').length).toBe(0);
  });

  it('should not have any leaks', function () {
    expect(view).toHaveNoLeaks();
  });
});
<commit_msg>Fixed test<commit_after>var Backbone = require('backbone');
var Notifier = require('../../../../../javascripts/cartodb3/components/notifier/notifier.js');

describe('components/notifier/notifier-view', function () {
  var view;
  var editorModel;

  beforeAll(function () {
    editorModel = new Backbone.Model();
    editorModel.isEditing = function () {
      return false;
    };

    Notifier.init({
      editorModel: editorModel
    });

    Notifier.getCollection().reset();
  });

  beforeEach(function () {
    jasmine.clock().install();
    view = Notifier.getView();
    view.render();

    Notifier.addNotification({
      id: 'foo',
      closable: false
    });
  });

  afterEach(function () {
    Notifier.getCollection().reset();
    jasmine.clock().uninstall();
  });

  it('should render properly', function () {
    expect(view.el).toBeDefined();
    expect(view.$('.Notifier-inner').length).toBe(1);
    expect(view.$('.Notifier-icon').length).toBe(0);
    expect(view.$('#foo').length).toBe(1);
  });

  it('should add subview properly', function () {
    Notifier.addNotification({
      id: 'bar'
    });
    expect(view.$('.Notifier-inner').length).toBe(2);
    expect(view.$('#foo').length).toBe(1);
    expect(view.$('#bar').length).toBe(1);
  });

  it('should remove subview properly', function () {
    Notifier.addNotification({
      id: 'bar'
    });
    Notifier.removeNotification('foo');

    expect(view.$('.Notifier-inner').length).toBe(1);
    expect(view.$('#bar').length).toBe(1);
    expect(view.$('#foo').length).toBe(0);
  });

  it('should update icon properly', function () {
    var model = Notifier.getNotification('foo');
    model.updateStatus('loading');

    expect(view.$('.Notifier-icon').length).toBe(1);
  });

  it('should update close button properly', function () {
    var model = Notifier.getNotification('foo');
    model.updateClosable(true);

    expect(view.$('.js-close').length).toBe(1);
    expect(view.$('.js-action').length).toBe(0);
  });

  it('should update button properly', function () {
    var model = Notifier.getNotification('foo');
    model.updateButton('OK');

    expect(view.$('.js-close').length).toBe(0);
    expect(view.$('.js-action').length).toBe(1);
  });

  it('should bind actions properly', function () {
    var callback = {
      fn: function () {}
    };

    spyOn(callback, 'fn');
    var model = Notifier.getNotification('foo');
    model.on('notification:close', callback.fn);
    model.on('notification:action', callback.fn);

    model.updateButton('OK');
    view.$('.js-action').trigger('click');
    expect(callback.fn).toHaveBeenCalled();

    model.updateClosable(true);
    view.$('.js-close').trigger('click');
    expect(callback.fn).toHaveBeenCalled();
  });

  it('should remove view on close properly', function () {
    var model = Notifier.getNotification('foo');
    model.updateClosable(true);
    view.$('.js-close').trigger('click');
    expect(view.$('.Notifier-inner').length).toBe(0);
  });

  it('should autoclose on success', function () {
    var model = Notifier.getNotification('foo');
    model.updateStatus('success');
    expect(view.$('.Notifier-inner').length).toBe(1);
    jasmine.clock().tick(10001);
    expect(view.$('.Notifier-inner').length).toBe(0);
  });

  it('should not have any leaks', function () {
    expect(view).toHaveNoLeaks();
  });
});
<|endoftext|>


<commit_before>var symphony = symphony || {};
symphony.interop = {createChannel: function(){
    var mb = meow.messagebroker();
    var sysstatus = "Ready";

    mb.subscribe("api.symphony.com", function (envelope) {
        console.log("api.symphony.com/incoming envelope: ", envelope);

        window.postMessage(envelope.message, "*");

    });

    mb.subscribe("com.symphony.system.interop", function (envelope) {
        console.log("system.symphony.com/message: ", envelope);
        console.log("system.symphony.com/envelope.replyAddress/ ", envelope.replyAddress);
        console.log("system.symphony.com/envelope.message.action/ ", envelope.message.action);

        if (envelope.replyAddress != null) {
            switch(envelope.message.action) {
                case 'Query_System_Status':
                    mb.send(envelope.replyAddress, { type: 'System_Response', action: 'Query_System_Status', status: sysstatus });
                    break;
                case 'Bring_Symphony_To_Front':
                    paragon.app.window.getCurrent(function (win) {
                        win.restore(function () {
                            win.setAlwaysOnTop(true, function () {
                                win.setAlwaysOnTop(false);
                                mb.send(envelope.replyAddress, { type: 'System_Response', action: 'Bring_Symphony_To_Front', result: true });
                            });
                        });
                    });
                    break;
            }
        }

    });

    mb.publish("com.symphony.system.interop.events", { type: "System_Status", status: sysstatus });

    symphony.interop.outboundChannel = {
        post: function (message) {
            if (message != null && message.responseAddress != null)
            {
                mb.send(message.responseAddress, message);
            }
        }
    }
}};
<commit_msg>Update SymphonyInterop.js<commit_after>var symphony = symphony || {};
symphony.interop = {createChannel: function(){
    var mb = meow.messagebroker();
    var sysstatus = "Ready";

    mb.subscribe("com.symphony.api", function (envelope) {
        console.log("api.symphony.com/incoming envelope: ", envelope);

        window.postMessage(envelope.message, "*");

    });

    mb.subscribe("com.symphony.system.interop", function (envelope) {
        console.log("system.symphony.com/message: ", envelope);
        console.log("system.symphony.com/envelope.replyAddress/ ", envelope.replyAddress);
        console.log("system.symphony.com/envelope.message.action/ ", envelope.message.action);

        if (envelope.replyAddress != null) {
            switch(envelope.message.action) {
                case 'Query_System_Status':
                    mb.send(envelope.replyAddress, { type: 'System_Response', action: 'Query_System_Status', status: sysstatus });
                    break;
                case 'Bring_Symphony_To_Front':
                    paragon.app.window.getCurrent(function (win) {
                        win.restore(function () {
                            win.setAlwaysOnTop(true, function () {
                                win.setAlwaysOnTop(false);
                                mb.send(envelope.replyAddress, { type: 'System_Response', action: 'Bring_Symphony_To_Front', result: true });
                            });
                        });
                    });
                    break;
            }
        }

    });

    mb.publish("com.symphony.system.interop.events", { type: "System_Status", status: sysstatus });

    symphony.interop.outboundChannel = {
        post: function (message) {
            if (message != null && message.responseAddress != null)
            {
                mb.send(message.responseAddress, message);
            }
        }
    }
}};
<|endoftext|>


<commit_before>/**
 * Diff two list in O(N).
 * @param {Array} oldList - Original List
 * @param {Array} newList - List After certain insertions, removes, or moves
 * @return {Object} - {moves: <Array>}
 *                  - moves is a list of actions that telling how to remove and insert
 */
function diff (oldList, newList, key) {
  var oldMap = makeKeyIndexAndFree(oldList, key)
  var newMap = makeKeyIndexAndFree(newList, key)

  var newFree = newMap.free

  var oldKeyIndex = oldMap.keyIndex
  var newKeyIndex = newMap.keyIndex

  var moves = []

  // a simulate list to manipulate
  var children = []
  var i = 0
  var item
  var itemKey
  var freeIndex = 0

  // fist pass to check item in old list: if it's removed or not
  while (i < oldList.length) {
    item = oldList[i]
    itemKey = getItemKey(item, key)
    if (itemKey) {
      if (!newKeyIndex.hasOwnProperty(itemKey)) {
        children.push(null)
      } else {
        var newItemIndex = newKeyIndex[itemKey]
        children.push(newList[newItemIndex])
      }
    } else {
      var freeItem = newFree[freeIndex++]
      children.push(freeItem || null)
    }
    i++
  }

  var simulateList = children.slice(0)

  // remove items no longer exist
  i = 0
  while (i < simulateList.length) {
    if (simulateList[i] === null) {
      remove(i)
      removeSimulate(i)
    } else {
      i++
    }
  }

  // i is cursor pointing to a item in new list
  // j is cursor pointing to a item in simulateList
  var j = i = 0
  while (i < newList.length) {
    item = newList[i]
    itemKey = getItemKey(item, key)

    var simulateItem = simulateList[j]
    var simulateItemKey = getItemKey(simulateItem, key)

    if (simulateItem) {
      if (itemKey === simulateItemKey) {
        j++
      } else {
        // new item, just inesrt it
        if (!oldKeyIndex.hasOwnProperty(itemKey)) {
          insert(i, item)
        } else {
          // if remove current simulateItem make item in right place
          // then just remove it
          var nextItemKey = getItemKey(simulateList[j + 1], key)
          if (nextItemKey === itemKey) {
            remove(i)
            removeSimulate(j)
            j++ // after removing, current j is right, just jump to next one
          } else {
            // else insert item
            insert(i, item)
          }
        }
      }
    } else {
      insert(i, item)
    }

    i++
  }

  //if j is not remove to the end, remove all the rest item
  var k = 0;
  while (j++<simulateList.length){
    remove(k+i);
    k++;
  }

  function remove (index) {
    var move = {index: index, type: 0}
    moves.push(move)
  }

  function insert (index, item) {
    var move = {index: index, item: item, type: 1}
    moves.push(move)
  }

  function removeSimulate (index) {
    simulateList.splice(index, 1)
  }

  return {
    moves: moves,
    children: children
  }
}

/**
 * Convert list to key-item keyIndex object.
 * @param {Array} list
 * @param {String|Function} key
 */
function makeKeyIndexAndFree (list, key) {
  var keyIndex = {}
  var free = []
  for (var i = 0, len = list.length; i < len; i++) {
    var item = list[i]
    var itemKey = getItemKey(item, key)
    if (itemKey) {
      keyIndex[itemKey] = i
    } else {
      free.push(item)
    }
  }
  return {
    keyIndex: keyIndex,
    free: free
  }
}

function getItemKey (item, key) {
  if (!item || !key) return void 666
  return typeof key === 'string'
    ? item[key]
    : key(item)
}

exports.makeKeyIndexAndFree = makeKeyIndexAndFree // exports for test
exports.diff = diff
<commit_msg>Update diff.js<commit_after>/**
 * Diff two list in O(N).
 * @param {Array} oldList - Original List
 * @param {Array} newList - List After certain insertions, removes, or moves
 * @return {Object} - {moves: <Array>}
 *                  - moves is a list of actions that telling how to remove and insert
 */
function diff (oldList, newList, key) {
  var oldMap = makeKeyIndexAndFree(oldList, key)
  var newMap = makeKeyIndexAndFree(newList, key)

  var newFree = newMap.free

  var oldKeyIndex = oldMap.keyIndex
  var newKeyIndex = newMap.keyIndex

  var moves = []

  // a simulate list to manipulate
  var children = []
  var i = 0
  var item
  var itemKey
  var freeIndex = 0

  // first pass to check item in old list: if it's removed or not
  while (i < oldList.length) {
    item = oldList[i]
    itemKey = getItemKey(item, key)
    if (itemKey) {
      if (!newKeyIndex.hasOwnProperty(itemKey)) {
        children.push(null)
      } else {
        var newItemIndex = newKeyIndex[itemKey]
        children.push(newList[newItemIndex])
      }
    } else {
      var freeItem = newFree[freeIndex++]
      children.push(freeItem || null)
    }
    i++
  }

  var simulateList = children.slice(0)

  // remove items no longer exist
  i = 0
  while (i < simulateList.length) {
    if (simulateList[i] === null) {
      remove(i)
      removeSimulate(i)
    } else {
      i++
    }
  }

  // i is cursor pointing to a item in new list
  // j is cursor pointing to a item in simulateList
  var j = i = 0
  while (i < newList.length) {
    item = newList[i]
    itemKey = getItemKey(item, key)

    var simulateItem = simulateList[j]
    var simulateItemKey = getItemKey(simulateItem, key)

    if (simulateItem) {
      if (itemKey === simulateItemKey) {
        j++
      } else {
        // new item, just inesrt it
        if (!oldKeyIndex.hasOwnProperty(itemKey)) {
          insert(i, item)
        } else {
          // if remove current simulateItem make item in right place
          // then just remove it
          var nextItemKey = getItemKey(simulateList[j + 1], key)
          if (nextItemKey === itemKey) {
            remove(i)
            removeSimulate(j)
            j++ // after removing, current j is right, just jump to next one
          } else {
            // else insert item
            insert(i, item)
          }
        }
      }
    } else {
      insert(i, item)
    }

    i++
  }

  //if j is not remove to the end, remove all the rest item
  var k = 0;
  while (j++<simulateList.length){
    remove(k+i);
    k++;
  }

  function remove (index) {
    var move = {index: index, type: 0}
    moves.push(move)
  }

  function insert (index, item) {
    var move = {index: index, item: item, type: 1}
    moves.push(move)
  }

  function removeSimulate (index) {
    simulateList.splice(index, 1)
  }

  return {
    moves: moves,
    children: children
  }
}

/**
 * Convert list to key-item keyIndex object.
 * @param {Array} list
 * @param {String|Function} key
 */
function makeKeyIndexAndFree (list, key) {
  var keyIndex = {}
  var free = []
  for (var i = 0, len = list.length; i < len; i++) {
    var item = list[i]
    var itemKey = getItemKey(item, key)
    if (itemKey) {
      keyIndex[itemKey] = i
    } else {
      free.push(item)
    }
  }
  return {
    keyIndex: keyIndex,
    free: free
  }
}

function getItemKey (item, key) {
  if (!item || !key) return void 666
  return typeof key === 'string'
    ? item[key]
    : key(item)
}

exports.makeKeyIndexAndFree = makeKeyIndexAndFree // exports for test
exports.diff = diff
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2013-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @emails oncall+ui_infra
 */

'use strict';

jest.disableAutomock();

var CharacterMetadata = require('CharacterMetadata');
var ContentBlock = require('ContentBlock');
var ContentState = require('ContentState');
var DraftModifier = require('DraftModifier');
var EditorState = require('EditorState');
var Immutable = require('immutable');
var SelectionState = require('SelectionState');
var RichTextEditorUtil = require('RichTextEditorUtil');

var {
  NONE,
  BOLD,
  ITALIC,
} = require('SampleDraftInlineStyle');

var {EMPTY} = CharacterMetadata;

var {
  List,
  Repeat,
} = Immutable;

var plainBlock = new ContentBlock({
  key: 'a',
  text: 'Arsenal',
  characterList: List(Repeat(EMPTY, 7)),
});

var boldChar = CharacterMetadata.create({style: BOLD});
var boldBlock = new ContentBlock({
  key: 'b',
  text: 'Burnley',
  characterList: List(Repeat(boldChar, 7)),
});

var emptyBlockA = new ContentBlock({
  key: 'emptyA',
  text: '',
  characterList: List(),
});

var emptyBlockB = new ContentBlock({
  key: 'emptyB',
  text: '',
  characterList: List(),
});

var italicChar = CharacterMetadata.create({style: ITALIC});
var italicBlock = new ContentBlock({
  key: 'c',
  text: 'Chelsea',
  characterList: List(Repeat(italicChar, 7)),
});

function getUndecoratedEditorState() {
  var contentState = ContentState.createFromBlockArray([
    plainBlock,
    boldBlock,
    emptyBlockA,
    emptyBlockB,
    italicBlock,
  ]);
  return EditorState.createWithContent(contentState);
}

function getEmptyLedMultiBlockEditorState() {
  var contentState = ContentState.createFromBlockArray([
    emptyBlockA,
    emptyBlockB,
    boldBlock,
  ]);
  return EditorState.createWithContent(contentState);
}

function getDecoratedEditorState(decorator) {
  var contentState = ContentState.createFromBlockArray([
    boldBlock,
    italicBlock,
  ]);
  return EditorState.createWithContent(contentState, decorator);
}

describe('EditorState', () => {

  describe('getCurrentInlineStyle', () => {
    var mainEditor = getUndecoratedEditorState();

    describe('Collapsed selection', () => {
      var mainSelection = new SelectionState({
        anchorKey: 'a',
        anchorOffset: 0,
        focusKey: 'a',
        focusOffset: 0,
        isBackward: false,
      });

      it('uses right of the caret at document start', () => {
        var editor = EditorState.acceptSelection(mainEditor, mainSelection);
        expect(editor.getCurrentInlineStyle()).toBe(NONE);
      });

      it('uses left of the caret, at position `1+`', () => {
        var selection = mainSelection.merge({
          anchorOffset: 1,
          focusOffset: 1,
        });
        var editor = EditorState.acceptSelection(mainEditor, selection);
        expect(editor.getCurrentInlineStyle()).toBe(NONE);
      });

      it('uses right of the caret at offset `0` within document', () => {
        var selection = mainSelection.merge({
          anchorKey: 'b',
          focusKey: 'b',
        });
        var editor = EditorState.acceptSelection(mainEditor, selection);
        expect(editor.getCurrentInlineStyle()).toBe(BOLD);
      });

      it('uses previous block at offset `0` within empty block', () => {
        var selection = mainSelection.merge({
          anchorKey: 'emptyA',
          focusKey: 'emptyA',
        });
        var editor = EditorState.acceptSelection(mainEditor, selection);
        expect(editor.getCurrentInlineStyle()).toBe(BOLD);
      });

      it('looks upward through empty blocks to find a character', () => {
        var selection = mainSelection.merge({
          anchorKey: 'emptyB',
          focusKey: 'emptyB',
        });
        var editor = EditorState.acceptSelection(mainEditor, selection);
        expect(editor.getCurrentInlineStyle()).toBe(BOLD);
      });

      it('does not discard style override when changing block type', () => {
        var editor = EditorState.createEmpty();

        editor = RichTextEditorUtil.toggleInlineStyle(editor, 'BOLD');
        expect(editor.getCurrentInlineStyle().toJS()).toEqual(['BOLD']);

        editor = RichTextEditorUtil.toggleBlockType(editor, 'test-block');
        expect(editor.getCurrentInlineStyle().toJS()).toEqual(['BOLD']);
      });

      it('does not discard style override when adjusting depth', () => {
        var editor = EditorState.createEmpty();

        editor = RichTextEditorUtil.toggleInlineStyle(editor, 'BOLD');
        expect(editor.getCurrentInlineStyle().toJS()).toEqual(['BOLD']);

        editor = RichTextEditorUtil.onTab({ preventDefault: () => {} }, editor, 1);
        expect(editor.getCurrentInlineStyle().toJS()).toEqual(['BOLD']);
      });

      it('does not discard style override when splitting block', () => {
        var editor = EditorState.createEmpty();

        editor = RichTextEditorUtil.toggleInlineStyle(editor, 'BOLD');
        expect(editor.getCurrentInlineStyle().toJS()).toEqual(['BOLD']);

        var contentState = DraftModifier.splitBlock(
          editor.getCurrentContent(),
          editor.getSelection()
        );

        editor = EditorState.push(editor, contentState, 'split-block');
        expect(editor.getCurrentInlineStyle().toJS()).toEqual(['BOLD']);
      });
    });

    describe('Non-collapsed selection', () => {
      var selectionState = new SelectionState({
        anchorKey: 'a',
        anchorOffset: 0,
        focusKey: 'a',
        focusOffset: 1,
        isBackward: false,
      });

      it('uses right of the start for blocks with text', () => {
        var selection = selectionState.set('focusKey', 'b');
        var editor = EditorState.acceptSelection(mainEditor, selection);
        expect(editor.getCurrentInlineStyle()).toBe(NONE);
      });

      it('uses left of the start if starting at end of block', () => {
        var blockB = mainEditor.getCurrentContent().getBlockForKey('b');
        var selection = selectionState.merge({
          anchorKey: 'b',
          anchorOffset: blockB.getLength(),
          focusKey: 'c',
          focusOffset: 3,
        });

        var editor = EditorState.acceptSelection(mainEditor, selection);
        expect(editor.getCurrentInlineStyle()).toBe(BOLD);
      });

      it('looks upward through empty blocks to find a character', () => {
        var selection = selectionState.merge({
          anchorKey: 'emptyA',
          anchorOffset: 0,
          focusKey: 'c',
          focusOffset: 3,
        });
        var editor = EditorState.acceptSelection(mainEditor, selection);
        expect(editor.getCurrentInlineStyle()).toBe(BOLD);
      });

      it('falls back to no style if in empty block at document start', () => {
        var editor = getEmptyLedMultiBlockEditorState(
          new SelectionState({
            anchorKey: 'emptyA',
            anchorOffset: 0,
            focusKey: 'c',
            focusOffset: 3,
            isBackward: false,
          })
        );
        expect(editor.getCurrentInlineStyle()).toBe(NONE);
      });
    });
  });

  describe('Decorator handling', () => {
    var boldA = List(Repeat('x', boldBlock.getLength()));
    var boldB = List(Repeat('y', boldBlock.getLength()));

    function Decorator() {}
    Decorator.prototype.getDecorations = jest.fn();

    function NextDecorator() {}
    NextDecorator.prototype.getDecorations = jest.fn();

    beforeEach(() => {
      Decorator.prototype.getDecorations.mockClear();
      Decorator.prototype.getDecorations.mockImplementation((v, c) => {
        return v === boldBlock ? boldA : List(Repeat(undefined, v.getLength()));
      });
    });

    it('must set a new decorator', () => {
      var decorator = new Decorator();
      var editorState = getDecoratedEditorState(decorator);
      expect(decorator.getDecorations.mock.calls.length).toBe(2);

      Decorator.prototype.getDecorations.mockImplementation((v, c) => {
        return v === boldBlock ? boldB : List(Repeat(undefined, v.getLength()));
      });
      var newDecorator = new NextDecorator();
      NextDecorator.prototype.getDecorations.mockImplementation((v, c) => {
        return v === boldBlock ? boldB : List(Repeat(undefined, v.getLength()));
      });

      var withNewDecorator = EditorState.set(editorState, {
        decorator: newDecorator,
      });
      expect(withNewDecorator).not.toBe(editorState);

      // Twice for the initial tree map generation, then twice more for
      // filter comparison.
      expect(decorator.getDecorations.mock.calls.length).toBe(4);

      // Twice for filter comparison, once for tree generation since one
      // block has the same decoration list and is filtered out.
      expect(newDecorator.getDecorations.mock.calls.length).toBe(3);

      expect(withNewDecorator.getDecorator()).toBe(newDecorator);

      // Preserve block trees that had the same decorator list.
      expect(
        editorState.getBlockTree(boldBlock.getKey())
      ).toBe(
        withNewDecorator.getBlockTree(boldBlock.getKey())
      );

      expect(
        editorState.getBlockTree(italicBlock.getKey())
      ).not.toBe(
        withNewDecorator.getBlockTree(italicBlock.getKey())
      );
    });

    it('must correctly remove a decorator', () => {
      var decorator = new Decorator();
      var editorState = getDecoratedEditorState(decorator);
      expect(decorator.getDecorations.mock.calls.length).toBe(2);
      var withNewDecorator = EditorState.set(editorState, {decorator: null});
      expect(withNewDecorator).not.toBe(editorState);
      expect(withNewDecorator.getDecorator()).toBe(null);
      expect(decorator.getDecorations.mock.calls.length).toBe(2);
    });
  });
});
<commit_msg>Test that `getDecorations` is called with correct arguments (#995)<commit_after>/**
 * Copyright (c) 2013-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @emails oncall+ui_infra
 */

'use strict';

jest.disableAutomock();

var CharacterMetadata = require('CharacterMetadata');
var ContentBlock = require('ContentBlock');
var ContentState = require('ContentState');
var DraftModifier = require('DraftModifier');
var EditorState = require('EditorState');
var Immutable = require('immutable');
var SelectionState = require('SelectionState');
var RichTextEditorUtil = require('RichTextEditorUtil');

var {
  NONE,
  BOLD,
  ITALIC,
} = require('SampleDraftInlineStyle');

var {EMPTY} = CharacterMetadata;

var {
  List,
  Repeat,
} = Immutable;

var plainBlock = new ContentBlock({
  key: 'a',
  text: 'Arsenal',
  characterList: List(Repeat(EMPTY, 7)),
});

var boldChar = CharacterMetadata.create({style: BOLD});
var boldBlock = new ContentBlock({
  key: 'b',
  text: 'Burnley',
  characterList: List(Repeat(boldChar, 7)),
});

var emptyBlockA = new ContentBlock({
  key: 'emptyA',
  text: '',
  characterList: List(),
});

var emptyBlockB = new ContentBlock({
  key: 'emptyB',
  text: '',
  characterList: List(),
});

var italicChar = CharacterMetadata.create({style: ITALIC});
var italicBlock = new ContentBlock({
  key: 'c',
  text: 'Chelsea',
  characterList: List(Repeat(italicChar, 7)),
});

function getUndecoratedEditorState() {
  var contentState = ContentState.createFromBlockArray([
    plainBlock,
    boldBlock,
    emptyBlockA,
    emptyBlockB,
    italicBlock,
  ]);
  return EditorState.createWithContent(contentState);
}

function getEmptyLedMultiBlockEditorState() {
  var contentState = ContentState.createFromBlockArray([
    emptyBlockA,
    emptyBlockB,
    boldBlock,
  ]);
  return EditorState.createWithContent(contentState);
}

function getDecoratedEditorState(decorator) {
  var contentState = ContentState.createFromBlockArray([
    boldBlock,
    italicBlock,
  ]);
  return EditorState.createWithContent(contentState, decorator);
}

describe('EditorState', () => {

  describe('getCurrentInlineStyle', () => {
    var mainEditor = getUndecoratedEditorState();

    describe('Collapsed selection', () => {
      var mainSelection = new SelectionState({
        anchorKey: 'a',
        anchorOffset: 0,
        focusKey: 'a',
        focusOffset: 0,
        isBackward: false,
      });

      it('uses right of the caret at document start', () => {
        var editor = EditorState.acceptSelection(mainEditor, mainSelection);
        expect(editor.getCurrentInlineStyle()).toBe(NONE);
      });

      it('uses left of the caret, at position `1+`', () => {
        var selection = mainSelection.merge({
          anchorOffset: 1,
          focusOffset: 1,
        });
        var editor = EditorState.acceptSelection(mainEditor, selection);
        expect(editor.getCurrentInlineStyle()).toBe(NONE);
      });

      it('uses right of the caret at offset `0` within document', () => {
        var selection = mainSelection.merge({
          anchorKey: 'b',
          focusKey: 'b',
        });
        var editor = EditorState.acceptSelection(mainEditor, selection);
        expect(editor.getCurrentInlineStyle()).toBe(BOLD);
      });

      it('uses previous block at offset `0` within empty block', () => {
        var selection = mainSelection.merge({
          anchorKey: 'emptyA',
          focusKey: 'emptyA',
        });
        var editor = EditorState.acceptSelection(mainEditor, selection);
        expect(editor.getCurrentInlineStyle()).toBe(BOLD);
      });

      it('looks upward through empty blocks to find a character', () => {
        var selection = mainSelection.merge({
          anchorKey: 'emptyB',
          focusKey: 'emptyB',
        });
        var editor = EditorState.acceptSelection(mainEditor, selection);
        expect(editor.getCurrentInlineStyle()).toBe(BOLD);
      });

      it('does not discard style override when changing block type', () => {
        var editor = EditorState.createEmpty();

        editor = RichTextEditorUtil.toggleInlineStyle(editor, 'BOLD');
        expect(editor.getCurrentInlineStyle().toJS()).toEqual(['BOLD']);

        editor = RichTextEditorUtil.toggleBlockType(editor, 'test-block');
        expect(editor.getCurrentInlineStyle().toJS()).toEqual(['BOLD']);
      });

      it('does not discard style override when adjusting depth', () => {
        var editor = EditorState.createEmpty();

        editor = RichTextEditorUtil.toggleInlineStyle(editor, 'BOLD');
        expect(editor.getCurrentInlineStyle().toJS()).toEqual(['BOLD']);

        editor = RichTextEditorUtil.onTab({ preventDefault: () => {} }, editor, 1);
        expect(editor.getCurrentInlineStyle().toJS()).toEqual(['BOLD']);
      });

      it('does not discard style override when splitting block', () => {
        var editor = EditorState.createEmpty();

        editor = RichTextEditorUtil.toggleInlineStyle(editor, 'BOLD');
        expect(editor.getCurrentInlineStyle().toJS()).toEqual(['BOLD']);

        var contentState = DraftModifier.splitBlock(
          editor.getCurrentContent(),
          editor.getSelection()
        );

        editor = EditorState.push(editor, contentState, 'split-block');
        expect(editor.getCurrentInlineStyle().toJS()).toEqual(['BOLD']);
      });
    });

    describe('Non-collapsed selection', () => {
      var selectionState = new SelectionState({
        anchorKey: 'a',
        anchorOffset: 0,
        focusKey: 'a',
        focusOffset: 1,
        isBackward: false,
      });

      it('uses right of the start for blocks with text', () => {
        var selection = selectionState.set('focusKey', 'b');
        var editor = EditorState.acceptSelection(mainEditor, selection);
        expect(editor.getCurrentInlineStyle()).toBe(NONE);
      });

      it('uses left of the start if starting at end of block', () => {
        var blockB = mainEditor.getCurrentContent().getBlockForKey('b');
        var selection = selectionState.merge({
          anchorKey: 'b',
          anchorOffset: blockB.getLength(),
          focusKey: 'c',
          focusOffset: 3,
        });

        var editor = EditorState.acceptSelection(mainEditor, selection);
        expect(editor.getCurrentInlineStyle()).toBe(BOLD);
      });

      it('looks upward through empty blocks to find a character', () => {
        var selection = selectionState.merge({
          anchorKey: 'emptyA',
          anchorOffset: 0,
          focusKey: 'c',
          focusOffset: 3,
        });
        var editor = EditorState.acceptSelection(mainEditor, selection);
        expect(editor.getCurrentInlineStyle()).toBe(BOLD);
      });

      it('falls back to no style if in empty block at document start', () => {
        var editor = getEmptyLedMultiBlockEditorState(
          new SelectionState({
            anchorKey: 'emptyA',
            anchorOffset: 0,
            focusKey: 'c',
            focusOffset: 3,
            isBackward: false,
          })
        );
        expect(editor.getCurrentInlineStyle()).toBe(NONE);
      });
    });
  });

  describe('Decorator handling', () => {
    var boldA = List(Repeat('x', boldBlock.getLength()));
    var boldB = List(Repeat('y', boldBlock.getLength()));

    function Decorator() {}
    Decorator.prototype.getDecorations = jest.fn();

    function NextDecorator() {}
    NextDecorator.prototype.getDecorations = jest.fn();

    beforeEach(() => {
      Decorator.prototype.getDecorations.mockClear();
      Decorator.prototype.getDecorations.mockImplementation((v, c) => {
        return v === boldBlock ? boldA : List(Repeat(undefined, v.getLength()));
      });
    });

    it('must set a new decorator', () => {
      var decorator = new Decorator();
      var editorState = getDecoratedEditorState(decorator);
      expect(decorator.getDecorations.mock.calls.length).toBe(2);

      Decorator.prototype.getDecorations.mockImplementation((v, c) => {
        return v === boldBlock ? boldB : List(Repeat(undefined, v.getLength()));
      });
      var newDecorator = new NextDecorator();
      NextDecorator.prototype.getDecorations.mockImplementation((v, c) => {
        return v === boldBlock ? boldB : List(Repeat(undefined, v.getLength()));
      });

      var withNewDecorator = EditorState.set(editorState, {
        decorator: newDecorator,
      });
      expect(withNewDecorator).not.toBe(editorState);

      // Twice for the initial tree map generation, then twice more for
      // filter comparison.
      expect(decorator.getDecorations.mock.calls.length).toBe(4);

      // Twice for filter comparison, once for tree generation since one
      // block has the same decoration list and is filtered out.
      expect(newDecorator.getDecorations.mock.calls.length).toBe(3);

      expect(withNewDecorator.getDecorator()).toBe(newDecorator);

      // Preserve block trees that had the same decorator list.
      expect(
        editorState.getBlockTree(boldBlock.getKey())
      ).toBe(
        withNewDecorator.getBlockTree(boldBlock.getKey())
      );

      expect(
        editorState.getBlockTree(italicBlock.getKey())
      ).not.toBe(
        withNewDecorator.getBlockTree(italicBlock.getKey())
      );
    });

    it('must call decorator with correct argument types and order', () => {
      var decorator = new Decorator();
      getDecoratedEditorState(decorator);
      decorator.getDecorations.mock.calls.forEach((call) => {
        expect(call[0] instanceof ContentBlock).toBe(true);
        expect(call[1] instanceof ContentState).toBe(true);
      });
    });

    it('must correctly remove a decorator', () => {
      var decorator = new Decorator();
      var editorState = getDecoratedEditorState(decorator);
      expect(decorator.getDecorations.mock.calls.length).toBe(2);
      var withNewDecorator = EditorState.set(editorState, {decorator: null});
      expect(withNewDecorator).not.toBe(editorState);
      expect(withNewDecorator.getDecorator()).toBe(null);
      expect(decorator.getDecorations.mock.calls.length).toBe(2);
    });
  });
});
<|endoftext|>


<commit_before>import { injectReducer } from '../../store/reducers'

export default (store) => ({
  path : 'event/:id',
  /*  Async getComponent is only invoked when route matches   */
  getComponent (nextState, cb) {
    /*  Webpack - use 'require.ensure' to create a split point
        and embed an async module loader (jsonp) when bundling   */
    require.ensure([], (require) => {
      /*  Webpack - use require callback to define
          dependencies for bundling   */
      const SingleEvent = require('./containers/SingleEventContainer').default
      const reducer = require('./modules/singleEvent').default

      /*  Add the reducer to the store on key 'event'  */
      injectReducer(store, { key: 'events', reducer })

      /*  Return getComponent   */
      cb(null, SingleEvent)

    /* Webpack named bundle   */
    }, 'events')
  }
})
<commit_msg>fix singleEvent redux pt2<commit_after>import { injectReducer } from '../../store/reducers'

export default (store) => ({
  path : 'event/:id',
  /*  Async getComponent is only invoked when route matches   */
  getComponent (nextState, cb) {
    /*  Webpack - use 'require.ensure' to create a split point
        and embed an async module loader (jsonp) when bundling   */
    require.ensure([], (require) => {
      /*  Webpack - use require callback to define
          dependencies for bundling   */
      const SingleEvent = require('./containers/SingleEventContainer').default
      const reducer = require('./modules/singleEvent').default

      /*  Add the reducer to the store on key 'event'  */
      injectReducer(store, { key: 'singleEvent', reducer })

      /*  Return getComponent   */
      cb(null, SingleEvent)

    /* Webpack named bundle   */
    }, 'events')
  }
})
<|endoftext|>