<commit_before>/** @license MIT License (c) Copyright (c) 2014 Julio Makdisse Saito */

/**
 * Mogger
 * Meld + Trace + Colorful logger
 *
 * Licensed under the MIT License at:
 * http://www.opensource.org/licenses/mit-license.php
 *
 * @author Julio Makdisse Saito (saitodisse@gmail.com)
 * @version 0.5.0
 */

(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define(['exports',
            'colorful-logger',
            'meld',
            'traceMeld',
            'lodash'
          ],
          function (
            exports,
            ColorfulLogger,
            meld,
            traceMeld,
            _
    ){
      factory(root, exports, ColorfulLogger, meld, traceMeld, _);
    });
  } else if (typeof exports === 'object') {
    // CommonJS
    var ColorfulLogger = require('colorful-logger');
    var meld = require('meld');
    var traceMeld = require('meld/aspect/trace');
    var _ = require('lodash');
    factory(root, exports, ColorfulLogger, meld, traceMeld, _);
  } else {
    // Browser globals
    factory((root.Mogger = {}), root.ColorfulLogger, root.meld, root.traceMeld, root._);
  }
}(this, function(root, Mogger, ColorfulLogger, meld, traceMeld, _) {

  var globalTimeoutLogId = null;
  var setParentTimeout = function(logger) {
    globalTimeoutLogId = setTimeout(function (){
      logger.log('----------------------------------pause--------------------------');
    }.bind(this), 100);
  };

  /*******************************
    Mogger.Tracer
  *******************************/
  Mogger.Tracer = function (config){
    // global configuration
    config = config || {};
    this.globalConfig = config;
    var getGlobalConfig = function() {
      return this.globalConfig;
    }.bind(this);

    //get logger and send configuration to him
    var logger = config.logger;
    var loggerConfig = config.loggerConfig;
    logger = this.logger = logger || new ColorfulLogger.Logger(loggerConfig);

    //showPause when to much time without any log
    var showPause = config.showPause || false;

    /*
      interceptorsObj:
      {
        globalInterceptors: config.interceptors,
        localInterceptors: options.interceptors,
        info: info
      }
    */
    var checkExistingInterceptors = function(interceptorsObj) {
      var hasLocalInterceptors = !_.isUndefined(interceptorsObj.localInterceptors);
      var hasGlobalInterceptors = !_.isUndefined(interceptorsObj.globalInterceptors);
      return (hasLocalInterceptors || hasGlobalInterceptors);
    };

    var matchInterceptor = function(interceptor, methodName) {
      var filterRegex = interceptor.filterRegex;
      var matchFilterResult = filterRegex.test(methodName);
      if(matchFilterResult){
        return interceptor;
      }
      return false;
    };

    var selectInterceptor = function(interceptor, methodName) {
      // interceptor Array
      if(interceptor && _.isArray(interceptor)){
        for (var i = 0; i < interceptor.length; i++) {
          var interceptorItem = interceptor[i];
          if( matchInterceptor(interceptorItem, methodName) ){
            return interceptorItem;
          }
        }
      }
      // interceptor single obj
      else if(interceptor && !_.isArray(interceptor)){
        return matchInterceptor(interceptor, methodName);
      }

      // no filter match
      return false;
    };

    var applyInterceptor = function(interceptorsObj, interceptor) {
      return interceptor.callback(interceptorsObj.info);
    };

    var checkApplyInterceptors = function(interceptorsObj) {
      if(!checkExistingInterceptors(interceptorsObj)){
        return interceptorsObj.info.method;
      }

      var interceptor = selectInterceptor(interceptorsObj.localInterceptors,  interceptorsObj.info.method);
      if (interceptor === false) {
        interceptor = selectInterceptor(interceptorsObj.globalInterceptors, interceptorsObj.info.method);
      }

      if (interceptor) {
        return applyInterceptor(interceptorsObj, interceptor);
      }
      else {
        return interceptorsObj.info.method;
      }
    };

    var defaults = _.partialRight(_.assign, function(a, b) {
      return typeof a == 'undefined' ? b : a;
    });

    var checkRelevantArguments = function(args) {
      if(args.length === 0){
        return false;
      }

      for (var i = 0; i < args.length; i++) {
        var argument = args[i];

        var isString = _.isString(argument) && argument.length > 0;
        var isNumber = _.isNumber(argument);
        var isBoolean = _.isBoolean(argument);
        var isArray = _.isArray(argument) && argument.length > 0;
        var isEmpty = _.isEmpty(argument);
        var isObject = _.isObject(argument);

        // console.log('<', argument, '>',
        //             '\nisString = ', isString,
        //             '\nisNumber = ', isNumber,
        //             '\nisBoolean = ', isBoolean,
        //             '\nisArray = ', isArray,
        //             '\nisEmpty = ', isEmpty,
        //             '\nisObject = ', isObject
        //             );

        var hasValues = isString || isNumber || isBoolean || isArray || (isObject && !isEmpty);
        if(hasValues){
          return true;
        }
      }
      return false;
    };

    var GetReporter = function (options) {
      this.onCall = function(info) {
        var logs = [],
            targetLog,
            mainMessage = info.method,
            isDisabled = getGlobalConfig().enabled === false || options.enabled === false,
            isIgnored = options.ignorePattern && options.ignorePattern.test(info.method),
            beforeConfig,
            targetConfig,
            interceptorsObj,
            wasModifiedByInterceptor,
            willLogArguments,
            showArguments = !_.isUndefined(options.showArguments) ? options.showArguments : config.showArguments
        ;

        if(isDisabled || isIgnored){
          return false;
        }

        /*
            before (first column / namespace)
        */
        beforeConfig = defaults(options.before, getGlobalConfig().before);
        if(beforeConfig){
          logs.push(beforeConfig);
        }

        /*
            Interceptors
        */
        interceptorsObj = {
          globalInterceptors: config.interceptors,
          localInterceptors: options.interceptors,
          info: info
        };
        mainMessage = checkApplyInterceptors(interceptorsObj);
        wasModifiedByInterceptor = (mainMessage !== info.method);

        /*
            targetConfig local or global
        */
        if(typeof getGlobalConfig().targetConfig !== 'undefined' && typeof options.targetConfig === 'undefined'){
          targetConfig = getGlobalConfig().targetConfig;
        }
        else{
          targetConfig = defaults(options.targetConfig, getGlobalConfig().targetConfig);
        }

        /*
            target (function)
        */
        if(targetConfig){
          targetLog = targetConfig;
          targetLog.message = mainMessage;
        }
        else{
          targetLog = {
            message: mainMessage
          };
        }
        logs.push(targetLog);

        /*
            Function arguments in a groupCollapsed
        */
        willLogArguments = showArguments &&
                           !wasModifiedByInterceptor &&
                           checkRelevantArguments(info.args);

        if(willLogArguments){
          logs[0].logType = 'groupCollapsed';
          logger.log(logs);

          logger.log({
            message: info.args
          });
          logger.log({
            logType: 'groupEnd'
          });
        }
        else{
          logs[0].logType = 'log';
          logger.log(logs);
        }

        /*
            pause
        */
        if(showPause){
          // cancel pause made before
          clearTimeout(globalTimeoutLogId);
          // if is not canceled, it shows the line bellow
          setParentTimeout(logger);
        }

      }.bind(this);

      // other things that can be catch in the future
      //    onReturn:
      //    onThrow:
    };

    this.targets = [];

    // ----------------------------
    // traceObj
    // ----------------------------
    // register one object to be monitored
    // each function will be catched here thanks to AOP meld/aspect/trace
    // ----------------------------
		this.traceObj = function(opt) {
      var reporter = new GetReporter(opt);
      var target = opt.target;

      // gets target real object from surrogateTargets,
      // only if its is an string
      var surrogateTargets = config.surrogateTargets;
      if(surrogateTargets && _.isString(target)){
        target = surrogateTargets[target];
      }

      this.targets.push({
        meldRemover: meld(target, /./, traceMeld(reporter)),
        options: opt
      });
		};

    // ----------------------------
    // removeAllTraces
    // ----------------------------
    // loop over all target and remove them from meld AOP tracer
    // ----------------------------
    this.removeAllTraces = function() {
      this.targets.forEach(function(target) {
        target.meldRemover && target.meldRemover.remove();
      });
    };

	};

  return Mogger;

}));

<commit_msg>fix UMD<commit_after>/** @license MIT License (c) Copyright (c) 2014 Julio Makdisse Saito */

/**
 * Mogger
 * Meld + Trace + Colorful logger
 *
 * Licensed under the MIT License at:
 * http://www.opensource.org/licenses/mit-license.php
 *
 * @author Julio Makdisse Saito (saitodisse@gmail.com)
 * @version 0.5.0
 */

