<commit_before>/**
 * Created by anonymous on 09/12/15 13:12.
 */

(function() {
    'use strict';

    angular
        .module('client')
        .config(clientRouter);

    clientRouter.$inject = ['$stateProvider', '$urlRouterProvider'];

    /* @ngInject */
    function clientRouter($stateProvider, $urlRouterProvider) {
        $urlRouterProvider.otherwise('/');

        $stateProvider
            .state('client', {
                abstract: true,
                views   : {
                    'layout@'      : {
                        templateUrl : layout('client.simple'),
                        controller  : 'ClientController',
                        controllerAs: 'client'
                    },
                    'header@client': {
                        templateUrl : view('client.header'),
                        controller  : 'ClientHeaderController',
                        controllerAs: 'header'
                    },
                    'sidenav@client'  : {
                        templateUrl : view('client.sidenav'),
                        controller  : 'ClientSidenavController',
                        controllerAs: 'sidenav'
                    },
                    'aside@client' : {
                        templateUrl : view('client.aside'),
                        controller  : 'ClientRightController',
                        controllerAs: 'aside'
                    },
                    'footer@client': {
                        templateUrl : view('client.footer'),
                        controller  : 'ClientFooterController',
                        controllerAs: 'footer'
                    },
                    'main@client'  : {}
                }
            })
            .state('client.home', {
                url  : '/',
                data : {pageName: 'Homepage'},
                views: {
                    'main@client': {
                        templateUrl : view('client.home'),
                        controller  : 'ClientHomeController',
                        controllerAs: 'home'
                    }
                }
            })
            .state('staticpage', {
                abstract: true,
                url     : '/page',
                views   : {
                    'layout@'          : {
                        templateUrl : layout('staticpage.simple'),
                        controller  : 'StaticpageController',
                        controllerAs: 'staticpage'
                    },
                    'header@staticpage': {
                        templateUrl : view('staticpage.header'),
                        controller  : 'StaticpageHeaderController',
                        controllerAs: 'header'
                    },
                    'sidenav@staticpage'  : {
                        templateUrl : view('staticpage.sidenav'),
                        controller  : 'StaticpageSidenavController',
                        controllerAs: 'sidenav'
                    },
                    'aside@staticpage' : {
                        templateUrl : view('staticpage.aside'),
                        controller  : 'StaticpageRightController',
                        controllerAs: 'aside'
                    },
                    'footer@staticpage': {
                        templateUrl : view('staticpage.footer'),
                        controller  : 'StaticpageFooterController',
                        controllerAs: 'footer'
                    },
                    'main@staticpage'  : {}
                }
            })
            .state('staticpage.landing', {
                url  : '/',
                data : {pageName: 'Landing page'},
                views: {
                    'main@staticpage': {
                        templateUrl : view('staticpage.landing'),
                        controller  : 'StaticpageLandingController',
                        controllerAs: 'landing'
                    }
                }
            });

        function dashboard(viewName) {
            if (viewName !== '') {
                return './views/dashboard/' + appName(viewName) + '/' + fileDir(viewName) + '/' + fileName(viewName) + '.html';
            } else {
                return './views/app/app/home/home.html';
            }
        }

        function view(viewName) {
            if (viewName !== '') {
                return './views/app/' + appName(viewName) + '/' + fileDir(viewName) + '/' + fileName(viewName) + '.html';
            } else {
                return './views/app/app/home/home.html';
            }
        }

        function layout(viewName) {
            if (viewName !== '') {
                return './views/layouts/' + appName(viewName) + '/' + fileDir(viewName) + '/' + fileName(viewName) + '.html';
            } else {
                return './views/app/app/home/home.html';
            }
        }

        function appName(v) {
            if (v.split('.')[0]) {
                return v.split('.')[0];
            } else {
                return 'app';
            }
        }

        function fileDir(v) {
            if (v.split('.')[1]) {
                return v.split('.')[1];
            } else if (!v.split('.')[0]) {
                return v;
            } else {
                return 'home';
            }
        }

        function fileName(v) {
            if (v.split('.')[2]) {
                return v.split('.')[2];
            } else if (!v.split('.')[2]) {
                if (v.split('.')[1]) {
                    return v.split('.')[1];
                }
            } else {
                return 'home';
            }
        }

    }

})();

<commit_msg>Modified routes<commit_after>/**
 * Created by anonymous on 09/12/15 13:12.
 */

(function() {
    'use strict';

    angular
        .module('client')
        .config(clientRouter);

    clientRouter.$inject = ['$stateProvider', '$urlRouterProvider'];

    /* @ngInject */
    function clientRouter($stateProvider, $urlRouterProvider) {
        $urlRouterProvider.otherwise('/');

        $stateProvider
            .state('client', {
                abstract: true,
                views   : {
                    'layout@'      : {
                        templateUrl : layout('client.simple'),
                        controller  : 'ClientController',
                        controllerAs: 'client'
                    },
                    'header@client': {
                        templateUrl : view('client.header'),
                        controller  : 'ClientHeaderController',
                        controllerAs: 'header'
                    },
                    'sidenav@client'  : {
                        templateUrl : view('client.sidenav'),
                        controller  : 'ClientSidenavController',
                        controllerAs: 'sidenav'
                    },
                    'aside@client' : {
                        templateUrl : view('client.aside'),
                        controller  : 'ClientAsideController',
                        controllerAs: 'aside'
                    },
                    'footer@client': {
                        templateUrl : view('client.footer'),
                        controller  : 'ClientFooterController',
                        controllerAs: 'footer'
                    },
                    'main@client'  : {}
                }
            })
            .state('client.home', {
                url  : '/',
                data : {pageName: 'Homepage'},
                views: {
                    'main@client': {
                        templateUrl : view('client.home'),
                        controller  : 'ClientHomeController',
                        controllerAs: 'home'
                    }
                }
            })
            .state('staticpage', {
                abstract: true,
                url     : '/page',
                views   : {
                    'layout@'          : {
                        templateUrl : layout('staticpage.simple'),
                        controller  : 'StaticpageController',
                        controllerAs: 'staticpage'
                    },
                    'header@staticpage': {
                        templateUrl : view('staticpage.header'),
                        controller  : 'StaticpageHeaderController',
                        controllerAs: 'header'
                    },
                    'sidenav@staticpage'  : {
                        templateUrl : view('staticpage.sidenav'),
                        controller  : 'StaticpageSidenavController',
                        controllerAs: 'sidenav'
                    },
                    'aside@staticpage' : {
                        templateUrl : view('staticpage.aside'),
                        controller  : 'StaticpageAsideController',
                        controllerAs: 'aside'
                    },
                    'footer@staticpage': {
                        templateUrl : view('staticpage.footer'),
                        controller  : 'StaticpageFooterController',
                        controllerAs: 'footer'
                    },
                    'main@staticpage'  : {}
                }
            })
            .state('staticpage.landing', {
                url  : '/',
                data : {pageName: 'Landing page'},
                views: {
                    'main@staticpage': {
                        templateUrl : view('staticpage.landing'),
                        controller  : 'StaticpageLandingController',
                        controllerAs: 'landing'
                    }
                }
            });

        function dashboard(viewName) {
            if (viewName !== '') {
                return './views/dashboard/' + appName(viewName) + '/' + fileDir(viewName) + '/' + fileName(viewName) + '.html';
            } else {
                return './views/app/app/home/home.html';
            }
        }

        function view(viewName) {
            if (viewName !== '') {
                return './views/app/' + appName(viewName) + '/' + fileDir(viewName) + '/' + fileName(viewName) + '.html';
            } else {
                return './views/app/app/home/home.html';
            }
        }

        function layout(viewName) {
            if (viewName !== '') {
                return './views/layouts/' + appName(viewName) + '/' + fileDir(viewName) + '/' + fileName(viewName) + '.html';
            } else {
                return './views/app/app/home/home.html';
            }
        }

        function appName(v) {
            if (v.split('.')[0]) {
                return v.split('.')[0];
            } else {
                return 'app';
            }
        }

        function fileDir(v) {
            if (v.split('.')[1]) {
                return v.split('.')[1];
            } else if (!v.split('.')[0]) {
                return v;
            } else {
                return 'home';
            }
        }

        function fileName(v) {
            if (v.split('.')[2]) {
                return v.split('.')[2];
            } else if (!v.split('.')[2]) {
                if (v.split('.')[1]) {
                    return v.split('.')[1];
                }
            } else {
                return 'home';
            }
        }

    }

})();

<|endoftext|>


<commit_before>'use strict';

document.addEventListener('DOMContentLoaded', function() {
  var file = document.getElementById('file');
  var form = document.getElementById('form');

  form.onsubmit = function(event) {
    event.preventDefault();
    file.click();
    return false;
  }

  // When the file is changed
  file.onchange = function(event) {
    event.preventDefault();

    function NaNToZero(time) {
      return isNaN(time) ? 0 : time;
    }

    // Get the values from the form
    var hours = parseInt(document.getElementById('h').value);
    var minutes = parseInt(document.getElementById('m').value);
    var seconds = parseInt(document.getElementById('s').value);
    var milliseconds = parseInt(document.getElementById('ms').value);

    hours = NaNToZero(hours);
    minutes = NaNToZero(minutes);
    seconds = NaNToZero(seconds);
    milliseconds = NaNToZero(milliseconds);

    var files = file.files;

    if (files.length < 1) {
      return false;
    }

    if (files.length > 1) {
      alert('Something is wrong.');
      return false;
    }

    var name = files[0].name;

    var reader = new FileReader();
    reader.onload = function(event) {
      var input = event.target.result;
      var nContent = sync(input, [hours, minutes, seconds, milliseconds]);
      var element = document.createElement('a');
      element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(nContent));
      element.setAttribute('download', name);

      element.style.display = 'none';
      document.body.appendChild(element);

      element.click();

      document.body.removeChild(element);
    };

    reader.readAsText(files[0]);
    return false;
  }

}, false);

