<commit_before>(function() {
  'use strict';
  angular.module('ngMask')
    .directive('mask', ['$log', '$timeout', 'MaskService', function($log, $timeout, MaskService) {
      return {
        restrict: 'A',
        require: 'ngModel',
        compile: function($element, $attrs) {
         if (!$attrs.mask || !$attrs.ngModel) {
            $log.info('Mask and ng-model attributes are required!');
            return;
          }

          var maskService = MaskService.create();
          var timeout;
          var promise;

          function setSelectionRange(selectionStart){
            if (typeof selectionStart !== 'number') {
              return;
            }

            // using $timeout:
            // it should run after the DOM has been manipulated by Angular
            // and after the browser renders (which may cause flicker in some cases)
            $timeout.cancel(timeout);
            timeout = $timeout(function(){
              var selectionEnd = selectionStart + 1;
              var input = $element[0];

              if (input.setSelectionRange) {
                input.focus();
                input.setSelectionRange(selectionStart, selectionEnd);
              } else if (input.createTextRange) {
                var range = input.createTextRange();

                range.collapse(true);
                range.moveEnd('character', selectionEnd);
                range.moveStart('character', selectionStart);
                range.select();
              }
            });
          }

          return {
            pre: function($scope, $element, $attrs, controller) {
              promise = maskService.generateRegex({
                mask: $attrs.mask,
                // repeat mask expression n times
                repeat: ($attrs.repeat || $attrs.maskRepeat),
                // clean model value - without divisors
                clean: (($attrs.clean || $attrs.maskClean) === 'true'),
                // limit length based on mask length
                limit: (($attrs.limit || $attrs.maskLimit || 'true') === 'true'),
                // how to act with a wrong value
                restrict: ($attrs.restrict || $attrs.maskRestrict || 'select'), //select, reject, accept
                // set validity mask
                validate: (($attrs.validate || $attrs.maskValidate || 'true') === 'true'),
                // default model value
                model: $attrs.ngModel,
                // default input value
                value: $attrs.ngValue
              });
            },
            post: function($scope, $element, $attrs, controller) {
              promise.then(function() {
                // get initial options
                var timeout;
                var options = maskService.getOptions();

                function parseViewValue(value) {
                  // set default value equal 0
                  value = value || '';

                  // get view value object
                  var viewValue = maskService.getViewValue(value);

                  // get mask without question marks
                  var maskWithoutOptionals = options['maskWithoutOptionals'] || '';

                  // get view values capped
                  // used on view
                  var viewValueWithDivisors = viewValue.withDivisors(true);
                  // used on model
                  var viewValueWithoutDivisors = viewValue.withoutDivisors(true);

                  try {
                    // get current regex
                    var regex = maskService.getRegex(viewValueWithDivisors.length - 1);
                    var fullRegex = maskService.getRegex(maskWithoutOptionals.length - 1);

                    // current position is valid
                    var validCurrentPosition = regex.test(viewValueWithDivisors) || fullRegex.test(viewValueWithDivisors);

                    // difference means for select option
                    var diffValueAndViewValueLengthIsOne = (value.length - viewValueWithDivisors.length) === 1;
                    var diffMaskAndViewValueIsGreaterThanZero = (maskWithoutOptionals.length - viewValueWithDivisors.length) > 0;

                    if (options.restrict !== 'accept') {
                      if (options.restrict === 'select' && (!validCurrentPosition || diffValueAndViewValueLengthIsOne)) {
                        var lastCharInputed = value[(value.length-1)];
                        var lastCharGenerated = viewValueWithDivisors[(viewValueWithDivisors.length-1)];

                        if ((lastCharInputed !== lastCharGenerated) && diffMaskAndViewValueIsGreaterThanZero) {
                          viewValueWithDivisors = viewValueWithDivisors + lastCharInputed;
                        }

                        var wrongPosition = maskService.getFirstWrongPosition(viewValueWithDivisors);
                        if (angular.isDefined(wrongPosition)) {
                          setSelectionRange(wrongPosition);
                        }
                      } else if (options.restrict === 'reject' && !validCurrentPosition) {
                        viewValue = maskService.removeWrongPositions(viewValueWithDivisors);
                        viewValueWithDivisors = viewValue.withDivisors(true);
                        viewValueWithoutDivisors = viewValue.withoutDivisors(true);

                        // setSelectionRange(viewValueWithDivisors.length);
                      }
                    }

                    if (!options.limit) {
                      viewValueWithDivisors = viewValue.withDivisors(false);
                      viewValueWithoutDivisors = viewValue.withoutDivisors(false);
                    }

                    // Set validity
                    if (options.validate && controller.$dirty) {
                      if (fullRegex.test(viewValueWithDivisors) || controller.$isEmpty(controller.$modelValue)) {
                        controller.$setValidity('mask', true);
                      } else {
                        controller.$setValidity('mask', false);
                      }
                    }

                    // Update view and model values
                    if(value !== viewValueWithDivisors){
                      controller.$setViewValue(angular.copy(viewValueWithDivisors), 'input');
                      controller.$render();
                    }
                  } catch (e) {
                    $log.error('[mask - parseViewValue]');
                    throw e;
                  }

                  // Update model, can be different of view value
                  if (options.clean) {
                    return viewValueWithoutDivisors;
                  } else {
                    return viewValueWithDivisors;
                  }
                }

                controller.$parsers.push(parseViewValue);

                $element.on('click input paste keyup', function() {
                  timeout = $timeout(function() {
                    // Manual debounce to prevent multiple execution
                    $timeout.cancel(timeout);

                    parseViewValue($element.val());
                    $scope.$apply();
                  }, 100);
                });

                // Register the watch to observe remote loading or promised data
                // Deregister calling returned function
                var watcher = $scope.$watch($attrs.ngModel, function (newValue, oldValue) {
                  if (angular.isDefined(newValue)) {
                    parseViewValue(newValue);
                    watcher();
                  }
                });

                // $evalAsync from a directive
                // it should run after the DOM has been manipulated by Angular
                // but before the browser renders
                if(options.value) {
                  $scope.$evalAsync(function($scope) {
                    controller.$setViewValue(angular.copy(options.value), 'input');
                    controller.$render();
                  });
                }
              });
            }
          }
        }
      }
    }]);
})();<commit_msg>Update mask.js<commit_after>(function() {
  'use strict';
  angular.module('ngMask')
    .directive('mask', ['$log', '$timeout', 'MaskService', function($log, $timeout, MaskService) {
      return {
        restrict: 'A',
        require: 'ngModel',
        compile: function($element, $attrs) {
         if (!$attrs.mask || !$attrs.ngModel) {
            $log.info('Mask and ng-model attributes are required!');
            return;
          }

          var maskService = MaskService.create();
          var timeout;
          var promise;

          function setSelectionRange(selectionStart){
            if (typeof selectionStart !== 'number') {
              return;
            }

            // using $timeout:
            // it should run after the DOM has been manipulated by Angular
            // and after the browser renders (which may cause flicker in some cases)
            $timeout.cancel(timeout);
            timeout = $timeout(function(){
              var selectionEnd = selectionStart + 1;
              var input = $element[0];

              if (input.setSelectionRange) {
                input.focus();
                input.setSelectionRange(selectionStart, selectionEnd);
              } else if (input.createTextRange) {
                var range = input.createTextRange();

                range.collapse(true);
                range.moveEnd('character', selectionEnd);
                range.moveStart('character', selectionStart);
                range.select();
              }
            });
          }

          return {
            pre: function($scope, $element, $attrs, controller) {
              promise = maskService.generateRegex({
                mask: $attrs.mask,
                // repeat mask expression n times
                repeat: ($attrs.repeat || $attrs.maskRepeat),
                // clean model value - without divisors
                clean: (($attrs.clean || $attrs.maskClean) === 'true'),
                // limit length based on mask length
                limit: (($attrs.limit || $attrs.maskLimit || 'true') === 'true'),
                // how to act with a wrong value
                restrict: ($attrs.restrict || $attrs.maskRestrict || 'select'), //select, reject, accept
                // set validity mask
                validate: (($attrs.validate || $attrs.maskValidate || 'true') === 'true'),
                // default model value
                model: $attrs.ngModel,
                // default input value
                value: $attrs.ngValue
              });
            },
            post: function($scope, $element, $attrs, controller) {
              promise.then(function() {
                // get initial options
                var timeout;
                var options = maskService.getOptions();

                function parseViewValue(value) {
                  // set default value equal 0
                  value = value || '';

                  // get view value object
                  var viewValue = maskService.getViewValue(value);

                  // get mask without question marks
                  var maskWithoutOptionals = options['maskWithoutOptionals'] || '';

                  // get view values capped
                  // used on view
                  var viewValueWithDivisors = viewValue.withDivisors(true);
                  // used on model
                  var viewValueWithoutDivisors = viewValue.withoutDivisors(true);

                  try {
                    // get current regex
                    var regex = maskService.getRegex(viewValueWithDivisors.length - 1);
                    var fullRegex = maskService.getRegex(maskWithoutOptionals.length - 1);

                    // current position is valid
                    var validCurrentPosition = regex.test(viewValueWithDivisors) || fullRegex.test(viewValueWithDivisors);

                    // difference means for select option
                    var diffValueAndViewValueLengthIsOne = (value.length - viewValueWithDivisors.length) === 1;
                    var diffMaskAndViewValueIsGreaterThanZero = (maskWithoutOptionals.length - viewValueWithDivisors.length) > 0;

                    if (options.restrict !== 'accept') {
                      if (options.restrict === 'select' && (!validCurrentPosition || diffValueAndViewValueLengthIsOne)) {
                        var lastCharInputed = value[(value.length-1)];
                        var lastCharGenerated = viewValueWithDivisors[(viewValueWithDivisors.length-1)];

                        if ((lastCharInputed !== lastCharGenerated) && diffMaskAndViewValueIsGreaterThanZero) {
                          viewValueWithDivisors = viewValueWithDivisors + lastCharInputed;
                        }

                        var wrongPosition = maskService.getFirstWrongPosition(viewValueWithDivisors);
                        if (angular.isDefined(wrongPosition)) {
                          setSelectionRange(wrongPosition);
                        }
                      } else if (options.restrict === 'reject' && !validCurrentPosition) {
                        viewValue = maskService.removeWrongPositions(viewValueWithDivisors);
                        viewValueWithDivisors = viewValue.withDivisors(true);
                        viewValueWithoutDivisors = viewValue.withoutDivisors(true);

                        // setSelectionRange(viewValueWithDivisors.length);
                      }
                    }

                    if (!options.limit) {
                      viewValueWithDivisors = viewValue.withDivisors(false);
                      viewValueWithoutDivisors = viewValue.withoutDivisors(false);
                    }

                    // Set validity
                    if (options.validate && controller.$dirty) {
                      if (fullRegex.test(viewValueWithDivisors) || controller.$isEmpty(controller.$modelValue)) {
                        controller.$setValidity('mask', true);
                      } else {
                        controller.$setValidity('mask', false);
                      }
                    }

                    // Update view and model values
                    if(value !== viewValueWithDivisors){
                      controller.$setViewValue(angular.copy(viewValueWithDivisors), 'input');
                      controller.$render();
                    }
                  } catch (e) {
                    $log.error('[mask - parseViewValue]');
                    throw e;
                  }

                  // Update model, can be different of view value
                  if (options.clean) {
                    return viewValueWithoutDivisors;
                  } else {
                    return viewValueWithDivisors;
                  }
                }

                controller.$parsers.push(parseViewValue);

                $element.on('click input paste keyup', function() {
                  timeout = $timeout(function() {
                    // Manual debounce to prevent multiple execution
                    $timeout.cancel(timeout);

                    parseViewValue($element.val());
                    $scope.$apply();
                  }, 100);
                });

                // Register the watch to observe remote loading or promised data
                var $scope.$watch($attrs.ngModel, function (newValue, oldValue) {
                  if (angular.isDefined(newValue)) {
                    parseViewValue(newValue);
                  }
                });

                // $evalAsync from a directive
                // it should run after the DOM has been manipulated by Angular
                // but before the browser renders
                if(options.value) {
                  $scope.$evalAsync(function($scope) {
                    controller.$setViewValue(angular.copy(options.value), 'input');
                    controller.$render();
                  });
                }
              });
            }
          }
        }
      }
    }]);
})();
<|endoftext|>


