<commit_before>// DOMContentLoaded is fired once the document has been loaded and parsed,
// but without waiting for other external resources to load (css/images/etc)
// That makes the app more responsive and perceived as faster.
// https://developer.mozilla.org/Web/Reference/Events/DOMContentLoaded
window.addEventListener('DOMContentLoaded', function() {

  // We'll ask the browser to use strict code to help us catch errors earlier.
  // https://developer.mozilla.org/Web/JavaScript/Reference/Functions_and_function_scope/Strict_mode
  'use strict';

  //test nfc code
  navigator.mozSetMessageHandler('activity', handlerFunction);

  // Example handler to get the URL from the activity.
  function handlerFunction(activity) {
    console.log(activity);
    if (activity.source.data.type == 'url') {
      var url = activity.source.data.url;
      console.log(url);
    }
  }

  console.log('test');

  navigator.mozNfc.ontagfound = function(event) {
    var tag = event.tag;
    console.log(event);
    console.log(tag instanceof MozNFCTag); // should print true
    console.log(tag);
  }

  navigator.mozNfc.ontaglost = function(event) {
    console.log(event);
  }

  var apiURL = 'https://developer.mozilla.org/search.json?q=';
  var errorMsg = document.getElementById('error');
  var searchInput = document.getElementById('term');
  var results = document.getElementById('results');
  var request = null;
  var translate = navigator.mozL10n.get;
  var form = document.querySelector('form');

  // Forms will take the values in the input fields they contain
  // and send them to a server for further processing,
  // but since we want to stay in this page AND make a request to another server,
  // we will listen to the 'submit' event, and prevent the form from doing what
  // it would usually do, using preventDefault.
  // Read more about it here:
  // https://developer.mozilla.org/Web/API/event.preventDefault
  //
  // Then we search without leaving this page, just as we wanted.
  form.addEventListener('submit', function(e) {
      e.preventDefault();
      search();
  }, false);

  // We want to wait until the localisations library has loaded all the strings.
  // So we'll tell it to let us know once it's ready.
  navigator.mozL10n.once(search);

  // ---

  function search() {

    // Are we searching already? Then stop that search
    if(request && request.abort) {
      request.abort();
    }

    results.textContent = translate('searching');

    // We will be using the 'hidden' attribute throughout the app rather than a
    // 'hidden' CSS class because it enhances accessibility.
    // See: http://www.whatwg.org/specs/web-apps/current-work/multipage/editing.html#the-hidden-attribute
    results.hidden = false;
    errorMsg.hidden = true;

    var term = searchInput.value;
    if(term.length === 0) {
      term = searchInput.placeholder;
    }

    var url = apiURL + term;

    // If you don't set the mozSystem option, you'll get CORS errors (Cross Origin Resource Sharing)
    // You can read more about CORS here: https://developer.mozilla.org/docs/HTTP/Access_control_CORS
    request = new XMLHttpRequest({ mozSystem: true });

    request.open('get', url, true);
    request.responseType = 'json';

    // We're setting some handlers here for dealing with both error and
    // data received. We could just declare the functions here, but they are in
    // separate functions so that search() is shorter, and more readable.
    request.addEventListener('error', onRequestError);
    request.addEventListener('load', onRequestLoad);

    request.send();

  }

  function onRequestError() {

    var errorMessage = request.error;
      if(!errorMessage) {
        errorMessage = translate('searching_error');
      }
      showError(errorMessage);

  }

  function onRequestLoad() {

    var response = request.response;

    if(response === null) {
      showError(translate('searching_error'));
      return;
    }

    results.textContent = '';

    var documents = response.documents;

    if(documents.length === 0) {

      var p = document.createElement('p');
      p.textContent = translate('search_no_results');
      results.appendChild(p);

    } else {

      documents.forEach(function(doc) {

        // We're using textContent because inserting content from external sources into your page using innerHTML can be dangerous.
        // https://developer.mozilla.org/Web/API/Element.innerHTML#Security_considerations
        var docLink = document.createElement('a');
        docLink.textContent = doc.title;
        docLink.href = doc.url;

        // We want the links to open in a pop up window with a 'close'
        // button, so that the user can consult the result and then close it and
        // be brought back to our app.
        // If we did nothing, these external links would take over the entirety
        // our app and there would be no way for a user to go back to the app.
        // But Firefox OS allows us to open ONE new window per app; these new
        // windows will have a close button, so the user can close the overlay
        // when they're happy with what they've read.
        // Therefore we will capture click events on links, stop them from
        // doing their usual thing using preventDefault(),
        // and then open the link but in a new window.
        docLink.addEventListener('click', function(evt) {
          evt.preventDefault();
          window.open(evt.target.href, 'overlay');
        });

        var h2 = document.createElement('h2');
        h2.appendChild(docLink);
        results.appendChild(h2);

      });

    }

    // And once we have all the content in place, we can show it.
    results.hidden = false;

  }

  function showError(text) {
    errorMsg.textContent = text;
    errorMsg.hidden = false;
    results.hidden = true;
  }

});
<commit_msg>test reading NDEF records<commit_after>// DOMContentLoaded is fired once the document has been loaded and parsed,
// but without waiting for other external resources to load (css/images/etc)
// That makes the app more responsive and perceived as faster.
// https://developer.mozilla.org/Web/Reference/Events/DOMContentLoaded
window.addEventListener('DOMContentLoaded', function() {

  // We'll ask the browser to use strict code to help us catch errors earlier.
  // https://developer.mozilla.org/Web/JavaScript/Reference/Functions_and_function_scope/Strict_mode
  'use strict';

  //test nfc code
  navigator.mozSetMessageHandler('activity', handlerFunction);

  // Example handler to get the URL from the activity.
  function handlerFunction(activity) {
    console.log(activity);
    if (activity.source.data.type == 'url') {
      var url = activity.source.data.url;
      console.log(url);
    }
  }

  console.log('test');

  navigator.mozNfc.ontagfound = function(event) {
    var tag = event.tag;
    console.log(event);
    console.log(tag instanceof MozNFCTag); // should print true
    console.log(tag);
    // tag is an instance of MozNFCTag
    tag.readNDEF().then(records => {
      console.log(records);
      // records should be an array of MozNDEFRecord.
    });
  }

  navigator.mozNfc.ontaglost = function(event) {
    console.log(event);
  }

  var apiURL = 'https://developer.mozilla.org/search.json?q=';
  var errorMsg = document.getElementById('error');
  var searchInput = document.getElementById('term');
  var results = document.getElementById('results');
  var request = null;
  var translate = navigator.mozL10n.get;
  var form = document.querySelector('form');

  // Forms will take the values in the input fields they contain
  // and send them to a server for further processing,
  // but since we want to stay in this page AND make a request to another server,
  // we will listen to the 'submit' event, and prevent the form from doing what
  // it would usually do, using preventDefault.
  // Read more about it here:
  // https://developer.mozilla.org/Web/API/event.preventDefault
  //
  // Then we search without leaving this page, just as we wanted.
  form.addEventListener('submit', function(e) {
      e.preventDefault();
      search();
  }, false);

  // We want to wait until the localisations library has loaded all the strings.
  // So we'll tell it to let us know once it's ready.
  navigator.mozL10n.once(search);

  // ---

  function search() {

    // Are we searching already? Then stop that search
    if(request && request.abort) {
      request.abort();
    }

    results.textContent = translate('searching');

    // We will be using the 'hidden' attribute throughout the app rather than a
    // 'hidden' CSS class because it enhances accessibility.
    // See: http://www.whatwg.org/specs/web-apps/current-work/multipage/editing.html#the-hidden-attribute
    results.hidden = false;
    errorMsg.hidden = true;

    var term = searchInput.value;
    if(term.length === 0) {
      term = searchInput.placeholder;
    }

    var url = apiURL + term;

    // If you don't set the mozSystem option, you'll get CORS errors (Cross Origin Resource Sharing)
    // You can read more about CORS here: https://developer.mozilla.org/docs/HTTP/Access_control_CORS
    request = new XMLHttpRequest({ mozSystem: true });

    request.open('get', url, true);
    request.responseType = 'json';

    // We're setting some handlers here for dealing with both error and
    // data received. We could just declare the functions here, but they are in
    // separate functions so that search() is shorter, and more readable.
    request.addEventListener('error', onRequestError);
    request.addEventListener('load', onRequestLoad);

    request.send();

  }

  function onRequestError() {

    var errorMessage = request.error;
      if(!errorMessage) {
        errorMessage = translate('searching_error');
      }
      showError(errorMessage);

  }

  function onRequestLoad() {

    var response = request.response;

    if(response === null) {
      showError(translate('searching_error'));
      return;
    }

    results.textContent = '';

    var documents = response.documents;

    if(documents.length === 0) {

      var p = document.createElement('p');
      p.textContent = translate('search_no_results');
      results.appendChild(p);

    } else {

      documents.forEach(function(doc) {

        // We're using textContent because inserting content from external sources into your page using innerHTML can be dangerous.
        // https://developer.mozilla.org/Web/API/Element.innerHTML#Security_considerations
        var docLink = document.createElement('a');
        docLink.textContent = doc.title;
        docLink.href = doc.url;

        // We want the links to open in a pop up window with a 'close'
        // button, so that the user can consult the result and then close it and
        // be brought back to our app.
        // If we did nothing, these external links would take over the entirety
        // our app and there would be no way for a user to go back to the app.
        // But Firefox OS allows us to open ONE new window per app; these new
        // windows will have a close button, so the user can close the overlay
        // when they're happy with what they've read.
        // Therefore we will capture click events on links, stop them from
        // doing their usual thing using preventDefault(),
        // and then open the link but in a new window.
        docLink.addEventListener('click', function(evt) {
          evt.preventDefault();
          window.open(evt.target.href, 'overlay');
        });

        var h2 = document.createElement('h2');
        h2.appendChild(docLink);
        results.appendChild(h2);

      });

    }

    // And once we have all the content in place, we can show it.
    results.hidden = false;

  }

  function showError(text) {
    errorMsg.textContent = text;
    errorMsg.hidden = false;
    results.hidden = true;
  }

});
<|endoftext|>


<commit_before>'use strict';

/* Controllers */

angular.module('myApp.controllers', []).
controller('AppCtrl', function($scope, $http) {
    $scope.pane = 0;
    $scope.familySize = 0
    var data = {};
    // This is called each time the screen should be advanced. It stores all current information into data.
    $scope.next = function() {
        console.log($scope.$$childTail);
        if($scope.pane == 1){
            if($scope.$$childTail)
                $scope.familySize = $scope.$$childTail.familySize;
        }
        $scope.pane++;
    };
    // This calls the backend to determine what to show next.
    var update = function() {
        data.pane = $scope.pane;
        $http.post('/api/getInfo', data).
        success(function(dat) {
            console.log(dat);
            if (dat) {
                $scope.pane = dat.screen;
                $scope.sex = dat.sex;
                $scope.number = dat.number;
                $scope.estimate = dat.estimate;
            }
        });
    }
    //
    $scope.previous = function() {
        $scope.pane--;
    };
});<commit_msg>Fixed bug where dependents did not need to be entered<commit_after>'use strict';

/* Controllers */