var sync = (function(input, time) {
  const regex = /\d{0,2}:\d{0,2}:\d{0,2},\d{0,3} --> \d{0,2}:\d{0,2}:\d{0,2},\d{0,3}/;

  var timeChange = parseInt(getMilliseconds.apply(this, time)),
    lines = input.split("\n"),
    output = "";

  function getMilliseconds(hours, minutes, seconds, milliseconds) {
    return milliseconds + seconds * 1000 + minutes * 60000 + hours * 3600000;
  }

  function modifyLine(initialLine) {
    initialLine = initialLine.split(" --> ");
    var finalLineElements = [];

    for (var a = 0; a < initialLine.length; a++) {
      var time = getTime(initialLine[a]);
      time += timeChange;
      finalLineElements[a] = timeToString(time);
    }

    return finalLineElements.join(" --> ");
  }

  function getTime(time) {
    time = time.split(":");

    if (time.length > 3)
      return false;

    var temporary = time[2].split(",");

    time.pop();

    for (var i = 0; i < temporary.length; i++)
      time[time.length] = temporary[i];

    for (var j = 0; j < time.length; j++)
      time[j] = parseInt(time[j]);

    if (time.length < 4)
      return false;

    return getMilliseconds(time[0], time[1], time[2], time[3]);
  }

  function timeToString(time) {
    var milliseconds = time % 1000;
    time = (time - milliseconds) / 1000;
    var seconds = time % 60;
    time = (time - seconds) / 60;
    var minutes = time % 60;
    var hours = (time - minutes) / 60;

    hours = (hours < 10) ? "0" + hours : hours;
    minutes = (minutes < 10) ? "0" + minutes : minutes;
    seconds = (seconds < 10) ? "0" + seconds : seconds;

    if (milliseconds < 100) {
      if (milliseconds < 10) {
        milliseconds = "00" + milliseconds;
      } else {
        milliseconds = "0" + milliseconds;
      }
    }

    return hours + ":" + minutes + ":" + seconds + "," + milliseconds;
  }

  for (var i = 0; i < lines.length; i++) {
    if (regex.test(lines[i])) {
      output += modifyLine(lines[i]) + "\n";
      continue;
    }
    output += lines[i] + "\n";
  }

  return output;
});
<commit_msg>Change from utf8 to ISO-8859-1<commit_after>'use strict';

document.addEventListener('DOMContentLoaded', function() {
  var file = document.getElementById('file');
  var form = document.getElementById('form');

  form.onsubmit = function(event) {
    event.preventDefault();
    file.click();
    return false;
  }

  // When the file is changed
  file.onchange = function(event) {
    event.preventDefault();

    function NaNToZero(time) {
      return isNaN(time) ? 0 : time;
    }

    // Get the values from the form
    var hours = parseInt(document.getElementById('h').value);
    var minutes = parseInt(document.getElementById('m').value);
    var seconds = parseInt(document.getElementById('s').value);
    var milliseconds = parseInt(document.getElementById('ms').value);

    hours = NaNToZero(hours);
    minutes = NaNToZero(minutes);
    seconds = NaNToZero(seconds);
    milliseconds = NaNToZero(milliseconds);

    var files = file.files;

    if (files.length < 1) {
      return false;
    }

    if (files.length > 1) {
      alert('Something is wrong.');
      return false;
    }

    var name = files[0].name;

    var reader = new FileReader();
    reader.onload = function(event) {
      var input = event.target.result;
      var nContent = sync(input, [hours, minutes, seconds, milliseconds]);
      var element = document.createElement('a');
      element.setAttribute('href', 'data:text/plain;charset=iso-8859-1,' + encodeURIComponent(nContent));
      element.setAttribute('download', name);

      element.style.display = 'none';
      document.body.appendChild(element);

      element.click();

      document.body.removeChild(element);
    };

    reader.readAsText(files[0]);
    return false;
  }

}, false);

var sync = (function(input, time) {
  const regex = /\d{0,2}:\d{0,2}:\d{0,2},\d{0,3} --> \d{0,2}:\d{0,2}:\d{0,2},\d{0,3}/;

  var timeChange = parseInt(getMilliseconds.apply(this, time)),
    lines = input.split("\n"),
    output = "";

  function getMilliseconds(hours, minutes, seconds, milliseconds) {
    return milliseconds + seconds * 1000 + minutes * 60000 + hours * 3600000;
  }

  function modifyLine(initialLine) {
    initialLine = initialLine.split(" --> ");
    var finalLineElements = [];

    for (var a = 0; a < initialLine.length; a++) {
      var time = getTime(initialLine[a]);
      time += timeChange;
      finalLineElements[a] = timeToString(time);
    }

    return finalLineElements.join(" --> ");
  }

  function getTime(time) {
    time = time.split(":");

    if (time.length > 3)
      return false;

    var temporary = time[2].split(",");

    time.pop();

    for (var i = 0; i < temporary.length; i++)
      time[time.length] = temporary[i];

    for (var j = 0; j < time.length; j++)
      time[j] = parseInt(time[j]);

    if (time.length < 4)
      return false;

    return getMilliseconds(time[0], time[1], time[2], time[3]);
  }

  function timeToString(time) {
    var milliseconds = time % 1000;
    time = (time - milliseconds) / 1000;
    var seconds = time % 60;
    time = (time - seconds) / 60;
    var minutes = time % 60;
    var hours = (time - minutes) / 60;

    hours = (hours < 10) ? "0" + hours : hours;
    minutes = (minutes < 10) ? "0" + minutes : minutes;
    seconds = (seconds < 10) ? "0" + seconds : seconds;

    if (milliseconds < 100) {
      if (milliseconds < 10) {
        milliseconds = "00" + milliseconds;
      } else {
        milliseconds = "0" + milliseconds;
      }
    }

    return hours + ":" + minutes + ":" + seconds + "," + milliseconds;
  }

  for (var i = 0; i < lines.length; i++) {
    if (regex.test(lines[i])) {
      output += modifyLine(lines[i]) + "\n";
      continue;
    }
    output += lines[i] + "\n";
  }

  return output;
});
<|endoftext|>


<commit_before>import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';
import { defer } from 'rsvp';
import { later } from '@ember/runloop';
import generateThings from 'dummy/utils/generate-things';
import { render, settled, find, click, scrollTo } from '@ember/test-helpers';