<commit_before>import request from 'axios';
import { likePlaylistVideo } from './PlaylistActions';
import { auth, handleError } from 'helpers/requestHelpers';
import { URL } from 'constants/URL';
import VIDEO from '../constants/Video';

const API_URL = `${URL}/video`;

export const addTags = ({ tags }) => ({
  type: VIDEO.ADD_TAGS,
  tags
});

export const attachStar = data => ({
  type: VIDEO.ATTACH_STAR,
  data
});

export const addVideoView = params => dispatch => {
  try {
    request.post(`${API_URL}/view`, params);
  } catch (error) {
    handleError(error, dispatch);
  }
};

export const changeByUserStatus = ({ contentId, byUser }) => ({
  type: VIDEO.CHANGE_BY_USER_STATUS,
  videoId: Number(contentId),
  byUser
});

export const closeAddVideoModal = () => ({
  type: VIDEO.CLOSE_MODAL
});

export const deleteVideo = ({
  videoId,
  arrayIndex,
  lastVideoId
}) => async dispatch => {
  try {
    const { data } = await request.delete(
      `${API_URL}?videoId=${videoId}&lastVideoId=${lastVideoId}`,
      auth()
    );
    dispatch({
      type: VIDEO.DELETE,
      arrayIndex,
      data
    });
    return Promise.resolve();
  } catch (error) {
    handleError(error, dispatch);
  }
};

export const deleteVideoComment = commentId => ({
  type: VIDEO.DELETE_COMMENT,
  commentId
});

export const deleteVideoDiscussion = discussionId => ({
  type: VIDEO.DELETE_DISCUSSION,
  discussionId
});

export const editVideoComment = data => ({
  type: VIDEO.EDIT_COMMENT,
  ...data
});

export const editRewardComment = ({ id, text }) => ({
  type: VIDEO.EDIT_REWARD_COMMENT,
  id,
  text
});

export const editVideoDiscussion = ({ editedDiscussion, discussionId }) => ({
  type: VIDEO.EDIT_DISCUSSION,
  data: editedDiscussion,
  discussionId
});

export const editVideoPage = params => async dispatch => {
  try {
    const { data } = await request.post(`${API_URL}/edit/page`, params, auth());
    if (data.success) {
      dispatch({
        type: VIDEO.EDIT_PAGE,
        params
      });
    }
    return Promise.resolve();
  } catch (error) {
    handleError(error, dispatch);
  }
};

export const editVideoTitle = params => async dispatch => {
  try {
    const { data } = await request.post(
      `${API_URL}/edit/title`,
      params,
      auth()
    );
    if (data.result) {
      dispatch({
        type: VIDEO.EDIT_TITLE,
        videoId: params.videoId,
        data: data.result
      });
    }
    return Promise.resolve();
  } catch (error) {
    handleError(error, dispatch);
  }
};

export const emptyCurrentVideoSlot = () => ({
  type: VIDEO.EMPTY_CURRENT_VIDEO_SLOT
});

export const fillCurrentVideoSlot = videoId => ({
  type: VIDEO.FILL_CURRENT_VIDEO_SLOT,
  videoId
});

export const getInitialVideos = () => async dispatch => {
  try {
    const {
      data: { videos, loadMoreButton }
    } = await request.get(API_URL);
    dispatch({
      type: VIDEO.LOAD,
      initialRun: true,
      loadMoreButton,
      videos
    });
  } catch (error) {
    handleError(error, dispatch);
  }
};

export const getMoreVideos = ({ videos, loadMoreButton }) => ({
  type: VIDEO.LOAD,
  initialRun: false,
  loadMoreButton,
  videos
});

export const loadTags = ({ tags }) => ({
  type: VIDEO.LOAD_TAGS,
  tags
});

export const likeVideo = (likes, videoId) => async dispatch => {
  dispatch({
    type: VIDEO.LIKE,
    data: likes,
    videoId
  });
  dispatch(likePlaylistVideo(likes, videoId));
};

export const likeVideoComment = ({ commentId, likes }) => ({
  type: VIDEO.LIKE_COMMENT,
  data: { commentId, likes }
});

export const loadMoreComments = data => ({
  type: VIDEO.LOAD_MORE_COMMENTS,
  ...data
});

export const loadMoreDiscussionReplies = ({
  commentId,
  loadMoreButton,
  replies
}) => ({
  type: VIDEO.LOAD_MORE_DISCUSSION_REPLIES,
  commentId,
  loadMoreButton,
  replies
});

export const loadMoreReplies = ({ commentId, loadMoreButton, replies }) => ({
  type: VIDEO.LOAD_MORE_REPLIES,
  commentId,
  loadMoreButton,
  replies
});

export const loadMoreDiscussionComments = ({ data, discussionId }) => ({
  type: VIDEO.LOAD_MORE_DISCUSSION_COMMENTS,
  discussionId,
  ...data
});

export const loadVideoDiscussions = ({ results, loadMoreButton }) => ({
  type: VIDEO.LOAD_DISCUSSIONS,
  results,
  loadMoreButton
});

export const loadMoreDiscussions = ({ results, loadMoreButton }) => ({
  type: VIDEO.LOAD_MORE_DISCUSSIONS,
  results,
  loadMoreButton
});

export const loadMorePlaylistVideos = (
  videoId,
  playlistId,
  shownVideos
) => async dispatch => {
  try {
    const {
      data: { playlistVideos, playlistVideosLoadMoreShown }
    } = await request.get(
      `${API_URL}/more/playlistVideos?videoId=${videoId}&playlistId=${playlistId}&${shownVideos}`
    );
    dispatch({
      type: VIDEO.LOAD_MORE_RIGHT_MENU_PL_VIDS,
      playlistVideos,
      playlistVideosLoadMoreShown
    });
    Promise.resolve();
  } catch (error) {
    handleError(error, dispatch);
  }
};

export const loadRightMenuVideos = (videoId, playlistId) => async dispatch => {
  try {
    const { data } = await request.get(
      `${URL}/${
        playlistId ? 'playlist' : 'video'
      }/rightMenu?videoId=${videoId}${
        playlistId ? `&playlistId=${playlistId}` : ''
      }`
    );
    dispatch({
      type: VIDEO.LOAD_RIGHT_MENU_VIDS,
      data
    });
  } catch (error) {
    handleError(error, dispatch);
  }
};

export const loadVideoComments = data => ({
  type: VIDEO.LOAD_COMMENTS,
  ...data
});

export const loadVideoDiscussionComments = ({ data, discussionId }) => ({
  type: VIDEO.LOAD_DISCUSSION_COMMENTS,
  discussionId,
  ...data
});

export const loadVideoPage = (videoId, fromClientSide) => async dispatch => {
  if (isNaN(videoId)) return dispatch({ type: VIDEO.PAGE_UNAVAILABLE });
  try {
    const { data } = await request.get(`${API_URL}/page?videoId=${videoId}`);
    dispatch({
      type: VIDEO.LOAD_PAGE,
      data
    });
    return Promise.resolve();
  } catch (error) {
    dispatch({ type: VIDEO.PAGE_UNAVAILABLE });
    handleError(error, dispatch);
  }
};

export const openAddVideoModal = () => ({
  type: VIDEO.OPEN_MODAL
});

export const resetVideoPage = () => ({
  type: VIDEO.RESET_PAGE
});

export const resetVideoState = () => ({
  type: VIDEO.RESET
});

export const setDifficulty = ({ contentId, difficulty }) => ({
  type: VIDEO.SET_DIFFICULTY,
  videoId: contentId,
  difficulty
});

export const setDiscussionDifficulty = ({ contentId, difficulty }) => ({
  type: VIDEO.SET_DISCUSSION_DIFFICULTY,
  contentId,
  difficulty
});

export const uploadQuestions = params => async dispatch => {
  try {
    await request.post(`${API_URL}/questions`, params, auth());
    const questions = params.questions.map(question => {
      return {
        title: question.title,
        choices: [
          question.choice1,
          question.choice2,
          question.choice3,
          question.choice4,
          question.choice5
        ],
        correctChoice: question.correctChoice
      };
    });
    dispatch({
      type: VIDEO.ADD_QUESTIONS,
      data: questions
    });
    return Promise.resolve();
  } catch (error) {
    handleError(error, dispatch);
  }
};

export const uploadVideo = data => ({
  type: VIDEO.UPLOAD,
  data
});

export const uploadComment = comment => ({
  type: VIDEO.UPLOAD_COMMENT,
  comment
});

export const uploadReply = reply => ({
  type: VIDEO.UPLOAD_REPLY,
  reply
});

export const uploadVideoDiscussion = data => ({
  type: VIDEO.UPLOAD_DISCUSSION,
  data
});
<commit_msg>minor patch<commit_after>import request from 'axios';
import { likePlaylistVideo } from './PlaylistActions';
import { auth, handleError } from 'helpers/requestHelpers';
import { URL } from 'constants/URL';
import VIDEO from '../constants/Video';

