<commit_before>function subscriberManagementPage() {
  var $page = $('#subscriber-management-page')
  var $subscribers = $page.find('.subscribers-list')
  var $subscriberNameQuery = $page.find('#subscriber-name-query')

  $page.on('show', function(event, subscriberId) {
    updateLocationHash(subscriberId || '')
    $.get('/subscribers?' + $.param({ roles: currentFilters() }), function(subscribers) {
      renderSubscribers(subscribers)

      // Apply subscriber search
      $subscriberNameQuery.trigger('input')

      if (subscriberId) {
        var $selected = $subscribers.find('.result[data-id=' + subscriberId + ']')
        openDetails($selected)
        var top = $selected.offset().top - 25
        $('body,html').animate({ scrollTop: top })
      }
    })
  })

  $subscriberNameQuery.on('input', function() {
    var searchString = $(this).val().toLowerCase()
    $subscribers.find('.result').each(function() {
      var name = $(this).children('.name').text().toLowerCase()
      $(this).toggle(_.contains(name, searchString))
    })
    closeDetails()
  })

  $page.find('.filters').change(function() { $page.trigger('show') })

  $subscribers.on('click', '.result', function() {
    var $this = $(this)
    var wasSelected = $this.hasClass('selected')
    closeDetails()
    if (!wasSelected) {
      openDetails($this)
    }
  })

  $page.find('button[name=new-subscriber]').on('click', function() {
    var $newSubscriberForm = renderNewSubscriberForm()

    $newSubscriberForm.find('.modify-only').remove()

    bindEventHandlers($newSubscriberForm, function(subscriberData) {
      subscriberData.roles = $newSubscriberForm.find('input[name=roles]')
        .filter(':checked').map(function() { return $(this).val() }).toArray()

      $.post('/accounts/', JSON.stringify(subscriberData), function(subscriber) {
        $subscribers.find('.result.selected').data('subscriber', subscriber)
        var $subscriber = renderSubscriber(subscriber).css('display', 'none')
        $subscribers.prepend($subscriber)
        $subscriber.slideToggle()
        closeDetails()
      })
    })

    $newSubscriberForm.find('input[name=roles]').on('change', function() {
      var $roles = $newSubscriberForm.find('input[name=roles]')
      if ($newSubscriberForm.find('input[name=roles]:checked').length >= 1) {
        $roles.get().forEach(function(e) { e.setCustomValidity('') })
      } else {
        $roles.get().forEach(function(e) { e.setCustomValidity('You must choose at least one role') })
      }
    })

    // This triggers validation for roles checkboxes, which are by default invalid
    $newSubscriberForm.find('input[name=roles]').trigger('change')

    closeDetails()
    $subscribers.addClass('selected').prepend($newSubscriberForm)
    $newSubscriberForm.slideDown()
  })

  function openDetails($row) {
    var subscriber = $row.data('subscriber')
    var $subscriberDetails = renderSubscriberDetails(subscriber)

    $subscriberDetails.find('.new-only').remove()

    if (!utils.hasRole(user, 'root')) {
      $subscriberDetails.find('button[name=remove]').remove()
    }

    bindEventHandlers($subscriberDetails, function(subscriberData) {
      $.post('/accounts/' + subscriber._id, JSON.stringify(subscriberData), function(subscriber) {
        $subscribers.find('.result.selected').replaceWith(renderSubscriber(subscriber))
        closeDetails()
      })
    })

    $subscriberDetails.find('button[name=remove]').click(function() {
      var $selected = $page.find('.result.selected')
      var subscriber = $selected.data('subscriber')
      showDialog($('#templates').find('.remove-subscriber-dialog').clone()
        .find('.subscriber-name').text(subscriber.name).end()
        .find('button[name=remove]').click(removeSubscriber).end()
        .find('button[name=cancel]').click(closeDialog).end())

      function removeSubscriber() {
        $.ajax('/accounts/' + subscriber._id, { type: 'DELETE' }).done(function() {
          closeDialog()
          closeDetails()
          $selected.slideUp(function() { $(this).remove() })
        })
      }
    })

    $row.addClass('selected').after($subscriberDetails)
    updateLocationHash(subscriber._id)
    $subscriberDetails.slideDown()
  }

  function bindEventHandlers($e, submitCallback) {
    $e.submit(function(event) {
      event.preventDefault()

      var subscriberData = {
        name: findInput('name').val(),
        emailAddresses: findInput('emails').select2('data').map(function(select2Pair) { return select2Pair.text }),
        yTunnus: findInput('yTunnus').val(),
        address: {
          street: findInput('street').val(),
          city: findInput('city').val(),
          zip: findInput('zip').val(),
          country: findInput('country').val()
        },
        billing: {
          invoiceText: $e.find('textarea[name=invoiceText]').val(),
          language: findInput('billingLanguage').val()
        },
        eInvoice: {},
        contactName: findInput('contactName').val(),
        phoneNumber: findInput('phoneNumber').val(),
        users: findInput('classifiers').select2('data').map(select2OptionToIdUsernamePair)
      }
      if ($e.find('input[name=billing-extra]').prop('checked')) {
        var extraBillingType = $e.find('input[name=billing-extra-type]:checked').val()
        if (extraBillingType === 'address') {
          subscriberData.billing.address = {
            street: findInput('billing.street').val(),
            city: findInput('billing.city').val(),
            zip: findInput('billing.zip').val(),
            country: findInput('billing.country').val()
          }
        } else if (extraBillingType === 'eInvoice') {
          subscriberData.eInvoice = {
            address: findInput('eInvoice.address').val(),
            operator: findInput('operator').val()
          }
        }
      }

      submitCallback(subscriberData)

      function findInput(name) {
        return $e.find('input[name="' + name + '"]')
      }
    })

    var $form = $e.find('form')

    $form.find('input').on('blur', function() {
      $(this).addClass('touched')
    })

    $form.on('input change', _.debounce(function() { $(this).trigger('validate') }, 200))

    $form.on('validate', function() {
      $(this).find('button[type=submit]').prop('disabled', !this.checkValidity())
    })

    $form.find('input[name=emails]').on('change', function(event) {
      $(this).addClass('touched')
      var emails = event.val
      if (!_.isEmpty(emails) && _.all(emails, validateEmail)) {
        this.setCustomValidity('')
        $(this).removeClass('invalid')
      } else {
        this.setCustomValidity('Invalid email')
        $(this).addClass('invalid')
      }

      function validateEmail(email) {
        return new RegExp('.+@.+\\..+').test(email)
      }
    })

    $form.find('input[name=billing-extra], input[name=billing-extra-type]').on('change click', function() {
      toggleBillingExtra($form)
    })

  }

  function toggleBillingExtra($form) {
    var extraBillingEnabled = $form.find('input[name=billing-extra]').prop('checked')
    $form.find('.billing-extra-fields input').prop('disabled', !extraBillingEnabled)

    if (extraBillingEnabled) {
      var type = $form.find('input[name=billing-extra-type]:checked').val()
      var $addressInputs = $form.find('.billing-extra-fields .billing-address input')
      var $eInvoiceInputs = $form.find('.billing-extra-fields .eInvoice input')

      $addressInputs.prop('disabled', type === 'eInvoice')
      $eInvoiceInputs.prop('disabled', type === 'address')
    }
  }

  function closeDetails() {
    $subscribers.find('.result.selected').removeClass('selected')
    $subscribers.find('.subscriber-details').slideUp(function() { $(this).remove() })
    updateLocationHash('')
  }

  function updateLocationHash(subscriberId) {
    location.hash = '#tilaajat/' + subscriberId
  }

  function renderSubscribers(subscribers) {
    $subscribers.empty()
    _(subscribers).sortBy('name').map(renderSubscriber).forEach(function(acc) { $subscribers.append(acc) })
  }

  function renderSubscriber(subscriber) {
    return $('<div>', { class: 'result', 'data-id': subscriber._id })
      .data('subscriber', subscriber)
      .append($('<span>', { class: 'name' }).text(subscriber.name))
      .append($('<span>', { class: 'roles' }).html(renderRoles(subscriber.roles)))
  }

  function renderRoles(roles) {
    if (_.isEmpty(roles)) return '<i class="icon-warning-sign"></i>'

    return _.map(roles, function(role) { return enums.roles[role] }).join(', ')
  }

  function currentFilters() {
    return $page.find('.filters input').filter(':checked').map(function() { return $(this).attr('name') }).toArray()
  }

  function renderSubscriberDetails(subscriber) {
    var $detailTemplate = renderSubscriberTemplate()
    var address = subscriber.address || false
    var billing = subscriber.billing || {}
    var billingAddress = billing.address || false
    var eInvoice = subscriber.eInvoice || false
    var extraBillingType = eInvoice ? 'eInvoice' : 'address'

    $detailTemplate
      .find('input[name=classifiers]').trigger('setVal', subscriber.users).end()
      .find('input[name=name]').val(subscriber.name).end()
      .find('input[name=yTunnus]').val(subscriber.yTunnus).end()
      .find('input[name=street]').val(address.street).end()
      .find('input[name=zip]').val(address.zip).end()
      .find('input[name=city]').val(address.city).end()
      .find('input[name=country]').val(address.country).end()
      .find('input[name=contactName]').val(subscriber.contactName).end()
      .find('input[name=phoneNumber]').val(subscriber.phoneNumber).end()
      .find('input[name=emails]').val(subscriber.emailAddresses).select2({
        tags: subscriber.emailAddresses,
        multiple: true
      }).end()
      .find('input[name="billing.street"]').val(billingAddress.street).end()
      .find('input[name="billing.zip"]').val(billingAddress.zip).end()
      .find('input[name="billing.city"]').val(billingAddress.city).end()
      .find('input[name="billing.country"]').val(billingAddress.country).end()
      .find('input[name="eInvoice.address"]').val(eInvoice.address).end()
      .find('input[name=operator]').val(eInvoice.operator).end()
      .find('input[name=billing-extra]').prop('checked', eInvoice || billingAddress).end()
      .find('input[name=billing-extra-type][value=' + extraBillingType + ']').prop('checked', true).end()
      .find('textarea[name=invoiceText]').val(billing.invoiceText).end()
      .find('input[name=billingLanguage]').val(billing.language).select2({
        data: getSelect2EnumDataFromKeyValMap(enums.billingLanguages)
      }).end()

    toggleBillingExtra($detailTemplate)

    return $detailTemplate
  }

  function select2OptionToIdUsernamePair(x) {
    if (!x) return null
    return { _id: x.id, name: x.name }
  }

  function renderSubscriberTemplate() {
    var $detailTemplate = $('#templates').find('.subscriber-details').clone()

    select2Autocomplete({
      $el: $detailTemplate.find('input[name=classifiers]'),
      path: function(term) { return '/users/search?q=' + encodeURIComponent(term) },
      multiple: true,
      toOption: function(x) {
        if (!x) return null
        return {
          id: x._id,
          text: x.name + (x.username ? ' (' + x.username + ')' : ''),
          name: x.username ? x.username : x.name
        }
      },
      fromOption: select2OptionToIdUsernamePair
    })

    $detailTemplate.find('input[name=billingLanguage]').select2({
      data: getSelect2EnumDataFromKeyValMap(enums.billingLanguages)
    })

    return $detailTemplate
  }

  function getSelect2EnumDataFromKeyValMap(keyValMap) {
    return Object.keys(keyValMap).map(function(key) { return { id: key, text: keyValMap[key] } })
  }

  function renderNewSubscriberForm() {
    var $detailTemplate = renderSubscriberTemplate()

    $detailTemplate.find('input[name=emails]').select2({
      tags: [],
      multiple: true
    }).end()

    toggleBillingExtra($detailTemplate)

    return $detailTemplate
  }
}
<commit_msg>Refactor select2 usage in subscriber management<commit_after>function subscriberManagementPage() {
  var $page = $('#subscriber-management-page')
  var $subscribers = $page.find('.subscribers-list')
  var $subscriberNameQuery = $page.find('#subscriber-name-query')

  $page.on('show', function(event, subscriberId) {
    updateLocationHash(subscriberId || '')
    $.get('/subscribers?' + $.param({ roles: currentFilters() }), function(subscribers) {
      renderSubscribers(subscribers)

      // Apply subscriber search
      $subscriberNameQuery.trigger('input')

      if (subscriberId) {
        var $selected = $subscribers.find('.result[data-id=' + subscriberId + ']')
        openDetails($selected)
        var top = $selected.offset().top - 25
        $('body,html').animate({ scrollTop: top })
      }
    })
  })

  $subscriberNameQuery.on('input', function() {
    var searchString = $(this).val().toLowerCase()
    $subscribers.find('.result').each(function() {
      var name = $(this).children('.name').text().toLowerCase()
      $(this).toggle(_.contains(name, searchString))
    })
    closeDetails()
  })

  $page.find('.filters').change(function() { $page.trigger('show') })

  $subscribers.on('click', '.result', function() {
    var $this = $(this)
    var wasSelected = $this.hasClass('selected')
    closeDetails()
    if (!wasSelected) {
      openDetails($this)
    }
  })

  $page.find('button[name=new-subscriber]').on('click', function() {
    var $newSubscriberForm = renderNewSubscriberForm()

    $newSubscriberForm.find('.modify-only').remove()

    bindEventHandlers($newSubscriberForm, function(subscriberData) {
      subscriberData.roles = $newSubscriberForm.find('input[name=roles]')
        .filter(':checked').map(function() { return $(this).val() }).toArray()

      $.post('/accounts/', JSON.stringify(subscriberData), function(subscriber) {
        $subscribers.find('.result.selected').data('subscriber', subscriber)
        var $subscriber = renderSubscriber(subscriber).css('display', 'none')
        $subscribers.prepend($subscriber)
        $subscriber.slideToggle()
        closeDetails()
      })
    })

    $newSubscriberForm.find('input[name=roles]').on('change', function() {
      var $roles = $newSubscriberForm.find('input[name=roles]')
      if ($newSubscriberForm.find('input[name=roles]:checked').length >= 1) {
        $roles.get().forEach(function(e) { e.setCustomValidity('') })
      } else {
        $roles.get().forEach(function(e) { e.setCustomValidity('You must choose at least one role') })
      }
    })

    // This triggers validation for roles checkboxes, which are by default invalid
    $newSubscriberForm.find('input[name=roles]').trigger('change')

    closeDetails()
    $subscribers.addClass('selected').prepend($newSubscriberForm)
    $newSubscriberForm.slideDown()
  })

  function openDetails($row) {
    var subscriber = $row.data('subscriber')
    var $subscriberDetails = renderSubscriberDetails(subscriber)

    $subscriberDetails.find('.new-only').remove()

    if (!utils.hasRole(user, 'root')) {
      $subscriberDetails.find('button[name=remove]').remove()
    }

    bindEventHandlers($subscriberDetails, function(subscriberData) {
      $.post('/accounts/' + subscriber._id, JSON.stringify(subscriberData), function(subscriber) {
        $subscribers.find('.result.selected').replaceWith(renderSubscriber(subscriber))
        closeDetails()
      })
    })

    $subscriberDetails.find('button[name=remove]').click(function() {
      var $selected = $page.find('.result.selected')
      var subscriber = $selected.data('subscriber')
      showDialog($('#templates').find('.remove-subscriber-dialog').clone()
        .find('.subscriber-name').text(subscriber.name).end()
        .find('button[name=remove]').click(removeSubscriber).end()
        .find('button[name=cancel]').click(closeDialog).end())

      function removeSubscriber() {
        $.ajax('/accounts/' + subscriber._id, { type: 'DELETE' }).done(function() {
          closeDialog()
          closeDetails()
          $selected.slideUp(function() { $(this).remove() })
        })
      }
    })

    $row.addClass('selected').after($subscriberDetails)
    updateLocationHash(subscriber._id)
    $subscriberDetails.slideDown()
  }

  function bindEventHandlers($e, submitCallback) {
    $e.submit(function(event) {
      event.preventDefault()

      var subscriberData = {
        name: findInput('name').val(),
        emailAddresses: findInput('emails').select2('data').map(function(select2Pair) { return select2Pair.text }),
        yTunnus: findInput('yTunnus').val(),
        address: {
          street: findInput('street').val(),
          city: findInput('city').val(),
          zip: findInput('zip').val(),
          country: findInput('country').val()
        },
        billing: {
          invoiceText: $e.find('textarea[name=invoiceText]').val(),
          language: findInput('billingLanguage').val()
        },
        eInvoice: {},
        contactName: findInput('contactName').val(),
        phoneNumber: findInput('phoneNumber').val(),
        users: findInput('classifiers').select2('data').map(select2OptionToIdUsernamePair)
      }
      if ($e.find('input[name=billing-extra]').prop('checked')) {
        var extraBillingType = $e.find('input[name=billing-extra-type]:checked').val()
        if (extraBillingType === 'address') {
          subscriberData.billing.address = {
            street: findInput('billing.street').val(),
            city: findInput('billing.city').val(),
            zip: findInput('billing.zip').val(),
            country: findInput('billing.country').val()
          }
        } else if (extraBillingType === 'eInvoice') {
          subscriberData.eInvoice = {
            address: findInput('eInvoice.address').val(),
            operator: findInput('operator').val()
          }
        }
      }

      submitCallback(subscriberData)

      function findInput(name) {
        return $e.find('input[name="' + name + '"]')
      }
    })

    var $form = $e.find('form')

    $form.find('input').on('blur', function() {
      $(this).addClass('touched')
    })

    $form.on('input change', _.debounce(function() { $(this).trigger('validate') }, 200))

    $form.on('validate', function() {
      $(this).find('button[type=submit]').prop('disabled', !this.checkValidity())
    })

    $form.find('input[name=emails]').on('change', function(event) {
      $(this).addClass('touched')
      var emails = event.val
      if (!_.isEmpty(emails) && _.all(emails, validateEmail)) {
        this.setCustomValidity('')
        $(this).removeClass('invalid')
      } else {
        this.setCustomValidity('Invalid email')
        $(this).addClass('invalid')
      }

      function validateEmail(email) {
        return new RegExp('.+@.+\\..+').test(email)
      }
    })

    $form.find('input[name=billing-extra], input[name=billing-extra-type]').on('change click', function() {
      toggleBillingExtra($form)
    })

  }

  function toggleBillingExtra($form) {
    var extraBillingEnabled = $form.find('input[name=billing-extra]').prop('checked')
    $form.find('.billing-extra-fields input').prop('disabled', !extraBillingEnabled)

    if (extraBillingEnabled) {
      var type = $form.find('input[name=billing-extra-type]:checked').val()
      var $addressInputs = $form.find('.billing-extra-fields .billing-address input')
      var $eInvoiceInputs = $form.find('.billing-extra-fields .eInvoice input')

      $addressInputs.prop('disabled', type === 'eInvoice')
      $eInvoiceInputs.prop('disabled', type === 'address')
    }
  }

  function closeDetails() {
    $subscribers.find('.result.selected').removeClass('selected')
    $subscribers.find('.subscriber-details').slideUp(function() { $(this).remove() })
    updateLocationHash('')
  }

  function updateLocationHash(subscriberId) {
    location.hash = '#tilaajat/' + subscriberId
  }

  function renderSubscribers(subscribers) {
    $subscribers.empty()
    _(subscribers).sortBy('name').map(renderSubscriber).forEach(function(acc) { $subscribers.append(acc) })
  }

  function renderSubscriber(subscriber) {
    return $('<div>', { class: 'result', 'data-id': subscriber._id })
      .data('subscriber', subscriber)
      .append($('<span>', { class: 'name' }).text(subscriber.name))
      .append($('<span>', { class: 'roles' }).html(renderRoles(subscriber.roles)))
  }

  function renderRoles(roles) {
    if (_.isEmpty(roles)) return '<i class="icon-warning-sign"></i>'

    return _.map(roles, function(role) { return enums.roles[role] }).join(', ')
  }

  function currentFilters() {
    return $page.find('.filters input').filter(':checked').map(function() { return $(this).attr('name') }).toArray()
  }

  function renderSubscriberDetails(subscriber) {
    var $detailTemplate = renderSubscriberTemplate()
    var address = subscriber.address || false
    var billing = subscriber.billing || {}
    var billingAddress = billing.address || false
    var eInvoice = subscriber.eInvoice || false
    var extraBillingType = eInvoice ? 'eInvoice' : 'address'

    $detailTemplate
      .find('input[name=classifiers]').trigger('setVal', subscriber.users).end()
      .find('input[name=name]').val(subscriber.name).end()
      .find('input[name=yTunnus]').val(subscriber.yTunnus).end()
      .find('input[name=street]').val(address.street).end()
      .find('input[name=zip]').val(address.zip).end()
      .find('input[name=city]').val(address.city).end()
      .find('input[name=country]').val(address.country).end()
      .find('input[name=contactName]').val(subscriber.contactName).end()
      .find('input[name=phoneNumber]').val(subscriber.phoneNumber).end()
      .find('input[name=emails]').select2('val', subscriber.emailAddresses).end()
      .find('input[name="billing.street"]').val(billingAddress.street).end()
      .find('input[name="billing.zip"]').val(billingAddress.zip).end()
      .find('input[name="billing.city"]').val(billingAddress.city).end()
      .find('input[name="billing.country"]').val(billingAddress.country).end()
      .find('input[name="eInvoice.address"]').val(eInvoice.address).end()
      .find('input[name=operator]').val(eInvoice.operator).end()
      .find('input[name=billing-extra]').prop('checked', eInvoice || billingAddress).end()
      .find('input[name=billing-extra-type][value=' + extraBillingType + ']').prop('checked', true).end()
      .find('textarea[name=invoiceText]').val(billing.invoiceText).end()
      .find('input[name=billingLanguage]').select2('val', billing.language).end()

    toggleBillingExtra($detailTemplate)

    return $detailTemplate
  }

  function select2OptionToIdUsernamePair(x) {
    if (!x) return null
    return { _id: x.id, name: x.name }
  }

  function renderSubscriberTemplate() {
    var $detailTemplate = $('#templates').find('.subscriber-details').clone()

    select2Autocomplete({
      $el: $detailTemplate.find('input[name=classifiers]'),
      path: function(term) { return '/users/search?q=' + encodeURIComponent(term) },
      multiple: true,
      toOption: function(x) {
        if (!x) return null
        return {
          id: x._id,
          text: x.name + (x.username ? ' (' + x.username + ')' : ''),
          name: x.username ? x.username : x.name
        }
      },
      fromOption: select2OptionToIdUsernamePair
    })

    $detailTemplate.find('input[name=emails]').select2({
      tags: [],
      multiple: true
    }).end()

    $detailTemplate.find('input[name=billingLanguage]').select2({
      data: select2DataFromEnumObject(enums.billingLanguages)
    })

    return $detailTemplate
  }

  function select2DataFromEnumObject(object) {
    return _.map(object, function(value, key) { return { id: key, text: value }})
  }

  function renderNewSubscriberForm() {
    var $detailTemplate = renderSubscriberTemplate()

    toggleBillingExtra($detailTemplate)

    return $detailTemplate
  }
}
<|endoftext|>