module('infinite-scroller', function (hooks) {
  setupRenderingTest(hooks);

  hooks.beforeEach(function (assert) {
    this.handleLoadMore = () => {
      assert.step('load more');
      this.willLoad = defer();
      return this.willLoad.promise;
    };

    this.scrollToPercentage = (selector, percentage) => {
      const el = find(selector);
      const y = ((el.scrollHeight - el.clientHeight) / 100) * percentage;
      return scrollTo(el, 0, y);
    };
  });

  test('it renders', async function (assert) {
    assert.expect(1);

    await render(hbs`<InfiniteScroller />`);

    assert.dom('.infinite-scroller').exists('has an appropriate class name');
  });

  test('scrollable class', async function (assert) {
    assert.expect(2);

    this.things = generateThings(1, 20);

    await render(hbs`
      <InfiniteScroller class="example-1">
        {{#each this.things as |thing|}}

{{thing.name}}

        {{/each}}
      </InfiniteScroller>
    `);

    assert.dom('.infinite-scroller').hasClass('infinite-scroller--scrollable');

    await render(hbs`<InfiniteScroller class="example-1" />`);

    assert
      .dom('.infinite-scroller')
      .doesNotHaveClass('infinite-scroller--scrollable');
  });

  test('load more action', async function (assert) {
    assert.expect(3);

    this.things = generateThings(1, 20);

    await render(hbs`
      <InfiniteScroller
        class="example-1"
        @onLoadMore={{this.handleLoadMore}}
      >
        {{#each this.things as |thing|}}

{{thing.name}}

        {{/each}}
      </InfiniteScroller>
    `);

    const promise = this.scrollToPercentage('.infinite-scroller', 100);

    later(() => {
      assert.verifySteps(
        [],
        'has not fired load more action due to debouncing of scroll event'
      );
    }, 100);

    await promise;

    assert.verifySteps(['load more']);
  });

  test('load more action (whilst loading)', async function (assert) {
    assert.expect(2);

    this.things = generateThings(1, 20);

    await render(hbs`
      <InfiniteScroller
        class="example-1"
        @onLoadMore={{this.handleLoadMore}}
      >
        {{#each this.things as |thing|}}

{{thing.name}}

        {{/each}}
      </InfiniteScroller>
    `);

    await this.scrollToPercentage('.infinite-scroller', 100);
    await this.scrollToPercentage('.infinite-scroller', 100);

    assert.verifySteps(['load more'], 'does not fire if already loading');
  });

  test('load more action (leeway)', async function (assert) {
    assert.expect(3);

    this.things = generateThings(1, 20);

    await render(hbs`
      <InfiniteScroller
        class="example-1"
        @leeway="50%"
        @onLoadMore={{this.handleLoadMore}}
      >
        {{#each this.things as |thing|}}

{{thing.name}}

        {{/each}}
      </InfiniteScroller>
    `);

    await this.scrollToPercentage('.infinite-scroller', 49);

    assert.verifySteps([], 'not scrolled enough');

    await this.scrollToPercentage('.infinite-scroller', 50);

    assert.verifySteps(['load more']);
  });

  test('load more action (debounce)', async function (assert) {
    assert.expect(3);

    this.things = generateThings(1, 20);

    await render(hbs`
      <InfiniteScroller
        class="example-1"
        @debounce={{50}}
        @onLoadMore={{this.handleLoadMore}}
      >
        {{#each this.things as |thing|}}

{{thing.name}}

        {{/each}}
      </InfiniteScroller>
    `);

    const promise = this.scrollToPercentage('.infinite-scroller', 100);

    later(() => {
      assert.verifySteps([], 'not fired yet');
    }, 50);

    await promise;

    assert.verifySteps(
      ['load more'],
      'fires load more action after being debounced'
    );
  });

  test('load more action (document)', async function (assert) {
    assert.expect(2);

    this.document = document;

    await render(hbs`

      <InfiniteScroller
        class="example-2"
        @element={{this.document}}
        @onLoadMore={{this.handleLoadMore}}
      >
        {{#each this.things as |thing|}}

{{thing.name}}

        {{/each}}
      </InfiniteScroller>
    `);

    await this.scrollToPercentage(document.documentElement, 100);

    assert.verifySteps(['load more']);
  });

  test('custom element via argument', async function (assert) {
    assert.expect(2);

    this.things = generateThings(1, 20);

    this.setElement = (element) => this.set('customElement', element);

    await render(hbs`

        {{#each this.things as |thing|}}

{{thing.name}}

        {{/each}}

      <InfiniteScroller
        @element={{this.customElement}}
        @onLoadMore={{this.handleLoadMore}}
      />
    `);

    await this.scrollToPercentage('.external-element', 100);

    assert.verifySteps(['load more']);
  });

  test('custom element via registration', async function (assert) {
    assert.expect(2);

    this.things = generateThings(1, 20);

    await render(hbs`
      <InfiniteScroller
        @onLoadMore={{this.handleLoadMore}}
        as |scroller|
      >

          {{#each this.things as |thing|}}

{{thing.name}}

          {{/each}}

      </InfiniteScroller>
    `);

    await this.scrollToPercentage('.internal-element', 100);

    assert.verifySteps(['load more']);
  });

  test('loading class name', async function (assert) {
    assert.expect(5);

    await render(hbs`
      <InfiniteScroller
        @onLoadMore={{this.handleLoadMore}} as |scroller|
      >
        <button type="button" {{on "click" scroller.loadMore}}>
          Load more
        </button>
      </InfiniteScroller>
    `);

    assert
      .dom('.infinite-scroller')
      .doesNotHaveClass(
        'infinite-scroller--loading',
        'precondition: is not loading'
      );

    await click('button');

    assert
      .dom('.infinite-scroller')
      .hasClass(
        'infinite-scroller--loading',
        'a loading class is added whilst the action is being performed'
      );

    this.willLoad.resolve();

    await settled();

    assert
      .dom('.infinite-scroller')
      .doesNotHaveClass(
        'infinite-scroller--loading',
        'loading class name is removed after the action resolves'
      );

    assert.verifySteps(['load more']);
  });

  test('yielded loadMore action', async function (assert) {
    assert.expect(2);

    await render(hbs`
      <InfiniteScroller
        @onLoadMore={{this.handleLoadMore}} as |scroller|
      >
        <button type="button" {{on "click" scroller.loadMore}}>
          Load more
        </button>
      </InfiniteScroller>
    `);

    await click('button');

    assert.verifySteps(['load more']);
  });

  test('yielded loading state', async function (assert) {
    assert.expect(5);

    await render(hbs`
      <InfiniteScroller
        @onLoadMore={{this.handleLoadMore}} as |scroller|
      >
        {{scroller.isLoading}}

        <button type="button" {{on "click" scroller.loadMore}}>
          Load more
        </button>
      </InfiniteScroller>
    `);

    assert.dom('span').hasText('false', 'precondition: not loading');

    await click('button');

    assert.dom('span').hasText('true', 'yields a hash with the loading state');

    this.willLoad.resolve();

    await settled();

    assert.dom('span').hasText('false', 'loading state is updated');

    assert.verifySteps(['load more']);
  });

  test('destroying (does not blow up)', async function (assert) {
    assert.expect(2);

    this.show = true;

    await render(hbs`
      {{#if this.show}}
        <InfiniteScroller
          @onLoadMore={{this.handleLoadMore}} as |scroller|
        >
          <button type="button" {{on "click" scroller.loadMore}}>
            Load more
          </button>
        </InfiniteScroller>
      {{/if}}
    `);

    await click('button');

    this.set('show', false);

    this.willLoad.resolve();

    assert.verifySteps(['load more']);
  });

  test('no promise (does not blow up)', async function (assert) {
    assert.expect(0);

    this.handleLoadMore = () => null;

    await render(hbs`
      <InfiniteScroller
        @onLoadMore={{this.handleLoadMore}} as |scroller|
      >
        <button type="button" {{on "click" scroller.loadMore}}>
          Load more
        </button>
      </InfiniteScroller>
    `);

    await click('button');
  });

  test('destroying during debounce (does not blow up)', async function (assert) {
    assert.expect(1);

    this.show = true;

    await render(hbs`
      {{#if this.show}}
        <InfiniteScroller
          class="example-1"
          @debounce={{50}}
          @onLoadMore={{this.handleLoadMore}}
        >
          {{#each this.things as |thing|}}

{{thing.name}}

          {{/each}}
        </InfiniteScroller>
      {{/if}}
    `);

    const promise = this.scrollToPercentage('.infinite-scroller', 100);

    later(() => {
      this.set('show', false);
    }, 25);

    await promise;

    assert.verifySteps([]);
  });

  test('is scrollable', async function (assert) {
    assert.expect(4);

    await render(hbs`
      <InfiniteScroller
        class="example-1"
        @onLoadMore={{this.handleLoadMore}} as |scroller|
      >
        {{#each this.things as |thing|}}

{{thing.name}}

        {{/each}}

        {{#unless scroller.isScrollable}}
          <button
            type="button"
            {{on "click" scroller.loadMore}}
          >
            Load more
          </button>
        {{/unless}}
      </InfiniteScroller>
    `);

    assert
      .dom('button')
      .exists(
        'load more button shows because infinite scroller component ' +
          'determined that there is no scroll movement available'
      );

    await click('button');

    this.set('things', generateThings(1, 20));
    this.willLoad.resolve();

    await settled();

    assert
      .dom('button')
      .doesNotExist(
        'infinite scroller component re-computes whether or not there is scroll movement available'
      );

    assert.verifySteps(['load more']);
  });

  test('changing element argument', async function (assert) {
    assert.expect(3);

    this.things = generateThings(1, 20);

    this.setDiv1 = (element) => {
      this.set('div1', element);
      this.set('customElement', this.div1);
    };

    this.setDiv2 = (element) => {
      this.set('div2', element);
    };

    await render(hbs`

        {{#each this.things as |thing|}}

{{thing.name}}

        {{/each}}

        {{#each this.things as |thing|}}

{{thing.name}}

        {{/each}}

      <InfiniteScroller
        @element={{this.customElement}}
        @onLoadMore={{this.handleLoadMore}}
      />
    `);

    await this.scrollToPercentage('.external-element:nth-child(1)', 100);

    this.willLoad.resolve();

    assert.verifySteps(['load more']);

    this.set('customElement', this.div2);

    await this.scrollToPercentage('.external-element:nth-child(2)', 100);

    assert.verifySteps(
      [],
      'only fires load action once, because the scroll listeners are not' +
        'reconfigured when element changes.'
    );
  });
});
<commit_msg>improve test<commit_after>import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';
import { defer } from 'rsvp';
import { later } from '@ember/runloop';
import generateThings from 'dummy/utils/generate-things';
import { render, settled, find, click, scrollTo } from '@ember/test-helpers';