angular.module('myApp.controllers', []).
controller('AppCtrl', function($scope, $http) {
    $scope.pane = 0;
    $scope.familySize = 0
    var data = {};
    // This is called each time the screen should be advanced. It stores all current information into data.
    $scope.next = function() {
        console.log($scope.$$childTail);
        if($scope.pane == 1){
            $scope.pane = 0;
            if($scope.$$childTail)
                $scope.familySize = $scope.$$childTail.familySize;
        }
        $scope.pane++;
    };
    // This calls the backend to determine what to show next.
    var update = function() {
        data.pane = $scope.pane;
        $http.post('/api/getInfo', data).
        success(function(dat) {
            console.log(dat);
            if (dat) {
                $scope.pane = dat.screen;
                $scope.sex = dat.sex;
                $scope.number = dat.number;
                $scope.estimate = dat.estimate;
            }
        });
    }
    //
    $scope.previous = function() {
        $scope.pane--;
    };
});<|endoftext|>


<commit_before>'use strict';

let dom = {};

dom.$SGGS = document.getElementById('SGGS');
dom.$about = document.getElementById('about');
dom.$modalRoot = document.getElementById('modalRoot');
dom.$autoScroll = document.getElementById('autoScroll');
dom.$nightModer = document.getElementById('nightModer');
dom.$selectBaani = document.getElementById('selectBaani');
dom.$baaniWrapper = document.getElementById('baaniWrapper');
dom.$modalBody = dom.$modalRoot.querySelector('.modal-body');
dom.$fontSizeChanger = document.getElementById('fontChanger');

// Sets the body of the modal and calls .modal on it
dom.setAndCallModal = (content, options) => (dom.$modalBody.innerHTML = content) && $(dom.$modalRoot).modal(options);

// Toggles dark-mode by adding or removing .dark-mode on given object
dom.toggleDarkMode = $t => $t.classList.contains('dark-mode') ? $t.classList.remove('dark-mode') : $t.classList.add('dark-mode');

// Returns a function which accepts a value and returns a Promise to set it to passed the object's given property
dom.set = (obj, prop) => {
  return val => {
    dom[obj][prop] = val;
    setTimeout(arguments.callee, 0);
  }
};

// Creates an element of type type and inits some properties based on config[]
dom.createElement = (type, config) => {
  let $t = document.createElement(type);
  for(let prop in config)
    $t[prop] = config[prop];
  return $t;
};

// Takes an object having keys as the $keys of dom and adds eventListener for each object[key][0] event with function object[key][1]
dom.addEventListener = (obj) => {
  for(let $ele in obj)
    for(let event in obj[$ele])
      dom[$ele].addEventListener(event, obj[$ele][event])
};

module.exports = dom;
<commit_msg>Comment fix<commit_after>'use strict';

let dom = {};

dom.$SGGS = document.getElementById('SGGS');
dom.$about = document.getElementById('about');
dom.$modalRoot = document.getElementById('modalRoot');
dom.$autoScroll = document.getElementById('autoScroll');
dom.$nightModer = document.getElementById('nightModer');
dom.$selectBaani = document.getElementById('selectBaani');
dom.$baaniWrapper = document.getElementById('baaniWrapper');
dom.$modalBody = dom.$modalRoot.querySelector('.modal-body');
dom.$fontSizeChanger = document.getElementById('fontChanger');

// Sets the body of the modal and calls .modal on it
dom.setAndCallModal = (content, options) => (dom.$modalBody.innerHTML = content) && $(dom.$modalRoot).modal(options);

// Toggles dark-mode by adding or removing .dark-mode on given object
dom.toggleDarkMode = $t => $t.classList.contains('dark-mode') ? $t.classList.remove('dark-mode') : $t.classList.add('dark-mode');

// Returns a function which accepts a value and set it to the passed object's given property
dom.set = (obj, prop) => {
  return val => {
    dom[obj][prop] = val;
    setTimeout(arguments.callee, 0);
  }
};

// Creates an element of type type and inits some properties based on config[]
dom.createElement = (type, config) => {
  let $t = document.createElement(type);
  for(let prop in config)
    $t[prop] = config[prop];
  return $t;
};

// Takes an object having keys as the $keys of dom and adds eventListener for each object[key][0] event with function object[key][1]
dom.addEventListener = (obj) => {
  for(let $ele in obj)
    for(let event in obj[$ele])
      dom[$ele].addEventListener(event, obj[$ele][event])
};

module.exports = dom;
<|endoftext|>