<commit_before>import layoutsIncluded from '../layouts-included';
import { LAYOUT_CHANGE, CMD_VIEW, SUB_LAYOUT, SUBLAYOUT_CHANGE } from 'constants';
import config from 'config/config';

const initialState = {
    current: config.backendLayouts ? null : "layout1",
    loaded: {
      ...layoutsIncluded,
    },
    sublayout: {},
    currentView: null,
    currentSublayout: null
};

export default function reducer( state = initialState, action ) {
  switch ( action.type ) {

    case LAYOUT_CHANGE:

      const loaded = state.loaded;

      if ( !config.backendLayouts ) {
        return {
         ...state,
         current: action.payload.code,
         currentSublayout: null,
         currentView: null,
        };
      }

      if (action.payload.data) {
        loaded[action.payload.code] = action.payload.data;
      }

      return {
        ...state,
        current: action.payload.code,
        loaded
      };

    case CMD_VIEW:

        const newLayoutCode = action.payload.code;
        if(newLayoutCode) {
            return {
                ...state,
                currentView: {
                    code: newLayoutCode,
                    dataCode: action.payload.root
                },
                currentSublayout: null
            };
        }

    case SUBLAYOUT_CHANGE:

        const newSublayoutCode = action.payload.code;
        const newSublayout = action.payload.items;
        if(newSublayoutCode) {
            return {
                ...state,
                currentView: null,
                currentSublayout: {
                    code: newSublayoutCode,
                    layout: [newSublayout]
                }
            }
        }

    case SUB_LAYOUT:

        let sublayout_code = action.payload.code;
        let layout = action.payload.items;
        if(sublayout_code && layout) {
            return {
                ...state,
                sublayout: {
                    ...state.sublayout,
                    [sublayout_code]: {
                        layout: [layout]
                    }
                }
            };
        }

    default:
      return state;
  }
}
<commit_msg>update command layout<commit_after>import layoutsIncluded from '../layouts-included';
import { LAYOUT_CHANGE, CMD_VIEW, SUB_LAYOUT, SUBLAYOUT_CHANGE } from 'constants';
import config from 'config/config';

