<commit_before>/* @flow */
import React from 'react';
import { MultiGrid, AutoSizer } from 'react-virtualized';
// import 'react-virtualized/styles.css';
import { infer } from 'jsontableschema';
// import './index.css';

const ROW_HEIGHT = 36;
const COLUMN_WIDTH = 144;
const GRID_MAX_HEIGHT = ROW_HEIGHT * 10;
// The width per text character for calculating widths for columns
const COLUMN_CHARACTER_WIDTH = 7;
// The number of sample rows that should be used to infer types for columns
// and widths for columns
const SAMPLE_SIZE = 10;

type Props = {
  data: Array<Object>,
  schema: { fields: Array<Object> },
  theme: string
};

type State = {
  data: Array<Object>,
  schema: { fields: Array<Object> },
  columnWidths: Array<number>
};

function getSampleRows(data: Array<Object>, sampleSize: number): Array<Object> {
  return Array.from({ length: sampleSize }, () => {
    const index = Math.floor(Math.random() * data.length);
    return data[index];
  });
}

function inferSchema(data: Array<Object>): { fields: Array<Object> } {
  // Take a sampling of rows from data
  const sampleRows = getSampleRows(data, SAMPLE_SIZE);
  // Separate headers and values
  const headers = Array.from(
    sampleRows.reduce(
      (result, row) => new Set([...result, ...Object.keys(row)]),
      new Set()
    )
  );
  const values = sampleRows.map(row => Object.values(row));
  // Infer column types and return schema for data
  return infer(headers, values);
}

function getState(props: Props) {
  const data = props.data;
  const schema = props.schema || inferSchema(data);
  const columns = schema.fields.map(field => field.name);
  const headers = columns.reduce(
    (result, column) => ({ ...result, [column]: column }),
    {}
  );
  const columnWidths = columns.map(column => {
    const sampleRows = getSampleRows(data, SAMPLE_SIZE);
    return sampleRows.reduce(
      (result, row) =>
        `${row[column]}`.length > result ? `${row[column]}`.length : result,
      Math.ceil(COLUMN_WIDTH / COLUMN_CHARACTER_WIDTH)
    );
  });
  return {
    data: [headers, ...data],
    schema,
    columnWidths
  };
}

export default class VirtualizedGrid extends React.Component {
  props: Props;
  state: State = {
    data: [],
    schema: { fields: [] },
    columnWidths: []
  };

  componentWillMount() {
    const state = getState(this.props);
    this.setState(state);
  }

  componentWillReceiveProps(nextProps: Props) {
    const state = getState(nextProps);
    this.setState(state);
  }

  cellRenderer = (
    {
      columnIndex,
      key,
      parent,
      rowIndex,
      style
    }: {
      columnIndex: number,
      key: string,
      parent: mixed,
      rowIndex: number,
      style: Object
    }
  ) => {
    const { name: column, type } = this.state.schema.fields[columnIndex];
    const value = this.state.data[rowIndex][column];
    return (
      <div
        key={key}
        className={rowIndex === 0 || columnIndex === 0 ? 'th' : 'td'}
        style={{
          ...style,
          boxSizing: 'border-box',
          borderTop: 'none',
          borderLeft: 'none',
          overflow: 'hidden',
          whiteSpace: 'nowrap',
          textOverflow: 'ellipsis',
          // Highlight even rows
          ...(this.props.theme === 'nteract' &&
            rowIndex % 2 === 0 &&
            !(rowIndex === 0 || columnIndex === 0)
            ? { background: 'rgba(255,255,255,0.075)' }
            : {}),
          // Bold the headers
          ...(rowIndex === 0 || columnIndex === 0
            ? { fontWeight: 'bold' }
            : {}),
          // Right-align numbers
          ...(!(rowIndex === 0 || columnIndex === 0) &&
            (type === 'number' || type === 'integer')
            ? { textAlign: 'right' }
            : { textAlign: 'left' })
        }}
      >
        {value}
      </div>
    );
  };

  render() {
    const rowCount = this.state.data.length;
    const height = rowCount * ROW_HEIGHT;
    return (
      <AutoSizer disableHeight>
        {({ width }) => (
          <MultiGrid
            cellRenderer={this.cellRenderer}
            columnCount={this.state.schema.fields.length}
            columnWidth={({ index }) =>
              this.state.columnWidths[index] * COLUMN_CHARACTER_WIDTH ||
              COLUMN_WIDTH}
            fixedColumnCount={1}
            fixedRowCount={1}
            height={height < GRID_MAX_HEIGHT ? height : GRID_MAX_HEIGHT}
            rowCount={rowCount}
            rowHeight={ROW_HEIGHT}
            style={{
              border: '1px solid var(--primary-border)'
            }}
            width={width}
          />
        )}
      </AutoSizer>
    );
  }
}
<commit_msg>Improve cell border logic<commit_after>/* @flow */
import React from 'react';
import { MultiGrid, AutoSizer } from 'react-virtualized';
// import 'react-virtualized/styles.css';
import { infer } from 'jsontableschema';
// import './index.css';

const ROW_HEIGHT = 36;
const COLUMN_WIDTH = 144;
const GRID_MAX_HEIGHT = ROW_HEIGHT * 10;
// The width per text character for calculating widths for columns
const COLUMN_CHARACTER_WIDTH = 7;
// The number of sample rows that should be used to infer types for columns
// and widths for columns
const SAMPLE_SIZE = 10;

type Props = {
  data: Array<Object>,
  schema: { fields: Array<Object> },
  theme: string
};

type State = {
  data: Array<Object>,
  schema: { fields: Array<Object> },
  columnWidths: Array<number>
};

function getSampleRows(data: Array<Object>, sampleSize: number): Array<Object> {
  return Array.from({ length: sampleSize }, () => {
    const index = Math.floor(Math.random() * data.length);
    return data[index];
  });
}

function inferSchema(data: Array<Object>): { fields: Array<Object> } {
  const sampleRows = getSampleRows(data, SAMPLE_SIZE);
  const headers = Array.from(
    sampleRows.reduce(
      (result, row) => new Set([...result, ...Object.keys(row)]),
      new Set()
    )
  );
  const values = sampleRows.map(row => Object.values(row));
  return infer(headers, values);
}

function getState(props: Props) {
  const data = props.data;
  const schema = props.schema || inferSchema(data);
  const columns = schema.fields.map(field => field.name);
  const headers = columns.reduce(
    (result, column) => ({ ...result, [column]: column }),
    {}
  );
  const columnWidths = columns.map(column => {
    const sampleRows = getSampleRows(data, SAMPLE_SIZE);
    return sampleRows.reduce(
      (result, row) =>
        `${row[column]}`.length > result ? `${row[column]}`.length : result,
      Math.ceil(COLUMN_WIDTH / COLUMN_CHARACTER_WIDTH)
    );
  });
  return {
    data: [headers, ...data],
    schema,
    columnWidths
  };
}

export default class VirtualizedGrid extends React.Component {
  props: Props;
  state: State = {
    data: [],
    schema: { fields: [] },
    columnWidths: []
  };

  componentWillMount() {
    const state = getState(this.props);
    this.setState(state);
  }

  componentWillReceiveProps(nextProps: Props) {
    const state = getState(nextProps);
    this.setState(state);
  }

  cellRenderer = (
    {
      columnIndex,
      key,
      parent,
      rowIndex,
      style
    }: {
      columnIndex: number,
      key: string,
      parent: mixed,
      rowIndex: number,
      style: Object
    }
  ) => {
    const { name: column, type } = this.state.schema.fields[columnIndex];
    const value = this.state.data[rowIndex][column];
    return (
      <div
        key={key}
        className={rowIndex === 0 || columnIndex === 0 ? 'th' : 'td'}
        style={{
          ...style,
          boxSizing: 'border-box',
          overflow: 'hidden',
          whiteSpace: 'nowrap',
          textOverflow: 'ellipsis',
          // Remove top border for all cells except first row
          ...(rowIndex !== 0 ? { borderTop: 'none' } : {}),
          // Remove left border for all cells except first column
          ...(columnIndex !== 0 ? { borderLeft: 'none' } : {}),
          // Highlight even rows
          ...(this.props.theme === 'nteract' &&
            rowIndex % 2 === 0 &&
            !(rowIndex === 0 || columnIndex === 0)
            ? { background: 'rgba(255,255,255,0.075)' }
            : {}),
          // Bold the headers
          ...(rowIndex === 0 || columnIndex === 0
            ? { fontWeight: 'bold' }
            : {}),
          // Right-align numbers
          ...(!(rowIndex === 0 || columnIndex === 0) &&
            (type === 'number' || type === 'integer')
            ? { textAlign: 'right' }
            : { textAlign: 'left' })
        }}
      >
        {value}
      </div>
    );
  };

  render() {
    const rowCount = this.state.data.length;
    const height = rowCount * ROW_HEIGHT;
    return (
      <AutoSizer disableHeight>
        {({ width }) => (
          <MultiGrid
            cellRenderer={this.cellRenderer}
            columnCount={this.state.schema.fields.length}
            columnWidth={({ index }) =>
              this.state.columnWidths[index] * COLUMN_CHARACTER_WIDTH ||
              COLUMN_WIDTH}
            fixedColumnCount={1}
            fixedRowCount={1}
            height={height < GRID_MAX_HEIGHT ? height : GRID_MAX_HEIGHT}
            rowCount={rowCount}
            rowHeight={ROW_HEIGHT}
            width={width}
          />
        )}
      </AutoSizer>
    );
  }
}
<|endoftext|>


<commit_before>'use strict';

angular.module('myphotosApp')
  .controller('MainCtrl', function ($scope, $http) {
    $scope.awesomeThings = [
      'HTML5 Boilerplate',
      'AngularJS',
      'Karma'
    ];
		$http({
			url: '/api/2014',
			method: 'GET'
			}).success(function(data, status, headers, config){
				$scope.year = 2014;
				$scope.images = data
				});
  });
<commit_msg>moved everything from controller to directive, add watch value on selectyear, changes the AJAX url, add isotope function<commit_after>'use strict';

angular.module('myphotosApp')
  .controller('MainCtrl', function ($scope, $http) {
  })
	.directive('skIsotope', function($http){
		return {
		  link: function ($scope, element, attrs) {
			// wtf lol value : Informagique, 3 arguments
			// pourrave qu'on sait pas pourquoi
			/**
			 * @param {string} selectYear recupere les donne du modele
			 * @param {string} wtg Nom du param watche
			 * @param {undefined} lol undefined Informagique
			 * @param {string} value value de la bariable watche
			 */
			  $scope.watch('selectYear', function (wtf, lol, value) {
					console.log('year', value);
					$http({
					url: '/api/' + value,
					method: 'GET'
					}).success(function(data, status, headers, config){
						$scope.year = 2014;
						$scope.images = data;
						//!\  Timeout de l'enfer Ne Pas Enlever
						// Need pour que Isotope puisse se lancer
						setTimeout(function () {
							element.isotope({
								masonryHorizontal: {
									rowHeight: 200
								},
									itemSelector: '.pictures',
							})
						}, 100);
					});
				});
			}
		}
	});