const API_URL = `${URL}/video`;

export const addTags = ({ tags }) => ({
  type: VIDEO.ADD_TAGS,
  tags
});

export const attachStar = data => ({
  type: VIDEO.ATTACH_STAR,
  data
});

export const addVideoView = params => dispatch => {
  try {
    request.post(`${API_URL}/view`, params);
  } catch (error) {
    handleError(error, dispatch);
  }
};

export const changeByUserStatus = ({ contentId, byUser }) => ({
  type: VIDEO.CHANGE_BY_USER_STATUS,
  videoId: Number(contentId),
  byUser
});

export const closeAddVideoModal = () => ({
  type: VIDEO.CLOSE_MODAL
});

export const deleteVideo = ({
  videoId,
  arrayIndex,
  lastVideoId
}) => async dispatch => {
  try {
    const { data } = await request.delete(
      `${API_URL}?videoId=${videoId}&lastVideoId=${lastVideoId}`,
      auth()
    );
    dispatch({
      type: VIDEO.DELETE,
      arrayIndex,
      data
    });
    return Promise.resolve();
  } catch (error) {
    handleError(error, dispatch);
  }
};

export const deleteVideoComment = commentId => ({
  type: VIDEO.DELETE_COMMENT,
  commentId
});

export const deleteVideoDiscussion = discussionId => ({
  type: VIDEO.DELETE_DISCUSSION,
  discussionId
});

export const editVideoComment = data => ({
  type: VIDEO.EDIT_COMMENT,
  ...data
});

export const editRewardComment = ({ id, text }) => ({
  type: VIDEO.EDIT_REWARD_COMMENT,
  id,
  text
});

export const editVideoDiscussion = ({ editedDiscussion, discussionId }) => ({
  type: VIDEO.EDIT_DISCUSSION,
  data: editedDiscussion,
  discussionId
});

export const editVideoPage = params => async dispatch => {
  try {
    const { data } = await request.post(`${API_URL}/edit/page`, params, auth());
    if (data.success) {
      dispatch({
        type: VIDEO.EDIT_PAGE,
        params
      });
    }
    return Promise.resolve();
  } catch (error) {
    handleError(error, dispatch);
  }
};

export const editVideoTitle = params => async dispatch => {
  try {
    const { data } = await request.post(
      `${API_URL}/edit/title`,
      params,
      auth()
    );
    if (data.result) {
      dispatch({
        type: VIDEO.EDIT_TITLE,
        videoId: params.videoId,
        data: data.result
      });
    }
    return Promise.resolve();
  } catch (error) {
    handleError(error, dispatch);
  }
};

export const emptyCurrentVideoSlot = () => ({
  type: VIDEO.EMPTY_CURRENT_VIDEO_SLOT
});

export const fillCurrentVideoSlot = videoId => ({
  type: VIDEO.FILL_CURRENT_VIDEO_SLOT,
  videoId
});

export const getInitialVideos = () => async dispatch => {
  try {
    const {
      data: { videos, loadMoreButton }
    } = await request.get(API_URL);
    dispatch({
      type: VIDEO.LOAD,
      initialRun: true,
      loadMoreButton,
      videos
    });
  } catch (error) {
    handleError(error, dispatch);
  }
};

export const getMoreVideos = ({ videos, loadMoreButton }) => ({
  type: VIDEO.LOAD,
  initialRun: false,
  loadMoreButton,
  videos
});

export const loadTags = ({ tags }) => ({
  type: VIDEO.LOAD_TAGS,
  tags
});

export const likeVideo = (likes, videoId) => async dispatch => {
  dispatch({
    type: VIDEO.LIKE,
    data: likes,
    videoId
  });
  dispatch(likePlaylistVideo(likes, videoId));
};

export const likeVideoComment = ({ commentId, likes }) => ({
  type: VIDEO.LIKE_COMMENT,
  data: { commentId, likes }
});

export const loadMoreComments = data => ({
  type: VIDEO.LOAD_MORE_COMMENTS,
  ...data
});

export const loadMoreDiscussionReplies = ({
  commentId,
  loadMoreButton,
  replies
}) => ({
  type: VIDEO.LOAD_MORE_DISCUSSION_REPLIES,
  commentId,
  loadMoreButton,
  replies
});

export const loadMoreReplies = ({ commentId, loadMoreButton, replies }) => ({
  type: VIDEO.LOAD_MORE_REPLIES,
  commentId,
  loadMoreButton,
  replies
});

export const loadMoreDiscussionComments = ({ data, discussionId }) => ({
  type: VIDEO.LOAD_MORE_DISCUSSION_COMMENTS,
  discussionId,
  ...data
});

export const loadVideoDiscussions = ({ results, loadMoreButton }) => ({
  type: VIDEO.LOAD_DISCUSSIONS,
  results,
  loadMoreButton
});

export const loadMoreDiscussions = ({ results, loadMoreButton }) => ({
  type: VIDEO.LOAD_MORE_DISCUSSIONS,
  results,
  loadMoreButton
});

export const loadMorePlaylistVideos = (
  videoId,
  playlistId,
  shownVideos
) => async dispatch => {
  try {
    const {
      data: { playlistVideos, playlistVideosLoadMoreShown }
    } = await request.get(
      `${API_URL}/more/playlistVideos?videoId=${videoId}&playlistId=${playlistId}&${shownVideos}`
    );
    dispatch({
      type: VIDEO.LOAD_MORE_RIGHT_MENU_PL_VIDS,
      playlistVideos,
      playlistVideosLoadMoreShown
    });
    Promise.resolve();
  } catch (error) {
    handleError(error, dispatch);
  }
};

export const loadRightMenuVideos = (videoId, playlistId) => async dispatch => {
  try {
    const { data } = await request.get(
      `${URL}/${
        playlistId ? 'playlist' : 'video'
      }/rightMenu?videoId=${videoId}${
        playlistId ? `&playlistId=${playlistId}` : ''
      }`
    );
    dispatch({
      type: VIDEO.LOAD_RIGHT_MENU_VIDS,
      data
    });
  } catch (error) {
    handleError(error, dispatch);
  }
};

export const loadVideoComments = data => ({
  type: VIDEO.LOAD_COMMENTS,
  ...data
});

export const loadVideoDiscussionComments = ({ data, discussionId }) => ({
  type: VIDEO.LOAD_DISCUSSION_COMMENTS,
  discussionId,
  ...data
});

export const loadVideoPage = (videoId, fromClientSide) => async dispatch => {
  if (isNaN(videoId)) return dispatch({ type: VIDEO.PAGE_UNAVAILABLE });
  try {
    const { data } = await request.get(`${API_URL}/page?videoId=${videoId}`);
    dispatch({
      type: VIDEO.LOAD_PAGE,
      data
    });
    return Promise.resolve();
  } catch (error) {
    dispatch({ type: VIDEO.PAGE_UNAVAILABLE });
    handleError(error, dispatch);
  }
};

export const openAddVideoModal = () => ({
  type: VIDEO.OPEN_MODAL
});

export const resetVideoPage = () => ({
  type: VIDEO.RESET_PAGE
});

export const resetVideoState = () => ({
  type: VIDEO.RESET
});

export const setDifficulty = ({ contentId, difficulty }) => ({
  type: VIDEO.SET_DIFFICULTY,
  videoId: Number(contentId),
  difficulty
});

export const setDiscussionDifficulty = ({ contentId, difficulty }) => ({
  type: VIDEO.SET_DISCUSSION_DIFFICULTY,
  contentId,
  difficulty
});

export const uploadQuestions = params => async dispatch => {
  try {
    await request.post(`${API_URL}/questions`, params, auth());
    const questions = params.questions.map(question => {
      return {
        title: question.title,
        choices: [
          question.choice1,
          question.choice2,
          question.choice3,
          question.choice4,
          question.choice5
        ],
        correctChoice: question.correctChoice
      };
    });
    dispatch({
      type: VIDEO.ADD_QUESTIONS,
      data: questions
    });
    return Promise.resolve();
  } catch (error) {
    handleError(error, dispatch);
  }
};

export const uploadVideo = data => ({
  type: VIDEO.UPLOAD,
  data
});

export const uploadComment = comment => ({
  type: VIDEO.UPLOAD_COMMENT,
  comment
});

export const uploadReply = reply => ({
  type: VIDEO.UPLOAD_REPLY,
  reply
});

export const uploadVideoDiscussion = data => ({
  type: VIDEO.UPLOAD_DISCUSSION,
  data
});
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react'
import GMap from 'shared/components/addon/maps/gmap'
import { isEmpty } from 'lodash'
import moment from 'moment'
import { getFileName, getFileExt } from 'shared/utils/file-utils'
import classNames from 'classnames'
import { PostPropArray } from 'shared/utils/forms'
import { at } from 'lodash'
import { Link } from 'react-router'
import { originLocaleName } from 'shared/utils/locale-utils'
import Linkify from 'react-linkify'
import ADContent from './ADContent'
import Carousel from 'nuka-carousel'
import { Lightbox } from 'shared/components/addon/lightbox'
import {
  toMoment,
  isBetween,
  isPastDay,
  toShortDate,
  toYear
} from 'shared/utils/date-utils'

let swal
if (process.env.BROWSER) {
  swal = require('sweetalert')
}

export default class Post extends Component {

  static propTypes = {
    auth: PropTypes.object.isRequired,
    post: PropTypes.object.isRequired,
    moreList: PropTypes.object.isRequired,
    map: PropTypes.object.isRequired,
    remove: PropTypes.func.isRequired,
    _T: PropTypes.func.isRequired,
    defaultLocale: PropTypes.string.isRequired
  }

  static contextTypes = {
    history: PropTypes.object.isRequired
  }

  constructor (props) {
    super(props)

    this.releaseTimeout = undefined
  }

  componentWillUnmount () {
    if (this.op) {
      clearTimeout(this.releaseTimeout)
    }
  }

  removeTags (html) {
    const pattern = /(<([^>]+)>)/ig;
    return html.replace(pattern , '')
  }

