<commit_before>var common = require('./common');

function validateOptions (userOptions) {
    var options = common.copyOptions(userOptions);
    common.ensureFlagExists('ignoreDeclaration', options);
    common.ensureFlagExists('ignoreAttributes', options);
    common.ensureFlagExists('ignoreText', options);
    common.ensureFlagExists('ignoreComment', options);
    common.ensureFlagExists('ignoreCdata', options);
    common.ensureFlagExists('ignoreDoctype', options);
    common.ensureFlagExists('compact', options);
    common.ensureFlagExists('indentText', options);
    common.ensureFlagExists('indentCdata', options);
    common.ensureFlagExists('fullTagEmptyElement', options);
    common.ensureSpacesExists(options);
    if (typeof options.spaces === 'number') {
        options.spaces = Array(options.spaces + 1).join(' ');
    }
    common.ensureKeyExists('declaration', options);
    common.ensureKeyExists('attributes', options);
    common.ensureKeyExists('text', options);
    common.ensureKeyExists('comment', options);
    common.ensureKeyExists('cdata', options);
    common.ensureKeyExists('doctype', options);
    common.ensureKeyExists('type', options);
    common.ensureKeyExists('name', options);
    common.ensureKeyExists('elements', options);
    return options;
}

function writeIndentation (options, depth, firstLine) {
    return (!firstLine && options.spaces ? '\n' : '') + Array(depth + 1).join(options.spaces);
}

function writeAttributes (attributes) {
    var key, result = '';
    for (key in attributes) {
        if (attributes.hasOwnProperty(key)) {
            result += ' ' + key + '="' + attributes[key] + '"';
        }
    }
    return result;
}

function writeDeclaration (declaration, options) {
    return '<?xml' + writeAttributes(declaration[options.attributesKey]) + '?>';
}

function writeComment (comment, options) {
    return options.ignoreComment ? '' : '<!--' + comment + '-->';
}

function writeCdata (cdata, options) {
    return options.ignoreCdata ? '' : '<![CDATA[' + cdata + ']]>';
}

function writeDoctype (doctype, options) {
    return options.ignoreDoctype ? '' : '<!DOCTYPE ' + doctype + '>';
}

function writeText (text, options) {
    return options.ignoreText ? '' : text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
}

function hasContent (element, options) {
    var i;
    if (element.elements && element.elements.length) {
        for (i = 0; i < element.elements.length; ++i) {
            switch (element.elements[i][options.typeKey]) {
                case 'text':
                    if (options.indentText) {
                        return true;
                    }
                    break; // skip to next key
                case 'cdata':
                    if (options.indentCdata) {
                        return true;
                    }
                    break; // skip to next key
                case 'doctype':
                case 'comment':
                case 'element':
                    return true;
                default:
                    return true;
            }
        }
    }
    return false;
}

function writeElement (element, options, depth) {
    var xml = '';
    xml += '<' + element.name;
    if (element[options.attributesKey]) {
        xml += writeAttributes(element[options.attributesKey]);
    }
    if (options.fullTagEmptyElement || (element[options.elementsKey] && element[options.elementsKey].length) || (element[options.attributesKey] && element[options.attributesKey]['xml:space'] === 'preserve')) {
        xml += '>';
        if (element[options.elementsKey] && element[options.elementsKey].length) {
            xml += writeElements(element[options.elementsKey], options, depth + 1);
        }
        xml += options.spaces && hasContent(element, options) ? '\n' + Array(depth + 1).join(options.spaces) : '';
        xml += '</' + element.name + '>';
    } else {
        xml += '/>';
    }
    return xml;
}

function writeElements (elements, options, depth, firstLine) {
    return elements.reduce(function (xml, element) {
        var indent = writeIndentation(options, depth, firstLine && !xml);
        switch (element.type) {
            case 'element': return xml + indent + writeElement(element, options, depth);
            case 'comment': return xml + indent + writeComment(element[options.commentKey], options);
            case 'doctype': return xml + indent + writeDoctype(element[options.doctypeKey], options);
            case 'cdata': return xml + (options.indentCdata ? indent : '') + writeCdata(element[options.cdataKey], options);
            case 'text': return xml + (options.indentText ? indent : '') + writeText(element[options.textKey], options);
        }
    }, '');
}

function hasContentCompact (element, options, anyContent) {
    var key;
    for (key in element) {
        if (element.hasOwnProperty(key)) {
            switch (key) {
                case options.parentKey:
                case options.attributesKey:
                    break; // skip to next key
                case options.textKey:
                    if (options.indentText || anyContent) {
                        return true;
                    }
                    break; // skip to next key
                case options.cdataKey:
                    if (options.indentCdata || anyContent) {
                        return true;
                    }
                    break; // skip to next key
                case options.doctypeKey:
                case options.commentKey:
                case options.declarationKey:
                    return true;
                default:
                    return true;
            }
        }
    }
    return false;
}

function writeElementCompact (element, name, options, depth, indent) {
    var xml = '';
    if (name) {
        xml += '<' + name;
        if (element[options.attributesKey]) {
            xml += writeAttributes(element[options.attributesKey]);
        }
        if (options.fullTagEmptyElement || hasContentCompact(element, options, true) || element[options.attributesKey] && element[options.attributesKey]['xml:space'] === 'preserve') {
            xml += '>';
        } else {
            xml += '/>';
            return xml;
        }
    }
    xml += writeElementsCompact(element, options, depth + 1, false);
    if (name) {
        xml += (indent ? writeIndentation(options, depth, false) : '') + '</' + name + '>';
    }
    return xml;
}

function writeElementsCompact (element, options, depth, firstLine) {
    var i, key, nodes, xml = '';
    for (key in element) {
        if (element.hasOwnProperty(key)) {
            nodes = element[key] instanceof Array ? element[key] : [element[key]];
            for (i = 0; i < nodes.length; ++i) {
                switch (key) {
                    case options.declarationKey: xml += writeDeclaration(nodes[i], options); break;
                    case options.attributesKey: case options.parentKey: break; // skip
                    case options.textKey: xml += (options.indentText ? writeIndentation(options, depth, firstLine) : '') + writeText(nodes[i], options); break;
                    case options.cdataKey: xml += (options.indentCdata ? writeIndentation(options, depth, firstLine) : '') + writeCdata(nodes[i], options); break;
                    case options.doctypeKey: xml += writeIndentation(options, depth, firstLine) + writeDoctype(nodes[i], options); break;
                    case options.commentKey: xml += writeIndentation(options, depth, firstLine) + writeComment(nodes[i], options); break;
                    default: xml += writeIndentation(options, depth, firstLine) + writeElementCompact(nodes[i], key, options, depth, hasContentCompact(nodes[i], options));
                }
                firstLine = firstLine && !xml;
            }
        }
    }
    return xml;
}

module.exports = function (js, options) {
    'use strict';
    options = validateOptions(options);
    var xml = '';
    if (options.compact) {
        xml = writeElementsCompact(js, options, 0, true);
    } else {
        if (js[options.declarationKey]) {
            xml += writeDeclaration(js[options.declarationKey], options);
        }
        if (js[options.elementsKey] && js[options.elementsKey].length) {
            xml += writeElements(js[options.elementsKey], options, 0, !xml);
        }
    }
    return xml;
};
<commit_msg>Update js2xml.js<commit_after>var common = require('./common');

function validateOptions(userOptions) {
    var options = common.copyOptions(userOptions);
    common.ensureFlagExists('ignoreDeclaration', options);
    common.ensureFlagExists('ignoreAttributes', options);
    common.ensureFlagExists('ignoreText', options);
    common.ensureFlagExists('ignoreComment', options);
    common.ensureFlagExists('ignoreCdata', options);
    common.ensureFlagExists('ignoreDoctype', options);
    common.ensureFlagExists('compact', options);
    common.ensureFlagExists('indentText', options);
    common.ensureFlagExists('indentCdata', options);
    common.ensureFlagExists('fullTagEmptyElement', options);
    common.ensureSpacesExists(options);
    if (typeof options.spaces === 'number') {
        options.spaces = Array(options.spaces + 1).join(' ');
    }
    common.ensureKeyExists('declaration', options);
    common.ensureKeyExists('processing', options);
    common.ensureKeyExists('attributes', options);
    common.ensureKeyExists('text', options);
    common.ensureKeyExists('comment', options);
    common.ensureKeyExists('cdata', options);
    common.ensureKeyExists('doctype', options);
    common.ensureKeyExists('type', options);
    common.ensureKeyExists('name', options);
    common.ensureKeyExists('elements', options);
    return options;
}

function writeIndentation(options, depth, firstLine) {
    return (!firstLine && options.spaces ? '\n' : '') + Array(depth + 1).join(options.spaces);
}

function writeAttributes(attributes) {
    var key, result = '';
    for (key in attributes) {
        if (attributes.hasOwnProperty(key)) {
            result += ' ' + key + '="' + attributes[key] + '"';
        }
    }
    return result;
}
function writeProcessingInstruction(name, declaration, options) {
    return '<?' + (name || declaration[options.nameKey]) + writeAttributes(declaration[options.attributesKey]) + '?>';
}
// function writeDeclaration(declaration, options) {
//     return '<?xml' + writeAttributes(declaration[options.attributesKey]) + '?>';
// }

function writeComment(comment, options) {
    return options.ignoreComment ? '' : '<!--' + comment + '-->';
}

function writeCdata(cdata, options) {
    return options.ignoreCdata ? '' : '<![CDATA[' + cdata + ']]>';
}

function writeDoctype(doctype, options) {
    return options.ignoreDoctype ? '' : '<!DOCTYPE ' + doctype + '>';
}

function writeText(text, options) {
    return options.ignoreText ? '' : text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
}

function hasContent(element, options) {
    var i;
    if (element.elements && element.elements.length) {
        for (i = 0; i < element.elements.length; ++i) {
            switch (element.elements[i][options.typeKey]) {
                case 'text':
                    if (options.indentText) {
                        return true;
                    }
                    break; // skip to next key
                case 'cdata':
                    if (options.indentCdata) {
                        return true;
                    }
                    break; // skip to next key
                case 'doctype':
                case 'comment':
                case 'element':
                    return true;
                default:
                    return true;
            }
        }
    }
    return false;
}

function writeElement(element, options, depth) {
    var xml = '';
    xml += '<' + element.name;
    if (element[options.attributesKey]) {
        xml += writeAttributes(element[options.attributesKey]);
    }
    if (options.fullTagEmptyElement || (element[options.elementsKey] && element[options.elementsKey].length) || (element[options.attributesKey] && element[options.attributesKey]['xml:space'] === 'preserve')) {
        xml += '>';
        if (element[options.elementsKey] && element[options.elementsKey].length) {
            xml += writeElements(element[options.elementsKey], options, depth + 1);
        }
        xml += options.spaces && hasContent(element, options) ? '\n' + Array(depth + 1).join(options.spaces) : '';
        xml += '</' + element.name + '>';
    } else {
        xml += '/>';
    }
    return xml;
}

function writeElements(elements, options, depth, firstLine) {
    return elements.reduce(function (xml, element) {
        var indent = writeIndentation(options, depth, firstLine && !xml);
        switch (element.type) {
            case 'element': return xml + indent + writeElement(element, options, depth);
            case 'comment': return xml + indent + writeComment(element[options.commentKey], options);
            case 'doctype': return xml + indent + writeDoctype(element[options.doctypeKey], options);
            case 'cdata': return xml + (options.indentCdata ? indent : '') + writeCdata(element[options.cdataKey], options);
            case 'text': return xml + (options.indentText ? indent : '') + writeText(element[options.textKey], options);
        }
    }, '');
}