<|endoftext|>


<commit_before>(function () {
  'use strict';
  angular
    .module('polls')
    .controller('PollsListController', PollsListController);

  PollsListController.$inject = [
    '$rootScope',
    '$state',
    '$scope',
    '$window',
    'Socket',
    'Action',
    'toastr',
    'ngDialog',
    'Storages',
    'Constants',
    'UserApi',
    '$timeout'
  ];

  function PollsListController(
    $rootScope,
    $state,
    $scope,
    $window,
    Socket,
    Action,
    toast,
    dialog,
    Storages,
    Constants,
    UserApi,
    $timeout
  ) {
    var vm = this;

    vm.polls = [];
    vm.hot_polls = [];
    vm.bookmarks = [];
    vm.tags = [];
    vm.new_data = [];
    vm.page = 0;
    vm.busy = false;
    vm.stopped = false;
    vm.is_has_new_polls = false;
    init();

    function init() {
      // Lắng nghe sự liện từ socket
      initSocket();
      // Load danh sách tags (Bao gồm số poll)
      get_popular_tags();
      // Load các polls có lượng like nhiều nhất
      get_populars();
      // Load danh sách poll đã bookmark
      if ($scope.isLogged) {
        // Lắng nghe sự kiện từ rootScope;
        get_bookmarks();
      }
    }

    function initSocket() {
      if (!Socket.socket) {
        Socket.connect();
      }
      Socket.emit('subscribe_public');
      Socket.on('poll_create', () => {
        vm.is_has_new_polls = true;
      });
      $scope.$on('$destroy', function () {
        Socket.emit('unsubscribe_public');
        Socket.removeListener('poll_create');
      });
    }

    vm.get_polls = get_polls;
    function get_polls() {
      if (vm.stopped || vm.busy) return;
      vm.busy = true;
      if (Storages.has_session(Constants.storages.polls)) {

      }
      Action.get_polls(vm.page)
        .then(res => {
          if (!res.data.length || res.data.length === 0) {
            vm.stopped = true;
            vm.busy = false;
            return;
          }
          // Xử lý poll trước khi hiển thị màn hình
          var promises = [];
          res.data.forEach(poll => {
            promises.push(process_before_show(poll));
          });
          return Promise.all(promises);
        })
        .then(results => {
          // Gán data vào list hiện tại
          results = results || [];
          vm.polls = _.union(vm.polls, results);
          vm.page += 1;
          vm.busy = false;
          $scope.$apply();
        })
        .catch(err => {
          vm.busy = false;
          vm.stopped = true;
          toast.error(err.message, 'Error!');
        });
    }
    function process_before_show(poll) {
      return new Promise((resolve, reject) => {
        poll = Action.process_before_show(poll);
        return resolve(poll);
      });
    }
    function get_populars() {
      Action.get_populars(0)
        .then(res => {
          vm.populars = res.data;
        })
        .catch(err => {
          toast.error(err.message, 'Error!');
        });
    }
    function get_popular_tags() {
      Action.get_popular_tags()
        .then(res => {
          vm.tags = res.data;
        })
        .catch(err => {
          toast.error(err.message, 'Error!');
        });
    }
    function get_bookmarks() {
      UserApi.get_bookmarks($scope.user._id, 0)
        .then(res => {
          vm.bookmarks = res.data || [];
        }, err => {
          toast.error(err.message, 'Error!');
        });
    }

    // Thao tác khác
    $scope.delete_poll = (poll) => {
      if (!poll.isCurrentUserOwner) {
        toast.error('You are not authorized.', 'Error!');
        return;
      }
      $scope.message_title = 'Delete poll!';
      $scope.message_content = 'Are you sure you want to delete this poll?';
      $scope.dialog_type = 3;
      $scope.buton_label = 'delete';
      dialog.openConfirm({
        scope: $scope,
        templateUrl: 'modules/core/client/views/templates/confirm.dialog.template.html'
      }).then(confirm => {
        handle_delete();
      }, reject => {
      });
      function handle_delete() {
        vm.polls = _.without(vm.polls, poll);
        Action.delete_poll(poll);
      }
    };
    $scope.report_poll = (poll) => {
      if (poll.reported) {
        toast.error('You are already reported ' + poll.title, 'Error!');
        return;
      }
      dialog.openConfirm({
        scope: $scope,
        templateUrl: 'modules/core/client/views/templates/report.dialog.template.html'
      }).then(reason => {
        handle_confirm(reason);
      }, reject => {
      });
      function handle_confirm(reason) {
        Action.save_report(poll, reason)
          .then(res => {
            poll.reported = (res) ? true : false;
            toast.success('You have successfully reported ' + poll.title, 'Thank you!');
          })
          .catch(err => {
            toast.error(err.message, 'Error!');
          });
      }
    };
    $scope.bookmark_poll = (poll) => {
      if (poll.bookmarked) {
        toast.error('You are already bookmark ' + poll.title, 'Error!');
        return;
      }
      Action.save_bookmark(poll._id)
        .then(res => {
          poll.bookmarked = (res) ? true : false;
          toast.success('Added ' + poll.title + ' to bookmarks.', 'Success!');
        })
        .catch(err => {
          toast.error(err.message, 'Error!');
        });
    };
    $scope.follow_poll = (poll) => {
      if (!$scope.isLogged) {
        toast.error('You must login to follow poll.', 'Error!');
        return;
      }
      Action.save_follow(poll.follow)
        .then(res => {
          if (res) {
            poll.follow = res;
            toast.success('You followed ' + poll.title, 'Success!');
          } else {
            poll.follow = { poll: poll._id };
          }
        })
        .catch(err => {
          toast.error(err.message, 'Error!');
        });
    };
    $scope.load_new = () => {
      $state.reload();
    };

    // Quick menu
    $scope.isOpen = false;
    $scope.isShowQuickToolTip = false;
    $scope.$watch('isOpen', function (isOpen) {
      if (isOpen) {
        $timeout(function () {
          $scope.isShowQuickToolTip = $scope.isOpen;
        }, 600);
      } else {
        $scope.isShowQuickToolTip = $scope.isOpen;
      }
    });
    $scope.q_quick_poll = () => {
      if (!$scope.isLogged) {
        $state.go('authentication.signin');
        return;
      }
      var q_quick_poll = dialog.open({
        template: 'modules/polls/client/views/quick-poll.client.view.html',
        controller: 'QuickPollController',
        controllerAs: 'ctrl',
        appendClassName: 'images-upload-dialog',
        closeByDocument: false
      });
      q_quick_poll.closePromise.then(function (result) {
        console.log(result);
      });
    };
    $scope.q_post_poll = () => {
      $state.go('polls.create');
    };
    $scope.q_search = () => {
      $state.go('search');
    };
  }
})();
<commit_msg>Commited from lenh at Thu, Aug 24, 2017  3:25:18 PM<commit_after>(function () {
  'use strict';
  angular
    .module('polls')
    .controller('PollsListController', PollsListController);

  PollsListController.$inject = [
    '$rootScope',
    '$state',
    '$scope',
    '$window',
    'Socket',
    'Action',
    'toastr',
    'ngDialog',
    'Storages',
    'Constants',
    'UserApi',
    '$timeout'
  ];

  function PollsListController(
    $rootScope,
    $state,
    $scope,
    $window,
    Socket,
    Action,
    toast,
    dialog,
    Storages,
    Constants,
    UserApi,
    $timeout
  ) {
    var vm = this;

    vm.polls = [];
    vm.hot_polls = [];
    vm.bookmarks = [];
    vm.tags = [];
    vm.new_data = [];
    vm.page = 0;
    vm.busy = false;
    vm.stopped = false;
    vm.is_has_new_polls = false;
    init();

    function init() {
      // Lắng nghe sự liện từ socket
      initSocket();
      // Load danh sách tags (Bao gồm số poll)
      get_popular_tags();
      // Load các polls có lượng like nhiều nhất
      get_populars();
      // Load danh sách poll đã bookmark
      if ($scope.isLogged) {
        // Lắng nghe sự kiện từ rootScope;
        get_bookmarks();
      }
    }

    function initSocket() {
      if (!Socket.socket) {
        Socket.connect();
      }
      Socket.emit('subscribe_public');
      Socket.on('poll_create', () => {
        vm.is_has_new_polls = true;
      });
      $scope.$on('$destroy', function () {
        Socket.emit('unsubscribe_public');
        Socket.removeListener('poll_create');
      });
    }

    vm.get_polls = get_polls;
    function get_polls() {
      if (vm.stopped || vm.busy) return;
      vm.busy = true;
      if (Storages.has_session(Constants.storages.polls)) {

      }
      Action.get_polls(vm.page)
        .then(res => {
          if (!res.data.length || res.data.length === 0) {
            vm.stopped = true;
            vm.busy = false;
            return;
          }
          // Xử lý poll trước khi hiển thị màn hình
          var promises = [];
          res.data.forEach(poll => {
            promises.push(process_before_show(poll));
          });
          return Promise.all(promises);
        })
        .then(results => {
          // Gán data vào list hiện tại
          results = results || [];
          vm.polls = _.union(vm.polls, results);
          vm.page += 1;
          vm.busy = false;
          $scope.$apply();
        })
        .catch(err => {
          vm.busy = false;
          vm.stopped = true;
          toast.error(err.message, 'Error!');
        });
    }
    function process_before_show(poll) {
      return new Promise((resolve, reject) => {
        poll = Action.process_before_show(poll);
        return resolve(poll);
      });
    }
    function get_populars() {
      Action.get_populars(0)
        .then(res => {
          vm.populars = res.data;
        })
        .catch(err => {
          toast.error(err.message, 'Error!');
        });
    }
    function get_popular_tags() {
      Action.get_popular_tags()
        .then(res => {
          vm.tags = res.data;
        })
        .catch(err => {
          toast.error(err.message, 'Error!');
        });
    }
    function get_bookmarks() {
      UserApi.get_bookmarks($scope.user._id, 0)
        .then(res => {
          vm.bookmarks = res.data || [];
        }, err => {
          toast.error(err.message, 'Error!');
        });
    }

    // Thao tác khác
    $scope.delete_poll = (poll) => {
      if (!poll.isCurrentUserOwner) {
        toast.error('You are not authorized.', 'Error!');
        return;
      }
      $scope.message_title = 'Delete poll!';
      $scope.message_content = 'Are you sure you want to delete this poll?';
      $scope.dialog_type = 3;
      $scope.buton_label = 'delete';
      dialog.openConfirm({
        scope: $scope,
        templateUrl: 'modules/core/client/views/templates/confirm.dialog.template.html'
      }).then(confirm => {
        handle_delete();
      }, reject => {
      });
      function handle_delete() {
        vm.polls = _.without(vm.polls, poll);
        Action.delete_poll(poll);
      }
    };
    $scope.report_poll = (poll) => {
      if (poll.reported) {
        toast.error('You are already reported ' + poll.title, 'Error!');
        return;
      }
      dialog.openConfirm({
        scope: $scope,
        templateUrl: 'modules/core/client/views/templates/report.dialog.template.html'
      }).then(reason => {
        handle_confirm(reason);
      }, reject => {
      });
      function handle_confirm(reason) {
        Action.save_report(poll, reason)
          .then(res => {
            poll.reported = (res) ? true : false;
            toast.success('You have successfully reported ' + poll.title, 'Thank you!');
          })
          .catch(err => {
            toast.error(err.message, 'Error!');
          });
      }
    };
    $scope.bookmark_poll = (poll) => {
      if (poll.bookmarked) {
        toast.error('You are already bookmark ' + poll.title, 'Error!');
        return;
      }
      Action.save_bookmark(poll._id)
        .then(res => {
          poll.bookmarked = (res) ? true : false;
          toast.success('Added ' + poll.title + ' to bookmarks.', 'Success!');
        })
        .catch(err => {
          toast.error(err.message, 'Error!');
        });
    };
    $scope.follow_poll = (poll) => {
      if (!$scope.isLogged) {
        toast.error('You must login to follow poll.', 'Error!');
        return;
      }
      Action.save_follow(poll.follow)
        .then(res => {
          if (res) {
            poll.follow = res;
            toast.success('You followed ' + poll.title, 'Success!');
          } else {
            poll.follow = { poll: poll._id };
          }
        })
        .catch(err => {
          toast.error(err.message, 'Error!');
        });
    };
    $scope.load_new = () => {
      $state.reload();
    };

    // Quick menu
    $scope.isOpen = false;
    $scope.q_quick_poll = () => {
      if (!$scope.isLogged) {
        $state.go('authentication.signin');
        return;
      }
      var q_quick_poll = dialog.open({
        template: 'modules/polls/client/views/quick-poll.client.view.html',
        controller: 'QuickPollController',
        controllerAs: 'ctrl',
        appendClassName: 'images-upload-dialog',
        closeByDocument: false
      });
      q_quick_poll.closePromise.then(function (result) {
        console.log(result);
      });
    };
    $scope.q_post_poll = () => {
      $state.go('polls.create');
    };
    $scope.q_search = () => {
      $state.go('search');
    };
  }
})();
<|endoftext|>