const initialState = {
    current: config.backendLayouts ? null : "layout1",
    loaded: {
      ...layoutsIncluded,
    },
    sublayout: {},
    currentView: null,
    currentSublayout: null
};

export default function reducer( state = initialState, action ) {
  switch ( action.type ) {

    case LAYOUT_CHANGE:

      const loaded = state.loaded;

      if ( !config.backendLayouts ) {
        return {
         ...state,
         current: action.payload.code,
         currentSublayout: null,
         currentView: null,
        };
      }

      if (action.payload.data) {
        loaded[action.payload.code] = action.payload.data;
      }

      return {
        ...state,
        current: action.payload.code,
        currentSublayout: null,
        currentView: null,
        loaded
      };

    case CMD_VIEW:

        const newLayoutCode = action.payload.code;
        if(newLayoutCode) {
            return {
                ...state,
                currentView: {
                    code: newLayoutCode,
                    dataCode: action.payload.root
                },
                currentSublayout: null
            };
        }

    case SUBLAYOUT_CHANGE:

        const newSublayoutCode = action.payload.code;
        const newSublayout = action.payload.items;
        if(newSublayoutCode) {
            return {
                ...state,
                currentView: null,
                currentSublayout: {
                    code: newSublayoutCode,
                    layout: [newSublayout]
                }
            }
        }

    case SUB_LAYOUT:

        let sublayout_code = action.payload.code;
        let layout = action.payload.items;
        if(sublayout_code && layout) {
            return {
                ...state,
                sublayout: {
                    ...state.sublayout,
                    [sublayout_code]: {
                        layout: [layout]
                    }
                }
            };
        }

    default:
      return state;
  }
}
<|endoftext|>


<commit_before>define([
    'backgrid',
    'underscore',
    'orotranslation/js/translator'
], function(Backgrid, _, __) {
    'use strict';

    var TagsCell;

    /**
     * Cell able to display tags values.
     *
     * Requires income data format:
     * ```javascript
     * var cellValue = [{id: 1, text: 'tag-1', locked: false}, {id: 2, text: 'tag-2', locked: true}, ...];
     * ```
     *
     * Also please prepare and pass choices through cell configuration
     *
     * @export  oro/datagrid/cell/tags-cell
     * @class   oro.datagrid.cell.TagsCell
     * @extends oro.datagrid.cell.StringCell
     */
    TagsCell = Backgrid.StringCell.extend({
        /**
         * @property {string}
         */
        type: 'tags',

        /**
         * @property {string}
         */
        className: 'tags-cell',

        /**
         * @inheritDoc
         */
        render: function() {
            var value = this.model.get(this.column.get('name'));
            var value = TEST_DATA;
            var html = '';

            if (value === null || value === void 0) {
                // assume empty
                value = [];
            }

            if (_.isArray(value) && value.length) {
                html = value.map(function(v) {
                    return '' + v.text + ' ';
                });
            } else {
                html = 'N/A';
            }

            this.$el.html(html);

            return this;
        }
    });

    return TagsCell;
});
<commit_msg>CRM-4656 CRM-4551 Removed initialization value by test data<commit_after>define([
    'backgrid',
    'underscore',
    'orotranslation/js/translator'
], function(Backgrid, _, __) {
    'use strict';

    var TagsCell;

    /**
     * Cell able to display tags values.
     *
     * Requires income data format:
     * ```javascript
     * var cellValue = [{id: 1, text: 'tag-1', locked: false}, {id: 2, text: 'tag-2', locked: true}, ...];
     * ```
     *
     * Also please prepare and pass choices through cell configuration
     *
     * @export  oro/datagrid/cell/tags-cell
     * @class   oro.datagrid.cell.TagsCell
     * @extends oro.datagrid.cell.StringCell
     */
    TagsCell = Backgrid.StringCell.extend({
        /**
         * @property {string}
         */
        type: 'tags',

        /**
         * @property {string}
         */
        className: 'tags-cell',

        /**
         * @inheritDoc
         */
        render: function() {
            var value = this.model.get(this.column.get('name'));
            var html = '';

            if (value === null || value === void 0) {
                // assume empty
                value = [];
            }

            if (_.isArray(value) && value.length) {
                html = value.map(function(v) {
                    return '' + v.text + ' ';
                });
            } else {
                html = 'N/A';
            }

            this.$el.html(html);

            return this;
        }
    });

    return TagsCell;
});
<|endoftext|>


<commit_before>/**
 * @fileoverview Provides a D3js component to be used to draw an elevation
 * profile chart.
 *
 * Example usage:
 *
 * var selection = d3.select('#element_id');
 * var profile = ngeo.profile({
 *  elevationExtractor: {
 *    z: function (item) {return item['values']['z'];)},
 *    dist: function (item) {return item['dist'];)}
 *  },
 *  hoverCallback: function(point) {
 *    console.log(point.x, point.y);
 *  },
 *  outCallback: function() {
 *    console.log("out");
 *  }});
 * selection.datum(data).call(profile);
 *
 * The selection data must be an array.
 * The layout for the items of this array is unconstrained: the elevation
 * and distance values are extracted using the elevationExtractor config
 * option. Optionally, POIs can be displayed and depend on a poiExtractor
 * config option.
 *
 * The data below will work for the above example:
 * [
 *     {
 *         "y": 199340,
 *         "values": {"z": 788.7},
 *         "dist": 0.0,
 *         "x": 541620
 *     }, ...
 * ]
 */
goog.provide('ngeo.profile');

/**
 *
 * @return {Object}
 * @param {ngeox.profile.ProfileOptions} options
 * @export
 *
 */