(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define(['exports',
            'colorful-logger',
            'meld',
            'traceMeld',
            'lodash'
          ],
          function (
            exports,
            ColorfulLogger,
            meld,
            traceMeld,
            _
    ){
      factory(root, exports, ColorfulLogger, meld, traceMeld, _);
    });
  } else if (typeof exports === 'object') {
    // CommonJS
    var ColorfulLogger = require('colorful-logger');
    var meld = require('meld');
    var traceMeld = require('meld/aspect/trace');
    var _ = require('lodash');
    factory(root, exports, ColorfulLogger, meld, traceMeld, _);
  } else {
    // Browser globals
    factory(root, (root.Mogger = {}), root.ColorfulLogger, root.meld, root.traceMeld, root._);
  }
}(this, function(root, Mogger, ColorfulLogger, meld, traceMeld, _) {

  var globalTimeoutLogId = null;
  var setParentTimeout = function(logger) {
    globalTimeoutLogId = setTimeout(function (){
      logger.log('----------------------------------pause--------------------------');
    }.bind(this), 100);
  };

  /*******************************
    Mogger.Tracer
  *******************************/
  Mogger.Tracer = function (config){
    // global configuration
    config = config || {};
    this.globalConfig = config;
    var getGlobalConfig = function() {
      return this.globalConfig;
    }.bind(this);

    //get logger and send configuration to him
    var logger = config.logger;
    var loggerConfig = config.loggerConfig;
    logger = this.logger = logger || new ColorfulLogger.Logger(loggerConfig);

    //showPause when to much time without any log
    var showPause = config.showPause || false;

    /*
      interceptorsObj:
      {
        globalInterceptors: config.interceptors,
        localInterceptors: options.interceptors,
        info: info
      }
    */
    var checkExistingInterceptors = function(interceptorsObj) {
      var hasLocalInterceptors = !_.isUndefined(interceptorsObj.localInterceptors);
      var hasGlobalInterceptors = !_.isUndefined(interceptorsObj.globalInterceptors);
      return (hasLocalInterceptors || hasGlobalInterceptors);
    };

    var matchInterceptor = function(interceptor, methodName) {
      var filterRegex = interceptor.filterRegex;
      var matchFilterResult = filterRegex.test(methodName);
      if(matchFilterResult){
        return interceptor;
      }
      return false;
    };

    var selectInterceptor = function(interceptor, methodName) {
      // interceptor Array
      if(interceptor && _.isArray(interceptor)){
        for (var i = 0; i < interceptor.length; i++) {
          var interceptorItem = interceptor[i];
          if( matchInterceptor(interceptorItem, methodName) ){
            return interceptorItem;
          }
        }
      }
      // interceptor single obj
      else if(interceptor && !_.isArray(interceptor)){
        return matchInterceptor(interceptor, methodName);
      }

      // no filter match
      return false;
    };

    var applyInterceptor = function(interceptorsObj, interceptor) {
      return interceptor.callback(interceptorsObj.info);
    };

    var checkApplyInterceptors = function(interceptorsObj) {
      if(!checkExistingInterceptors(interceptorsObj)){
        return interceptorsObj.info.method;
      }

      var interceptor = selectInterceptor(interceptorsObj.localInterceptors,  interceptorsObj.info.method);
      if (interceptor === false) {
        interceptor = selectInterceptor(interceptorsObj.globalInterceptors, interceptorsObj.info.method);
      }

      if (interceptor) {
        return applyInterceptor(interceptorsObj, interceptor);
      }
      else {
        return interceptorsObj.info.method;
      }
    };

    var defaults = _.partialRight(_.assign, function(a, b) {
      return typeof a == 'undefined' ? b : a;
    });

    var checkRelevantArguments = function(args) {
      if(args.length === 0){
        return false;
      }

      for (var i = 0; i < args.length; i++) {
        var argument = args[i];

        var isString = _.isString(argument) && argument.length > 0;
        var isNumber = _.isNumber(argument);
        var isBoolean = _.isBoolean(argument);
        var isArray = _.isArray(argument) && argument.length > 0;
        var isEmpty = _.isEmpty(argument);
        var isObject = _.isObject(argument);

        // console.log('<', argument, '>',
        //             '\nisString = ', isString,
        //             '\nisNumber = ', isNumber,
        //             '\nisBoolean = ', isBoolean,
        //             '\nisArray = ', isArray,
        //             '\nisEmpty = ', isEmpty,
        //             '\nisObject = ', isObject
        //             );

        var hasValues = isString || isNumber || isBoolean || isArray || (isObject && !isEmpty);
        if(hasValues){
          return true;
        }
      }
      return false;
    };

    var GetReporter = function (options) {
      this.onCall = function(info) {
        var logs = [],
            targetLog,
            mainMessage = info.method,
            isDisabled = getGlobalConfig().enabled === false || options.enabled === false,
            isIgnored = options.ignorePattern && options.ignorePattern.test(info.method),
            beforeConfig,
            targetConfig,
            interceptorsObj,
            wasModifiedByInterceptor,
            willLogArguments,
            showArguments = !_.isUndefined(options.showArguments) ? options.showArguments : config.showArguments
        ;

        if(isDisabled || isIgnored){
          return false;
        }

        /*
            before (first column / namespace)
        */
        beforeConfig = defaults(options.before, getGlobalConfig().before);
        if(beforeConfig){
          logs.push(beforeConfig);
        }

        /*
            Interceptors
        */
        interceptorsObj = {
          globalInterceptors: config.interceptors,
          localInterceptors: options.interceptors,
          info: info
        };
        mainMessage = checkApplyInterceptors(interceptorsObj);
        wasModifiedByInterceptor = (mainMessage !== info.method);

        /*
            targetConfig local or global
        */
        if(typeof getGlobalConfig().targetConfig !== 'undefined' && typeof options.targetConfig === 'undefined'){
          targetConfig = getGlobalConfig().targetConfig;
        }
        else{
          targetConfig = defaults(options.targetConfig, getGlobalConfig().targetConfig);
        }

        /*
            target (function)
        */
        if(targetConfig){
          targetLog = targetConfig;
          targetLog.message = mainMessage;
        }
        else{
          targetLog = {
            message: mainMessage
          };
        }
        logs.push(targetLog);

        /*
            Function arguments in a groupCollapsed
        */
        willLogArguments = showArguments &&
                           !wasModifiedByInterceptor &&
                           checkRelevantArguments(info.args);

        if(willLogArguments){
          logs[0].logType = 'groupCollapsed';
          logger.log(logs);

          logger.log({
            message: info.args
          });
          logger.log({
            logType: 'groupEnd'
          });
        }
        else{
          logs[0].logType = 'log';
          logger.log(logs);
        }

        /*
            pause
        */
        if(showPause){
          // cancel pause made before
          clearTimeout(globalTimeoutLogId);
          // if is not canceled, it shows the line bellow
          setParentTimeout(logger);
        }

      }.bind(this);

      // other things that can be catch in the future
      //    onReturn:
      //    onThrow:
    };

    this.targets = [];

    // ----------------------------
    // traceObj
    // ----------------------------
    // register one object to be monitored
    // each function will be catched here thanks to AOP meld/aspect/trace
    // ----------------------------
		this.traceObj = function(opt) {
      var reporter = new GetReporter(opt);
      var target = opt.target;

      // gets target real object from surrogateTargets,
      // only if its is an string
      var surrogateTargets = config.surrogateTargets;
      if(surrogateTargets && _.isString(target)){
        target = surrogateTargets[target];
      }

      this.targets.push({
        meldRemover: meld(target, /./, traceMeld(reporter)),
        options: opt
      });
		};

    // ----------------------------
    // removeAllTraces
    // ----------------------------
    // loop over all target and remove them from meld AOP tracer
    // ----------------------------
    this.removeAllTraces = function() {
      this.targets.forEach(function(target) {
        target.meldRemover && target.meldRemover.remove();
      });
    };

	};

  return Mogger;

}));

<|endoftext|>


<commit_before>'use strict';

var _ = require('lodash');

/**@ngInject*/
var ProjectsResource = function($resource, apiResource) {
  var Project = $resource(apiResource('projectsById'), { id: '@id' }, {
    'update': { method:'PUT' },
    'approve': {
      url: apiResource('projectsById') + '/approve',
      method: 'POST',
      params: {'includes[]': ['approvals', 'approvers']}
    },
    'reject': {
      url: apiResource('projectsById') + '/reject',
      method: 'POST',
      params: {'includes[]': ['approvals', 'approvers']}
    },
    'approvals': {
      url: apiResource('projectsById') + '/approvals',
      method: 'GET',
      isArray: true
    }
  });

  Project.prototype.isApproved = function() {
    return this.approval === 'approved';
  };

  // TODO : Improve this; Dislike combining things this way.
  var finalApproval = _.memoize(function(approvals, approvers) {
    var approval = approvals[approvals.length - 1];
    if (approvers) {
      _.each(approvers, function(approver) {
        if (approver.id == approval.staff_id) {
          approval.staff_name = [approver.first_name, approver.last_name].join(' ');
        }
      });
    }
    return approval;
  });

  Project.prototype.finalApproval = function() {
    if (0 === this.approvals.length) {
      return null;
    }
    return finalApproval(this.approvals, this.approvers);
  };

  return Project;
};

module.exports = ProjectsResource;
<commit_msg>Include default params for query and get calls<commit_after>'use strict';

var _ = require('lodash');

/**@ngInject*/
var ProjectsResource = function($resource, apiResource) {
  var Project = $resource(apiResource('projectsById'), { id: '@id' }, {
    'query': {
      method: 'GET',
      paramDefaults: {
        'methods[]': ['domain', 'url', 'problem_count', 'account_number', 'resources', 'resources_unit', 'cpu', 'hdd', 'ram', 'status', 'monthly_spend']
      },
      isArray: true
    },
    'get': {
      method: 'GET',
      paramDefaults: {
        'methods[]': ['domain', 'url', 'problem_count', 'account_number', 'resources', 'resources_unit', 'cpu', 'hdd', 'ram', 'status', 'monthly_spend', 'order_history']
      },
      isArray: false
    },
    'update': { method:'PUT' },
    'approve': {
      url: apiResource('projectsById') + '/approve',
      method: 'POST',
      params: {'includes[]': ['approvals', 'approvers']}
    },
    'reject': {
      url: apiResource('projectsById') + '/reject',
      method: 'POST',
      params: {'includes[]': ['approvals', 'approvers']}
    },
    'approvals': {
      url: apiResource('projectsById') + '/approvals',
      method: 'GET',
      isArray: true
    }
  });

  Project.prototype.isApproved = function() {
    return this.approval === 'approved';
  };

  // TODO : Improve this; Dislike combining things this way.
  var finalApproval = _.memoize(function(approvals, approvers) {
    var approval = approvals[approvals.length - 1];
    if (approvers) {
      _.each(approvers, function(approver) {
        if (approver.id == approval.staff_id) {
          approval.staff_name = [approver.first_name, approver.last_name].join(' ');
        }
      });
    }
    return approval;
  });

  Project.prototype.finalApproval = function() {
    if (0 === this.approvals.length) {
      return null;
    }
    return finalApproval(this.approvals, this.approvers);
  };

  return Project;
};

module.exports = ProjectsResource;
<|endoftext|>


<commit_before>/*
 * Copyright 2020 Google LLC
 *
 * 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
 *
 *     https://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.
 */

/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';

/**
 * External dependencies
 */
import { useCallback, useMemo, useReducer } from 'react';
import moment from 'moment';
import queryString from 'query-string';

/**
 * Internal dependencies
 */

import {
  STORY_STATUSES,
  STORY_SORT_OPTIONS,
  ORDER_BY_SORT,
  ITEMS_PER_PAGE,
} from '../../constants';
import storyReducer, {
  defaultStoriesState,
  ACTION_TYPES as STORY_ACTION_TYPES,
} from '../reducer/stories';