<commit_before>/**
 * @file Define multiple non-enumerable properties at once.
 * @see {@link https://www.npmjs.com/package/define-properties|define-properties}
 * @version 3.1.0
 * @author Xotic750 <Xotic750@gmail.com>
 * @copyright  Xotic750
 * @license {@link <https://opensource.org/licenses/MIT> MIT}
 * @module define-properties-x
 */

import isFunction from 'is-function-x';

import isUndefined from 'validate.io-undefined';
import forEach from 'array-for-each-x';
import defineProperty from 'object-define-property-x';
import isFalsey from 'is-falsey-x';
import getKeys from 'get-own-enumerable-keys-x';

/**
 * Method `property`.
 *
 * @private
 * @param {object} object - The object on which to define the property.
 * @param {string|Symbol} prop - The property name.
 * @param {*} value - The value of the property.
 * @param {boolean} [force=false] - If `true` then set property regardless.
 */
// eslint-disable-next-line max-params
const $property = function property(object, prop, value, force) {
  if (prop in object && isFalsey(force)) {
    return;
  }

  defineProperty(object, prop, {
    configurable: true,
    enumerable: false,
    value,
    writable: true,
  });
};

/**
 * Method `properties`.
 *
 * @private
 * @param {object} object - The object on which to define the property.
 * @param {object} map - The object of properties.
 * @param {object} [predicates] - The object of property predicates.
 */
const $properties = function properties(object, map, predicates) {
  const preds = isUndefined(predicates) ? {} : predicates;
  forEach(getKeys(map), function(name) {
    const predicate = preds[name];
    $property(object, name, map[name], isFunction(predicate) && predicate());
  });
};

export default {
  /**
   * Define multiple non-enumerable properties at once.
   * Uses `Object.defineProperty` when available; falls back to standard
   * assignment in older engines. Existing properties are not overridden.
   * Accepts a map of property names to a predicate that, when true,
   * force-overrides.
   *
   * @function
   * @param {object} object - The object on which to define the property.
   * @param {object} map - The object of properties.
   * @param {object} [predicates] - The object of property predicates.
   * @example
   * var define = require('define-properties-x');
   * define.properties({
   *   a: 1,
   *   b: 2
   * }, {
   *   a: function () { return false; },
   *   b: function () { return true; }
   * });
   */
  properties: $properties,
  /**
   * Just like `properties` but for defining a single non-enumerable
   * property. Useful in environments that do not
   * support `Computed property names`. This can be done
   * with `properties`, but this method can read a little cleaner.
   *
   * @function
   * @param {object} object - The object on which to define the property.
   * @param {string|Symbol} prop - The property name.
   * @param {*} value - The value of the property.
   * @param {boolean} [force=false] - If `true` then set property regardless.
   * @example
   * var define = require('define-properties-x');
   * var myString = 'something';
   * define.property(obj, Symbol.iterator, function () {}, true);
   * define.property(obj, myString, function () {}, true);
   */
  property: $property,
};
<commit_msg>Terraformed<commit_after>import isFunction from 'is-function-x';

import isUndefined from 'validate.io-undefined';
import forEach from 'array-for-each-x';
import defineProperty from 'object-define-property-x';
import isFalsey from 'is-falsey-x';
import getKeys from 'get-own-enumerable-keys-x';

/**
 * Method `property`.
 *
 * @private
 * @param {object} object - The object on which to define the property.
 * @param {string|Symbol} prop - The property name.
 * @param {*} value - The value of the property.
 * @param {boolean} [force=false] - If `true` then set property regardless.
 */
// eslint-disable-next-line max-params
const $property = function property(object, prop, value, force) {
  if (prop in object && isFalsey(force)) {
    return;
  }

  defineProperty(object, prop, {
    configurable: true,
    enumerable: false,
    value,
    writable: true,
  });
};

/**
 * Method `properties`.
 *
 * @private
 * @param {object} object - The object on which to define the property.
 * @param {object} map - The object of properties.
 * @param {object} [predicates] - The object of property predicates.
 */
const $properties = function properties(object, map, predicates) {
  const preds = isUndefined(predicates) ? {} : predicates;
  forEach(getKeys(map), function(name) {
    const predicate = preds[name];
    $property(object, name, map[name], isFunction(predicate) && predicate());
  });
};

export default {
  /**
   * Define multiple non-enumerable properties at once.
   * Uses `Object.defineProperty` when available; falls back to standard
   * assignment in older engines. Existing properties are not overridden.
   * Accepts a map of property names to a predicate that, when true,
   * force-overrides.
   *
   * @function
   * @param {object} object - The object on which to define the property.
   * @param {object} map - The object of properties.
   * @param {object} [predicates] - The object of property predicates.
   */
  properties: $properties,
  /**
   * Just like `properties` but for defining a single non-enumerable
   * property. Useful in environments that do not
   * support `Computed property names`. This can be done
   * with `properties`, but this method can read a little cleaner.
   *
   * @function
   * @param {object} object - The object on which to define the property.
   * @param {string|Symbol} prop - The property name.
   * @param {*} value - The value of the property.
   * @param {boolean} [force=false] - If `true` then set property regardless.
   */
  property: $property,
};
<|endoftext|>


<commit_before>/**
 * Render the page server side
 * @see https://github.com/szomolanyi/MeteorApolloStarter/blob/master/imports/startup/server/ssr.js
 * @see https://github.com/apollographql/GitHunt-React/blob/master/src/server.js
 * @see https://www.apollographql.com/docs/react/features/server-side-rendering.html#renderToStringWithData
 */
import React from 'react';
import ReactDOM from 'react-dom/server';
import { getDataFromTree } from 'react-apollo';
import { computeContextFromReq } from '../apollo-server/context.js';

import { runCallbacks } from '../../modules/callbacks';
import { createClient } from './apolloClient';

import Head from './components/Head';
import ApolloState from './components/ApolloState';
import AppGenerator from './components/AppGenerator';

const makePageRenderer = async sink => {
  const req = sink.request;
  // according to the Apollo doc, client needs to be recreated on every request
  // this avoids caching server side
  const client = await createClient(await computeContextFromReq(req));

  // Used by callbacks to handle side effects
  // E.g storing the stylesheet generated by styled-components
  const context = {};

  // Allows components to set statuscodes and redirects that will get executed on the server
  let serverRequestStatus = {}

  // TODO: req object does not seem to have been processed by the Express
  // middlewares at this point
  // @see https://github.com/meteor/meteor-feature-requests/issues/174#issuecomment-441047495

  const App = <AppGenerator req={req} apolloClient={client} serverRequestStatus={serverRequestStatus} />;

  // run user registered callbacks that wraps the React app
  const WrappedApp = runCallbacks({
    name: 'router.server.wrapper',
    iterator: App,
    properties: { req, context, apolloClient: client },
  });

  let htmlContent = '';
  try {
    // LESSWRONG: Split a call to renderToStringWithData into getDataFromTree
    // followed by ReactDOM.renderToString, then pass a context variable
    // isGetDataFromTree to only the getDataFromTree call. This is to enable
    // a hack in packages/lesswrong/server/material-ui/themeProvider.js.
    //
    // In getDataFromTree, the order in which components are rendered is
    // complicated and depends on what HoCs they have and the order in which
    // results come back from the database; whereas in
    // ReactDOM.renderToString, the render order is simply an inorder
    // traversal of the resulting virtual DOM. When the client rehydrates the
    // SSR, it traverses inorder, like renderToString did.
    //
    // Ordinarily the render order wouldn't matter, except that material-UI
    // JSS stylesheet generation happens on first render, and it generates
    // some class names which contain an iterating counter, which needs to
    // match between client and server.
    //
    // So the hacky solution is: when rendering for getDataFromTree, we pass
    // a context variable isGetDataFromTree, and if that's present and true,
    // we suppress JSS style generation.
    await getDataFromTree(WrappedApp, {isGetDataFromTree: true});
  } catch (err) {
    console.error(`Error while server-rendering. date: ${new Date().toString()} url: ${req.url}`); // eslint-disable-line no-console
    console.error(err);
    // // show error in client in dev
    // if (Meteor.isDevelopment) {
    //   htmlContent = `Error while server-rendering: ${err.message}`;
    // }
  }

  htmlContent = await ReactDOM.renderToString(WrappedApp);

  if(serverRequestStatus.status) {
    sink.setStatusCode(serverRequestStatus.status)
  }
  if(serverRequestStatus.redirectUrl) {
    if (!serverRequestStatus.status) console.warn("No redirect status set, defaulting to 301")
    sink.redirect(serverRequestStatus.redirectUrl, serverRequestStatus.status || 301)
  }

  // TODO: there should be a cleaner way to set this wrapper
  // id must always match the client side start.jsx file
  const wrappedHtmlContent = `<div id="react-app">${htmlContent}</div>`;
  sink.appendToBody(wrappedHtmlContent);
  // TODO: this sounds cleaner but where do we add the
 ?
  //sink.renderIntoElementById('react-app', content)

  // add headers using helmet
  const head = ReactDOM.renderToString();
  sink.appendToHead(head);

  // add Apollo state, the client will then parse the string
  const initialState = client.extract();
  const serializedApolloState = ReactDOM.renderToString(
    <ApolloState initialState={initialState} />
  );
  sink.appendToBody(serializedApolloState);

  // post render callback
  runCallbacks({
    name: 'router.server.postRender',
    iterator: sink,
    properties: { context },
  });
};