  parseContent (content) {
    const ent = require('ent')
    const linkProps = {
      'target': '_blank'
    }
    if (content) {
      return (
        content.replace(/^\"|\"$/g, '').split('\n').map((t, i) => {
          return t === ''
            ?

            :
<Linkify properties={linkProps}>{ent.decode(this.removeTags(t))}</Linkify>

        })
      )
    }
  }

  deletePost = () => {
    const { post, remove, _T } = this.props
    const { detail } = post
    const { transitionTo, createLocation } = this.context.history
    swal({
      title: _T('post.detail.delete.title'),
      text: _T('post.detail.delete.text'),
      type: 'warning',
      showCancelButton: true,
      confirmButtonText: _T('post.detail.delete.confirm'),
      cancelButtonText: _T('post.detail.delete.cancel'),
      closeOnConfirm: false,
      showLoaderOnConfirm: true
    }, () => {
      Promise.all([
        remove(detail.id)
      ]).then((res) => {
        if (res[0].type === 'REMOVE_POST_COMPLETED') {
          swal({
            title: _T('post.detail.delete.ok.title'),
            text: _T('post.detail.delete.ok.text'),
            type: 'success',
            confirmButtonText: _T('post.detail.delete.ok.confirm'),
            closeOnConfirm: true
          }, () => {
            transitionTo(createLocation('/w'))
          })
        } else {
          swal(_T('post.detail.delete.err.title')
            , _T('post.detail.delete.err.text'),
            'error')
        }
      })
    })
  }

  handleImgClick (src, event) {
    Lightbox.show(

    )
  }

  renderDetailProp (detail) {
    return (

        {at(PostPropArray(originLocaleName(this.props.defaultLocale)), detail.prop)}

    )
  }

  renderRegisterInfo (detail) {
    if (!detail.url) return

    const Translate = require('react-translate-component')
    const open = toMoment(detail.openDate)
    const close = toMoment(detail.closeDate)
    const now = moment()

    if (now.isBetween(open, close)) {
      return (

            <Translate content="post.detail.open" />

      )
    } else if (now.isAfter(close)) {
      return (

            <Translate content="post.detail.close" />

      )
    }
  }

  renderImageAttachments () {
    const { detail } = this.props.post
    const files = typeof detail.file !== 'undefined'
      ? JSON.parse(detail.file)
      : []

    const imgs = []
    files && files.map(function (file) {
      if (getFileExt(file) !== 'pdf') {
        imgs.push(file)
      }
    })
    if (!isEmpty(imgs)) {
      return (

          <Carousel cellAlign="center" slideWidth="100%">
          {
            imgs.map(function (link) {
              if (getFileExt(link) !== 'pdf') {
                const src = '/uploads/' + link
                return (

                )
              } else {
                return (
)
              }
            }.bind(this))
          }
          </Carousel>

      )
    }

    return (

    )
  }

  renderMoreList () {
    const { titleList, isFetching } = this.props.moreList
    if (isFetching) {
      return (

      )
    } else {
      return (

            { !isEmpty(titleList) && titleList.map(function (item, i) {
              return (

                  <Link to={`/w/${item.id}`}>

                      { toShortDate(item.startDate) }

                    { item.title }
                  </Link>

              )})
            }

      )
    }
  }

  render () {
    const Translate = require('react-translate-component')

    if (!isEmpty(this.props.post.errors)) {
      return (

              <Translate content="post.detail.noexist" />

      )
    } else {
      const { detail } = this.props.post
      const { content } = detail
      const files = typeof detail.file !== 'undefined'
        ? JSON.parse(detail.file)
        : []

      const detailClass = classNames('content', { hide: !detail.id })

      const finalContent = this.parseContent(content)

      const eventDate = (detail.startDate === detail.endDate)
      ? toShortDate(detail.endDate)
      : toShortDate(detail.startDate) + ' - ' + toShortDate(detail.endDate)

      let eventEndYear =
        toYear(detail.endDate) > toYear(new Date())
        ? toYear(detail.endDate)
        : null

      const eventStartYear =
        toYear(detail.startDate) < toYear(new Date())
        ? toYear(detail.startDate)
        : null

      if (eventStartYear && toYear(detail.endDate) === toYear(new Date())) {
        eventEndYear = <Translate content="post.detail.this_year" />
      }

      const mainClasses = classNames(
        'ui',
        'two',
        'column',
        'post',
        'detail',
        'stackable',
        'has-header',
        'grid',
        'container'
      )

      const directionMode = true

      return (

                  {this.props.post.isFetching && !detail.id &&

                  }

                    {eventDate && (

                          {eventDate}

                      )}

                      {eventStartYear && (

                          {eventStartYear}
                          { eventEndYear
                            && <Translate content="post.detail.start" /> }

                      )}
                      {eventEndYear && (

                            <Translate content="post.detail.end" /> {eventEndYear}

                      )}

                      {detail.title}

                      {finalContent}
                      { files && !isEmpty(files)
                        &&

                          <Translate content="post.detail.attachments" />

 }

                      {
                        files && !isEmpty(files)
                        && files.map(function (file, i) {
                          return (

                                      { getFileName(file) }

                          )
                        })
                      }

                        {this.renderDetailProp(detail)}

                  {!isEmpty(detail.uid)
                    && this.props.auth.user.id === detail.uid &&

                      <Link
                        className="ui basic green button"
                        to={`/post/${detail.id}/edit`}>
                        <Translate content="post.detail.edit" />
                      </Link>

                        <Translate content="post.detail.delete.confirm" />

                  }

                { this.renderImageAttachments() }

                {this.renderRegisterInfo(detail)}

              {(detail.cid > 0) && (

                <Link
                  className="ui orange fluid large top attached button"
                  to={`/c/${detail.cid}`}>
                  {detail.ocname}
                </Link>

              )}

                { (detail.lat && detail.lat) &&
                <GMap
                  ref="gmap"
                  {...this.props.map}
                  directionMode={directionMode}
                  defaultLocale={this.props.defaultLocale}
                />
                }
                {this.renderMoreList()}

                <ADContent />

      )
    }
  }
}
<commit_msg>fix bugs<commit_after>import React, { Component, PropTypes } from 'react'
import GMap from 'shared/components/addon/maps/gmap'
import { isEmpty } from 'lodash'
import moment from 'moment'
import { getFileName, getFileExt } from 'shared/utils/file-utils'
import classNames from 'classnames'
import { PostPropArray } from 'shared/utils/forms'
import { at } from 'lodash'
import { Link } from 'react-router'
import { originLocaleName } from 'shared/utils/locale-utils'
import Linkify from 'react-linkify'
import ADContent from './ADContent'
import Carousel from 'nuka-carousel'
import { Lightbox } from 'shared/components/addon/lightbox'
import {
  toMoment,
  isBetween,
  isPastDay,
  toShortDate,
  toYear
} from 'shared/utils/date-utils'

let swal
if (process.env.BROWSER) {
  swal = require('sweetalert')
}

export default class Post extends Component {

  static propTypes = {
    auth: PropTypes.object.isRequired,
    post: PropTypes.object.isRequired,
    moreList: PropTypes.object.isRequired,
    map: PropTypes.object.isRequired,
    remove: PropTypes.func.isRequired,
    _T: PropTypes.func.isRequired,
    defaultLocale: PropTypes.string.isRequired
  }

  static contextTypes = {
    history: PropTypes.object.isRequired
  }

  constructor (props) {
    super(props)

    this.releaseTimeout = undefined
  }

  componentWillUnmount () {
    if (this.op) {
      clearTimeout(this.releaseTimeout)
    }
  }

  removeTags (html) {
    const pattern = /(<([^>]+)>)/ig;
    return html.replace(pattern , '')
  }

  parseContent (content) {
    const ent = require('ent')
    const linkProps = {
      'target': '_blank'
    }
    if (content) {
      return (
        content.replace(/^\"|\"$/g, '').split('\n').map((t, i) => {
          return t === ''
            ?

            :
<Linkify properties={linkProps}>{ent.decode(this.removeTags(t))}</Linkify>

        })
      )
    }
  }

  deletePost = () => {
    const { post, remove, _T } = this.props
    const { detail } = post
    const { transitionTo, createLocation } = this.context.history
    swal({
      title: _T('post.detail.delete.title'),
      text: _T('post.detail.delete.text'),
      type: 'warning',
      showCancelButton: true,
      confirmButtonText: _T('post.detail.delete.confirm'),
      cancelButtonText: _T('post.detail.delete.cancel'),
      closeOnConfirm: false,
      showLoaderOnConfirm: true
    }, () => {
      Promise.all([
        remove(detail.id)
      ]).then((res) => {
        if (res[0].type === 'REMOVE_POST_COMPLETED') {
          swal({
            title: _T('post.detail.delete.ok.title'),
            text: _T('post.detail.delete.ok.text'),
            type: 'success',
            confirmButtonText: _T('post.detail.delete.ok.confirm'),
            closeOnConfirm: true
          }, () => {
            transitionTo(createLocation('/w'))
          })
        } else {
          swal(_T('post.detail.delete.err.title')
            , _T('post.detail.delete.err.text'),
            'error')
        }
      })
    })
  }

  handleImgClick (src, event) {
    Lightbox.show(

    )
  }

  checkImageFile (file) {
    if (getFileExt(file) === 'pdf' ||
        getFileExt(file) === 'doc' ||
        getFileExt(file) === 'docx') {
      return false
    }

    return true
  }

  renderDetailProp (detail) {
    return (

        {at(PostPropArray(originLocaleName(this.props.defaultLocale)), detail.prop)}

    )
  }

  renderRegisterInfo (detail) {
    if (!detail.url) return

    const Translate = require('react-translate-component')
    const open = toMoment(detail.openDate)
    const close = toMoment(detail.closeDate)
    const now = moment()

    if (now.isBetween(open, close)) {
      return (

            <Translate content="post.detail.open" />

      )
    } else if (now.isAfter(close)) {
      return (

            <Translate content="post.detail.close" />

      )
    }
  }

  renderImageAttachments () {
    const { detail } = this.props.post
    const files = typeof detail.file !== 'undefined'
      ? JSON.parse(detail.file)
      : []

    const imgs = []
    const checkImageFile = this.checkImageFile
    files && files.map(function (file) {
      if (checkImageFile(file)) {
        imgs.push(file)
      }
    })
    if (!isEmpty(imgs)) {
      return (

          <Carousel cellAlign="center" slideWidth="100%">
          {
            imgs.map(function (link) {
              if (checkImageFile(link)) {
                const src = '/uploads/' + link
                return (

                )
              } else {
                return (
)
              }
            }.bind(this))
          }
          </Carousel>

      )
    }

    return (

    )
  }

  renderMoreList () {
    const { titleList, isFetching } = this.props.moreList
    if (isFetching) {
      return (

      )
    } else {
      return (

            { !isEmpty(titleList) && titleList.map(function (item, i) {
              return (

                  <Link to={`/w/${item.id}`}>

                      { toShortDate(item.startDate) }

                    { item.title }
                  </Link>

              )})
            }

      )
    }
  }

  render () {
    const Translate = require('react-translate-component')

    if (!isEmpty(this.props.post.errors)) {
      return (

              <Translate content="post.detail.noexist" />

      )
    } else {
      const { detail } = this.props.post
      const { content } = detail
      const files = typeof detail.file !== 'undefined'
        ? JSON.parse(detail.file)
        : []

      const detailClass = classNames('content', { hide: !detail.id })

      const finalContent = this.parseContent(content)

      const eventDate = (detail.startDate === detail.endDate)
      ? toShortDate(detail.endDate)
      : toShortDate(detail.startDate) + ' - ' + toShortDate(detail.endDate)

      let eventEndYear =
        toYear(detail.endDate) > toYear(new Date())
        ? toYear(detail.endDate)
        : null

      const eventStartYear =
        toYear(detail.startDate) < toYear(new Date())
        ? toYear(detail.startDate)
        : null

      if (eventStartYear && toYear(detail.endDate) === toYear(new Date())) {
        eventEndYear = <Translate content="post.detail.this_year" />
      }

      const mainClasses = classNames(
        'ui',
        'two',
        'column',
        'post',
        'detail',
        'stackable',
        'has-header',
        'grid',
        'container'
      )

      const directionMode = true

      return (

                  {this.props.post.isFetching && !detail.id &&

                  }

                    {eventDate && (

                          {eventDate}

                      )}

                      {eventStartYear && (

                          {eventStartYear}
                          { eventEndYear
                            && <Translate content="post.detail.start" /> }

                      )}
                      {eventEndYear && (

                            <Translate content="post.detail.end" /> {eventEndYear}

                      )}

                      {detail.title}

                      {finalContent}
                      { files && !isEmpty(files)
                        &&

                          <Translate content="post.detail.attachments" />

 }

                      {
                        files && !isEmpty(files)
                        && files.map(function (file, i) {
                          return (

                                      { getFileName(file) }

                          )
                        })
                      }

                        {this.renderDetailProp(detail)}

                  {!isEmpty(detail.uid)
                    && this.props.auth.user.id === detail.uid &&

                      <Link
                        className="ui basic green button"
                        to={`/post/${detail.id}/edit`}>
                        <Translate content="post.detail.edit" />
                      </Link>

                        <Translate content="post.detail.delete.confirm" />

                  }

                { this.renderImageAttachments() }

                {this.renderRegisterInfo(detail)}

              {(detail.cid > 0) && (

                <Link
                  className="ui orange fluid large top attached button"
                  to={`/c/${detail.cid}`}>
                  {detail.ocname}
                </Link>

              )}

                { (detail.lat && detail.lat) &&
                <GMap
                  ref="gmap"
                  {...this.props.map}
                  directionMode={directionMode}
                  defaultLocale={this.props.defaultLocale}
                />
                }
                {this.renderMoreList()}

                <ADContent />

      )
    }
  }
}
<|endoftext|>