<commit_before>linz.addLoadEvent(function () {

    var filtersAreDirty = false;

    /* FILTERS */

    if ($('.selectedFilters').length && $('.selectedFilters').val().length > 0) {
        toggleFilterBox('show');
    }

    $('[data-sort-field]').click(function () {

        var sort = $('.selectedSort').val(),
            sortField = $(this).attr('data-sort-field');

        if (sort === sortField) {
            sortField = '-' + sortField;
        }

        // update hidden sort field in the filter form
        $('.selectedSort').val(sortField);

        filtersAreDirty = true;

        triggerSubmit();

        return true;

    });

    $('form.filters').on('submit', function (event) {

        var isValid = $('.filters')[0].checkValidity();

        if (!isValid) {
            return false;
        }

        // Disable the submit button.
        $('.filters').find(':submit').attr('disabled', true);
        $('.filters').find('.btn[data-toggle="dropdown"]').attr('disabled', true);

        // Add the spinner.
        $(this).find(':submit').append(' ');

    });

    $('form.filters button[type="submit"]').click(function (event) {

        // reset the pagination if required
        if (filtersAreDirty || event.isTrigger === undefined) {
            $('input.page').val(1);
        }

    });

    function renderFilter (filter) {

        var filterText = filter.html(),
            filterVal = filter.attr('data-filter-field'),
            filterFormControl = filter.siblings('.controlField').children().html(),
            aFilters;

        var content = document.querySelector('#filter').content.cloneNode(true);

        // update template with filter content
        content.querySelector('.filter-name').textContent = filterText;
        content.querySelector('.filter-control').innerHTML = content.querySelector('.filter-control').innerHTML + filterFormControl;
        content.querySelector('.fa-times').setAttribute('data-filter-field', filter.attr('data-filter-field'));
        document.querySelector('.filter-list').appendChild(document.importNode(content, true));

        // determine if a multiselect was added to the dom, if so, apply the plugin
        $('.multiselect', $('.filter-list').children().last()).multiselect({
            buttonContainer: '
'
        });

        // hide dropdown for 'Add filter'
        filter.parents('.dropdown').removeClass('open');

        var selectedFilters = $('.selectedFilters').val();

        if (selectedFilters) {
            aFilters = $('.selectedFilters').val().split();
        } else {
            aFilters = [];
        }

        // only add the filter once
        if (aFilters.indexOf(filterVal) < 0) {
            aFilters.push(filterVal);
        }

        $('.selectedFilters').val(aFilters.join());

        filtersAreDirty = true;

        toggleFilterBox('show');

        assignRemoveButton();
        linz.loadDatepicker();

        return false;

    }

    function doesFilterExist (name) {

        return $('.filter-list').children().find('input[name^=' + name + ']', 'select[name^=' + name + ']').length > 0;

    }

    $('.control-addFilter').click(function () {

        if ($(this).parent().is('.disabled')) {
            return;
        }

        return renderFilter($(this));

    });

    // Handle once filters.
    (function () {

        var onceFilters = $('a[data-filter-once="true"]');

        onceFilters.on('click', function () {
            return $(this).parent().addClass('disabled');
        });

    })();

    // Render alwaysOn filters.
    (function () {

        var alwaysOnFilters = $('a[data-filter-alwayson="true"]'),
            disabled = [];

        alwaysOnFilters.each(function (index) {

            if ($(this).attr('data-filter-once') === 'true') {

                if (!$('.filter-list [data-filter-field="' + $(this).attr('data-filter-field') + '"]').length) {
                    renderFilter($(this));
                }

                $(this).remove();

                return $('.filter-list [data-filter-field="' + $(this).attr('data-filter-field') + '"]').css('visibility', 'hidden');

            }

            if(!doesFilterExist($(this).attr('data-filter-field'))) {
                renderFilter($(this));
            }

            return $('.filter-list [data-filter-field="' + $(this).attr('data-filter-field') + '"]').slice(0,1).css('visibility', 'hidden');

        });

        var filterBtn = $('.addFilterBtn');

        if (!filterBtn.find('.control-addFilter').length) {
            filterBtn.remove();
        }

    })();

    assignRemoveButton();

    /* PAGINATION */

    $('select.pagination').change(function () {
        $('input.page').val($(this).val());
        triggerSubmit();
    });

    /* PAGE SIZE */

    $('select.pagination-size').change(function () {
        $('input.pageSize').val($(this).val());
        filtersAreDirty = true;
        triggerSubmit();
    });

    /* GROUP ACTIONS */

    $('input[data-linz-control="checked-all"]').click(function () {

        var isChecked = $(this).is(':checked');

        $('input[data-linz-control="checked-record"]').prop('checked',isChecked);

    });

    // bind event for check-all checkbox to show group action buttons
    $('input[data-linz-control="checked-all"]').click(function () {

        if ($(this).is(':checked')) {
            return $('.group-actions').removeClass('hidden');
        }

        $('.group-actions').addClass('hidden');

    });

    // bind event to checkboxes to show group action buttons when checked
    $('input[data-linz-control="checked-record"]').click(function () {

        if ($(this).is(':checked')) {
            return $('.group-actions').removeClass('hidden');
        }

        // check if any of the other checkboxes are checked
        if ($('input[data-linz-control="checked-record"]:checked').length) {
            return;
        }

        // since none are checked, let's close group action buttons
        $('.group-actions').addClass('hidden');

    });

    // We know the page has loaded at this point, so we can re-enable the modals.
    $('[data-linz-control="export"], [data-linz-control="group-action"], [data-linz-control="record-action"]').removeClass('disabled');

    // bind group action buttons
    $('[data-linz-control="group-action"]').click(function () {

        var queryObj = $(this),
            url = queryObj.attr('href');

        $('#groupActionModal').modal().load(url);

       return false;
    });

    // bind record action buttons
    $('[data-linz-control="record-action"]').click(function () {

        var queryObj = $(this),
            url = queryObj.attr('href');

        $('#recordActionModal').modal().load(url);

       return false;

    });

    // bind model save button and update the selected ids to modal form
    $('#groupActionModal').on('shown.bs.modal', function (e) {

        var selectedIDs = [],
            _this = this;

        $('input[data-linz-control="checked-record"]:checked').each(function () {
            selectedIDs.push($(this).val());
        });

        // add selected IDs to hidden field
        $(_this).find('[data-group-action="ids"]').val(selectedIDs);

        // add form validation
        $(_this).find('form[data-linz-validation="true"]').bootstrapValidator({});

    });

    // bind model save button
    $('#recordActionModal').on('shown.bs.modal', function (e) {

        var _this = this;

        // add form validation
        $(_this).find('form[data-linz-validation="true"]').bootstrapValidator({});

    });

    // bind export button
    $('[data-linz-control="export"]').click(function (event) {

        // stop the href navigation
        event.preventDefault();

        var queryObj = $(this),
            url = queryObj.attr('href'),
            useModal = (queryObj.attr('data-target') === "#exportModal");

        if (useModal) {

            var modal = $('#exportModal');
            modal.attr('data-linz-export-url', url);
            modal.modal();

            return false;

        }

        // retrieve the ids
        var selectedIds = $('input[data-linz-control="checked-record"]:checked').map(function () {
            return $(this).val();
        }).get();

        // construct the form
        var form = document.createElement('form');
        form.method = 'post';
        form.action = url;

        var inputFilters = document.createElement('input');
        inputFilters.type = 'hidden';
        inputFilters.name = 'filters';
        inputFilters.value = $('#modelQuery').html();

        var inputSelectedIds = document.createElement('input')
        inputSelectedIds.type = 'hidden';
        inputSelectedIds.name = 'selectedIds';
        inputSelectedIds.value = selectedIds.join(',');

        var inputModelName = document.createElement('input');
        inputModelName.type = 'hidden';
        inputModelName.name = 'modelName';
        inputModelName.value = $('[data-linz-model]').attr('data-linz-model');

        var tokenInput = document.createElement('input');
        tokenInput.type = 'hidden';
        tokenInput.name = '_csrf';
        tokenInput.value = $('meta[name=csrf-token]').attr('content');

        // append to the form
        form.appendChild(inputFilters);
        form.appendChild(inputSelectedIds);
        form.appendChild(inputModelName);
        form.appendChild(tokenInput);

        // append form to body
        document.body.appendChild(form);

        // submit the form
        form.submit();

        return false;

    });

    function removeFomList (list, value, separator) {
        separator = separator || ",";
        var values = list.split(separator);

        for(var i = 0 ; i < values.length ; i++) {
            if(values[i] === value) {
                values.splice(i, 1);
                return values.join(separator);
            }
        }

        return list;

    }

    function assignRemoveButton (queryObj) {

        // remove all event listener
        $('.fa-times').unbind();

        // re-assign listeners including any new ones added to DOM after page load
        $('.fa-times').click(function () {

            var filteredField = $(this).attr('data-filter-field'),
                selectedFilters = $('.selectedFilters').val(),
                numOfSameFilters = $('.fa-times[data-filter-field=' + filteredField + ']').length;

            filtersAreDirty = true;

            // ensure there are no multiple filters on the same field, before removing it from the list
            if (numOfSameFilters <= 1) {

                selectedFilters = removeFomList(selectedFilters, filteredField)

                $('.selectedFilters').val(selectedFilters);

                if (selectedFilters.length <= 0) {
                    // since there are no filters, let's post the form to clear all filters except the sorting
                    // submit the form and reset the pagination
                    triggerSubmit();
                }

            }

            $('[data-filter-field="' + filteredField + '"]').parent().removeClass('disabled');

            $(this).parents('.form-group').remove();

        });
    }

    function toggleFilterBox(showOrHide) {
        if (showOrHide) {
            $('.filters').show();
        } else {
            $('.filters').hide();
        }
    }

    // trigger a click of the 'filter' button
    function triggerSubmit () {

        // click the button
        $('.filters').submit();

    }

});
<commit_msg>fix group actions<commit_after>linz.addLoadEvent(function () {

    var filtersAreDirty = false;

    /* FILTERS */

    if ($('.selectedFilters').length && $('.selectedFilters').val().length > 0) {
        toggleFilterBox('show');
    }

    $('[data-sort-field]').click(function () {

        var sort = $('.selectedSort').val(),
            sortField = $(this).attr('data-sort-field');

        if (sort === sortField) {
            sortField = '-' + sortField;
        }

        // update hidden sort field in the filter form
        $('.selectedSort').val(sortField);

        filtersAreDirty = true;

        triggerSubmit();

        return true;

    });

    $('form.filters').on('submit', function (event) {

        var isValid = $('.filters')[0].checkValidity();

        if (!isValid) {
            return false;
        }

        // Disable the submit button.
        $('.filters').find(':submit').attr('disabled', true);
        $('.filters').find('.btn[data-toggle="dropdown"]').attr('disabled', true);

        // Add the spinner.
        $(this).find(':submit').append(' ');

    });

    $('form.filters button[type="submit"]').click(function (event) {

        // reset the pagination if required
        if (filtersAreDirty || event.isTrigger === undefined) {
            $('input.page').val(1);
        }

    });

    function renderFilter (filter) {

        var filterText = filter.html(),
            filterVal = filter.attr('data-filter-field'),
            filterFormControl = filter.siblings('.controlField').children().html(),
            aFilters;

        var content = document.querySelector('#filter').content.cloneNode(true);

        // update template with filter content
        content.querySelector('.filter-name').textContent = filterText;
        content.querySelector('.filter-control').innerHTML = content.querySelector('.filter-control').innerHTML + filterFormControl;
        content.querySelector('.fa-times').setAttribute('data-filter-field', filter.attr('data-filter-field'));
        document.querySelector('.filter-list').appendChild(document.importNode(content, true));

        // determine if a multiselect was added to the dom, if so, apply the plugin
        $('.multiselect', $('.filter-list').children().last()).multiselect({
            buttonContainer: '
'
        });

        // hide dropdown for 'Add filter'
        filter.parents('.dropdown').removeClass('open');

        var selectedFilters = $('.selectedFilters').val();

        if (selectedFilters) {
            aFilters = $('.selectedFilters').val().split();
        } else {
            aFilters = [];
        }

        // only add the filter once
        if (aFilters.indexOf(filterVal) < 0) {
            aFilters.push(filterVal);
        }

        $('.selectedFilters').val(aFilters.join());

        filtersAreDirty = true;

        toggleFilterBox('show');

        assignRemoveButton();
        linz.loadDatepicker();

        return false;

    }

    function doesFilterExist (name) {

        return $('.filter-list').children().find('input[name^=' + name + ']', 'select[name^=' + name + ']').length > 0;

    }

    $('.control-addFilter').click(function () {

        if ($(this).parent().is('.disabled')) {
            return;
        }

        return renderFilter($(this));

    });

    // Handle once filters.
    (function () {

        var onceFilters = $('a[data-filter-once="true"]');

        onceFilters.on('click', function () {
            return $(this).parent().addClass('disabled');
        });

    })();

    // Render alwaysOn filters.
    (function () {

        var alwaysOnFilters = $('a[data-filter-alwayson="true"]'),
            disabled = [];

        alwaysOnFilters.each(function (index) {

            if ($(this).attr('data-filter-once') === 'true') {

                if (!$('.filter-list [data-filter-field="' + $(this).attr('data-filter-field') + '"]').length) {
                    renderFilter($(this));
                }

                $(this).remove();

                return $('.filter-list [data-filter-field="' + $(this).attr('data-filter-field') + '"]').css('visibility', 'hidden');

            }

            if(!doesFilterExist($(this).attr('data-filter-field'))) {
                renderFilter($(this));
            }

            return $('.filter-list [data-filter-field="' + $(this).attr('data-filter-field') + '"]').slice(0,1).css('visibility', 'hidden');

        });

        var filterBtn = $('.addFilterBtn');

        if (!filterBtn.find('.control-addFilter').length) {
            filterBtn.remove();
        }

    })();

    assignRemoveButton();

    /* PAGINATION */

    $('select.pagination').change(function () {
        $('input.page').val($(this).val());
        triggerSubmit();
    });

    /* PAGE SIZE */

    $('select.pagination-size').change(function () {
        $('input.pageSize').val($(this).val());
        filtersAreDirty = true;
        triggerSubmit();
    });

    /* GROUP ACTIONS */

    $('input[data-linz-control="checked-all"]').click(function () {

        var isChecked = $(this).is(':checked');

        $('input[data-linz-control="checked-record"]').prop('checked',isChecked);

    });

    // bind event for check-all checkbox to show group action buttons
    $('input[data-linz-control="checked-all"]').click(function () {

        if ($(this).is(':checked')) {
            return $('.group-actions').removeClass('hidden');
        }

        $('.group-actions').addClass('hidden');

    });

    // bind event to checkboxes to show group action buttons when checked
    $('input[data-linz-control="checked-record"]').click(function () {

        if ($(this).is(':checked')) {
            return $('.group-actions').removeClass('hidden');
        }

        // check if any of the other checkboxes are checked
        if ($('input[data-linz-control="checked-record"]:checked').length) {
            return;
        }

        // since none are checked, let's close group action buttons
        $('.group-actions').addClass('hidden');

    });

    // We know the page has loaded at this point, so we can re-enable the modals.
    $('[data-linz-control="export"], [data-linz-control="group-action"], [data-linz-control="record-action"]').removeClass('disabled');

    // bind group action buttons
    $('[data-linz-control="group-action"]').click(function () {

        var queryObj = $(this),
            url = queryObj.attr('href');

        // Bind model save button and update the selected ids to modal form.
        $('#groupActionModal').modal().load(url, function () {

            var selectedIDs = [],
                _this = this;

            $('input[data-linz-control="checked-record"]:checked').each(function () {
                selectedIDs.push($(this).val());
            });

            // add selected IDs to hidden field
            $(_this).find('[data-group-action="ids"]').val(selectedIDs);

            // add form validation
            $(_this).find('form[data-linz-validation="true"]').bootstrapValidator({});

        });

       return false;
    });

    // bind record action buttons
    $('[data-linz-control="record-action"]').click(function () {

        var queryObj = $(this),
            url = queryObj.attr('href');

        $('#recordActionModal').modal().load(url);

       return false;

    });

    // bind model save button
    $('#recordActionModal').on('shown.bs.modal', function (e) {

        var _this = this;

        // add form validation
        $(_this).find('form[data-linz-validation="true"]').bootstrapValidator({});

    });

    // bind export button
    $('[data-linz-control="export"]').click(function (event) {

        // stop the href navigation
        event.preventDefault();

        var queryObj = $(this),
            url = queryObj.attr('href'),
            useModal = (queryObj.attr('data-target') === "#exportModal");

        if (useModal) {

            var modal = $('#exportModal');
            modal.attr('data-linz-export-url', url);
            modal.modal();

            return false;

        }

        // retrieve the ids
        var selectedIds = $('input[data-linz-control="checked-record"]:checked').map(function () {
            return $(this).val();
        }).get();

        // construct the form
        var form = document.createElement('form');
        form.method = 'post';
        form.action = url;

        var inputFilters = document.createElement('input');
        inputFilters.type = 'hidden';
        inputFilters.name = 'filters';
        inputFilters.value = $('#modelQuery').html();

        var inputSelectedIds = document.createElement('input')
        inputSelectedIds.type = 'hidden';
        inputSelectedIds.name = 'selectedIds';
        inputSelectedIds.value = selectedIds.join(',');

        var inputModelName = document.createElement('input');
        inputModelName.type = 'hidden';
        inputModelName.name = 'modelName';
        inputModelName.value = $('[data-linz-model]').attr('data-linz-model');

        var tokenInput = document.createElement('input');
        tokenInput.type = 'hidden';
        tokenInput.name = '_csrf';
        tokenInput.value = $('meta[name=csrf-token]').attr('content');

        // append to the form
        form.appendChild(inputFilters);
        form.appendChild(inputSelectedIds);
        form.appendChild(inputModelName);
        form.appendChild(tokenInput);

        // append form to body
        document.body.appendChild(form);

        // submit the form
        form.submit();

        return false;

    });

    function removeFomList (list, value, separator) {
        separator = separator || ",";
        var values = list.split(separator);

        for(var i = 0 ; i < values.length ; i++) {
            if(values[i] === value) {
                values.splice(i, 1);
                return values.join(separator);
            }
        }

        return list;

    }

    function assignRemoveButton (queryObj) {

        // remove all event listener
        $('.fa-times').unbind();

        // re-assign listeners including any new ones added to DOM after page load
        $('.fa-times').click(function () {

            var filteredField = $(this).attr('data-filter-field'),
                selectedFilters = $('.selectedFilters').val(),
                numOfSameFilters = $('.fa-times[data-filter-field=' + filteredField + ']').length;

            filtersAreDirty = true;

            // ensure there are no multiple filters on the same field, before removing it from the list
            if (numOfSameFilters <= 1) {

                selectedFilters = removeFomList(selectedFilters, filteredField)

                $('.selectedFilters').val(selectedFilters);

                if (selectedFilters.length <= 0) {
                    // since there are no filters, let's post the form to clear all filters except the sorting
                    // submit the form and reset the pagination
                    triggerSubmit();
                }

            }

            $('[data-filter-field="' + filteredField + '"]').parent().removeClass('disabled');

            $(this).parents('.form-group').remove();

        });
    }

    function toggleFilterBox(showOrHide) {
        if (showOrHide) {
            $('.filters').show();
        } else {
            $('.filters').hide();
        }
    }

    // trigger a click of the 'filter' button
    function triggerSubmit () {

        // click the button
        $('.filters').submit();

    }

});
<|endoftext|>