export default makePageRenderer;<commit_msg>Move rendering back into try-catch<commit_after>/**
 * Render the page server side
 * @see https://github.com/szomolanyi/MeteorApolloStarter/blob/master/imports/startup/server/ssr.js
 * @see https://github.com/apollographql/GitHunt-React/blob/master/src/server.js
 * @see https://www.apollographql.com/docs/react/features/server-side-rendering.html#renderToStringWithData
 */
import React from 'react';
import ReactDOM from 'react-dom/server';
import { getDataFromTree } from 'react-apollo';
import { computeContextFromReq } from '../apollo-server/context.js';

import { runCallbacks } from '../../modules/callbacks';
import { createClient } from './apolloClient';

import Head from './components/Head';
import ApolloState from './components/ApolloState';
import AppGenerator from './components/AppGenerator';

const makePageRenderer = async sink => {
  const req = sink.request;
  // according to the Apollo doc, client needs to be recreated on every request
  // this avoids caching server side
  const client = await createClient(await computeContextFromReq(req));

  // Used by callbacks to handle side effects
  // E.g storing the stylesheet generated by styled-components
  const context = {};

  // Allows components to set statuscodes and redirects that will get executed on the server
  let serverRequestStatus = {}

  // TODO: req object does not seem to have been processed by the Express
  // middlewares at this point
  // @see https://github.com/meteor/meteor-feature-requests/issues/174#issuecomment-441047495

  const App = <AppGenerator req={req} apolloClient={client} serverRequestStatus={serverRequestStatus} />;

  // run user registered callbacks that wraps the React app
  const WrappedApp = runCallbacks({
    name: 'router.server.wrapper',
    iterator: App,
    properties: { req, context, apolloClient: client },
  });

  let htmlContent = '';
  try {
    // LESSWRONG: Split a call to renderToStringWithData into getDataFromTree
    // followed by ReactDOM.renderToString, then pass a context variable
    // isGetDataFromTree to only the getDataFromTree call. This is to enable
    // a hack in packages/lesswrong/server/material-ui/themeProvider.js.
    //
    // In getDataFromTree, the order in which components are rendered is
    // complicated and depends on what HoCs they have and the order in which
    // results come back from the database; whereas in
    // ReactDOM.renderToString, the render order is simply an inorder
    // traversal of the resulting virtual DOM. When the client rehydrates the
    // SSR, it traverses inorder, like renderToString did.
    //
    // Ordinarily the render order wouldn't matter, except that material-UI
    // JSS stylesheet generation happens on first render, and it generates
    // some class names which contain an iterating counter, which needs to
    // match between client and server.
    //
    // So the hacky solution is: when rendering for getDataFromTree, we pass
    // a context variable isGetDataFromTree, and if that's present and true,
    // we suppress JSS style generation.
    await getDataFromTree(WrappedApp, {isGetDataFromTree: true});
    htmlContent = await ReactDOM.renderToString(WrappedApp);
  } catch (err) {
    console.error(`Error while server-rendering. date: ${new Date().toString()} url: ${req.url}`); // eslint-disable-line no-console
    console.error(err);
    // // show error in client in dev
    // if (Meteor.isDevelopment) {
    //   htmlContent = `Error while server-rendering: ${err.message}`;
    // }
  }

  if(serverRequestStatus.status) {
    sink.setStatusCode(serverRequestStatus.status)
  }
  if(serverRequestStatus.redirectUrl) {
    if (!serverRequestStatus.status) console.warn("No redirect status set, defaulting to 301")
    sink.redirect(serverRequestStatus.redirectUrl, serverRequestStatus.status || 301)
  }

  // TODO: there should be a cleaner way to set this wrapper
  // id must always match the client side start.jsx file
  const wrappedHtmlContent = `<div id="react-app">${htmlContent}</div>`;
  sink.appendToBody(wrappedHtmlContent);
  // TODO: this sounds cleaner but where do we add the
 ?
  //sink.renderIntoElementById('react-app', content)

  // add headers using helmet
  const head = ReactDOM.renderToString();
  sink.appendToHead(head);

  // add Apollo state, the client will then parse the string
  const initialState = client.extract();
  const serializedApolloState = ReactDOM.renderToString(
    <ApolloState initialState={initialState} />
  );
  sink.appendToBody(serializedApolloState);

  // post render callback
  runCallbacks({
    name: 'router.server.postRender',
    iterator: sink,
    properties: { context },
  });
};

export default makePageRenderer;<|endoftext|>


<commit_before>var divEl = document.getElementById('testdiv');
divEl.innerHTML = "Onload not required";
divEl.style.color = 'red';

window.onmessage = (event) => {
  divEl = document.getElementById('testdiv');
  divEl.innerHTML = "messages arriving";
  divEl.style.color = 'green';
};

window.onload = function() {

  var divEl = document.getElementById('testdiv');
  divEl.innerHTML = "Onload happened";
  divEl.style.color = 'blue';

  window.onmessage = (event) => {
    console.log("C1 message received from parent");
    if (event.data) {
      // console.log(JSON.stringify(event));
      // console.log(JSON.stringify(event.data));

      if (event.data.action === "Init") {
          initUI(event.data.content);
      } else if (event.data.action === "Freeze") {
          console.log("C1 Freeze request");
          setFrozen(true);
      } else if (event.data.action === "Unfreeze") {
          console.log("C1 Unfreeze request");
          setFrozen(false);
      } else if (event.data.action === "Remove") {
          removeIngredient(event.data.content);
      }
    }
  }
}

const assets = "http://alexlamb.github.io/js/assets/"
// const assets = "assets/"
const leftChev = "chevron-left.png";
const rightChev = "chevron-right.png";
const width = 1000;
const height = 130;
const optionsWidth = width - 100;
const optionOffset = 45;
const itemsPerPage = 6;
const itemWidth = 150;
const itemHeight = 100;

var optionButtons = [];
var optionBorders = [];
var optionRects = [];
var optionShades = [];
var buttons;
var state;
var buttonData;
var frozen = false;
var shift = 0;
var pages = 1;
var page = 0;
// var selected = 0;

var leftChevron;
var rightChevron;

function initUI(data) {
    buttonData = data;
    state = new Array(data.length);
    state.fill(0);

    pages = Math.floor((data.length * itemWidth) / optionsWidth);
    console.log("C1 pages:"+pages);

    frozen = false;

    var buttonSideW = itemWidth * 3 / 4;
    var buttonSideH = itemHeight * 3 / 4;
    var buttonRimW = (itemWidth - buttonSideW) / 2;
    var buttonRimH = (itemHeight - buttonSideH) / 2;
    var borderSideW = itemWidth * 5 / 6;
    var borderSideH = itemHeight * 5 / 6;
    var borderRimW = (itemWidth - borderSideW) / 2;
    var borderRimH = (itemHeight - borderSideH) / 2;

    var svgNode = document.getElementById("svgCanvas");
    while (svgNode.firstChild) {
        svgNode.removeChild(svgNode.firstChild);
    }

    draw = SVG('svgCanvas').size(width, height);
    draw.rect(width, height).fill("#F0F0F0");
    buttons = draw.group();
    edges = draw.group();

    for (let i = 0; i < data.length; i++) {
        var item = data[i];

        let optionRect = buttons.rect(borderSideW,borderSideH).fill('none');
        optionRect.move(borderRimW+(optionOffset+i*itemWidth),borderRimH);
        optionRect.radius(15);
        optionRects.push(optionRect);

        let optionShade = buttons.rect(borderSideW,borderSideH).fill('none');
        optionShade.move(borderRimW+(optionOffset+i*itemWidth),borderRimH);
        optionShade.radius(15);
        optionShades.push(optionShade);

        let optionButton = buttons.image(assets+data[i].image,buttonSideW,buttonSideH);
        optionButtons.push(optionButton);
        optionButton.move(buttonRimW+(optionOffset+i*itemWidth),buttonRimH);

        optionButton.style('cursor', 'pointer');
        optionButton.click(function() {selectOption(i)});
        optionButton.mouseover(function() {highlightOption(i)});
        optionButton.mouseout(function() {fadeOption(i)});

        let optionBorder = buttons.rect(borderSideW,borderSideH);
        optionBorders.push(optionBorder);
        optionBorder.fill('none').stroke({color: 'Silver', width: 1});
        optionBorder.move(borderRimW+(optionOffset+i*itemWidth),borderRimH);
        optionBorder.radius(15);

        let optionText = buttons.text(data[i].name);
        let length = optionText.length();
        let adjust = (borderSideW - length)/2;
        optionText.move(borderRimW+(optionOffset+i*itemWidth)+adjust,borderRimH+borderSideH+10);
        optionText.fill('Black');
    }

    leftEdge = edges.rect(optionOffset, height);
    leftEdge.fill('#F0F0F0');
    leftEdge.click(function() {pageLeft()});
    // leftIm = edges.image(assets+leftChev,optionOffset, height);
    // leftIm.click(function() {pageLeft()});

    rightEdge = edges.rect(optionOffset, height).move(width-(optionOffset),0);
    rightEdge.fill('#F0F0F0');
    rightEdge.click(function() {pageRight()});

    // rimX = edges.rect(width,height);
    // rimX.fill('none').stroke('Silver');

    const chevronL = optionOffset/2 - 10;
    const chevronR = optionOffset/2 + 10;
    const chevronT = height/2 - 18;
    const chevronB = height/2 + 18;

    let leftPathString = "M "+chevronR+" "+chevronT+" ";
    leftPathString += "L "+chevronL+" "+(height/2)+" ";
    leftPathString += "L "+chevronR+" "+chevronB+" ";
    leftChevron = edges.path(leftPathString);
    let chevStroke = {
        width:4,
        color:'Gray',
        linecap:'round'
    };

    leftChevron.fill('none').stroke(chevStroke);

    let rightPathString = "M "+chevronL+" "+chevronT+" ";
    rightPathString += "L "+chevronR+" "+(height/2)+" ";
    rightPathString += "L "+chevronL+" "+chevronB+" ";
    rightChevron = edges.path(rightPathString);
    rightChevron.fill('none').stroke(chevStroke);
    rightChevron.dmove(width-(optionOffset+5),0);

    // updateChevrons();
}

function highlightOption(i) {
    console.log("C1 highlight:"+i);
    if (!frozen || state[i] > 0) {
        optionShades[i].animate(5).fill('White');
    }
}

function fadeOption(i) {
    console.log("C1 fade:"+i+" frozen:"+frozen+" state:"+state[i]+" func:"+(!frozen || state[i] > 1));
    if (!frozen || state[i] > 0) {
        console.log("C1 fading");
        optionShades[i].animate(5).fill('none');
    }
}