module('infinite-scroller', function (hooks) {
  setupRenderingTest(hooks);

  hooks.beforeEach(function (assert) {
    this.handleLoadMore = () => {
      assert.step('load more');
      this.willLoad = defer();
      return this.willLoad.promise;
    };

    this.scrollToPercentage = (selector, percentage) => {
      const el = find(selector);
      const y = ((el.scrollHeight - el.clientHeight) / 100) * percentage;
      return scrollTo(el, 0, y);
    };
  });

  test('it renders', async function (assert) {
    assert.expect(1);

    await render(hbs`<InfiniteScroller />`);

    assert.dom('.infinite-scroller').exists('has an appropriate class name');
  });

  test('scrollable class', async function (assert) {
    assert.expect(2);

    this.things = generateThings(1, 20);

    await render(hbs`
      <InfiniteScroller class="example-1">
        {{#each this.things as |thing|}}

{{thing.name}}

        {{/each}}
      </InfiniteScroller>
    `);

    assert.dom('.infinite-scroller').hasClass('infinite-scroller--scrollable');

    await render(hbs`<InfiniteScroller class="example-1" />`);

    assert
      .dom('.infinite-scroller')
      .doesNotHaveClass('infinite-scroller--scrollable');
  });

  test('load more action', async function (assert) {
    assert.expect(3);

    this.things = generateThings(1, 20);

    await render(hbs`
      <InfiniteScroller
        class="example-1"
        @onLoadMore={{this.handleLoadMore}}
      >
        {{#each this.things as |thing|}}

{{thing.name}}

        {{/each}}
      </InfiniteScroller>
    `);

    const promise = this.scrollToPercentage('.infinite-scroller', 100);

    later(() => {
      assert.verifySteps(
        [],
        'has not fired load more action due to debouncing of scroll event'
      );
    }, 100);

    await promise;

    assert.verifySteps(['load more']);
  });

  test('load more action (whilst loading)', async function (assert) {
    assert.expect(2);

    this.things = generateThings(1, 20);

    await render(hbs`
      <InfiniteScroller
        class="example-1"
        @onLoadMore={{this.handleLoadMore}}
      >
        {{#each this.things as |thing|}}

{{thing.name}}

        {{/each}}
      </InfiniteScroller>
    `);

    await this.scrollToPercentage('.infinite-scroller', 100);
    await this.scrollToPercentage('.infinite-scroller', 100);

    assert.verifySteps(['load more'], 'does not fire if already loading');
  });

  test('load more action (leeway)', async function (assert) {
    assert.expect(3);

    this.things = generateThings(1, 20);

    await render(hbs`
      <InfiniteScroller
        class="example-1"
        @leeway="40%"
        @onLoadMore={{this.handleLoadMore}}
      >
        {{#each this.things as |thing|}}

{{thing.name}}

        {{/each}}
      </InfiniteScroller>
    `);

    await this.scrollToPercentage('.infinite-scroller', 59);

    assert.verifySteps([], 'not scrolled enough');

    await this.scrollToPercentage('.infinite-scroller', 60);

    assert.verifySteps(['load more']);
  });

  test('load more action (debounce)', async function (assert) {
    assert.expect(3);

    this.things = generateThings(1, 20);

    await render(hbs`
      <InfiniteScroller
        class="example-1"
        @debounce={{50}}
        @onLoadMore={{this.handleLoadMore}}
      >
        {{#each this.things as |thing|}}

{{thing.name}}

        {{/each}}
      </InfiniteScroller>
    `);

    const promise = this.scrollToPercentage('.infinite-scroller', 100);

    later(() => {
      assert.verifySteps([], 'not fired yet');
    }, 50);

    await promise;

    assert.verifySteps(
      ['load more'],
      'fires load more action after being debounced'
    );
  });

  test('load more action (document)', async function (assert) {
    assert.expect(2);

    this.document = document;

    await render(hbs`

      <InfiniteScroller
        class="example-2"
        @element={{this.document}}
        @onLoadMore={{this.handleLoadMore}}
      >
        {{#each this.things as |thing|}}

{{thing.name}}

        {{/each}}
      </InfiniteScroller>
    `);

    await this.scrollToPercentage(document.documentElement, 100);

    assert.verifySteps(['load more']);
  });

  test('custom element via argument', async function (assert) {
    assert.expect(2);

    this.things = generateThings(1, 20);

    this.setElement = (element) => this.set('customElement', element);

    await render(hbs`

        {{#each this.things as |thing|}}

{{thing.name}}

        {{/each}}

      <InfiniteScroller
        @element={{this.customElement}}
        @onLoadMore={{this.handleLoadMore}}
      />
    `);

    await this.scrollToPercentage('.external-element', 100);

    assert.verifySteps(['load more']);
  });

  test('custom element via registration', async function (assert) {
    assert.expect(2);

    this.things = generateThings(1, 20);

    await render(hbs`
      <InfiniteScroller
        @onLoadMore={{this.handleLoadMore}}
        as |scroller|
      >

          {{#each this.things as |thing|}}

{{thing.name}}

          {{/each}}

      </InfiniteScroller>
    `);

    await this.scrollToPercentage('.internal-element', 100);

    assert.verifySteps(['load more']);
  });

  test('loading class name', async function (assert) {
    assert.expect(5);

    await render(hbs`
      <InfiniteScroller
        @onLoadMore={{this.handleLoadMore}} as |scroller|
      >
        <button type="button" {{on "click" scroller.loadMore}}>
          Load more
        </button>
      </InfiniteScroller>
    `);

    assert
      .dom('.infinite-scroller')
      .doesNotHaveClass(
        'infinite-scroller--loading',
        'precondition: is not loading'
      );

    await click('button');

    assert
      .dom('.infinite-scroller')
      .hasClass(
        'infinite-scroller--loading',
        'a loading class is added whilst the action is being performed'
      );

    this.willLoad.resolve();

    await settled();

    assert
      .dom('.infinite-scroller')
      .doesNotHaveClass(
        'infinite-scroller--loading',
        'loading class name is removed after the action resolves'
      );

    assert.verifySteps(['load more']);
  });

  test('yielded loadMore action', async function (assert) {
    assert.expect(2);

    await render(hbs`
      <InfiniteScroller
        @onLoadMore={{this.handleLoadMore}} as |scroller|
      >
        <button type="button" {{on "click" scroller.loadMore}}>
          Load more
        </button>
      </InfiniteScroller>
    `);

    await click('button');

    assert.verifySteps(['load more']);
  });

  test('yielded loading state', async function (assert) {
    assert.expect(5);

    await render(hbs`
      <InfiniteScroller
        @onLoadMore={{this.handleLoadMore}} as |scroller|
      >
        {{scroller.isLoading}}

        <button type="button" {{on "click" scroller.loadMore}}>
          Load more
        </button>
      </InfiniteScroller>
    `);

    assert.dom('span').hasText('false', 'precondition: not loading');

    await click('button');

    assert.dom('span').hasText('true', 'yields a hash with the loading state');

    this.willLoad.resolve();

    await settled();

    assert.dom('span').hasText('false', 'loading state is updated');

    assert.verifySteps(['load more']);
  });

  test('destroying (does not blow up)', async function (assert) {
    assert.expect(2);

    this.show = true;

    await render(hbs`
      {{#if this.show}}
        <InfiniteScroller
          @onLoadMore={{this.handleLoadMore}} as |scroller|
        >
          <button type="button" {{on "click" scroller.loadMore}}>
            Load more
          </button>
        </InfiniteScroller>
      {{/if}}
    `);

    await click('button');

    this.set('show', false);

    this.willLoad.resolve();

    assert.verifySteps(['load more']);
  });

  test('no promise (does not blow up)', async function (assert) {
    assert.expect(0);

    this.handleLoadMore = () => null;

    await render(hbs`
      <InfiniteScroller
        @onLoadMore={{this.handleLoadMore}} as |scroller|
      >
        <button type="button" {{on "click" scroller.loadMore}}>
          Load more
        </button>
      </InfiniteScroller>
    `);

    await click('button');
  });

  test('destroying during debounce (does not blow up)', async function (assert) {
    assert.expect(1);

    this.show = true;

    await render(hbs`
      {{#if this.show}}
        <InfiniteScroller
          class="example-1"
          @debounce={{50}}
          @onLoadMore={{this.handleLoadMore}}
        >
          {{#each this.things as |thing|}}

{{thing.name}}

          {{/each}}
        </InfiniteScroller>
      {{/if}}
    `);

    const promise = this.scrollToPercentage('.infinite-scroller', 100);

    later(() => {
      this.set('show', false);
    }, 25);

    await promise;

    assert.verifySteps([]);
  });

  test('is scrollable', async function (assert) {
    assert.expect(4);

    await render(hbs`
      <InfiniteScroller
        class="example-1"
        @onLoadMore={{this.handleLoadMore}} as |scroller|
      >
        {{#each this.things as |thing|}}

{{thing.name}}

        {{/each}}

        {{#unless scroller.isScrollable}}
          <button
            type="button"
            {{on "click" scroller.loadMore}}
          >
            Load more
          </button>
        {{/unless}}
      </InfiniteScroller>
    `);

    assert
      .dom('button')
      .exists(
        'load more button shows because infinite scroller component ' +
          'determined that there is no scroll movement available'
      );

    await click('button');

    this.set('things', generateThings(1, 20));
    this.willLoad.resolve();

    await settled();

    assert
      .dom('button')
      .doesNotExist(
        'infinite scroller component re-computes whether or not there is scroll movement available'
      );

    assert.verifySteps(['load more']);
  });

  test('changing element argument', async function (assert) {
    assert.expect(3);

    this.things = generateThings(1, 20);

    this.setDiv1 = (element) => {
      this.set('div1', element);
      this.set('customElement', this.div1);
    };

    this.setDiv2 = (element) => {
      this.set('div2', element);
    };

    await render(hbs`

        {{#each this.things as |thing|}}

{{thing.name}}

        {{/each}}

        {{#each this.things as |thing|}}

{{thing.name}}

        {{/each}}

      <InfiniteScroller
        @element={{this.customElement}}
        @onLoadMore={{this.handleLoadMore}}
      />
    `);

    await this.scrollToPercentage('.external-element:nth-child(1)', 100);

    this.willLoad.resolve();

    assert.verifySteps(['load more']);

    this.set('customElement', this.div2);

    await this.scrollToPercentage('.external-element:nth-child(2)', 100);

    assert.verifySteps(
      [],
      'only fires load action once, because the scroll listeners are not' +
        'reconfigured when element changes.'
    );
  });
});
<|endoftext|>


<commit_before>/**
 * Tabslet | tabs jQuery plugin
 *
 * @copyright Copyright 2015, Dimitris Krestos
 * @license   Apache License, Version 2.0 (http://www.opensource.org/licenses/apache2.0.php)
 * @link      http://vdw.staytuned.gr
 * @version   v1.7.1
 */

  /* Sample html structure

Tab 1

Tab 2

Tab 3

  OR

Tab 1

Tab 2

Tab 3

  */

;(function($, window, undefined) {
  "use strict";

  $.fn.tabslet = function(options) {

    var defaults = {
      mouseevent:   'click',
      attribute:    'href',
      animation:    false,
      autorotate:   false,
      deeplinking:  false,
      pauseonhover: true,
      delay:        2000,
      active:       1,
      container:    false,
      controls:     {
        prev: '.prev',
        next: '.next'
      }
    };

    var options = $.extend(defaults, options);

    return this.each(function() {

      var $this      = $(this), _cache_li = [], _cache_div = [];
      var _container = options.container ? $(options.container) : $this;
      var _tabs      = _container.find('> div');

      // Caching
      _tabs.each(function() { _cache_div.push($(this).css('display')); });

      // Autorotate
      var elements = $this.find('> ul > li'), i = options.active - 1; // ungly

      if ( !$this.data( 'tabslet-init' ) ) {

        $this.data( 'tabslet-init', true );

        $this.opts = [];

        $.map( ['mouseevent', 'attribute', 'animation', 'autorotate', 'deeplinking', 'pauseonhover', 'delay', 'container'], function( val, i ) {
          $this.opts[val] = $this.data(val) || options[val];
        });

        $this.opts['active'] = $this.opts.deeplinking ? deep_link() : ( $this.data('active') || options.active )

        _tabs.hide();

        if ( $this.opts.active ) {
          _tabs.eq($this.opts.active - 1).show();
          elements.eq($this.opts.active - 1).addClass('active');
        }

        var fn = eval(

          function(e, tab) {
            var _this = tab ? elements.find('a[' + $this.opts.attribute + '=' + tab +']').parent() : $(this);

            _this.trigger('_before');

            elements.removeClass('active');
            _this.addClass('active');
            _tabs.hide();

            i = elements.index(_this);

            var currentTab = tab || _this.find('a').attr($this.opts.attribute);

            if ($this.opts.deeplinking) location.hash = currentTab;

            if ($this.opts.animation) {

              _container.find(currentTab).animate( { opacity: 'show' }, 'slow', function() {
                _this.trigger('_after');
              });

            } else {

              _container.find(currentTab).show();
              _this.trigger('_after');

            }

            return false;

          }

        );

        var init = eval("elements." + $this.opts.mouseevent + "(fn)");

        init;

        var t;

        var forward = function() {

          i = ++i % elements.length; // wrap around

          $this.opts.mouseevent == 'hover' ? elements.eq(i).trigger('mouseover') : elements.eq(i).click();

          if ($this.opts.autorotate) {

            clearTimeout(t);

            t = setTimeout(forward, $this.opts.delay);

            $this.mouseover(function () {

              if ($this.opts.pauseonhover) clearTimeout(t);

            });

          }

        }

        if ($this.opts.autorotate) {

          t = setTimeout(forward, $this.opts.delay);

          $this.hover(function() {

            if ($this.opts.pauseonhover) clearTimeout(t);

          }, function() {

            t = setTimeout(forward, $this.opts.delay);

          });

          if ($this.opts.pauseonhover) $this.on( "mouseleave", function() { clearTimeout(t); t = setTimeout(forward, $this.opts.delay); });

        }

        var deep_link = function() {

          var ids = [];

          elements.find('a').each(function() { ids.push($(this).attr($this.opts.attribute)); });

          var index = $.inArray(location.hash, ids)

          if (index > -1) {

            return index + 1

          } else {

            return ($this.data('active') || options.active)

          }

        }

        var move = function(direction) {

          if (direction == 'forward') i = ++i % elements.length; // wrap around

          if (direction == 'backward') i = --i % elements.length; // wrap around

          elements.eq(i).click();

        }

        $this.find(options.controls.next).click(function() {
          move('forward');
        });

        $this.find(options.controls.prev).click(function() {
          move('backward');
        });

        $this.on ('show', function(e, tab) {
          fn(e, tab);
        });

        $this.on ('next', function() {
          move('forward');
        });

        $this.on ('prev', function() {
          move('backward');
        });

        $this.on ('destroy', function() {
          $(this)
            .removeData()
            .find('> ul li').each( function(i) {
              $(this).removeClass('active');
            });
          _tabs.each( function(i) {
            $(this).removeAttr('style').css( 'display', _cache_div[i] );
          });
        });

      }

    });

  };

  $(document).ready(function () { $('[data-toggle="tabslet"]').tabslet(); });

})(jQuery);<commit_msg>Added activeclass to options to give users flexibility of choosing their own active state class also allowing the use of SMACSS principles for state classes<commit_after>/**
 * Tabslet | tabs jQuery plugin
 *
 * @copyright Copyright 2015, Dimitris Krestos
 * @license   Apache License, Version 2.0 (http://www.opensource.org/licenses/apache2.0.php)
 * @link      http://vdw.staytuned.gr
 * @version   v1.7.1
 */

  /* Sample html structure

Tab 1

Tab 2

Tab 3

  OR

Tab 1

Tab 2

Tab 3

  */