function hasContentCompact(element, options, anyContent) {
    var key;
    for (key in element) {
        if (element.hasOwnProperty(key)) {
            switch (key) {
                case options.parentKey:
                case options.attributesKey:
                    break; // skip to next key
                case options.textKey:
                    if (options.indentText || anyContent) {
                        return true;
                    }
                    break; // skip to next key
                case options.cdataKey:
                    if (options.indentCdata || anyContent) {
                        return true;
                    }
                    break; // skip to next key
                case options.doctypeKey:
                case options.commentKey:
                case options.declarationKey:
                    return true;
                default:
                    return true;
            }
        }
    }
    return false;
}

function writeElementCompact(element, name, options, depth, indent) {
    var xml = '';
    if (name) {
        xml += '<' + name;
        if (element[options.attributesKey]) {
            xml += writeAttributes(element[options.attributesKey]);
        }
        if (options.fullTagEmptyElement || hasContentCompact(element, options, true) || element[options.attributesKey] && element[options.attributesKey]['xml:space'] === 'preserve') {
            xml += '>';
        } else {
            xml += '/>';
            return xml;
        }
    }
    xml += writeElementsCompact(element, options, depth + 1, false);
    if (name) {
        xml += (indent ? writeIndentation(options, depth, false) : '') + '</' + name + '>';
    }
    return xml;
}

function writeElementsCompact(element, options, depth, firstLine) {
    var i, key, nodes, xml = '';
    for (key in element) {
        if (element.hasOwnProperty(key)) {
            nodes = element[key] instanceof Array ? element[key] : [element[key]];
            for (i = 0; i < nodes.length; ++i) {
                switch (key) {
                    case options.declarationKey: xml += writeDeclaration(nodes[i], options); break;
                    case options.attributesKey: case options.parentKey: break; // skip
                    case options.textKey: xml += (options.indentText ? writeIndentation(options, depth, firstLine) : '') + writeText(nodes[i], options); break;
                    case options.cdataKey: xml += (options.indentCdata ? writeIndentation(options, depth, firstLine) : '') + writeCdata(nodes[i], options); break;
                    case options.doctypeKey: xml += writeIndentation(options, depth, firstLine) + writeDoctype(nodes[i], options); break;
                    case options.commentKey: xml += writeIndentation(options, depth, firstLine) + writeComment(nodes[i], options); break;
                    default: xml += writeIndentation(options, depth, firstLine) + writeElementCompact(nodes[i], key, options, depth, hasContentCompact(nodes[i], options));
                }
                firstLine = firstLine && !xml;
            }
        }
    }
    return xml;
}

module.exports = function (js, options) {
    'use strict';
    options = validateOptions(options);
    var xml = '';
    if (options.compact) {
        xml = writeElementsCompact(js, options, 0, true);
    } else {
        if (js[options.declarationKey]) {
            xml += writeProcessingInstruction('xml', js[options.declarationKey], options);
        }
        if (js[options.processingKey]) {
            js[options.processingKey].forEach(e => {
                xml += writeProcessingInstruction(e.name, e, options);
            })
        }
        if (js[options.elementsKey] && js[options.elementsKey].length) {
            xml += writeElements(js[options.elementsKey], options, 0, !xml);
        }
    }
    return xml;
};
<|endoftext|>


<commit_before>/*
  ~  Copyright 2016 Ripple Foundation C.I.C. Ltd
  ~
  ~  Licensed under the Apache License, Version 2.0 (the "License");
  ~  you may not use this file except in compliance with the License.
  ~  You may obtain a copy of the License at
  ~
  ~    http://www.apache.org/licenses/LICENSE-2.0

  ~  Unless required by applicable law or agreed to in writing, software
  ~  distributed under the License is distributed on an "AS IS" BASIS,
  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~  See the License for the specific language governing permissions and
  ~  limitations under the License.
*/
let templatePatients = require('./patients-list.html');

class PatientsController {
  constructor($scope, $state, $stateParams, $location, $ngRedux, patientsActions, serviceRequests, Patient, serviceFormatted, $timeout, $uibModal, ConfirmationDocsModal) {
    let vm = this;

    serviceRequests.publisher('routeState', {state: $state.router.globals.current.views, breadcrumbs: $state.router.globals.current.breadcrumbs, name: 'patients-list'});
    serviceRequests.publisher('headerTitle', {title: 'Patients Lists', isShowTitle: true});

    $scope.patientsTable = serviceRequests.patientsTable || {
      info: {
        title: 'PATIENT INFO',
        settings: {
          name: {
            select: true,
            title: 'Name',
            disabled: true,
            width: 150
          },
          address: {
            select: true,
            title: 'Address',
            width: 300
          },
          dateOfBirth: {
            select: true,
            title: 'Born',
            disabled: true,
            width: 105
          },
          gender: {
            select: true,
            title: 'Gender',
            disabled: true,
            width: 90
          },
          nhsNumber: {
            select: true,
            title: 'NHS No.',
            width: 115
          }
        }
      },
      date: {
        title: 'DATE / TIME',
        settings: {
          orders: {
            select: false,
            title: 'Orders',
            width: 110
          },
          results: {
            select: false,
            title: 'Results',
            width: 110
          },
          vitals: {
            select: false,
            title: 'Vitals',
            width: 110
          },
          diagnosis: {
            select: false,
            title: 'Diagnosis',
            width: 130
          }
        }
      },
      count: {
        title: 'COUNT',
        settings: {
          orders: {
            select: false,
            title: 'Orders',
            width: 100
          },
          results: {
            select: false,
            title: 'Results',
            width: 100
          },
          vitals: {
            select: false,
            title: 'Vitals',
            width: 100
          },
          diagnosis: {
            select: false,
            title: 'Diagnosis',
            width: 120
          }
        }
      }
    };
    $scope.patientsTableSettings = {};

    if (serviceRequests.patientsTable) {
      serviceRequests.patientsTable = $scope.patientsTable;
    }

    $scope.changeTableSettings = function () {
      serviceRequests.patientsTable = $scope.patientsTable;
      $scope.resizeFixedTables();
    };

    $scope.hoveredTableRow = -1;
    $scope.hoverTableRow = function (index) {
      $scope.hoveredTableRow = index;
    };
    $scope.unHoverTableRow = function () {
      $scope.hoveredTableRow = -1;
    };
    $scope.getHoveredTableRow = function (index) {
      return $scope.hoveredTableRow == index;
    };

    $scope.getpatientsTableSettings = function () {
      var newSettings = {};
      for (var key in $scope.patientsTable.info.settings) {
        newSettings[key] = $scope.patientsTable.info.settings[key];
        newSettings[key].type = 'info';
      }
      for (var key in $scope.patientsTable.date.settings) {
        newSettings[key + 'Date'] = $scope.patientsTable.date.settings[key];
        newSettings[key + 'Date'].type = 'date';
        newSettings[key + 'Count'] = $scope.patientsTable.count.settings[key];
        newSettings[key + 'Count'].type = 'count';
      }
      $scope.patientsTableSettings = newSettings;
    };
    $scope.getpatientsTableSettings();

    $scope.resizeFixedTables = function () {
      $timeout(function () {
        var $wrapTables = $('.wrap-patients-table');

        var $tableNames = $wrapTables.find('.table-patients-name');
        var $tableNamesRows = $tableNames.find('tr');

        var $tableControls = $wrapTables.find('.table-patients-controls');
        var $tableControlsRows = $tableControls.find('tr');

        var $tableFullRows = $('.table-patients-full tr');
        var $tds = $tableFullRows.eq(1).find('td');

        $tableNames.width($tds.eq(0).outerWidth() + 1);
        $tableControls.width($tds.eq($tds.length - 1).outerWidth());
        $tableFullRows.each(function (i, row, rows) {
          var height = $(row).height();
          $tableNamesRows.eq(i).height(height);
          $tableControlsRows.eq(i).height(height);
        });
      });
    };

    $scope.selectAllSettings = function (key) {
      var settings = $scope.patientsTable[key].settings;
      var isSelectAll = true;

      for (var item in settings) {
        if (settings[item].select === false) {
          isSelectAll = false;
          break;
        }
      }

      for (var item in settings) {
        if (!settings[item].disabled) {
          settings[item].select = !isSelectAll;
        }
      }

      $scope.resizeFixedTables();
    };

    vm.patientFilter = function (patient) {
      if (vm.filters.department) {
        return (patient.department === vm.filters.department);
      }

      if (vm.filters.ageRange) {
        return (patient.ageRange === vm.filters.ageRange);
      }

      return true;
    };

    vm.setPatients = function (patients) {
      var curPatients = [];

      angular.forEach(patients, function (patient) {
        var curPatient = new Patient.patient(patient);
        curPatients.push(curPatient);
      });

      vm.patients = curPatients.slice();
      serviceFormatted.formattingTablesDate(vm.patients, ['dateOfBirth'], serviceFormatted.formatCollection.DDMMMYYYY);
      serviceFormatted.filteringKeys = ['name', 'address', 'dateOfBirth', 'gender', 'nhsNumber'];

      $scope.resizeFixedTables();
    };
    $(window).on('resize', function () {
      $scope.resizeFixedTables();
    });

    vm.openModal = function (patient, state) {
      ConfirmationDocsModal.openModal(patient, state);
    };

    if ($stateParams.patientsList.length === 0 && !$stateParams.displayEmptyTable) {
      vm.filters = {
        department: $stateParams.department,
        ageRange: $stateParams.ageRange
      };

      let unsubscribe = $ngRedux.connect(state => ({
        isFetching: state.patients.isFetching,
        error: state.patients.error,
        // patients: state.patients.data,
        getPatients: vm.setPatients(state.patients.data)
      }))(this);

      $scope.$on('$destroy', unsubscribe);

      this.loadPatientsList = patientsActions.loadPatients;
      this.loadPatientsList();
    } else {
      // vm.patients = $stateParams.patientsList;
      vm.filters = {
        advancedSearch: true,
        advancedSearchParams: $stateParams.advancedSearchParams
      };
      vm.setPatients($stateParams.patientsList);
      $location.url($location.path());
    }
  }
}

const PatientsComponent = {
  template: templatePatients,
  controller: PatientsController
};

PatientsController.$inject = ['$scope', '$state', '$stateParams', '$location', '$ngRedux', 'patientsActions', 'serviceRequests', 'Patient', 'serviceFormatted', '$timeout', '$uibModal', 'ConfirmationDocsModal'];
export default PatientsComponent;<commit_msg>Fixes transition on patient<commit_after>/*
  ~  Copyright 2016 Ripple Foundation C.I.C. Ltd
  ~
  ~  Licensed under the Apache License, Version 2.0 (the "License");
  ~  you may not use this file except in compliance with the License.
  ~  You may obtain a copy of the License at
  ~
  ~    http://www.apache.org/licenses/LICENSE-2.0

  ~  Unless required by applicable law or agreed to in writing, software
  ~  distributed under the License is distributed on an "AS IS" BASIS,
  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~  See the License for the specific language governing permissions and
  ~  limitations under the License.
*/
let templatePatients = require('./patients-list.html');