export function reshapeStoryObject(editStoryURL) {
  return function (originalStoryData) {
    const {
      id,
      title,
      modified,
      status,
      date,
      author,
      story_data: storyData,
    } = originalStoryData;
    if (
      !Array.isArray(storyData.pages) ||
      !id ||
      storyData.pages.length === 0
    ) {
      return null;
    }
    return {
      id,
      status,
      title: title.raw,
      modified: moment(modified),
      created: moment(date),
      pages: storyData.pages,
      author,
      centerTargetAction: '',
      bottomTargetAction: `${editStoryURL}&post=${id}`,
      originalStoryData,
    };
  };
}

const useStoryApi = (dataAdapter, { editStoryURL, wpApi }) => {
  const [state, dispatch] = useReducer(storyReducer, defaultStoriesState);

  const fetchStories = useCallback(
    async ({
      status = STORY_STATUSES[0].value,
      sortOption = STORY_SORT_OPTIONS.LAST_MODIFIED,
      sortDirection,
      searchTerm,
      page = 1,
      perPage = ITEMS_PER_PAGE,
    }) => {
      dispatch({
        type: STORY_ACTION_TYPES.LOADING_STORIES,
        payload: true,
      });

      if (!wpApi) {
        dispatch({
          type: STORY_ACTION_TYPES.FETCH_STORIES_FAILURE,
          payload: true,
        });
        return;
      }

      const query = {
        context: 'edit',
        search: searchTerm || undefined,
        orderby: sortOption,
        page,
        per_page: perPage,
        order: sortDirection || ORDER_BY_SORT[sortOption],
        status,
      };

      try {
        const path = queryString.stringifyUrl({
          url: wpApi,
          query,
        });

        const response = await dataAdapter.get(path, {
          parse: false,
        });

        const totalPages =
          response.headers && parseInt(response.headers.get('X-WP-TotalPages'));

        const totalStoriesByStatus =
          response.headers &&
          JSON.parse(response.headers.get('X-WP-TotalByStatus'));

        const serverStoryResponse = await response.json();

        const reshapedStories = serverStoryResponse
          .map(reshapeStoryObject(editStoryURL))
          .filter(Boolean);

        dispatch({
          type: STORY_ACTION_TYPES.FETCH_STORIES_SUCCESS,
          payload: {
            stories: reshapedStories,
            totalPages,
            totalStoriesByStatus,
            page,
          },
        });
      } catch (err) {
        dispatch({
          type: STORY_ACTION_TYPES.FETCH_STORIES_FAILURE,
          payload: true,
        });
      } finally {
        dispatch({
          type: STORY_ACTION_TYPES.LOADING_STORIES,
          payload: false,
        });
      }
    },
    [wpApi, dataAdapter, editStoryURL]
  );

  const updateStory = useCallback(
    async (story) => {
      try {
        const response = await dataAdapter.post(`${wpApi}/${story.id}`, {
          data: story,
        });
        dispatch({
          type: STORY_ACTION_TYPES.UPDATE_STORY,
          payload: reshapeStoryObject(editStoryURL)(response),
        });
      } catch (e) {
        // eslint-disable-next-line no-console
        console.error(e);
      }
    },
    [wpApi, dataAdapter, editStoryURL]
  );

  const trashStory = useCallback(
    async (story) => {
      try {
        await dataAdapter.deleteRequest(`${wpApi}/${story.id}`, {
          data: story,
        });
        dispatch({
          type: STORY_ACTION_TYPES.TRASH_STORY,
          payload: { id: story.id, storyStatus: story.status },
        });
      } catch (e) {
        // eslint-disable-next-line no-console
        console.error(e);
      }
    },
    [wpApi, dataAdapter]
  );

  const duplicateStory = useCallback(
    async (story) => {
      try {
        const {
          content,
          story_data,
          style_presets,
          publisher_logo,
          featured_media,
          title,
        } = story.originalStoryData;
        const response = await dataAdapter.post(wpApi, {
          data: {
            content,
            story_data,
            featured_media,
            style_presets,
            publisher_logo,
            title: {
              raw: `${title.raw} ${__('(Copy)', 'web-stories')}`,
            },
            status: 'draft',
          },
        });
        dispatch({
          type: STORY_ACTION_TYPES.DUPLICATE_STORY,
          payload: reshapeStoryObject(editStoryURL)(response),
        });
      } catch (e) {
        // eslint-disable-next-line no-console
        console.error(e);
      }
    },
    [wpApi, dataAdapter, editStoryURL]
  );

  const api = useMemo(
    () => ({
      updateStory,
      fetchStories,
      trashStory,
      duplicateStory,
    }),
    [duplicateStory, trashStory, updateStory, fetchStories]
  );

  return { stories: state, api };
};

export default useStoryApi;
<commit_msg>set cache to no-cache for fetchStories<commit_after>/*
 * Copyright 2020 Google LLC
 *
 * 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
 *
 *     https://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.
 */

/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';

/**
 * External dependencies
 */
import { useCallback, useMemo, useReducer } from 'react';
import moment from 'moment';
import queryString from 'query-string';

/**
 * Internal dependencies
 */

import {
  STORY_STATUSES,
  STORY_SORT_OPTIONS,
  ORDER_BY_SORT,
  ITEMS_PER_PAGE,
} from '../../constants';
import storyReducer, {
  defaultStoriesState,
  ACTION_TYPES as STORY_ACTION_TYPES,
} from '../reducer/stories';

export function reshapeStoryObject(editStoryURL) {
  return function (originalStoryData) {
    const {
      id,
      title,
      modified,
      status,
      date,
      author,
      story_data: storyData,
    } = originalStoryData;
    if (
      !Array.isArray(storyData.pages) ||
      !id ||
      storyData.pages.length === 0
    ) {
      return null;
    }
    return {
      id,
      status,
      title: title.raw,
      modified: moment(modified),
      created: moment(date),
      pages: storyData.pages,
      author,
      centerTargetAction: '',
      bottomTargetAction: `${editStoryURL}&post=${id}`,
      originalStoryData,
    };
  };
}

const useStoryApi = (dataAdapter, { editStoryURL, wpApi }) => {
  const [state, dispatch] = useReducer(storyReducer, defaultStoriesState);

  const fetchStories = useCallback(
    async ({
      status = STORY_STATUSES[0].value,
      sortOption = STORY_SORT_OPTIONS.LAST_MODIFIED,
      sortDirection,
      searchTerm,
      page = 1,
      perPage = ITEMS_PER_PAGE,
    }) => {
      dispatch({
        type: STORY_ACTION_TYPES.LOADING_STORIES,
        payload: true,
      });

      if (!wpApi) {
        dispatch({
          type: STORY_ACTION_TYPES.FETCH_STORIES_FAILURE,
          payload: true,
        });
        return;
      }

      const query = {
        context: 'edit',
        search: searchTerm || undefined,
        orderby: sortOption,
        page,
        per_page: perPage,
        order: sortDirection || ORDER_BY_SORT[sortOption],
        status,
      };

      try {
        const path = queryString.stringifyUrl({
          url: wpApi,
          query,
        });

        const response = await dataAdapter.get(path, {
          parse: false,
          cache: 'no-cache',
        });

        const totalPages =
          response.headers && parseInt(response.headers.get('X-WP-TotalPages'));

        const totalStoriesByStatus =
          response.headers &&
          JSON.parse(response.headers.get('X-WP-TotalByStatus'));

        const serverStoryResponse = await response.json();

        const reshapedStories = serverStoryResponse
          .map(reshapeStoryObject(editStoryURL))
          .filter(Boolean);

        dispatch({
          type: STORY_ACTION_TYPES.FETCH_STORIES_SUCCESS,
          payload: {
            stories: reshapedStories,
            totalPages,
            totalStoriesByStatus,
            page,
          },
        });
      } catch (err) {
        dispatch({
          type: STORY_ACTION_TYPES.FETCH_STORIES_FAILURE,
          payload: true,
        });
      } finally {
        dispatch({
          type: STORY_ACTION_TYPES.LOADING_STORIES,
          payload: false,
        });
      }
    },
    [wpApi, dataAdapter, editStoryURL]
  );

  const updateStory = useCallback(
    async (story) => {
      try {
        const response = await dataAdapter.post(`${wpApi}/${story.id}`, {
          data: story,
        });
        dispatch({
          type: STORY_ACTION_TYPES.UPDATE_STORY,
          payload: reshapeStoryObject(editStoryURL)(response),
        });
      } catch (e) {
        // eslint-disable-next-line no-console
        console.error(e);
      }
    },
    [wpApi, dataAdapter, editStoryURL]
  );

  const trashStory = useCallback(
    async (story) => {
      try {
        await dataAdapter.deleteRequest(`${wpApi}/${story.id}`, {
          data: story,
        });
        dispatch({
          type: STORY_ACTION_TYPES.TRASH_STORY,
          payload: { id: story.id, storyStatus: story.status },
        });
      } catch (e) {
        // eslint-disable-next-line no-console
        console.error(e);
      }
    },
    [wpApi, dataAdapter]
  );

  const duplicateStory = useCallback(
    async (story) => {
      try {
        const {
          content,
          story_data,
          style_presets,
          publisher_logo,
          featured_media,
          title,
        } = story.originalStoryData;
        const response = await dataAdapter.post(wpApi, {
          data: {
            content,
            story_data,
            featured_media,
            style_presets,
            publisher_logo,
            title: {
              raw: `${title.raw} ${__('(Copy)', 'web-stories')}`,
            },
            status: 'draft',
          },
        });
        dispatch({
          type: STORY_ACTION_TYPES.DUPLICATE_STORY,
          payload: reshapeStoryObject(editStoryURL)(response),
        });
      } catch (e) {
        // eslint-disable-next-line no-console
        console.error(e);
      }
    },
    [wpApi, dataAdapter, editStoryURL]
  );

  const api = useMemo(
    () => ({
      updateStory,
      fetchStories,
      trashStory,
      duplicateStory,
    }),
    [duplicateStory, trashStory, updateStory, fetchStories]
  );

  return { stories: state, api };
};

export default useStoryApi;
<|endoftext|>


<commit_before>
import {getValue} from '../lib/helpers';