function pageLeft() {
    if (page > 0) {
        page--;
        buttons.animate(250).dmove(itemWidth*itemsPerPage,0);
        // updateChevrons();
    } else {
        page = pages - 1;
        buttons.dmove(-itemWidth*itemsPerPage*pages,0);
        buttons.animate(250).dmove(itemWidth*itemsPerPage,0);
    }
    console.log("C1 page:"+page+" shift:"+buttons.x());
}

function pageRight() {
    if (page < pages-1) {
        page++;
        buttons.animate(250).dmove(-itemWidth*itemsPerPage,0);
        // updateChevrons();
    } else {
        page = 0;
        buttons.dmove(itemWidth*itemsPerPage*pages,0);
        buttons.animate(250).dmove(-itemWidth*itemsPerPage,0);
    }
    console.log("C1 page:"+page+" shift:"+buttons.x());
}

// function updateChevrons() {
//     console.log("page:"+page+" pages:"+pages);
//     if (page == 0) {
//         leftChevron.stroke('none');
//     } else {
//         leftChevron.stroke('Gray');
//     }
//     if (page == pages - 1) {
//         rightChevron.stroke('none');
//     } else {
//         rightChevron.stroke('Gray');
//     }
// }

function setFrozen(value) {
    console.log("C1 setFrozen");
    frozen = value;

    for (let i = 0; i < state.length; i++) {
        if (state[i] == 0) {
            if (frozen) {
                // optionBorders[i].stroke('DimGray');
                optionRects[i].fill('DimGray');
            } else {
                // optionBorders[i].stroke('Silver');
                optionRects[i].fill('none');
            }
        }
    }
}

function selectOption(i) {

    let sendMessage = false;

    console.log("C1 selectOption:"+i);
    // if (state[i] == 0 && !frozen && selected < 5) {
    if (state[i] == 0 && !frozen) {
        optionBorders[i].stroke({color:'#52009A', width:2});
        optionRects[i].fill('#BAB6CA');
        state[i] = 1;
        sendMessage = true;
        // selected++;
        // if (selected >= 5) {
        //     setFrozen(true);
        // }

    // } else if (state[i] > 0 && selected < 5) {
    } else if (state[i] > 0) {
        optionBorders[i].stroke({color:'Silver', width:1});
        console.log("C1 Unfreezing");
        state[i] = 0;
        setFrozen(false);
        sendMessage = true;
        // selected--;
    }

    if (sendMessage) {
        var message = {
            action: "UpdateSelection",
            selection: state
        };
        window.parent.postMessage(message,"*");
    }
    // console.log("Selected:"+selected);
}

function removeIngredient(data) {
    for (let i = 0; i < data.length; i++) {
        if (data[i] == 0 && state[i] > 0) {

            optionBorders[i].stroke('none');
            console.log("C1 Unfreezing");
            state[i] = 0;
            setFrozen(false);
        }
    }
}
<commit_msg>Update iChild1.js<commit_after>var divEl = document.getElementById('testdiv');
divEl.innerHTML = "Onload not required";
divEl.style.color = 'red';

window.onmessage = (event) => {
  divEl = document.getElementById('testdiv');
  divEl.innerHTML = "messages arriving";
  divEl.style.color = 'green';
};

window.onload = function() {

  var divEl = document.getElementById('testdiv');
  divEl.innerHTML = "Onload happened";
  divEl.style.color = 'blue';

  window.onmessage = (event) => {
    console.log("C1 message received from parent");
    if (event.data) {
      // console.log(JSON.stringify(event));
      // console.log(JSON.stringify(event.data));

      if (event.data.action === "Init") {
          initUI(event.data.content);
      } else if (event.data.action === "Freeze") {
          console.log("C1 Freeze request");
          setFrozen(true);
      } else if (event.data.action === "Unfreeze") {
          console.log("C1 Unfreeze request");
          setFrozen(false);
      } else if (event.data.action === "Remove") {
          removeIngredient(event.data.content);
      }
    }
  }
}

const assets = "https://alexlamb.github.io/js/assets/"
// const assets = "assets/"
const leftChev = "chevron-left.png";
const rightChev = "chevron-right.png";
const width = 1000;
const height = 130;
const optionsWidth = width - 100;
const optionOffset = 45;
const itemsPerPage = 6;
const itemWidth = 150;
const itemHeight = 100;

var optionButtons = [];
var optionBorders = [];
var optionRects = [];
var optionShades = [];
var buttons;
var state;
var buttonData;
var frozen = false;
var shift = 0;
var pages = 1;
var page = 0;
// var selected = 0;

var leftChevron;
var rightChevron;

function initUI(data) {
    buttonData = data;
    state = new Array(data.length);
    state.fill(0);

    pages = Math.floor((data.length * itemWidth) / optionsWidth);
    console.log("C1 pages:"+pages);

    frozen = false;

    var buttonSideW = itemWidth * 3 / 4;
    var buttonSideH = itemHeight * 3 / 4;
    var buttonRimW = (itemWidth - buttonSideW) / 2;
    var buttonRimH = (itemHeight - buttonSideH) / 2;
    var borderSideW = itemWidth * 5 / 6;
    var borderSideH = itemHeight * 5 / 6;
    var borderRimW = (itemWidth - borderSideW) / 2;
    var borderRimH = (itemHeight - borderSideH) / 2;

    var svgNode = document.getElementById("svgCanvas");
    while (svgNode.firstChild) {
        svgNode.removeChild(svgNode.firstChild);
    }

    draw = SVG('svgCanvas').size(width, height);
    draw.rect(width, height).fill("#F0F0F0");
    buttons = draw.group();
    edges = draw.group();

    for (let i = 0; i < data.length; i++) {
        var item = data[i];

        let optionRect = buttons.rect(borderSideW,borderSideH).fill('none');
        optionRect.move(borderRimW+(optionOffset+i*itemWidth),borderRimH);
        optionRect.radius(15);
        optionRects.push(optionRect);

        let optionShade = buttons.rect(borderSideW,borderSideH).fill('none');
        optionShade.move(borderRimW+(optionOffset+i*itemWidth),borderRimH);
        optionShade.radius(15);
        optionShades.push(optionShade);

        let optionButton = buttons.image(assets+data[i].image,buttonSideW,buttonSideH);
        optionButtons.push(optionButton);
        optionButton.move(buttonRimW+(optionOffset+i*itemWidth),buttonRimH);

        optionButton.style('cursor', 'pointer');
        optionButton.click(function() {selectOption(i)});
        optionButton.mouseover(function() {highlightOption(i)});
        optionButton.mouseout(function() {fadeOption(i)});

        let optionBorder = buttons.rect(borderSideW,borderSideH);
        optionBorders.push(optionBorder);
        optionBorder.fill('none').stroke({color: 'Silver', width: 1});
        optionBorder.move(borderRimW+(optionOffset+i*itemWidth),borderRimH);
        optionBorder.radius(15);

        let optionText = buttons.text(data[i].name);
        let length = optionText.length();
        let adjust = (borderSideW - length)/2;
        optionText.move(borderRimW+(optionOffset+i*itemWidth)+adjust,borderRimH+borderSideH+10);
        optionText.fill('Black');
    }

    leftEdge = edges.rect(optionOffset, height);
    leftEdge.fill('#F0F0F0');
    leftEdge.click(function() {pageLeft()});
    // leftIm = edges.image(assets+leftChev,optionOffset, height);
    // leftIm.click(function() {pageLeft()});

    rightEdge = edges.rect(optionOffset, height).move(width-(optionOffset),0);
    rightEdge.fill('#F0F0F0');
    rightEdge.click(function() {pageRight()});

    // rimX = edges.rect(width,height);
    // rimX.fill('none').stroke('Silver');

    const chevronL = optionOffset/2 - 10;
    const chevronR = optionOffset/2 + 10;
    const chevronT = height/2 - 18;
    const chevronB = height/2 + 18;

    let leftPathString = "M "+chevronR+" "+chevronT+" ";
    leftPathString += "L "+chevronL+" "+(height/2)+" ";
    leftPathString += "L "+chevronR+" "+chevronB+" ";
    leftChevron = edges.path(leftPathString);
    let chevStroke = {
        width:4,
        color:'Gray',
        linecap:'round'
    };

    leftChevron.fill('none').stroke(chevStroke);

    let rightPathString = "M "+chevronL+" "+chevronT+" ";
    rightPathString += "L "+chevronR+" "+(height/2)+" ";
    rightPathString += "L "+chevronL+" "+chevronB+" ";
    rightChevron = edges.path(rightPathString);
    rightChevron.fill('none').stroke(chevStroke);
    rightChevron.dmove(width-(optionOffset+5),0);

    // updateChevrons();
}

function highlightOption(i) {
    console.log("C1 highlight:"+i);
    if (!frozen || state[i] > 0) {
        optionShades[i].animate(5).fill('White');
    }
}

function fadeOption(i) {
    console.log("C1 fade:"+i+" frozen:"+frozen+" state:"+state[i]+" func:"+(!frozen || state[i] > 1));
    if (!frozen || state[i] > 0) {
        console.log("C1 fading");
        optionShades[i].animate(5).fill('none');
    }
}

function pageLeft() {
    if (page > 0) {
        page--;
        buttons.animate(250).dmove(itemWidth*itemsPerPage,0);
        // updateChevrons();
    } else {
        page = pages - 1;
        buttons.dmove(-itemWidth*itemsPerPage*pages,0);
        buttons.animate(250).dmove(itemWidth*itemsPerPage,0);
    }
    console.log("C1 page:"+page+" shift:"+buttons.x());
}

function pageRight() {
    if (page < pages-1) {
        page++;
        buttons.animate(250).dmove(-itemWidth*itemsPerPage,0);
        // updateChevrons();
    } else {
        page = 0;
        buttons.dmove(itemWidth*itemsPerPage*pages,0);
        buttons.animate(250).dmove(-itemWidth*itemsPerPage,0);
    }
    console.log("C1 page:"+page+" shift:"+buttons.x());
}

// function updateChevrons() {
//     console.log("page:"+page+" pages:"+pages);
//     if (page == 0) {
//         leftChevron.stroke('none');
//     } else {
//         leftChevron.stroke('Gray');
//     }
//     if (page == pages - 1) {
//         rightChevron.stroke('none');
//     } else {
//         rightChevron.stroke('Gray');
//     }
// }

function setFrozen(value) {
    console.log("C1 setFrozen");
    frozen = value;

    for (let i = 0; i < state.length; i++) {
        if (state[i] == 0) {
            if (frozen) {
                // optionBorders[i].stroke('DimGray');
                optionRects[i].fill('DimGray');
            } else {
                // optionBorders[i].stroke('Silver');
                optionRects[i].fill('none');
            }
        }
    }
}