;(function($, window, undefined) {
  "use strict";

  $.fn.tabslet = function(options) {

    var defaults = {
      mouseevent:   'click',
      activeclass:    'active',
      attribute:    'href',
      animation:    false,
      autorotate:   false,
      deeplinking:  false,
      pauseonhover: true,
      delay:        2000,
      active:       1,
      container:    false,
      controls:     {
        prev: '.prev',
        next: '.next'
      }
    };

    var options = $.extend(defaults, options);

    return this.each(function() {

      var $this      = $(this), _cache_li = [], _cache_div = [];
      var _container = options.container ? $(options.container) : $this;
      var _tabs      = _container.find('> div');

      // Caching
      _tabs.each(function() { _cache_div.push($(this).css('display')); });

      // Autorotate
      var elements = $this.find('> ul > li'), i = options.active - 1; // ungly

      if ( !$this.data( 'tabslet-init' ) ) {

        $this.data( 'tabslet-init', true );

        $this.opts = [];

        $.map( ['mouseevent', 'activeclass', 'attribute', 'animation', 'autorotate', 'deeplinking', 'pauseonhover', 'delay', 'container'], function( val, i ) {
          $this.opts[val] = $this.data(val) || options[val];
        });

        $this.opts['active'] = $this.opts.deeplinking ? deep_link() : ( $this.data('active') || options.active )

        _tabs.hide();

        if ( $this.opts.active ) {
          _tabs.eq($this.opts.active - 1).show();
          elements.eq($this.opts.active - 1).addClass(options.activeclass);
        }

        var fn = eval(

          function(e, tab) {
            var _this = tab ? elements.find('a[' + $this.opts.attribute + '=' + tab +']').parent() : $(this);

            _this.trigger('_before');

            elements.removeClass(options.activeclass);
            _this.addClass(options.activeclass);
            _tabs.hide();

            i = elements.index(_this);

            var currentTab = tab || _this.find('a').attr($this.opts.attribute);

            if ($this.opts.deeplinking) location.hash = currentTab;

            if ($this.opts.animation) {

              _container.find(currentTab).animate( { opacity: 'show' }, 'slow', function() {
                _this.trigger('_after');
              });

            } else {

              _container.find(currentTab).show();
              _this.trigger('_after');

            }

            return false;

          }

        );

        var init = eval("elements." + $this.opts.mouseevent + "(fn)");

        init;

        var t;

        var forward = function() {

          i = ++i % elements.length; // wrap around

          $this.opts.mouseevent == 'hover' ? elements.eq(i).trigger('mouseover') : elements.eq(i).click();

          if ($this.opts.autorotate) {

            clearTimeout(t);

            t = setTimeout(forward, $this.opts.delay);

            $this.mouseover(function () {

              if ($this.opts.pauseonhover) clearTimeout(t);

            });

          }

        }

        if ($this.opts.autorotate) {

          t = setTimeout(forward, $this.opts.delay);

          $this.hover(function() {

            if ($this.opts.pauseonhover) clearTimeout(t);

          }, function() {

            t = setTimeout(forward, $this.opts.delay);

          });

          if ($this.opts.pauseonhover) $this.on( "mouseleave", function() { clearTimeout(t); t = setTimeout(forward, $this.opts.delay); });

        }

        var deep_link = function() {

          var ids = [];

          elements.find('a').each(function() { ids.push($(this).attr($this.opts.attribute)); });

          var index = $.inArray(location.hash, ids)

          if (index > -1) {

            return index + 1

          } else {

            return ($this.data('active') || options.active)

          }

        }

        var move = function(direction) {

          if (direction == 'forward') i = ++i % elements.length; // wrap around

          if (direction == 'backward') i = --i % elements.length; // wrap around

          elements.eq(i).click();

        }

        $this.find(options.controls.next).click(function() {
          move('forward');
        });

        $this.find(options.controls.prev).click(function() {
          move('backward');
        });

        $this.on ('show', function(e, tab) {
          fn(e, tab);
        });

        $this.on ('next', function() {
          move('forward');
        });

        $this.on ('prev', function() {
          move('backward');
        });

        $this.on ('destroy', function() {
          $(this)
            .removeData()
            .find('> ul li').each( function(i) {
              $(this).removeClass(options.activeclass);
            });
          _tabs.each( function(i) {
            $(this).removeAttr('style').css( 'display', _cache_div[i] );
          });
        });

      }

    });

  };

  $(document).ready(function () { $('[data-toggle="tabslet"]').tabslet(); });

})(jQuery);
<|endoftext|>


<commit_before>var _ = require('underscore');
var React = require('react');
var Mosaic = require('mosaic-commons');

module.exports = React.createClass({
    displayName : 'PaginatedListView',

    getInitialState : function() {
        return this._newState();
    },

    componentWillMount : function() {
        this._updateState({
            index : this.props.index,
            reset : true
        });
    },

    componentWillReceiveProps : function(props) {
        this._updateState({
            index : props.index,
            reset : true
        });
    },

    componentDidMount : function() {
        this._refocus();
    },

    componentDidUpdate : function() {
        this._refocus();
    },

    _refocus : function() {
        if (this.state.reset) {
            this._moveToItem(this.state.index || 0);
        } else {
            this._focusToIndex(this.state.index || this.state.itemsStartIndex);
        }
    },

    _getPageSize : function() {
        var pageSize = +this.props.pageSize || 50;
        return pageSize;
    },

    _updateState : function(options) {
        this.setState(this._newState(options));
    },

    update : function() {
        var idx = this.state.index || this.state.itemsStartIndex || 0;
        this._focusToIndex(idx);
    },

    _focusToIndex : function(index) {
        var that = this;
        setTimeout(function() {
            if (!that.isMounted())
                return;
            index = Math.max(index || 0, 0);
            var idx = Math.max(index - that.state.itemsStartIndex, 0);
            var scrollerElm = that.getDOMNode();
            var elm = that.refs.items.getDOMNode();
            var topOffset = elm.offsetTop;
            var children = elm.childNodes;
            idx = Math.max(0, Math.min(idx, children.length - 1));
            var child = children[idx];
            var top = 0;
            if (child) {
                top = child.offsetTop;
            }
            scrollerElm.scrollTop = top;
        }, 1);
    },

    _newState : function(options) {
        return _.extend({
            index : 0,
            length : 0,
            items : [],
            itemsStartIndex : 0,
            reset : true
        }, this.state, options);
    },

    _setPage : function(pageId, ev) {
        var pageSize = this._getPageSize();
        var index = pageId * pageSize;
        this._moveToItem(index);
        if (ev) {
            ev.stopPropagation();
            ev.preventDefault();
        }
    },

    _moveToItem : function(index) {
        var that = this;
        var length = 0;
        var itemsStartIndex = 0;
        return Mosaic.P.then(function() {
            return that.props.getItemsNumber();
        }).then(function(len) {
            length = len || 0;
            var idx = Math.max(0, Math.min(length - 1, index || 0));
            var pageSize = that._getPageSize();
            var from = Math.floor(idx / pageSize) * pageSize;
            itemsStartIndex = from;
            var to = Math.ceil(idx / pageSize) * pageSize;
            if (from === to) {
                to += pageSize;
            }
            to = Math.min(length - 1, to);
            var num = to - from + 1;
            return that.props.renderItems({
                index : from,
                length : num
            });
        }).then(function(items) {
            that._updateState({
                index : index,
                items : items,
                itemsStartIndex : itemsStartIndex,
                length : length,
                reset : false
            });
        });
    },

    _renderPagination : function() {
        var pageSize = this._getPageSize();
        var pageIndex = Math.floor(this.state.itemsStartIndex / pageSize);
        var pageCount = Math.floor(this.state.length / pageSize) + 1;
        var buttons = [];
        if (pageCount <= 1) {
            return React.DOM.nav();
        }
        var that = this;
        function getButton(index, label, key, activeClass) {
            var className;
            if (pageIndex === index) {
                className = activeClass;
            }
            return React.DOM.li({
                key : key,
                className : className
            }, React.DOM.a({
                href : '#',
                onClick : that._setPage.bind(that, index)
            }, label));
        }
        function getSpace(index) {
            return getButton(index, '…', 'space-' + index);
        }

        var buttonsNumber = this.props.buttonsNumber || 5;

        buttons.push(getButton(0, '«', 'prev', 'disabled'));
        var from = Math.max(0, pageIndex - Math.floor(buttonsNumber / 2));
        if (from + buttonsNumber >= pageCount) {
            from = Math.max(0, pageCount - buttonsNumber);
        }
        var to = Math.min(pageCount, from + buttonsNumber);

        if (from > 0) {
            buttons.push(getSpace(Math.max(0, pageIndex - buttonsNumber)));
        }
        for (var i = from; i < to; i++) {
            buttons.push(getButton(i, (i + 1) + '', 'item-' + i, 'active'));
        }
        if (to < pageCount) {
            buttons.push(getSpace(Math.min(pageCount - 1, pageIndex + //
            buttonsNumber)));
        }
        buttons.push(getButton(pageCount - 1, '»', 'next', 'disabled'));
        var className = that.props.paginationClassName || 'pagination';
        return React.DOM.nav({}, React.DOM.ul({
            className : className
        }, buttons));
    },

    _checkPagination : function(key, defaultValue) {
        var value = this.props[key];
        if (value === undefined || value === null) {
            return defaultValue;
        } else {
            return !!value;
        }
    },

    render : function() {
        var topPagination;
        if (this._checkPagination('topPagination', false)) {
            topPagination = this._renderPagination();
        }
        var bottomPagination;
        if (this._checkPagination('bottomPagination', true)) {
            bottomPagination = this._renderPagination();
        }
        return React.DOM.div({
            className : this.props.className
        }, //
        topPagination, //
        React.DOM.div({
            ref : 'items'
        }, this.state.items),//
        bottomPagination);
    },

});
<commit_msg>Fix pagination<commit_after>var _ = require('underscore');
var React = require('react');
var Mosaic = require('mosaic-commons');