export default function createPlayer(setName) {
  setName('lowestSingle');

  return function lowestSingle(isPlaying, state) {
    if (isPlaying) {
      state.hand.sort(function (a, b) {
        return parseInt(a) < parseInt(b);
      });
      return lowestValidSingle(state.hand, state.table);
    }
  };
}

function lowestValidSingle(hand, table) {
  var play = hand.pop();
  if (getValue(play) >= getValue(table)) {
    return play;
  } else if (hand.length > 0) {
    return lowestValidSingle(hand, table);
  } else {
    return false;
  }
}
<commit_msg>testing a strategy that plays high<commit_after>
// import {getValue} from '../lib/helpers';

export default function createPlayer(setName) {
  setName('lowestSingle');

  return function highestValid(isPlaying, state) {
    if (isPlaying) {
      var plays = state.getUniqueValidPlays();
      return plays[plays.length - 1];
    }
  };
}
<|endoftext|>


<commit_before>/**
 * Groups preferences together and displays them in a manner to reflect that fact.
 */
import Preference from './Preference';
import {createEl, qs} from './utils';
import template from '!!raw-loader!./templates/PreferenceGroup.html';

export default class PreferenceGroup extends Preference {

  /**
   *
   * @param name {String} The name to be used as prefix for all keys of the preferences
   *                e.g windowOptions --> preferences will be windowOptions.optionX
   * @param label {String} The title to be shown to the user
   * @param description {String} The description to be shown to the user
   * @param preferences {Preference[]}
   * @param toggleable {boolean} Indicates whether the preferences
   *                    can be toggled together
   */
  constructor({name, label, description, preferences, toggleable = false}) {
    super({name, label, description});
    for (let preference of preferences) {
      if (!preference.name.startsWith(`${name}.`)) {
        throw `Preference names must start with ${name}`;
      }
    }
    this._preferences = preferences;
    this._toggleable = toggleable;
    if(this._toggleable){
      this.$container.classList.add('pref-group_toggable');
    }
  }

  _buildContainerEl() {
    return createEl(template);
  }

  _buildEl() {
    return this.$container.querySelector(`.${PreferenceGroup.EL_CLASS}`);
  }

  async fillContainer() {
    qs('.pref-group__label', this.$container).innerHTML = this.label;
    qs('.pref-group__description', this.$container).innerHTML = this.description;

    const $preferences = this.$container.querySelector('.preferences');
    return Promise.all(this._preferences.map((preference) => {
      $preferences.appendChild(preference.$container);
      return preference.fillContainer();
    }));
  }

  get() {
    return this._toggleable ?
        this.el.checked
        : false;
  }

  set({value}) {
    if (this._toggleable) {
      this.el.checked = value;
    }
  }

  async updateFromDb() {
    super.updateFromDb();
    return Promise.all(this._preferences.map((preference) => preference.updateFromDb()));
  }

  update() {
    return Promise.all([super.update()].concat(
        this._preferences.map((preference) => preference.update())
    ));

  }
}

PreferenceGroup.TYPE = 'group';
PreferenceGroup.EL_CLASS = 'pref-group__toggle';
<commit_msg>Improve doc a little<commit_after>/**
 * Groups preferences together and displays them in a manner to reflect that fact.
 */
import Preference from './Preference';
import {createEl, qs} from './utils';
import template from '!!raw-loader!./templates/PreferenceGroup.html';

export default class PreferenceGroup extends Preference {

  /**
   *
   * @param name {String} The name to be used as prefix for all keys of the preferences
   *                e.g windowOptions --> preferences will be windowOptions.optionX
   * @param label {String} The title to be shown to the user
   * @param description {String} The description to be shown to the user
   * @param preferences {Preference[]}
   * @param toggleable {boolean} Indicates whether the preferences
   *                    can be toggled on and off together
   */
  constructor({name, label, description, preferences, toggleable = false}) {
    super({name, label, description});
    for (let preference of preferences) {
      if (!preference.name.startsWith(`${name}.`)) {
        throw `Preference names must start with ${name}`;
      }
    }
    this._preferences = preferences;
    this._toggleable = toggleable;
    if(this._toggleable){
      this.$container.classList.add('pref-group_toggable');
    }
  }

  _buildContainerEl() {
    return createEl(template);
  }

  _buildEl() {
    return this.$container.querySelector(`.${PreferenceGroup.EL_CLASS}`);
  }

  async fillContainer() {
    qs('.pref-group__label', this.$container).innerHTML = this.label;
    qs('.pref-group__description', this.$container).innerHTML = this.description;

    const $preferences = this.$container.querySelector('.preferences');
    return Promise.all(this._preferences.map((preference) => {
      $preferences.appendChild(preference.$container);
      return preference.fillContainer();
    }));
  }

  get() {
    return this._toggleable ?
        this.el.checked
        : false;
  }

  set({value}) {
    if (this._toggleable) {
      this.el.checked = value;
    }
  }

  async updateFromDb() {
    super.updateFromDb();
    return Promise.all(this._preferences.map((preference) => preference.updateFromDb()));
  }

  update() {
    return Promise.all([super.update()].concat(
        this._preferences.map((preference) => preference.update())
    ));

  }
}

PreferenceGroup.TYPE = 'group';
PreferenceGroup.EL_CLASS = 'pref-group__toggle';
<|endoftext|>


<commit_before>import React, { PureComponent } from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'
import OutsideClickHandler from 'react-outside-click-handler'
import styled from 'styled-components'
import {
  position,
  top,
  right,
  bottom,
  left,
  width,
  height,
} from 'styled-system'
import { debounce } from 'underscore'

import { preset } from 'v2/styles/functions'

import compactObject from 'v2/util/compactObject'

const Background = styled.div`
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: ${x => x.theme.z.modal};
  pointer-events: none;
`

const TargetOverlay = styled.div`
  position: fixed;
  ${top}
  ${right}
  ${bottom}
  ${left}
  ${width}
  ${height}
`

const Wrapper = styled.div`
  box-sizing: border-box;
  ${preset(position, { position: 'absolute' })}
  ${top}
  ${right}
  ${bottom}
  ${left}
  ${width}
  ${height}
  pointer-events: all;
`

export default class Overlay extends PureComponent {
  static propTypes = {
    children: PropTypes.node.isRequired,
    onClose: PropTypes.func,
    targetEl: PropTypes.func.isRequired,
    anchorY: PropTypes.oneOf(['top', 'bottom']),
    anchorX: PropTypes.oneOf(['left', 'right']),
    alignToY: PropTypes.oneOf(['top', 'bottom']),
    alignToX: PropTypes.oneOf(['left', 'right']),
    offsetX: PropTypes.number,
    offsetY: PropTypes.number,
    marginY: PropTypes.number,
    fullWidth: PropTypes.bool,
    disableTarget: PropTypes.bool, // Useful for toggling UI
  }

  static defaultProps = {
    onClose: () => {},
    anchorY: 'top',
    anchorX: 'left',
    alignToY: 'bottom',
    alignToX: 'left',
    offsetX: 0,
    offsetY: 0,
    marginY: 10,
    fullWidth: false,
    disableTarget: false,
  }

  constructor(props) {
    super(props)

    this.el = document.createElement('div')
  }

  state = {
    top: null,
    right: null,
    bottom: null,
    left: null,
    width: null,
    height: null,
    targetOverlay: null,
  }

  componentDidMount() {
    const { targetEl, disableTarget } = this.props

    document.body.appendChild(this.el)

    this.positionOverlay = () => {
      this.alignToEl(targetEl())

      if (disableTarget) {
        this.overlayTarget()
      }
    }

    this.debouncedPositionOverlay = debounce(this.positionOverlay, 100)

    window.addEventListener('resize', this.debouncedPositionOverlay)
    document.body.addEventListener('mousewheel', this.debouncedPositionOverlay)

    this.positionOverlay()

    // Re-position the overlay if anything in the subtree changes
    this.observer = new MutationObserver(this.positionOverlay)
    this.observer.observe(this.wrapper, { childList: true, subtree: true })
  }

  componentWillUnmount() {
    this.el.parentNode.removeChild(this.el)

    window.removeEventListener('resize', this.debouncedPositionOverlay)
    document.body.removeEventListener(
      'mousewheel',
      this.debouncedPositionOverlay
    )

    this.observer.disconnect()
  }

  overlayTarget = () => {
    const { targetEl } = this.props
    console.log('target', targetEl, this.props)
    const { top, left, width, height } = targetEl().getBoundingClientRect()

    this.setState({
      targetOverlay: { top, left, width, height },
    })
  }

  alignToEl = el => {
    const {
      anchorY,
      anchorX,
      alignToY,
      alignToX,
      offsetY,
      offsetX,
      fullWidth,
      marginY,
    } = this.props

    console.log({
      anchorY,
      anchorX,
      alignToY,
      alignToX,
      offsetY,
      offsetX,
      fullWidth,
      marginY,
      el,
    })

    const {
      [alignToY]: y,
      [alignToX]: x,
      width: elWidth,
    } = el.getBoundingClientRect()

    const positions = {
      top: y,
      bottom: window.innerHeight - y,
      left: x,
      right: window.innerWidth - x,
    }

    const positionState = {
      [anchorY]: positions[anchorY] + offsetY,
      [anchorX]: positions[anchorX] + offsetX,
    }

    if (fullWidth) {
      positionState.width = elWidth
    }

    // Moves into position
    this.setState(positionState, () => {
      // Then handle overflowing calculations
      const {
        bottom: bottomEdge,
        top: topEdge,
        height: wrapperHeight,
      } = this.wrapper.getBoundingClientRect()

      const computedTopEdge = topEdge - marginY
      const computedBottomEdge = bottomEdge + marginY

      const isOverflowingViewportTop =
        anchorY === 'bottom' && computedTopEdge <= 0
      const isOverflowingViewportBottom =
        anchorY === 'top' && computedBottomEdge >= window.innerHeight

      if (isOverflowingViewportTop) {
        return this.setState({ height: wrapperHeight + computedTopEdge })
      }

      if (isOverflowingViewportBottom) {
        const bottomDifference = window.innerHeight - computedBottomEdge
        return this.setState({ height: wrapperHeight + bottomDifference })
      }

      if (this.state.height) {
        return this.setState({ height: null })
      }

      return null
    })
  }