<commit_before>var socketIo = require('socket.io'),
    mongoose = require('mongoose'),
    Alert = mongoose.model('Alert');

module.exports = function(server){
    var io = socketIo.listen(server);

    var num_connections = 0;
    var previous_data = []; //TODO: cache via redis

    //TODO: only published (unless admin),
    //TODO: enddate >= today
    //TODO: published == true
    var stream = Alert.find().tailable().stream();

    stream.on('data', function (doc) {
        //note: there may be as few a 0 users connected at this point, meaning that noone may see this initial data
        //hence, it is stored in previousData, so that it will be accessible to all who join later
        console.log('Alert stream doc', doc, 'num_connections emitting to:', num_connections);

        io.emit('alert', doc);
        previous_data.push(doc);
    });

    stream.on('error', function (err) {
        console.error('Alert stream error', err);
    });

    stream.on('close', function () {
        console.log('Alert stream closed');
    });

    io.sockets.on('connection', function(socket) {
        console.log('user connected to socket. num_connections', ++num_connections);

        //connecting user may have missed out on all previous transmissions, get them up to speed
        io.sockets.socket(socket.id).emit('alerts', previous_data);

        socket.on('disconnect', function(){
            console.log('user disconnected. num_connections', --num_connections);
        });
    });
};
<commit_msg>Updated code to socket.io 1.0 structure<commit_after>var socketIo = require('socket.io'),
    mongoose = require('mongoose'),
    Alert = mongoose.model('Alert');

module.exports = function(server){
    var io = socketIo.listen(server);

    var num_connections = 0;
    var previous_data = []; //TODO: cache via redis

    //TODO: only published (unless admin),
    //TODO: enddate >= today
    //TODO: published == true
    var stream = Alert.find().tailable().stream();

    stream.on('data', function (doc) {
        //note: there may be as few a 0 users connected at this point, meaning that noone may see this initial data
        //hence, it is stored in previousData, so that it will be accessible to all who join later
        console.log('Alert stream doc', doc, 'num_connections emitting to:', num_connections);

        io.emit('alert', doc);
        previous_data.push(doc);
    });

    stream.on('error', function (err) {
        console.error('Alert stream error', err);
    });

    stream.on('close', function () {
        console.log('Alert stream closed');
    });

    io.sockets.on('connection', function(socket) {
        console.log('user connected to socket. num_connections', ++num_connections);

        //connecting user may have missed out on all previous transmissions, get them up to speed
        console.log('sending', previous_data.length, 'items to socket', socket.id);
        io.sockets.connected[socket.id].emit('alerts', previous_data);

        socket.on('disconnect', function(){
            console.log('user disconnected. num_connections', --num_connections);
        });
    });
};
<|endoftext|>