ngeo.profile = function(options) {
  /**
   * @type {boolean}
   * Whether the simplified profile should be shown.
   */
  var light = goog.isDef(options.light) ? options.light : false;

  /**
   * The values for margins around the chart defined in pixels.
   */
  var margin = light ? {top: 0, right: 0, bottom: 0, left: 0} :
      {top: 10, right: 20, bottom: 30, left: 40};

  /**
   * Method to get the coordinate in pixels from a distance.
   */
  var bisectDistance = d3.bisector(function(d) {
    return elevationExtractor.dist(d);
  }).left;

  /**
   * @type {function(Object)}
   * Hover callback function.
   */
  var hoverCallback = goog.isDef(options.hoverCallback) ?
      options.hoverCallback : goog.nullFunction;

  /**
   * @type {function()}
   * Out callback function.
   */
  var outCallback = goog.isDef(options.outCallback) ?
      options.outCallback : goog.nullFunction;

  /**
   * Elevation data extractor used to get the dist and elevation values.
   */
  var elevationExtractor = options.elevationExtractor;

  /**
   * POI data extractor.
   */
  var poiExtractor = options.poiExtractor;

  /**
   * Optional SVG inline style.
   */
  var styleDefs = options.styleDefs;

  /**
   * @type {number}
   */
  var poiLabelAngle = goog.isDef(options.poiLabelAngle) ?
      options.poiLabelAngle : -60;

  /**
   * @type {function(number): number|undefined}
   */
  var ratioXYRule = options.ratioXYRule;

  /**
   * @type {ngeox.profile.ProfileFormatter}
   */
  var formatter = goog.isDef(options.formatter) ?
      options.formatter : {
        xhover: function(dist, units) {
          return parseFloat(dist.toPrecision(3)) + ' ' + units;
        },
        yhover: function(ele, units) { return Math.round(ele) + ' m'; },
        xtick: function(dist, units) { return dist; },
        ytick: function(ele, units) { return ele; }
      };

  /**
   * @type {boolean}
   */
  var lightXAxis = goog.isDef(options.lightXAxis) ? options.lightXAxis : false;

  /**
   * @type {number|undefined}
   */
  var yLowerBound = options.yLowerBound;

  // Objects shared with the showPois function
  /**
   * @type {Object}
   */
  var svg;

  /**
   * D3 x scale.
   */
  var x;

  /**
   * D3 y scale.
   */
  var y;

  var profile = function(selection) {
    selection.each(function(data) {
      /**
      * Distance units. Either 'm' or 'km'.
      */
      var units;

      /**
      * Factor to determine whether to use 'm' or 'km'.
      */
      var xFactor;

      var extractor = elevationExtractor;

      var width = Math.max(this.clientWidth - margin.right - margin.left, 0);
      x = d3.scale.linear().range([0, width]);

      var height = Math.max(this.clientHeight - margin.top - margin.bottom, 0);
      y = d3.scale.linear().range([height, 0]);

      var xAxis = d3.svg.axis().scale(x).orient('bottom');
      var yAxis = d3.svg.axis()
          .scale(y)
          .orient('left');

      var area = d3.svg.area()
          .x(function(d) { return x(extractor.dist(d)); })
          .y0(height)
          .y1(function(d) { return y(extractor.z(d)); });
      var line = d3.svg.line()
          .x(function(d) { return x(extractor.dist(d)); })
          .y(function(d) { return y(extractor.z(d)); });

      // Select the svg element, if it exists.
      svg = d3.select(this).selectAll('svg').data([data]);

      // Otherwise, create the skeletal chart.
      var svgEnter = svg.enter().append('svg');
      if (goog.isDef(styleDefs)) {
        svgEnter.append('defs').append('style')
          .attr('type', 'text/css')
          .text(styleDefs);
      }
      var gEnter = svgEnter.append('g');
      clearPois();

      gEnter.style('font', '11px Arial');
      gEnter.append('path').attr('class', 'area')
          .style('fill', 'rgba(222, 222, 222, 0.5)');
      gEnter.append('path').attr('class', 'line')
          .style('stroke', '#F00')
          .style('fill', 'none');

      gEnter.insert('g', ':first-child')
          .attr('class', 'grid-y');

      if (!light) {
        gEnter.append('g')
          .attr('class', 'x axis')
          .attr('transform', 'translate(0,' + height + ')');

        gEnter.append('text')
          .attr('class', 'x label')
          .attr('text-anchor', 'end')
          .attr('x', width - 4)
          .attr('y', height - 4);

        gEnter.append('g')
          .attr('class', 'y axis');

        gEnter.append('text')
          .attr('class', 'y label')
          .attr('text-anchor', 'end')
          .attr('y', 6)
          .attr('dy', '.75em')
          .attr('transform', 'rotate(-90)')
          .style('fill', 'grey')
          .text('elevation (m)');

        gEnter.append('g')
          .attr('class', 'metas')
          .attr('transform', 'translate(' + (width + 3) + ', 0)');
      }

      gEnter.append('g').attr('class', 'pois');

      var yHover = gEnter.append('g').attr('class', 'y grid-hover');
      yHover.append('svg:line').attr('stroke-dasharray', '5,5');
      yHover.append('text');

      var xHover = gEnter.append('g').attr('class', 'x grid-hover');
      xHover.append('svg:line').attr('stroke-dasharray', '5,5');
      xHover.append('text');

      gEnter.append('rect')
          .attr('class', 'overlay')
          .attr('width', width)
          .attr('height', height)
          .style('fill', 'none')
          .style('pointer-events', 'all');

      // Update the outer dimensions.
      svg.attr('width', width + margin.left + margin.right)
          .attr('height', height + margin.top + margin.bottom);

      // Update the inner dimensions.
      var g = svg.select('g')
          .attr('transform', 'translate(' + margin.left + ',' +
              margin.top + ')');

      var xDomain = d3.extent(data, function(d) { return extractor.dist(d); });
      x.domain(xDomain);

      var yDomain = d3.extent(data, function(d) { return extractor.z(d); });
      var padding = (yDomain[1] - yDomain[0]) * 0.1;
      y.domain([yDomain[0] - padding, yDomain[1] + padding]);

      // set the ratio according to the horizontal distance
      if (goog.isDef(ratioXYRule)) {
        var ratioXY = ratioXYRule(xDomain[1]);
        if (ratioXY > 0) {
          var yMean = (yDomain[1] - yDomain[0]) / 2 + yDomain[0];
          var xResolution = (xDomain[1] - xDomain[0]) / width;
          var yTarget2 = ratioXY * xResolution * height / 2;
          y.domain([yMean - yTarget2, yMean + yTarget2]);
        }
      }

      // Lower bound for y-axis
      if (goog.isDef(yLowerBound) && y.domain()[0] < yLowerBound) {
        var shift = yLowerBound - y.domain()[0];
        y.domain([yLowerBound, y.domain()[1] - shift]);
      }

      // Update the area path.
      g.select('.area')
          .transition()
          .attr('d', area);
      g.select('.line')
          .transition()
          .attr('d', line);

      if (xDomain[1] > 2000) {
        xFactor = 1000;
        units = 'km';
      } else {
        xFactor = 1;
        units = 'm';
      }

      if (!light) {
        xAxis.tickFormat(function(d) {
          return formatter.xtick(d / xFactor, units);
        });
        if (lightXAxis) {
          xAxis.tickValues([0, x.domain()[1]]);
        }

        yAxis.tickFormat(function(d) {
          return formatter.ytick(d, 'm');
        });

        g.select('.x.axis')
          .transition()
          .call(xAxis);

        g.select('.x.label')
          .text('distance (' + units + ')')
          .style('fill', 'grey')
          .style('shape-rendering', 'crispEdges');

        g.select('.y.axis')
          .transition()
          .call(yAxis);
      }

      g.select('.grid-y')
          .transition()
          .call(yAxis.tickSize(-width, 0, 0).tickFormat(''))
          .selectAll('.tick line')
          .style('stroke', '#ccc')
          .style('opacity', 0.7);

      g.selectAll('.axis').selectAll('path, line')
          .style('fill', 'none')
          .style('stroke', '#000')
          .style('shape-rendering', 'crispEdges');

      g.selectAll('.grid-hover line')
          .style('stroke', '#222')
          .style('opacity', 0.8);

      g.select('.overlay')
          .on('mouseout', mouseout)
          .on('mousemove', mousemove);

      function mousemove() {
        var mouseX = d3.mouse(this)[0];
        var x0 = x.invert(mouseX);
        var i = bisectDistance(data, x0, 1);

        var point = data[i];
        var elevation = extractor.z(point);
        var dist = extractor.dist(point);

        g.select('.x.grid-hover')
            .style('display', 'inline')
            .select('line')
            .attr('x1', x(dist))
            .attr('y1', height)
            .attr('x2', x(dist))
            .attr('y2', y(elevation));

        g.select('.y.grid-hover')
            .style('display', 'inline')
            .select('line')
            .attr('x1', x(0))
            .attr('y1', y(elevation))
            .attr('x2', width)
            .attr('y2', y(elevation));

        var right = x0 > xDomain[1] / 2;
        var xtranslate = x(dist);
        xtranslate += right ? -10 : 10;

        g.select('.x.grid-hover text')
            .text(formatter.xhover(dist / xFactor, units))
            .style('text-anchor', right ? 'end' : 'start')
            .attr('transform', 'translate(' + xtranslate + ',' +
                (height - 10) + ')');

        g.select('.y.grid-hover text')
            .text(formatter.yhover(elevation, 'm'))
            .style('text-anchor', right ? 'end' : 'start')
            .attr('transform', 'translate(' + xtranslate + ',' +
                (y(elevation) - 10) + ')');
        hoverCallback.call(null, point);
      }

      function mouseout() {
        g.selectAll('.grid-hover')
            .style('display', 'none');
        outCallback.call(null);
      }
    });
  };

  profile.showPois = function(pois) {
    pois = goog.isDef(pois) ? pois : [];
    goog.asserts.assert(pois.length === 0 || goog.isDef(poiExtractor));

    var pe = poiExtractor;
    var g = svg.select('g');
    var profileData = svg.datum();
    var ps = g.select('.pois');

    var p = ps.selectAll('.poi').data(pois, function(d) {
      var i = bisectDistance(profileData, Math.round(pe.dist(d) * 10) / 10, 1);
      var point = profileData[i];
      if (point) {
        var z = elevationExtractor.z(point);
        pe.z(d, z);
      }
      return pe.id(d);
    });

    var poiEnterG = p.enter()
      .append('g')
      .attr('class', 'poi');

    poiEnterG.append('text')
      .attr('x', light ? 0 : 9)
      .attr('dy', '.35em')
      .attr('text-anchor', light ? 'middle' : 'start');

    poiEnterG.append('line')
      .style('shape-rendering', 'crispEdges');

    p.style('opacity', 0)
      .transition()
      .duration(1000)
      .delay(100)
      .style('opacity', 1);

    p.selectAll('text')
      .attr('transform', function(d) {
          if (light) {
            return ['translate(',
              x(pe.dist(d)), ',',
              y(pe.z(d)) - 10, ')'
            ].join('');
          } else {
            return ['translate(',
              x(pe.dist(d)), ',',
              y(pe.z(d)) - 20, ') rotate(', poiLabelAngle, ')'
            ].join('');
          }
        })
      .text(function(d) {
          return pe.sort(d) + (light ? '' : (' - ' + pe.title(d)));
        });

    p.selectAll('line')
       .style('stroke', 'grey')
       .attr('x1', function(d) { return x(pe.dist(d));})
       .attr('y1', function(d) { return y(y.domain()[0]);})
       .attr('x2', function(d) { return x(pe.dist(d));})
       .attr('y2', function(d) { return y(pe.z(d));});

    // remove unused pois
    p.exit().remove();
  };

  function clearPois() {
    profile.showPois([]);
  }

  return profile;
};
<commit_msg>Clean call to tickSize<commit_after>/**
 * @fileoverview Provides a D3js component to be used to draw an elevation
 * profile chart.
 *
 * Example usage:
 *
 * var selection = d3.select('#element_id');
 * var profile = ngeo.profile({
 *  elevationExtractor: {
 *    z: function (item) {return item['values']['z'];)},
 *    dist: function (item) {return item['dist'];)}
 *  },
 *  hoverCallback: function(point) {
 *    console.log(point.x, point.y);
 *  },
 *  outCallback: function() {
 *    console.log("out");
 *  }});
 * selection.datum(data).call(profile);
 *
 * The selection data must be an array.
 * The layout for the items of this array is unconstrained: the elevation
 * and distance values are extracted using the elevationExtractor config
 * option. Optionally, POIs can be displayed and depend on a poiExtractor
 * config option.
 *
 * The data below will work for the above example:
 * [
 *     {
 *         "y": 199340,
 *         "values": {"z": 788.7},
 *         "dist": 0.0,
 *         "x": 541620
 *     }, ...
 * ]
 */