class PatientsController {
  constructor($scope, $state, $stateParams, $location, $ngRedux, patientsActions, serviceRequests, Patient, serviceFormatted, $timeout, $uibModal, ConfirmationModal) {
    let vm = this;

    serviceRequests.publisher('routeState', {state: $state.router.globals.current.views, breadcrumbs: $state.router.globals.current.breadcrumbs, name: 'patients-list'});
    serviceRequests.publisher('headerTitle', {title: 'Patients Lists', isShowTitle: true});

    $scope.patientsTable = serviceRequests.patientsTable || {
      info: {
        title: 'PATIENT INFO',
        settings: {
          name: {
            select: true,
            title: 'Name',
            disabled: true,
            width: 150
          },
          address: {
            select: true,
            title: 'Address',
            width: 300
          },
          dateOfBirth: {
            select: true,
            title: 'Born',
            disabled: true,
            width: 105
          },
          gender: {
            select: true,
            title: 'Gender',
            disabled: true,
            width: 90
          },
          nhsNumber: {
            select: true,
            title: 'NHS No.',
            width: 115
          }
        }
      },
      date: {
        title: 'DATE / TIME',
        settings: {
          orders: {
            select: false,
            title: 'Orders',
            width: 110
          },
          results: {
            select: false,
            title: 'Results',
            width: 110
          },
          vitals: {
            select: false,
            title: 'Vitals',
            width: 110
          },
          diagnosis: {
            select: false,
            title: 'Diagnosis',
            width: 130
          }
        }
      },
      count: {
        title: 'COUNT',
        settings: {
          orders: {
            select: false,
            title: 'Orders',
            width: 100
          },
          results: {
            select: false,
            title: 'Results',
            width: 100
          },
          vitals: {
            select: false,
            title: 'Vitals',
            width: 100
          },
          diagnosis: {
            select: false,
            title: 'Diagnosis',
            width: 120
          }
        }
      }
    };
    $scope.patientsTableSettings = {};

    if (serviceRequests.patientsTable) {
      serviceRequests.patientsTable = $scope.patientsTable;
    }

    $scope.changeTableSettings = function () {
      serviceRequests.patientsTable = $scope.patientsTable;
      $scope.resizeFixedTables();
    };

    $scope.hoveredTableRow = -1;
    $scope.hoverTableRow = function (index) {
      $scope.hoveredTableRow = index;
    };
    $scope.unHoverTableRow = function () {
      $scope.hoveredTableRow = -1;
    };
    $scope.getHoveredTableRow = function (index) {
      return $scope.hoveredTableRow == index;
    };

    $scope.getpatientsTableSettings = function () {
      var newSettings = {};
      for (var key in $scope.patientsTable.info.settings) {
        newSettings[key] = $scope.patientsTable.info.settings[key];
        newSettings[key].type = 'info';
      }
      for (var key in $scope.patientsTable.date.settings) {
        newSettings[key + 'Date'] = $scope.patientsTable.date.settings[key];
        newSettings[key + 'Date'].type = 'date';
        newSettings[key + 'Count'] = $scope.patientsTable.count.settings[key];
        newSettings[key + 'Count'].type = 'count';
      }
      $scope.patientsTableSettings = newSettings;
    };
    $scope.getpatientsTableSettings();

    $scope.resizeFixedTables = function () {
      $timeout(function () {
        var $wrapTables = $('.wrap-patients-table');

        var $tableNames = $wrapTables.find('.table-patients-name');
        var $tableNamesRows = $tableNames.find('tr');

        var $tableControls = $wrapTables.find('.table-patients-controls');
        var $tableControlsRows = $tableControls.find('tr');

        var $tableFullRows = $('.table-patients-full tr');
        var $tds = $tableFullRows.eq(1).find('td');

        $tableNames.width($tds.eq(0).outerWidth() + 1);
        $tableControls.width($tds.eq($tds.length - 1).outerWidth());
        $tableFullRows.each(function (i, row, rows) {
          var height = $(row).height();
          $tableNamesRows.eq(i).height(height);
          $tableControlsRows.eq(i).height(height);
        });
      });
    };

    $scope.selectAllSettings = function (key) {
      var settings = $scope.patientsTable[key].settings;
      var isSelectAll = true;

      for (var item in settings) {
        if (settings[item].select === false) {
          isSelectAll = false;
          break;
        }
      }

      for (var item in settings) {
        if (!settings[item].disabled) {
          settings[item].select = !isSelectAll;
        }
      }

      $scope.resizeFixedTables();
    };

    vm.patientFilter = function (patient) {
      if (vm.filters.department) {
        return (patient.department === vm.filters.department);
      }

      if (vm.filters.ageRange) {
        return (patient.ageRange === vm.filters.ageRange);
      }

      return true;
    };

    vm.setPatients = function (patients) {
      var curPatients = [];

      angular.forEach(patients, function (patient) {
        var curPatient = new Patient.patient(patient);
        curPatients.push(curPatient);
      });

      vm.patients = curPatients.slice();
      serviceFormatted.formattingTablesDate(vm.patients, ['dateOfBirth'], serviceFormatted.formatCollection.DDMMMYYYY);
      serviceFormatted.filteringKeys = ['name', 'address', 'dateOfBirth', 'gender', 'nhsNumber'];

      $scope.resizeFixedTables();
    };
    $(window).on('resize', function () {
      $scope.resizeFixedTables();
    });

    vm.openModal = function (patient, state) {
      ConfirmationModal.openModal(patient, state);
    };

    if ($stateParams.patientsList.length === 0 && !$stateParams.displayEmptyTable) {
      vm.filters = {
        department: $stateParams.department,
        ageRange: $stateParams.ageRange
      };

      let unsubscribe = $ngRedux.connect(state => ({
        isFetching: state.patients.isFetching,
        error: state.patients.error,
        // patients: state.patients.data,
        getPatients: vm.setPatients(state.patients.data)
      }))(this);

      $scope.$on('$destroy', unsubscribe);

      this.loadPatientsList = patientsActions.loadPatients;
      this.loadPatientsList();
    } else {
      // vm.patients = $stateParams.patientsList;
      vm.filters = {
        advancedSearch: true,
        advancedSearchParams: $stateParams.advancedSearchParams
      };
      vm.setPatients($stateParams.patientsList);
      $location.url($location.path());
    }
  }
}

const PatientsComponent = {
  template: templatePatients,
  controller: PatientsController
};

PatientsController.$inject = ['$scope', '$state', '$stateParams', '$location', '$ngRedux', 'patientsActions', 'serviceRequests', 'Patient', 'serviceFormatted', '$timeout', '$uibModal', 'ConfirmationModal'];
export default PatientsComponent;<|endoftext|>


<commit_before>'use strict';

import React from 'react';
import ReactDOM from 'react-dom';
import {getTrackCSS, getTrackLeft, getTrackAnimateCSS} from './trackHelper';
import assign from 'object-assign';