  render() {
    const { targetOverlay, ...state } = this.state
    const { children, onClose, disableTarget, ...rest } = this.props

    return ReactDOM.createPortal(
      <Background>
        <OutsideClickHandler onOutsideClick={onClose}>
          <Wrapper
            {...compactObject(state)}
            {...rest}
            ref={el => {
              this.wrapper = el
            }}
          >
            {disableTarget && (
              <TargetOverlay {...targetOverlay} onClick={onClose} />
            )}

            {children}
          </Wrapper>
        </OutsideClickHandler>
      </Background>,
      this.el
    )
  }
}
<commit_msg>Remove console<commit_after>import React, { PureComponent } from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'
import OutsideClickHandler from 'react-outside-click-handler'
import styled from 'styled-components'
import {
  position,
  top,
  right,
  bottom,
  left,
  width,
  height,
} from 'styled-system'
import { debounce } from 'underscore'

import { preset } from 'v2/styles/functions'

import compactObject from 'v2/util/compactObject'

const Background = styled.div`
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: ${x => x.theme.z.modal};
  pointer-events: none;
`

const TargetOverlay = styled.div`
  position: fixed;
  ${top}
  ${right}
  ${bottom}
  ${left}
  ${width}
  ${height}
`

const Wrapper = styled.div`
  box-sizing: border-box;
  ${preset(position, { position: 'absolute' })}
  ${top}
  ${right}
  ${bottom}
  ${left}
  ${width}
  ${height}
  pointer-events: all;
`

export default class Overlay extends PureComponent {
  static propTypes = {
    children: PropTypes.node.isRequired,
    onClose: PropTypes.func,
    targetEl: PropTypes.func.isRequired,
    anchorY: PropTypes.oneOf(['top', 'bottom']),
    anchorX: PropTypes.oneOf(['left', 'right']),
    alignToY: PropTypes.oneOf(['top', 'bottom']),
    alignToX: PropTypes.oneOf(['left', 'right']),
    offsetX: PropTypes.number,
    offsetY: PropTypes.number,
    marginY: PropTypes.number,
    fullWidth: PropTypes.bool,
    disableTarget: PropTypes.bool, // Useful for toggling UI
  }

  static defaultProps = {
    onClose: () => {},
    anchorY: 'top',
    anchorX: 'left',
    alignToY: 'bottom',
    alignToX: 'left',
    offsetX: 0,
    offsetY: 0,
    marginY: 10,
    fullWidth: false,
    disableTarget: false,
  }

  constructor(props) {
    super(props)

    this.el = document.createElement('div')
  }

  state = {
    top: null,
    right: null,
    bottom: null,
    left: null,
    width: null,
    height: null,
    targetOverlay: null,
  }

  componentDidMount() {
    const { targetEl, disableTarget } = this.props

    document.body.appendChild(this.el)

    this.positionOverlay = () => {
      this.alignToEl(targetEl())

      if (disableTarget) {
        this.overlayTarget()
      }
    }

    this.debouncedPositionOverlay = debounce(this.positionOverlay, 100)

    window.addEventListener('resize', this.debouncedPositionOverlay)
    document.body.addEventListener('mousewheel', this.debouncedPositionOverlay)

    this.positionOverlay()

    // Re-position the overlay if anything in the subtree changes
    this.observer = new MutationObserver(this.positionOverlay)
    this.observer.observe(this.wrapper, { childList: true, subtree: true })
  }

  componentWillUnmount() {
    this.el.parentNode.removeChild(this.el)

    window.removeEventListener('resize', this.debouncedPositionOverlay)
    document.body.removeEventListener(
      'mousewheel',
      this.debouncedPositionOverlay
    )

    this.observer.disconnect()
  }

  overlayTarget = () => {
    const { targetEl } = this.props
    console.log('target', targetEl, this.props)
    const { top, left, width, height } = targetEl().getBoundingClientRect()

    this.setState({
      targetOverlay: { top, left, width, height },
    })
  }

  alignToEl = el => {
    const {
      anchorY,
      anchorX,
      alignToY,
      alignToX,
      offsetY,
      offsetX,
      fullWidth,
      marginY,
    } = this.props

    const {
      [alignToY]: y,
      [alignToX]: x,
      width: elWidth,
    } = el.getBoundingClientRect()

    const positions = {
      top: y,
      bottom: window.innerHeight - y,
      left: x,
      right: window.innerWidth - x,
    }

    const positionState = {
      [anchorY]: positions[anchorY] + offsetY,
      [anchorX]: positions[anchorX] + offsetX,
    }

    if (fullWidth) {
      positionState.width = elWidth
    }

    // Moves into position
    this.setState(positionState, () => {
      // Then handle overflowing calculations
      const {
        bottom: bottomEdge,
        top: topEdge,
        height: wrapperHeight,
      } = this.wrapper.getBoundingClientRect()

      const computedTopEdge = topEdge - marginY
      const computedBottomEdge = bottomEdge + marginY

      const isOverflowingViewportTop =
        anchorY === 'bottom' && computedTopEdge <= 0
      const isOverflowingViewportBottom =
        anchorY === 'top' && computedBottomEdge >= window.innerHeight

      if (isOverflowingViewportTop) {
        return this.setState({ height: wrapperHeight + computedTopEdge })
      }

      if (isOverflowingViewportBottom) {
        const bottomDifference = window.innerHeight - computedBottomEdge
        return this.setState({ height: wrapperHeight + bottomDifference })
      }

      if (this.state.height) {
        return this.setState({ height: null })
      }

      return null
    })
  }

  render() {
    const { targetOverlay, ...state } = this.state
    const { children, onClose, disableTarget, ...rest } = this.props

    return ReactDOM.createPortal(
      <Background>
        <OutsideClickHandler onOutsideClick={onClose}>
          <Wrapper
            {...compactObject(state)}
            {...rest}
            ref={el => {
              this.wrapper = el
            }}
          >
            {disableTarget && (
              <TargetOverlay {...targetOverlay} onClick={onClose} />
            )}

            {children}
          </Wrapper>
        </OutsideClickHandler>
      </Background>,
      this.el
    )
  }
}
<|endoftext|>


<commit_before>import React from 'react';
import noTextChildNodes from './noTextChildNodes';
import possibleStandardNames from './possibleStandardNames';

const hyphen2CamelCase = (str) =>  str.replace(/-([a-z])/gi,(s, group) =>  group.toUpperCase());
const style2object = (styleString) => styleString.split(';').filter(s => s.length).reduce((a, b) => {
  const keyValue = b.split(':');
  a[hyphen2CamelCase(keyValue[0])] = keyValue[1];
  return a;
}, {});

const poorlyNamedAttributes = {
  "tabindex" : "tabIndex",
  "accesskey" : "accessKey",
  "autocomplete" : "autoComplete",
  "text-anchor" : "textAnchor",
  "datetime" : "dateTime",
  "colspan" : "colSpan" ,
  "rowspan" : "rowSpan" ,
  "for" : "htmlFor",
};

class Dom2React {

  constructor(tests) {
    this.tests = tests || [];
  }

  prepareChildren(childNodeList, level) {
    const children = Array.prototype.slice.call(childNodeList).map((node, index) =>
      this.prepareNode(node, level + 1, index)
    ).filter(Boolean);
    if (!children.length) return null;
    return children;
  }

  prepareAttributes(node, reactKey) {
    const attributes = {
      key: reactKey,
    };

    const nodeClassNames = node.getAttribute('class');
    if (nodeClassNames) {
      attributes.className = nodeClassNames;
    }

    Array.prototype.slice.call(node.attributes).map((att) => {
      switch (att.name) {
        //these are manually handled above, so break;
        case 'class':
        case 'style':
          break;
        case 'checked':
        case 'selected':
        case 'disabled':
        case 'autoplay':
        case 'controls':
          attributes[att.name] = att.name;
          break;
        default:
          if (possibleStandardNames[att.name]) {
            attributes[possibleStandardNames[att.name]] = att.value;
          } else {
            attributes[att.name] = att.value;
          }
      }
      return null;
    });
    return attributes;
  }

  prepareNode(_node, level = 0, index = 0) {
    if (!_node) return null;
    let node = _node;
    const key = `${level}-${index}`;
    const result = [];

    this.tests.forEach((test) => {
      if (test.condition(node, key, level, this)) {
        if (typeof test.modify === 'function') {
          node = test.modify(node, key, level, this);
          if (!(node instanceof Node)) {
            node = _node;
            console.warn('The `modify`-method always must return a valid DomNode (instanceof Node) - your modification will be ignored (Hint: if you want to render a React-component, use the `action`-method instead)');
          }
        }
        if (typeof test.action === 'function') {
          result.push(test.action(node, key, level, this));
        }
      }
    });

    if (result.length) return result;

    switch (node.nodeType) {
      case 1: // regular dom-node
        return React.createElement(
          node.nodeName.toLowerCase(),
          this.prepareAttributes(node, key),
          this.prepareChildren(node.childNodes, level)
        );

      case 3: // textnode
        const nodeText = node.nodeValue.toString();

        if (!node.parentNode) {
          return nodeText;
        }

        const parentNodeName = node.parentNode.nodeName.toLowerCase();

        if (noTextChildNodes.indexOf(parentNodeName) !== -1) {
          if (/\S/.test(nodeText)) {
            console.warn(`a textnode is not allowed inside '${parentNodeName}'. your text "${nodeText}" will be ignored`);
          }
          return null;
        }

        return nodeText;

      case 8: // html-comment
        // console.info(node.nodeValue.toString());
        return null;

      default:
        // console.warn(`unhandled nodetype ${node.nodeType}`);
        return null;
    }
  }

}

export default Dom2React;
<commit_msg>removed unneeded code from last merge<commit_after>import React from 'react';
import noTextChildNodes from './noTextChildNodes';
import possibleStandardNames from './possibleStandardNames';

class Dom2React {

  constructor(tests) {
    this.tests = tests || [];
  }

  prepareChildren(childNodeList, level) {
    const children = Array.prototype.slice.call(childNodeList).map((node, index) =>
      this.prepareNode(node, level + 1, index)
    ).filter(Boolean);
    if (!children.length) return null;
    return children;
  }