goog.provide('ngeo.profile');

/**
 *
 * @return {Object}
 * @param {ngeox.profile.ProfileOptions} options
 * @export
 *
 */
ngeo.profile = function(options) {
  /**
   * @type {boolean}
   * Whether the simplified profile should be shown.
   */
  var light = goog.isDef(options.light) ? options.light : false;

  /**
   * The values for margins around the chart defined in pixels.
   */
  var margin = light ? {top: 0, right: 0, bottom: 0, left: 0} :
      {top: 10, right: 20, bottom: 30, left: 40};

  /**
   * Method to get the coordinate in pixels from a distance.
   */
  var bisectDistance = d3.bisector(function(d) {
    return elevationExtractor.dist(d);
  }).left;

  /**
   * @type {function(Object)}
   * Hover callback function.
   */
  var hoverCallback = goog.isDef(options.hoverCallback) ?
      options.hoverCallback : goog.nullFunction;

  /**
   * @type {function()}
   * Out callback function.
   */
  var outCallback = goog.isDef(options.outCallback) ?
      options.outCallback : goog.nullFunction;

  /**
   * Elevation data extractor used to get the dist and elevation values.
   */
  var elevationExtractor = options.elevationExtractor;

  /**
   * POI data extractor.
   */
  var poiExtractor = options.poiExtractor;

  /**
   * Optional SVG inline style.
   */
  var styleDefs = options.styleDefs;

  /**
   * @type {number}
   */
  var poiLabelAngle = goog.isDef(options.poiLabelAngle) ?
      options.poiLabelAngle : -60;

  /**
   * @type {function(number): number|undefined}
   */
  var ratioXYRule = options.ratioXYRule;

  /**
   * @type {ngeox.profile.ProfileFormatter}
   */
  var formatter = goog.isDef(options.formatter) ?
      options.formatter : {
        xhover: function(dist, units) {
          return parseFloat(dist.toPrecision(3)) + ' ' + units;
        },
        yhover: function(ele, units) { return Math.round(ele) + ' m'; },
        xtick: function(dist, units) { return dist; },
        ytick: function(ele, units) { return ele; }
      };

  /**
   * @type {boolean}
   */
  var lightXAxis = goog.isDef(options.lightXAxis) ? options.lightXAxis : false;

  /**
   * @type {number|undefined}
   */
  var yLowerBound = options.yLowerBound;

  // Objects shared with the showPois function
  /**
   * @type {Object}
   */
  var svg;

  /**
   * D3 x scale.
   */
  var x;

  /**
   * D3 y scale.
   */
  var y;

  var profile = function(selection) {
    selection.each(function(data) {
      /**
      * Distance units. Either 'm' or 'km'.
      */
      var units;

      /**
      * Factor to determine whether to use 'm' or 'km'.
      */
      var xFactor;

      var extractor = elevationExtractor;

      var width = Math.max(this.clientWidth - margin.right - margin.left, 0);
      x = d3.scale.linear().range([0, width]);

      var height = Math.max(this.clientHeight - margin.top - margin.bottom, 0);
      y = d3.scale.linear().range([height, 0]);

      var xAxis = d3.svg.axis().scale(x).orient('bottom');
      var yAxis = d3.svg.axis()
          .scale(y)
          .orient('left');

      var area = d3.svg.area()
          .x(function(d) { return x(extractor.dist(d)); })
          .y0(height)
          .y1(function(d) { return y(extractor.z(d)); });
      var line = d3.svg.line()
          .x(function(d) { return x(extractor.dist(d)); })
          .y(function(d) { return y(extractor.z(d)); });

      // Select the svg element, if it exists.
      svg = d3.select(this).selectAll('svg').data([data]);

      // Otherwise, create the skeletal chart.
      var svgEnter = svg.enter().append('svg');
      if (goog.isDef(styleDefs)) {
        svgEnter.append('defs').append('style')
          .attr('type', 'text/css')
          .text(styleDefs);
      }
      var gEnter = svgEnter.append('g');
      clearPois();

      gEnter.style('font', '11px Arial');
      gEnter.append('path').attr('class', 'area')
          .style('fill', 'rgba(222, 222, 222, 0.5)');
      gEnter.append('path').attr('class', 'line')
          .style('stroke', '#F00')
          .style('fill', 'none');

      gEnter.insert('g', ':first-child')
          .attr('class', 'grid-y');

      if (!light) {
        gEnter.append('g')
          .attr('class', 'x axis')
          .attr('transform', 'translate(0,' + height + ')');

        gEnter.append('text')
          .attr('class', 'x label')
          .attr('text-anchor', 'end')
          .attr('x', width - 4)
          .attr('y', height - 4);

        gEnter.append('g')
          .attr('class', 'y axis');

        gEnter.append('text')
          .attr('class', 'y label')
          .attr('text-anchor', 'end')
          .attr('y', 6)
          .attr('dy', '.75em')
          .attr('transform', 'rotate(-90)')
          .style('fill', 'grey')
          .text('elevation (m)');

        gEnter.append('g')
          .attr('class', 'metas')
          .attr('transform', 'translate(' + (width + 3) + ', 0)');
      }

      gEnter.append('g').attr('class', 'pois');

      var yHover = gEnter.append('g').attr('class', 'y grid-hover');
      yHover.append('svg:line').attr('stroke-dasharray', '5,5');
      yHover.append('text');

      var xHover = gEnter.append('g').attr('class', 'x grid-hover');
      xHover.append('svg:line').attr('stroke-dasharray', '5,5');
      xHover.append('text');

      gEnter.append('rect')
          .attr('class', 'overlay')
          .attr('width', width)
          .attr('height', height)
          .style('fill', 'none')
          .style('pointer-events', 'all');

      // Update the outer dimensions.
      svg.attr('width', width + margin.left + margin.right)
          .attr('height', height + margin.top + margin.bottom);

      // Update the inner dimensions.
      var g = svg.select('g')
          .attr('transform', 'translate(' + margin.left + ',' +
              margin.top + ')');

      var xDomain = d3.extent(data, function(d) { return extractor.dist(d); });
      x.domain(xDomain);

      var yDomain = d3.extent(data, function(d) { return extractor.z(d); });
      var padding = (yDomain[1] - yDomain[0]) * 0.1;
      y.domain([yDomain[0] - padding, yDomain[1] + padding]);

      // set the ratio according to the horizontal distance
      if (goog.isDef(ratioXYRule)) {
        var ratioXY = ratioXYRule(xDomain[1]);
        if (ratioXY > 0) {
          var yMean = (yDomain[1] - yDomain[0]) / 2 + yDomain[0];
          var xResolution = (xDomain[1] - xDomain[0]) / width;
          var yTarget2 = ratioXY * xResolution * height / 2;
          y.domain([yMean - yTarget2, yMean + yTarget2]);
        }
      }

      // Lower bound for y-axis
      if (goog.isDef(yLowerBound) && y.domain()[0] < yLowerBound) {
        var shift = yLowerBound - y.domain()[0];
        y.domain([yLowerBound, y.domain()[1] - shift]);
      }

      // Update the area path.
      g.select('.area')
          .transition()
          .attr('d', area);
      g.select('.line')
          .transition()
          .attr('d', line);

      if (xDomain[1] > 2000) {
        xFactor = 1000;
        units = 'km';
      } else {
        xFactor = 1;
        units = 'm';
      }

      if (!light) {
        xAxis.tickFormat(function(d) {
          return formatter.xtick(d / xFactor, units);
        });
        if (lightXAxis) {
          xAxis.tickValues([0, x.domain()[1]]);
        }

        yAxis.tickFormat(function(d) {
          return formatter.ytick(d, 'm');
        });

        g.select('.x.axis')
          .transition()
          .call(xAxis);

        g.select('.x.label')
          .text('distance (' + units + ')')
          .style('fill', 'grey')
          .style('shape-rendering', 'crispEdges');

        g.select('.y.axis')
          .transition()
          .call(yAxis);
      }

      g.select('.grid-y')
          .transition()
          .call(yAxis.tickSize(-width, 0).tickFormat(''))
          .selectAll('.tick line')
          .style('stroke', '#ccc')
          .style('opacity', 0.7);

      g.selectAll('.axis').selectAll('path, line')
          .style('fill', 'none')
          .style('stroke', '#000')
          .style('shape-rendering', 'crispEdges');

      g.selectAll('.grid-hover line')
          .style('stroke', '#222')
          .style('opacity', 0.8);

      g.select('.overlay')
          .on('mouseout', mouseout)
          .on('mousemove', mousemove);

      function mousemove() {
        var mouseX = d3.mouse(this)[0];
        var x0 = x.invert(mouseX);
        var i = bisectDistance(data, x0, 1);

        var point = data[i];
        var elevation = extractor.z(point);
        var dist = extractor.dist(point);

        g.select('.x.grid-hover')
            .style('display', 'inline')
            .select('line')
            .attr('x1', x(dist))
            .attr('y1', height)
            .attr('x2', x(dist))
            .attr('y2', y(elevation));

        g.select('.y.grid-hover')
            .style('display', 'inline')
            .select('line')
            .attr('x1', x(0))
            .attr('y1', y(elevation))
            .attr('x2', width)
            .attr('y2', y(elevation));

        var right = x0 > xDomain[1] / 2;
        var xtranslate = x(dist);
        xtranslate += right ? -10 : 10;

        g.select('.x.grid-hover text')
            .text(formatter.xhover(dist / xFactor, units))
            .style('text-anchor', right ? 'end' : 'start')
            .attr('transform', 'translate(' + xtranslate + ',' +
                (height - 10) + ')');

        g.select('.y.grid-hover text')
            .text(formatter.yhover(elevation, 'm'))
            .style('text-anchor', right ? 'end' : 'start')
            .attr('transform', 'translate(' + xtranslate + ',' +
                (y(elevation) - 10) + ')');
        hoverCallback.call(null, point);
      }

      function mouseout() {
        g.selectAll('.grid-hover')
            .style('display', 'none');
        outCallback.call(null);
      }
    });
  };

  profile.showPois = function(pois) {
    pois = goog.isDef(pois) ? pois : [];
    goog.asserts.assert(pois.length === 0 || goog.isDef(poiExtractor));

    var pe = poiExtractor;
    var g = svg.select('g');
    var profileData = svg.datum();
    var ps = g.select('.pois');

    var p = ps.selectAll('.poi').data(pois, function(d) {
      var i = bisectDistance(profileData, Math.round(pe.dist(d) * 10) / 10, 1);
      var point = profileData[i];
      if (point) {
        var z = elevationExtractor.z(point);
        pe.z(d, z);
      }
      return pe.id(d);
    });

    var poiEnterG = p.enter()
      .append('g')
      .attr('class', 'poi');

    poiEnterG.append('text')
      .attr('x', light ? 0 : 9)
      .attr('dy', '.35em')
      .attr('text-anchor', light ? 'middle' : 'start');

    poiEnterG.append('line')
      .style('shape-rendering', 'crispEdges');

    p.style('opacity', 0)
      .transition()
      .duration(1000)
      .delay(100)
      .style('opacity', 1);

    p.selectAll('text')
      .attr('transform', function(d) {
          if (light) {
            return ['translate(',
              x(pe.dist(d)), ',',
              y(pe.z(d)) - 10, ')'
            ].join('');
          } else {
            return ['translate(',
              x(pe.dist(d)), ',',
              y(pe.z(d)) - 20, ') rotate(', poiLabelAngle, ')'
            ].join('');
          }
        })
      .text(function(d) {
          return pe.sort(d) + (light ? '' : (' - ' + pe.title(d)));
        });

    p.selectAll('line')
       .style('stroke', 'grey')
       .attr('x1', function(d) { return x(pe.dist(d));})
       .attr('y1', function(d) { return y(y.domain()[0]);})
       .attr('x2', function(d) { return x(pe.dist(d));})
       .attr('y2', function(d) { return y(pe.z(d));});

    // remove unused pois
    p.exit().remove();
  };

  function clearPois() {
    profile.showPois([]);
  }

  return profile;
};
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import { browserHistory } from 'react-router';
import { Grid, Col, ControlLabel, FormControl } from 'react-bootstrap';
import io from 'socket.io-client';
import ErrorModal from '../Errors/ErrorModal';
import OtherPlayers from './OtherPlayers';
import Table from './Table';
import Player from './Player';
import Chat from '../Chat';
import ResultsModal from './modals/ResultsModal';
import DisconnectedModal from './modals/DisconnectedModal';
import { GameState, SocketInfo, TimerValues } from '../../shared/constants';