module.exports = React.createClass({
    displayName : 'PaginatedListView',

    getInitialState : function() {
        return this._newState();
    },

    componentWillMount : function() {
        this._updateState({
            index : this.props.index,
            reset : true
        });
    },

    componentWillReceiveProps : function(props) {
        this._updateState({
            index : props.index,
            reset : true
        });
    },

    componentDidMount : function() {
        this._refocus();
    },

    componentDidUpdate : function() {
        this._refocus();
    },

    _refocus : function() {
        if (this.state.reset) {
            this._moveToItem(this.state.index || 0);
        } else {
            this._focusToIndex(this.state.index || this.state.itemsStartIndex);
        }
    },

    _getPageSize : function() {
        var pageSize = +this.props.pageSize || 50;
        return pageSize;
    },

    _updateState : function(options) {
        this.setState(this._newState(options));
    },

    update : function() {
        var idx = this.state.index || this.state.itemsStartIndex || 0;
        this._focusToIndex(idx);
    },

    _focusToIndex : function(index) {
        var that = this;
        setTimeout(function() {
            if (!that.isMounted())
                return;
            index = Math.max(index || 0, 0);
            var idx = Math.max(index - that.state.itemsStartIndex, 0);
            var scrollerElm = that.getDOMNode();
            var elm = that.refs.items.getDOMNode();
            var topOffset = elm.offsetTop;
            var children = elm.childNodes;
            idx = Math.max(0, Math.min(idx, children.length - 1));
            var child = children[idx];
            var top = 0;
            if (child) {
                top = child.offsetTop;
            }
            scrollerElm.scrollTop = top;
        }, 1);
    },

    _newState : function(options) {
        return _.extend({
            index : 0,
            length : 0,
            items : [],
            itemsStartIndex : 0,
            reset : true
        }, this.state, options);
    },

    _setPage : function(pageId, ev) {
        var pageSize = this._getPageSize();
        var index = pageId * pageSize;
        this._moveToItem(index);
        if (ev) {
            ev.stopPropagation();
            ev.preventDefault();
        }
    },

    _moveToItem : function(index) {
        var that = this;
        var length = 0;
        var itemsStartIndex = 0;
        return Mosaic.P.then(function() {
            return that.props.getItemsNumber();
        }).then(function(len) {
            length = len || 0;
            var idx = Math.max(0, Math.min(length - 1, index || 0));
            var pageSize = that._getPageSize();
            var from = Math.floor(idx / pageSize) * pageSize;
            itemsStartIndex = from;
            var to = Math.ceil(idx / pageSize) * pageSize;
            if (from === to) {
                to += pageSize;
            }
            to = Math.min(length - 1, to);
            var num = to - from;
            return that.props.renderItems({
                index : from,
                length : num
            });
        }).then(function(items) {
            that._updateState({
                index : index,
                items : items,
                itemsStartIndex : itemsStartIndex,
                length : length,
                reset : false
            });
        });
    },

    _renderPagination : function() {
        var pageSize = this._getPageSize();
        var pageIndex = Math.floor(this.state.itemsStartIndex / pageSize);
        var pageCount = Math.floor(this.state.length / pageSize) + 1;
        var buttons = [];
        if (pageCount <= 1) {
            return React.DOM.nav();
        }
        var that = this;
        function getButton(index, label, key, activeClass) {
            var className;
            if (pageIndex === index) {
                className = activeClass;
            }
            return React.DOM.li({
                key : key,
                className : className
            }, React.DOM.a({
                href : '#',
                onClick : that._setPage.bind(that, index)
            }, label));
        }
        function getSpace(index) {
            return getButton(index, '…', 'space-' + index);
        }

        var buttonsNumber = this.props.buttonsNumber || 5;

        buttons.push(getButton(0, '«', 'prev', 'disabled'));
        var from = Math.max(0, pageIndex - Math.floor(buttonsNumber / 2));
        if (from + buttonsNumber >= pageCount) {
            from = Math.max(0, pageCount - buttonsNumber);
        }
        var to = Math.min(pageCount, from + buttonsNumber);

        if (from > 0) {
            buttons.push(getSpace(Math.max(0, pageIndex - buttonsNumber)));
        }
        for (var i = from; i < to; i++) {
            buttons.push(getButton(i, (i + 1) + '', 'item-' + i, 'active'));
        }
        if (to < pageCount) {
            buttons.push(getSpace(Math.min(pageCount - 1, pageIndex + //
            buttonsNumber)));
        }
        buttons.push(getButton(pageCount - 1, '»', 'next', 'disabled'));
        var className = that.props.paginationClassName || 'pagination';
        return React.DOM.nav({}, React.DOM.ul({
            className : className
        }, buttons));
    },

    _checkPagination : function(key, defaultValue) {
        var value = this.props[key];
        if (value === undefined || value === null) {
            return defaultValue;
        } else {
            return !!value;
        }
    },

    render : function() {
        var topPagination;
        if (this._checkPagination('topPagination', false)) {
            topPagination = this._renderPagination();
        }
        var bottomPagination;
        if (this._checkPagination('bottomPagination', true)) {
            bottomPagination = this._renderPagination();
        }
        return React.DOM.div({
            className : this.props.className
        }, //
        topPagination, //
        React.DOM.div({
            ref : 'items'
        }, this.state.items),//
        bottomPagination);
    },

});
<|endoftext|>


<commit_before>/*
 * timeago: a jQuery plugin, version: 0.7.1 (2009-02-18)
 * @requires jQuery v1.2 or later
 *
 * Timeago is a jQuery plugin that makes it easy to support automatically
 * updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago").
 *
 * For usage and examples, visit:
 * http://timeago.yarp.com/
 *
 * Licensed under the MIT:
 * http://www.opensource.org/licenses/mit-license.php
 *
 * Copyright (c) 2008-2009, Ryan McGeary (ryanonjavascript -[at]- mcgeary [*dot*] org)
 */