function selectOption(i) {

    let sendMessage = false;

    console.log("C1 selectOption:"+i);
    // if (state[i] == 0 && !frozen && selected < 5) {
    if (state[i] == 0 && !frozen) {
        optionBorders[i].stroke({color:'#52009A', width:2});
        optionRects[i].fill('#BAB6CA');
        state[i] = 1;
        sendMessage = true;
        // selected++;
        // if (selected >= 5) {
        //     setFrozen(true);
        // }

    // } else if (state[i] > 0 && selected < 5) {
    } else if (state[i] > 0) {
        optionBorders[i].stroke({color:'Silver', width:1});
        console.log("C1 Unfreezing");
        state[i] = 0;
        setFrozen(false);
        sendMessage = true;
        // selected--;
    }

    if (sendMessage) {
        var message = {
            action: "UpdateSelection",
            selection: state
        };
        window.parent.postMessage(message,"*");
    }
    // console.log("Selected:"+selected);
}

function removeIngredient(data) {
    for (let i = 0; i < data.length; i++) {
        if (data[i] == 0 && state[i] > 0) {

            optionBorders[i].stroke('none');
            console.log("C1 Unfreezing");
            state[i] = 0;
            setFrozen(false);
        }
    }
}
<|endoftext|>


<commit_before>// @flow

import React, {
  useContext,
  useEffect,
  useMemo,
  useLayoutEffect,
  useRef,
} from 'react';
import AutoSizer from 'react-virtualized-auto-sizer';
import { FixedSizeList } from 'react-window';
import { TreeContext } from './TreeContext';
import ButtonIcon from './ButtonIcon';
import Element from './Element';
import OwnersStack from './OwnersStack';
import SearchInput from './SearchInput';

import styles from './Tree.css';

type Props = {||};

export default function Tree(props: Props) {
  const {
    baseDepth,
    getElementAtIndex,
    numElements,
    ownerStack,
    selectedElementIndex,
    selectNextElementInTree,
    selectPreviousElementInTree,
  } = useContext(TreeContext);
  const listRef = useRef<FixedSizeList<any>>();

  // Make sure a newly selected element is visible in the list.
  // This is helpful for things like the owners list.
  useLayoutEffect(() => {
    if (selectedElementIndex !== null && listRef.current != null) {
      listRef.current.scrollToItem(selectedElementIndex);
    }
  }, [listRef, selectedElementIndex]);

  // Navigate the tree with up/down arrow keys.
  useEffect(() => {
    // TODO Use selectNextElement / selectPreviousElement (with dispatch)

    const handleKeyDown = event => {
      // eslint-disable-next-line default-case
      switch (event.key) {
        case 'ArrowDown':
          selectNextElementInTree();
          event.preventDefault();
          break;
        case 'ArrowUp':
          selectPreviousElementInTree();
          event.preventDefault();
          break;
      }
    };

    window.addEventListener('keydown', handleKeyDown);

    return () => {
      window.removeEventListener('keydown', handleKeyDown);
    };
  }, [
    selectedElementIndex,
    selectNextElementInTree,
    selectPreviousElementInTree,
  ]);

  // Let react-window know to re-render any time the underlying tree data changes.
  // This includes the owner context, since it controls a filtered view of the tree.
  const itemData = useMemo(
    () => ({
      baseDepth,
      numElements,
      getElementAtIndex,
    }),
    [baseDepth, numElements, getElementAtIndex]
  );

  const itemSize = parseInt(
    getComputedStyle((document.body: any)).getPropertyValue(
      '--line-height-data'
    ),
    10
  );

  return (

        {ownerStack.length > 0 ? <OwnersStack /> : <SearchInput />}
        <button
          className={styles.IconButton}
          title="Select an element in the page to inspect it"
        >
          <ButtonIcon type="search" />
        </button>

        <AutoSizer>
          {({ height, width }) => (
            <FixedSizeList
              className={styles.List}
              height={height}
              itemCount={numElements}
              itemData={itemData}
              itemSize={itemSize}
              ref={listRef}
              width={width}
            >
              {Element}
            </FixedSizeList>
          )}
        </AutoSizer>

  );
}
<commit_msg>Fixed NaN warning for pre-mount CSS prop read<commit_after>// @flow

import React, {
  useContext,
  useEffect,
  useMemo,
  useLayoutEffect,
  useRef,
} from 'react';
import AutoSizer from 'react-virtualized-auto-sizer';
import { FixedSizeList } from 'react-window';
import { TreeContext } from './TreeContext';
import ButtonIcon from './ButtonIcon';
import Element from './Element';
import OwnersStack from './OwnersStack';
import SearchInput from './SearchInput';

import styles from './Tree.css';

type Props = {||};

export default function Tree(props: Props) {
  const {
    baseDepth,
    getElementAtIndex,
    numElements,
    ownerStack,
    selectedElementIndex,
    selectNextElementInTree,
    selectPreviousElementInTree,
  } = useContext(TreeContext);
  const listRef = useRef<FixedSizeList<any>>();

  // Make sure a newly selected element is visible in the list.
  // This is helpful for things like the owners list.
  useLayoutEffect(() => {
    if (selectedElementIndex !== null && listRef.current != null) {
      listRef.current.scrollToItem(selectedElementIndex);
    }
  }, [listRef, selectedElementIndex]);

  // Navigate the tree with up/down arrow keys.
  useEffect(() => {
    // TODO Use selectNextElement / selectPreviousElement (with dispatch)

    const handleKeyDown = event => {
      // eslint-disable-next-line default-case
      switch (event.key) {
        case 'ArrowDown':
          selectNextElementInTree();
          event.preventDefault();
          break;
        case 'ArrowUp':
          selectPreviousElementInTree();
          event.preventDefault();
          break;
      }
    };

    window.addEventListener('keydown', handleKeyDown);

    return () => {
      window.removeEventListener('keydown', handleKeyDown);
    };
  }, [
    selectedElementIndex,
    selectNextElementInTree,
    selectPreviousElementInTree,
  ]);

  // Let react-window know to re-render any time the underlying tree data changes.
  // This includes the owner context, since it controls a filtered view of the tree.
  const itemData = useMemo(
    () => ({
      baseDepth,
      numElements,
      getElementAtIndex,
    }),
    [baseDepth, numElements, getElementAtIndex]
  );

  const itemSize =
    parseInt(
      getComputedStyle((document.body: any)).getPropertyValue(
        '--line-height-data'
      ),
      10
    ) || 18;

  return (

        {ownerStack.length > 0 ? <OwnersStack /> : <SearchInput />}
        <button
          className={styles.IconButton}
          title="Select an element in the page to inspect it"
        >
          <ButtonIcon type="search" />
        </button>

        <AutoSizer>
          {({ height, width }) => (
            <FixedSizeList
              className={styles.List}
              height={height}
              itemCount={numElements}
              itemData={itemData}
              itemSize={itemSize}
              ref={listRef}
              width={width}
            >
              {Element}
            </FixedSizeList>
          )}
        </AutoSizer>

  );
}
<|endoftext|>


<commit_before>'use strict';

angular.module('mpokDoroTimerApp')
  .controller('MainCtrl', ['$scope', '$interval', '$window',
    'localStorageService',
    function($scope, $interval, $window, localStorageService) {

      // 25 minutes is equal to 1500 seconds
      // 25 minutes is equal to 1500 * 1000 milliseconds
      // var timebox = 1500 * 1000,
      var timebox = 1 * 1000,
        timer = {};

      // initialization

      (function(scope) {
        var pomodoro = parseInt(localStorageService.get('pomodoro'), 10);

        if (isNaN(pomodoro)) {
          scope.pomodoro = 0;
          // localStorageService.set('pomodoro', $scope.pomodoro.toString());
        } else if (pomodoro > 0) {
          scope.pomodoro = pomodoro;
        }
      })($scope);

      $scope.workInProgress = false;

      /**
       * Start pomodoro. When we hit the start button, it will hide the start
       * button and show the stop button.
       * Once the pomodoro started we track the timebox and will notify the user
       * when we hit 25 minutes.
       */
      $scope.start = function() {
        $scope.workInProgress = true;

        timer = $interval(function() {
          // record the pomodoro
          $scope.pomodoro += 1;

          localStorageService.set('pomodoro', $scope.pomodoro.toString());

          var START = $scope.pomodoro !== 0;
          // Every four pomodoro take a longer break
          var FOURTH_POMODORO = $scope.pomodoro % 4 === 0;

          if (START && FOURTH_POMODORO) {
            $window.alert('Come on take a long break for 20 minutes!');
          } else {
            $window.alert('Come on take a short break for 5 minutes!');
          }

          // Cancels a task associated with the `timer`
          $interval.cancel(timer);

          $scope.workInProgress = false;
        }, timebox);
      };

      /**
       * Stop pomodoro. When we hit the stop button, it will hide the stop
       * button and show the start button.
       */
      $scope.stop = function() {
        $interval.cancel(timer);
        $scope.workInProgress = false;
      };
    }
  ]);<commit_msg>fix(main): forgot to uncomment the default timebox<commit_after>'use strict';

angular.module('mpokDoroTimerApp')
  .controller('MainCtrl', ['$scope', '$interval', '$window',
    'localStorageService',
    function($scope, $interval, $window, localStorageService) {

      // 25 minutes is equal to 1500 seconds
      // 25 minutes is equal to 1500 * 1000 milliseconds
      var timebox = 1500 * 1000,
        timer = {};

      // initialization
      (function(scope) {
        var pomodoro = parseInt(localStorageService.get('pomodoro'), 10);

        if (isNaN(pomodoro)) {
          scope.pomodoro = 0;
          // localStorageService.set('pomodoro', $scope.pomodoro.toString());
        } else if (pomodoro > 0) {
          scope.pomodoro = pomodoro;
        }
      })($scope);

      $scope.workInProgress = false;

      /**
       * Start pomodoro. When we hit the start button, it will hide the start
       * button and show the stop button.
       * Once the pomodoro started we track the timebox and will notify the user
       * when we hit 25 minutes.
       */
      $scope.start = function() {
        $scope.workInProgress = true;

        timer = $interval(function() {
          // record the pomodoro
          $scope.pomodoro += 1;

          localStorageService.set('pomodoro', $scope.pomodoro.toString());

          var START = $scope.pomodoro !== 0;
          // Every four pomodoro take a longer break
          var FOURTH_POMODORO = $scope.pomodoro % 4 === 0;

          if (START && FOURTH_POMODORO) {
            $window.alert('Come on take a long break for 20 minutes!');
          } else {
            $window.alert('Come on take a short break for 5 minutes!');
          }

          // Cancels a task associated with the `timer`
          $interval.cancel(timer);

          $scope.workInProgress = false;
        }, timebox);
      };

      /**
       * Stop pomodoro. When we hit the stop button, it will hide the stop
       * button and show the start button.
       */
      $scope.stop = function() {
        $interval.cancel(timer);
        $scope.workInProgress = false;
      };
    }
  ]);<|endoftext|>


<commit_before>/*
 * jNotify.js
 * Written by Jeffrey Muller
 * jHeberg.net - 2013
 */