<commit_before>(function(window) {
    'use strict';

    angular.module('stockflux.tearout')
        .directive('tearable', ['geometryService', 'hoverService', 'currentWindowService', 'configService',
            (geometryService, hoverService, currentWindowService, configService) => {
                return {
                    restrict: 'C',
                    link: (scope, element, attrs) => {
                        // Finding the tear element is tightly coupled to the HTML layout.
                        var dragElement = element[0],
                            tearElement = dragElement.parentNode.parentNode,
                            tileWidth = tearElement.clientWidth || 230,
                            tileHeight = tearElement.clientHeight || 100,
                            store;

                        var windowService = window.windowService;
                        var tearoutWindow = windowService.createTearoutWindow(window.name);

                        var myDropTarget = tearElement.parentNode,
                            parent = myDropTarget.parentNode,
                            myHoverArea = parent.getElementsByClassName('hover-area')[0],
                            offset = { x: 0, y: 0 },
                            currentlyDragging = false,
                            insideFavouritesPane = true,
                            dragService;

                        hoverService.add(myHoverArea, scope.stock.code);

                        function setOffset(x, y) {
                            offset.x = x;
                            offset.y = y;
                        }

                        function setCurrentlyDragging(dragging) {
                            currentlyDragging = dragging;
                        }

                        function moveTearoutWindow(x, y) {
                            var tileTopPadding = 5,
                                tileRightPadding = 5,
                                tearElementWidth = 16;

                            tearoutWindow.moveTo(
                                x - tileWidth + (tearElementWidth - offset.x + tileRightPadding),
                                y - (tileTopPadding + offset.y));
                        }

                        function displayTearoutWindow() {
                            tearoutWindow.show();
                            tearoutWindow.setAsForeground();
                        }

                        function appendToOpenfinWindow(injection, openfinWindow) {
                            openfinWindow.contentWindow.document.body.appendChild(injection);
                        }

                        function returnFromTearout() {
                            myDropTarget.appendChild(tearElement);
                            tearoutWindow.hide();
                        }

                        function clearIncomingTearoutWindow() {
                            var document = tearoutWindow.getNativeWindow().document;
                            document.body = document.createElement('body');
                        }

                        function handleMouseDown(e) {
                            if (e.button !== 0) {
                                // Only process left clicks
                                return false;
                            }

                            if (dragElement.classList.contains('single')) {
                                // There is only one favourite card so don't allow tearing out
                                return false;
                            }

                            dragService = windowService.registerDrag(tearoutWindow, currentWindowService.getCurrentWindow());

                            setCurrentlyDragging(true);
                            setOffset(e.offsetX, e.offsetY);
                            moveTearoutWindow(e.screenX, e.screenY);
                            clearIncomingTearoutWindow();
                            appendToOpenfinWindow(tearElement, tearoutWindow);
                            displayTearoutWindow();
                        }

                        function handleMouseMove(e) {
                            if (currentlyDragging) {
                                moveTearoutWindow(e.screenX, e.screenY);
                            }
                        }

                        function handleMouseUp(e) {
                            if (e.button !== 0) {
                                // Only process left clicks
                                return false;
                            }

                            if (currentlyDragging) {
                                setCurrentlyDragging(false);
                                if (insideFavouritesPane) {
                                    returnFromTearout();
                                } else {
                                    if (!store) {
                                        store = window.storeService.open(window.name);
                                    }

                                    dragService.overAnotherInstance((overAnotherInstance) => {
                                        if (overAnotherInstance) {
                                            dragService.moveToOtherInstance(scope.stock);
                                            store.remove(scope.stock);
                                            dragService = null;
                                        } else {
                                            // Create new window instance
                                            var compact = store.isCompact();
                                            windowService.createMainWindow(null, compact, (newWindow) => {
                                                newWindow.resizeTo(window.outerWidth, window.outerHeight, 'top-left');
                                                var newCardOffset = configService.getTopCardOffset(compact);
                                                newWindow.moveTo(e.screenX - newCardOffset[0], e.screenY - newCardOffset[1]);
                                                var newStore = window.storeService.open(newWindow.name);
                                                newStore.add(scope.stock);
                                                store.remove(scope.stock);
                                                newStore.toggleCompact(compact);
                                            });
                                        }

                                        // Remove drop-target from original instance
                                        parent.removeChild(myHoverArea);
                                        parent.removeChild(myDropTarget);
                                        dispose();

                                        // Destroy myself.
                                        tearoutWindow.close();
                                    });
                                }
                            }
                        }

                        function reorderFavourites() {
                            var hoverTargets = hoverService.get();

                            for (var i = 0, max = hoverTargets.length; i < max; i++) {
                                var overDropTarget = geometryService.elementIntersect(
                                    tearoutWindow, window, hoverTargets[i].hoverArea);

                                if (overDropTarget) {
                                    if (!store) {
                                        store = window.storeService.open(window.name);
                                    }

                                    store.reorder(scope.stock.code, hoverTargets[i].code);
                                    break;
                                }
                            }
                        }

                        function boundsChangingEvent() {
                            // Check if you are over a drop target by seeing if the tearout rectangle intersects the drop target
                            insideFavouritesPane = geometryService.elementIntersect(
                                tearoutWindow, window, document.getElementsByClassName('favourites')[0]);

                            if (insideFavouritesPane) {
                                reorderFavourites();
                            }
                        }

                        tearoutWindow.addEventListener('bounds-changing', boundsChangingEvent);

                        dragElement.addEventListener('mousedown', handleMouseDown);
                        document.addEventListener('mousemove', handleMouseMove, true);
                        document.addEventListener('mouseup', handleMouseUp, true);

                        function dispose() {
                            hoverService.remove(scope.stock.code);
                            tearoutWindow.removeEventListener('bounds-changing', boundsChangingEvent);
                            dragElement.removeEventListener('mousedown', handleMouseDown);
                            document.removeEventListener('mousemove', handleMouseMove);
                            document.removeEventListener('mouseup', handleMouseUp);
                        }

                        scope.$on('$destroy', () => {
                            dispose();
                        });
                    }
                };
            }]);
}(window));
<commit_msg>Refactor tearout directive<commit_after>(function(window) {
    'use strict';

    angular.module('stockflux.tearout')
        .directive('tearable', ['geometryService', 'hoverService', 'currentWindowService', 'configService',
            (geometryService, hoverService, currentWindowService, configService) => {
                return {
                    restrict: 'C',
                    link: (scope, element, attrs) => {
                        // Finding the tear element is tightly coupled to the HTML layout.
                        var dragElement = element[0],
                            tearElement = dragElement.parentNode.parentNode,
                            tileWidth = tearElement.clientWidth || 230,
                            tileHeight = tearElement.clientHeight || 100,
                            store;

                        var windowService = window.windowService;
                        var tearoutWindow = windowService.createTearoutWindow(window.name);

                        var myDropTarget = tearElement.parentNode,
                            parent = myDropTarget.parentNode,
                            myHoverArea = parent.getElementsByClassName('hover-area')[0],
                            offset = { x: 0, y: 0 },
                            currentlyDragging = false,
                            dragService;

                        hoverService.add(myHoverArea, scope.stock.code);

                        function insideFavouritesPane() {
                            // Check if you are over a drop target by seeing if the tearout rectangle intersects the drop target
                            return geometryService.elementIntersect(
                                tearoutWindow, window, document.getElementsByClassName('favourites')[0]);
                        }

                        function setOffset(x, y) {
                            offset.x = x;
                            offset.y = y;
                        }

                        function moveTearoutWindow(x, y) {
                            var tileTopPadding = 5,
                                tileRightPadding = 5,
                                tearElementWidth = 16;

                            tearoutWindow.moveTo(
                                x - tileWidth + (tearElementWidth - offset.x + tileRightPadding),
                                y - (tileTopPadding + offset.y));
                        }

                        function displayTearoutWindow() {
                            tearoutWindow.show();
                            tearoutWindow.setAsForeground();
                        }

                        function appendToOpenfinWindow(injection, openfinWindow) {
                            openfinWindow.contentWindow.document.body.appendChild(injection);
                        }

                        function returnFromTearout() {
                            myDropTarget.appendChild(tearElement);
                            tearoutWindow.hide();
                        }

                        function clearIncomingTearoutWindow() {
                            var document = tearoutWindow.getNativeWindow().document;
                            document.body = document.createElement('body');
                        }

                        function handleMouseDown(e) {
                            if (e.button !== 0) {
                                // Only process left clicks
                                return false;
                            }

                            if (dragElement.classList.contains('single')) {
                                // There is only one favourite card so don't allow tearing out
                                return false;
                            }

                            dragService = windowService.registerDrag(tearoutWindow, currentWindowService.getCurrentWindow());

                            currentlyDragging = true;
                            setOffset(e.offsetX, e.offsetY);
                            moveTearoutWindow(e.screenX, e.screenY);
                            clearIncomingTearoutWindow();
                            appendToOpenfinWindow(tearElement, tearoutWindow);
                            displayTearoutWindow();
                        }

                        function handleMouseMove(e) {
                            if (currentlyDragging) {
                                moveTearoutWindow(e.screenX, e.screenY);
                            }
                        }

                        function handleMouseUp(e) {
                            if (e.button !== 0) {
                                // Only process left clicks
                                return false;
                            }

                            if (currentlyDragging) {
                                currentlyDragging = false;
                                if (insideFavouritesPane()) {
                                    returnFromTearout();
                                } else {
                                    if (!store) {
                                        store = window.storeService.open(window.name);
                                    }

                                    dragService.overAnotherInstance((overAnotherInstance) => {
                                        if (overAnotherInstance) {
                                            dragService.moveToOtherInstance(scope.stock);
                                            store.remove(scope.stock);
                                            dragService = null;
                                        } else {
                                            // Create new window instance
                                            var compact = store.isCompact();
                                            windowService.createMainWindow(null, compact, (newWindow) => {
                                                newWindow.resizeTo(window.outerWidth, window.outerHeight, 'top-left');
                                                var newCardOffset = configService.getTopCardOffset(compact);
                                                newWindow.moveTo(e.screenX - newCardOffset[0], e.screenY - newCardOffset[1]);
                                                var newStore = window.storeService.open(newWindow.name);
                                                newStore.add(scope.stock);
                                                store.remove(scope.stock);
                                                newStore.toggleCompact(compact);
                                            });
                                        }

                                        // Remove drop-target from original instance
                                        parent.removeChild(myHoverArea);
                                        parent.removeChild(myDropTarget);
                                        dispose();

                                        // Destroy myself.
                                        tearoutWindow.close();
                                    });
                                }
                            }
                        }

                        function reorderFavourites() {
                            var hoverTargets = hoverService.get();

                            for (var i = 0, max = hoverTargets.length; i < max; i++) {
                                var overDropTarget = geometryService.elementIntersect(
                                    tearoutWindow, window, hoverTargets[i].hoverArea);

                                if (overDropTarget) {
                                    if (!store) {
                                        store = window.storeService.open(window.name);
                                    }

                                    store.reorder(scope.stock.code, hoverTargets[i].code);
                                    break;
                                }
                            }
                        }

                        function boundsChangingEvent() {
                            if (insideFavouritesPane()) {
                                reorderFavourites();
                            }
                        }

                        tearoutWindow.addEventListener('bounds-changing', boundsChangingEvent);

                        dragElement.addEventListener('mousedown', handleMouseDown);
                        document.addEventListener('mousemove', handleMouseMove, true);
                        document.addEventListener('mouseup', handleMouseUp, true);

                        function dispose() {
                            hoverService.remove(scope.stock.code);
                            tearoutWindow.removeEventListener('bounds-changing', boundsChangingEvent);
                            dragElement.removeEventListener('mousedown', handleMouseDown);
                            document.removeEventListener('mousemove', handleMouseMove);
                            document.removeEventListener('mouseup', handleMouseUp);
                        }

                        scope.$on('$destroy', () => {
                            dispose();
                        });
                    }
                };
            }]);
}(window));
<|endoftext|>


<commit_before>import jwt from 'jsonwebtoken';
import dotenv from 'dotenv';
import models from '../models';

const user = models.User;

dotenv.config();
const secret = process.env.SECRET;
const allow = (req, res, next) => {
  const token = req.body.token || req.query.token || req.headers['x-access-token'];
  if (token) {
    jwt.verify(token, secret, ((error, decoded) => {
      if (error) {
        return res.status(401)
          .json({
            status: 'fail',
            message: 'Unable to verify token'
          });
      }
      req.decoded = decoded;
      next();
    }));
  }
  if (!token) {
    next();
  }
};

export default allow;
<commit_msg>chore(middleware): remove status messages from response messages<commit_after>import jwt from 'jsonwebtoken';
import dotenv from 'dotenv';

dotenv.config();
const secret = process.env.SECRET;
const allow = (req, res, next) => {
  const token = req.body.token || req.query.token || req.headers['x-access-token'];
  if (token) {
    jwt.verify(token, secret, ((error, decoded) => {
      if (error) {
        return res.status(401)
          .json({
            Message: 'Unable to verify token'
          });
      }
      req.decoded = decoded;
      next();
    }));
  }
  if (!token) {
    next();
  }
};

export default allow;
<|endoftext|>