  prepareAttributes(node, reactKey) {
    const attributes = {
      key: reactKey,
    };

    const nodeClassNames = node.getAttribute('class');
    if (nodeClassNames) {
      attributes.className = nodeClassNames;
    }

    Array.prototype.slice.call(node.attributes).map((att) => {
      switch (att.name) {
        //these are manually handled above, so break;
        case 'class':
        case 'style':
          break;
        case 'checked':
        case 'selected':
        case 'disabled':
        case 'autoplay':
        case 'controls':
          attributes[att.name] = att.name;
          break;
        default:
          if (possibleStandardNames[att.name]) {
            attributes[possibleStandardNames[att.name]] = att.value;
          } else {
            attributes[att.name] = att.value;
          }
      }
      return null;
    });
    return attributes;
  }

  prepareNode(_node, level = 0, index = 0) {
    if (!_node) return null;
    let node = _node;
    const key = `${level}-${index}`;
    const result = [];

    this.tests.forEach((test) => {
      if (test.condition(node, key, level, this)) {
        if (typeof test.modify === 'function') {
          node = test.modify(node, key, level, this);
          if (!(node instanceof Node)) {
            node = _node;
            console.warn('The `modify`-method always must return a valid DomNode (instanceof Node) - your modification will be ignored (Hint: if you want to render a React-component, use the `action`-method instead)');
          }
        }
        if (typeof test.action === 'function') {
          result.push(test.action(node, key, level, this));
        }
      }
    });

    if (result.length) return result;

    switch (node.nodeType) {
      case 1: // regular dom-node
        return React.createElement(
          node.nodeName.toLowerCase(),
          this.prepareAttributes(node, key),
          this.prepareChildren(node.childNodes, level)
        );

      case 3: // textnode
        const nodeText = node.nodeValue.toString();

        if (!node.parentNode) {
          return nodeText;
        }

        const parentNodeName = node.parentNode.nodeName.toLowerCase();

        if (noTextChildNodes.indexOf(parentNodeName) !== -1) {
          if (/\S/.test(nodeText)) {
            console.warn(`a textnode is not allowed inside '${parentNodeName}'. your text "${nodeText}" will be ignored`);
          }
          return null;
        }

        return nodeText;

      case 8: // html-comment
        // console.info(node.nodeValue.toString());
        return null;

      default:
        // console.warn(`unhandled nodetype ${node.nodeType}`);
        return null;
    }
  }

}

export default Dom2React;
<|endoftext|>


<commit_before>/**
 * This module provides the artificial events bubbling feature
 *
 * Copyright (C) 2010 Nikolay Nemshilov
 */

// patching the Element's 'fire' method again
// to make it to bypass the event to its parent
Element[PROTO].fire = patch_function(
  Element_observer.fire,
  /(\w+)(\s*=\s*\w+\.shift[\s\S]+)(return this)/m,
  '$1$2var p=!$1.stopped&&this.parent&&this.parent();p&&p.fire($1);$3'
);

/**
 * Triggers a manual focus/blur events bubbling
 *
 * @param raw dom-event
 * @return void
 */
function focus_boobler(event) {
  var target = $(event.target || event.srcElement),
      parent = target.parent && target.parent();

  parent && parent.fire(
    (event.type === 'focusin' || event.type == 'focus') ?
    'focus' : 'blur', Object.without(event, 'type')
  );
};

/**
 * Hooking up the 'focus' and 'blur' events
 * at the document level and then rebooble them
 * manually like they were normal events
 *
 */
if (Browser.IE) {
  document[ADD_EVENT_METHOD]('onfocusin',  focus_boobler);
  document[ADD_EVENT_METHOD]('onfocusout', focus_boobler);
} else {
  document[ADD_EVENT_METHOD]('focus', focus_boobler, true);
  document[ADD_EVENT_METHOD]('blur',  focus_boobler, true);
}

/**
 * Tests if there is the event support
 *
 * @param String event name
 * @retrun Boolean check result
 */
function event_support_for(name) {
  var e = $E('div')._;
  e.setAttribute(name, ';');
  return isFunction(e[name]);
};

if (!event_support_for('onsubmit')) {
  /**
   * Emulates the 'submit' event bubbling for IE browsers
   *
   * @param raw dom-event
   * @return void
   */
  function submit_boobler(raw_event) {
    var event = $(raw_event), element = event.target._,
        type = element.type, form = element.form, parent;

    if (form && (parent = $(form).parent()) && (
      (raw_event.keyCode === 13   && (type === 'text'   || type === 'password')) ||
      (raw_event.type === 'click' && (type === 'submit' || type === 'image'))
    )) {
      event.type   = 'submit';
      event.target = $(form);
      parent.fire(event);
    }
  };

  document[ADD_EVENT_METHOD]('onclick',    submit_boobler);
  document[ADD_EVENT_METHOD]('onkeypress', submit_boobler);

}
<commit_msg>#216 making the 'change' events bubble in IE<commit_after>/**
 * This module provides the artificial events bubbling feature
 *
 * Copyright (C) 2010 Nikolay Nemshilov
 */

// patching the Element's 'fire' method again
// to make it to bypass the event to its parent
Element[PROTO].fire = patch_function(
  Element_observer.fire,
  /(\w+)(\s*=\s*\w+\.shift[\s\S]+)(return this)/m,
  '$1$2var p=!$1.stopped&&this.parent&&this.parent();p&&p.fire($1);$3'
);

/**
 * Triggers a manual focus/blur events bubbling
 *
 * @param raw dom-event
 * @return void
 */
function focus_boobler(event) {
  var target = $(event.target || event.srcElement),
      parent = target.parent && target.parent();

  parent && parent.fire(
    (event.type === 'focusin' || event.type === 'focus') ?
    'focus' : 'blur', Object.without(event, 'type')
  );
};

/**
 * Hooking up the 'focus' and 'blur' events
 * at the document level and then rebooble them
 * manually like they were normal events
 *
 */
if (Browser.IE) {
  document[ADD_EVENT_METHOD]('onfocusin',  focus_boobler);
  document[ADD_EVENT_METHOD]('onfocusout', focus_boobler);
} else {
  document[ADD_EVENT_METHOD]('focus', focus_boobler, true);
  document[ADD_EVENT_METHOD]('blur',  focus_boobler, true);
}

/**
 * Tests if there is the event support
 *
 * @param String event name
 * @retrun Boolean check result
 */
function event_support_for(name) {
  var e = $E('div')._;
  e.setAttribute(name, ';');
  return isFunction(e[name]);
};

if (!event_support_for('onsubmit')) {
  /**
   * Emulates the 'submit' event bubbling for IE browsers
   *
   * @param raw dom-event
   * @return void
   */
  function submit_boobler(raw_event) {
    var event = $(raw_event), element = event.target._,
        type = element.type, form = element.form, parent;

    if (form && (parent = $(form).parent()) && (
      (raw_event.keyCode === 13   && (type === 'text'   || type === 'password')) ||
      (raw_event.type === 'click' && (type === 'submit' || type === 'image'))
    )) {
      event.type   = 'submit';
      event.target = $(form);
      parent.fire(event);
    }
  };

  document[ADD_EVENT_METHOD]('onclick',    submit_boobler);
  document[ADD_EVENT_METHOD]('onkeypress', submit_boobler);
}

if (!event_support_for('onchange')) {

  function get_input_value(target) {
    var element = target._,
        type    = element.type;

    return type === 'radio' || type === 'checkbox' ?
      element.checked : target.getValue();
  };

  /**
   * Emulates the 'change' event bubbling
   *
   * @param Event wrapped dom-event
   * @param Input wrapped input element
   * @return void
   */
  function change_boobler(event, target) {
    var parent  = target.parent(),
        value   = get_input_value(target);

    if (parent && ''+target._prev_value !== ''+value) {
      target._prev_value = value; // saving the value so it didn't fire up again
      event.type = 'change';
      parent.fire(event);
    }
  };

  /**
   * Catches the input field changes
   *
   * @param raw dom-event
   * @return void
   */
  function catch_inputs_access(raw_event) {
    var event  = $(raw_event),
        target = event.target,
        type   = target._.type,
        tag    = target._.tagName,
        input_is_radio = (type === 'radio' || type === 'checkbox');

    if (
      (event.type === 'click' && (input_is_radio || tag === 'SELECT')) ||
      (event.type === 'keydown' && (
        (event.keyCode == 13 && (tag !== 'TEXTAREA')) ||
        type === 'select-multiple'
      ))
    )

    change_boobler(event, target);
  };

  document[ADD_EVENT_METHOD]('onclick',   catch_inputs_access);
  document[ADD_EVENT_METHOD]('onkeydown', catch_inputs_access);

  /**
   * Catch inputs blur
   *
   * @param raw dom-event
   * @return void
   */
  function catch_input_left(raw_event) {
    var event  = $(raw_event),
        target = event.target;

    if (target instanceof Input) {
      change_boobler(event, target);
    }
  };

  if (Browser.IE) {
    document[ADD_EVENT_METHOD]('onfocusout', catch_input_left);
  } else {
    document[ADD_EVENT_METHOD]('blur', catch_input_left, true);
  }

  /**
   * storing the input element previous value, so we could figure out
   * if it was changed later on
   */
  document[ADD_EVENT_METHOD]('onbeforeactivate', function(event) {
    var element = $(event).target, checked = 'checked';

    if (element instanceof Input) {
      element._prev_value = get_input_value(element);
    }
  });
}<|endoftext|>


<commit_before>// Copyright 2020, Google LLC.
// 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
//
//    https://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.
'use strict';

/**
 * This application demonstrates how to perform basic translation operations
 * with the Google Cloud Media Translation API.
 *
 * Note: Correct microphone settings is required: check enclosed link, and make
 * sure the following conditions are met:
 * 1. SoX must be installed and available in your $PATH- it can be found here:
 * http://sox.sourceforge.net/
 * 2. Microphone must be working
 * 3. Encoding, sampleRateHertz, and # of channels must match header of audio file you're
 * recording to.
 * 4. Get Node-Record-lpcm16 https://www.npmjs.com/package/node-record-lpcm16
 * More Info: https://cloud.google.com/speech-to-text/docs/streaming-recognize
 */

/**
 * Translates audio streaming from a microphone
 * @param {string} encoding the audio encoding codec
 * @param {string} sampleRateHertz the sampling rate of the audio stream
 * @param {string} sourceLanguageCode the language to translate from
 * @param {string} targetLanguageCode the language to translate to
 */