<commit_before>function $(s) {
    return document.querySelector(s);
}

/**
 * Game of Life simulation and display.
 * @param {HTMLCanvasElement} canvas Render target
 * @param {number} [scale] Size of each cell in pixels (power of 2)
 * @param {number} [p] Starting probability of a cell being alive
 */
function GOL(canvas, scale, p) {
    var gl = this.gl = Igloo.getContext(canvas);
    if (gl == null) {
        alert('Could not initialize WebGL!');
        throw new Error('No WebGL');
    }
    scale = scale || 4;
    var w = canvas.width, h = canvas.height;
    this.viewsize = vec2(w, h);
    this.statesize = vec2(w / scale, h / scale);
    this.lasttick = GOL.now();
    this.fps = 0;

    gl.disable(gl.DEPTH_TEST);
    this.programs = {
        copy: new Igloo.Program(gl, 'glsl/quad.vert', 'glsl/copy.frag'),
        gol: new Igloo.Program(gl, 'glsl/quad.vert', 'glsl/gol.frag')
    };
    this.buffers = {
        quad: new Igloo.Buffer(gl, new Float32Array([
                -1, -1, 1, -1, -1, 1, 1, 1
        ]))
    };
    this.textures = {
        a: this.texture(),
        b: this.texture()
    };
    this.framebuffers = {
        step: gl.createFramebuffer()
    };
    this.state = 'a';
    this.fillRandom(p == null ? 0.5 : p);
}

/**
 * @returns {number} The epoch in integer seconds
 */
GOL.now = function() {
    return Math.floor(Date.now() / 1000);
};

/**
 * @returns {WebGLTexture} A texture suitable for bearing Life state
 */
GOL.prototype.texture = function() {
    var gl = this.gl;
    var tex = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, tex);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA,
                  this.statesize.x, this.statesize.y,
                  0, gl.RGBA, gl.UNSIGNED_BYTE, null);
    return tex;
};

/**
 * Set the entire simulation state at once.
 * @param {Uint8Array} state An RGBA array
 * @returns {GOL} this
 */
GOL.prototype.fill = function(state) {
    var gl = this.gl;
    gl.bindTexture(gl.TEXTURE_2D, this.textures[this.state]);
    gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0,
                     this.statesize.x, this.statesize.y,
                     gl.RGBA, gl.UNSIGNED_BYTE, state);
    return this;
};

/**
 * Fill the entire state with random values.
 * @param {number} [p] Chance of a cell being alive (0.0 to 1.0)
 * @returns {GOL} this
 */
GOL.prototype.fillRandom = function(p) {
    var gl = this.gl, fs = 4;
    var rand = new Uint8Array(this.statesize.x * this.statesize.y * fs);
    for (var i = 0; i < rand.length; i += fs) {
        var v = Math.random() < p ? 255 : 0;
        rand[i + 0] = rand[i + 1] = rand[i + 2] = v;
        rand[i + 3] = 255;
    }
    this.fill(rand);
    return this;
};

/**
 * @returns {string} The name of the non-current state texture
 */
GOL.prototype.other = function() {
    return this.state == 'a' ? 'b' : 'a';
};

/**
 * Step the Game of Life state on the GPU without rendering anything.
 * @returns {GOL} this
 */
GOL.prototype.step = function() {
    if (GOL.now() != this.lasttick) {
        $('.fps').innerHTML = this.fps + ' FPS';
        this.lasttick = GOL.now();
        this.fps = 0;
    } else {
        this.fps++;
    }
    var gl = this.gl;
    gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffers.step);
    gl.bindTexture(gl.TEXTURE_2D, this.textures[this.other()]);
    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
                            gl.TEXTURE_2D, this.textures[this.other()], 0);
    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, this.textures[this.state]);
    gl.viewport(0, 0, this.statesize.x, this.statesize.y);
    this.programs.gol.use()
        .attrib('quad', this.buffers.quad, 2)
        .uniform('state', 0, true)
        .uniform('scale', this.statesize)
        .draw(gl.TRIANGLE_STRIP, 4);
    this.state = this.other();
    return this;
};

/**
 * Render the Game of Life state stored on the GPU.
 * @returns {GOL} this
 */
GOL.prototype.draw = function() {
    var gl = this.gl;
    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    gl.bindTexture(gl.TEXTURE_2D, this.textures[this.state]);
    gl.viewport(0, 0, this.viewsize.x, this.viewsize.y);
    this.programs.copy.use()
        .attrib('quad', this.buffers.quad, 2)
        .uniform('state', 0, true)
        .uniform('scale', this.viewsize)
        .draw(gl.TRIANGLE_STRIP, 4);
    return this;
};

/**
 * Iterate the Game of Life state and then draw.
 * @returns {GOL} this
 */
GOL.prototype.all = function() {
    this.step();
    this.draw();
    return this;
};

/**
 * Reset the state to random values.
 * @param {number} [p] Chance of a cell being alive (0.0 to 1.0)
 * @returns {GOL} this
 */
GOL.prototype.reset = function(p) {
    this.fill(this.state, p == null ? 0.5 : p);
    return this;
};

/**
 * Set the state at a specific position.
 * @param {number} x
 * @param {number} y
 * @param {boolean} state True/false for live/dead
 */
GOL.prototype.set = function(x, y, state) {
    var gl = this.gl,
        v = state * 255;
    gl.bindTexture(gl.TEXTURE_2D, this.textures[this.state]);
    gl.texSubImage2D(gl.TEXTURE_2D, 0, x, y, 1, 1,
                     gl.RGBA, gl.UNSIGNED_BYTE,
                     new Uint8Array([v, v, v, 255]));
};

/* Initialize everything. */
var gol = null;
window.addEventListener('load', function() {
    var canvas = $('#life');
    gol = new GOL(canvas).draw();
    setInterval(function(){
        gol.all();
    }, 60);
    canvas.addEventListener('click', function() {
        gol.reset();
    });
});
<commit_msg>Add note about LUMINANCE.<commit_after>function $(s) {
    return document.querySelector(s);
}

/**
 * Game of Life simulation and display.
 * @param {HTMLCanvasElement} canvas Render target
 * @param {number} [scale] Size of each cell in pixels (power of 2)
 * @param {number} [p] Starting probability of a cell being alive
 */
function GOL(canvas, scale, p) {
    var gl = this.gl = Igloo.getContext(canvas);
    if (gl == null) {
        alert('Could not initialize WebGL!');
        throw new Error('No WebGL');
    }
    scale = scale || 4;
    var w = canvas.width, h = canvas.height;
    this.viewsize = vec2(w, h);
    this.statesize = vec2(w / scale, h / scale);
    this.lasttick = GOL.now();
    this.fps = 0;

    gl.disable(gl.DEPTH_TEST);
    this.programs = {
        copy: new Igloo.Program(gl, 'glsl/quad.vert', 'glsl/copy.frag'),
        gol: new Igloo.Program(gl, 'glsl/quad.vert', 'glsl/gol.frag')
    };
    this.buffers = {
        quad: new Igloo.Buffer(gl, new Float32Array([
                -1, -1, 1, -1, -1, 1, 1, 1
        ]))
    };
    this.textures = {
        a: this.texture(),
        b: this.texture()
    };
    this.framebuffers = {
        step: gl.createFramebuffer()
    };
    this.state = 'a';
    this.fillRandom(p == null ? 0.5 : p);
}

/**
 * @returns {number} The epoch in integer seconds
 */
GOL.now = function() {
    return Math.floor(Date.now() / 1000);
};

/**
 * @returns {WebGLTexture} A texture suitable for bearing Life state
 */
GOL.prototype.texture = function() {
    /* LUMINANCE textures would have been preferable (one byte per
     * cell), but, unlike RGBA, LUMINANCE is not a complete color
     * attachment for a framebuffer.
     */
    var gl = this.gl;
    var tex = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, tex);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA,
                  this.statesize.x, this.statesize.y,
                  0, gl.RGBA, gl.UNSIGNED_BYTE, null);
    return tex;
};

/**
 * Set the entire simulation state at once.
 * @param {Uint8Array} state An RGBA array
 * @returns {GOL} this
 */
GOL.prototype.fill = function(state) {
    var gl = this.gl;
    gl.bindTexture(gl.TEXTURE_2D, this.textures[this.state]);
    gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0,
                     this.statesize.x, this.statesize.y,
                     gl.RGBA, gl.UNSIGNED_BYTE, state);
    return this;
};

/**
 * Fill the entire state with random values.
 * @param {number} [p] Chance of a cell being alive (0.0 to 1.0)
 * @returns {GOL} this
 */
GOL.prototype.fillRandom = function(p) {
    var gl = this.gl, fs = 4;
    var rand = new Uint8Array(this.statesize.x * this.statesize.y * fs);
    for (var i = 0; i < rand.length; i += fs) {
        var v = Math.random() < p ? 255 : 0;
        rand[i + 0] = rand[i + 1] = rand[i + 2] = v;
        rand[i + 3] = 255;
    }
    this.fill(rand);
    return this;
};

/**
 * @returns {string} The name of the non-current state texture
 */
GOL.prototype.other = function() {
    return this.state == 'a' ? 'b' : 'a';
};

/**
 * Step the Game of Life state on the GPU without rendering anything.
 * @returns {GOL} this
 */
GOL.prototype.step = function() {
    if (GOL.now() != this.lasttick) {
        $('.fps').innerHTML = this.fps + ' FPS';
        this.lasttick = GOL.now();
        this.fps = 0;
    } else {
        this.fps++;
    }
    var gl = this.gl;
    gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffers.step);
    gl.bindTexture(gl.TEXTURE_2D, this.textures[this.other()]);
    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
                            gl.TEXTURE_2D, this.textures[this.other()], 0);
    gl.bindTexture(gl.TEXTURE_2D, this.textures[this.state]);
    gl.viewport(0, 0, this.statesize.x, this.statesize.y);
    this.programs.gol.use()
        .attrib('quad', this.buffers.quad, 2)
        .uniform('state', 0, true)
        .uniform('scale', this.statesize)
        .draw(gl.TRIANGLE_STRIP, 4);
    this.state = this.other();
    return this;
};