(function($) {

    var o = {}; // Options object

    ////////////////////////
    // Ui
    ////////////////////////

    create = function() {
        if ($('body div.jNotify').length === 0) {
            var container = $('<div>').addClass(o.position + ' jNotify');

            $('body').append(container);
        }
    }

    render = function() {
        var notification = $('<div>').addClass('jNotify-notification');

        if (o.isClosable === true) {
            notification.append($('<button>').addClass('close').html('×'));
        }

        notification.append($('<div>').addClass('content').html(o.content));

        return notification;
    }

    remove = function(notification) {
        var content = $(notification).find('div.content').html();

        $(notification).fadeOut(function() {
            $(notification).remove();

            if ($('div.jNotify div.jNotify-notification').length > 0 && o.pool > 0) {
                display();
            }
        });
    }

    display = function() {
        var displayed = 0;
        $('div.jNotify div.jNotify-notification').each(function(idx, e) {
            if ($(e).is(':hidden')) {
                $(e).fadeIn();

                var t = setTimeout(function() {
                    remove(e);
                    clearInterval(t);
                }, o.timeout);
            }

            displayed++;
            if (o.pool > 0 && displayed >= o.pool) {
                return false;
            }
        });
    }

    ///////////////////////
    // Callbacks
    ///////////////////////

    onClickClose = function() {
        var notification = $(this).parent();

        remove(notification);
    }

    ///////////////////////
    // Constructor
    ///////////////////////

    $.jNotify = function(options) {
        var defaults = {
            // Layout to use (must be "top left", "top right", "bottom left", "bottom right")
            position: 'top right',

            // Define if the notification is closable
            isClosable: true,

            // Content of the notification
            content: '',

            // Callback to call when user click on "close" button
            onClickClose: onClickClose,

            // Time in milliseconds while bubble is displayed
            timeout: 5000,

            // Limit the number of notification displayed (0 to disable)
            pool: 0
        };

        o = $.extend(defaults, options);

        create();
        var notification = render();

        $('div.jNotify').append(notification);

        display();
    }

})(jQuery);<commit_msg>Add missing callback for click on close button<commit_after>/*
 * jNotify.js
 * Written by Jeffrey Muller
 * jHeberg.net - 2013
 */

(function($) {

    var o = {}; // Options object

    ////////////////////////
    // Ui
    ////////////////////////

    create = function() {
        if ($('body div.jNotify').length === 0) {
            var container = $('<div>').addClass(o.position + ' jNotify');

            $('body').append(container);
        }
    }

    render = function() {
        var notification = $('<div>').addClass('jNotify-notification');

        if (o.isClosable === true) {
            notification.append($('<button>').addClass('close').html('×'));
        }

        notification.append($('<div>').addClass('content').html(o.content));

        return notification;
    }

    remove = function(notification) {
        var content = $(notification).find('div.content').html();

        $(notification).fadeOut(function() {
            $(notification).remove();

            if ($('div.jNotify div.jNotify-notification').length > 0 && o.pool > 0) {
                display();
            }
        });
    }

    display = function() {
        var displayed = 0;
        $('div.jNotify div.jNotify-notification').each(function(idx, e) {
            if ($(e).is(':hidden')) {
                $(e).fadeIn();

                var t = setTimeout(function() {
                    remove(e);
                    clearInterval(t);
                }, o.timeout);
                $(e).find('button.close').click(o.onClickClose);
            }

            displayed++;
            if (o.pool > 0 && displayed >= o.pool) {
                return false;
            }
        });
    }

    ///////////////////////
    // Callbacks
    ///////////////////////

    onClickClose = function() {
        var notification = $(this).parent();

        remove(notification);
    }

    ///////////////////////
    // Constructor
    ///////////////////////

    $.jNotify = function(options) {
        var defaults = {
            // Layout to use (must be "top left", "top right", "bottom left", "bottom right")
            position: 'top right',

            // Define if the notification is closable
            isClosable: true,

            // Content of the notification
            content: '',

            // Callback to call when user click on "close" button
            onClickClose: onClickClose,

            // Time in milliseconds while bubble is displayed
            timeout: 5000,

            // Limit the number of notification displayed (0 to disable)
            pool: 0
        };

        o = $.extend(defaults, options);

        create();
        var notification = render();

        $('div.jNotify').append(notification);

        display();
    }

})(jQuery);<|endoftext|>


<commit_before>/*/////////////////////////////////////////////////////////////////////////////////

 MO5.js - JavaScript Library For Building Modern DOM And Canvas Applications

 Copyright (c) 2013 Jonathan Steinbeck
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the distribution.

 * Neither the name MO5.js nor the names of its contributors
   may be used to endorse or promote products derived from this software
   without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

/////////////////////////////////////////////////////////////////////////////////*/

/* global MO5, document, console */

MO5("MO5.CoreObject", "MO5.transform", "MO5.TimerWatcher", "MO5.dom.effects.typewriter",
        "MO5.types", "MO5.Point", "MO5.Size").
define("MO5.dom.Element", function (CoreObject, transform, TimerWatcher,
        typewriter, types, Point, Size) {

    function Element (args) {

        var self = this;

        args = args || {};

        CoreObject.call(this);

        this.parent = args.parent || document.body;
        this.nodeType = args.nodeType || "div";
        this.element = args.element || document.createElement(this.nodeType);

        wrapElement(this, this.element);

        Element.propertiesToExclude.forEach(function (property) {
            delete self[property];
        });
    }

    // Properties that should not shadow the DOM element's properties.
    // If you want to add a method with the same name as a DOM element's
    // property to the prototype, you need to add the method's name to this array.
    Element.propertiesToExclude = [
        "appendChild"
    ];

    /**
     * Creates an Element instance for a DOMElement.
     */
    Element.fromDomElement = function (domElement) {
        return new Element({element: domElement, nodeType: domElement.nodeName});
    };

    Element.prototype = new CoreObject();
    Element.prototype.constructor = Element;

    Element.prototype.appendTo = function (element) {
        return element.appendChild(this.element);
    };

    Element.prototype.remove = function () {
        return this.element.parentNode.removeChild(this.element);
    };

    Element.prototype.appendChild = function (child) {
        var node = child instanceof Element ? child.element : child;
        return this.element.appendChild(node);
    };

    Element.prototype.fadeIn = function (args) {

        args = args || {};

        var element = this.element;

        if (this._lastFadeTimer && this._lastFadeTimer.isRunning()) {
            this._lastFadeTimer.cancel();
        }

        this.show();

        this._lastFadeTimer = transform(
            function (v) {
                element.style.opacity = v;
            },
            parseInt(element.style.opacity, 10) || 0,
            1,
            args
        );

        return this._lastFadeTimer;
    };

    Element.prototype.fadeOut = function (args) {

        args = args || {};

        var element = this.element;

        if (this._lastFadeTimer && this._lastFadeTimer.isRunning()) {
            this._lastFadeTimer.cancel();
        }

        this._lastFadeTimer = transform(
            function (v) {
                element.style.opacity = v;
            },
            parseInt(element.style.opacity, 10) || 1,
            0,
            args
        );

        this._lastFadeTimer.once("stopped", this.hide.bind(this));

        return this._lastFadeTimer;
    };

    Element.prototype.opacity = function (value) {

        if (typeof value === "number") {
            this.element.style.opacity = value;
        }

        return this.element.style.opacity;
    };

    Element.prototype.position = function (point) {

        if (types.isObject(point)) {
            this.element.style.left = "" + (+point.x) + "px";
            this.element.style.top = "" + (+point.y) + "px";
        }

        return new Point(this.element.offsetLeft, this.element.offsetTop);

    };

    Element.prototype.size = function (size) {

        if (types.isObject(size)) {
            this.element.style.width = "" + size.width + "px";
            this.element.style.height = "" + size.height + "px";
        }

        return new Size(this.element.offsetWidth, this.element.offsetHeight);
    };

    Element.prototype.width = function (width) {

        if (types.isNumber(width)) {
            this.element.style.width = "" + width + "px";
        }

        return this.element.offsetWidth;
    };

    Element.prototype.height = function (height) {

        if (types.isNumber(height)) {
            this.element.style.height = "" + height + "px";
        }

        return this.element.offsetHeight;
    };

    Element.prototype.moveTo = function (x, y, args) {

        args = args || {};

        var element = this.element,
            ox = element.offsetLeft,
            oy = element.offsetTop,
            t0, t1;

        t0 = transform(
            function (v) {
                element.style.left = v + "px";
            },
            ox,
            x,
            args
        );

        t1 = transform(
            function (v) {
                element.style.top = v + "px";
            },
            oy,
            y,
            args
        );

        return new TimerWatcher().addTimer(t0).addTimer(t1);
    };

    Element.prototype.move = function (x, y, args) {

        args = args || {};

        var element = this.element,
            dx = element.offsetLeft + x,
            dy = element.offsetTop + y;

        return this.moveTo(dx, dy, args);
    };

    Element.prototype.display = function () {
        this.element.style.visibility = "";
    };

    Element.prototype.show = Element.prototype.display;

    Element.prototype.hide = function () {
        this.element.style.visibility = "hidden";
    };

    Element.prototype.typewriter = function (args) {
        args = args || {};
        typewriter(this.element, args);
    };

    Element.prototype.addCssClass = function (classToAdd) {

        var classes;

        if (this.element.classList) {
            this.element.classList.add(classToAdd);
            return this;
        }

        classes = this.getCssClasses();

        if (!contains(classes, classToAdd)) {
            classes.push(classToAdd);
            this.element.setAttribute("class", classes.join(" "));
        }

        return this;
    };

    Element.prototype.removeCssClass = function (classToRemove) {

        var classes;

        if (this.element.classList) {
            this.element.classList.remove(classToRemove);
        }

        classes = this.getCssClasses();

        if (contains(classes, classToRemove)) {
            this.element.setAttribute("class", classes.filter(function (item) {
                return item !== classToRemove;
            }).join(" "));
        }

        return this;
    };

    Element.prototype.getCssClasses = function () {
        return (this.element.getAttribute("class") || "").split(" ");
    };

    Element.prototype.hasCssClass = function (classToCheckFor) {
        return this.element.classList ?
            this.element.classList.contains(classToCheckFor) :
            contains(this.getCssClasses(), classToCheckFor);
    };

    Element.prototype.clearCssClasses = function () {
        this.element.setAttribute("class", "");
        return this;
    };

    Element.prototype.setCssId = function (cssId) {
        this.element.setAttribute("id", cssId);
        return this;
    };

    Element.prototype.destroy = function () {

        try {
            this.element.parentNode.removeChild(this.element);
        }
        catch (e) {
            console.log(e);
        }

        this.element = null;

        this.destroyed = true;
        this.trigger("destroyed", null, false);

        for (var key in this) {
            if (this.hasOwnProperty(key)) {
                delete this[key];
            }
        }

        this.destroyed = true;
    };

    ////////////////////////////////////////
    // dom.Element helper functions
    ////////////////////////////////////////

    function wrapElement (element, domElement) {
        for (var key in domElement) {
            (function (currentProperty, key) {

                if (key === "id") {
                    return;
                }

                if (typeof currentProperty === "function") {
                    element[key] = function () {
                        return domElement[key].apply(domElement, arguments);
                    };
                }
                else {
                    element[key] = function (content) {

                        if (arguments.length) {
                            domElement[key] = content;
                            return element;
                        }

                        return domElement[key];
                    };
                }
            }(domElement[key], key));
        }
    }

    function contains (array, item) {
        return array.indexOf(item) !== -1;
    }

    return Element;

});<commit_msg>Changed dom.Element.position() to work inside tables and nested absolutely positioned parents.<commit_after>/*/////////////////////////////////////////////////////////////////////////////////

 MO5.js - JavaScript Library For Building Modern DOM And Canvas Applications

 Copyright (c) 2013 Jonathan Steinbeck
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the distribution.

 * Neither the name MO5.js nor the names of its contributors
   may be used to endorse or promote products derived from this software
   without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

/////////////////////////////////////////////////////////////////////////////////*/