function main(encoding, sampleRateHertz, sourceLanguage, targetLanguage) {
  sampleRateHertz = Number(sampleRateHertz);

  // [START media_translation_translate_from_mic]

  // Node-Record-lpcm16
  const recorder = require('node-record-lpcm16');

  // Imports the Cloud Media Translation client library
  const {
    SpeechTranslationServiceClient,
  } = require('@google-cloud/media-translation');

  // Creates a client
  const client = new SpeechTranslationServiceClient();

  function translateFromMicrophone() {
    /**
     * TODO(developer): Uncomment the following lines before running the sample.
     */
    //const encoding = 'linear16';
    //const sampleRateHertz = 16000;
    //const sourceLanguage = 'Language to translate from, as BCP-47 locale';
    //const targetLanguage = 'Language to translate to, as BCP-47 locale';

    const config = {
      audioConfig: {
        audioEncoding: encoding,
        sourceLanguageCode: sourceLanguage,
        targetLanguageCode: targetLanguage,
      },
    };

    // First request needs to have only a streaming config, no data.
    const initialRequest = {
      streamingConfig: config,
      audioContent: null,
    };

    // Create a recognize stream
    const stream = client
      .streamingTranslateSpeech()
      .on('error', e => {
        if (e.code && e.code === 4) {
          console.log('Streaming translation reached its deadline.');
        } else {
          console.log(e);
        }
      })
      .on('data', response => {
        const {result} = response;
        if (result.textTranslationResult.isFinal) {
          console.log(
            `\nFinal translation: ${result.textTranslationResult.translation}`
          );
          console.log(`Final recognition result: ${result.recognitionResult}`);
        } else {
          console.log(
            `\nPartial translation: ${result.textTranslationResult.translation}`
          );
          console.log(
            `Partial recognition result: ${result.recognitionResult}`
          );
        }
      });

    let isFirst = true;
    // Start recording and send microphone input to the Media Translation API
    recorder
      .record({
        sampleRateHertz: sampleRateHertz,
        threshold: 0, //silence threshold
        recordProgram: 'rec',
        silence: '5.0', //seconds of silence before ending
      })
      .stream()
      .on('data', chunk => {
        if (isFirst) {
          stream.write(initialRequest);
          isFirst = false;
        }
        const request = {
          streamingConfig: config,
          audioContent: chunk.toString('base64'),
        };
        stream.write(request);
      });

    console.log('Listening, press Ctrl+C to stop.');
  }

  translateFromMicrophone();

  // [END media_translation_translate_from_mic]
}
main(...process.argv.slice(2));
<commit_msg>feat(samples): demonstrate real-time conversation translation (#48)<commit_after>// Copyright 2020, Google LLC.
// 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
//
//    https://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.
'use strict';

/**
 * This application demonstrates how to perform basic translation operations
 * with the Google Cloud Media Translation API.
 *
 * Note: Correct microphone settings is required: check enclosed link, and make
 * sure the following conditions are met:
 * 1. SoX must be installed and available in your $PATH- it can be found here:
 * http://sox.sourceforge.net/
 * 2. Microphone must be working
 * 3. Encoding, sampleRateHertz, and # of channels must match header of audio file you're
 * recording to.
 * 4. Get Node-Record-lpcm16 https://www.npmjs.com/package/node-record-lpcm16
 * More Info: https://cloud.google.com/speech-to-text/docs/streaming-recognize
 */

/**
 * Translates audio streaming from a microphone
 * @param {string} encoding the audio encoding codec
 * @param {string} sampleRateHertz the sampling rate of the audio stream
 * @param {string} sourceLanguageCode the language to translate from
 * @param {string} targetLanguageCode the language to translate to
 */
function main(encoding, sampleRateHertz, sourceLanguage, targetLanguage) {
  sampleRateHertz = Number(sampleRateHertz);

  // [START media_translation_translate_from_mic]

  // Allow user input from terminal
  const readline = require('readline');

  const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
  });

  function doTranslationLoop() {
    rl.question("Press any key to translate or 'q' to quit: ", answer => {
      if (answer.toLowerCase() === 'q') {
        rl.close();
      } else {
        translateFromMicrophone();
      }
    });
  }

  // Node-Record-lpcm16
  const recorder = require('node-record-lpcm16');

  // Imports the Cloud Media Translation client library
  const {
    SpeechTranslationServiceClient,
  } = require('@google-cloud/media-translation');

  // Creates a client
  const client = new SpeechTranslationServiceClient();

  function translateFromMicrophone() {
    /**
     * TODO(developer): Uncomment the following lines before running the sample.
     */
    //const encoding = 'linear16';
    //const sampleRateHertz = 16000;
    //const sourceLanguage = 'Language to translate from, as BCP-47 locale';
    //const targetLanguage = 'Language to translate to, as BCP-47 locale';
    console.log('Begin speaking ...');

    const config = {
      audioConfig: {
        audioEncoding: encoding,
        sourceLanguageCode: sourceLanguage,
        targetLanguageCode: targetLanguage,
      },
      singleUtterance: true,
    };

    // First request needs to have only a streaming config, no data.
    const initialRequest = {
      streamingConfig: config,
      audioContent: null,
    };

    let currentTranslation = '';
    let currentRecognition = '';
    // Create a recognize stream
    const stream = client
      .streamingTranslateSpeech()
      .on('error', e => {
        if (e.code && e.code === 4) {
          console.log('Streaming translation reached its deadline.');
        } else {
          console.log(e);
        }
      })
      .on('data', response => {
        const {result, speechEventType} = response;
        if (speechEventType === 'END_OF_SINGLE_UTTERANCE') {
          console.log(`\nFinal translation: ${currentTranslation}`);
          console.log(`Final recognition result: ${currentRecognition}`);

          stream.destroy();
          recording.stop();
        } else {
          currentTranslation = result.textTranslationResult.translation;
          currentRecognition = result.recognitionResult;
          console.log(`\nPartial translation: ${currentTranslation}`);
          console.log(`Partial recognition result: ${currentRecognition}`);
        }
      });

    let isFirst = true;
    // Start recording and send microphone input to the Media Translation API
    const recording = recorder.record({
      sampleRateHertz: sampleRateHertz,
      threshold: 0, //silence threshold
      recordProgram: 'rec',
      silence: '5.0', //seconds of silence before ending
    });
    recording
      .stream()
      .on('data', chunk => {
        if (isFirst) {
          stream.write(initialRequest);
          isFirst = false;
        }
        const request = {
          streamingConfig: config,
          audioContent: chunk.toString('base64'),
        };
        stream.write(request);
      })
      .on('close', () => {
        doTranslationLoop();
      });
  }

  doTranslationLoop();
  // [END media_translation_translate_from_mic]
}
main(...process.argv.slice(2));
<|endoftext|>


<commit_before>var TIMELINE = {};