(function($) {
  $.timeago = function(timestamp) {
    if (timestamp instanceof Date) return inWords(timestamp);
    else if (typeof timestamp == "string") return inWords($.timeago.parse(timestamp));
    else return inWords($.timeago.parse($(timestamp).attr("title")));
  };
  var $t = $.timeago;

  $.extend($.timeago, {
    settings: {
      refreshMillis: 60000,
      allowFuture: false,
      strings: {
        prefixAgo: null,
        prefixFromNow: null,
        suffixAgo: "ago",
        suffixFromNow: "from now",
        ago: null, // DEPRECATED, use suffixAgo
        fromNow: null, // DEPRECATED, use suffixFromNow
        seconds: "less than a minute",
        minute: "about a minute",
        minutes: "%d minutes",
        hour: "about an hour",
        hours: "about %d hours",
        day: "a day",
        days: "%d days",
        month: "about a month",
        months: "%d months",
        year: "about a year",
        years: "%d years"
      }
    },
    inWords: function(distanceMillis) {
      var $l = this.settings.strings;
      var prefix = $l.prefixAgo;
      var suffix = $l.suffixAgo || $l.ago;
      if (this.settings.allowFuture) {
        if (distanceMillis < 0) {
          prefix = $l.prefixFromNow;
          suffix = $l.suffixFromNow || $l.fromNow;
        }
        distanceMillis = Math.abs(distanceMillis);
      }

      var seconds = distanceMillis / 1000;
      var minutes = seconds / 60;
      var hours = minutes / 60;
      var days = hours / 24;
      var years = days / 365;

      var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) ||
        seconds < 90 && substitute($l.minute, 1) ||
        minutes < 45 && substitute($l.minutes, Math.round(minutes)) ||
        minutes < 90 && substitute($l.hour, 1) ||
        hours < 24 && substitute($l.hours, Math.round(hours)) ||
        hours < 48 && substitute($l.day, 1) ||
        days < 30 && substitute($l.days, Math.floor(days)) ||
        days < 60 && substitute($l.month, 1) ||
        days < 365 && substitute($l.months, Math.floor(days / 30)) ||
        years < 2 && substitute($l.year, 1) ||
        substitute($l.years, Math.floor(years));

      return $.trim([prefix, words, suffix].join(" "));
    },
    parse: function(iso8601) {
      var s = $.trim(iso8601);
      s = s.replace(/-/,"/").replace(/-/,"/");
      s = s.replace(/T/," ").replace(/Z/," UTC");
      s = s.replace(/([\+-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400
      return new Date(s);
    }
  });

  $.fn.timeago = function() {
    var self = this;
    self.each(refresh);

    var $s = $t.settings;
    if ($s.refreshMillis > 0) {
      setInterval(function() { self.each(refresh); }, $s.refreshMillis);
    }
    return self;
  };

  function refresh() {
    var date = $t.parse(this.title);
    if (!isNaN(date)) {
      $(this).text(inWords(date));
    }
    return this;
  }

  function inWords(date) {
    return $t.inWords(distance(date));
  }

  function distance(date) {
    return (new Date().getTime() - date.getTime());
  }

  function substitute(stringOrFunction, value) {
    var string = $.isFunction(stringOrFunction) ? stringOrFunction(value) : stringOrFunction;
    return string.replace(/%d/i, value);
  }

  // fix for IE6 suckage
  document.createElement('abbr');
})(jQuery);
<commit_msg>Version bump to v0.7.2<commit_after>/*
 * timeago: a jQuery plugin, version: 0.7.2 (2009-07-30)
 * @requires jQuery v1.2 or later
 *
 * Timeago is a jQuery plugin that makes it easy to support automatically
 * updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago").
 *
 * For usage and examples, visit:
 * http://timeago.yarp.com/
 *
 * Licensed under the MIT:
 * http://www.opensource.org/licenses/mit-license.php
 *
 * Copyright (c) 2008-2009, Ryan McGeary (ryanonjavascript -[at]- mcgeary [*dot*] org)
 */
(function($) {
  $.timeago = function(timestamp) {
    if (timestamp instanceof Date) return inWords(timestamp);
    else if (typeof timestamp == "string") return inWords($.timeago.parse(timestamp));
    else return inWords($.timeago.parse($(timestamp).attr("title")));
  };
  var $t = $.timeago;

  $.extend($.timeago, {
    settings: {
      refreshMillis: 60000,
      allowFuture: false,
      strings: {
        prefixAgo: null,
        prefixFromNow: null,
        suffixAgo: "ago",
        suffixFromNow: "from now",
        ago: null, // DEPRECATED, use suffixAgo
        fromNow: null, // DEPRECATED, use suffixFromNow
        seconds: "less than a minute",
        minute: "about a minute",
        minutes: "%d minutes",
        hour: "about an hour",
        hours: "about %d hours",
        day: "a day",
        days: "%d days",
        month: "about a month",
        months: "%d months",
        year: "about a year",
        years: "%d years"
      }
    },
    inWords: function(distanceMillis) {
      var $l = this.settings.strings;
      var prefix = $l.prefixAgo;
      var suffix = $l.suffixAgo || $l.ago;
      if (this.settings.allowFuture) {
        if (distanceMillis < 0) {
          prefix = $l.prefixFromNow;
          suffix = $l.suffixFromNow || $l.fromNow;
        }
        distanceMillis = Math.abs(distanceMillis);
      }

      var seconds = distanceMillis / 1000;
      var minutes = seconds / 60;
      var hours = minutes / 60;
      var days = hours / 24;
      var years = days / 365;

      var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) ||
        seconds < 90 && substitute($l.minute, 1) ||
        minutes < 45 && substitute($l.minutes, Math.round(minutes)) ||
        minutes < 90 && substitute($l.hour, 1) ||
        hours < 24 && substitute($l.hours, Math.round(hours)) ||
        hours < 48 && substitute($l.day, 1) ||
        days < 30 && substitute($l.days, Math.floor(days)) ||
        days < 60 && substitute($l.month, 1) ||
        days < 365 && substitute($l.months, Math.floor(days / 30)) ||
        years < 2 && substitute($l.year, 1) ||
        substitute($l.years, Math.floor(years));

      return $.trim([prefix, words, suffix].join(" "));
    },
    parse: function(iso8601) {
      var s = $.trim(iso8601);
      s = s.replace(/-/,"/").replace(/-/,"/");
      s = s.replace(/T/," ").replace(/Z/," UTC");
      s = s.replace(/([\+-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400
      return new Date(s);
    }
  });

  $.fn.timeago = function() {
    var self = this;
    self.each(refresh);

    var $s = $t.settings;
    if ($s.refreshMillis > 0) {
      setInterval(function() { self.each(refresh); }, $s.refreshMillis);
    }
    return self;
  };

  function refresh() {
    var date = $t.parse(this.title);
    if (!isNaN(date)) {
      $(this).text(inWords(date));
    }
    return this;
  }

  function inWords(date) {
    return $t.inWords(distance(date));
  }

  function distance(date) {
    return (new Date().getTime() - date.getTime());
  }

  function substitute(stringOrFunction, value) {
    var string = $.isFunction(stringOrFunction) ? stringOrFunction(value) : stringOrFunction;
    return string.replace(/%d/i, value);
  }

  // fix for IE6 suckage
  document.createElement('abbr');
})(jQuery);
<|endoftext|>


<commit_before>/* eslint-disable no-console */
// @flow

import React from 'react';
import invariant from 'invariant';

type Props = {
  continuePasting?: (string) => void,
  onExit?: () => void,
  pasteData?: string,
}

type State = {
  editedPaste: string,
}

export default class PasteDialog extends React.Component {
  state: State;
  buttonFocused: ?bool;

  constructor(props: Props) {
    super(props);
    this.state = {
      editedPaste: props.pasteData || '',
    };

    this.buttonFocused = false;
  }

  componentWillReceiveProps(props: Props) {
    this.setState({
      editedPaste: props.pasteData || '',
    });
  }

  escFunction = (e: KeyboardEvent) => {
    if ((e.key === 'Escape' || e.key === 'Esc') && this.props.onExit) {
      this.props.onExit(e);
    }
  }
  componentDidMount(){
    window.addEventListener('keydown', this.escFunction, {capture: false});
  }
  componentWillUnmount(){
    window.removeEventListener('keydown', this.escFunction, {capture: false});
  }

  doPaste = () => {
    const data = this.state.editedPaste;
    const paste = this.props.continuePasting;
    invariant(data, 'paste data must be set');
    invariant(paste, 'paste function must be set');
    paste(data);
  }

  focus = (elem: HTMLElement) => {
    if (this.buttonFocused === true) {
      elem.focus();
      this.buttonFocused = false;
    }
  }

  render() {
    if (this.props.pasteData == null || this.props.continuePasting == null) {
      this.buttonFocused = null;
      return
;
    }

    if (this.buttonFocused === null) {
      this.buttonFocused = true;
    }

    const config = window.config.getConfig();
    return

            You have a chance to edit your multiline paste
            before it reaches the terminal. Esc cancels.

          <textarea id='paste-data'
            rows={this.state.editedPaste.split('\n').length}
            style={{
              margin: '1em 0',
              background: config.backgroundColor,
              color: config.foregroundColor,
              fontSize: config.fontSize,
              borderColor: config.borderColor,
              fontFamily: config.fontFamily,
            }}
            onChange={e => this.setState({editedPaste: e.target.value})}
            value={this.state.editedPaste}
          />

            <button id='paste' onClick={this.doPaste} ref={elem => this.focus(elem)} style={{
              background: 'transparent',
              border: 'none',
              width: '20px',
              height: '20px'
            }}>
              <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000" fill={config.foregroundColor}><g><path d="M720.9,396.3c-13.3-8.4-30.9-4.5-39.3,8.8L477.2,728.2L343.8,620.8c-12.2-9.9-30.2-7.9-40,4.5c-9.8,12.4-7.8,30.4,4.4,40.3l158.1,127.2c5.1,4.1,11.3,6.3,17.8,6.3c1.6,0,3.1-0.1,4.7-0.4c8-1.3,15-6,19.3-12.9l221.4-350C738,422.5,734.1,404.8,720.9,396.3z"/><path d="M768.8,141.4h-84.3v-26h-78.2C593.4,60.7,547,10,488.8,10c-58.2,0-108,50.7-120.8,105.4h-78.2v26h-58.5c-85.4,0-155,65.8-155,151.8v540.9c0,85.9,69.5,155.9,155,155.9h537.6c85.4,0,155-70,155-155.9V293.2C923.8,207.2,854.3,141.4,768.8,141.4z M419.9,166.9v-32.8c0-36.8,32.3-71.7,68.9-71.7c36.6,0,63.9,34.9,63.9,71.7v32.8h79.1v133.6H340V166.9H419.9z M869.4,834.1c0,54.4-46.5,102.8-100.5,102.8H231.2c-54.1,0-104.7-48.4-104.7-102.8V293.2c0-54.4,50.6-98.6,104.7-98.6h58.5v159.1h394.9V194.6h84.3c54.1,0,100.5,44.3,100.5,98.6L869.4,834.1L869.4,834.1z"/></g></svg>
            </button>

;
  }
}
<commit_msg>remove eslint ignore<commit_after>// @flow

import React from 'react';
import invariant from 'invariant';

type Props = {
  continuePasting?: (string) => void,
  onExit?: () => void,
  pasteData?: string,
}

type State = {
  editedPaste: string,
}

export default class PasteDialog extends React.Component {
  state: State;
  buttonFocused: ?bool;

  constructor(props: Props) {
    super(props);
    this.state = {
      editedPaste: props.pasteData || '',
    };

    this.buttonFocused = false;
  }

  componentWillReceiveProps(props: Props) {
    this.setState({
      editedPaste: props.pasteData || '',
    });
  }

  escFunction = (e: KeyboardEvent) => {
    if ((e.key === 'Escape' || e.key === 'Esc') && this.props.onExit) {
      this.props.onExit(e);
    }
  }
  componentDidMount(){
    window.addEventListener('keydown', this.escFunction, {capture: false});
  }
  componentWillUnmount(){
    window.removeEventListener('keydown', this.escFunction, {capture: false});
  }

  doPaste = () => {
    const data = this.state.editedPaste;
    const paste = this.props.continuePasting;
    invariant(data, 'paste data must be set');
    invariant(paste, 'paste function must be set');
    paste(data);
  }

  focus = (elem: HTMLElement) => {
    if (this.buttonFocused === true) {
      elem.focus();
      this.buttonFocused = false;
    }
  }

  render() {
    if (this.props.pasteData == null || this.props.continuePasting == null) {
      this.buttonFocused = null;
      return
;
    }

    if (this.buttonFocused === null) {
      this.buttonFocused = true;
    }

    const config = window.config.getConfig();
    return

            You have a chance to edit your multiline paste
            before it reaches the terminal. Esc cancels.

          <textarea id='paste-data'
            rows={this.state.editedPaste.split('\n').length}
            style={{
              margin: '1em 0',
              background: config.backgroundColor,
              color: config.foregroundColor,
              fontSize: config.fontSize,
              borderColor: config.borderColor,
              fontFamily: config.fontFamily,
            }}
            onChange={e => this.setState({editedPaste: e.target.value})}
            value={this.state.editedPaste}
          />

            <button id='paste' onClick={this.doPaste} ref={elem => this.focus(elem)} style={{
              background: 'transparent',
              border: 'none',
              width: '20px',
              height: '20px'
            }}>
              <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000" fill={config.foregroundColor}><g><path d="M720.9,396.3c-13.3-8.4-30.9-4.5-39.3,8.8L477.2,728.2L343.8,620.8c-12.2-9.9-30.2-7.9-40,4.5c-9.8,12.4-7.8,30.4,4.4,40.3l158.1,127.2c5.1,4.1,11.3,6.3,17.8,6.3c1.6,0,3.1-0.1,4.7-0.4c8-1.3,15-6,19.3-12.9l221.4-350C738,422.5,734.1,404.8,720.9,396.3z"/><path d="M768.8,141.4h-84.3v-26h-78.2C593.4,60.7,547,10,488.8,10c-58.2,0-108,50.7-120.8,105.4h-78.2v26h-58.5c-85.4,0-155,65.8-155,151.8v540.9c0,85.9,69.5,155.9,155,155.9h537.6c85.4,0,155-70,155-155.9V293.2C923.8,207.2,854.3,141.4,768.8,141.4z M419.9,166.9v-32.8c0-36.8,32.3-71.7,68.9-71.7c36.6,0,63.9,34.9,63.9,71.7v32.8h79.1v133.6H340V166.9H419.9z M869.4,834.1c0,54.4-46.5,102.8-100.5,102.8H231.2c-54.1,0-104.7-48.4-104.7-102.8V293.2c0-54.4,50.6-98.6,104.7-98.6h58.5v159.1h394.9V194.6h84.3c54.1,0,100.5,44.3,100.5,98.6L869.4,834.1L869.4,834.1z"/></g></svg>
            </button>

;
  }
}
<|endoftext|>


<commit_before>(function($){

    /**
     * Copyright 2012, Digital Fusion
     * Licensed under the MIT license.
     * http://teamdf.com/jquery-plugins/license/
     *
     * @author Sam Sehnert
     * @desc A small plugin that checks whether elements are within
     *       the user visible viewport of a web browser.
     *       only accounts for vertical position, not horizontal.
     */
    $.fn.visible = function(partial,hidden,direction,container){

        if (this.length < 1)
            return;

        var $t          = this.length > 1 ? this.eq(0) : this,
						isContained = typeof container !== 'undefined' && container !== null,
						$w				  = isContained ? $(container) : $(window),
						wPosition        = isContained ? $w.position() : 0,
            t           = $t.get(0),
            vpWidth     = $w.outerWidth(),
            vpHeight    = $w.outerHeight(),
            direction   = (direction) ? direction : 'both',
            clientSize  = hidden === true ? t.offsetWidth * t.offsetHeight : true;

        if (typeof t.getBoundingClientRect === 'function'){

            // Use this native browser method, if available.
            var rec = t.getBoundingClientRect(),
                tViz = isContained ?
												rec.top - wPosition.top >= 0 && rec.top < vpHeight + wPosition.top :
												rec.top >= 0 && rec.top < vpHeight,
                bViz = isContained ?
												rec.bottom - wPosition.top > 0 && rec.bottom <= vpHeight + wPosition.top :
												rec.bottom > 0 && rec.bottom <= vpHeight,
                lViz = isContained ?
												rec.left - wPosition.left >= 0 && rec.left < vpWidth + wPosition.left :
												rec.left >= 0 && rec.left <  vpWidth,
                rViz = isContained ?
												rec.right - wPosition.left > 0  && rec.right < vpWidth + wPosition.left  :
												rec.right > 0 && rec.right <= vpWidth,
                vVisible   = partial ? tViz || bViz : tViz && bViz,
                hVisible   = partial ? lViz || rViz : lViz && rViz;

            if(direction === 'both')
                return clientSize && vVisible && hVisible;
            else if(direction === 'vertical')
                return clientSize && vVisible;
            else if(direction === 'horizontal')
                return clientSize && hVisible;
        } else {

            var viewTop 				= isContained ? 0 : wPosition,
                viewBottom      = viewTop + vpHeight,
                viewLeft        = $w.scrollLeft(),
                viewRight       = viewLeft + vpWidth,
                position          = $t.position(),
                _top            = position.top,
                _bottom         = _top + $t.height(),
                _left           = position.left,
                _right          = _left + $t.width(),
                compareTop      = partial === true ? _bottom : _top,
                compareBottom   = partial === true ? _top : _bottom,
                compareLeft     = partial === true ? _right : _left,
                compareRight    = partial === true ? _left : _right;

            if(direction === 'both')
                return !!clientSize && ((compareBottom <= viewBottom) && (compareTop >= viewTop)) && ((compareRight <= viewRight) && (compareLeft >= viewLeft));
            else if(direction === 'vertical')
                return !!clientSize && ((compareBottom <= viewBottom) && (compareTop >= viewTop));
            else if(direction === 'horizontal')
                return !!clientSize && ((compareRight <= viewRight) && (compareLeft >= viewLeft));
        }
    };

})(jQuery);
<commit_msg>Resolved case where element was larger than window<commit_after>(function($){

    /**
     * Copyright 2012, Digital Fusion
     * Licensed under the MIT license.
     * http://teamdf.com/jquery-plugins/license/
     *
     * @author Sam Sehnert
     * @desc A small plugin that checks whether elements are within
     *       the user visible viewport of a web browser.
     *       only accounts for vertical position, not horizontal.
     */
    $.fn.visible = function(partial,hidden,direction,container){

        if (this.length < 1)
            return;

        var $t          = this.length > 1 ? this.eq(0) : this,
						isContained = typeof container !== 'undefined' && container !== null,
						$w				  = isContained ? $(container) : $(window),
						wPosition        = isContained ? $w.position() : 0,
            t           = $t.get(0),
            vpWidth     = $w.outerWidth(),
            vpHeight    = $w.outerHeight(),
            direction   = (direction) ? direction : 'both',
            clientSize  = hidden === true ? t.offsetWidth * t.offsetHeight : true;

        if (typeof t.getBoundingClientRect === 'function'){

            // Use this native browser method, if available.
            var rec = t.getBoundingClientRect(),
                tViz = isContained ?
												rec.top - wPosition.top >= 0 && rec.top < vpHeight + wPosition.top :
												rec.top >= 0 && rec.top < vpHeight,
                bViz = isContained ?
												rec.bottom - wPosition.top > 0 && rec.bottom <= vpHeight + wPosition.top :
												rec.bottom > 0 && rec.bottom <= vpHeight,
                lViz = isContained ?
												rec.left - wPosition.left >= 0 && rec.left < vpWidth + wPosition.left :
												rec.left >= 0 && rec.left <  vpWidth,
                rViz = isContained ?
												rec.right - wPosition.left > 0  && rec.right < vpWidth + wPosition.left  :
												rec.right > 0 && rec.right <= vpWidth,
                vVisible   = partial ? tViz || bViz : tViz && bViz,
                hVisible   = partial ? lViz || rViz : lViz && rViz,
		vVisible = (rec.top < 0 && rec.bottom > vpHeight) ? true : vVisible,
                hVisible = (rec.left < 0 && rec.right > vpWidth) ? true : hVisible;

            if(direction === 'both')
                return clientSize && vVisible && hVisible;
            else if(direction === 'vertical')
                return clientSize && vVisible;
            else if(direction === 'horizontal')
                return clientSize && hVisible;
        } else {

            var viewTop 				= isContained ? 0 : wPosition,
                viewBottom      = viewTop + vpHeight,
                viewLeft        = $w.scrollLeft(),
                viewRight       = viewLeft + vpWidth,
                position          = $t.position(),
                _top            = position.top,
                _bottom         = _top + $t.height(),
                _left           = position.left,
                _right          = _left + $t.width(),
                compareTop      = partial === true ? _bottom : _top,
                compareBottom   = partial === true ? _top : _bottom,
                compareLeft     = partial === true ? _right : _left,
                compareRight    = partial === true ? _left : _right;

            if(direction === 'both')
                return !!clientSize && ((compareBottom <= viewBottom) && (compareTop >= viewTop)) && ((compareRight <= viewRight) && (compareLeft >= viewLeft));
            else if(direction === 'vertical')
                return !!clientSize && ((compareBottom <= viewBottom) && (compareTop >= viewTop));
            else if(direction === 'horizontal')
                return !!clientSize && ((compareRight <= viewRight) && (compareLeft >= viewLeft));
        }
    };

})(jQuery);
<|endoftext|>


<commit_before>//TODO: Unit test for glimmer components is not supported. Also the URL and response is already tested in other tests.

// import { A } from '@ember/array';
// import { module, test } from 'qunit';
// import { setupTest } from 'ember-qunit';

// const cloudName = 'demo';

// module('Unit | Component | cloudinary-resource-list', function (hooks) {
//   setupTest(hooks);

//   // Specify the other units that are required for this test.
//   // needs: []
//   hooks.beforeEach(function () {
//     this.owner.register('config:environment', {
//       cloudinary: { cloudName },
//     });
//   });

//   test('Cloudinary URL is composed correctly', function (assert) {
//     let component = this.owner
//       .factoryFor('component:cloudinary-resource-list')
//       .create();

//     let tag = 'test';
//     component.set('cloudinaryTag', tag);

//     let url = component.buildUrl();
//     assert.expect(
//       url,
//       `https://res.cloudinary.com/${cloudName}/image/list/${tag}.json`,
//       'Url is OK'
//     );
//   });

//   test('Response is sorted correctly', function (assert) {
//     let component = this.owner
//       .factoryFor('component:cloudinary-resource-list')
//       .create();

//     let response = {
//       resources: A([
//         { publid_id: 1, context: { custom: { order: 3 } } },
//         { publid_id: 2, context: { custom: { order: 2 } } },
//         { publid_id: 3, context: { custom: { order: 1 } } },
//       ]),
//     };

//     let orderedItems = component.handleCloudinaryResponse(response);
//     assert.expect(orderedItems[0].publid_id, 3, 'Resource items order is OK');
//   });
// });
<commit_msg>lint error<commit_after>/* eslint-disable qunit/no-commented-tests */
//TODO: Unit test for glimmer components is not supported. Also the URL and response is already tested in other tests.

// import { A } from '@ember/array';
// import { module, test } from 'qunit';
// import { setupTest } from 'ember-qunit';

// const cloudName = 'demo';

// module('Unit | Component | cloudinary-resource-list', function (hooks) {
//   setupTest(hooks);

//   // Specify the other units that are required for this test.
//   // needs: []
//   hooks.beforeEach(function () {
//     this.owner.register('config:environment', {
//       cloudinary: { cloudName },
//     });
//   });

//   test('Cloudinary URL is composed correctly', function (assert) {
//     let component = this.owner
//       .factoryFor('component:cloudinary-resource-list')
//       .create();

//     let tag = 'test';
//     component.set('cloudinaryTag', tag);

//     let url = component.buildUrl();
//     assert.expect(
//       url,
//       `https://res.cloudinary.com/${cloudName}/image/list/${tag}.json`,
//       'Url is OK'
//     );
//   });

//   test('Response is sorted correctly', function (assert) {
//     let component = this.owner
//       .factoryFor('component:cloudinary-resource-list')
//       .create();

//     let response = {
//       resources: A([
//         { publid_id: 1, context: { custom: { order: 3 } } },
//         { publid_id: 2, context: { custom: { order: 2 } } },
//         { publid_id: 3, context: { custom: { order: 1 } } },
//       ]),
//     };

//     let orderedItems = component.handleCloudinaryResponse(response);
//     assert.expect(orderedItems[0].publid_id, 3, 'Resource items order is OK');
//   });
// });
<|endoftext|>