var helpers = {
  // supposed to start autoplay of slides
  initialize: function (props) {
    const slickList = ReactDOM.findDOMNode(this.list);

    var slideCount = React.Children.count(props.children);
    var listWidth = this.getWidth(slickList);
    var trackWidth = this.getWidth(ReactDOM.findDOMNode(this.track));
    var slideWidth;

    if (!props.vertical) {
      var centerPaddingAdj = props.centerMode && (parseInt(props.centerPadding) * 2);
      if (props.centerPadding.slice(-1) === '%') {
        centerPaddingAdj *= listWidth / 100
      }
      slideWidth = Math.ceil((this.getWidth(ReactDOM.findDOMNode(this)) - centerPaddingAdj)/props.slidesToShow)
    } else {
      slideWidth = Math.ceil(this.getWidth(ReactDOM.findDOMNode(this)))
    }

    const slideHeight = this.getHeight(slickList.querySelector('[data-index="0"]'));
    const listHeight = slideHeight * props.slidesToShow;

    var currentSlide = props.rtl ? slideCount - 1 - props.initialSlide : props.initialSlide;

    this.setState({
      slideCount,
      slideWidth,
      listWidth,
      trackWidth,
      currentSlide,
      slideHeight,
      listHeight,
    }, function () {
      // this reference isn't lost due to mixin
      var targetLeft = getTrackLeft(assign({
        slideIndex: this.state.currentSlide,
        trackRef: this.track
      }, props, this.state));
      // getCSS function needs previously set state
      var trackStyle = getTrackCSS(assign({left: targetLeft}, props, this.state));

      this.setState({trackStyle: trackStyle});

      this.autoPlay(); // once we're set up, trigger the initial autoplay.
    });
  },
  update: function (props) {
    const slickList = ReactDOM.findDOMNode(this.list);
    // This method has mostly same code as initialize method.
    // Refactor it
    var slideCount = React.Children.count(props.children);
    var listWidth = this.getWidth(slickList);
    var trackWidth = this.getWidth(ReactDOM.findDOMNode(this.track));
    var slideWidth;

    if (!props.vertical) {
      var centerPaddingAdj = props.centerMode && (parseInt(props.centerPadding) * 2);
      if (props.centerPadding.slice(-1) === '%') {
        centerPaddingAdj *= listWidth / 100
      }
      slideWidth = Math.ceil((this.getWidth(ReactDOM.findDOMNode(this)) - centerPaddingAdj)/props.slidesToShow)
    } else {
      slideWidth = Math.ceil(this.getWidth(ReactDOM.findDOMNode(this)))
    }

    const slideHeight = this.getHeight(slickList.querySelector('[data-index="0"]'));
    const listHeight = slideHeight * props.slidesToShow;

    // pause slider if autoplay is set to false
    if(!props.autoplay) {
      this.pause();
    } else {
      this.autoPlay();
    }

    this.setState({
      slideCount,
      slideWidth,
      listWidth,
      trackWidth,
      slideHeight,
      listHeight,
    }, function () {

      var targetLeft = getTrackLeft(assign({
        slideIndex: this.state.currentSlide,
        trackRef: this.track
      }, props, this.state));
      // getCSS function needs previously set state
      var trackStyle = getTrackCSS(assign({left: targetLeft}, props, this.state));

      this.setState({trackStyle: trackStyle});
    });
  },
  getWidth: function getWidth(elem) {
    return elem && (elem.getBoundingClientRect().width || elem.offsetWidth) || 0;
  },
  getHeight(elem) {
    return elem && (elem.getBoundingClientRect().height || elem.offsetHeight) || 0;
  },
  adaptHeight: function () {
    if (this.props.adaptiveHeight) {
      var selector = '[data-index="' + this.state.currentSlide +'"]';
      if (this.list) {
        var slickList = ReactDOM.findDOMNode(this.list);
        var elem = slickList.querySelector(selector) || {};
        slickList.style.height = (elem.offsetHeight || 0) + 'px';
      }
    }
  },
  canGoNext: function (opts){
    var canGo = true;
    if (!opts.infinite) {
      if (opts.centerMode) {
        // check if current slide is last slide
        if (opts.currentSlide >= (opts.slideCount - 1)) {
          canGo = false;
        }
      } else {
        // check if all slides are shown in slider
        if (opts.slideCount <= opts.slidesToShow ||
          opts.currentSlide >= (opts.slideCount - opts.slidesToShow)) {
          canGo = false;
        }
      }
    }
    return canGo;
  },
  slideHandler: function (index) {
    // index is target slide index

    // Functionality of animateSlide and postSlide is merged into this function
    var animationTargetSlide, finalTargetSlide;
    var animationTargetLeft, finalTargetLeft;
    var callback;

    if (this.props.waitForAnimate && this.state.animating) {
      return;
    }

    if (this.props.fade) {
      finalTargetSlide = this.state.currentSlide;

      // Don't change slide if infinite=false and target slide is out of range
      if(this.props.infinite === false &&
        (index < 0 || index >= this.state.slideCount)) {
        return;
      }

      //  Shifting animationTargetSlide back into the range
      if (index < 0) {
        animationTargetSlide = index + this.state.slideCount;
      } else if (index >= this.state.slideCount) {
        animationTargetSlide = index - this.state.slideCount;
      } else {
        animationTargetSlide = index;
      }

      if (this.props.lazyLoad && this.state.lazyLoadedList.indexOf(animationTargetSlide) < 0) {
        this.setState({
          lazyLoadedList: this.state.lazyLoadedList.concat(animationTargetSlide)
        });
      }

      callback = () => {
        this.setState({
          animating: false
        });
        if (this.props.afterChange) {
          this.props.afterChange(animationTargetSlide);
        }
        delete this.animationEndCallback;
      };

      this.setState({
        animating: true,
        currentSlide: animationTargetSlide
      }, function () {
        this.animationEndCallback = setTimeout(callback, this.props.speed);
      });

      if (this.props.beforeChange) {
        this.props.beforeChange(this.state.currentSlide, animationTargetSlide);
      }

      this.autoPlay();
      return;
    }

    animationTargetSlide = index;

    /*
      @TODO: Make sure to leave no bug in the code below
      start: critical checkpoint
    */
    if (animationTargetSlide < 0) {
      if(this.props.infinite === false) {
        finalTargetSlide = 0;
      } else if (this.state.slideCount % this.props.slidesToScroll !== 0) {
        finalTargetSlide = this.state.slideCount - (this.state.slideCount % this.props.slidesToScroll);
      } else {
        finalTargetSlide = this.state.slideCount + animationTargetSlide;
      }
    } else if (animationTargetSlide >= this.state.slideCount) {
      if(this.props.infinite === false) {
        finalTargetSlide = this.state.slideCount - this.props.slidesToShow;
      } else if (this.state.slideCount % this.props.slidesToScroll !== 0) {
        finalTargetSlide = 0;
      } else {
        finalTargetSlide = animationTargetSlide - this.state.slideCount;
      }
    // } else if (animationTargetSlide + this.props.slidesToShow >= this.state.slideCount) {
    //   if (this.props.infinite === false) {
    //     finalTargetSlide = this.state.slideCount - this.props.slidesToShow
    //   } else {
    //     if ((this.state.slideCount - animationTargetSlide) % this.props.slidesToScroll !== 0) {
    //       finalTargetSlide = this.state.slideCount - this.props.slidesToShow
    //     } else {
    //       finalTargetSlide = animationTargetSlide
    //     }
    //   }
    } else {
      finalTargetSlide = animationTargetSlide;
    }

    /*
      stop: critical checkpoint
    */

    animationTargetLeft = getTrackLeft(assign({
      slideIndex: animationTargetSlide,
      trackRef: this.track
    }, this.props, this.state));

    finalTargetLeft = getTrackLeft(assign({
      slideIndex: finalTargetSlide,
      trackRef: this.track
    }, this.props, this.state));

    if (this.props.infinite === false) {
      if (animationTargetLeft === finalTargetLeft) {
        animationTargetSlide = finalTargetSlide;
      }
      animationTargetLeft = finalTargetLeft;
    }

    if (this.props.beforeChange) {
      this.props.beforeChange(this.state.currentSlide, finalTargetSlide);
    }

    if (this.props.lazyLoad) {
      var slidesToLoad = [];
      let slideCount = this.state.slideCount
      for (var i = animationTargetSlide; i < animationTargetSlide + this.props.slidesToShow; i++ ) {
        if (this.state.lazyLoadedList.indexOf(i) < 0) {
          slidesToLoad.push(i)
        }
        if (i >= slideCount && this.state.lazyLoadedList.indexOf(i - slideCount) < 0) {
          slidesToLoad.push(i - slideCount)
        }
        if (i < 0 && this.state.lazyLoadedList.indexOf(i + slideCount) < 0) {
          slidesToLoad.push(i + slideCount)
        }
      }
      if (slidesToLoad.length > 0) {
        this.setState({
          lazyLoadedList: this.state.lazyLoadedList.concat(slidesToLoad)
        });
      }
    }

    // Slide Transition happens here.
    // animated transition happens to target Slide and
    // non - animated transition happens to current Slide
    // If CSS transitions are false, directly go the current slide.
    animationTargetSlide = finalTargetSlide
    animationTargetLeft = finalTargetLeft
    if (this.props.useCSS === false) {

      this.setState({
        currentSlide: finalTargetSlide,
        trackStyle: getTrackCSS(assign({left: finalTargetLeft}, this.props, this.state))
      }, function () {
        if (this.props.afterChange) {
          this.props.afterChange(finalTargetSlide);
        }
      });

    } else {

      var nextStateChanges = {
        animating: false,
        currentSlide: finalTargetSlide,
        trackStyle: getTrackCSS(assign({left: finalTargetLeft}, this.props, this.state)),
        swipeLeft: null
      };
      callback = () => {
        this.setState(nextStateChanges, () => {
          if (this.props.afterChange) {
            this.props.afterChange(finalTargetSlide);
          }
          delete this.animationEndCallback;
        });
      };

      this.setState({
        animating: true,
        currentSlide: finalTargetSlide,
        trackStyle: getTrackAnimateCSS(assign({left: animationTargetLeft}, this.props, this.state))
      }, function () {
        this.animationEndCallback = setTimeout(callback, this.props.speed);
      });

    }

    this.autoPlay();
  },
  swipeDirection: function (touchObject) {
    var xDist, yDist, r, swipeAngle;

    xDist = touchObject.startX - touchObject.curX;
    yDist = touchObject.startY - touchObject.curY;
    r = Math.atan2(yDist, xDist);

    swipeAngle = Math.round(r * 180 / Math.PI);
    if (swipeAngle < 0) {
        swipeAngle = 360 - Math.abs(swipeAngle);
    }
    if ((swipeAngle <= 45) && (swipeAngle >= 0) || (swipeAngle <= 360) && (swipeAngle >= 315)) {
        return 'left';
    }
    if ((swipeAngle >= 135) && (swipeAngle <= 225)) {
        return 'right';
    }
    if (this.props.verticalSwiping === true) {
      if ((swipeAngle >= 35) && (swipeAngle <= 135)) {
        return 'down';
      } else {
        return 'up';
      }
    }

    return 'vertical';
  },
  play: function(){
    var nextIndex;

    if (!this.state.mounted) {
      return false
    }

    if (this.props.rtl) {
      nextIndex = this.state.currentSlide - this.props.slidesToScroll;
    } else {
      if (this.canGoNext(Object.assign({}, this.props,this.state))) {
        nextIndex = this.state.currentSlide + this.props.slidesToScroll;
      } else {
        return false;
      }
    }

    this.slideHandler(nextIndex);
  },
  autoPlay: function () {
    if (this.state.autoPlayTimer) {
      clearTimeout(this.state.autoPlayTimer);
    }
    if (this.props.autoplay) {
      this.setState({
        autoPlayTimer: setTimeout(this.play, this.props.autoplaySpeed)
      });
    }
  },
  pause: function () {
    if (this.state.autoPlayTimer) {
      clearTimeout(this.state.autoPlayTimer);
      this.setState({
        autoPlayTimer: null
      });
    }
  }
};

export default helpers;
<commit_msg>modified logic for handling odd/even cases and centermode cases more smoothly<commit_after>'use strict';

import React from 'react';
import ReactDOM from 'react-dom';
import {getTrackCSS, getTrackLeft, getTrackAnimateCSS} from './trackHelper';
import assign from 'object-assign';