TIMELINE.generatePostElement = function(post) {
	return $('
')
	.attr({
		title: post.createdAt + '
via ' + post.app.name,
		'data-id': post.id,
		'data-user-id': post.userId,
		'data-user-comment': post.user.comment,
		'data-user-color': post.user.color,
		style: post.isReply ? 'border-color: ' + post.reply.user.color + ';' : ''
	})
	.append(post.isReply ? generateReplyTo() : null)
	.append(generateArticle(post))
	.append(generateFooter());

	function generateReplyTo() {
		return $('
')
		.append(generateArticle(post.reply));
	}

	function generateArticle(post) {
		return $('
')
		.append(generateIcon())
		.append(generateHeader())
		.append($('
').html((post.isReply ? ' ' : '') + parseText(post.text)))
		.append(post.isImageAttached ? generateImage() : null);

		function generateIcon() {
			return $('')
			.attr('href', conf.url + '/' + post.user.screenName + '/talk?noheader=true')
			.append(
			$('')
			.attr('src', conf.url + '/img/icon/' + post.user.screenName)
			);
		}

		function generateHeader() {
			return generateHeader()
			.append(generateScreenName())
			.append(generateTime());

			function generateHeader() {
				return $('').prepend($('
').prepend(generateName()));
			}

			function generateName() {
				return $('')
				.attr('href', conf.url + '/' + post.user.screenName)
				.text(escapeHtml(post.user.name));
			}

			function generateScreenName() {
				return $('')
				.text('@' + post.user.screenName);
			}

			function generateTime() {
				return $('<time>')
				.attr('datetime', post.createdAt)
				.text(post.createdAt);
			}
		}

		function generateImage() {
			return $('')
			.attr('src', conf.url + '/img/post/' + post.id);
		}
	}

	function generateFooter() {
		return $('')
		.append(generateForm());

		function generateForm() {
			return $('<form class="replyForm">')
			.append(generateTextArea())
			.append(generateInReplyToPostId())
			.append(generateSubmitButton())
			.append(generateImageAttacher());

			function generateTextArea() {
				return $('<textarea name="text">')
				.text('@' + post.user.screenName + ' ');
			}

			function generateInReplyToPostId() {
				return $('<input name="in_reply_to_post_id" type="hidden">')
				.attr('value', post.id);
			}

			function generateSubmitButton() {
				return $('<input type="submit" value="Reply">');
			}

			function generateImageAttacher() {
				return $('
')
				.append($('

'))
				.append($('<input name="image" type="file" accept="image/*">'));
			}
		}
	}

	function parseText(text) {
		text = escapeHtml(text);
		text = parseURL(text);
		text = parseReply(text);
		text = parseBold(text);
		text = parseSmall(text);
		text = parseNewLine(text);
		return text;

		function parseURL(text) {
			return text.replace(/https?:\/\/[-_.!~*a-zA-Z0-9;\/?:\@&=+\$,%#]+/g, function(url) {
				return '' + url + '';
			});
		}

		function parseReply(text) {
			return text.replace(/@([a-zA-Z0-9_]+)/g, function(_, screenName) {
				return '@' + screenName + '';
			});
		}

		function parseBold(text) {
			return text.replace(/\*\*(.+?)\*\*/g, function(_, word) {
				return '' + word + '';
			});
		}

		function parseSmall(text) {
			return text.replace(/\(\((.+?)\)\)/g, function(_, word) {
				return '(' + word + ')';
			});
		}

		function parseNewLine(text) {
			return text.replace(/(\r\n|\r|\n)/g, '
');
		}
	}

	function escapeHtml(text) {
		return $('
').text(text).html();
	}
}

TIMELINE.setEventPost = function($post) {
	$post.children('article').children('a').click(function() {
		var $content = $("").attr({ src: $post.children('article').children('a').attr('href'), seamless: true });
		openWindow($content, '' + $post.children('article').children('header').children('h2').children('a').text(), 300, 450);
		return false;
	});

	$post.find('.replyForm').submit(function(event) {
		event.preventDefault();
		var $form = $(this);
		var $submitButton = $form.find('[type=submit]');
		$submitButton.attr('disabled', true);
		$.ajax({
			url: 'https://api.misskey.xyz/post/create',
			type: 'post',
			data: new FormData($form[0]),
			processData: false,
			contentType: false,
			dataType: 'json',
			xhrFields: {
				withCredentials: true
			}
		}).done(function() {
			$submitButton.attr('disabled', false);
			$form.text('送信しました');
		}).fail(function() {
			$submitButton.attr('disabled', false);
		});
	});

	/*
	$post.find('.fr').submit(function (event) {
	event.preventDefault();
	var $form = $(this);
	var $submitButton = $form.find('[type=image]');
	$submitButton.attr('disabled', true);
	$.ajax({
	url: $form.attr('action'),
	type: $form.attr('method'),
	data: new FormData($form[0]),
	processData: false,
	contentType: false,
	}).done(function () {
	$submitButton.attr('disabled', false);
	if ($post.attr('data-is_favorite')) {
	$post.attr('data-is_favorite', false);
	$submitButton.attr('src', 'https://misskey.xyz/img/misskey/unfavorite.svg');
	$form.attr('action', 'https://misskey.xyz/api/post/favorite/create');
	} else {
	$post.attr('data-is_favorite', true);
	$submitButton.attr('src', 'https://misskey.xyz/img/misskey/favorite.svg');
	$form.attr('action', 'https://misskey.xyz/api/post/favorite/delete');
	}
	}).fail(function () {
	$submitButton.attr('disabled', false);
	});
	});
	*/

	$post.find('.imageAttacher input[name=image]').change(function() {
		var $input = $(this);
		var file = $(this).prop('files')[0];
		if (!file.type.match('image.*')) return;
		var reader = new FileReader();
		reader.onload = function() {
			var $img = $('').attr('src', reader.result);
			$input.parent('.imageAttacher').find('p, img').remove();
			$input.parent('.imageAttacher').append($img);
		};
		reader.readAsDataURL(file);
	});

	$post.click(function(event) {
		if (document.getSelection().toString() == '') {
			if ($(event.target).is('input') || $(event.target).is('textarea')) return;
			if ($(this).children('footer').css('display') === 'none') {
				$('.timeline > .posts > .post footer').each(function() {
					$(this).hide(200);
				});
				$(this).children('footer').show(200);
				var text = $(this).find('footer .replyForm textarea').val();
				$(this).find('footer .replyForm textarea').val('');
				$(this).find('footer .replyForm textarea').focus().val(text);
			} else {
				$(this).children('footer').hide(200);
			}
		}
	});

	/*
	$post.dblclick(function (event) {
	if ($(event.target).is('input') || $(event.target).is('textarea')) return;
	window.open('https://misskey.xyz/' + $(this).attr('data-user-screen_name') + '/post/' + $(this).attr('data-id'));
	});
	*/

}

$(function() {
	$('.timeline .post').each(function() {
		TIMELINE.setEventPost($(this));
	});
});<commit_msg>Fix selector<commit_after>var TIMELINE = {};

TIMELINE.generatePostElement = function(post) {
	return $('
')
	.attr({
		title: post.createdAt + '
via ' + post.app.name,
		'data-id': post.id,
		'data-user-id': post.userId,
		'data-user-comment': post.user.comment,
		'data-user-color': post.user.color,
		style: post.isReply ? 'border-color: ' + post.reply.user.color + ';' : ''
	})
	.append(post.isReply ? generateReplyTo() : null)
	.append(generateArticle(post))
	.append(generateFooter());

	function generateReplyTo() {
		return $('
')
		.append(generateArticle(post.reply));
	}

	function generateArticle(post) {
		return $('
')
		.append(generateIcon())
		.append(generateHeader())
		.append($('
').html((post.isReply ? ' ' : '') + parseText(post.text)))
		.append(post.isImageAttached ? generateImage() : null);

		function generateIcon() {
			return $('')
			.attr('href', conf.url + '/' + post.user.screenName + '/talk?noheader=true')
			.append(
			$('')
			.attr('src', conf.url + '/img/icon/' + post.user.screenName)
			);
		}

		function generateHeader() {
			return generateHeader()
			.append(generateScreenName())
			.append(generateTime());

			function generateHeader() {
				return $('').prepend($('
').prepend(generateName()));
			}

			function generateName() {
				return $('')
				.attr('href', conf.url + '/' + post.user.screenName)
				.text(escapeHtml(post.user.name));
			}

			function generateScreenName() {
				return $('')
				.text('@' + post.user.screenName);
			}

			function generateTime() {
				return $('<time>')
				.attr('datetime', post.createdAt)
				.text(post.createdAt);
			}
		}

		function generateImage() {
			return $('')
			.attr('src', conf.url + '/img/post/' + post.id);
		}
	}

	function generateFooter() {
		return $('')
		.append(generateForm());

		function generateForm() {
			return $('<form class="replyForm">')
			.append(generateTextArea())
			.append(generateInReplyToPostId())
			.append(generateSubmitButton())
			.append(generateImageAttacher());

			function generateTextArea() {
				return $('<textarea name="text">')
				.text('@' + post.user.screenName + ' ');
			}

			function generateInReplyToPostId() {
				return $('<input name="in_reply_to_post_id" type="hidden">')
				.attr('value', post.id);
			}

			function generateSubmitButton() {
				return $('<input type="submit" value="Reply">');
			}

			function generateImageAttacher() {
				return $('
')
				.append($('

'))
				.append($('<input name="image" type="file" accept="image/*">'));
			}
		}
	}

	function parseText(text) {
		text = escapeHtml(text);
		text = parseURL(text);
		text = parseReply(text);
		text = parseBold(text);
		text = parseSmall(text);
		text = parseNewLine(text);
		return text;

		function parseURL(text) {
			return text.replace(/https?:\/\/[-_.!~*a-zA-Z0-9;\/?:\@&=+\$,%#]+/g, function(url) {
				return '' + url + '';
			});
		}

		function parseReply(text) {
			return text.replace(/@([a-zA-Z0-9_]+)/g, function(_, screenName) {
				return '@' + screenName + '';
			});
		}

		function parseBold(text) {
			return text.replace(/\*\*(.+?)\*\*/g, function(_, word) {
				return '' + word + '';
			});
		}

		function parseSmall(text) {
			return text.replace(/\(\((.+?)\)\)/g, function(_, word) {
				return '(' + word + ')';
			});
		}

		function parseNewLine(text) {
			return text.replace(/(\r\n|\r|\n)/g, '
');
		}
	}

	function escapeHtml(text) {
		return $('
').text(text).html();
	}
}

TIMELINE.setEventPost = function($post) {
	$post.children('article').children('a').click(function() {
		var $content = $("").attr({ src: $post.children('article').children('a').attr('href'), seamless: true });
		openWindow($content, '' + $post.children('article').children('header').children('h2').children('a').text(), 300, 450);
		return false;
	});

	$post.find('.replyForm').submit(function(event) {
		event.preventDefault();
		var $form = $(this);
		var $submitButton = $form.find('[type=submit]');
		$submitButton.attr('disabled', true);
		$.ajax({
			url: 'https://api.misskey.xyz/post/create',
			type: 'post',
			data: new FormData($form[0]),
			processData: false,
			contentType: false,
			dataType: 'json',
			xhrFields: {
				withCredentials: true
			}
		}).done(function() {
			$submitButton.attr('disabled', false);
			$form.text('送信しました');
		}).fail(function() {
			$submitButton.attr('disabled', false);
		});
	});

	/*
	$post.find('.fr').submit(function (event) {
	event.preventDefault();
	var $form = $(this);
	var $submitButton = $form.find('[type=image]');
	$submitButton.attr('disabled', true);
	$.ajax({
	url: $form.attr('action'),
	type: $form.attr('method'),
	data: new FormData($form[0]),
	processData: false,
	contentType: false,
	}).done(function () {
	$submitButton.attr('disabled', false);
	if ($post.attr('data-is_favorite')) {
	$post.attr('data-is_favorite', false);
	$submitButton.attr('src', 'https://misskey.xyz/img/misskey/unfavorite.svg');
	$form.attr('action', 'https://misskey.xyz/api/post/favorite/create');
	} else {
	$post.attr('data-is_favorite', true);
	$submitButton.attr('src', 'https://misskey.xyz/img/misskey/favorite.svg');
	$form.attr('action', 'https://misskey.xyz/api/post/favorite/delete');
	}
	}).fail(function () {
	$submitButton.attr('disabled', false);
	});
	});
	*/

	$post.find('.imageAttacher input[name=image]').change(function() {
		var $input = $(this);
		var file = $(this).prop('files')[0];
		if (!file.type.match('image.*')) return;
		var reader = new FileReader();
		reader.onload = function() {
			var $img = $('').attr('src', reader.result);
			$input.parent('.imageAttacher').find('p, img').remove();
			$input.parent('.imageAttacher').append($img);
		};
		reader.readAsDataURL(file);
	});

	$post.click(function(event) {
		if (document.getSelection().toString() == '') {
			if ($(event.target).is('input') || $(event.target).is('textarea')) return;
			if ($(this).children('footer').css('display') === 'none') {
				$('.timeline > .posts > .post > footer').each(function() {
					$(this).hide(200);
				});
				$(this).children('footer').show(200);
				var text = $(this).find('footer .replyForm textarea').val();
				$(this).find('footer .replyForm textarea').val('');
				$(this).find('footer .replyForm textarea').focus().val(text);
			} else {
				$(this).children('footer').hide(200);
			}
		}
	});

	/*
	$post.dblclick(function (event) {
	if ($(event.target).is('input') || $(event.target).is('textarea')) return;
	window.open('https://misskey.xyz/' + $(this).attr('data-user-screen_name') + '/post/' + $(this).attr('data-id'));
	});
	*/

}

$(function() {
	$('.timeline .post').each(function() {
		TIMELINE.setEventPost($(this));
	});
});<|endoftext|>