/**
 * Render the Game of Life state stored on the GPU.
 * @returns {GOL} this
 */
GOL.prototype.draw = function() {
    var gl = this.gl;
    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    gl.bindTexture(gl.TEXTURE_2D, this.textures[this.state]);
    gl.viewport(0, 0, this.viewsize.x, this.viewsize.y);
    this.programs.copy.use()
        .attrib('quad', this.buffers.quad, 2)
        .uniform('state', 0, true)
        .uniform('scale', this.viewsize)
        .draw(gl.TRIANGLE_STRIP, 4);
    return this;
};

/**
 * Iterate the Game of Life state and then draw.
 * @returns {GOL} this
 */
GOL.prototype.all = function() {
    this.step();
    this.draw();
    return this;
};

/**
 * Reset the state to random values.
 * @param {number} [p] Chance of a cell being alive (0.0 to 1.0)
 * @returns {GOL} this
 */
GOL.prototype.reset = function(p) {
    this.fill(this.state, p == null ? 0.5 : p);
    return this;
};

/**
 * Set the state at a specific position.
 * @param {number} x
 * @param {number} y
 * @param {boolean} state True/false for live/dead
 */
GOL.prototype.set = function(x, y, state) {
    var gl = this.gl,
        v = state * 255;
    gl.bindTexture(gl.TEXTURE_2D, this.textures[this.state]);
    gl.texSubImage2D(gl.TEXTURE_2D, 0, x, y, 1, 1,
                     gl.RGBA, gl.UNSIGNED_BYTE,
                     new Uint8Array([v, v, v, 255]));
};

/* Initialize everything. */
var gol = null;
window.addEventListener('load', function() {
    var canvas = $('#life');
    gol = new GOL(canvas).draw();
    setInterval(function(){
        gol.all();
    }, 60);
    canvas.addEventListener('click', function() {
        gol.reset();
    });
});
<|endoftext|>


<commit_before>// js/reservation.js
(function ( $ ) {
    function ReservationSlotsTableManager( target_table, table_data ) {
        this.table = target_table;
        this.data = table_data;
        this.selections = [];
        this.created_tr = [];
    }

    ReservationSlotsTableManager.prototype.makeTable = function () {
        let tbody = $( this.table ).find( 'tbody' ).get( 0 );

        let boats = this.data.boats;
        for ( let i = 0; i < boats.length; i++ ) {
            let boat = boats[i];
            let label = boat.boat_name + ' - ' + boat.boat_type;
            let tr_str = '
' + label + '
';
            let tr = $( tr_str ).appendTo( tbody ).get( 0 );
            this.created_tr.push( tr );
            let slots = boat.slots;
            for ( let j = 0; j < slots.length; j++ ) {
                let slot = slots[j];
                let tooltip_str = slot.start_time + '-' + slot.end_time;
                let td_str = '	';
                let td = $( td_str ).appendTo( tr ).get( 0 );
                $( td ).tooltip({
                    container: 'body',
                    placement: 'top'
                });
                $( td ).data( 'slot', slot );
                $( td ).click( this.cellClickHandler.bind( this ));
            }
        }
    };

    ReservationSlotsTableManager.prototype.destroyTable = function () {
        for (let i = 0; i < this.created_tr.length; i++) {
            $( this.created_tr[i] ).remove();
        }
        this.created_tr = [];
        this.selections = [];
    };

    ReservationSlotsTableManager.prototype.cellClickHandler = function ( event ) {
        let slot = $( event.target ).data( 'slot' );
        let selections_index = this.selections.indexOf( slot );
        if ( selections_index === -1 ) {
            this.selections.push( slot );
            $( event.target ).addClass( 'info' );
        } else {
            this.selections.splice( selections_index, 1 );
            $( event.target ).removeClass( 'info' );
        }
        console.log( 'Cell click handler!' );
        console.log( 'selections = ' + this.selections );
    };

    function reservationSlotsQueryButtonClickHandler( event ) {
        var year = $( '#reservation_slots_query_year' ).val();
        var month = $( '#reservation_slots_query_month' ).val();
        var day = $( '#reservation_slots_query_day' ).val();

        var url = '/reservation_slots/json/date/' + year + '/' + month + '/' + day;

        $.ajax({
            url: url,
            dataType: 'json',
            method: 'GET'
        }).done( function ( data ) {
            $( '#reservation_slots_date' ).text( data.date );

            let table = $( '#reservation_slots_table' ).get( 0 );
            let manager = $( table ).data( 'manager' );
            if ( manager !== undefined ) {
                manager.destroyTable();
                $( table ).removeData( 'manager' );
            }
            manager = new ReservationSlotsTableManager( table, data );
            $( table ).data( 'manager', manager );
            manager.makeTable();
        }).fail( function () {
            console.log( 'Failed ajax reqeust!' );
        });
    }

    function saveReservationSlotsButtonClickHandler( event ) {
        let manager = $( '#reservation_slots_table' ).data( 'manager' );
        // sort the selections based on slot.start_time
        manager.selections.sort( function ( a, b ) {
            if ( a.start_time  b.start_time ) {
                return 1;
            }
            return 0;
        });
        // for now, we assume selections are contiguous (add validation later)
        let reserved_start_time = manager.selections[0].start_time;
        let reserved_end_time = manager.selections[manager.selections.length - 1].end_time;
        let reserved_num_hours = ( manager.selections.length * 30 ) / 60;
        let reserved_date = manager.data.date;
        let slot_ids = [];
        for ( let i = 0; i < manager.selections.length; i++ ) {
            slot_ids.push( manager.selections[i].slot_id );
        }
        let reserved_slots = slot_ids.join( ',' );

        $( '#reserved_slots' ).val( reserved_slots );

        $( '#reserved_date' ).text( reserved_date );
        $( '#reserved_start_time' ).text( reserved_start_time );
        $( '#reserved_end_time' ).text( reserved_end_time );
        $( '#reserved_num_hours' ).text( reserved_num_hours );

        $( '#reservation_slots_modal' ).modal( 'hide' );
    }

    $( document ).ready( function () {
        $( '#btn_reservation_slots_query' )
            .click( reservationSlotsQueryButtonClickHandler );
        $( '#btn_save_reservation_slots' )
            .click( saveReservationSlotsButtonClickHandler );
    });
})( jQuery );
<commit_msg>Mark unavailable slots in reservation slots table<commit_after>// js/reservation.js
(function ( $ ) {
    function ReservationSlotsTableManager( target_table, table_data ) {
        this.table = target_table;
        this.data = table_data;
        this.selections = [];
        this.created_tr = [];
    }

    ReservationSlotsTableManager.prototype.makeTable = function () {
        let tbody = $( this.table ).find( 'tbody' ).get( 0 );

        let boats = this.data.boats;
        for ( let i = 0; i < boats.length; i++ ) {
            let boat = boats[i];
            let label = boat.boat_name + ' - ' + boat.boat_type;
            let tr_str = '
' + label + '
';
            let tr = $( tr_str ).appendTo( tbody ).get( 0 );
            this.created_tr.push( tr );
            let slots = boat.slots;
            for ( let j = 0; j < slots.length; j++ ) {
                let slot = slots[j];
                let tooltip_str = slot.start_time + '-' + slot.end_time;
                let td_str = '	';
                let td = $( td_str ).appendTo( tr ).get( 0 );
                $( td ).tooltip({
                    container: 'body',
                    placement: 'top'
                });
                $( td ).data( 'slot', slot );
                $( td ).click( this.cellClickHandler.bind( this ));
                if ( slot.available === 0 ) {
                    $( td ).addClass( 'danger' );
                }
            }
        }
    };

    ReservationSlotsTableManager.prototype.destroyTable = function () {
        for (let i = 0; i < this.created_tr.length; i++) {
            $( this.created_tr[i] ).remove();
        }
        this.created_tr = [];
        this.selections = [];
    };

    ReservationSlotsTableManager.prototype.cellClickHandler = function ( event ) {
        let slot = $( event.target ).data( 'slot' );

        if ( slot.available === 0 ) {
            return;
        }

        let selections_index = this.selections.indexOf( slot );
        if ( selections_index === -1 ) {
            this.selections.push( slot );
            $( event.target ).addClass( 'info' );
        } else {
            this.selections.splice( selections_index, 1 );
            $( event.target ).removeClass( 'info' );
        }
        console.log( 'Cell click handler!' );
        console.log( 'selections = ' + this.selections );
    };

    function reservationSlotsQueryButtonClickHandler( event ) {
        var year = $( '#reservation_slots_query_year' ).val();
        var month = $( '#reservation_slots_query_month' ).val();
        var day = $( '#reservation_slots_query_day' ).val();

        var url = '/reservation_slots/json/date/' + year + '/' + month + '/' + day;

        $.ajax({
            url: url,
            dataType: 'json',
            method: 'GET'
        }).done( function ( data ) {
            $( '#reservation_slots_date' ).text( data.date );

            let table = $( '#reservation_slots_table' ).get( 0 );
            let manager = $( table ).data( 'manager' );
            if ( manager !== undefined ) {
                manager.destroyTable();
                $( table ).removeData( 'manager' );
            }
            manager = new ReservationSlotsTableManager( table, data );
            $( table ).data( 'manager', manager );
            manager.makeTable();
        }).fail( function () {
            console.log( 'Failed ajax reqeust!' );
        });
    }

    function saveReservationSlotsButtonClickHandler( event ) {
        let manager = $( '#reservation_slots_table' ).data( 'manager' );
        // sort the selections based on slot.start_time
        manager.selections.sort( function ( a, b ) {
            if ( a.start_time  b.start_time ) {
                return 1;
            }
            return 0;
        });
        // for now, we assume selections are contiguous (add validation later)
        let reserved_start_time = manager.selections[0].start_time;
        let reserved_end_time = manager.selections[manager.selections.length - 1].end_time;
        let reserved_num_hours = ( manager.selections.length * 30 ) / 60;
        let reserved_date = manager.data.date;
        let slot_ids = [];
        for ( let i = 0; i < manager.selections.length; i++ ) {
            slot_ids.push( manager.selections[i].slot_id );
        }
        let reserved_slots = slot_ids.join( ',' );

        $( '#reserved_slots' ).val( reserved_slots );

        $( '#reserved_date' ).text( reserved_date );
        $( '#reserved_start_time' ).text( reserved_start_time );
        $( '#reserved_end_time' ).text( reserved_end_time );
        $( '#reserved_num_hours' ).text( reserved_num_hours );

        $( '#reservation_slots_modal' ).modal( 'hide' );
    }

    $( document ).ready( function () {
        $( '#btn_reservation_slots_query' )
            .click( reservationSlotsQueryButtonClickHandler );
        $( '#btn_save_reservation_slots' )
            .click( saveReservationSlotsButtonClickHandler );
    });
})( jQuery );
<|endoftext|>


<commit_before>/*!
 * HoloDateWidget v0.1 ~ Copyright (c) 2013 Denis Rodin, http://galaxyard.com
 * Released under MIT license
 */