var helpers = {
  // supposed to start autoplay of slides
  initialize: function (props) {
    const slickList = ReactDOM.findDOMNode(this.list);

    var slideCount = React.Children.count(props.children);
    var listWidth = this.getWidth(slickList);
    var trackWidth = this.getWidth(ReactDOM.findDOMNode(this.track));
    var slideWidth;

    if (!props.vertical) {
      var centerPaddingAdj = props.centerMode && (parseInt(props.centerPadding) * 2);
      if (props.centerPadding.slice(-1) === '%') {
        centerPaddingAdj *= listWidth / 100
      }
      slideWidth = Math.ceil((this.getWidth(ReactDOM.findDOMNode(this)) - centerPaddingAdj)/props.slidesToShow)
    } else {
      slideWidth = Math.ceil(this.getWidth(ReactDOM.findDOMNode(this)))
    }

    const slideHeight = this.getHeight(slickList.querySelector('[data-index="0"]'));
    const listHeight = slideHeight * props.slidesToShow;

    var currentSlide = props.rtl ? slideCount - 1 - props.initialSlide : props.initialSlide;

    this.setState({
      slideCount,
      slideWidth,
      listWidth,
      trackWidth,
      currentSlide,
      slideHeight,
      listHeight,
    }, function () {
      // this reference isn't lost due to mixin
      var targetLeft = getTrackLeft(assign({
        slideIndex: this.state.currentSlide,
        trackRef: this.track
      }, props, this.state));
      // getCSS function needs previously set state
      var trackStyle = getTrackCSS(assign({left: targetLeft}, props, this.state));

      this.setState({trackStyle: trackStyle});

      this.autoPlay(); // once we're set up, trigger the initial autoplay.
    });
  },
  update: function (props) {
    const slickList = ReactDOM.findDOMNode(this.list);
    // This method has mostly same code as initialize method.
    // Refactor it
    var slideCount = React.Children.count(props.children);
    var listWidth = this.getWidth(slickList);
    var trackWidth = this.getWidth(ReactDOM.findDOMNode(this.track));
    var slideWidth;

    if (!props.vertical) {
      var centerPaddingAdj = props.centerMode && (parseInt(props.centerPadding) * 2);
      if (props.centerPadding.slice(-1) === '%') {
        centerPaddingAdj *= listWidth / 100
      }
      slideWidth = Math.ceil((this.getWidth(ReactDOM.findDOMNode(this)) - centerPaddingAdj)/props.slidesToShow)
    } else {
      slideWidth = Math.ceil(this.getWidth(ReactDOM.findDOMNode(this)))
    }

    const slideHeight = this.getHeight(slickList.querySelector('[data-index="0"]'));
    const listHeight = slideHeight * props.slidesToShow;

    // pause slider if autoplay is set to false
    if(!props.autoplay) {
      this.pause();
    } else {
      this.autoPlay();
    }

    this.setState({
      slideCount,
      slideWidth,
      listWidth,
      trackWidth,
      slideHeight,
      listHeight,
    }, function () {

      var targetLeft = getTrackLeft(assign({
        slideIndex: this.state.currentSlide,
        trackRef: this.track
      }, props, this.state));
      // getCSS function needs previously set state
      var trackStyle = getTrackCSS(assign({left: targetLeft}, props, this.state));

      this.setState({trackStyle: trackStyle});
    });
  },
  getWidth: function getWidth(elem) {
    return elem && (elem.getBoundingClientRect().width || elem.offsetWidth) || 0;
  },
  getHeight(elem) {
    return elem && (elem.getBoundingClientRect().height || elem.offsetHeight) || 0;
  },
  adaptHeight: function () {
    if (this.props.adaptiveHeight) {
      var selector = '[data-index="' + this.state.currentSlide +'"]';
      if (this.list) {
        var slickList = ReactDOM.findDOMNode(this.list);
        var elem = slickList.querySelector(selector) || {};
        slickList.style.height = (elem.offsetHeight || 0) + 'px';
      }
    }
  },
  canGoNext: function (opts){
    var canGo = true;
    if (!opts.infinite) {
      if (opts.centerMode) {
        // check if current slide is last slide
        if (opts.currentSlide >= (opts.slideCount - 1)) {
          canGo = false;
        }
      } else {
        // check if all slides are shown in slider
        if (opts.slideCount <= opts.slidesToShow ||
          opts.currentSlide >= (opts.slideCount - opts.slidesToShow)) {
          canGo = false;
        }
      }
    }
    return canGo;
  },
  slideHandler: function (index) {
    // index is target slide index

    // Functionality of animateSlide and postSlide is merged into this function
    var animationTargetSlide, finalTargetSlide;
    var animationTargetLeft, finalTargetLeft;
    var callback;

    if (this.props.waitForAnimate && this.state.animating) {
      return;
    }

    if (this.props.fade) {
      finalTargetSlide = this.state.currentSlide;

      // Don't change slide if infinite=false and target slide is out of range
      if(this.props.infinite === false &&
        (index < 0 || index >= this.state.slideCount)) {
        return;
      }

      //  Shifting animationTargetSlide back into the range
      if (index < 0) {
        animationTargetSlide = index + this.state.slideCount;
      } else if (index >= this.state.slideCount) {
        animationTargetSlide = index - this.state.slideCount;
      } else {
        animationTargetSlide = index;
      }

      if (this.props.lazyLoad && this.state.lazyLoadedList.indexOf(animationTargetSlide) < 0) {
        this.setState({
          lazyLoadedList: this.state.lazyLoadedList.concat(animationTargetSlide)
        });
      }

      callback = () => {
        this.setState({
          animating: false
        });
        if (this.props.afterChange) {
          this.props.afterChange(animationTargetSlide);
        }
        delete this.animationEndCallback;
      };

      this.setState({
        animating: true,
        currentSlide: animationTargetSlide
      }, function () {
        this.animationEndCallback = setTimeout(callback, this.props.speed);
      });

      if (this.props.beforeChange) {
        this.props.beforeChange(this.state.currentSlide, animationTargetSlide);
      }

      this.autoPlay();
      return;
    }

    animationTargetSlide = index;

    /*
      @TODO: Make sure to leave no bug in the code below
      start: critical checkpoint
    */
    if (animationTargetSlide < 0) {
      if(this.props.infinite === false) {
        finalTargetSlide = 0;
      } else if (this.state.slideCount % this.props.slidesToScroll !== 0) {
        finalTargetSlide = this.state.slideCount - (this.state.slideCount % this.props.slidesToScroll);
      } else {
        finalTargetSlide = this.state.slideCount + animationTargetSlide;
      }
    } else if (this.props.centerMode && animationTargetSlide >= this.state.slideCount) {
      if(this.props.infinite === false) {
        animationTargetSlide = this.state.slideCount - 1
        finalTargetSlide = this.state.slideCount - 1
      } else {
        animationTargetSlide = this.state.slideCount
        finalTargetSlide = 0
      }
    } else if (animationTargetSlide >= this.state.slideCount) {
      if(this.props.infinite === false) {
        finalTargetSlide = this.state.slideCount - this.props.slidesToShow;
      } else if (this.state.slideCount % this.props.slidesToScroll !== 0) {
        finalTargetSlide = 0;
      } else {
        finalTargetSlide = animationTargetSlide - this.state.slideCount;
      }
    } else if (this.state.currentSlide + this.slidesToShow < this.state.slideCount && animationTargetSlide + this.props.slidesToShow >= this.state.slideCount) {
      if (this.props.infinite === false) {
        finalTargetSlide = this.state.slideCount - this.props.slidesToShow
      } else {
        if ((this.state.slideCount - animationTargetSlide) % this.props.slidesToScroll !== 0) {
          finalTargetSlide = this.state.slideCount - this.props.slidesToShow
        } else {
          finalTargetSlide = animationTargetSlide
        }
      }
    } else {
      finalTargetSlide = animationTargetSlide;
    }

    /*
      stop: critical checkpoint
    */

    animationTargetLeft = getTrackLeft(assign({
      slideIndex: animationTargetSlide,
      trackRef: this.track
    }, this.props, this.state));

    finalTargetLeft = getTrackLeft(assign({
      slideIndex: finalTargetSlide,
      trackRef: this.track
    }, this.props, this.state));

    if (this.props.infinite === false) {
      if (animationTargetLeft === finalTargetLeft) {
        animationTargetSlide = finalTargetSlide;
      }
      animationTargetLeft = finalTargetLeft;
    }

    if (this.props.beforeChange) {
      this.props.beforeChange(this.state.currentSlide, finalTargetSlide);
    }

    if (this.props.lazyLoad) {
      var slidesToLoad = [];
      let slideCount = this.state.slideCount
      for (var i = animationTargetSlide; i < animationTargetSlide + this.props.slidesToShow; i++ ) {
        if (this.state.lazyLoadedList.indexOf(i) < 0) {
          slidesToLoad.push(i)
        }
        if (i >= slideCount && this.state.lazyLoadedList.indexOf(i - slideCount) < 0) {
          slidesToLoad.push(i - slideCount)
        }
        if (i < 0 && this.state.lazyLoadedList.indexOf(i + slideCount) < 0) {
          slidesToLoad.push(i + slideCount)
        }
      }
      if (slidesToLoad.length > 0) {
        this.setState({
          lazyLoadedList: this.state.lazyLoadedList.concat(slidesToLoad)
        });
      }
    }

    // Slide Transition happens here.
    // animated transition happens to target Slide and
    // non - animated transition happens to current Slide
    // If CSS transitions are false, directly go the current slide.

    if (this.props.useCSS === false) {
      this.setState({
        currentSlide: finalTargetSlide,
        trackStyle: getTrackCSS(assign({left: finalTargetLeft}, this.props, this.state))
      }, function () {
        if (this.props.afterChange) {
          this.props.afterChange(finalTargetSlide);
        }
      });

    } else {

      var nextStateChanges = {
        animating: false,
        currentSlide: finalTargetSlide,
        trackStyle: getTrackCSS(assign({left: finalTargetLeft}, this.props, this.state)),
        swipeLeft: null
      };
      callback = () => {
        this.setState(nextStateChanges, () => {
          if (this.props.afterChange) {
            this.props.afterChange(finalTargetSlide);
          }
          delete this.animationEndCallback;
        });
      };

      this.setState({
        animating: true,
        currentSlide: finalTargetSlide,
        trackStyle: getTrackAnimateCSS(assign({left: animationTargetLeft}, this.props, this.state))
      }, function () {
        this.animationEndCallback = setTimeout(callback, this.props.speed);
      });

    }

    this.autoPlay();
  },
  swipeDirection: function (touchObject) {
    var xDist, yDist, r, swipeAngle;

    xDist = touchObject.startX - touchObject.curX;
    yDist = touchObject.startY - touchObject.curY;
    r = Math.atan2(yDist, xDist);

    swipeAngle = Math.round(r * 180 / Math.PI);
    if (swipeAngle < 0) {
        swipeAngle = 360 - Math.abs(swipeAngle);
    }
    if ((swipeAngle <= 45) && (swipeAngle >= 0) || (swipeAngle <= 360) && (swipeAngle >= 315)) {
        return 'left';
    }
    if ((swipeAngle >= 135) && (swipeAngle <= 225)) {
        return 'right';
    }
    if (this.props.verticalSwiping === true) {
      if ((swipeAngle >= 35) && (swipeAngle <= 135)) {
        return 'down';
      } else {
        return 'up';
      }
    }

    return 'vertical';
  },
  play: function(){
    var nextIndex;

    if (!this.state.mounted) {
      return false
    }

    if (this.props.rtl) {
      nextIndex = this.state.currentSlide - this.props.slidesToScroll;
    } else {
      if (this.canGoNext(Object.assign({}, this.props,this.state))) {
        nextIndex = this.state.currentSlide + this.props.slidesToScroll;
      } else {
        return false;
      }
    }

    this.slideHandler(nextIndex);
  },
  autoPlay: function () {
    if (this.state.autoPlayTimer) {
      clearTimeout(this.state.autoPlayTimer);
    }
    if (this.props.autoplay) {
      this.setState({
        autoPlayTimer: setTimeout(this.play, this.props.autoplaySpeed)
      });
    }
  },
  pause: function () {
    if (this.state.autoPlayTimer) {
      clearTimeout(this.state.autoPlayTimer);
      this.setState({
        autoPlayTimer: null
      });
    }
  }
};

export default helpers;
<|endoftext|>


<commit_before>var http = Npm.require('http');
var hostname = Npm.require('os').hostname();
var logger = Npm.require('debug')('kadira:apm');
var Fibers = Npm.require('fibers');

Kadira = {};
Kadira.models = {};
Kadira.options = {};
Kadira.env = {
  currentSub: null, // keep current subscription inside ddp
  kadiraInfo: new Meteor.EnvironmentVariable(),
};