/* global MO5, document, console */

MO5("MO5.CoreObject", "MO5.transform", "MO5.TimerWatcher", "MO5.dom.effects.typewriter",
        "MO5.types", "MO5.Point", "MO5.Size").
define("MO5.dom.Element", function (CoreObject, transform, TimerWatcher,
        typewriter, types, Point, Size) {

    function Element (args) {

        var self = this;

        args = args || {};

        CoreObject.call(this);

        this.parent = args.parent || document.body;
        this.nodeType = args.nodeType || "div";
        this.element = args.element || document.createElement(this.nodeType);

        wrapElement(this, this.element);

        Element.propertiesToExclude.forEach(function (property) {
            delete self[property];
        });
    }

    // Properties that should not shadow the DOM element's properties.
    // If you want to add a method with the same name as a DOM element's
    // property to the prototype, you need to add the method's name to this array.
    Element.propertiesToExclude = [
        "appendChild"
    ];

    /**
     * Creates an Element instance for a DOMElement.
     */
    Element.fromDomElement = function (domElement) {
        return new Element({element: domElement, nodeType: domElement.nodeName});
    };

    Element.prototype = new CoreObject();
    Element.prototype.constructor = Element;

    Element.prototype.appendTo = function (element) {
        return element.appendChild(this.element);
    };

    Element.prototype.remove = function () {
        return this.element.parentNode.removeChild(this.element);
    };

    Element.prototype.appendChild = function (child) {
        var node = child instanceof Element ? child.element : child;
        return this.element.appendChild(node);
    };

    Element.prototype.fadeIn = function (args) {

        args = args || {};

        var element = this.element;

        if (this._lastFadeTimer && this._lastFadeTimer.isRunning()) {
            this._lastFadeTimer.cancel();
        }

        this.show();

        this._lastFadeTimer = transform(
            function (v) {
                element.style.opacity = v;
            },
            parseInt(element.style.opacity, 10) || 0,
            1,
            args
        );

        return this._lastFadeTimer;
    };

    Element.prototype.fadeOut = function (args) {

        args = args || {};

        var element = this.element;

        if (this._lastFadeTimer && this._lastFadeTimer.isRunning()) {
            this._lastFadeTimer.cancel();
        }

        this._lastFadeTimer = transform(
            function (v) {
                element.style.opacity = v;
            },
            parseInt(element.style.opacity, 10) || 1,
            0,
            args
        );

        this._lastFadeTimer.once("stopped", this.hide.bind(this));

        return this._lastFadeTimer;
    };

    Element.prototype.opacity = function (value) {

        if (typeof value === "number") {
            this.element.style.opacity = value;
        }

        return this.element.style.opacity;
    };

    Element.prototype.position = function (point) {

        var element = this.element, rect = {};

        if (types.isObject(point)) {
            element.style.left = "" + (+point.x) + "px";
            element.style.top = "" + (+point.y) + "px";
        }

        rect.left = element.offsetLeft;
        rect.top = element.offsetTop;

        if (element.getBoundingClientRect) {
            rect = element.getBoundingClientRect();
        }

        return new Point(rect.left, rect.top);

    };

    Element.prototype.size = function (size) {

        if (types.isObject(size)) {
            this.element.style.width = "" + size.width + "px";
            this.element.style.height = "" + size.height + "px";
        }

        return new Size(this.element.offsetWidth, this.element.offsetHeight);
    };

    Element.prototype.width = function (width) {

        if (types.isNumber(width)) {
            this.element.style.width = "" + width + "px";
        }

        return this.element.offsetWidth;
    };

    Element.prototype.height = function (height) {

        if (types.isNumber(height)) {
            this.element.style.height = "" + height + "px";
        }

        return this.element.offsetHeight;
    };

    Element.prototype.moveTo = function (x, y, args) {

        args = args || {};

        var element = this.element,
            ox = element.offsetLeft,
            oy = element.offsetTop,
            t0, t1;

        t0 = transform(
            function (v) {
                element.style.left = v + "px";
            },
            ox,
            x,
            args
        );

        t1 = transform(
            function (v) {
                element.style.top = v + "px";
            },
            oy,
            y,
            args
        );

        return new TimerWatcher().addTimer(t0).addTimer(t1);
    };

    Element.prototype.move = function (x, y, args) {

        args = args || {};

        var element = this.element,
            dx = element.offsetLeft + x,
            dy = element.offsetTop + y;

        return this.moveTo(dx, dy, args);
    };

    Element.prototype.display = function () {
        this.element.style.visibility = "";
    };

    Element.prototype.show = Element.prototype.display;

    Element.prototype.hide = function () {
        this.element.style.visibility = "hidden";
    };

    Element.prototype.typewriter = function (args) {
        args = args || {};
        typewriter(this.element, args);
    };

    Element.prototype.addCssClass = function (classToAdd) {

        var classes;

        if (this.element.classList) {
            this.element.classList.add(classToAdd);
            return this;
        }

        classes = this.getCssClasses();

        if (!contains(classes, classToAdd)) {
            classes.push(classToAdd);
            this.element.setAttribute("class", classes.join(" "));
        }

        return this;
    };

    Element.prototype.removeCssClass = function (classToRemove) {

        var classes;

        if (this.element.classList) {
            this.element.classList.remove(classToRemove);
        }

        classes = this.getCssClasses();

        if (contains(classes, classToRemove)) {
            this.element.setAttribute("class", classes.filter(function (item) {
                return item !== classToRemove;
            }).join(" "));
        }

        return this;
    };

    Element.prototype.getCssClasses = function () {
        return (this.element.getAttribute("class") || "").split(" ");
    };

    Element.prototype.hasCssClass = function (classToCheckFor) {
        return this.element.classList ?
            this.element.classList.contains(classToCheckFor) :
            contains(this.getCssClasses(), classToCheckFor);
    };

    Element.prototype.clearCssClasses = function () {
        this.element.setAttribute("class", "");
        return this;
    };

    Element.prototype.setCssId = function (cssId) {
        this.element.setAttribute("id", cssId);
        return this;
    };

    Element.prototype.destroy = function () {

        try {
            this.element.parentNode.removeChild(this.element);
        }
        catch (e) {
            console.log(e);
        }

        this.element = null;

        this.destroyed = true;
        this.trigger("destroyed", null, false);

        for (var key in this) {
            if (this.hasOwnProperty(key)) {
                delete this[key];
            }
        }

        this.destroyed = true;
    };

    ////////////////////////////////////////
    // dom.Element helper functions
    ////////////////////////////////////////

    function wrapElement (element, domElement) {
        for (var key in domElement) {
            (function (currentProperty, key) {

                if (key === "id") {
                    return;
                }

                if (typeof currentProperty === "function") {
                    element[key] = function () {
                        return domElement[key].apply(domElement, arguments);
                    };
                }
                else {
                    element[key] = function (content) {

                        if (arguments.length) {
                            domElement[key] = content;
                            return element;
                        }

                        return domElement[key];
                    };
                }
            }(domElement[key], key));
        }
    }

    function contains (array, item) {
        return array.indexOf(item) !== -1;
    }

    return Element;

});<|endoftext|>


<commit_before>(function() {
  var mainSpan, shiftSpan, ctrlSpan, altSpan; //, metaSpan

  function startup() {
    mainSpan = document.getElementById("keydisplay");
    shiftSpan = document.getElementById("shiftkey");
    ctrlSpan = document.getElementById("ctrlkey");
    altSpan = document.getElementById("altkey");
    //metaSpan = document.getElementById("metakey");
    document.addEventListener("keydown", keyCheck);
    document.addEventListener("keyup", keyUpCheck);
  }

  function keyCheck(e) {
    if (e.keyCode != 16 && e.keyCode != 17 && e.keyCode != 18) {
      displayKey(e.keyCode);
    }
    modifier(shiftSpan, e.shiftKey);
    modifier(ctrlSpan, e.ctrlKey);
    modifier(altSpan, e.altKey);
    //modifier(metaSpan, e.metaKey);
    e.preventDefault();
  }

  function keyUpCheck(e) {
    modifier(shiftSpan, e.shiftKey);
    modifier(ctrlSpan, e.ctrlKey);
    modifier(altSpan, e.altKey);
    //modifier(metaSpan, e.metaKey);
    e.preventDefault();
  }

  function displayKey(code) {
    mainSpan.innerHTML = code;
  }

  function modifier(elem, on) {
    if (on) {
      elem.className = "";
    }
    else {
      elem.className = "off";
    }
  }

  document.addEventListener("DOMContentLoaded", startup);
}).call();
<commit_msg>Update keycode.js<commit_after>(function() {
  var mainSpan, shiftSpan, ctrlSpan, altSpan; //, metaSpan

  function startup() {
    mainSpan = document.getElementById("keydisplay");
    shiftSpan = document.getElementById("shiftkey");
    ctrlSpan = document.getElementById("ctrlkey");
    altSpan = document.getElementById("altkey");
    //metaSpan = document.getElementById("metakey");
    document.addEventListener("keydown", keyCheck);
    document.addEventListener("keyup", keyUpCheck);
  }

  function keyCheck(e) {
    if (e.keyCode != 16 && e.keyCode != 17 && e.keyCode != 18) {
      displayKey(e.keyCode);
    }
    modifier(shiftSpan, e.shiftKey);
    modifier(ctrlSpan, e.ctrlKey);
    modifier(altSpan, e.altKey);
    //modifier(metaSpan, e.metaKey);
    if (checkboxIsChecked()) {
      e.preventDefault();
    }
  }

  function keyUpCheck(e) {
    modifier(shiftSpan, e.shiftKey);
    modifier(ctrlSpan, e.ctrlKey);
    modifier(altSpan, e.altKey);
    //modifier(metaSpan, e.metaKey);
    if (checkboxIsChecked()) {
      e.preventDefault();
    }
  }

  function displayKey(code) {
    mainSpan.innerHTML = code;
  }

  function modifier(elem, on) {
    if (on) {
      elem.className = "";
    }
    else {
      elem.className = "off";
    }
  }

  function checkboxIsChecked() {
    return document.getElementById("blockCheckbox").checked;
  }

  document.addEventListener("DOMContentLoaded", startup);
}).call();
<|endoftext|>