const ModalOpenDelay = 1000;

class Game extends Component {

  constructor(props) {
    super(props);

    this.state = {
      joinUrl: '',
      resultsClosedForGame: null,
      socket: null,
      socketConnected: false,
      showConnectionError: false
    };

    this.gameEnded = this.gameEnded.bind(this);
    this.onSocketException = this.onSocketException.bind(this);
    this.hideResultsModal = this.hideResultsModal.bind(this);
    this.handleJoinUrlFocus = this.handleJoinUrlFocus.bind(this);
  }

  componentWillMount() {
    if (this.props.gameId) {
      // Configure websocket
      const socket = io('', { path: SocketInfo.gameSocketUrl });

      // Connection events
      socket.on('connect', () => {
        this.setState({
          socketConnected: true,
          showConnectionError: false
        });
        socket.emit('joinGame', this.props.gameId, this.props.playerId);
      });
      socket.on('disconnect', () => {
        this.setState({
          socketConnected: false,
          showConnectionError: true
        });
      });

      // Game events
      socket.on('joinedPlayersChanged', this.props.onJoinedPlayersChanged);
      socket.on('gameStarted', this.props.onGameStarted);
      socket.on('gameUpdated', this.props.onGameUpdated);
      socket.on('gameEnded', this.gameEnded);
      socket.on('cardsExchanged', this.props.onCardsExchanged);
      socket.on('newRoundStarted', this.props.onNewRoundStarted);
      socket.on('exception', this.onSocketException);

      this.setState({
        socket: socket,
        joinUrl: `${window.location.href.substring(0, window.location.href.lastIndexOf('/') + 1)}join/` +
          `${this.props.gameId}`
      });
    }
    else {
      browserHistory.push('/home');
    }
  }

  componentWillUnmount() {
    if (this.state.socketConnected) {
      this.removeSocketListeners();

      if (this.props.gameId) {
        this.props.onQuitGame();
      }
    }
  }

  // 'exception' socket event is a signal that server has removed the player from the game
  onSocketException() {
    this.setState({
      socketConnected: false
    });
    this.removeSocketListeners();
    browserHistory.push('/home');
  }

  removeSocketListeners() {
    // Only removing of 'disconnect' event is required
    this.state.socket.removeAllListeners('disconnect');
  }

  gameEnded(data) {
    this.props.onGameEnd(data);

    setTimeout(() => {
      this.props.toggleResultsModal(true);

      // Auto-close modal when inactive
      setTimeout((gameNumber) => {
        if (this.state.resultsClosedForGame == null || this.state.resultsClosedForGame < gameNumber) {
          this.hideResultsModal();
        }
      }, TimerValues.cardExchangeInactivityMaxPeriod - TimerValues.inactivityWarningTime - ModalOpenDelay,
        this.props.results.gameNumber);
    }, ModalOpenDelay);
  }

  hideResultsModal() {
    this.props.toggleResultsModal(false);

    this.setState({
      resultsClosedForGame: this.props.results.gameNumber
    });

    if (this.props.results.gameNumber < this.props.results.totalGameCount) {
      this.props.requestCardExchange();
    }
    else {
      browserHistory.push('/home');
    }
  }

  handleJoinUrlFocus(e) {
    e.target.select();
  }

  render() {
    const { gameId, playerCount, gameState, otherPlayers, table, isRevolution, player, showResultsModal, results,
      helpText } = this.props;

    return (
      <Grid className="Game" fluid>
        <ErrorModal />
        <Chat socket={this.state.socket} gameId={gameId} />
        {results &&
          <ResultsModal results={results} show={showResultsModal} onHide={this.hideResultsModal} />
        }
        <DisconnectedModal show={this.state.showConnectionError} />
        <OtherPlayers playerCount={playerCount} players={otherPlayers} />

          {gameState === GameState.NOT_STARTED &&

              <Col componentClass={ControlLabel} sm={6} md={3} mdOffset={3}>
                Share this link to your friends, so they can join the game!
              </Col>
              <Col sm={6} md={3}>
                <FormControl type="text" value={this.state.joinUrl} readOnly onFocus={this.handleJoinUrlFocus} />
              </Col>

          }
          {gameState !== GameState.NOT_STARTED &&

                {!isRevolution && }
                {isRevolution && }

          }

        {helpText &&
{helpText}
}
        {player.player &&
          <Player {...player} onHit={this.props.onCardsHit} onCardsChange={this.props.onCardSelectionChange} />
        }
      </Grid>
    );
  }
}

Game.propTypes = {
  playerCount: PropTypes.number,
  otherPlayers: PropTypes.array,
  table: PropTypes.array,
  isRevolution: PropTypes.bool,
  player: PropTypes.object,
  results: PropTypes.object,
  helpText: PropTypes.string
};

export default Game;
<commit_msg>Clear timers when quitting from the game<commit_after>import React, { Component, PropTypes } from 'react';
import { browserHistory } from 'react-router';
import { Grid, Col, ControlLabel, FormControl } from 'react-bootstrap';
import io from 'socket.io-client';
import ErrorModal from '../Errors/ErrorModal';
import OtherPlayers from './OtherPlayers';
import Table from './Table';
import Player from './Player';
import Chat from '../Chat';
import ResultsModal from './modals/ResultsModal';
import DisconnectedModal from './modals/DisconnectedModal';
import { GameState, SocketInfo, TimerValues } from '../../shared/constants';

const ModalOpenDelay = 1000;

class Game extends Component {

  constructor(props) {
    super(props);

    this.state = {
      joinUrl: '',
      resultsClosedForGame: null,
      socket: null,
      socketConnected: false,
      showConnectionError: false
    };

    this.timers = {
      resultsModalOpen: null,
      resultsModalClose: null
    };

    this.gameEnded = this.gameEnded.bind(this);
    this.onSocketException = this.onSocketException.bind(this);
    this.hideResultsModal = this.hideResultsModal.bind(this);
    this.handleJoinUrlFocus = this.handleJoinUrlFocus.bind(this);
  }