(function(){
    var defOptions = {
        onChange: function(val) {},
        defDate: new XDate(),
        locale: 'ru',
        dateFormat: 'dd/MM/yyyy',
        startYearOffset: -10,
        endYearOffset: +10
    };

    var HDW = function(el, options){
        this.element = typeof el == 'object' ? el : document.getElementById(el);
        this.options = extend(defOptions, options);
        XDate.defaultLocale = this.options.locale;
        this.date = this.options.defDate;
        var that = this, opt=that.options;

        if (opt.startYearOffset>=opt.endYearOffset) {
            opt.endYearOffset = opt.startYearOffset + 2;
        }
        that.startYear = that.date.getFullYear()+opt.startYearOffset;
        that.endYear = that.date.getFullYear()+opt.endYearOffset;

        this.element.readOnly = true;

        var hdw = document.createDocumentFragment();
        var dlg = newDiv('hdw-dialog hdw-theme', hdw);
        dlg.style.display = 'none';

        var btn = newDiv('hdw-btn theme', dlg);
        btn.innerText = 'OK';

        var title = newDiv('hdw-title theme', dlg);
        title.innerText = that.options.defDate.toString('ddd d MMMM, yyyy', that.options.locale);

        //day selector
        var daySel = newDiv('hdw-day-sel', dlg);
        newDiv('hdv-day-active theme', dlg);

        var scl =  newDiv('hdw-day-scl', daySel);
        var ul = newElement('ul','hdw-day-ul',scl);

        var li = newElement('li','hdw-day-li theme',ul);
        for (var i=1; i<32; ++i) {
            li = newElement('li','hdw-day-li theme',ul);
            li.innerText = i;
        }
        newElement('li','hdw-day-li theme',ul);

        //month selector
        var monthSel = newDiv('hdw-month-sel', dlg);
        newDiv('hdv-month-active theme', dlg);

        scl =  newDiv('hdw-month-scl', monthSel);
        ul = newElement('ul','hdw-month-ul',scl);

        li = newElement('li','hdw-month-li theme',ul);
        for (var i=1; i<13; ++i) {
            li = newElement('li','hdw-month-li theme',ul);
            li.innerText = i;
        }
        newElement('li','hdw-month-li theme',ul);

        //year selector
        var yearSel = newDiv('hdw-year-sel', dlg);
        newDiv('hdv-year-active theme', dlg);

        scl =  newDiv('hdw-year-scl', yearSel);
        ul = newElement('ul','hdw-year-ul',scl);

        li = newElement('li','hdw-year-li theme',ul);

        for (var i=that.startYear; i<=that.endYear; ++i) {
            li = newElement('li','hdw-year-li theme',ul);
            li.innerText = i;
        }
        newElement('li','hdw-year-li theme',ul);

        var ovl = newDiv('hdw-overlay', hdw);
        ovl.style.display = 'none';

        document.body.appendChild(hdw);

        this.dayScroll = new iScroll(daySel, {
            snap: 'li',
            momentum: true,
            hScrollbar: false,
            vScrollbar: false,
            hScroll: false,
            bounce: false,
            useTransition:true
        }, function(day) {
            that.date.setDate(day+1);
            updateDate(that.date, that, title);
        });

        this.monthScroll = new iScroll(monthSel, {
            snap: 'li',
            momentum: true,
            hScrollbar: false,
            vScrollbar: false,
            hScroll: false,
            bounce: false,
            useTransition:true
        }, function(month) {
            that.date.setMonth(month);
            updateDate(that.date, that, title);
        });

        this.yearScroll = new iScroll(yearSel, {
            snap: 'li',
            momentum: true,
            hScrollbar: false,
            vScrollbar: false,
            hScroll: false,
            bounce: false,
            useTransition:true
        }, function(yearNum) {
            that.date.setFullYear(that.startYear+yearNum);
            updateDate(that.date, that, title);
        });

        this.xbtn = XButton(btn, {dlg: dlg, ovl: ovl, hdw: this}, onOkBtnClick, 'btn-down');

        this.element.addEventListener('click', function() {
            //this.removeEventListener('click', arguments.callee, false );
            ovl.style.display = 'block';
            dlg.style.display = 'block';
            ovl.style.opacity = 0.5;
            dlg.style.opacity = 1;

            setDate(that, title);

            console.log(that.dayScroll.currPageY);
        }, false);
    };

    HDW.prototype = {
        destroy: function(){
            this.xbtn.destroy();
            this.xbtn = null;
            this.dayScroll.destroy();
            this.dayScroll = null;
            this.monthScroll.destroy();
            this.monthScroll = null;
            this.yearScroll.destroy();
            this.yearScroll = null;
        }
    };

    function onOkBtnClick(rel) {
        var dlg = rel.dlg;
        var ovl = rel.ovl;
        var hdw = rel.hdw;

        ovl.style.display = 'none';
        dlg.style.display = 'none';
        ovl.style.opacity = 0;
        dlg.style.opacity = 0;

        //set input date
        hdw.element.value = hdw.date.toString(hdw.options.dateFormat, hdw.options.locale);
        hdw.options.onChange(hdw.date);
    }

    function setDate(that, title) {
        var date = that.date;
        title.innerText = date.toString('ddd d MMMM, yyyy', that.options.locale);
        var day = date.getDate()-1;
        var month = date.getMonth();
        var yearNum = date.getFullYear() - that.startYear;

        that.dayScroll.refresh();
        that.dayScroll.scrollToPage(0, day, 0);

        that.monthScroll.refresh();
        that.monthScroll.scrollToPage(0, month, 0);

        that.yearScroll.refresh();
        that.yearScroll.scrollToPage(0, yearNum, 0);
    }

    function updateDate(date, that, title) {
        title.innerText = date.toString('ddd d MMMM, yyyy', that.options.locale);
    }

    function newDiv(className, parent) {
        var div = document.createElement('div');
        div.className=className;
        parent.appendChild(div);
        return div;
    }

    function newElement(tag, className, parent) {
        var el = document.createElement(tag);
        el.className=className;
        parent.appendChild(el);
        return el;
    }

    function extend(destination, source) {
        for (var k in source) {
            if (source.hasOwnProperty(k)) {
                destination[k] = source[k];
            }
        }
        return destination;
    }

    window.HDW = function(element, options) {
        return new HDW(element, options);
    };

}());<commit_msg>fix: initialize on input with value<commit_after>/*!
 * HoloDateWidget v0.1 ~ Copyright (c) 2013 Denis Rodin, http://galaxyard.com
 * Released under MIT license
 */

(function(){
    var defOptions = {
        onChange: function(val) {},
        defDate: new XDate(),
        locale: 'ru',
        dateFormat: 'dd/MM/yyyy',
        startYearOffset: -10,
        endYearOffset: +10
    };

    var HDW = function(el, options){
        this.element = typeof el == 'object' ? el : document.getElementById(el);
        this.options = extend(defOptions, options);
        XDate.defaultLocale = this.options.locale;

        if (this.element.value != null && this.element.value != '') {
            this.date = new XDate(this.element.value);
        } else {
            this.date = this.options.defDate;
        }

        var that = this, opt=that.options;

        if (opt.startYearOffset>=opt.endYearOffset) {
            opt.endYearOffset = opt.startYearOffset + 2;
        }
        that.startYear = that.date.getFullYear()+opt.startYearOffset;
        that.endYear = that.date.getFullYear()+opt.endYearOffset;

        this.element.readOnly = true;

        var hdw = document.createDocumentFragment();
        var dlg = newDiv('hdw-dialog hdw-theme', hdw);
        dlg.style.display = 'none';

        var btn = newDiv('hdw-btn theme', dlg);
        btn.innerText = 'OK';

        var title = newDiv('hdw-title theme', dlg);
        title.innerText = that.options.defDate.toString('ddd d MMMM, yyyy', that.options.locale);

        //day selector
        var daySel = newDiv('hdw-day-sel', dlg);
        newDiv('hdv-day-active theme', dlg);

        var scl =  newDiv('hdw-day-scl', daySel);
        var ul = newElement('ul','hdw-day-ul',scl);

        var li = newElement('li','hdw-day-li theme',ul);
        for (var i=1; i<32; ++i) {
            li = newElement('li','hdw-day-li theme',ul);
            li.innerText = i;
        }
        newElement('li','hdw-day-li theme',ul);

        //month selector
        var monthSel = newDiv('hdw-month-sel', dlg);
        newDiv('hdv-month-active theme', dlg);

        scl =  newDiv('hdw-month-scl', monthSel);
        ul = newElement('ul','hdw-month-ul',scl);

        li = newElement('li','hdw-month-li theme',ul);
        for (var i=1; i<13; ++i) {
            li = newElement('li','hdw-month-li theme',ul);
            li.innerText = i;
        }
        newElement('li','hdw-month-li theme',ul);

        //year selector
        var yearSel = newDiv('hdw-year-sel', dlg);
        newDiv('hdv-year-active theme', dlg);

        scl =  newDiv('hdw-year-scl', yearSel);
        ul = newElement('ul','hdw-year-ul',scl);

        li = newElement('li','hdw-year-li theme',ul);

        for (var i=that.startYear; i<=that.endYear; ++i) {
            li = newElement('li','hdw-year-li theme',ul);
            li.innerText = i;
        }
        newElement('li','hdw-year-li theme',ul);

        var ovl = newDiv('hdw-overlay', hdw);
        ovl.style.display = 'none';

        document.body.appendChild(hdw);

        this.dayScroll = new iScroll(daySel, {
            snap: 'li',
            momentum: true,
            hScrollbar: false,
            vScrollbar: false,
            hScroll: false,
            bounce: false,
            useTransition:true
        }, function(day) {
            that.date.setDate(day+1);
            updateDate(that.date, that, title);
        });

        this.monthScroll = new iScroll(monthSel, {
            snap: 'li',
            momentum: true,
            hScrollbar: false,
            vScrollbar: false,
            hScroll: false,
            bounce: false,
            useTransition:true
        }, function(month) {
            that.date.setMonth(month);
            updateDate(that.date, that, title);
        });

        this.yearScroll = new iScroll(yearSel, {
            snap: 'li',
            momentum: true,
            hScrollbar: false,
            vScrollbar: false,
            hScroll: false,
            bounce: false,
            useTransition:true
        }, function(yearNum) {
            that.date.setFullYear(that.startYear+yearNum);
            updateDate(that.date, that, title);
        });

        this.xbtn = XButton(btn, {dlg: dlg, ovl: ovl, hdw: this}, onOkBtnClick, 'btn-down');

        this.element.addEventListener('click', function() {
            //this.removeEventListener('click', arguments.callee, false );
            ovl.style.display = 'block';
            dlg.style.display = 'block';
            ovl.style.opacity = 0.5;
            dlg.style.opacity = 1;

            setDate(that, title);
        }, false);
    };

    HDW.prototype = {
        destroy: function(){
            this.xbtn.destroy();
            this.xbtn = null;
            this.dayScroll.destroy();
            this.dayScroll = null;
            this.monthScroll.destroy();
            this.monthScroll = null;
            this.yearScroll.destroy();
            this.yearScroll = null;
        }
    };

    function onOkBtnClick(rel) {
        var dlg = rel.dlg;
        var ovl = rel.ovl;
        var hdw = rel.hdw;

        ovl.style.display = 'none';
        dlg.style.display = 'none';
        ovl.style.opacity = 0;
        dlg.style.opacity = 0;

        //set input date
        hdw.element.value = hdw.date.toString(hdw.options.dateFormat, hdw.options.locale);
        hdw.options.onChange(hdw.date);
    }

    function setDate(that, title) {
        var date = that.date;
        title.innerText = date.toString('ddd d MMMM, yyyy', that.options.locale);
        var day = date.getDate()-1;
        var month = date.getMonth();
        var yearNum = date.getFullYear() - that.startYear;

        that.dayScroll.refresh();
        that.dayScroll.scrollToPage(0, day, 0);

        that.monthScroll.refresh();
        that.monthScroll.scrollToPage(0, month, 0);

        that.yearScroll.refresh();
        that.yearScroll.scrollToPage(0, yearNum, 0);
    }

    function updateDate(date, that, title) {
        title.innerText = date.toString('ddd d MMMM, yyyy', that.options.locale);
    }

    function newDiv(className, parent) {
        var div = document.createElement('div');
        div.className=className;
        parent.appendChild(div);
        return div;
    }

    function newElement(tag, className, parent) {
        var el = document.createElement(tag);
        el.className=className;
        parent.appendChild(el);
        return el;
    }

    function extend(destination, source) {
        for (var k in source) {
            if (source.hasOwnProperty(k)) {
                destination[k] = source[k];
            }
        }
        return destination;
    }

    window.HDW = function(element, options) {
        return new HDW(element, options);
    };

}());<|endoftext|>