Kadira.connect = function(appId, appSecret, options) {
  options = options || {};
  options.appId = appId;
  options.payloadTimeout = options.payloadTimeout || 1000 * 20;
  options.endpoint = options.endpoint || "https://engine.kadira.io";
  options.thresholds = options.thresholds || {};

  Kadira.options = options;
  Kadira.syncedDate = new Ntp(options.endpoint);
  Kadira.syncedDate.sync();
  Kadira.models.methods = new MethodsModel(options.thresholds.methods);
  Kadira.models.pubsub = new PubsubModel();
  Kadira.models.system = new SystemModel();
  Kadira.models.error = new ErrorModel(appId);
  Kadira.sendPayload = sendPayload;

  // setting runtime info, which will be sent to kadira
  __meteor_runtime_config__.kadira = {
    appId: appId,
    endpoint: options.endpoint
  };

  if(canTrackErrors()) {
    Kadira.enableErrorTracking();
  } else {
    Kadira.disableErrorTracking();
  }

  //track how many times we've sent the data
  var countDataSent = 0;
  var detailInfoSentInterval = Math.ceil((1000 * 60) / options.payloadTimeout); //once per min

  if(appId && appSecret) {
    appId = appId.trim();
    appSecret = appSecret.trim();

    pingToCheckAuth(function(){
      schedulePayloadSend();
    });
    logger('connected to app: ', appId);
  } else {
    throw new Error('Kadira: required appId and appSecret');
  }

  //start wrapping Meteor's internal methods
  Kadira._startInstrumenting(function() {
    console.log('Kadira: completed instrumenting the app')
    Kadira.connected = true;
  });

  var payloadRetries = 0;
  var payloadRetry = new Retry({
      minCount: 0, // don't do any immediate payloadRetries
      baseTimeout: 5*1000,
      maxTimeout: 60000
  });

  function sendPayload(callback) {

    callHTTP();

    function callHTTP() {
      new Fibers(function() {
        var payload = buildPayload();
        var headers = buildHeaders();
        var httpOptions = {headers: headers, data: payload};

        try {
          var response = HTTP.call('POST', options.endpoint, httpOptions);
          processResponse(response);
        } catch(err) {
          tryAgain(err);
        }
      }).run();
    }

    function processResponse(response) {
      if(response.statusCode == '401') {
        throw new Error('Kadira: AppId, AppSecret combination is invalid');
      } else if(response.statusCode == '200') {
        //success send again in 10 secs
        schedulePayloadSend();
        if(payloadRetries > 0) {
          logger('connected again and payload sent.')
        }
        cleaPayloadRetry();
        callback && callback();
      } else {
        tryAgain();
      }
    }

    function tryAgain(err) {
      err = err || {};
      logger('retrying to send payload to server')
      if(++payloadRetries < 5) {
        payloadRetry.retryLater(payloadRetries, callHTTP);
      } else {
        console.error('Kadira: Error sending payload(dropped after 5 tries) ', err.message);
        cleaPayloadRetry();
        schedulePayloadSend();
      }
    }

  }

  function cleaPayloadRetry() {
    payloadRetries = 0;
    payloadRetry.clear();
  }

  function buildHeaders(){
    return {'APM-APP-ID': appId, 'APM-APP-SECRET': appSecret}
  }

  function schedulePayloadSend() {
    setTimeout(sendPayload, options.payloadTimeout);
  }

  function canTrackErrors () {
    if(Kadira.options.enableErrorTracking === undefined) {
      return true;
    } else {
      return Kadira.options.enableErrorTracking;
    }
  }

  var authCheckFailures = 0;
  function pingToCheckAuth(callback){
    var httpOptions = {headers: buildHeaders(), data: {}};
    var endpoint = options.endpoint + '/ping'

    new Fibers(function() {
      HTTP.call('POST', endpoint, httpOptions, function(err, response){
        if(response) {
          if(response.statusCode == 200) {
            console.log('Kadira: successfully authenticated');
            authRetry.clear();
            callback();
          } else if(response.statusCode == 401) {
            console.error('Kadira: authenticatation failed - check your appId & appSecret')
          } else {
            retryPingToCheckAuth(callback);
          }
        } else {
          retryPingToCheckAuth();
        }
      });
    }).run();

    var authRetry = new Retry({
      minCount: 0, // don't do any immediate retries
      baseTimeout: 5*1000 // start with 30s
    });

    function retryPingToCheckAuth(){
      console.log('Kadira: retrying to authenticate');
      authRetry.retryLater(authCheckFailures, function(){
        pingToCheckAuth(callback)
      });
    }
  }

  function buildPayload() {
    var payload = {host: hostname};
    var buildDetailedInfo = (countDataSent++ % detailInfoSentInterval) == 0;
    _.extend(payload, Kadira.models.methods.buildPayload(buildDetailedInfo));
    _.extend(payload, Kadira.models.pubsub.buildPayload(buildDetailedInfo));
    _.extend(payload, Kadira.models.system.buildPayload());
    if(options.enableErrorTracking) {
      _.extend(payload, Kadira.models.error.buildPayload());
    }

    return payload;
  }
};

// this return the __kadiraInfo from the current Fiber by default
// if called with 2nd argument as true, it will get the kadira info from
// Meteor.EnvironmentVariable
//
// WARNNING: retunred info object is the reference object.
//  Changing it might cause issues when building traces. So use with care
Kadira._getInfo = function(currentFiber, useEnvironmentVariable) {
  currentFiber = currentFiber || Fibers.current;
  if(currentFiber) {
    if(useEnvironmentVariable) {
      return Kadira.env.kadiraInfo.get();
    }
    return currentFiber.__kadiraInfo;
  }
};

// this does not clone the info object. So, use with care
Kadira._setInfo = function(info) {
  Fibers.current.__kadiraInfo = info;
  var kadiraInfo = Kadira.env.kadiraInfo.get();
};

Kadira.enableErrorTracking = function () {
  __meteor_runtime_config__.kadira.enableErrorTracking = true;
  Kadira.options.enableErrorTracking = true;
};

Kadira.disableErrorTracking = function () {
  __meteor_runtime_config__.kadira.enableErrorTracking = false;
  Kadira.options.enableErrorTracking = false;
};

Kadira.trackError = function (type, message, options) {
  if(Kadira.options.enableErrorTracking && type && message) {
    options = options || {};
    options.subType = options.subType || 'server';
    options.stacks = options.stacks || '';
    var error = {message: message, stack: options.stacks};
    var trace = {
      type: type,
      subType: options.subType,
      name: message,
      errored: true,
      at: Kadira.syncedDate.getTime(),
      events: [['start', 0, {}], ['error', 0, {error: error}]],
      metrics: {total: 0}
    };
    Kadira.models.error.trackError(error, trace);
  }
}
<commit_msg>Remove trailing slash from endpoint<commit_after>var http = Npm.require('http');
var hostname = Npm.require('os').hostname();
var logger = Npm.require('debug')('kadira:apm');
var Fibers = Npm.require('fibers');

Kadira = {};
Kadira.models = {};
Kadira.options = {};
Kadira.env = {
  currentSub: null, // keep current subscription inside ddp
  kadiraInfo: new Meteor.EnvironmentVariable(),
};

Kadira.connect = function(appId, appSecret, options) {
  options = options || {};
  options.appId = appId;
  options.payloadTimeout = options.payloadTimeout || 1000 * 20;
  options.endpoint = options.endpoint || "https://engine.kadira.io";
  options.thresholds = options.thresholds || {};

  // remove trailing slash from endpoint url (if any)
  if(_.last(options.endpoint) === '/') {
    options.endpoint = options.endpoint.substr(0, options.endpoint.length - 1);
  }

  Kadira.options = options;
  Kadira.syncedDate = new Ntp(options.endpoint);
  Kadira.syncedDate.sync();
  Kadira.models.methods = new MethodsModel(options.thresholds.methods);
  Kadira.models.pubsub = new PubsubModel();
  Kadira.models.system = new SystemModel();
  Kadira.models.error = new ErrorModel(appId);
  Kadira.sendPayload = sendPayload;

  // setting runtime info, which will be sent to kadira
  __meteor_runtime_config__.kadira = {
    appId: appId,
    endpoint: options.endpoint
  };

  if(canTrackErrors()) {
    Kadira.enableErrorTracking();
  } else {
    Kadira.disableErrorTracking();
  }

  //track how many times we've sent the data
  var countDataSent = 0;
  var detailInfoSentInterval = Math.ceil((1000 * 60) / options.payloadTimeout); //once per min

  if(appId && appSecret) {
    appId = appId.trim();
    appSecret = appSecret.trim();

    pingToCheckAuth(function(){
      schedulePayloadSend();
    });
    logger('connected to app: ', appId);
  } else {
    throw new Error('Kadira: required appId and appSecret');
  }

  //start wrapping Meteor's internal methods
  Kadira._startInstrumenting(function() {
    console.log('Kadira: completed instrumenting the app')
    Kadira.connected = true;
  });

  var payloadRetries = 0;
  var payloadRetry = new Retry({
      minCount: 0, // don't do any immediate payloadRetries
      baseTimeout: 5*1000,
      maxTimeout: 60000
  });

  function sendPayload(callback) {

    callHTTP();

    function callHTTP() {
      new Fibers(function() {
        var payload = buildPayload();
        var headers = buildHeaders();
        var httpOptions = {headers: headers, data: payload};

        try {
          var response = HTTP.call('POST', options.endpoint, httpOptions);
          processResponse(response);
        } catch(err) {
          tryAgain(err);
        }
      }).run();
    }

    function processResponse(response) {
      if(response.statusCode == '401') {
        throw new Error('Kadira: AppId, AppSecret combination is invalid');
      } else if(response.statusCode == '200') {
        //success send again in 10 secs
        schedulePayloadSend();
        if(payloadRetries > 0) {
          logger('connected again and payload sent.')
        }
        cleaPayloadRetry();
        callback && callback();
      } else {
        tryAgain();
      }
    }

    function tryAgain(err) {
      err = err || {};
      logger('retrying to send payload to server')
      if(++payloadRetries < 5) {
        payloadRetry.retryLater(payloadRetries, callHTTP);
      } else {
        console.error('Kadira: Error sending payload(dropped after 5 tries) ', err.message);
        cleaPayloadRetry();
        schedulePayloadSend();
      }
    }

  }

  function cleaPayloadRetry() {
    payloadRetries = 0;
    payloadRetry.clear();
  }

  function buildHeaders(){
    return {'APM-APP-ID': appId, 'APM-APP-SECRET': appSecret}
  }

  function schedulePayloadSend() {
    setTimeout(sendPayload, options.payloadTimeout);
  }

  function canTrackErrors () {
    if(Kadira.options.enableErrorTracking === undefined) {
      return true;
    } else {
      return Kadira.options.enableErrorTracking;
    }
  }

  var authCheckFailures = 0;
  function pingToCheckAuth(callback){
    var httpOptions = {headers: buildHeaders(), data: {}};
    var endpoint = options.endpoint + '/ping'

    new Fibers(function() {
      HTTP.call('POST', endpoint, httpOptions, function(err, response){
        if(response) {
          if(response.statusCode == 200) {
            console.log('Kadira: successfully authenticated');
            authRetry.clear();
            callback();
          } else if(response.statusCode == 401) {
            console.error('Kadira: authenticatation failed - check your appId & appSecret')
          } else {
            retryPingToCheckAuth(callback);
          }
        } else {
          retryPingToCheckAuth();
        }
      });
    }).run();

    var authRetry = new Retry({
      minCount: 0, // don't do any immediate retries
      baseTimeout: 5*1000 // start with 30s
    });

    function retryPingToCheckAuth(){
      console.log('Kadira: retrying to authenticate');
      authRetry.retryLater(authCheckFailures, function(){
        pingToCheckAuth(callback)
      });
    }
  }

  function buildPayload() {
    var payload = {host: hostname};
    var buildDetailedInfo = (countDataSent++ % detailInfoSentInterval) == 0;
    _.extend(payload, Kadira.models.methods.buildPayload(buildDetailedInfo));
    _.extend(payload, Kadira.models.pubsub.buildPayload(buildDetailedInfo));
    _.extend(payload, Kadira.models.system.buildPayload());
    if(options.enableErrorTracking) {
      _.extend(payload, Kadira.models.error.buildPayload());
    }

    return payload;
  }
};

// this return the __kadiraInfo from the current Fiber by default
// if called with 2nd argument as true, it will get the kadira info from
// Meteor.EnvironmentVariable
//
// WARNNING: retunred info object is the reference object.
//  Changing it might cause issues when building traces. So use with care
Kadira._getInfo = function(currentFiber, useEnvironmentVariable) {
  currentFiber = currentFiber || Fibers.current;
  if(currentFiber) {
    if(useEnvironmentVariable) {
      return Kadira.env.kadiraInfo.get();
    }
    return currentFiber.__kadiraInfo;
  }
};

// this does not clone the info object. So, use with care
Kadira._setInfo = function(info) {
  Fibers.current.__kadiraInfo = info;
  var kadiraInfo = Kadira.env.kadiraInfo.get();
};

Kadira.enableErrorTracking = function () {
  __meteor_runtime_config__.kadira.enableErrorTracking = true;
  Kadira.options.enableErrorTracking = true;
};

Kadira.disableErrorTracking = function () {
  __meteor_runtime_config__.kadira.enableErrorTracking = false;
  Kadira.options.enableErrorTracking = false;
};