  componentWillMount() {
    if (this.props.gameId) {
      // Configure websocket
      const socket = io('', { path: SocketInfo.gameSocketUrl });

      // Connection events
      socket.on('connect', () => {
        this.setState({
          socketConnected: true,
          showConnectionError: false
        });
        socket.emit('joinGame', this.props.gameId, this.props.playerId);
      });
      socket.on('disconnect', () => {
        this.setState({
          socketConnected: false,
          showConnectionError: true
        });
      });

      // Game events
      socket.on('joinedPlayersChanged', this.props.onJoinedPlayersChanged);
      socket.on('gameStarted', this.props.onGameStarted);
      socket.on('gameUpdated', this.props.onGameUpdated);
      socket.on('gameEnded', this.gameEnded);
      socket.on('cardsExchanged', this.props.onCardsExchanged);
      socket.on('newRoundStarted', this.props.onNewRoundStarted);
      socket.on('exception', this.onSocketException);

      this.setState({
        socket: socket,
        joinUrl: `${window.location.href.substring(0, window.location.href.lastIndexOf('/') + 1)}join/` +
          `${this.props.gameId}`
      });
    }
    else {
      browserHistory.push('/home');
    }
  }

  componentWillUnmount() {
    if (this.state.socketConnected) {
      this.removeSocketListeners();

      if (this.props.gameId) {
        this.props.onQuitGame();
      }
    }

    // Cancel timers
    for (let key in this.timers) { // eslint-disable-line no-restricted-syntax
      if (this.timers.hasOwnProperty(key)) {
        let timer = this.timers[key];
        if (timer) {
          clearTimeout(timer);
        }
      }
    }
  }

  // 'exception' socket event is a signal that server has removed the player from the game
  onSocketException() {
    this.setState({
      socketConnected: false
    });
    this.removeSocketListeners();
    browserHistory.push('/home');
  }

  removeSocketListeners() {
    // Only removing of 'disconnect' event is required
    this.state.socket.removeAllListeners('disconnect');
  }

  gameEnded(data) {
    this.props.onGameEnd(data);

    this.timers.resultsModalOpen = setTimeout(() => {
      this.props.toggleResultsModal(true);

      // Auto-close modal on inactivity warning
      this.timers.resultsModalClose = setTimeout((gameNumber) => {
        if (this.state.resultsClosedForGame == null || this.state.resultsClosedForGame < gameNumber) {
          this.hideResultsModal();
        }
      }, TimerValues.cardExchangeInactivityMaxPeriod - TimerValues.inactivityWarningTime - ModalOpenDelay,
        this.props.results.gameNumber);
    }, ModalOpenDelay);
  }

  hideResultsModal() {
    this.props.toggleResultsModal(false);

    this.setState({
      resultsClosedForGame: this.props.results.gameNumber
    });

    if (this.props.results.gameNumber < this.props.results.totalGameCount) {
      this.props.requestCardExchange();
    }
    else {
      browserHistory.push('/home');
    }
  }

  handleJoinUrlFocus(e) {
    e.target.select();
  }

  render() {
    const { gameId, playerCount, gameState, otherPlayers, table, isRevolution, player, showResultsModal, results,
      helpText } = this.props;

    return (
      <Grid className="Game" fluid>
        <ErrorModal />
        <Chat socket={this.state.socket} gameId={gameId} />
        {results &&
          <ResultsModal results={results} show={showResultsModal} onHide={this.hideResultsModal} />
        }
        <DisconnectedModal show={this.state.showConnectionError} />
        <OtherPlayers playerCount={playerCount} players={otherPlayers} />

          {gameState === GameState.NOT_STARTED &&

              <Col componentClass={ControlLabel} sm={6} md={3} mdOffset={3}>
                Share this link to your friends, so they can join the game!
              </Col>
              <Col sm={6} md={3}>
                <FormControl type="text" value={this.state.joinUrl} readOnly onFocus={this.handleJoinUrlFocus} />
              </Col>

          }
          {gameState !== GameState.NOT_STARTED &&

                {!isRevolution && }
                {isRevolution && }

          }

        {helpText &&
{helpText}
}
        {player.player &&
          <Player {...player} onHit={this.props.onCardsHit} onCardsChange={this.props.onCardSelectionChange} />
        }
      </Grid>
    );
  }
}

Game.propTypes = {
  playerCount: PropTypes.number,
  otherPlayers: PropTypes.array,
  table: PropTypes.array,
  isRevolution: PropTypes.bool,
  player: PropTypes.object,
  results: PropTypes.object,
  helpText: PropTypes.string
};

export default Game;
<|endoftext|>


<commit_before>/*
 * This file is part of the RedKiteCmsBunde Application and it is distributed
 * under the GPL LICENSE Version 2.0. To use this application you must leave
 * intact this copyright notice.
 *
 * Copyright (c) RedKite Labs <webmaster@redkite-labs.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * For extra documentation and help please visit http://www.redkite-labs.com
 *
 * @license    GPL LICENSE Version 2.0
 *
 */

;var isEditorOpened = false;

