<commit_before>// ------------------------------------ UI tools -----------------------------------------
var Ui = {
  // return true if the dialog of grid with "name" is open, unless return false
  isOpen: function() {
    return ($(".ui-dialog:visible").size() > 0);
  },

  // check if the grid is being edited
  isEditing: function() {
    var editing = false;
    $.each(gridManager.grids, function(){
      if(this.getCellEditor() != null) editing = true;
    });
    return editing;
  },

  // Resize grid
  resizeGrid: function(grid) {
    grid.resizeCanvas();
    grid.autosizeColumns();
    grid.filterPanel.generateFilters();
    $(window).resize(function() {
      grid.resizeCanvas();
      grid.autosizeColumns();
      grid.filterPanel.generateFilters();
    });
  },

  // Check if filter panel is open (Not in use since Material Design implementation)
  filterPanelOpen: function() {
    return ($('.slick-headerrow-columns:visible').size() > 0 && $( document.activeElement ).parent().attr('class') === 'slick-headerrow-columns');
  },

  // Check if the grid is being filtered
  isFiltering: function() {
    return $(document.activeElement).parent().hasClass('slick-header-column');
  },

  // Check if can add or delete records
  addOrDeleteLocked: function() {
    return this.isEditing() || this.isOpen() || this.isFiltering();
  },

  // Select grid names
  selectGridNames: function() {
    var gridContainers = $(".grid_container"), gridName;
    return $.map( gridContainers, function(container){
      gridName = $.trim($(container).attr("id").split("grid_")[1]);
      if (gridName) {
        return gridName;
      }
    });
  },

  // Refresh create form when continue create new record
  refreshCreateForm: function(grid) {
    var name = grid.name;
    $.get(grid.path + '/wulin_master_new_form' + grid.query, function(data){
      newFormDom = $(data);
      $('#' + name + '_form:visible form').replaceWith(newFormDom.find('form'));
      setTimeout(function(){ Ui.setupForm(grid, false); }, 350);
      Ui.setupComponents(grid);
    });
  },

  // Reset form
  resetForm: function(name) {
    $(':input','#new_' + name).not(':button, :submit, :reset, :hidden').not('[readonly]').val('').removeAttr('checked').removeAttr('selected');
    // For chosen
    $('ul.chzn-choices li.search-choice').remove();
  },

  // Create and open dialog
  openDialog: function(grid, action, options, callback) {
    $.get(grid.path + '/' + action + grid.query, function(data){
      Ui.createModelModal(grid, data, {
        ready: function(modal, trigger) {
          Ui.setupForm(grid, false);
        }
      });
    });
  },

  setupComponents: function(grid) {
    var name = grid.name;
    // setup select as chosen
    $('#' + name + '_form select[data-required="true"]').chosen();
    $('#' + name + '_form select[data-required="false"]').chosen({allow_single_deselect: true});

    $('#' + name + '_form select').off('change').on('change', function(){
      var flag = $('#' + name + '_form input.target_flag:checkbox[data-target="' + $(this).attr('data-target') + '"]');
      if (flag.size() > 0) flag.attr('checked', 'checked');
    });

    // setup datepicker
    $('#' + name + '_form input[data-date]').datepicker({ dateFormat: 'yy-mm-dd' });
    $('#' + name + '_form input[data-datetime]').datetimepicker({
      onlyTime: false,
      dateFormat: "yy-mm-dd",
      timeFormat: 'HH:mm',
      timeOnly: false,
      stepMinute: 1,
      minuteGrid: 0,
      beforeShow: function() { calendarOpen = true; },
      onClose: function() { calendarOpen = false; }
    });
    $('#' + name + '_form input[data-time]').timepicker({});
  },

  setupForm: function(grid, monitor) {
    var remotePath = [];
    var choicesColumn = [];
    var distinctColumn = [];
    var path;
    var name = grid.name;
    var scope = $('#' + name + '_form');
    var formType = scope.data('action');
    var columns = window[name + "_columns"] || grid.getColumns();
    var currentData = {};

    if (grid.loader)
      currentData = grid.loader.data[grid.getSelectedRows()[0]];

    // special handling for 'choices' and 'choices_column' options
    $.each(columns, function(i, n) {
      if (n['choices'] && typeof(n['choices']) == 'string') {
        if (n['distinct'] && formType != 'create') {
          distinctColumn.push([n.field, n['choices']]);
        } else {
          var formable = n.formable === false ? false : true;

          var editorChoices = n.choices;
          // Use editor's source instead of grid's source
          if (n.editor.source) {
            var match = /^.*(source=.*)$/igm.exec(n.choices);
            var grid_source = match[1];
            editorChoices = n.choices.replace(grid_source, 'source=' + n.editor.source);
          }

          remotePath.push([n.field, editorChoices, formable]);
        }
      } else if (currentData && n['choices_column']) {
        choicesColumn.push([n.field, currentData[n['choices_column']]]);
      }
    });

    // Fetch select options from remote
    if (remotePath.length > 0) {
      $.each(remotePath, function(i, n) {
        var field = n[0];
        var path = n[1];
        var formable = n[2];
        if (!path || !formable) return;

        var first_input;
        var target = $("select[data-field='" + field + "']", scope);
        var source = target.attr('data-source');
        if (target.size() == 1) {
          $('option[value!=""]', target).remove();

          $.getJSON(path, function(itemdata){
            $.each(itemdata, function(index, value) {
              if ($.isPlainObject(value)) {
                target.append(
                  "<option value='" + value.id + "'>" +
                  value[source] +
                  "</option>"
                );
              } else {
                target.append("<option value='" + value + "'>" + value + "</option>");
              }
            });
            Ui.setupChosen(target, monitor);
          });

        }
      });
    }

    // Fetch distinct select options from remote
    if (distinctColumn.length > 0) {
      $.each(distinctColumn, function(i, n) {
        var field = n[0];
        var path = n[1];
        if (!path) return;

        var first_input;
        var target = $("select[data-field='" + field + "']", scope);
        var source = target.attr('data-source');
        if (target.size() == 1) {
          $('option[value!=""]', target).remove();

          $.getJSON(path, function(itemdata){
            $.each(itemdata, function(index, value) {
              if ($.isPlainObject(value)) {
                target.append("<option value='" + value.id + "'>" + value[source] + "</option>");
              } else {
                target.append("<option value='" + value + "'>" + value + "</option>");
              }
            });
            target.append("<option>Add new Option</option>");
          });

        }
      });
    }

    // Fetch select options from current data
    if (choicesColumn.length > 0) {
        $.each(choicesColumn, function(i, n) {
        var field = n[0];
        var first_input;
        var target = $("select[data-field='" + field + "']", scope);
        if (target.size() == 1) {
          $('option[value!=""]', target).remove();
            $.each(n[1], function(index, value) {
              target.append("<option value='" + value + "'>" + value + "</option>");
            });
            Ui.setupChosen(target, monitor);
        }
      });
    }

    first_input = $( '#' + name + '_form input:text', scope).first();
    if (first_input.attr('data-date')) {
      first_input.focus();
    }

    // Layout
    $('.ui-dialog-titlebar').hide();
    $('.ui-resizable-handle').hide();
    // $('.chzn-container').width('100%');
    // $('.chzn-drop').width('100%');
    // $('.chzn-search input').width('96%');
  },

  setupChosen: function(dom, monitor) {
    setTimeout(function(){
      var afterSetupChosen = dom.data('afterSetupChosen');
      if (dom.hasClass("chzn-done")) {
        dom.trigger("liszt:updated");
      } else {
        dom.chosen();
      }

      if( afterSetupChosen ) {
        afterSetupChosen();
      }
    }, 100);
  },

  // Close Modal
  closeModal: function(name) {
    var $form = $( '#' + name + '_form' );
    window._focused = {};
    $form.closest('.modal').modal('close');
    $form.closest('.modal').remove();
  },

  // Flash the notification
  flashNotice: function(ids, action) {
    var recordSize = $.isArray(ids) ? ids.length : ids.split(',').length,
    recordUnit = recordSize > 1 ? 'records' : 'record',
    actionDesc = action === 'delete' ? 'has been deleted!' : 'has been created!';

    if (recordSize > 0) {
      $('.notice_flash').remove();
      $('#indicators').before('
' + recordSize + ' ' + recordUnit + ' ' + actionDesc + '
');
      $('.notice_flash').fadeOut(7000);
    }
  },

  // Find the selected grid
  findCurrentGrid: function() {
    var currentGrid = null;
    currentGridContainer = $( document.activeElement ).parents('.grid_container');
    if (currentGridContainer.size() === 0) {
      return null;
    }
    gridName = currentGridContainer.attr('id').split('grid_')[1];

    if (gridManager.grids.length == 1) {
      currentGrid = gridManager.grids[0];
    } else {
      if (currentGridContainer.size() == 1) {
        currentGrid = gridManager.getGrid(gridName);
      } else {
        $.each(gridManager.grids, function(){
          if(this.getSelectedRows().length > 0) currentGrid = this;
        });
      }
    }
    return currentGrid;
  },

  getModalSize: function(grid, data) {
    var width, height;
    $('body').append(data);
    var modalHeight = $('.create_form .title').outerHeight() +             // Title
                      $('.create_form form').outerHeight() +               // Fields
                      $('.create_form .submit').outerHeight() +            // Button
                      120;                                                 // Padding
    if (grid.options) {
      width = grid.options.form_dialog_width || 600;
      height = grid.options.form_dialog_height || modalHeight;
    } else {
      width = 600;
      height = modalHeight;
    }
    $('.create_form').remove();
    return { width: width, height: height };
  },

  baseModal: function(options) {
    var $modal = $('
')
      .addClass('modal')
      .appendTo($('body'));
    var $modalContent = $('
')
      .addClass('modal-content')
      .appendTo($modal);

    $.extend(options, {
      complete: function() {
        $modal.remove();
      }
    });
    $modal.modal(options);
    $modal.modal('open');

    return $modal;
  },

  headerModal: function(title, options) {
    options = options || {};
    var $headerModal = this.baseModal(options)
      .addClass('modal-fixed-footer')
      .css({overflow: 'hidden'});
    var $modalHeader = $('
')
      .addClass('modal-header')
      .append($('').text(title))
      .append($('').text('close').addClass('modal-close material-icons right'))
      .prependTo($headerModal);

    return $headerModal;
  },

  createModelModal: function(grid, data, options) {
    $.extend(options, {
      startingTop: '5%',
      endingTop: '5%',
    });

    var modalSize = this.getModalSize(grid, data);
    var $modelModal = this.baseModal(options)
      .width(modalSize.width)
      .height(modalSize.height)
      .css({'max-height': '90%'});

    $modelModal.find('.modal-content').append(data);
  },

  createJsonViewModal: function(jsonData) {
    var $jsonViewModal = this.headerModal('JSON View');
    $jsonViewModal.find('.modal-content')
      .css('margin-top', '24px')
      .JSONView(jsonData)
      .JSONView('collapse');
  },

  formatData: function(grid, arrayData) {
    var data = {}, columns;
    columns = grid.loader.getColumns();
    $.each(columns, function(index, column){
      data[column['id']] = arrayData[index];
    });
    return data;
  }

};
<commit_msg>FEATURE - Speed up JSON rendering by using 'collapsed: true' option<commit_after>// ------------------------------------ UI tools -----------------------------------------
var Ui = {
  // return true if the dialog of grid with "name" is open, unless return false
  isOpen: function() {
    return ($(".ui-dialog:visible").size() > 0);
  },

  // check if the grid is being edited
  isEditing: function() {
    var editing = false;
    $.each(gridManager.grids, function(){
      if(this.getCellEditor() != null) editing = true;
    });
    return editing;
  },

  // Resize grid
  resizeGrid: function(grid) {
    grid.resizeCanvas();
    grid.autosizeColumns();
    grid.filterPanel.generateFilters();
    $(window).resize(function() {
      grid.resizeCanvas();
      grid.autosizeColumns();
      grid.filterPanel.generateFilters();
    });
  },

  // Check if filter panel is open (Not in use since Material Design implementation)
  filterPanelOpen: function() {
    return ($('.slick-headerrow-columns:visible').size() > 0 && $( document.activeElement ).parent().attr('class') === 'slick-headerrow-columns');
  },

  // Check if the grid is being filtered
  isFiltering: function() {
    return $(document.activeElement).parent().hasClass('slick-header-column');
  },

  // Check if can add or delete records
  addOrDeleteLocked: function() {
    return this.isEditing() || this.isOpen() || this.isFiltering();
  },

  // Select grid names
  selectGridNames: function() {
    var gridContainers = $(".grid_container"), gridName;
    return $.map( gridContainers, function(container){
      gridName = $.trim($(container).attr("id").split("grid_")[1]);
      if (gridName) {
        return gridName;
      }
    });
  },

  // Refresh create form when continue create new record
  refreshCreateForm: function(grid) {
    var name = grid.name;
    $.get(grid.path + '/wulin_master_new_form' + grid.query, function(data){
      newFormDom = $(data);
      $('#' + name + '_form:visible form').replaceWith(newFormDom.find('form'));
      setTimeout(function(){ Ui.setupForm(grid, false); }, 350);
      Ui.setupComponents(grid);
    });
  },

  // Reset form
  resetForm: function(name) {
    $(':input','#new_' + name).not(':button, :submit, :reset, :hidden').not('[readonly]').val('').removeAttr('checked').removeAttr('selected');
    // For chosen
    $('ul.chzn-choices li.search-choice').remove();
  },

  // Create and open dialog
  openDialog: function(grid, action, options, callback) {
    $.get(grid.path + '/' + action + grid.query, function(data){
      Ui.createModelModal(grid, data, {
        ready: function(modal, trigger) {
          Ui.setupForm(grid, false);
        }
      });
    });
  },

  setupComponents: function(grid) {
    var name = grid.name;
    // setup select as chosen
    $('#' + name + '_form select[data-required="true"]').chosen();
    $('#' + name + '_form select[data-required="false"]').chosen({allow_single_deselect: true});

    $('#' + name + '_form select').off('change').on('change', function(){
      var flag = $('#' + name + '_form input.target_flag:checkbox[data-target="' + $(this).attr('data-target') + '"]');
      if (flag.size() > 0) flag.attr('checked', 'checked');
    });

    // setup datepicker
    $('#' + name + '_form input[data-date]').datepicker({ dateFormat: 'yy-mm-dd' });
    $('#' + name + '_form input[data-datetime]').datetimepicker({
      onlyTime: false,
      dateFormat: "yy-mm-dd",
      timeFormat: 'HH:mm',
      timeOnly: false,
      stepMinute: 1,
      minuteGrid: 0,
      beforeShow: function() { calendarOpen = true; },
      onClose: function() { calendarOpen = false; }
    });
    $('#' + name + '_form input[data-time]').timepicker({});
  },

  setupForm: function(grid, monitor) {
    var remotePath = [];
    var choicesColumn = [];
    var distinctColumn = [];
    var path;
    var name = grid.name;
    var scope = $('#' + name + '_form');
    var formType = scope.data('action');
    var columns = window[name + "_columns"] || grid.getColumns();
    var currentData = {};

    if (grid.loader)
      currentData = grid.loader.data[grid.getSelectedRows()[0]];

    // special handling for 'choices' and 'choices_column' options
    $.each(columns, function(i, n) {
      if (n['choices'] && typeof(n['choices']) == 'string') {
        if (n['distinct'] && formType != 'create') {
          distinctColumn.push([n.field, n['choices']]);
        } else {
          var formable = n.formable === false ? false : true;

          var editorChoices = n.choices;
          // Use editor's source instead of grid's source
          if (n.editor.source) {
            var match = /^.*(source=.*)$/igm.exec(n.choices);
            var grid_source = match[1];
            editorChoices = n.choices.replace(grid_source, 'source=' + n.editor.source);
          }

          remotePath.push([n.field, editorChoices, formable]);
        }
      } else if (currentData && n['choices_column']) {
        choicesColumn.push([n.field, currentData[n['choices_column']]]);
      }
    });

    // Fetch select options from remote
    if (remotePath.length > 0) {
      $.each(remotePath, function(i, n) {
        var field = n[0];
        var path = n[1];
        var formable = n[2];
        if (!path || !formable) return;

        var first_input;
        var target = $("select[data-field='" + field + "']", scope);
        var source = target.attr('data-source');
        if (target.size() == 1) {
          $('option[value!=""]', target).remove();

          $.getJSON(path, function(itemdata){
            $.each(itemdata, function(index, value) {
              if ($.isPlainObject(value)) {
                target.append(
                  "<option value='" + value.id + "'>" +
                  value[source] +
                  "</option>"
                );
              } else {
                target.append("<option value='" + value + "'>" + value + "</option>");
              }
            });
            Ui.setupChosen(target, monitor);
          });

        }
      });
    }

    // Fetch distinct select options from remote
    if (distinctColumn.length > 0) {
      $.each(distinctColumn, function(i, n) {
        var field = n[0];
        var path = n[1];
        if (!path) return;

        var first_input;
        var target = $("select[data-field='" + field + "']", scope);
        var source = target.attr('data-source');
        if (target.size() == 1) {
          $('option[value!=""]', target).remove();

          $.getJSON(path, function(itemdata){
            $.each(itemdata, function(index, value) {
              if ($.isPlainObject(value)) {
                target.append("<option value='" + value.id + "'>" + value[source] + "</option>");
              } else {
                target.append("<option value='" + value + "'>" + value + "</option>");
              }
            });
            target.append("<option>Add new Option</option>");
          });

        }
      });
    }

    // Fetch select options from current data
    if (choicesColumn.length > 0) {
        $.each(choicesColumn, function(i, n) {
        var field = n[0];
        var first_input;
        var target = $("select[data-field='" + field + "']", scope);
        if (target.size() == 1) {
          $('option[value!=""]', target).remove();
            $.each(n[1], function(index, value) {
              target.append("<option value='" + value + "'>" + value + "</option>");
            });
            Ui.setupChosen(target, monitor);
        }
      });
    }

    first_input = $( '#' + name + '_form input:text', scope).first();
    if (first_input.attr('data-date')) {
      first_input.focus();
    }

    // Layout
    $('.ui-dialog-titlebar').hide();
    $('.ui-resizable-handle').hide();
    // $('.chzn-container').width('100%');
    // $('.chzn-drop').width('100%');
    // $('.chzn-search input').width('96%');
  },

  setupChosen: function(dom, monitor) {
    setTimeout(function(){
      var afterSetupChosen = dom.data('afterSetupChosen');
      if (dom.hasClass("chzn-done")) {
        dom.trigger("liszt:updated");
      } else {
        dom.chosen();
      }

      if( afterSetupChosen ) {
        afterSetupChosen();
      }
    }, 100);
  },

  // Close Modal
  closeModal: function(name) {
    var $form = $( '#' + name + '_form' );
    window._focused = {};
    $form.closest('.modal').modal('close');
    $form.closest('.modal').remove();
  },

  // Flash the notification
  flashNotice: function(ids, action) {
    var recordSize = $.isArray(ids) ? ids.length : ids.split(',').length,
    recordUnit = recordSize > 1 ? 'records' : 'record',
    actionDesc = action === 'delete' ? 'has been deleted!' : 'has been created!';

    if (recordSize > 0) {
      $('.notice_flash').remove();
      $('#indicators').before('
' + recordSize + ' ' + recordUnit + ' ' + actionDesc + '
');
      $('.notice_flash').fadeOut(7000);
    }
  },

  // Find the selected grid
  findCurrentGrid: function() {
    var currentGrid = null;
    currentGridContainer = $( document.activeElement ).parents('.grid_container');
    if (currentGridContainer.size() === 0) {
      return null;
    }
    gridName = currentGridContainer.attr('id').split('grid_')[1];

    if (gridManager.grids.length == 1) {
      currentGrid = gridManager.grids[0];
    } else {
      if (currentGridContainer.size() == 1) {
        currentGrid = gridManager.getGrid(gridName);
      } else {
        $.each(gridManager.grids, function(){
          if(this.getSelectedRows().length > 0) currentGrid = this;
        });
      }
    }
    return currentGrid;
  },

  getModalSize: function(grid, data) {
    var width, height;
    $('body').append(data);
    var modalHeight = $('.create_form .title').outerHeight() +             // Title
                      $('.create_form form').outerHeight() +               // Fields
                      $('.create_form .submit').outerHeight() +            // Button
                      120;                                                 // Padding
    if (grid.options) {
      width = grid.options.form_dialog_width || 600;
      height = grid.options.form_dialog_height || modalHeight;
    } else {
      width = 600;
      height = modalHeight;
    }
    $('.create_form').remove();
    return { width: width, height: height };
  },

  baseModal: function(options) {
    var $modal = $('
')
      .addClass('modal')
      .appendTo($('body'));
    var $modalContent = $('
')
      .addClass('modal-content')
      .appendTo($modal);

    $.extend(options, {
      complete: function() {
        $modal.remove();
      }
    });
    $modal.modal(options);
    $modal.modal('open');

    return $modal;
  },

  headerModal: function(title, options) {
    options = options || {};
    var $headerModal = this.baseModal(options)
      .addClass('modal-fixed-footer')
      .css({overflow: 'hidden'});
    var $modalHeader = $('
')
      .addClass('modal-header')
      .append($('').text(title))
      .append($('').text('close').addClass('modal-close material-icons right'))
      .prependTo($headerModal);

    return $headerModal;
  },

  createModelModal: function(grid, data, options) {
    $.extend(options, {
      startingTop: '5%',
      endingTop: '5%',
    });

    var modalSize = this.getModalSize(grid, data);
    var $modelModal = this.baseModal(options)
      .width(modalSize.width)
      .height(modalSize.height)
      .css({'max-height': '90%'});

    $modelModal.find('.modal-content').append(data);
  },

  createJsonViewModal: function(jsonData) {
    var $jsonViewModal = this.headerModal('JSON View');
    $jsonViewModal.find('.modal-content').JSONView(jsonData, { collapsed: true });
  },

  formatData: function(grid, arrayData) {
    var data = {}, columns;
    columns = grid.loader.getColumns();
    $.each(columns, function(index, column){
      data[column['id']] = arrayData[index];
    });
    return data;
  }

};
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import PropTypes from 'prop-types'
import './AvatarMenu.scss'

const silenceClick = e => {
  e.preventDefault()
  e.stopPropagation()
}
const MenuOption = ({ onClick, label }) => (

{label}

)
const Menu = ({ isOpen, user, onClick }) => (

    <MenuOption onClick={silenceClick} label={user.githubLogin} />
    <MenuOption onClick={onClick('logout')} label='Log out' />

)

class AvatarMenu extends Component {
  state = { menuOpen: false }
  onAvatarClick = () => {
    const { menuOpen } = this.state
    this.setState({ menuOpen: !menuOpen })
  }
  onLogoutClick = () => {
    this.props.logout()
    window.location.replace('/api/user/logout')
  }
  onClick = action => () => {
    switch (action) {
      case 'logout':
        return this.onLogoutClick()
    }
  }
  render () {
    const { user = {}, logout } = this.props
    const { menuOpen } = this.state
    const triangleClassName = ['avatar-menu__triangle', menuOpen ? 'open' : ''].join(' ')
    return (

        ◢
        <Menu
          isOpen={menuOpen}
          user={user}
          onClick={this.onClick} />

    )
  }
}

export default AvatarMenu
<commit_msg>refactored avatar menu<commit_after>import React, { Component } from 'react'
import PropTypes from 'prop-types'
import ClickOutside from 'react-click-outside'
import cn from 'classnames'
import './AvatarMenu.scss'

const silenceClick = e => {
  e.preventDefault()
  e.stopPropagation()
}
const MenuOption = ({ onClick, label }) => (

{label}

)
const Menu = ({ isOpen, user, onClick }) => (
  <ClickOutside onClickOutside={onClick('clickOutside')}>

      <MenuOption onClick={silenceClick} label={user.githubLogin} />
      <MenuOption onClick={onClick('logout')} label='Log out' />

  </ClickOutside>
)

class AvatarMenu extends Component {
  state = { menuOpen: false }
  openMenu = () => this.setState({ menuOpen: true })
  closeMenu = () => this.setState({ menuOpen: false })
  onLogoutClick = () => {
    this.props.logout()
    window.location.replace('/api/user/logout')
  }
  onClick = action => () => {
    switch (action) {
      case 'logout':
        return this.onLogoutClick()
      case 'clickOutside':
        return this.closeMenu()
    }
  }
  render () {
    const { user = {}, logout } = this.props
    const { menuOpen } = this.state

    return (

        ◢
        <Menu
          isOpen={menuOpen}
          user={user}
          onClick={this.onClick} />

    )
  }
}

export default AvatarMenu
<|endoftext|>


<commit_before>window.materializeForm = {
  init: function() {
    this.initSelect()
    this.initCheckbox()
    this.initDate()
  },
  initSelect: function() {
    $('select[multiple="multiple"] option[value=""]').attr('disabled', true)
    $('select').material_select()
  },
  initCheckbox: function() {
    $('input[type=checkbox]').addClass('filled-in')
  },
  initDate: function() {
    $('input.date').pickadate({
      selectMonths: true,
      selectYears: 100
    });
  }
}

$(document).ready(function() {
  window.materializeForm.init()
});

$(document).ajaxSuccess(function() {
  window.materializeForm.init()
});
<commit_msg>support newer formSelect() method<commit_after>window.materializeForm = {
  init: function() {
    this.initSelect()
    this.initCheckbox()
    this.initDate()
  },
  initSelect: function() {
    $('select[multiple="multiple"] option[value=""]').attr('disabled', true)
    if (typeof $('select').material_select === "function") {
      $('select').material_select()
    } else {
      $('select').formSelect()
    }

  },
  initCheckbox: function() {
    $('input[type=checkbox]').addClass('filled-in')
  },
  initDate: function() {
    $('input.date').pickadate({
      selectMonths: true,
      selectYears: 100
    });
  }
}

$(document).ready(function() {
  window.materializeForm.init()
});

$(document).ajaxSuccess(function() {
  window.materializeForm.init()
});
<|endoftext|>


<commit_before>//PhantomJS script fired by back-end exporter
console.log('PhantomJS exporter running...');

var system = require('system');
var export_url = system.args[1];
var output_file = system.args[2];
var options_file = system.args[3];
var page = require('webpage').create();
var filesystem = require('fs');
var cookies = {};

var set_cookies = function(export_url, options_file) {
    var parser = document.createElement('a');
    parser.href = export_url;
    var cookie_domain = parser.hostname;
    var json_string, options;

    try {
        json_string = filesystem.read(options_file);
        options = JSON.parse(json_string);
    } catch(e) {
        console.error('Error reading/parsing JSON options file: ' + e);
        phantom.exit(1);
    }

    Object.keys(options).forEach(function(name) {
        cookies[name] = options[name];
        var cookie = {
          name: name,
          value: options[name],
          domain: cookie_domain,
          path: '/',
        };
        phantom.addCookie(cookie);
    });
}

var set_page_callbacks = function(page) {
  page.onConsoleMessage = function(msg) {
    console.log(msg);
  };
  page.onResourceError = function(resourceError) {
    console.log('Unable to load resource (#' + resourceError.id + 'URL:' + resourceError.url + ')');
    console.log('Error code: ' + resourceError.errorCode + '. Description: ' + resourceError.errorString);
  };
  page.onError = function(msg, trace) {
    var msgStack = ['ERROR: ' + msg];
    if (trace && trace.length) {
      msgStack.push('TRACE:');
      trace.forEach(function(t) {
        msgStack.push(' -> ' + t.file + ': ' + t.line + (t.function ? ' (in function "' + t.function +'")' : ''));
      });
    }
    console.error(msgStack.join('\n'));
  };
  page.onNavigationRequested = function(requested_url, type, willNavigate, main) {
    if (main && requested_url != export_url) {
      console.log('Unexpected redirect to: ' + requested_url);
      phantom.exit(1);
    }
  };
}

set_cookies(export_url, options_file);
set_page_callbacks(page);
console.log('Opening: ' + export_url);
page.open(export_url, function(status) {
  if (status !== 'success') {
    console.log('Unable to load page. Status was: ' + status);
    phantom.exit(1);
  }

  //waitFor does not work exactly as advertised due to a bug in PhantomJS.
  //It only fires once, and only at the end of the page load completing.
  //We might need an additional setTimeout around this one, but the
  //internet is reporting mixed results with that workaround.
  setTimeout(function() {
    waitFor(
      function() {  //"test condition" function
        return page.evaluate(function() {
          console.log('window.status: ' + window.status);
          return window.status == 'annotation_load_complete';
        });
      },
      function() {  //thing to do when it's ready function
        console.log('READY');
        set_styling(page);
        set_toc(cookies['toc_levels']);

        window.setTimeout(function () {
          //Give the previous set_* functions more time to finish their DOM
          //  manipulation. Not proven to make a difference either way, yet.
          write_file(output_file, page.content);
          phantom.exit();
        }, 60 * 1000);
      },
      1200000  //Arbitrarily huge number of milliseconds to let giant playlists finish
    );
  }, 200);
});

/**
 * @param testFx javascript condition that evaluates to a boolean,
 * it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
 * as a callback function.
 * @param onReady what to do when testFx condition is fulfilled,
 * it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
 * as a callback function.
 * @param timeOutMillis the max amount of time to wait.
 */
var waitFor = function(testFx, onReady, timeOutMillis) {
  var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 20000;
  var start = new Date().getTime();
  var condition = false;
  var interval = setInterval(function() {
    if ((new Date().getTime() - start < maxtimeOutMillis) && !condition) {
      // If not time-out yet and condition not yet fulfilled
      condition = (typeof(testFx) === "string" ? eval(testFx) : testFx());
    } else {
      if(!condition) {
        console.log("'waitFor()' timeout after " + maxtimeOutMillis + "ms");
        phantom.exit(1);
      } else {
        // Condition fulfilled (timeout and/or condition is true)
        console.log("'waitFor()' finished in " + (new Date().getTime() - start) + "ms.");
        typeof(onReady) === "string" ? eval(onReady) : onReady();
        clearInterval(interval);
      }
    }
  }, 1000 * 10); // repeat check every X milliseconds
};

var set_toc = function(maxLevel) {
  if (!maxLevel) {return;}

  // https://support.office.com/en-in/article/Field-codes-TOC-Table-of-Contents-field-1f538bc4-60e6-4854-9f64-67754d78d05c
  var tocHtml = [
    "",
    "",
    "[TOC Preview: To update, right-click and choose "Update field"]",
    "",
    "",
  ].join('\n');

  page.evaluate(function(tocHtml) {
    $('#toc-container').append(tocHtml);
    $('#word-doc-toc-container').append($('#toc').detach());
  }, tocHtml);
}

var get_doc_styles = function() {
  var font_face_string = cookies['print_font_face_mapped'];
  var font_size_string = cookies['print_font_size_mapped'];

  var font_size_scaler = function (match, p1, p2, p3, offset, string) {
    var scaling_name = cookies['print_font_size'];
    // This is the same 4px jump from fonts.js, converted to pt (=3pt), assuming
    // the base Doc style is sized as medium and thus requires no scaling.
    var size_conversion = {
      small: -3,
      medium: 0,
      large: 3,
      xlarge: 6,
    }
    var test_size_conversion = {
      small: -3,
      medium: -1,
      large: 1,
      xlarge: 3,
    }
    var new_size = Math.ceil(parseFloat(p2) + size_conversion[scaling_name]);
    return p1 + new_size + p3;
  }

  var margins = [
    cookies['print_margin_top'],
    cookies['print_margin_right'],
    cookies['print_margin_bottom'],
    cookies['print_margin_left'],
  ].join(' ');

  // Inject desired font face
  return filesystem.read('app/assets/stylesheets/doc-export.css')
    .replace(/(font-family:)(.+);/g, '$1' + font_face_string + ';')
    .replace(/MARGIN_PLACEHOLDER/, margins)
    .replace(/(font-size:)(.+)(pt;)/g, font_size_scaler);

  // Scale font sizes
  //  return css.replace(/(font-size:)(.+)(pt;)/g, font_size_scaler);
}

var set_styling = function(page) {
  var doc_styles = get_doc_styles();

  page.evaluate(function(doc_styles, cookies) {
        var html = $('html');
        html.attr('xmlns:v', 'urn:schemas-microsoft-com:vml');
        html.attr('xmlns:o', 'urn:schemas-microsoft-com:office:office');
        html.attr('xmlns:w', 'urn:schemas-microsoft-com:office:word');
        html.attr('xmlns:m', 'http://schemas.microsoft.com/office/2004/12/omml');
        html.attr('xmlns', 'http://www.w3.org/TR/REC-html40');
        html.attr('xml:lang', 'en');

      var font_face_string = cookies['print_font_face_mapped'];
      var font_size_string = cookies['print_font_size_mapped'];

        //NOTE: Some of these rules work with the non-Microsoft-specific CSS we inject, too.

        //TODO: move this to doc-export.css and add margin parsing in get_doc_styles();
    //TODO: grab a ton of the Word 2015 PC settings from rs2.b64.HTML and add tehm to doc stle.css
        var header = [
            doc_styles,
        ].join("\n");

        $('title').after($(header));

    //Highlights don't work in DOC, so we fake it with underlined text.
    //TODO: Move this to doc-export.css
    //Note: This also underlines text that was highlighted as part of a comment - not just pure highlights.
    $("span[class*=highlight-]").css('text-decoration', 'underline');

    //Get some whitespace where page breaks should go (but don't actually create a full-on page break)
    $("div.page-break").replaceWith( "

\n

" );

    // Word will only style this correctly if it is a P tag, not a div. #whoknowswhy
    $.each($('div.Case-internal-header'), function(i, node) {
      var divNode = $(node);
      var newNode = $('
');
      newNode.attr('class', divNode.attr('class'));
      if (divNode.attr('align') == 'center') {
        // Convert align=center to something Word respects
        newNode.css('text-align', 'center')
      }
      divNode.contents().unwrap().wrap(newNode);
    });

    //Just use the text of each TOC link in the TOC. This helps avoid HTML color bugs between platforms.
    $.each($('#toc').find('a'), function(i, node) {
      $(node).replaceWith($(node).text());
    });

    //Make sure Footnote class is the first class for existing footnote nodes, for Doc export.
    //NOTE: Does not work for footnotes with annotation tags in them, such as footnotes inside hidden text.
    $.each( $('.footnote').parent('p.Item-text'), function(i, node) {
      var footNode = $(node);
      footNode.removeClass('Item-text');
      footNode.attr('class', 'Footnote ' + footNode.attr('class'));
    });

        //Word ignores external stylesheets, so we inject their CSS inline into the DOM
        //and remove the actual stylesheet tags to prevent errors when Word tries to
        //load that over the network or something silly like that.
        var sheets = [];
        $('.stylesheet-link-tag').each(function(i, el) {
          sheets.push(el);
        });
        var injectable_css = [];
        for (var i in sheets) {
          var sheet = $(sheets[i]);
          if (sheet.attr('media') != 'screen') {
            injectable_css.push( sheet.cssText() );
          }
          sheet.remove();
        }

    var background_url_remover = function(match, p1, p2, p3, p4, offset, string) {
      if (p2 == '' || p2 == ' ') {
        // Don't create invalid rules
        return p4 == ';' ? '' : '}';
      }
      else {
        return [p1, p2, p3, p4].join('');
      }
    }

    // Strip background URLs in the CSS to prevent fatal errors opening the exported
    // Doc file in Word 2011 on a Mac.
    var raw_css = injectable_css.join("\n");
    raw_css = raw_css.replace(
      /(background(?:-image)?:)(.*?)url\(.*?\)([\s\S]*?)([;}])/g,
      background_url_remover
    );
    $('#export-styles').append(raw_css);
    $('#additional_styles').append($('#additional_styles').cssText());
    $('#highlight_styles').append($('#highlight_styles').cssText());

    // TOC: Forcibly remove bullets and prevent entire TOC
 from indenting 0.5in
    $('.MsoToc1 li').attr('style', 'mso-list:l0 level1 lfo1; margin-left: -0.5in;');

    // This seems to be required to avoid the issue where Word 2011 on a Mac indents
    // playlist items. We avoid using .css(...) here because that would wipe out the
    // Word-specific inline style that these nodes already have. That's important.
    $.each($('li.listitem'), function(i, el) {
      var newStyle = $(el).attr('style') + ' margin-left: 0in;';
      $(el).attr('style', newStyle);
    });

    // Remove all image tags. They are only going to cause trouble in a Doc export
    $('img').remove();

  }, doc_styles, cookies);
}

var write_file = function(output_file, content) {
    if (output_file == '-') {
        console.log(content);
        return;
    }

    try {
        filesystem.write(output_file, content, 'w');
        console.log('Wrote ' + content.length + ' bytes to ' + output_file);
    } catch(e) {
        console.log(e);
    }
}

<commit_msg>Wrap multi-word font names in quotes and remove troublesome DOM elements for Doc export<commit_after>//PhantomJS script fired by back-end exporter
console.log('PhantomJS exporter running...');

var system = require('system');
var export_url = system.args[1];
var output_file = system.args[2];
var options_file = system.args[3];
var page = require('webpage').create();
var filesystem = require('fs');
var cookies = {};

var set_cookies = function(export_url, options_file) {
    var parser = document.createElement('a');
    parser.href = export_url;
    var cookie_domain = parser.hostname;
    var json_string, options;

    try {
        json_string = filesystem.read(options_file);
        options = JSON.parse(json_string);
    } catch(e) {
        console.error('Error reading/parsing JSON options file: ' + e);
        phantom.exit(1);
    }

    Object.keys(options).forEach(function(name) {
        cookies[name] = options[name];
        var cookie = {
          name: name,
          value: options[name],
          domain: cookie_domain,
          path: '/',
        };
        phantom.addCookie(cookie);
    });
}

var set_page_callbacks = function(page) {
  page.onConsoleMessage = function(msg) {
    console.log(msg);
  };
  page.onResourceError = function(resourceError) {
    console.log('Unable to load resource (#' + resourceError.id + 'URL:' + resourceError.url + ')');
    console.log('Error code: ' + resourceError.errorCode + '. Description: ' + resourceError.errorString);
  };
  page.onError = function(msg, trace) {
    var msgStack = ['ERROR: ' + msg];
    if (trace && trace.length) {
      msgStack.push('TRACE:');
      trace.forEach(function(t) {
        msgStack.push(' -> ' + t.file + ': ' + t.line + (t.function ? ' (in function "' + t.function +'")' : ''));
      });
    }
    console.error(msgStack.join('\n'));
  };
  page.onNavigationRequested = function(requested_url, type, willNavigate, main) {
    if (main && requested_url != export_url) {
      console.log('Unexpected redirect to: ' + requested_url);
      phantom.exit(1);
    }
  };
}

set_cookies(export_url, options_file);
set_page_callbacks(page);
console.log('Opening: ' + export_url);
page.open(export_url, function(status) {
  if (status !== 'success') {
    console.log('Unable to load page. Status was: ' + status);
    phantom.exit(1);
  }

  //waitFor does not work exactly as advertised due to a bug in PhantomJS.
  //It only fires once, and only at the end of the page load completing.
  //We might need an additional setTimeout around this one, but the
  //internet is reporting mixed results with that workaround.
  setTimeout(function() {
    waitFor(
      function() {  //"test condition" function
        return page.evaluate(function() {
          console.log('window.status: ' + window.status);
          return window.status == 'annotation_load_complete';
        });
      },
      function() {  //thing to do when it's ready function
        console.log('READY');
        set_styling(page);
        set_toc(cookies['toc_levels']);

        window.setTimeout(function () {
          //Give the previous set_* functions more time to finish their DOM
          //  manipulation. Not proven to make a difference either way, yet.
          write_file(output_file, page.content);
          phantom.exit();
        }, 60 * 1000);
      },
      1200000  //Arbitrarily huge number of milliseconds to let giant playlists finish
    );
  }, 200);
});

/**
 * @param testFx javascript condition that evaluates to a boolean,
 * it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
 * as a callback function.
 * @param onReady what to do when testFx condition is fulfilled,
 * it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
 * as a callback function.
 * @param timeOutMillis the max amount of time to wait.
 */
var waitFor = function(testFx, onReady, timeOutMillis) {
  var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 20000;
  var start = new Date().getTime();
  var condition = false;
  var interval = setInterval(function() {
    if ((new Date().getTime() - start < maxtimeOutMillis) && !condition) {
      // If not time-out yet and condition not yet fulfilled
      condition = (typeof(testFx) === "string" ? eval(testFx) : testFx());
    } else {
      if(!condition) {
        console.log("'waitFor()' timeout after " + maxtimeOutMillis + "ms");
        phantom.exit(1);
      } else {
        // Condition fulfilled (timeout and/or condition is true)
        console.log("'waitFor()' finished in " + (new Date().getTime() - start) + "ms.");
        typeof(onReady) === "string" ? eval(onReady) : onReady();
        clearInterval(interval);
      }
    }
  }, 1000 * 10); // repeat check every X milliseconds
};

var set_toc = function(maxLevel) {
  if (!maxLevel) {return;}

  // https://support.office.com/en-in/article/Field-codes-TOC-Table-of-Contents-field-1f538bc4-60e6-4854-9f64-67754d78d05c
  var tocHtml = [
    "",
    "",
    "[TOC Preview: To update, right-click and choose "Update field"]",
    "",
    "",
  ].join('\n');

  page.evaluate(function(tocHtml) {
    $('#toc-container').append(tocHtml);
    $('#word-doc-toc-container').append($('#toc').detach());
  }, tocHtml);
}

var get_doc_styles = function() {
  var font_face_string = cookies['print_font_face_mapped'];
  var font_size_string = cookies['print_font_size_mapped'];

  var packed = [];
  var fallbacks = font_face_string.split(',');
  for(var x=0; x < fallbacks.length; x++) {
    var font = fallbacks[x];
    packed.push(
      font.indexOf(' ') >= 0 ? '"' + font + '"' : font
    );
  }
  var wrapped_font_face_string = packed.join(',');

  var font_size_scaler = function (match, p1, p2, p3, offset, string) {
    var scaling_name = cookies['print_font_size'];
    // This is the same 4px jump from fonts.js, converted to pt (=3pt), assuming
    // the base Doc style is sized as medium and thus requires no scaling.
    var size_conversion = {
      small: -3,
      medium: 0,
      large: 3,
      xlarge: 6,
    }
    var test_size_conversion = {
      small: -3,
      medium: -1,
      large: 1,
      xlarge: 3,
    }
    var new_size = Math.ceil(parseFloat(p2) + size_conversion[scaling_name]);
    return p1 + new_size + p3;
  }

  var margins = [
    cookies['print_margin_top'],
    cookies['print_margin_right'],
    cookies['print_margin_bottom'],
    cookies['print_margin_left'],
  ].join(' ');

  // Inject desired font face
  return filesystem.read('app/assets/stylesheets/doc-export.css')
    .replace(/(font-family:)(.+);/g, '$1' + wrapped_font_face_string + ';')
    .replace(/MARGIN_PLACEHOLDER/, margins)
    .replace(/(font-size:)(.+)(pt;)/g, font_size_scaler);

  // Scale font sizes
  //  return css.replace(/(font-size:)(.+)(pt;)/g, font_size_scaler);
}

var set_styling = function(page) {
  var doc_styles = get_doc_styles();

  page.evaluate(function(doc_styles, cookies) {
        var html = $('html');
        html.attr('xmlns:v', 'urn:schemas-microsoft-com:vml');
        html.attr('xmlns:o', 'urn:schemas-microsoft-com:office:office');
        html.attr('xmlns:w', 'urn:schemas-microsoft-com:office:word');
        html.attr('xmlns:m', 'http://schemas.microsoft.com/office/2004/12/omml');
        html.attr('xmlns', 'http://www.w3.org/TR/REC-html40');
        html.attr('xml:lang', 'en');

      var font_face_string = cookies['print_font_face_mapped'];
      var font_size_string = cookies['print_font_size_mapped'];

      //TODO: reverse engineer some of the Word 2015 PC settings from rs2.b64.HTML
      // and add them to doc stle.css
      $('title').after($(doc_styles));

    //Highlights don't work in DOC, so we fake it with underlined text.
    //TODO: Move this to doc-export.css
    //Note: This also underlines text that was highlighted as part of a comment - not just pure highlights.
    $("span[class*=highlight-]").css('text-decoration', 'underline');

    //Get some whitespace where page breaks should go (but don't actually create a full-on page break)
    $("div.page-break").replaceWith( "

\n

" );

    // Word will only style this correctly if it is a P tag, not a div.
    $.each($('div.Case-internal-header'), function(i, node) {
      var divNode = $(node);
      var newNode = $('
');
      newNode.attr('class', divNode.attr('class'));
      if (divNode.attr('align') == 'center') {
        // Convert align=center to something Word respects
        newNode.css('text-align', 'center')
      }
      divNode.contents().unwrap().wrap(newNode);
    });

    //Just use the text of each TOC link in the TOC. This helps avoid HTML color bugs between platforms.
    $.each($('#toc').find('a'), function(i, node) {
      $(node).replaceWith($(node).text());
    });

    //Make sure Footnote class is the first class for existing footnote nodes, for Doc export.
    //NOTE: Does not work for footnotes with annotation tags in them, such as footnotes inside hidden text.
    $.each( $('.footnote').parent('p.Item-text'), function(i, node) {
      var footNode = $(node);
      footNode.removeClass('Item-text');
      footNode.attr('class', 'Footnote ' + footNode.attr('class'));
    });

        //Word ignores external stylesheets, so we inject their CSS inline into the DOM
        //and remove the actual stylesheet tags to prevent errors when Word tries to
        //load that over the network or something silly like that.
        var sheets = [];
        $('.stylesheet-link-tag').each(function(i, el) {
          sheets.push(el);
        });
        var injectable_css = [];
        for (var i in sheets) {
          var sheet = $(sheets[i]);
          if (sheet.attr('media') != 'screen') {
            injectable_css.push( sheet.cssText() );
          }
          sheet.remove();
        }

    var background_url_remover = function(match, p1, p2, p3, p4, offset, string) {
      if (p2 == '' || p2 == ' ') {
        // Don't create invalid rules
        return p4 == ';' ? '' : '}';
      }
      else {
        return [p1, p2, p3, p4].join('');
      }
    }

    // Strip background URLs in the CSS to prevent fatal errors opening the exported
    // Doc file in Word 2011 on a Mac.
    var raw_css = injectable_css.join("\n");
    raw_css = raw_css.replace(
      /(background(?:-image)?:)(.*?)url\(.*?\)([\s\S]*?)([;}])/g,
      background_url_remover
    );
    $('#export-styles').append(raw_css);
    $('#additional_styles').append($('#additional_styles').cssText());

    // TOC: Forcibly remove bullets and prevent entire TOC
 from indenting 0.5in
    $('.MsoToc1 li').attr('style', 'mso-list:l0 level1 lfo1; margin-left: -0.5in;');

    // This seems to be required to avoid the issue where Word 2011 on a Mac indents
    // playlist items. We avoid using .css(...) here because that would wipe out the
    // Word-specific inline style that these nodes already have. That's important.
    $.each($('li.listitem'), function(i, el) {
      var newStyle = $(el).attr('style') + ' margin-left: 0in;';
      $(el).attr('style', newStyle);
    });

    // Remove un-needed TypeKit cruft that likely causes Word 2011 issues
    $('link[rel=stylesheet][href*=typekit], style:contains(".tk-"), #annotator-dynamic-style, #highlight_styles, style[rel="alternate stylesheet"]').remove();

    //NOTE: We might not need to remove that contains('.tk-') node, now that we know it is
    //  probably the empty nodes around it that were breaking things.

    // NOTE: Word 2011 can't parse empty


<commit_before>$(document).ready( function () {
	if ( ( $( '#ca-addsection' ).length > 0 ||
		( $.inArray( 'Non-talk pages that are automatically signed', mw.config.get( 'wgCategories' ) )  >= 0 &&
		mw.config.get( 'wgAction' ) == 'view' ) ) &&
		$.inArray( 'Pages that should not be manually archived', mw.config.get( 'wgCategories'  ) ) === -1 ) {
		var request0 = {
			action: 'query',
			titles: mw.config.get( 'wgPageName' ),
			rvsection: 0,
			prop: 'revisions|info',
			rvprop: "content",
			indexpageids: 1,
			format: 'json'
		};
		$.get( mw.config.get( 'wgScriptPath' ) + '/api.php', request0, function( response0 ) {
			var content0 = response0.query.pages.revisions[0]['*'];
			var headerLevelRegEx = new RegExp( '\\| *headerlevel *= *(\\d+)' );
			var headerLevel = headerLevelRegEx.exec( content0 );
			if ( headerLevel === null || headerLevel === undefined ) {
				headerLevel = 2;
			} else {
				headerLevel = parseInt( headerLevel[1] );
			}
			$( 'h' + headerLevel + ' span.mw-headline' ).each( function( i, v ) {
				var editSectionUrl = $( this ).parent().find( '.mw-editsection a:first' ).attr( 'href' );
				var sectionReg = /&section=(.*)/;
				var sectionRaw = sectionReg.exec( editSectionUrl );
				if ( sectionRaw != null && sectionRaw[1].indexOf( 'T' ) < 0 ) {
					var section = parseInt( sectionRaw[1] );
					if ( $( this ).parent().prop( 'tagName' ) == 'H' + headerLevel ) {

						$( this ).parent( 'h' + headerLevel ).append( '
 | ' + 'Archive' + '
' );

						$( this ).parent( 'h' + headerLevel ).find( 'a.archiverLink' ).click( function() {

							var mHeaders = 'Retrieving headers...';
							var mSection = 'retrieving section content...';
							var mPosting = 'Content retrieved, performing edits...';
							var mPosted = 'Archive appended...';
							var mCleared = 'Section cleared...';
							var mReloading = 'All done! Reloading...';

							$( 'body' ).append( '

' );

							$( 'body' ).prepend( '

' );

							$( '.arcProg' ).append( '
' + mHeaders + '
' );

							var regexObject3 = new RegExp( '\\| *counter *= *(\\d+)' );
							var counter = regexObject3.exec( content0 );
							if ( counter === null || counter === undefined ) {
								$( '.arcProg' ).remove();
								$( '.overlay' ).remove();
								alert( 'No archive counter was detected on this page, so archiving was aborted.\n\n\tSee User:Equazcion/OneClickArchiver for details.' );
							} else {
								var archiveNum = counter[1];

								var archiveNameReg = /\| *archive *= *(.*\%\(counter\)d.*?) *(-->)?/;
								var archiveNameRegMatch = archiveNameReg.exec( content0 );
								if ( archiveNameRegMatch === null || archiveNameRegMatch === undefined ) {
									$( '.arcProg' ).remove();
									$( '.overlay' ).remove();
									alert( 'No archive name was detected on this page, so archiving was aborted.\n\n\tSee User:Equazcion/OneClickArchiver for details.' );
								} else {
									var year = new Date().getFullYear();
									var month = new Date().getMonth();

									var rootBase = mw.config.get( 'wgPageName' )
										.replace( /\/.*/g, '' )
										.replace( /_/g, ' ' );
									var archiveName = archiveNameRegMatch[1]
										.replace( /\| *archive *= */, '' )
										.replace( /\%\(year\)d/g, year)
										.replace( /\%\(month\)d/g, month)
										.replace( /\%\(monthname\)s/g, mw.config.get( 'wgMonthNames' )[month+1] )
										.replace( /\%\(monthnameshort\)s/g, mw.config.get( 'wgMonthNamesShort' )[month+1] )
										.replace( /\%\(counter\)d/g, archiveNum);
									var archiveBase = archiveName
										.replace( /\/.*/, '' )
										.replace( /_/g, ' ' );
									var archiveSub = archiveName
										.replace( /_/g, ' ' )
										.replace( archiveBase, '' );
									if( archiveBase != rootBase ) {
										$( '.arcProg' ).remove();
										$( '.overlay' ).remove();
										alert( 'Archiving was aborted due to archive page name mismatch:\n\n\tFound:\t\t' + archiveName + '\n\tExpected:\t' + mw.config.get( 'wgPageName' ).replace( '_', ' ' ) + archiveSub + '\n\n\n\tSee User:Equazcion/OneClickArchiver for details.' );
									} else {
										$( '.arcProg' ).append( '
' + 'Archive name ' + archiveName + ' found, ' + mSection + '
' );

										var request5 = {
											action: 'query',
											titles: mw.config.get( 'wgPageName' ),
											rvsection: section,
											prop: 'revisions|info',
											intoken: 'edit',
											rvprop: 'content',
											indexpageids: 1,
											dataType: 'xml',
											format: 'xml'
										};

										$.get( mw.config.get( 'wgScriptPath' ) + '/api.php', request5, function( response5 ) {

											$( '.arcProg' ).append( '
' + mPosting + '
' );

											var dnau = $( response5 ).find( 'rev' ).text().match( // );
											if ( dnau === null || dnau === undefined ) {
												var dnauDate = Date.now();
												dnau = null;
											} else {
												dnau = dnau[1] + ':' + dnau[2] + ' ' + dnau[3] + ' ' + dnau[4] + ' ' + dnau[5];
												var dnauDate = new Date( dnau );
												dnauDate = dnauDate.valueOf();
											}

											if ( dnauDate > Date.now() ) {
												$( '.arcProg' ).remove();
												$( '.overlay' ).remove();
												alert( 'This section has been marked \"Do Not Archive Until\" " + dnau + ", so archiving was aborted.\n\n\tSee User:Equazcion/OneClickArchiver for details.' );
											} else {
												var contentSection = '\n\n{{Clear}}\n' + $( response5 ).find( 'rev' ).text();

												if ( dnau != null ) {
													contentSection = contentSection.replace( //g, '' );
												}
												new mw.Api().postWithToken( 'edit', {
													action: 'edit',
													title: archiveName,
													appendtext: contentSection,
													summary: '[[User:Equazcion/OneClickArchiver|OneClickArchiver]] ([[User:Technical_13/SandBox/OneClickArchiver.js|β]]) adding 1 discussion'
												} ).done( function() {
													$( '.arcProg' ).append( '
' + mPosted + '
' );
													new mw.Api().postWithToken( 'edit', {
														action: 'edit',
														section: section,
														title: mw.config.get( 'wgPageName' ),
														text: '',
														summary: '[[User:Equazcion/OneClickArchiver|OneClickArchiver]] ([[User:Technical_13/SandBox/OneClickArchiver.js|β]]) archived 1 discussion to [[' + archiveName + ']]',
													} ).done( function() {
														$( '.arcProg' ).append( '
' + mCleared + '
' );
														$( '.arcProg' ).append( '
' + mReloading + '
' );
														location.reload();
													} );
												} );
											}
										} );
									}
								}
							}
						} );
					}
				}
			} );
			var linkTextD = 'OCA - on', linkDescD = 'Disable OneClickArchiver on this page';
			var linkTextE = 'OCA - off', linkDescE = 'Enable OneClickArchiver on this page';
			var linkText = linkTextD, linkDesc = linkDescD;
			var OCAstate = mw.user.options.get( 'userjs-OCA-enabled', 'true' );
			if ( OCAstate === 'false' ) {
				linkText = linkTextE, linkDesc = linkDescE;
				$( 'div.archiverDiv' ).css( 'display', 'none' );
			}
			var archiverToggle = mw.util.addPortletLink(
				'p-cactions',
				'#archiverLink',
				linkText,
				'pt-OCA',
				linkDesc,
				'o',
				null
			);
			$( archiverToggle ).click( function ( e ) {
				e.preventDefault();
				/* Toggle the archiveLinks */
				$( 'div.archiverDiv' ).css( 'display', function (i, val) {
					return val === 'none' ? '' : 'none';
				});
				/* Toggle the toggle link */
				$( 'li#pt-OCA a' ).html( function ( i, val ) {
					return val === linkTextD ? linkTextE : linkTextD;
				});
				/* Toggle the toggle description */
				$( 'li#pt-OCA a' ).attr( 'title', function (i, val) {
					return val === linkDescD ? linkDescE : linkDescD;
				});
				/* Toggle default state */
				new mw.Api().postWithToken( 'options', {
					action: 'options',
					optionname: 'userjs-OCA-enabled',
					optionvalue: OCAstate === 'true' ? 'false' : 'true'
				} ).done( function() {
					var resultMsg = 'OneClickArchiver is now ' + ( OCAstate === 'true' ? 'disabled' : 'enabled' ) + ' by default.';
					mw.notify(resultMsg);
					OCAstate = OCAstate === 'true' ? 'false' : 'true';
				} );
			} );
		} );
	}
} );
<commit_msg>This is the current live version...<commit_after>if( ( $('#ca-addsection').length > 0 || ( $.inArray('Non-talk pages that are automatically signed', mw.config.get( 'wgCategories' ))  >= 0 && mw.config.get( 'wgAction' ) == 'view' ) ) && $.inArray('Pages that should not be manually archived', mw.config.get( 'wgCategories' )) === -1){
	var request0 = {
		action:"query",
		titles: mw.config.get( 'wgPageName' ),
		rvsection: 0,
		prop: "revisions|info",
		intoken: "edit",
		rvprop: "content",
		indexpageids: 1,
		dataType: "xml",
		format: "xml"
	};
	$.get(mw.config.get( 'wgScriptPath' )+"/api.php", request0, function(response0){
		var content0 = $(response0).find('rev').text();
		var headerLevelRegEx = new RegExp('\\| *headerlevel *= *(\\d+)');
		var headerLevel = headerLevelRegEx.exec(content0);
		if ((headerLevel === null) || (typeof(headerLevel) === 'undefined')){
			headerLevel = 2;
		} else {
			headerLevel = parseInt(headerLevel[1]);
		}
		$('h' + headerLevel + ' span.mw-headline').each(function(index, value){
			var editSectionUrl = $(this).parent().find('.mw-editsection a:first').attr('href');
			var sectionReg = /&section=(.*)/;
			var sectionRaw = sectionReg.exec(editSectionUrl);
			if ((sectionRaw != null) && (sectionRaw[1].indexOf('T') < 0)){
				var section = parseInt(sectionRaw[1]);
				if ($(this).parent().prop("tagName") == 'H' + headerLevel){

					$(this).parent('h' + headerLevel).append('
 | ' + 'Archive' + '
');

					$(this).parent('h' + headerLevel).find('a.archiverLink').click(function(){

						var mHeaders = 'Retrieving headers...';
						var mSection = 'retrieving section content...';
						var mPosting = 'Content retrieved, performing edits...';
						var mPosted = 'Archive appended...';
						var mCleared = 'Section cleared...';
						var mReloading = 'All done! Reloading...';

						$('body').append('

');

						$('body').prepend('

');

						$('.arcProg').append('
' + mHeaders + '
');

						var regexObject3 = new RegExp('\\| *counter *= *(\\d+)');
						var counter = regexObject3.exec(content0);
						if ((counter === null) || (typeof(counter) === 'undefined')){
							$('.arcProg').remove();
							$('.overlay').remove();
							alert("No archive counter was detected on this page, so archiving was aborted.\n\n\tSee User:Equazcion/OneClickArchiver for details.");
						} else {
							var archiveNum = counter[1];

							var archiveNameReg = /\| *archive *= *(.*\%\(counter\)d.*?) *(-->)?/;
							var archiveNameRegMatch = archiveNameReg.exec(content0);
							if ((archiveNameRegMatch === null) || (typeof(archiveNameRegMatch) === 'undefined')){
								$('.arcProg').remove();
								$('.overlay').remove();
								alert("No archive name was detected on this page, so archiving was aborted.\n\n\tSee User:Equazcion/OneClickArchiver for details.");
							} else {

								var monthNames = ["january", "february", "march", "april", "may", "june",
									"july", "august", "september", "october", "november", "december"];

								var shortMonthNames = ["jan", "feb", "mar", "apr", "may", "jun",
									"jul", "aug", "sep", "oct", "nov", "dec"];

								var year = new Date().getFullYear();
								var month = new Date().getMonth();

								var rootBase = mw.config.get('wgPageName')
									.replace(/\/.*/g, '')
									.replace(/_/g, ' ');
 								var archiveName = archiveNameRegMatch[1]
									.replace(/\| *archive *= */, '')
									.replace(/\%\(year\)d/g, year)
									.replace(/\%\(month\)d/g, month)
									.replace(/\%\(monthname\)s/g, monthNames[month])
									.replace(/\%\(monthnameshort\)s/g, shortMonthNames[month])
									.replace(/\%\(counter\)d/g, archiveNum);
								var archiveBase = archiveName
									.replace(/\/.*/, '')
									.replace(/_/g, ' ');
								var archiveSub = archiveName
									.replace(/_/g, ' ')
									.replace(archiveBase, '');
								if(archiveBase != rootBase){
									$('.arcProg').remove();
									$('.overlay').remove();
									alert("Archiving was aborted due to archive page name mismatch:\n\n\tFound:\t\t" + archiveName + "\n\tExpected:\t" + mw.config.get('wgPageName').replace("_", " ") + archiveSub + "\n\n\n\tSee User:Equazcion/OneClickArchiver for details.");
								} else {
									$('.arcProg').append('
' + 'Archive name ' + archiveName + ' found, ' + mSection + '
');

									var request5 = {
										action:"query",
										titles: mw.config.get( 'wgPageName' ),
										rvsection: section,
										prop: "revisions|info",
										intoken: "edit",
										rvprop: "content",
										indexpageids: 1,
										dataType: "xml",
										format: "xml"
									};

									$.get(mw.config.get( 'wgScriptPath' )+"/api.php", request5, function(response5){

										$('.arcProg').append('
' + mPosting + '
');

										var dnau = $(response5).find('rev').text().match(//);
										if (dnau === null || typeof(dnau) === 'undefined'){
											var dnauDate = Date.now();
											dnau = null;
										} else {
											dnau = dnau[1] + ':' + dnau[2] + ' ' + dnau[3] + ' ' + dnau[4] + ' ' + dnau[5];
											var dnauDate = new Date(dnau);
											dnauDate = dnauDate.valueOf();
										}

										if(dnauDate > Date.now()){
											$('.arcProg').remove();
											$('.overlay').remove();
											alert("This section has been marked \"Do Not Archive Until\" " + dnau + ", so archiving was aborted.\n\n\tSee User:Equazcion/OneClickArchiver for details.");
										} else {
											var contentSection = '\n\n{{Clear}}\n' + $(response5).find('rev').text();

											if(dnau != null){
												contentSection = contentSection.replace(//g, '');
											}

											var request1 = {
												action:"edit",
												title: archiveName,
												appendtext: contentSection,
												summary: '[[User:Equazcion/OneClickArchiver|OneClickArchiver]] adding 1 discussion',
												token: mw.user.tokens.get( 'editToken' )
											};

											var request2 = {
												action:"edit",
												section: section,
												title: mw.config.get( 'wgPageName' ),
												text: "",
												summary: '[[User:Equazcion/OneClickArchiver|OneClickArchiver]] archived 1 discussion to [[' + archiveName + ']]',
												token: mw.user.tokens.get( 'editToken' )
											};

											$.when(
												$.post(mw.config.get( 'wgScriptPath' )+"/api.php", request1, function(response1){
													$('.arcProg').append('
' + mPosted + '
'); }),
												$.post(mw.config.get( 'wgScriptPath' )+"/api.php", request2, function(response2){
													$('.arcProg').append('
' + mCleared + '
'); })
											 ).done(function() {
												$('.arcProg').append('
' + mReloading + '
');
												location.reload();
											});
										}
									});
								}
							}
						}
					});
				}
			}
		});
		var linkTextD = "OCA - on", linkDescD = "Disable OneClickArchiver on this page";
		var linkTextE = "OCA - off", linkDescE = "Enable OneClickArchiver on this page";
		var linkText = linkTextD, linkDesc = linkDescD;
		var OCAstate = mw.user.options.get('userjs-OCA-enabled', 'true');
		if(OCAstate === 'false'){
			linkText = linkTextE, linkDesc = linkDescE;
			$( 'div.archiverDiv' ).css( 'display', 'none');
		}
		var archiverToggle = mw.util.addPortletLink(
			'p-cactions',
			'#archiverLink',
			linkText,
			'pt-OCA',
			linkDesc,
			'o',
			null
		);
		$( archiverToggle ).click( function ( e ) {
			e.preventDefault();
			/* Toggle the archiveLinks */
			$( 'div.archiverDiv' ).css( 'display', function (i, val) {
				return val === "none" ? "" : "none";
			});
			/* Toggle the toggle link */
			$( 'li#pt-OCA a' ).html( function (i, val) {
				return val === linkTextD ? linkTextE : linkTextD;
			});
			/* Toggle the toggle description */
			$( 'li#pt-OCA a' ).attr( 'title', function (i, val) {
				return val === linkDescD ? linkDescE : linkDescD;
			});
			/* Toggle default state */
			new mw.Api().postWithToken( 'options', {
				action: 'options',
				optionname: 'userjs-OCA-enabled',
				optionvalue: OCAstate === 'true' ? 'false' : 'true'
			} ).done(function() {
				var resultMsg = 'OneClickArchiver is now ' + ((OCAstate === 'true') ? 'disabled' : 'enabled') + ' by default.';
				mw.notify(resultMsg);
			});
		});
	});
}
<|endoftext|>


<commit_before>Teikei.module("Places", function(Places, App, Backbone, Marionette, $, _) {

  var DEFAULT_ZOOM = 10
  var BERLIN = [52.52, 13.39];

  Places.MapView = Marionette.ItemView.extend({

    element: "#map",

    markers: [],

    initialize: function() {
      this.collection.once("reset", this.initMap, this);
      this.collection.bind("change", this.updateMap, this);
      this.collection.bind("add", this.add, this);
    },

    showTip: function(id) {
      var marker = _.find(this.markers, function(item){
        return Number(id) === item.model.id;
      });
      this.initTip(marker);
      marker.openPopup();
    },

    initTip: function(marker) {
      if (marker === undefined) {
        return;
      }
      var model = marker.model;
      var mapItemView = new Places.MapItemView({model: model});
      mapItemView.render();
      marker.bindPopup(mapItemView.el, {offset: L.point(0, -55)});

      this.listenTo(mapItemView, "select:details", function(){
        this.trigger("select:details", model.id, model.get("type"));
      }, this);

      this.listenTo(mapItemView, "select:network", function(){
        this.trigger("select:network", model.id, model.get("type"));
      }, this);
    },

    add: function(model) {
      this.updateMap();
      this.map.setView(this.getLatLng(model), DEFAULT_ZOOM);
      this.showTip(model.id);
    },

    updateMap: function(model) {
      this.markerLayer.clearLayers();
      this.markerLayer = this.initMarkerLayer(this.collection);
      this.map.addLayer(this.markerLayer);
    },

    hilightMarkers: function(places) {
      var bounds = [];
      _.each(this.markers, function(marker) {
        marker.setOpacity(0.3);
        _.each(places, function(place){
          if (place.id === marker.model.id) {
            marker.setOpacity(1);
            bounds.push(marker.getLatLng());
          }
        });
      });
      this.map.fitBounds(bounds);
    },

    drawNetwork: function(places) {
      var networkLayer = this.networkLayer;
      var farms = _.filter(places, function(item) {
        return item.type === "Farm";
      });
      var depots = _.filter(places, function(item) {
        return item.type === "Depot";
      });

      _.each(farms, function(farm) {
        _.each(depots, function(depot) {
          var latlngs = [
            new L.LatLng(farm.latitude, farm.longitude),
            new L.LatLng(depot.latitude, depot.longitude)
          ];
          var polyline = L.polyline(latlngs, {color: '#a00e46', weight: 2});
          polyline.addTo(networkLayer);
        });
      });
    },

    hilightNetwork: function(model) {
      var places = _.map(model.get("places"), function(item) {
        return item.place;
      });
      places.push(model.attributes);
      this.drawNetwork(places);
      this.hilightMarkers(places);
    },

    unHilightNetwork: function() {
      _.each(this.markers, function(marker) {
        _.defer(function(){
          marker.setOpacity(1);
        });
      });
      this.networkLayer.clearLayers();
      Backbone.history.navigate('/');
    },

    showArea: function(bounds) {
      this.map.fitBounds(bounds);
    },

    initMap: function() {
      this.tileLayer = this.initTileLayer();
      this.networkLayer = L.layerGroup();
      this.markerLayer = this.initMarkerLayer(this.collection);
      this.map = L.map("map").setView(BERLIN, DEFAULT_ZOOM);
      this.map.addLayer(this.tileLayer);
      this.map.addLayer(this.networkLayer);
      this.map.addLayer(this.markerLayer);
      this.map.on("popupclose", _.bind(this.unHilightNetwork, this));
    },

    initMarkerLayer: function(collection) {
      var markers = this.markers = [];
      collection.each(function(model){
        var marker = this.initMarker(model);
        if (marker) markers.push(marker);
      }, this);
      return L.layerGroup(markers);
    },

    initMarker: function(model) {
      var type = model.get("type");
      var icon = new Places.MarkerIcon[type]();
      var location = this.getLatLng(model);

      if (location) {
        var marker = L.marker(location, {icon: icon});
        marker.model = model;
        marker.on("click", _.bind(function () {
          Backbone.history.navigate('places/' + model.id + '/tip');
          this.initTip(marker);
        }, this));
        return marker;
      }
    },

    getLatLng: function(model){
      var lat = model.get("latitude");
      var lng = model.get("longitude");
      if (lat && lng) {
        return new L.LatLng(lat, lng);
      }
    },

    initTileLayer: function() {
      return L.tileLayer("http://{s}.tiles.mapbox.com/v3/" + Places.MapConfig.APIKEY + "/{z}/{x}/{y}.png", {
        attribution: "Map data © OpenStreetMap contributors, CC-BY-SA"
      });
    }

  });
});
<commit_msg>Don’t bind tip initialization to click handler (as it would initialize the view multiple times).<commit_after>Teikei.module("Places", function(Places, App, Backbone, Marionette, $, _) {

  var DEFAULT_ZOOM = 10
  var BERLIN = [52.52, 13.39];

  Places.MapView = Marionette.ItemView.extend({

    element: "#map",

    markers: [],

    initialize: function() {
      this.collection.once("reset", this.initMap, this);
      this.collection.bind("change", this.updateMap, this);
      this.collection.bind("add", this.add, this);
    },

    showTip: function(id) {
      var marker = _.find(this.markers, function(item){
        return Number(id) === item.model.id;
      });
      this.initTip(marker);
      marker.openPopup();
    },

    initTip: function(marker) {
      if (marker === undefined) {
        return;
      }
      var model = marker.model;
      var mapItemView = new Places.MapItemView({model: model});
      mapItemView.render();
      marker.bindPopup(mapItemView.el, {offset: L.point(0, -55)});

      this.listenTo(mapItemView, "select:details", function(){
        this.trigger("select:details", model.id, model.get("type"));
      }, this);

      this.listenTo(mapItemView, "select:network", function(){
        this.trigger("select:network", model.id, model.get("type"));
      }, this);
    },

    add: function(model) {
      this.updateMap();
      this.map.setView(this.getLatLng(model), DEFAULT_ZOOM);
      this.showTip(model.id);
    },

    updateMap: function(model) {
      this.markerLayer.clearLayers();
      this.markerLayer = this.initMarkerLayer(this.collection);
      this.map.addLayer(this.markerLayer);
    },

    hilightMarkers: function(places) {
      var bounds = [];
      _.each(this.markers, function(marker) {
        marker.setOpacity(0.3);
        _.each(places, function(place){
          if (place.id === marker.model.id) {
            marker.setOpacity(1);
            bounds.push(marker.getLatLng());
          }
        });
      });
      this.map.fitBounds(bounds);
    },

    drawNetwork: function(places) {
      var networkLayer = this.networkLayer;
      var farms = _.filter(places, function(item) {
        return item.type === "Farm";
      });
      var depots = _.filter(places, function(item) {
        return item.type === "Depot";
      });

      _.each(farms, function(farm) {
        _.each(depots, function(depot) {
          var latlngs = [
            new L.LatLng(farm.latitude, farm.longitude),
            new L.LatLng(depot.latitude, depot.longitude)
          ];
          var polyline = L.polyline(latlngs, {color: '#a00e46', weight: 2});
          polyline.addTo(networkLayer);
        });
      });
    },

    hilightNetwork: function(model) {
      var places = _.map(model.get("places"), function(item) {
        return item.place;
      });
      places.push(model.attributes);
      this.drawNetwork(places);
      this.hilightMarkers(places);
    },

    unHilightNetwork: function() {
      _.each(this.markers, function(marker) {
        _.defer(function(){
          marker.setOpacity(1);
        });
      });
      this.networkLayer.clearLayers();
      Backbone.history.navigate('/');
    },

    showArea: function(bounds) {
      this.map.fitBounds(bounds);
    },

    initMap: function() {
      this.tileLayer = this.initTileLayer();
      this.networkLayer = L.layerGroup();
      this.markerLayer = this.initMarkerLayer(this.collection);
      this.map = L.map("map").setView(BERLIN, DEFAULT_ZOOM);
      this.map.addLayer(this.tileLayer);
      this.map.addLayer(this.networkLayer);
      this.map.addLayer(this.markerLayer);
      this.map.on("popupclose", _.bind(this.unHilightNetwork, this));
    },

    initMarkerLayer: function(collection) {
      var markers = this.markers = [];
      collection.each(function(model){
        var marker = this.initMarker(model);
        if (marker) markers.push(marker);
      }, this);
      return L.layerGroup(markers);
    },

    initMarker: function(model) {
      var type = model.get("type");
      var icon = new Places.MarkerIcon[type]();
      var location = this.getLatLng(model);

      if (location) {
        var marker = L.marker(location, {icon: icon});
        marker.model = model;
        this.initTip(marker);
        marker.on("click", _.bind(function () {
          Backbone.history.navigate('places/' + model.id + '/tip');
        }, this));
        return marker;
      }
    },

    getLatLng: function(model){
      var lat = model.get("latitude");
      var lng = model.get("longitude");
      if (lat && lng) {
        return new L.LatLng(lat, lng);
      }
    },

    initTileLayer: function() {
      return L.tileLayer("http://{s}.tiles.mapbox.com/v3/" + Places.MapConfig.APIKEY + "/{z}/{x}/{y}.png", {
        attribution: "Map data © OpenStreetMap contributors, CC-BY-SA"
      });
    }

  });
});
<|endoftext|>


<commit_before>const async = require('async');
const utils = require('../../utils/utils.js');
const constants = require('../../constants');
const BlockchainProcessLauncher = require('./blockchainProcessLauncher');

class BlockchainModule {

  constructor(embark, options) {
    this.logger = embark.logger;
    this.events = embark.events;
    this.blockchainConfig = embark.config.blockchainConfig;
    this.contractsConfig = embark.config.contractsConfig;
    this.embark = embark;
    this.locale = options.locale;
    this.isDev = options.isDev;
    this.ipc = options.ipc;
    this.client = options.client;

    this.registerBlockchainProcess();
  }

  registerBlockchainProcess() {
    const self = this;
    this.events.request('processes:register', 'blockchain', (cb) => {
      self.assertNodeConnection(true, (connected) => {
        if (connected) return cb();
        self.startBlockchainNode(cb);
        this.listenToCommands();
        this.registerConsoleCommands();
      });
    });

    if (!this.ipc.isServer()) return;
    self.ipc.on('blockchain:node', (_message, cb) => {
      cb(null, utils.buildUrlFromConfig(self.contractsConfig.deployment));
    });
  }

  listenToCommands() {
    this.events.setCommandHandler('logs:ethereum:turnOn',  (cb) => {
      this.events.emit('logs:ethereum:enable');
      return cb(null, 'Enabling Geth logs');
    });

    this.events.setCommandHandler('logs:ethereum:turnOff',  (cb) => {
      this.events.emit('logs:ethereum:disable');
      return cb(null, 'Disabling Geth logs');
    });
  }

  registerConsoleCommands() {
    const self = this;
    self.embark.registerConsoleCommand((cmd, _options) => {
      return {
        match: () => cmd === 'log geth on',
        process: (cb) => self.events.request('logs:ethereum:turnOn', cb)
      };
    });

    self.embark.registerConsoleCommand((cmd, _options) => {
      return {
        match: () => cmd === 'log geth off',
        process: (cb) => self.events.request('logs:ethereum:turnOff', cb)
      };
    });
  }

  assertNodeConnection(noLogs, cb) {
    if (typeof noLogs === 'function') {
      cb = noLogs;
      noLogs = false;
    }
    const self = this;

    async.waterfall([
      function checkWeb3State(next) {
        self.events.request("blockchain:web3:isReady", (connected) => {
          if (connected) {
            return next(connected);
          }
          next();
        });
      },
      function pingEndpoint(next) {
        if (!self.contractsConfig || !self.contractsConfig.deployment || !self.contractsConfig.deployment.host) {
          return next();
        }
        const {host, port, type, protocol} = self.contractsConfig.deployment;
        utils.pingEndpoint(host, port, type, protocol, self.blockchainConfig.wsOrigins.split(',')[0], next);
      }
    ], function(err) {
      if (err === true || err === undefined) {
        return cb(true);
      }
      return cb(false);
    });
  }

  startBlockchainNode(callback) {
    const self = this;

    let blockchainProcess = new BlockchainProcessLauncher({
      events: self.events,
      logger: self.logger,
      normalizeInput: utils.normalizeInput,
      blockchainConfig: self.blockchainConfig,
      locale: self.locale,
      client: self.client,
      isDev: self.isDev,
      embark: this.embark
    });

    blockchainProcess.startBlockchainNode();
    self.events.once(constants.blockchain.blockchainReady, () => {
      callback();
    });
    self.events.once(constants.blockchain.blockchainExit, () => {
      callback();
    });
  }

}

module.exports = BlockchainModule;
<commit_msg>chore(blockchain): rename `log geth` cmd to log blockchain<commit_after>const async = require('async');
const utils = require('../../utils/utils.js');
const constants = require('../../constants');
const BlockchainProcessLauncher = require('./blockchainProcessLauncher');

class BlockchainModule {

  constructor(embark, options) {
    this.logger = embark.logger;
    this.events = embark.events;
    this.blockchainConfig = embark.config.blockchainConfig;
    this.contractsConfig = embark.config.contractsConfig;
    this.embark = embark;
    this.locale = options.locale;
    this.isDev = options.isDev;
    this.ipc = options.ipc;
    this.client = options.client;

    this.registerBlockchainProcess();
  }

  registerBlockchainProcess() {
    const self = this;
    this.events.request('processes:register', 'blockchain', (cb) => {
      self.assertNodeConnection(true, (connected) => {
        if (connected) return cb();
        self.startBlockchainNode(cb);
        this.listenToCommands();
        this.registerConsoleCommands();
      });
    });

    if (!this.ipc.isServer()) return;
    self.ipc.on('blockchain:node', (_message, cb) => {
      cb(null, utils.buildUrlFromConfig(self.contractsConfig.deployment));
    });
  }

  listenToCommands() {
    this.events.setCommandHandler('logs:ethereum:turnOn',  (cb) => {
      this.events.emit('logs:ethereum:enable');
      return cb(null, 'Enabling Geth logs');
    });

    this.events.setCommandHandler('logs:ethereum:turnOff',  (cb) => {
      this.events.emit('logs:ethereum:disable');
      return cb(null, 'Disabling Geth logs');
    });
  }

  registerConsoleCommands() {
    const self = this;
    self.embark.registerConsoleCommand((cmd, _options) => {
      return {
        match: () => cmd === 'log blockchain on',
        process: (cb) => self.events.request('logs:ethereum:turnOn', cb)
      };
    });

    self.embark.registerConsoleCommand((cmd, _options) => {
      return {
        match: () => cmd === 'log blockchain off',
        process: (cb) => self.events.request('logs:ethereum:turnOff', cb)
      };
    });
  }

  assertNodeConnection(noLogs, cb) {
    if (typeof noLogs === 'function') {
      cb = noLogs;
      noLogs = false;
    }
    const self = this;

    async.waterfall([
      function checkWeb3State(next) {
        self.events.request("blockchain:web3:isReady", (connected) => {
          if (connected) {
            return next(connected);
          }
          next();
        });
      },
      function pingEndpoint(next) {
        if (!self.contractsConfig || !self.contractsConfig.deployment || !self.contractsConfig.deployment.host) {
          return next();
        }
        const {host, port, type, protocol} = self.contractsConfig.deployment;
        utils.pingEndpoint(host, port, type, protocol, self.blockchainConfig.wsOrigins.split(',')[0], next);
      }
    ], function(err) {
      if (err === true || err === undefined) {
        return cb(true);
      }
      return cb(false);
    });
  }

  startBlockchainNode(callback) {
    const self = this;

    let blockchainProcess = new BlockchainProcessLauncher({
      events: self.events,
      logger: self.logger,
      normalizeInput: utils.normalizeInput,
      blockchainConfig: self.blockchainConfig,
      locale: self.locale,
      client: self.client,
      isDev: self.isDev,
      embark: this.embark
    });

    blockchainProcess.startBlockchainNode();
    self.events.once(constants.blockchain.blockchainReady, () => {
      callback();
    });
    self.events.once(constants.blockchain.blockchainExit, () => {
      callback();
    });
  }

}

module.exports = BlockchainModule;
<|endoftext|>


<commit_before>function insertAtPosition(position,node)
{
    if (position.node.nodeType == Node.ELEMENT_NODE) {
        if (position.offset == position.node.childNodes.length)
            DOM.appendChild(position.node,node);
        else
            DOM.insertBefore(position.node,node,position.node.childNodes[position.offset]);
    }
    else if (position.node.nodeType == Node.TEXT_NODE) {
        var newText = DOM.createTextNode(document,position.node.nodeValue.slice(position.offset));
        position.node.nodeValue = position.node.nodeValue.slice(0,position.offset);
        DOM.insertBefore(position.node.parentNode,newText,position.node.nextSibling);
        DOM.insertBefore(position.node.parentNode,node,position.node.nextSibling);
    }
}

function insertTextAtPosition(position,str)
{
    if (position.node.nodeType == Node.ELEMENT_NODE) {
        insertAtPosition(position,DOM.createTextNode(document,str));
    }
    else if (position.node.nodeType == Node.TEXT_NODE) {
        position.node.nodeValue = position.node.nodeValue.slice(0,position.offset) + str +
                                  position.node.nodeValue.slice(position.offset);
    }
}

function showRangeAsBrackets(range)
{
    insertTextAtPosition(range.end,"]");
    insertTextAtPosition(range.start,"[");
}

function removeIds()
{
    recurse(document.body);

    function recurse(node)
    {
        if (node.nodeType == Node.ELEMENT_NODE) {
            node.removeAttribute("id");
            for (var child = node.firstChild; child != null; child = child.nextSibling)
                recurse(child);
        }
    }
}

function selectNode(node)
{
    var offset = DOM.nodeOffset(node);
    Selection.setSelectionRange(new Range(node.parentNode,offset,node.parentNode,offset+1));
}

function removeWhitespaceAndCommentNodes(node)
{
    if (isWhitespaceTextNode(node) || (node.nodeType == Node.COMMENT_NODE)) {
        DOM.deleteNode(node);
    }
    else {
        var next;
        for (var child = node.firstChild; child != null; child = next) {
            next = child.nextSibling;
            removeWhitespaceAndCommentNodes(child);
        }
    }
}

// selectionWrapElement() and selectionUnwrapElement() used to be in formatting.js but have
// now been made obselete by the addition of applyFormattingChanges(). However there are still
// a few tests which use them.
function selectionWrapElement(elementName)
{
    if (elementName == "B")
        Formatting.applyFormattingChanges(null,{"font-weight": "bold"});
    else if (elementName == "I")
        Formatting.applyFormattingChanges(null,{"font-style": "italic"});
    else if (elementName == "U")
        Formatting.applyFormattingChanges(null,{"text-decoration": "underline"});
}

function selectionUnwrapElement(elementName)
{
    if (elementName == "B")
        Formatting.applyFormattingChanges(null,{"font-weight": null});
    else if (elementName == "I")
        Formatting.applyFormattingChanges(null,{"font-style": null});
    else if (elementName == "U")
        Formatting.applyFormattingChanges(null,{"text-decoration": null});
}

function showEmptyTextNodes()
{
    recurse(document);

    function recurse(node)
    {
        if ((node.nodeType == Node.TEXT_NODE) && (node.nodeValue.length == 0))
            node.nodeValue = "*";
        for (var child = node.firstChild; child != null; child = child.nextSibling)
            recurse(child);
    }
}

function showClipboard(clipboard)
{
    var html = clipboard["text/html"];
    var text = clipboard["text/plain"];

    if ((html.length == 0) || (html.charAt(html.length-1) != "\n"))
        html += "\n";
    if ((text.length == 0) || (text.charAt(text.length-1) != "\n"))
        text += "\n";

    return "text/html\n"+
           "---------\n"+
           "\n"+
           html+
           "\n"+
           "text/plain\n"+
           "----------\n"+
           "\n"+
           text;
}
<commit_msg>Added a parameter to showRangeAsBrackets() to force the range start and end indicators to be placed in an adjacent text node if one exists<commit_after>function insertAtPosition(position,node)
{
    if (position.node.nodeType == Node.ELEMENT_NODE) {
        if (position.offset == position.node.childNodes.length)
            DOM.appendChild(position.node,node);
        else
            DOM.insertBefore(position.node,node,position.node.childNodes[position.offset]);
    }
    else if (position.node.nodeType == Node.TEXT_NODE) {
        var newText = DOM.createTextNode(document,position.node.nodeValue.slice(position.offset));
        position.node.nodeValue = position.node.nodeValue.slice(0,position.offset);
        DOM.insertBefore(position.node.parentNode,newText,position.node.nextSibling);
        DOM.insertBefore(position.node.parentNode,node,position.node.nextSibling);
    }
}

function insertTextAtPosition(position,str,inText)
{
    if (inText && (position.node.nodeType == Node.ELEMENT_NODE)) {
        var before = position.node.childNodes[position.offset-1];
        var after = position.node.childNodes[position.offset];
        if ((after != null) && (after.nodeType == Node.TEXT_NODE))
            position = new Position(after,0);
        else if ((before != null) && (before.nodeType == Node.TEXT_NODE))
            position = new Position(before,before.nodeValue.length);
    }
    if (position.node.nodeType == Node.ELEMENT_NODE) {
        insertAtPosition(position,DOM.createTextNode(document,str));
    }
    else if (position.node.nodeType == Node.TEXT_NODE) {
        position.node.nodeValue = position.node.nodeValue.slice(0,position.offset) + str +
                                  position.node.nodeValue.slice(position.offset);
    }
}

function showRangeAsBrackets(range,inText)
{
    insertTextAtPosition(range.end,"]",inText);
    insertTextAtPosition(range.start,"[",inText);
}

function removeIds()
{
    recurse(document.body);

    function recurse(node)
    {
        if (node.nodeType == Node.ELEMENT_NODE) {
            node.removeAttribute("id");
            for (var child = node.firstChild; child != null; child = child.nextSibling)
                recurse(child);
        }
    }
}

function selectNode(node)
{
    var offset = DOM.nodeOffset(node);
    Selection.setSelectionRange(new Range(node.parentNode,offset,node.parentNode,offset+1));
}

function removeWhitespaceAndCommentNodes(node)
{
    if (isWhitespaceTextNode(node) || (node.nodeType == Node.COMMENT_NODE)) {
        DOM.deleteNode(node);
    }
    else {
        var next;
        for (var child = node.firstChild; child != null; child = next) {
            next = child.nextSibling;
            removeWhitespaceAndCommentNodes(child);
        }
    }
}

// selectionWrapElement() and selectionUnwrapElement() used to be in formatting.js but have
// now been made obselete by the addition of applyFormattingChanges(). However there are still
// a few tests which use them.
function selectionWrapElement(elementName)
{
    if (elementName == "B")
        Formatting.applyFormattingChanges(null,{"font-weight": "bold"});
    else if (elementName == "I")
        Formatting.applyFormattingChanges(null,{"font-style": "italic"});
    else if (elementName == "U")
        Formatting.applyFormattingChanges(null,{"text-decoration": "underline"});
}

function selectionUnwrapElement(elementName)
{
    if (elementName == "B")
        Formatting.applyFormattingChanges(null,{"font-weight": null});
    else if (elementName == "I")
        Formatting.applyFormattingChanges(null,{"font-style": null});
    else if (elementName == "U")
        Formatting.applyFormattingChanges(null,{"text-decoration": null});
}

function showEmptyTextNodes()
{
    recurse(document);

    function recurse(node)
    {
        if ((node.nodeType == Node.TEXT_NODE) && (node.nodeValue.length == 0))
            node.nodeValue = "*";
        for (var child = node.firstChild; child != null; child = child.nextSibling)
            recurse(child);
    }
}

function showClipboard(clipboard)
{
    var html = clipboard["text/html"];
    var text = clipboard["text/plain"];

    if ((html.length == 0) || (html.charAt(html.length-1) != "\n"))
        html += "\n";
    if ((text.length == 0) || (text.charAt(text.length-1) != "\n"))
        text += "\n";

    return "text/html\n"+
           "---------\n"+
           "\n"+
           html+
           "\n"+
           "text/plain\n"+
           "----------\n"+
           "\n"+
           text;
}
<|endoftext|>