Kadira.trackError = function (type, message, options) {
  if(Kadira.options.enableErrorTracking && type && message) {
    options = options || {};
    options.subType = options.subType || 'server';
    options.stacks = options.stacks || '';
    var error = {message: message, stack: options.stacks};
    var trace = {
      type: type,
      subType: options.subType,
      name: message,
      errored: true,
      at: Kadira.syncedDate.getTime(),
      events: [['start', 0, {}], ['error', 0, {error: error}]],
      metrics: {total: 0}
    };
    Kadira.models.error.trackError(error, trace);
  }
}
<|endoftext|>


<commit_before>
var ActionEmitter = require('./action_emitter');

var helpers = require('./helpers'),
    Request = require('./request'),
    Route   = require('./route');

// helpers
var each      = helpers.each,
    map       = helpers.map,
    compact   = helpers.compact,
    addEvent  = helpers.addEvent,
    isArray   = helpers.isArray;

/**
@class Navigator
@constructor
@private
**/
var Navigator = function () {
  this._routes  = null;
  this._exits   = [];
  this._silent  = false;
  this._dispatchingStarted = false;
  this._emitters = [];
};

Navigator.prototype = {

  /**
  @method setup
  @param {Object} options
  **/
  setup: function (options) {
    options = options || {};

    for (var k in options) {
      if (options.hasOwnProperty(k)) {
        this[k] = options[k];
      }
    }

    this._attachEvents();
  },

  /**
  @method setRoutes
  @param {Object} routes a configuration of routes and targets
  **/
  setRoutes: function (routes) {
    this._routes = routes;
  },

  /**
  @method createRouteForURI
  @param {String} uri
  @return {Request}
  **/
  createRouteForURI: function (uri) {
    return new Route(this._routes, uri);
  },

  /**
  @method createRequest
  @param {String} uri
  @param {String|Null} queryString
  @param {String} matchedRoute
  @return {Request}
  **/
  createRequest: function (uri, queryString, matchedRoute) {
    this._request = new Request({
      uri: uri,
      queryString: queryString,
      matchedRoute: matchedRoute
    });

    return this._request;
  },

  /**
  @method getCurrentRequest
  @return {Request}
  **/
  getCurrentRequest: function () {
    return this._request;
  },

  /**
  @method getCurrentPathname
  @return {String}
  **/
  getCurrentPathname: function () {
    if (this.pushStateEnabled) {
      return this._removeURIRoot(location.pathname);
    }
    else {
      return location.hash.replace('#', '').split('?')[0];
    }
  },

  /**
  @method getCurrentURI
  @return {String}
  **/
  getCurrentURI: function () {
    if (this.pushStateEnabled) {
      return this._removeURIRoot(location.pathname) + location.search;
    }
    else {
      return location.hash.replace('#', '');
    }
  },

  /**
  @method getQueryString
  @return {String|Null}
  **/
  getQueryString: function () {
    var uri, queryString;

    if (this.pushStateEnabled) {
      return location.search || null;
    }
    else {
      queryString = this.getCurrentURI().split('?')[1];

      if (queryString) {
        return '?' + queryString;
      }
      else {
        return null;
      }
    }
  },

  /**
  @method dispatch
  **/
  dispatch: function () {
    var uri         = this.getCurrentPathname(),
        route       = this.createRouteForURI(uri),
        queryString = this.getQueryString(),
        request     = this.createRequest(uri, queryString, route.matchedRoute);

    this._emitters = [];
    this._invokeExits(request);

    // temporary action array that can be halted
    this._actions = route.actions;

    if (!this._silent) {
      this._invokeActions(request, route.options);
    }

    // collect exits of the current matching route
    this._exits = route.exits;

    if (!this._dispatchingStarted) {
      this._dispatchingStarted = true;
    }
  },

  /**
  @method onURIChange
  **/
  onURIChange: function () {
    this.dispatch();
    this._silent = false;
  },

  /**
  @method onPopState
  @param {Event}
  **/
  onPopState: function (ev) {
    // Some browsers fire 'popstate' on the initial page load with a null state
    // object. We always want manual control over the initial page dispatch, so
    // prevent any popStates from changing the url until we have started
    // dispatching.
    if (this._dispatchingStarted) {
      this.onURIChange();
    }
  },

  /**
  @method onClick
  @param {Event} ev
  **/
  onClick: function (ev) {
    var target = ev.target,
        matchesSelector = this._matchesSelector(target),
        uriWithoutRoot,
        uri;

    if (ev.button === 1 || ev.metaKey || ev.ctrlKey) return;

    // Feels sub-optimal, itererates through all ancestors on every click :/
    // jquery selector handlers do essentially the same thing though!
    while (target) {
      if (this._matchesSelector(target)) {
        break;
      }

      target = target.parentNode;
    }

    if (!target) return;

    ev.preventDefault();

    uri = this._stripDomain(target.href, window.location.hostname);
    uriWithoutRoot = this._removeURIRoot(uri);

    this.navigate(uriWithoutRoot);
  },

  getExitMessage: function () {
    return compact(map(this._emitters, function (emitter) {
      return emitter.getExitMessage();
    })).join(', ') || undefined;
  },

  onBeforeUnload: function (ev) {
    var exitMessage = this.getExitMessage();

    if (exitMessage) {
      ev.returnValue = exitMessage;
      return exitMessage;
    }
  },

  /**
  @method navigate
  @param {String} uri
  @param {Object} [options]
  **/
  navigate: function (uri, options) {
    var link;

    var exitMessage = this.getExitMessage();
    if (exitMessage && !window.confirm(exitMessage)) {
      return
    }

    options = options || {};
    // halt any previous action invocations
    this._actions = [];

    link = this.hrefFor(uri, options);

    if (options.silent) {
      this._silent = true;
    }

    if (this.pushStateEnabled) {
      link = this._removeURIRoot(link);

      link = this.root + link;

      if (options.replace) {
        history.replaceState('navigate', '', link);
      }
      else {
        history.pushState('navigate', '', link);
      }

      this.onURIChange();
    }
    else {
      if (options.replace) location.replace('#' + link);
      else location.hash = link;
    }
  },

  /**
  @method hrefFor
  @param {String} uri
  @param {Object} [options]
   **/
  hrefFor: function (uri, options) {
    options = options || {};

    var link        = uri + '';
    var request     = this.getCurrentRequest();
    var namedParams = options.namedParams;
    var queryParams = options.queryParams;

    if (!namedParams && request) {
      namedParams = request.namedParams;
    }

    if (queryParams) {
      link += this.serializeQueryParams(queryParams);
    }

    if (namedParams) {
      for (var p in namedParams) {
        if (namedParams.hasOwnProperty(p)) {
          link = link.replace(':' + p, encodeURIComponent(namedParams[p]));
        }
      }
    }

    return link;
  },

  /**
  @method refresh
  **/
  refresh: function () {
    this.dispatch();
  },

  /**
  @method _attachEvents
  @protected
  **/
  _attachEvents: function () {
    var pushStateEnabled = this.pushStateEnabled;

    if (pushStateEnabled) {
      // Popstate fired on initial page load causes double trigger
      // Hack to prevent popState firing two times in Safari (workaround found here: https://github.com/visionmedia/page.js/commit/6e6af2f6c0d7638e06a5ea3de0ff808237bdf2ef)
      var self = this;
      setTimeout(function() {
        addEvent(window, 'popstate', self.onPopState, self);
      }, 0);
    }
    else {
      addEvent(window, 'hashchange', this.onURIChange, this);
    }

    addEvent(document, 'click', this.onClick, this);
    addEvent(window, 'beforeunload', this.onBeforeUnload, this);
  },

  /**
  @method _matchesSelector
  @param {DOMNode} node
  @protected
  **/
  _matchesSelector: function (node) {
    var nodeList = document.querySelectorAll(this.linkSelector),
        contains = false,
        i;

    for ( i = 0; i < nodeList.length; i++ ) {
      if (!contains) contains = ( node === nodeList[i] );
      else break;
    }

    return contains;
  },

  /**
  pop of any exits function and invoke them

  @method _invokeExits
  @param {Request} nextRequest
  @protected
  **/
  _invokeExits: function (nextRequest) {
    var exit, target, method;

    while(this._exits.length) {
      exit = this._exits.pop();
      target = exit.target;
      method = exit.method;

      if (!(method in target)) {
        throw new Error("Can't call exit " + method + ' on target when changing uri to ' + request.uri);
      }

      target[method].call(target, nextRequest);
    }
  },

  /**
  invoke all actions with request and options

  @method _invokeActions
  @param {Request} request
  @param {Object} options
  @protected
  **/
  _invokeActions: function (request, options) {
    var action, target, method, emitter;

    while (this._actions.length) {
      action = this._actions.shift();
      target = action.target;
      method = action.method;
      emitter = new ActionEmitter;

      if (!(method in target)) {
        throw new Error("Can't call action " + method + ' on target for uri ' + request.uri);
      }

      this._emitters.push(emitter);

      target[method].call(target, request, options, emitter);
    }
  },

  /**
  @method _removeURIRoot
  @param {String} uri '/partners/s/foo-bar'
  @return {String} uri '/s/foo-bar'
  **/
  _removeURIRoot: function (uri) {
    var rootRegex = new RegExp('^' + this.root);

    return uri.replace(rootRegex, '');
  },

  /**
  @method _stripDomain
  @param {String} href 'http://domain.com/partners/s/foo-bar?with=params#andahash'
  @param {String} Optional - hostname 'domain.com'
  @return {String} uri '/partners/s/foo-bar?with=params'
  **/
  _stripDomain: function (href, hostname) {
    var hostname = hostname ? hostname : window.location.hostname,
        uriStartIndex = href.indexOf(hostname) + hostname.length;

    return href.substr(uriStartIndex);
  },

  /**
  @method serializeQueryParams
  @param {Object} queryParams
  @return {String} queryString "?foo=bar&baz[]=boo&baz=[]oob"
  **/
  serializeQueryParams: function (queryParams) {
    var queryString = [],
        val;

    for (var key in queryParams) {
      if (queryParams.hasOwnProperty(key)) {
        val = queryParams[key];

        if (isArray(val)) {
          each(val, function (item) {
            queryString.push(encodeURIComponent(key) + '[]=' + encodeURIComponent(item));
          });
        }
        else {
          queryString.push(encodeURIComponent(key) + '=' + encodeURIComponent(val));
        }
      }
    }

    queryString = '?' + queryString.join('&');

    return queryString;
  }

};

module.exports = Navigator;
<commit_msg>Strip port on navigate if it exists<commit_after>
var ActionEmitter = require('./action_emitter');

var helpers = require('./helpers'),
    Request = require('./request'),
    Route   = require('./route');

// helpers
var each      = helpers.each,
    map       = helpers.map,
    compact   = helpers.compact,
    addEvent  = helpers.addEvent,
    isArray   = helpers.isArray;

/**
@class Navigator
@constructor
@private
**/
var Navigator = function () {
  this._routes  = null;
  this._exits   = [];
  this._silent  = false;
  this._dispatchingStarted = false;
  this._emitters = [];
};