(function($){
    $.fn.ToggleBodyContents =function()
    {
        this.each(function()
        {
            $(this).click(function()
            {
                $('#slot_' + $(this).attr('ref')).animate({
                  height: 'toggle'
                }, 200);

                return false;
            });
        });

        return this;
    };

    $.fn.AddBlock =function(type, options, successCallback)
    {
        try {
            this.each(function()
            {
                var contentType = (type == null) ? $(this).attr('data-type') : type;
                var included = $(this).attr('data-included') == "1" ? true : false;
                $.ajax({
                    type: 'POST',
                    url: frontController + 'backend/' + $('#al_available_languages option:selected').val() + '/addBlock',
                    data: {'page' :  $('#al_pages_navigator').html(),
                           'language' : $('#al_languages_navigator').html(),
                           'pageId' :  $('#al_pages_navigator').attr('rel'),
                           'languageId' : $('#al_languages_navigator').attr('rel'),
                           'idBlock' : $(this).attr('data-block-id'),
                           'slotName' : $(this).attr('data-slot-name'),
                           'contentType': contentType,
                           'included': included,
                           'options': options},
                    beforeSend: function()
                    {
                        $('body').AddAjaxLoader();
                    },
                    success: function(response)
                    {
                        updateContentsJSon(response);
                        if (successCallback != null) {
                            successCallback();
                        }

                        $(document).trigger("blockAdded", []);
                    },
                    error: function(err)
                    {
                        $('body').showAlert(err.responseText, 0, 'alert-error alert-danger');
                    },
                    complete: function()
                    {
                        $('body').RemoveAjaxLoader();
                    }
                });

                return false;
            });
        }
        catch(e){
            $('body').showAlert('An unespected error occoured in al-blocks file, method AddBlock. Here is the error from the server:

' + e + '

Please open an issue at Github reporting this entire message.', 0, 'alert-error alert-danger');
        }
    };

    $.fn.EditBlock =function(key, value, options, successCallback)
    {
        try {
            var activeBlock = $('body').data('activeBlock');
            var item = (activeBlock != null) ? activeBlock.attr('data-item') : null;
            this.each(function()
            {
                value = (value == null) ? encodeURIComponent($(this).val()) : value;
                $.ajax({
                    type: 'POST',
                    url: frontController + 'backend/' + $('#al_available_languages option:selected').val() + '/editBlock',
                    data: {'page' :  $('#al_pages_navigator').html(),
                           'language' : $('#al_languages_navigator').html(),
                           'pageId' :  $('#al_pages_navigator').attr('rel'),
                           'languageId' : $('#al_languages_navigator').attr('rel'),
                           'idBlock'    : $('body').data('idBlock'),
                           'slotName'   : $('body').data("slotName"),
                           'key'        : key,
                           'value'      : value,
                           'included'   : $('body').data('included'),
                           'item'       : item,
                           'options'    : options
                    },
                    beforeSend: function()
                    {
                        $('body').AddAjaxLoader();
                    },
                    success: function(response)
                    {
                        updateContentsJSon(response);
                        Holder.run();

                        activeBlock = $('body').data('activeBlock');
                        if (successCallback != null) {
                            successCallback(activeBlock);
                        }

                        if (activeBlock != null) {
                            $(document).trigger("blockEdited", [ activeBlock ]);
                        }
                    },
                    error: function(err)
                    {
                        $('body').showAlert(err.responseText, 0, 'alert-error alert-danger');
                    },
                    complete: function()
                    {
                        $(document).blocksEditor('stopCursorOverEditor');
                        $('body').RemoveAjaxLoader();
                    }
                });

                return false;
            });
        }
        catch(e){
            $('body').showAlert('An unespected error occoured in al-blocks file, method EditBlock. Here is the error from the server:

' + e + '

Please open an issue at Github reporting this entire message.', 0, 'alert-error alert-danger');
        }
    };

    $.fn.Delete =function()
    {
        this.each(function()
        {
            $(this).click(function()
            {
                $(this).DeleteContent();

                return false;
            });
        });
    };

    $.fn.DeleteBlock =function()
    {
        if (confirm(translate('Are you sure to remove the active block'))) {
            try {
                var included = $(this).attr('data-included') == "1" ? true : false;
                $.ajax({
                    type: 'POST',
                    url: frontController + 'backend/' + $('#al_available_languages option:selected').val() + '/deleteBlock',
                    data: {'page' :  $('#al_pages_navigator').html(),
                           'language' : $('#al_languages_navigator').html(),
                           'pageId' :  $('#al_pages_navigator').attr('rel'),
                           'languageId' : $('#al_languages_navigator').attr('rel'),
                           'idBlock' : $(this).attr('data-block-id'),
                           'slotName' : $(this).attr('data-slot-name'),
                           'included': included
                    },
                    beforeSend: function()
                    {
                        $('body').AddAjaxLoader();
                    },
                    success: function(response)
                    {
                        updateContentsJSon(response);

                        $(document).trigger("blockDeleted", []);
                    },
                    error: function(err)
                    {
                        $('body').showAlert(err.responseText, 0, 'alert-error alert-danger');
                    },
                    complete: function()
                    {
                        $('body').RemoveAjaxLoader();
                    }
                });
            }
            catch(e){
                $('body').showAlert('An unespected error occoured in al-blocks file, method DeleteBlock. Here is the error from the server:

' + e + '

Please open an issue at Github reporting this entire message.', 0, 'alert-error alert-danger');
            }
        }
    };
})($);

function showMediaLibrary(html)
{
    if($('body').find("al_media_lib").length == 0)
    {
        $('

')
                .css("display", "none")
                .appendTo('body');
    }
    $('#al_media_lib').html(html);
}

function updateContentsJSon(response, editorWidth)
{
    var slot;
    $(response).each(function(key, item)
    {
        switch(item.key)
        {
            case "message":
                $('body').showAlert(item.value);

                break;
            case "redraw-slot":
                slot = $('.al_' + item.slotName);
                if (slot.length > 0) {
                    slot
                        .html(item.value)
                        .find('[data-editor="enabled"]')
                        .blocksEditor('start')
                    ;
                } else {
                    var element = $('[data-name="' + item.blockId + '"]');
                    var parent = element.parent();
                    element.replaceWith(item.value);
                    $(parent)
                        .find('[data-editor="enabled"]')
                        .blocksEditor('start')
                    ;
                }

                break;
            case "add-block":
                if(item.insertAfter == 'block_0')
                {
                    var slot = $('.al_' + item.slotName);
                    if (slot.length > 0) {
                        slot
                            .empty()
                            .append(item.value)
                        ;
                    } else {
                        $('[data-slot-name="' + item.slotName + '"]')
                            .replaceWith(item.value);
                    }
                }
                else
                {
                    $(item.value).insertAfter('[data-name="' + item.insertAfter + '"]');
                }

                $('[data-name="' + item.blockId + '"]').blocksEditor('start');

                break;
            case "edit-block":
                var blockName = '[data-name="' + item.blockName + '"]';
                var block = $(blockName);
                block
                    .blocksEditor('stopEditElement')
                    .replaceWith(item.value);

                block
                    .blocksEditor('startEditElement')
                    .blocksEditor('hideElementContent')
                ;

                $('body').data('activeBlock', block);

                break;
            case "remove-block":
                $('[data-name="' + item.blockName + '"]')
                    .unbind()
                    .remove()
                ;

                break;
            case "images-list":
                $('.al_images_list').html(item.value);

                break;
            case "externalAssets":
                $('.al_' + item.section  + '_list').html(item.value);
                $('[data-name="' + item.blockName + '"]').replaceWith(item.blockContent);

                break;
            case "editorContents":
                $('.editor_contents').html(item.value);

                break;
        }
    });
}
<commit_msg>fixed a bug recentry introduced. The block must be retrieved again instead of referring the previous retrieved instance<commit_after>/*
 * This file is part of the RedKiteCmsBunde Application and it is distributed
 * under the GPL LICENSE Version 2.0. To use this application you must leave
 * intact this copyright notice.
 *
 * Copyright (c) RedKite Labs <webmaster@redkite-labs.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * For extra documentation and help please visit http://www.redkite-labs.com
 *
 * @license    GPL LICENSE Version 2.0
 *
 */

;var isEditorOpened = false;

(function($){
    $.fn.ToggleBodyContents =function()
    {
        this.each(function()
        {
            $(this).click(function()
            {
                $('#slot_' + $(this).attr('ref')).animate({
                  height: 'toggle'
                }, 200);

                return false;
            });
        });

        return this;
    };

    $.fn.AddBlock =function(type, options, successCallback)
    {
        try {
            this.each(function()
            {
                var contentType = (type == null) ? $(this).attr('data-type') : type;
                var included = $(this).attr('data-included') == "1" ? true : false;
                $.ajax({
                    type: 'POST',
                    url: frontController + 'backend/' + $('#al_available_languages option:selected').val() + '/addBlock',
                    data: {'page' :  $('#al_pages_navigator').html(),
                           'language' : $('#al_languages_navigator').html(),
                           'pageId' :  $('#al_pages_navigator').attr('rel'),
                           'languageId' : $('#al_languages_navigator').attr('rel'),
                           'idBlock' : $(this).attr('data-block-id'),
                           'slotName' : $(this).attr('data-slot-name'),
                           'contentType': contentType,
                           'included': included,
                           'options': options},
                    beforeSend: function()
                    {
                        $('body').AddAjaxLoader();
                    },
                    success: function(response)
                    {
                        updateContentsJSon(response);
                        if (successCallback != null) {
                            successCallback();
                        }

                        $(document).trigger("blockAdded", []);
                    },
                    error: function(err)
                    {
                        $('body').showAlert(err.responseText, 0, 'alert-error alert-danger');
                    },
                    complete: function()
                    {
                        $('body').RemoveAjaxLoader();
                    }
                });

                return false;
            });
        }
        catch(e){
            $('body').showAlert('An unespected error occoured in al-blocks file, method AddBlock. Here is the error from the server:

' + e + '

Please open an issue at Github reporting this entire message.', 0, 'alert-error alert-danger');
        }
    };

    $.fn.EditBlock =function(key, value, options, successCallback)
    {
        try {
            var activeBlock = $('body').data('activeBlock');
            var item = (activeBlock != null) ? activeBlock.attr('data-item') : null;
            this.each(function()
            {
                value = (value == null) ? encodeURIComponent($(this).val()) : value;
                $.ajax({
                    type: 'POST',
                    url: frontController + 'backend/' + $('#al_available_languages option:selected').val() + '/editBlock',
                    data: {'page' :  $('#al_pages_navigator').html(),
                           'language' : $('#al_languages_navigator').html(),
                           'pageId' :  $('#al_pages_navigator').attr('rel'),
                           'languageId' : $('#al_languages_navigator').attr('rel'),
                           'idBlock'    : $('body').data('idBlock'),
                           'slotName'   : $('body').data("slotName"),
                           'key'        : key,
                           'value'      : value,
                           'included'   : $('body').data('included'),
                           'item'       : item,
                           'options'    : options
                    },
                    beforeSend: function()
                    {
                        $('body').AddAjaxLoader();
                    },
                    success: function(response)
                    {
                        updateContentsJSon(response);
                        Holder.run();

                        activeBlock = $('body').data('activeBlock');
                        if (successCallback != null) {
                            successCallback(activeBlock);
                        }

                        if (activeBlock != null) {
                            $(document).trigger("blockEdited", [ activeBlock ]);
                        }
                    },
                    error: function(err)
                    {
                        $('body').showAlert(err.responseText, 0, 'alert-error alert-danger');
                    },
                    complete: function()
                    {
                        $(document).blocksEditor('stopCursorOverEditor');
                        $('body').RemoveAjaxLoader();
                    }
                });

                return false;
            });
        }
        catch(e){
            $('body').showAlert('An unespected error occoured in al-blocks file, method EditBlock. Here is the error from the server:

' + e + '

Please open an issue at Github reporting this entire message.', 0, 'alert-error alert-danger');
        }
    };

    $.fn.Delete =function()
    {
        this.each(function()
        {
            $(this).click(function()
            {
                $(this).DeleteContent();

                return false;
            });
        });
    };

    $.fn.DeleteBlock =function()
    {
        if (confirm(translate('Are you sure to remove the active block'))) {
            try {
                var included = $(this).attr('data-included') == "1" ? true : false;
                $.ajax({
                    type: 'POST',
                    url: frontController + 'backend/' + $('#al_available_languages option:selected').val() + '/deleteBlock',
                    data: {'page' :  $('#al_pages_navigator').html(),
                           'language' : $('#al_languages_navigator').html(),
                           'pageId' :  $('#al_pages_navigator').attr('rel'),
                           'languageId' : $('#al_languages_navigator').attr('rel'),
                           'idBlock' : $(this).attr('data-block-id'),
                           'slotName' : $(this).attr('data-slot-name'),
                           'included': included
                    },
                    beforeSend: function()
                    {
                        $('body').AddAjaxLoader();
                    },
                    success: function(response)
                    {
                        updateContentsJSon(response);

                        $(document).trigger("blockDeleted", []);
                    },
                    error: function(err)
                    {
                        $('body').showAlert(err.responseText, 0, 'alert-error alert-danger');
                    },
                    complete: function()
                    {
                        $('body').RemoveAjaxLoader();
                    }
                });
            }
            catch(e){
                $('body').showAlert('An unespected error occoured in al-blocks file, method DeleteBlock. Here is the error from the server:

' + e + '

Please open an issue at Github reporting this entire message.', 0, 'alert-error alert-danger');
            }
        }
    };
})($);

function showMediaLibrary(html)
{
    if($('body').find("al_media_lib").length == 0)
    {
        $('

')
                .css("display", "none")
                .appendTo('body');
    }
    $('#al_media_lib').html(html);
}

function updateContentsJSon(response, editorWidth)
{
    var slot;
    $(response).each(function(key, item)
    {
        switch(item.key)
        {
            case "message":
                $('body').showAlert(item.value);

                break;
            case "redraw-slot":
                slot = $('.al_' + item.slotName);
                if (slot.length > 0) {
                    slot
                        .html(item.value)
                        .find('[data-editor="enabled"]')
                        .blocksEditor('start')
                    ;
                } else {
                    var element = $('[data-name="' + item.blockId + '"]');
                    var parent = element.parent();
                    element.replaceWith(item.value);
                    $(parent)
                        .find('[data-editor="enabled"]')
                        .blocksEditor('start')
                    ;
                }

                break;
            case "add-block":
                if(item.insertAfter == 'block_0')
                {
                    var slot = $('.al_' + item.slotName);
                    if (slot.length > 0) {
                        slot
                            .empty()
                            .append(item.value)
                        ;
                    } else {
                        $('[data-slot-name="' + item.slotName + '"]')
                            .replaceWith(item.value);
                    }
                }
                else
                {
                    $(item.value).insertAfter('[data-name="' + item.insertAfter + '"]');
                }

                $('[data-name="' + item.blockId + '"]').blocksEditor('start');

                break;
            case "edit-block":
                var blockName = '[data-name="' + item.blockName + '"]';
                $(blockName)
                    .blocksEditor('stopEditElement')
                    .replaceWith(item.value);

                // Here we need to retrieve the block again because it has just been replaced
                $(blockName)
                    .blocksEditor('startEditElement')
                    .blocksEditor('hideElementContent')
                ;

                $('body').data('activeBlock', block);

                break;
            case "remove-block":
                $('[data-name="' + item.blockName + '"]')
                    .unbind()
                    .remove()
                ;

                break;
            case "images-list":
                $('.al_images_list').html(item.value);

                break;
            case "externalAssets":
                $('.al_' + item.section  + '_list').html(item.value);
                $('[data-name="' + item.blockName + '"]').replaceWith(item.blockContent);

                break;
            case "editorContents":
                $('.editor_contents').html(item.value);

                break;
        }
    });
}
<|endoftext|>