<commit_before>/*
 * Copyright 1999-2010 Luca Garulli (l.garulli--at--orientechnologies.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

function OForm() {
	this.object = null;
	this.templateMap = {};
	this.fieldTypes = {};

	/**
	 * Binds an object to the current page. When called recursively, prefix
	 * parameter contains the caller object's field.
	 */
	OForm.prototype.object2form = function(obj, prefix, level) {
		if (this.object == null)
			this.object = obj;

		if (prefix == null)
			prefix = "";
		else
			prefix = prefix + "_";

		if (level == null)
			level = 0;

		this.fieldTypes[prefix] = 'o';

		for (field in obj) {
			if (field.charAt(0) == "@")
				continue;

			var value = obj[field];

			var componentName = prefix + field;
			var component = $("#" + componentName);

			if (value instanceof Array)
				this.array2component(value, component, componentName, level);
			else if (typeof value == "object")
				this.object2form(value, prefix + field, level);
			else
				this.value2component(value, component, level);
		}
	}

	/**
	 * Binds an array to a component.
	 *
	 * @param array
	 *            value to map as array
	 * @param component
	 *            HTML component
	 */
	OForm.prototype.array2component = function(array, component, prefix, level) {
		if (component != null ) {
			componentChild = component.children().last();

			var referenceRow = this.templateMap[prefix];

			if (referenceRow == null) {
				// FIRST TIME: SEARCH THE TEMPLATE
				referenceRow = componentChild.html();
				this.templateMap[prefix] = referenceRow;
			}

			component.empty();

			var indexToFind = "_?" + level;
			for (index in array) {
				var row = referenceRow;
				while (row.indexOf(indexToFind) > -1)
					row = row.replace(indexToFind, "_" + index);

				component.append(row);

				var value = array[index];
				if (value != null && typeof value == "object") {
					if (index == 0)
						this.fieldTypes[prefix] = 'o';

					this.object2form(value, prefix + "_" + index, level + 1);
				} else {
					if (index == 0)
						this.fieldTypes[prefix] = 'v';
					this
							.value2component(value, prefix + "_" + index,
									level + 1);
				}
			}
		}
	}

	/**
	 * Binds a generic simple value to a component.
	 *
	 * @param value
	 *            value to map
	 * @param component
	 *            HTML component
	 */
	OForm.prototype.value2component = function(value, component) {
		if (typeof component == "string") {
			this.fieldTypes[component] = 'v';

			// SEARCH THE COMPONENT
			component = $("#" + component);
			if (component == null) {
				// SEARCH WITH LAST PIECE OF THE NAME
				var lastPiecePos = component.lastIndexOf("_");
				if (lastPiecePos > -1)
					component = $("#" + component.substring(lastPiecePos));
			}
		}

		if (component != null) {
			// SET THE VALUE
			if (component.is('input')) {
				component.val(value);
			} else
				// AS TEXT
				component.text(value);
		}
	}

	/**
	 * Binds back the form's values to the original object.
	 */
	OForm.prototype.form2object = function(obj, prefix, field) {
		if (obj == null)
			obj = this.object;

		if (prefix == null)
			prefix = "";
		else
			prefix = prefix + "_";

		for (field in obj) {
			if (field.charAt(0) == "@")
				continue;

			var value = obj[field];

			var componentName = prefix + field;
			var component = $("#" + componentName);

			if (value instanceof Array)
				this.component2array(obj, component, componentName, field);
			else if (value != null && typeof value == "object")
				this.form2object(value, prefix + field);
			else
				this.component2value(component);
		}

		return obj;
	}

	/**
	 * Binds components to an array.
	 *
	 * @param array
	 *            value to map as array
	 * @param component
	 *            HTML component
	 */
	OForm.prototype.component2array = function(obj, component, prefix, field) {
		if (component != null ) {
			// RESET THE JSON ARRAY
			var array = obj[field];

			// BROWSE ALL THE COMPONENT
			var componentType = this.fieldTypes[prefix];
			if (componentType != null)
				for (index in array) {
					componentName = prefix + "_" + index;

					if (componentType == 'o')
						array[index] = this.form2object(array[index], componentName);
					else
						array[index] = this.component2value(componentName);

					++index;
				}
		}
	}
	/**
	 * Binds a component to a object field.
	 *
	 * @param value
	 *            value to map
	 * @param component
	 *            HTML component
	 */
	OForm.prototype.component2value = function(component) {
		if (typeof component == "string") {
			// SEARCH THE COMPONENT
			component = $("#" + component);
			if (component == null) {
				// SEARCH WITH LAST PIECE OF THE NAME
				var lastPiecePos = component.lastIndexOf("_");
				if (lastPiecePos > -1)
					component = $("#" + component.substring(lastPiecePos));
			}
		}

		if (component != null) {
			// SET THE VALUE
			if (component.is('input')) {
				return component.val();
			} else
				// AS TEXT
				return component.text();
		}
	}

	OForm.prototype.generateFieldButtons(id, styleClass){
		return "

" + this.generateFieldRemove(id +'_remove', styleClass ); "

";
	}

	OForm.prototype.generateFieldRemove(id, styleClass ){
		var out = "<button id='" + id + "'";
		if( styleClass)
		out += " class='ui-button-text-icon'";

		style="text-align: left">Add field </button>
		return var;
	}
}
<commit_msg>New version that binds any tag for collections<commit_after>/*
 * Copyright 1999-2010 Luca Garulli (l.garulli--at--orientechnologies.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

function OForm() {
	this.object = null;
	this.templateMap = {};
	this.fieldTypes = {};

	/**
	 * Binds an object to the current page. When called recursively, prefix
	 * parameter contains the caller object's field.
	 */
	OForm.prototype.object2form = function(obj, prefix, level) {
		if (this.object == null)
			this.object = obj;

		if (prefix == null)
			prefix = "";
		else
			prefix = prefix + "_";

		if (level == null)
			level = 0;

		this.fieldTypes[prefix] = 'o';

		for (field in obj) {
			if (field.charAt(0) == "@")
				continue;

			var value = obj[field];

			var componentName = prefix + field;
			var component = $("#" + componentName);

			if (value instanceof Array)
				this.array2component(value, component, componentName, level);
			else if (typeof value == "object")
				this.object2form(value, prefix + field, level);
			else
				this.value2component(value, component, level);
		}
	}

	/**
	 * Binds an array to a component.
	 *
	 * @param array
	 *            value to map as array
	 * @param component
	 *            HTML component
	 */
	OForm.prototype.array2component = function(array, component, prefix, level) {
		if (component != null ) {
			componentChild = component.children().last();

			var referenceRow = this.templateMap[prefix];

			if (referenceRow == null) {
				// FIRST TIME: SEARCH THE TEMPLATE
				referenceRow = componentChild.html();
				this.templateMap[prefix] = referenceRow;
			}

			component.empty();

			var indexToFind = "_?" + level;
			for (index in array) {
				var row = referenceRow;
				while (row.indexOf(indexToFind) > -1)
					row = row.replace(indexToFind, "_" + index);

				component.append(row);

				var value = array[index];
				if (value != null && typeof value == "object") {
					if (index == 0)
						this.fieldTypes[prefix] = 'o';

					this.object2form(value, prefix + "_" + index, level + 1);
				} else {
					if (index == 0)
						this.fieldTypes[prefix] = 'v';
					this
							.value2component(value, prefix + "_" + index,
									level + 1);
				}
			}
		}
	}

	/**
	 * Binds a generic simple value to a component.
	 *
	 * @param value
	 *            value to map
	 * @param component
	 *            HTML component
	 */
	OForm.prototype.value2component = function(value, component) {
		if (typeof component == "string") {
			this.fieldTypes[component] = 'v';

			// SEARCH THE COMPONENT
			component = $("#" + component);
			if (component == null) {
				// SEARCH WITH LAST PIECE OF THE NAME
				var lastPiecePos = component.lastIndexOf("_");
				if (lastPiecePos > -1)
					component = $("#" + component.substring(lastPiecePos));
			}
		}

		if (component != null) {
			// SET THE VALUE
			if (component.is('input')) {
				component.val(value);
			} else
				// AS TEXT
				component.text(value);
		}
	}

	/**
	 * Binds back the form's values to the original object.
	 */
	OForm.prototype.form2object = function(obj, prefix, field) {
		if (obj == null)
			obj = this.object;

		if (prefix == null)
			prefix = "";
		else
			prefix = prefix + "_";

		for (field in obj) {
			if (field.charAt(0) == "@")
				continue;

			var value = obj[field];

			var componentName = prefix + field;
			var component = $("#" + componentName);

			if (value instanceof Array)
				this.component2array(obj, component, componentName, field);
			else if (value != null && typeof value == "object")
				this.form2object(value, prefix + field);
			else
				this.component2value(component);
		}

		return obj;
	}

	/**
	 * Binds components to an array.
	 *
	 * @param array
	 *            value to map as array
	 * @param component
	 *            HTML component
	 */
	OForm.prototype.component2array = function(obj, component, prefix, field) {
		if (component != null ) {
			// RESET THE JSON ARRAY
			var array = obj[field];

			// BROWSE ALL THE COMPONENT
			var componentType = this.fieldTypes[prefix];
			if (componentType != null)
				for (index in array) {
					componentName = prefix + "_" + index;

					if (componentType == 'o')
						array[index] = this.form2object(array[index], componentName);
					else
						array[index] = this.component2value(componentName);

					++index;
				}
		}
	}
	/**
	 * Binds a component to a object field.
	 *
	 * @param value
	 *            value to map
	 * @param component
	 *            HTML component
	 */
	OForm.prototype.component2value = function(component) {
		if (typeof component == "string") {
			// SEARCH THE COMPONENT
			component = $("#" + component);
			if (component == null) {
				// SEARCH WITH LAST PIECE OF THE NAME
				var lastPiecePos = component.lastIndexOf("_");
				if (lastPiecePos > -1)
					component = $("#" + component.substring(lastPiecePos));
			}
		}

		if (component != null) {
			// SET THE VALUE
			if (component.is('input')) {
				return component.val();
			} else
				// AS TEXT
				return component.text();
		}
	}
}
<|endoftext|>


<commit_before>/**
 * Detect Element Resize.
 * https://github.com/sdecima/javascript-detect-element-resize
 * Sebastian Decima
 *
 * Forked from version 0.5.3; includes the following modifications:
 * 1) Guard against unsafe 'window' and 'document' references (to support SSR).
 * 2) Defer initialization code via a top-level function wrapper (to support SSR).
 * 3) Avoid unnecessary reflows by not measuring size for scroll events bubbling from children.
 **/