Navigator.prototype = {

  /**
  @method setup
  @param {Object} options
  **/
  setup: function (options) {
    options = options || {};

    for (var k in options) {
      if (options.hasOwnProperty(k)) {
        this[k] = options[k];
      }
    }

    this._attachEvents();
  },

  /**
  @method setRoutes
  @param {Object} routes a configuration of routes and targets
  **/
  setRoutes: function (routes) {
    this._routes = routes;
  },

  /**
  @method createRouteForURI
  @param {String} uri
  @return {Request}
  **/
  createRouteForURI: function (uri) {
    return new Route(this._routes, uri);
  },

  /**
  @method createRequest
  @param {String} uri
  @param {String|Null} queryString
  @param {String} matchedRoute
  @return {Request}
  **/
  createRequest: function (uri, queryString, matchedRoute) {
    this._request = new Request({
      uri: uri,
      queryString: queryString,
      matchedRoute: matchedRoute
    });

    return this._request;
  },

  /**
  @method getCurrentRequest
  @return {Request}
  **/
  getCurrentRequest: function () {
    return this._request;
  },

  /**
  @method getCurrentPathname
  @return {String}
  **/
  getCurrentPathname: function () {
    if (this.pushStateEnabled) {
      return this._removeURIRoot(location.pathname);
    }
    else {
      return location.hash.replace('#', '').split('?')[0];
    }
  },

  /**
  @method getCurrentURI
  @return {String}
  **/
  getCurrentURI: function () {
    if (this.pushStateEnabled) {
      return this._removeURIRoot(location.pathname) + location.search;
    }
    else {
      return location.hash.replace('#', '');
    }
  },

  /**
  @method getQueryString
  @return {String|Null}
  **/
  getQueryString: function () {
    var uri, queryString;

    if (this.pushStateEnabled) {
      return location.search || null;
    }
    else {
      queryString = this.getCurrentURI().split('?')[1];

      if (queryString) {
        return '?' + queryString;
      }
      else {
        return null;
      }
    }
  },

  /**
  @method dispatch
  **/
  dispatch: function () {
    var uri         = this.getCurrentPathname(),
        route       = this.createRouteForURI(uri),
        queryString = this.getQueryString(),
        request     = this.createRequest(uri, queryString, route.matchedRoute);

    this._emitters = [];
    this._invokeExits(request);

    // temporary action array that can be halted
    this._actions = route.actions;

    if (!this._silent) {
      this._invokeActions(request, route.options);
    }

    // collect exits of the current matching route
    this._exits = route.exits;

    if (!this._dispatchingStarted) {
      this._dispatchingStarted = true;
    }
  },

  /**
  @method onURIChange
  **/
  onURIChange: function () {
    this.dispatch();
    this._silent = false;
  },

  /**
  @method onPopState
  @param {Event}
  **/
  onPopState: function (ev) {
    // Some browsers fire 'popstate' on the initial page load with a null state
    // object. We always want manual control over the initial page dispatch, so
    // prevent any popStates from changing the url until we have started
    // dispatching.
    if (this._dispatchingStarted) {
      this.onURIChange();
    }
  },

  /**
  @method onClick
  @param {Event} ev
  **/
  onClick: function (ev) {
    var target = ev.target,
        matchesSelector = this._matchesSelector(target),
        uriWithoutRoot,
        uri;

    if (ev.button === 1 || ev.metaKey || ev.ctrlKey) return;

    // Feels sub-optimal, itererates through all ancestors on every click :/
    // jquery selector handlers do essentially the same thing though!
    while (target) {
      if (this._matchesSelector(target)) {
        break;
      }

      target = target.parentNode;
    }

    if (!target) return;

    ev.preventDefault();

    uri = this._stripDomain(target.href, window.location.hostname);
    uriWithoutRoot = this._removeURIRoot(uri);

    this.navigate(uriWithoutRoot);
  },

  getExitMessage: function () {
    return compact(map(this._emitters, function (emitter) {
      return emitter.getExitMessage();
    })).join(', ') || undefined;
  },

  onBeforeUnload: function (ev) {
    var exitMessage = this.getExitMessage();

    if (exitMessage) {
      ev.returnValue = exitMessage;
      return exitMessage;
    }
  },

  /**
  @method navigate
  @param {String} uri
  @param {Object} [options]
  **/
  navigate: function (uri, options) {
    var link;

    var exitMessage = this.getExitMessage();
    if (exitMessage && !window.confirm(exitMessage)) {
      return
    }

    options = options || {};
    // halt any previous action invocations
    this._actions = [];

    link = this.hrefFor(uri, options);

    if (options.silent) {
      this._silent = true;
    }

    if (this.pushStateEnabled) {
      link = this._removeURIRoot(link);

      link = this.root + link;

      if (options.replace) {
        history.replaceState('navigate', '', link);
      }
      else {
        history.pushState('navigate', '', link);
      }

      this.onURIChange();
    }
    else {
      if (options.replace) location.replace('#' + link);
      else location.hash = link;
    }
  },

  /**
  @method hrefFor
  @param {String} uri
  @param {Object} [options]
   **/
  hrefFor: function (uri, options) {
    options = options || {};

    var link        = uri + '';
    var request     = this.getCurrentRequest();
    var namedParams = options.namedParams;
    var queryParams = options.queryParams;

    if (!namedParams && request) {
      namedParams = request.namedParams;
    }

    if (queryParams) {
      link += this.serializeQueryParams(queryParams);
    }

    if (namedParams) {
      for (var p in namedParams) {
        if (namedParams.hasOwnProperty(p)) {
          link = link.replace(':' + p, encodeURIComponent(namedParams[p]));
        }
      }
    }

    return link;
  },

  /**
  @method refresh
  **/
  refresh: function () {
    this.dispatch();
  },

  /**
  @method _attachEvents
  @protected
  **/
  _attachEvents: function () {
    var pushStateEnabled = this.pushStateEnabled;

    if (pushStateEnabled) {
      // Popstate fired on initial page load causes double trigger
      // Hack to prevent popState firing two times in Safari (workaround found here: https://github.com/visionmedia/page.js/commit/6e6af2f6c0d7638e06a5ea3de0ff808237bdf2ef)
      var self = this;
      setTimeout(function() {
        addEvent(window, 'popstate', self.onPopState, self);
      }, 0);
    }
    else {
      addEvent(window, 'hashchange', this.onURIChange, this);
    }

    addEvent(document, 'click', this.onClick, this);
    addEvent(window, 'beforeunload', this.onBeforeUnload, this);
  },

  /**
  @method _matchesSelector
  @param {DOMNode} node
  @protected
  **/
  _matchesSelector: function (node) {
    var nodeList = document.querySelectorAll(this.linkSelector),
        contains = false,
        i;

    for ( i = 0; i < nodeList.length; i++ ) {
      if (!contains) contains = ( node === nodeList[i] );
      else break;
    }

    return contains;
  },

  /**
  pop of any exits function and invoke them

  @method _invokeExits
  @param {Request} nextRequest
  @protected
  **/
  _invokeExits: function (nextRequest) {
    var exit, target, method;

    while(this._exits.length) {
      exit = this._exits.pop();
      target = exit.target;
      method = exit.method;

      if (!(method in target)) {
        throw new Error("Can't call exit " + method + ' on target when changing uri to ' + request.uri);
      }

      target[method].call(target, nextRequest);
    }
  },

  /**
  invoke all actions with request and options

  @method _invokeActions
  @param {Request} request
  @param {Object} options
  @protected
  **/
  _invokeActions: function (request, options) {
    var action, target, method, emitter;

    while (this._actions.length) {
      action = this._actions.shift();
      target = action.target;
      method = action.method;
      emitter = new ActionEmitter;

      if (!(method in target)) {
        throw new Error("Can't call action " + method + ' on target for uri ' + request.uri);
      }

      this._emitters.push(emitter);

      target[method].call(target, request, options, emitter);
    }
  },

  /**
  @method _removeURIRoot
  @param {String} uri '/partners/s/foo-bar'
  @return {String} uri '/s/foo-bar'
  **/
  _removeURIRoot: function (uri) {
    var rootRegex = new RegExp('^' + this.root);

    return uri.replace(rootRegex, '');
  },

  /**
  @method _stripDomain
  @param {String} href 'http://domain.com/partners/s/foo-bar?with=params#andahash'
  @param {String} Optional - hostname 'domain.com'
  @param {string} Optional - port '8080'
  @return {String} uri '/partners/s/foo-bar?with=params'
  **/
  _stripDomain: function (href, hostname, port) {
    var hostname = hostname ? hostname : window.location.hostname,
        uriStartIndex = href.indexOf(hostname) + hostname.length;

    var port = port ? port : window.location.port;
    if (port) {
      var fullHost = hostname + ':' + port;
      uriStartIndex = href.indexOf(fullHost) + fullHost.length;
    }

    return href.substr(uriStartIndex);
  },

  /**
  @method serializeQueryParams
  @param {Object} queryParams
  @return {String} queryString "?foo=bar&baz[]=boo&baz=[]oob"
  **/
  serializeQueryParams: function (queryParams) {
    var queryString = [],
        val;

    for (var key in queryParams) {
      if (queryParams.hasOwnProperty(key)) {
        val = queryParams[key];

        if (isArray(val)) {
          each(val, function (item) {
            queryString.push(encodeURIComponent(key) + '[]=' + encodeURIComponent(item));
          });
        }
        else {
          queryString.push(encodeURIComponent(key) + '=' + encodeURIComponent(val));
        }
      }
    }

    queryString = '?' + queryString.join('&');

    return queryString;
  }

};

module.exports = Navigator;
<|endoftext|>


<commit_before>// ==UserScript==
// @id             iitc-plugin-mod-slots@randomizax
// @name           IITC plugin: Portal Mod Status on Map
// @category       Layer
// @version        0.4.0.@@DATETIMEVERSION@@
// @namespace      https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL      @@UPDATEURL@@
// @downloadURL    @@DOWNLOADURL@@
// @description    [@@BUILDNAME@@-@@BUILDDATE@@] Show mod slots on map.
// @include        https://www.ingress.com/intel*
// @include        http://www.ingress.com/intel*
// @match          https://www.ingress.com/intel*
// @match          http://www.ingress.com/intel*
// @grant          none
// ==/UserScript==

@@PLUGINSTART@@

// PLUGIN START ////////////////////////////////////////////////////////

// use own namespace for plugin
window.plugin.portalModSlots = function() {
};

window.plugin.portalModSlots.MOD_COLOR = {
  VERY_RARE: '#ff5cf4', RARE: '#683480', COMMON: '#44a065', NONE: '#fff',
  "SoftBank Ultra Link": '#d09d00',
  "Ito En Transmuter (+)": '#38389b',
  "Ito En Transmuter (-)": '#38389b'
};
window.plugin.portalModSlots.MOD_DISPLAY = {
  "Portal Shield":  'PS',
  "Aegis Shield":     'AX',
  "Multi-hack":     'MH',
  "Heat Sink":      'HS',
  "Force Amp":      'FA',
  "Turret":         'TU',
  "Link Amp":       'LA',
  "SoftBank Ultra Link":       'SB',
  "Ito En Transmuter (+)":     'PL',
  "Ito En Transmuter (-)":    'MI',
  OCCUPIED:         'UK',
  NONE:             '__'
};

window.plugin.portalModSlots.slotLayers = {};
window.plugin.portalModSlots.slotLayerGroup = null;
window.plugin.portalModSlots.modLayers = {};
window.plugin.portalModSlots.modLayerGroup = null;

window.plugin.portalModSlots.setupCSS = function() {
  $("