<commit_before>// get view_events

/**
 * @api {get} /accounts/:account_id/view_events Get View Events
 * @apiName Get View Events
 * @apiGroup View Events
 * @apiVersion 1.0.0
 *
 * @apiDescription Get view events for an account - note that only view events that have been _processed_ will appear in the response
 *
 * @apiHeader {String} Content-Type Content-Type: application/json
 * @apiHeader {String} Authorization Authorization: Bearer access_token (see [Getting Access Tokens](https://support.brightcove.com/getting-access-tokens))
 *
 * @apiParam {Number} account_id a Video Cloud account ID
 * @apiParam (URL Parameters) {Number{1..100}} [limit=25] number of items to return
 * @apiParam (URL Parameters) {Number} [offset=0] number of videos to skip in the response
 * @apiParam (URL Parameters) {String="video_id","video_name","tracking_id","external_id","player_id","page_url","watched","time_watched","created_at","updated_at","is_synced","utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content"} [sort="created_at"] field to sort results by
 * @apiParam (URL Parameters) {String="video_id","video_name","tracking_id","external_id","player_id","page_url","watched","time_watched","created_at","updated_at","is_synced","utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content"} [fields="video_id,video_name,tracking_id,external_id,player_id,page_url,watched,time_watched,created_at,updated_at,is_synced"] fields to return for items (one or more as a comma-delimited list - by default, all fields are returned)
 * @apiParam (URL Parameters) {String="field==value"} [where] one or more field==value pairs to filter the results; fields supported are "video_id", "video_name", "tracking_id", "external_id", "player_id", "page_url", "watched", "time_watched", "created_at", "updated_at", "is_synced","utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content"

 * @apiParam (URL Parameters) {mixed} [from] Start time for the period covered by the report — epoch time in milliseconds or a date in the format `yyyy-mm-dd` (such as `2013-09-26`) or a relative date in d (days), h (hours), m (minutes), s (seconds) (such as -2d or -6h)
 * @apiParam (URL Parameters) {mixed} [to] End time for the period covered by the report — `now` or epoch time in milliseconds or a date in the format `yyyy-mm-dd` (such as `2013-09-26`) or a relative date in d (days), h (hours), m (minutes), s (seconds) (such as 2d or 6h)
 *
 * @apiParamExample {String} View Events Report Example:
 *     https://audience.api.brightcove.com/v1/accounts/1486906377/view_events?limit=10&fields=first_name&sort=video_name&where=video_id==1234567890&from=-30d&to=now
 *
 * @apiSuccess (200) {Number} count the total number of items
 * @apiSuccess (200) {Number} limit the limit for items in this request
 * @apiSuccess (200) {Number} offset the offset for items in this request
 * @apiSuccess (200) {Object[]} result array of result items
 * @apiSuccess (200) {String} result.created_at the date created
 * @apiSuccess (200) {String} result.page_url the url for the Brightcove player
 * @apiSuccess (200) {String} result.player_id the ID for the Brightcove player
 * @apiSuccess (200) {String} result.video_id the Video Cloud video id
 * @apiSuccess (200) {String} result.video_name the Video Cloud video name
 * @apiSuccess (200) {Number} result.watched the percentage of the video watched (current playhead position / video duration)
 * @apiSuccess (200) {Number} result.time_watched the seconds of the video watched
 *
 * @apiSuccessExample {json} Success Response:
 *    HTTP/1.1 200 OK
 *    {
 *        "count": 27,
 *        "limit": 25,
 *        "offset": 0,
 *        "result": [
 *            {
 *                "created_at": "2016-04-25T18:30:21.651Z",
 *                "page_url": "http://players.brightcove.net/1486906377/V1s6NOwRx_default/index.html?videoId=4842718056001",
 *                "player_id": "V1s6NOwRx",
 *                "time_watched": 2,
 *                "updated_at": "2016-04-25T18:30:21.651Z",
 *                "video_id": "4842718056001",
 *                "video_name": "Horses Heading to the Track",
 *                "watched": 19
 *            },
 *            {
 *                "created_at": "2016-04-25T18:31:55.071Z",
 *                "page_url": "http://players.brightcove.net/1486906377/BkgFuzyhg_default/index.html?videoId=4842718056001",
 *                "player_id": "BkgFuzyhg",
 *                "time_watched": 15,
 *                "updated_at": "2016-04-25T18:32:00.879Z",
 *                "video_id": "4842718056001",
 *                "video_name": "Horses Heading to the Track",
 *                "watched": 99
 *            }, ...
 *        ]
 *    }
 *
 *
 * @apiError (Error 4xx) {json} BAD_REQUEST_ERROR 400: Query parameters are invalid
 * @apiError (Error 4xx) {json} UNAUTHORIZED_ERROR 401: The access token is either absent, has expired, or is invalid
 * @apiError (Error 4xx) {json} RESOURCE_NOT_FOUND 404: The URL does not exist
 * @apiError (Error 4xx) {json} REQUEST_THROTTLED_ERROR 429: The user has exceeded the rate limiting policy
 * @apiError (Error 5xx) {json} INTERNAL_ERROR 500: An internal error has occurred
 * @apiError (Error 5xx) {json} GATEWAY_TIMEOUT_ERROR 504: The server timed out while fulfilling your request

 *
 * @apiErrorExample {json} 404 Error Response
 *     HTTP/1.1 404 Not Found
 *    [
 *        {
 *            "error_code": "UNAUTHORIZED_ERROR",
 *            "message": "Permission denied"
 *        }
 *    ]
 *
 *
 */
<commit_msg>update<commit_after>// get view_events

/**
 * @api {get} /accounts/:account_id/view_events Get View Events
 * @apiName Get View Events
 * @apiGroup View Events
 * @apiVersion 1.0.0
 *
 * @apiDescription Get view events for an account - note that only view events that have been _processed_ will appear in the response
 *
 * @apiHeader {String} Content-Type Content-Type: application/json
 * @apiHeader {String} Authorization Authorization: Bearer access_token (see [Getting Access Tokens](https://support.brightcove.com/getting-access-tokens))
 *
 * @apiParam {Number} account_id a Video Cloud account ID
 * @apiParam (URL Parameters) {Number{1..100}} [limit=25] number of items to return
 * @apiParam (URL Parameters) {Number} [offset=0] number of videos to skip in the response
 * @apiParam (URL Parameters) {String="video_id","video_name","tracking_id","external_id","player_id","page_url","watched","time_watched","created_at","updated_at","is_synced","utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content"} [sort="created_at"] field to sort results by
 * @apiParam (URL Parameters) {String="video_id","video_name","tracking_id","external_id","player_id","page_url","watched","time_watched","created_at","updated_at","is_synced","utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content"} [fields="video_id,video_name,tracking_id,external_id,player_id,page_url,watched,time_watched,created_at,updated_at,is_synced"] fields to return for items (one or more as a comma-delimited list - by default, all fields are returned)
 * @apiParam (URL Parameters) {String="field==value"} [where] one or more field==value pairs to filter the results; fields supported are "video_id", "video_name", "tracking_id", "external_id", "player_id", "page_url", "watched", "time_watched", "created_at", "updated_at", "is_synced","utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content"
 * @apiParam (URL Parameters) {mixed} [from] Start time for the period covered by the report — epoch time in milliseconds or a date in the format `yyyy-mm-dd` (such as `2013-09-26`) or a relative date in d (days), h (hours), m (minutes), s (seconds) (such as -2d or -6h)
 * @apiParam (URL Parameters) {mixed} [to] End time for the period covered by the report — `now` or epoch time in milliseconds or a date in the format `yyyy-mm-dd` (such as `2013-09-26`) or a relative date in d (days), h (hours), m (minutes), s (seconds) (such as 2d or 6h)
 *
 * @apiParamExample {String} View Events Report Example:
 *     https://audience.api.brightcove.com/v1/accounts/1486906377/view_events?limit=10&fields=first_name&sort=video_name&where=video_id==1234567890&from=-30d&to=now
 *
 * @apiSuccess (200) {Number} count the total number of items
 * @apiSuccess (200) {Number} limit the limit for items in this request
 * @apiSuccess (200) {Number} offset the offset for items in this request
 * @apiSuccess (200) {Object[]} result array of result items
 * @apiSuccess (200) {String} result.created_at the date created
 * @apiSuccess (200) {String} result.page_url the url for the Brightcove player
 * @apiSuccess (200) {String} result.player_id the ID for the Brightcove player
 * @apiSuccess (200) {String} result.video_id the Video Cloud video id
 * @apiSuccess (200) {String} result.video_name the Video Cloud video name
 * @apiSuccess (200) {Number} result.watched the percentage of the video watched (current playhead position / video duration)
 * @apiSuccess (200) {Number} result.time_watched the seconds of the video watched
 *
 * @apiSuccessExample {json} Success Response:
 *    HTTP/1.1 200 OK
 *    {
 *        "count": 27,
 *        "limit": 25,
 *        "offset": 0,
 *        "result": [
 *            {
 *                "created_at": "2016-04-25T18:30:21.651Z",
 *                "page_url": "http://players.brightcove.net/1486906377/V1s6NOwRx_default/index.html?videoId=4842718056001",
 *                "player_id": "V1s6NOwRx",
 *                "time_watched": 2,
 *                "updated_at": "2016-04-25T18:30:21.651Z",
 *                "video_id": "4842718056001",
 *                "video_name": "Horses Heading to the Track",
 *                "watched": 19
 *            },
 *            {
 *                "created_at": "2016-04-25T18:31:55.071Z",
 *                "page_url": "http://players.brightcove.net/1486906377/BkgFuzyhg_default/index.html?videoId=4842718056001",
 *                "player_id": "BkgFuzyhg",
 *                "time_watched": 15,
 *                "updated_at": "2016-04-25T18:32:00.879Z",
 *                "video_id": "4842718056001",
 *                "video_name": "Horses Heading to the Track",
 *                "watched": 99
 *            }, ...
 *        ]
 *    }
 *
 *
 * @apiError (Error 4xx) {json} BAD_REQUEST_ERROR 400: Query parameters are invalid
 * @apiError (Error 4xx) {json} UNAUTHORIZED_ERROR 401: The access token is either absent, has expired, or is invalid
 * @apiError (Error 4xx) {json} RESOURCE_NOT_FOUND 404: The URL does not exist
 * @apiError (Error 4xx) {json} REQUEST_THROTTLED_ERROR 429: The user has exceeded the rate limiting policy
 * @apiError (Error 5xx) {json} INTERNAL_ERROR 500: An internal error has occurred
 * @apiError (Error 5xx) {json} GATEWAY_TIMEOUT_ERROR 504: The server timed out while fulfilling your request

 *
 * @apiErrorExample {json} 404 Error Response
 *     HTTP/1.1 404 Not Found
 *    [
 *        {
 *            "error_code": "UNAUTHORIZED_ERROR",
 *            "message": "Permission denied"
 *        }
 *    ]
 *
 *
 */