export default function createDetectElementResize () {
  // Check `document` and `window` in case of server-side rendering
  var _window
  if (typeof window !== 'undefined') {
    _window = window
  } else if (typeof self !== 'undefined') {
    _window = self
  } else {
    _window = this
  }

  var attachEvent = typeof document !== 'undefined' && document.attachEvent;
  var stylesCreated = false;

  if (!attachEvent) {
    var requestFrame = (function(){
      var raf = _window.requestAnimationFrame || _window.mozRequestAnimationFrame || _window.webkitRequestAnimationFrame ||
                function(fn){ return _window.setTimeout(fn, 20); };
      return function(fn){ return raf(fn); };
    })();

    var cancelFrame = (function(){
      var cancel = _window.cancelAnimationFrame || _window.mozCancelAnimationFrame || _window.webkitCancelAnimationFrame ||
                   _window.clearTimeout;
      return function(id){ return cancel(id); };
    })();

    var resetTriggers = function(element){
      var triggers = element.__resizeTriggers__,
        expand = triggers.firstElementChild,
        contract = triggers.lastElementChild,
        expandChild = expand.firstElementChild;
      contract.scrollLeft = contract.scrollWidth;
      contract.scrollTop = contract.scrollHeight;
      expandChild.style.width = expand.offsetWidth + 1 + 'px';
      expandChild.style.height = expand.offsetHeight + 1 + 'px';
      expand.scrollLeft = expand.scrollWidth;
      expand.scrollTop = expand.scrollHeight;
    };

    var checkTriggers = function(element){
      return element.offsetWidth != element.__resizeLast__.width ||
             element.offsetHeight != element.__resizeLast__.height;
    }

    var scrollListener = function(e){
      // Don't measure (which forces) reflow for scrolls that happen inside of children!
      if (
        e.target.className.indexOf('contract-trigger') < 0 &&
        e.target.className.indexOf('expand-trigger') < 0
      ) {
        return
      }

      var element = this;
      resetTriggers(this);
      if (this.__resizeRAF__) cancelFrame(this.__resizeRAF__);
      this.__resizeRAF__ = requestFrame(function(){
        if (checkTriggers(element)) {
          element.__resizeLast__.width = element.offsetWidth;
          element.__resizeLast__.height = element.offsetHeight;
          element.__resizeListeners__.forEach(function(fn){
            fn.call(element, e);
          });
        }
      });
    };

    /* Detect CSS Animations support to detect element display/re-attach */
    var animation = false,
      animationstring = 'animation',
      keyframeprefix = '',
      animationstartevent = 'animationstart',
      domPrefixes = 'Webkit Moz O ms'.split(' '),
      startEvents = 'webkitAnimationStart animationstart oAnimationStart MSAnimationStart'.split(' '),
      pfx  = '';
    {
      var elm = document.createElement('fakeelement');
      if( elm.style.animationName !== undefined ) { animation = true; }

      if( animation === false ) {
        for( var i = 0; i < domPrefixes.length; i++ ) {
          if( elm.style[ domPrefixes[i] + 'AnimationName' ] !== undefined ) {
            pfx = domPrefixes[ i ];
            animationstring = pfx + 'Animation';
            keyframeprefix = '-' + pfx.toLowerCase() + '-';
            animationstartevent = startEvents[ i ];
            animation = true;
            break;
          }
        }
      }
    }

    var animationName = 'resizeanim';
    var animationKeyframes = '@' + keyframeprefix + 'keyframes ' + animationName + ' { from { opacity: 0; } to { opacity: 0; } } ';
    var animationStyle = keyframeprefix + 'animation: 1ms ' + animationName + '; ';
  }

  var createStyles = function() {
    if (!stylesCreated) {
      //opacity:0 works around a chrome bug https://code.google.com/p/chromium/issues/detail?id=286360
      var css = (animationKeyframes ? animationKeyframes : '') +
          '.resize-triggers { ' + (animationStyle ? animationStyle : '') + 'visibility: hidden; opacity: 0; } ' +
          '.resize-triggers, .resize-triggers > div, .contract-trigger:before { content: \" \"; display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; z-index: -1; } .resize-triggers > div { background: #eee; overflow: auto; } .contract-trigger:before { width: 200%; height: 200%; }',
        head = document.head || document.getElementsByTagName('head')[0],
        style = document.createElement('style');

      style.type = 'text/css';
      if (style.styleSheet) {
        style.styleSheet.cssText = css;
      } else {
        style.appendChild(document.createTextNode(css));
      }

      head.appendChild(style);
      stylesCreated = true;
    }
  }

  var addResizeListener = function(element, fn){
    if (attachEvent) element.attachEvent('onresize', fn);
    else {
      if (!element.__resizeTriggers__) {
        var elementStyle = _window.getComputedStyle(element);
        if (elementStyle && elementStyle.position == 'static') {
          element.style.position = 'relative';
        }
        createStyles();
        element.__resizeLast__ = {};
        element.__resizeListeners__ = [];
        (element.__resizeTriggers__ = document.createElement('div')).className = 'resize-triggers';
        element.__resizeTriggers__.innerHTML = '

' +
                                            '

';
        element.appendChild(element.__resizeTriggers__);
        resetTriggers(element);
        element.addEventListener('scroll', scrollListener, true);

        /* Listen for a css animation to detect element display/re-attach */
        if (animationstartevent) {
          element.__resizeTriggers__.__animationListener__ = function animationListener(e) {
            if(e.animationName == animationName)
              resetTriggers(element);
          };
          element.__resizeTriggers__.addEventListener(
            animationstartevent, element.__resizeTriggers__.__animationListener__
          );
        }
      }
      element.__resizeListeners__.push(fn);
    }
  };

  var removeResizeListener = function(element, fn){
    if (attachEvent) element.detachEvent('onresize', fn);
    else {
      element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1);
      if (!element.__resizeListeners__.length) {
          element.removeEventListener('scroll', scrollListener, true);
          if (element.__resizeTriggers__.__animationListener__) {
            element.__resizeTriggers__.removeEventListener(
              animationstartevent, element.__resizeTriggers__.__animationListener__
            );
            element.__resizeTriggers__.__animationListener__ = null;
          }
          element.__resizeTriggers__ = !element.removeChild(element.__resizeTriggers__);
      }
    }
  }

  return {
    addResizeListener,
    removeResizeListener
  };
}
<commit_msg>Reuse style tag for detectElementResize<commit_after>/**
 * Detect Element Resize.
 * https://github.com/sdecima/javascript-detect-element-resize
 * Sebastian Decima
 *
 * Forked from version 0.5.3; includes the following modifications:
 * 1) Guard against unsafe 'window' and 'document' references (to support SSR).
 * 2) Defer initialization code via a top-level function wrapper (to support SSR).
 * 3) Avoid unnecessary reflows by not measuring size for scroll events bubbling from children.
 **/

export default function createDetectElementResize () {
  // Check `document` and `window` in case of server-side rendering
  var _window
  if (typeof window !== 'undefined') {
    _window = window
  } else if (typeof self !== 'undefined') {
    _window = self
  } else {
    _window = this
  }

  var attachEvent = typeof document !== 'undefined' && document.attachEvent;

  if (!attachEvent) {
    var requestFrame = (function(){
      var raf = _window.requestAnimationFrame || _window.mozRequestAnimationFrame || _window.webkitRequestAnimationFrame ||
                function(fn){ return _window.setTimeout(fn, 20); };
      return function(fn){ return raf(fn); };
    })();

    var cancelFrame = (function(){
      var cancel = _window.cancelAnimationFrame || _window.mozCancelAnimationFrame || _window.webkitCancelAnimationFrame ||
                   _window.clearTimeout;
      return function(id){ return cancel(id); };
    })();

    var resetTriggers = function(element){
      var triggers = element.__resizeTriggers__,
        expand = triggers.firstElementChild,
        contract = triggers.lastElementChild,
        expandChild = expand.firstElementChild;
      contract.scrollLeft = contract.scrollWidth;
      contract.scrollTop = contract.scrollHeight;
      expandChild.style.width = expand.offsetWidth + 1 + 'px';
      expandChild.style.height = expand.offsetHeight + 1 + 'px';
      expand.scrollLeft = expand.scrollWidth;
      expand.scrollTop = expand.scrollHeight;
    };

    var checkTriggers = function(element){
      return element.offsetWidth != element.__resizeLast__.width ||
             element.offsetHeight != element.__resizeLast__.height;
    }

    var scrollListener = function(e){
      // Don't measure (which forces) reflow for scrolls that happen inside of children!
      if (
        e.target.className.indexOf('contract-trigger') < 0 &&
        e.target.className.indexOf('expand-trigger') < 0
      ) {
        return
      }

      var element = this;
      resetTriggers(this);
      if (this.__resizeRAF__) cancelFrame(this.__resizeRAF__);
      this.__resizeRAF__ = requestFrame(function(){
        if (checkTriggers(element)) {
          element.__resizeLast__.width = element.offsetWidth;
          element.__resizeLast__.height = element.offsetHeight;
          element.__resizeListeners__.forEach(function(fn){
            fn.call(element, e);
          });
        }
      });
    };

    /* Detect CSS Animations support to detect element display/re-attach */
    var animation = false,
      animationstring = 'animation',
      keyframeprefix = '',
      animationstartevent = 'animationstart',
      domPrefixes = 'Webkit Moz O ms'.split(' '),
      startEvents = 'webkitAnimationStart animationstart oAnimationStart MSAnimationStart'.split(' '),
      pfx  = '';
    {
      var elm = document.createElement('fakeelement');
      if( elm.style.animationName !== undefined ) { animation = true; }

      if( animation === false ) {
        for( var i = 0; i < domPrefixes.length; i++ ) {
          if( elm.style[ domPrefixes[i] + 'AnimationName' ] !== undefined ) {
            pfx = domPrefixes[ i ];
            animationstring = pfx + 'Animation';
            keyframeprefix = '-' + pfx.toLowerCase() + '-';
            animationstartevent = startEvents[ i ];
            animation = true;
            break;
          }
        }
      }
    }

    var animationName = 'resizeanim';
    var animationKeyframes = '@' + keyframeprefix + 'keyframes ' + animationName + ' { from { opacity: 0; } to { opacity: 0; } } ';
    var animationStyle = keyframeprefix + 'animation: 1ms ' + animationName + '; ';
  }

  var createStyles = function() {
    if (!document.getElementById('detectElementResize')) {
      //opacity:0 works around a chrome bug https://code.google.com/p/chromium/issues/detail?id=286360
      var css = (animationKeyframes ? animationKeyframes : '') +
          '.resize-triggers { ' + (animationStyle ? animationStyle : '') + 'visibility: hidden; opacity: 0; } ' +
          '.resize-triggers, .resize-triggers > div, .contract-trigger:before { content: \" \"; display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; z-index: -1; } .resize-triggers > div { background: #eee; overflow: auto; } .contract-trigger:before { width: 200%; height: 200%; }',
        head = document.head || document.getElementsByTagName('head')[0],
        style = document.createElement('style');

      style.id = 'detectElementResize';
      style.type = 'text/css';
      if (style.styleSheet) {
        style.styleSheet.cssText = css;
      } else {
        style.appendChild(document.createTextNode(css));
      }

      head.appendChild(style);
    }
  }

  var addResizeListener = function(element, fn){
    if (attachEvent) element.attachEvent('onresize', fn);
    else {
      if (!element.__resizeTriggers__) {
        var elementStyle = _window.getComputedStyle(element);
        if (elementStyle && elementStyle.position == 'static') {
          element.style.position = 'relative';
        }
        createStyles();
        element.__resizeLast__ = {};
        element.__resizeListeners__ = [];
        (element.__resizeTriggers__ = document.createElement('div')).className = 'resize-triggers';
        element.__resizeTriggers__.innerHTML = '

' +
                                            '

';
        element.appendChild(element.__resizeTriggers__);
        resetTriggers(element);
        element.addEventListener('scroll', scrollListener, true);

        /* Listen for a css animation to detect element display/re-attach */
        if (animationstartevent) {
          element.__resizeTriggers__.__animationListener__ = function animationListener(e) {
            if(e.animationName == animationName)
              resetTriggers(element);
          };
          element.__resizeTriggers__.addEventListener(
            animationstartevent, element.__resizeTriggers__.__animationListener__
          );
        }
      }
      element.__resizeListeners__.push(fn);
    }
  };

  var removeResizeListener = function(element, fn){
    if (attachEvent) element.detachEvent('onresize', fn);
    else {
      element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1);
      if (!element.__resizeListeners__.length) {
          element.removeEventListener('scroll', scrollListener, true);
          if (element.__resizeTriggers__.__animationListener__) {
            element.__resizeTriggers__.removeEventListener(
              animationstartevent, element.__resizeTriggers__.__animationListener__
            );
            element.__resizeTriggers__.__animationListener__ = null;
          }
          element.__resizeTriggers__ = !element.removeChild(element.__resizeTriggers__);
      }
    }
  }

  return {
    addResizeListener,
    removeResizeListener
  };
}
<|endoftext|>