<|endoftext|>


<commit_before>/* global bag, $*/
/* global escapeHtml, toTitleCase, formatDate, known_companies, transfer_marble, record_company*/
/* exported build_marble, record_company, build_user_panels, build_company_panel, build_notification, populate_users_marbles*/

// =================================================================================
//	UI Building
// =================================================================================
//build a marble
function build_marble(marble){
	var html = '';
	var colorClass = '';
	var size = 'largeMarble';

	marble.name = escapeHtml(marble.name);
	marble.color = escapeHtml(marble.color);
	marble.owner.username = escapeHtml(marble.owner.username);
	marble.owner.company = escapeHtml(marble.owner.company);
	var full_owner = build_full_owner(marble.owner.username, marble.owner.company);

	console.log('[ui] building marble: ', marble.color, full_owner, marble.name.substring(0,4) + '...');
	if(marble.size == 16) size = 'smallMarble';
	if(marble.color) colorClass = marble.color.toLowerCase() + 'bg';

	html += '';

	$('.marblesWrap[full_owner="' + full_owner +'"]').find('.innerMarbleWrap').prepend(html);
	$('.marblesWrap[full_owner="' + full_owner +'"]').find('.noMarblesMsg').hide();
	return html;
}

//redraw the user's marbles
function populate_users_marbles(msg){
	var full_owner = build_full_owner(msg.username, msg.company);

	//reset
	console.log('[ui] clearing marbles for user ' + full_owner);
	$('.marblesWrap[full_owner="' + full_owner +'"]').find('.innerMarbleWrap').html('');
	$('.marblesWrap[full_owner="' + full_owner +'"]').find('.noMarblesMsg').show();

	for(var i in msg.marbles){
		build_marble(msg.marbles[i]);
	}
}

//crayp resize - dsh to do, dynamic one
function size_user_name(name){
	var style = '';
	if(name.length >= 10) style = 'font-size: 22px;';
	if(name.length >= 15) style = 'font-size: 18px;';
	if(name.length >= 20) style = 'font-size: 15px;';
	if(name.length >= 25) style = 'font-size: 11px;';
	return style;
}

//build all user panels
function build_user_panels(data){
	var full_owner = '';

	//reset
	console.log('[ui] clearing all user panels');
	$('.ownerWrap').html('');
	for(var x in known_companies){
		known_companies[x].count = 0;
		known_companies[x].visible = 0;							//reset visible counts
	}

	for(var i in data){
		var html = '';
		var colorClass = '';
		data[i].username = escapeHtml(data[i].username);
		data[i].company = escapeHtml(data[i].company);
		record_company(data[i].company);
		known_companies[data[i].company].count++;
		known_companies[data[i].company].visible++;

		full_owner = build_full_owner(data[i].username, data[i].company);
		console.log('[ui] building owner panel ' + full_owner);

		html += '
';
		html +=		'
';
		html +=			toTitleCase(data[i].username);
		html +=			'';
		html +=		'
';
		html +=		'

';
		html +=		'
No marbles
';
		html +=	'
';

		$('.companyPanel[company="' + data[i].company + '"]').find('.ownerWrap').append(html);
		$('.companyPanel[company="' + data[i].company + '"]').find('.companyVisible').html(known_companies[data[i].company].visible);
		$('.companyPanel[company="' + data[i].company + '"]').find('.companyCount').html(known_companies[data[i].company].count);
	}

	//drag and drop marble
	$('.innerMarbleWrap').sortable({connectWith: '.innerMarbleWrap', items: 'span'}).disableSelection();
	$('.innerMarbleWrap').droppable({drop:
		function( event, ui ) {
			var dragged_user = $(ui.draggable).attr('username').toLowerCase();
			var dropped_user = $(event.target).parents('.marblesWrap').attr('username').toLowerCase();
			var dropped_company = $(event.target).parents('.marblesWrap').attr('company');
			console.log('dropped a marble', dragged_user, dropped_user, dropped_company);
			if(dragged_user != dropped_user){										//only transfer marbles that changed owners
				$(ui.draggable).addClass('invalid');
				transfer_marble($(ui.draggable).attr('id'), dropped_user, dropped_company);
				return true;
			}
		}
	});

	//user count
	$('#foundUsers').html(data.length);
	$('#totalUsers').html(data.length);
}

//build company wrap
function build_company_panel(company){
	console.log('[ui] building company panel ' + company);
	var html = '';
	html += '
';
	html +=		'
';
	html +=			'' + toTitleCase(company) + ' - ';
	html +=			'0/';
	html +=			'0';
	if(company === bag.marble_company) {
		html +=			'';
	}
	else{
		html +=			'';
	}
	html +=		'
';
	html +=		'

';
	html += '
';
	$('#allUserPanelsWrap').append(html);
}

//build the correct "full owner" string - concate username and company
function build_full_owner(username, company){
	return username.toLowerCase() + '.' + company;
}

//build a notification msg, `error` is boolean
function build_notification(error, msg){
	var html = '';
	var css = '';
	var iconClass = 'fa-check';
	if(error) {
		css = 'warningNotice';
		iconClass = 'fa-minus-circle';
	}

	html +=	'
';
	html +=		'';
	html +=		'' + formatDate(Date.now(), '%M/%d %I:%m:%s') + '  ';
	html +=		'' + msg + '';
	html +=		'';
	html +=	'
';
	return html;
}
<commit_msg>safer ui building<commit_after>/* global bag, $*/
/* global escapeHtml, toTitleCase, formatDate, known_companies, transfer_marble, record_company*/
/* exported build_marble, record_company, build_user_panels, build_company_panel, build_notification, populate_users_marbles*/

// =================================================================================
//	UI Building
// =================================================================================
//build a marble
function build_marble(marble){
	var html = '';
	var colorClass = '';
	var size = 'largeMarble';

	marble.name = escapeHtml(marble.name);
	marble.color = escapeHtml(marble.color);
	marble.owner.username = escapeHtml(marble.owner.username);
	marble.owner.company = escapeHtml(marble.owner.company);
	var full_owner = build_full_owner(marble.owner.username, marble.owner.company);

	console.log('[ui] building marble: ', marble.color, full_owner, marble.name.substring(0,4) + '...');
	if(marble.size == 16) size = 'smallMarble';
	if(marble.color) colorClass = marble.color.toLowerCase() + 'bg';

	html += '';

	$('.marblesWrap[full_owner="' + full_owner +'"]').find('.innerMarbleWrap').prepend(html);
	$('.marblesWrap[full_owner="' + full_owner +'"]').find('.noMarblesMsg').hide();
	return html;
}

//redraw the user's marbles
function populate_users_marbles(msg){
	var full_owner = build_full_owner(msg.username, msg.company);

	//reset
	console.log('[ui] clearing marbles for user ' + full_owner);
	$('.marblesWrap[full_owner="' + full_owner +'"]').find('.innerMarbleWrap').html('');
	$('.marblesWrap[full_owner="' + full_owner +'"]').find('.noMarblesMsg').show();

	for(var i in msg.marbles){
		build_marble(msg.marbles[i]);
	}
}

//crayp resize - dsh to do, dynamic one
function size_user_name(name){
	var style = '';
	if(name.length >= 10) style = 'font-size: 22px;';
	if(name.length >= 15) style = 'font-size: 18px;';
	if(name.length >= 20) style = 'font-size: 15px;';
	if(name.length >= 25) style = 'font-size: 11px;';
	return style;
}

//build all user panels
function build_user_panels(data){
	var full_owner = '';

	//reset
	console.log('[ui] clearing all user panels');
	$('.ownerWrap').html('');
	for(var x in known_companies){
		known_companies[x].count = 0;
		known_companies[x].visible = 0;							//reset visible counts
	}

	for(var i in data){
		var html = '';
		var colorClass = '';
		data[i].username = escapeHtml(data[i].username);
		data[i].company = escapeHtml(data[i].company);
		record_company(data[i].company);
		known_companies[data[i].company].count++;
		known_companies[data[i].company].visible++;

		full_owner = build_full_owner(data[i].username, data[i].company);
		console.log('[ui] building owner panel ' + full_owner);

		html += '
';
		html +=		'
';
		html +=			toTitleCase(data[i].username);
		html +=			'';
		html +=		'
';
		html +=		'

';
		html +=		'
No marbles
';
		html +=	'
';

		$('.companyPanel[company="' + data[i].company + '"]').find('.ownerWrap').append(html);
		$('.companyPanel[company="' + data[i].company + '"]').find('.companyVisible').html(known_companies[data[i].company].visible);
		$('.companyPanel[company="' + data[i].company + '"]').find('.companyCount').html(known_companies[data[i].company].count);
	}

	//drag and drop marble
	$('.innerMarbleWrap').sortable({connectWith: '.innerMarbleWrap', items: 'span'}).disableSelection();
	$('.innerMarbleWrap').droppable({drop:
		function( event, ui ) {
			var dragged_user = $(ui.draggable).attr('username').toLowerCase();
			var dropped_user = $(event.target).parents('.marblesWrap').attr('username').toLowerCase();
			var dropped_company = $(event.target).parents('.marblesWrap').attr('company');

			console.log('dropped a marble', dragged_user, dropped_user, dropped_company);
			if(dragged_user != dropped_user){										//only transfer marbles that changed owners
				$(ui.draggable).addClass('invalid');
				transfer_marble($(ui.draggable).attr('id'), dropped_user, dropped_company);
				return true;
			}
		}
	});

	//user count
	$('#foundUsers').html(data.length);
	$('#totalUsers').html(data.length);
}

//build company wrap
function build_company_panel(company){
	company = escapeHtml(company);
	console.log('[ui] building company panel ' + company);
	var html = '';
	html += '
';
	html +=		'
';
	html +=			'' + toTitleCase(company) + ' - ';
	html +=			'0/';
	html +=			'0';
	if(company === escapeHtml(bag.marble_company)) {
		html +=			'';
	}
	else{
		html +=			'';
	}
	html +=		'
';
	html +=		'

';
	html += '
';
	$('#allUserPanelsWrap').append(html);
}

//build the correct "full owner" string - concate username and company
function build_full_owner(username, company){
	return escapeHtml(username.toLowerCase() + '.' + company);
}

//build a notification msg, `error` is boolean
function build_notification(error, msg){
	var html = '';
	var css = '';
	var iconClass = 'fa-check';
	if(error) {
		css = 'warningNotice';
		iconClass = 'fa-minus-circle';
	}

	html +=	'
';
	html +=		'';
	html +=		'' + formatDate(Date.now(), '%M/%d %I:%m:%s') + '  ';
	html +=		'' + escapeHtml(msg) + '';
	html +=		'';
	html +=	'
';
	return html;
}
<|endoftext|>