<commit_before>kWidget.addReadyCallback( function( playerId ){
	/**
	 * The main omnitureOnPage object:
	 */
	var omnitureOnPage = function(kdp){
		return this.init(kdp);
	}
	omnitureOnPage.prototype = {
		init:function( kdp ){
			var _this = this;
			this.kdp = kdp;
			// Check for on-page s-code that already exists
			this.sCodeCheck(function(){
				_this.bindPlayer();
			})
		},
		sCodeCheck: function( callback ){
			// check if already on the page:
			if(window['s'] && window['s']['Media'] ){
				callback();
				return ;
			}
			// check if we have
			if( !this.getConfig('s_codeUrl') ){
				kWidget.log( "Error: s_codeUrl must be set for Omniture onPage plugin");
				return ;
			}
			kWidget.appendScriptUrl( this.getConfig('s_codeUrl'), callback );
		},
		/** Getters **/
		getMediaPlayerName: function(){
			return 'Kaltura Omniture OnPage v' + mw.getConfig('version');
		},
		getMediaName: function(){
			return this.getAttr('mediaProxy.entry.name');
		},
		getDuration: function(){
			return Math.floor( this.getAttr('duration') );
		},
		getCurrentTime: function(){
			return Math.floor( this.getAttr('video.player.currentTime') );
		},
		bindPlayer: function(){
			var _this = this;
			var firstPlay = true;
			// setup shortcuts:
			var stop = function(){
				_this.runMediaCommand( "stop", _this.getMediaName(), _this.getCurrentTime() );
			}
			var play = function(){
				_this.runMediaCommand( "play", _this.getMediaName(), _this.getCurrentTime() );
			}
			// Run open on first play:
			this.kdp.kBind( 'doPlay', function(){
				if( firstPlay ){
					_this.runMediaCommand( "open",
						_this.getMediaName(),
						_this.getDuration(),
						_this.getMediaPlayerName()
					)
				}
				_this.runMediaCommand( "play", _this.getMediaName(), _this.getCurrentTime() );
				firstPlay = false;
			})
			this.kdp.kBind( 'playerSeekStart', stop );
			this.kdp.kBind( 'playerSeekEnd', play );
			this.kdp.kBind( 'doPause', stop );
			this.kdp.kBind( 'playerPlayEnd', function(){
				stop();
				_this.runMediaCommand( "close", _this.getMediaName() )
			});
		},

		runMediaCommand: function(){
	 		var args = $.makeArray( arguments );
	 		var cmd = args[0];
	 		var argSet = args.slice( 1 );
	 		try{
	 			eval( 's.Media.' + cmd + '("' + argSet.join('","') + '");');
	 			// not working :(
	 			//s.Media[cmd].apply( this, args );
	 		}catch( e ){
	 			kWidget.log( "Error: Omniture, trying to run media command:" + cmd + ' does not exist' );
	 		}

	 		// audit if trackEventMonitor is set:
	 		if( this.getConfig( 'trackEventMonitor') ){
		 		try{
		 			window.parent[ this.getConfig( 'trackEventMonitor') ]( 's.Media.' + cmd + '( ' + argSet.join(', ') + ' )' );
		 		} catch ( e ){}
	 		}
	 	},
		normalizeAttrValue: function( attrValue ){
			// normalize flash kdp string values
			switch( attrValue ){
				case "null":
					return null;
				break;
				case "true":
					return true;
				break;
				case "false":
					return false;
				break;
			}
			return attrValue;
		},
		getAttr: function( attr ){
			return this.normalizeAttrValue(
				this.kdp.evaluate( '{' + attr + '}' )
			);
		},
		getConfig : function( attr ){
			return this.normalizeAttrValue(
				this.kdp.evaluate('{omnitureOnPage.' + attr + '}' )
			);
		}
	}

	/**********************************
	 * Initialization of omnitureOnpage:
	 **********************************/
	new omnitureOnPage( document.getElementById( playerId ) );
});
<commit_msg>Omniture OnPage: Cleaner logging via " of values<commit_after>kWidget.addReadyCallback( function( playerId ){
	/**
	 * The main omnitureOnPage object:
	 */
	var omnitureOnPage = function(kdp){
		return this.init(kdp);
	}
	omnitureOnPage.prototype = {
		init:function( kdp ){
			var _this = this;
			this.kdp = kdp;
			// Check for on-page s-code that already exists
			this.sCodeCheck(function(){
				_this.bindPlayer();
			})
		},
		sCodeCheck: function( callback ){
			// check if already on the page:
			if(window['s'] && window['s']['Media'] ){
				callback();
				return ;
			}
			// check if we have
			if( !this.getConfig('s_codeUrl') ){
				kWidget.log( "Error: s_codeUrl must be set for Omniture onPage plugin");
				return ;
			}
			kWidget.appendScriptUrl( this.getConfig('s_codeUrl'), callback );
		},
		/** Getters **/
		getMediaPlayerName: function(){
			return 'Kaltura Omniture OnPage v' + mw.getConfig('version');
		},
		getMediaName: function(){
			return this.getAttr('mediaProxy.entry.name');
		},
		getDuration: function(){
			return Math.floor( this.getAttr('duration') );
		},
		getCurrentTime: function(){
			return Math.floor( this.getAttr('video.player.currentTime') );
		},
		bindPlayer: function(){
			var _this = this;
			var firstPlay = true;
			// setup shortcuts:
			var stop = function(){
				_this.runMediaCommand( "stop", _this.getMediaName(), _this.getCurrentTime() );
			}
			var play = function(){
				_this.runMediaCommand( "play", _this.getMediaName(), _this.getCurrentTime() );
			}
			// Run open on first play:
			this.kdp.kBind( 'doPlay', function(){
				if( firstPlay ){
					_this.runMediaCommand( "open",
						_this.getMediaName(),
						_this.getDuration(),
						_this.getMediaPlayerName()
					)
				}
				_this.runMediaCommand( "play", _this.getMediaName(), _this.getCurrentTime() );
				firstPlay = false;
			})
			this.kdp.kBind( 'playerSeekStart', stop );
			this.kdp.kBind( 'playerSeekEnd', play );
			this.kdp.kBind( 'doPause', stop );
			this.kdp.kBind( 'playerPlayEnd', function(){
				stop();
				_this.runMediaCommand( "close", _this.getMediaName() )
			});
		},

		runMediaCommand: function(){
	 		var args = $.makeArray( arguments );
	 		var cmd = args[0];
	 		var argSet = args.slice( 1 );
	 		try{
	 			eval( 's.Media.' + cmd + '("' + argSet.join('","') + '");');
	 			// not working :(
	 			//s.Media[cmd].apply( this, args );
	 		}catch( e ){
	 			kWidget.log( "Error: Omniture, trying to run media command:" + cmd + ' does not exist' );
	 		}

	 		// audit if trackEventMonitor is set:
	 		if( this.getConfig( 'trackEventMonitor') ){
		 		try{
		 			window.parent[ this.getConfig( 'trackEventMonitor') ]( 's.Media.' + cmd + '( "' + argSet.join('", "') + '" )' );
		 		} catch ( e ){}
	 		}
	 	},
		normalizeAttrValue: function( attrValue ){
			// normalize flash kdp string values
			switch( attrValue ){
				case "null":
					return null;
				break;
				case "true":
					return true;
				break;
				case "false":
					return false;
				break;
			}
			return attrValue;
		},
		getAttr: function( attr ){
			return this.normalizeAttrValue(
				this.kdp.evaluate( '{' + attr + '}' )
			);
		},
		getConfig : function( attr ){
			return this.normalizeAttrValue(
				this.kdp.evaluate('{omnitureOnPage.' + attr + '}' )
			);
		}
	}

	/**********************************
	 * Initialization of omnitureOnpage:
	 **********************************/
	new omnitureOnPage( document.getElementById( playerId ) );
});
<|endoftext|>


<commit_before>'use strict';

var PRISTINE_CLASS = 'ng-pristine',
    DIRTY_CLASS = 'ng-dirty';

var Module = angular.module('datePicker');

Module.constant('dateTimeConfig', {
  template: function (attrs) {
    return '' +
        '

';
  },
  format: 'yyyy-MM-dd HH:mm',
  views: ['date', 'year', 'month', 'hours', 'minutes', 'month'],
  dismiss: false,
  position: 'relative'
});

Module.directive('dateTimeAppend', function () {
  return {
    link: function (scope, element) {
      element.bind('click', function () {
        element.find('input').focus();
      });
    }
  };
});

Module.directive('dateTime', function ($compile, $document, $filter, dateTimeConfig, $parse) {
  var body = $document.find('body');
  var dateFilter = $filter('date');

  return {
    require: 'ngModel',
    scope:true,
    link: function (scope, element, attrs, ngModel) {
      var format = attrs.format || dateTimeConfig.format;
      var parentForm = element.inheritedData('$formController');
      var views = $parse(attrs.views)(scope) || dateTimeConfig.views.concat();
      var view = attrs.view || views[0];
      var index = views.indexOf(view);
      var dismiss = attrs.dismiss ? $parse(attrs.dismiss)(scope) : dateTimeConfig.dismiss;
      var picker = null;
      var position = attrs.position || dateTimeConfig.position;
      var container = null;

      if (index === -1) {
        views.splice(index, 1);
      }

      views.unshift(view);

      function formatter(value) {
        return dateFilter(value, format);
      }

      function parser() {
        return ngModel.$modelValue;
      }

      ngModel.$formatters.push(formatter);
      ngModel.$parsers.unshift(parser);

      var template = dateTimeConfig.template(attrs);

      function updateInput(event) {
        event.stopPropagation();
        if (ngModel.$pristine) {
          ngModel.$dirty = true;
          ngModel.$pristine = false;
          element.removeClass(PRISTINE_CLASS).addClass(DIRTY_CLASS);
          if (parentForm) {
            parentForm.$setDirty();
          }
          ngModel.$render();
        }
      }

      function clear() {
        if (picker) {
          picker.remove();
          picker = null;
        }
        if (container) {
          container.remove();
          container = null;
        }
      }

      function showPicker() {
        if (picker) {
          return;
        }
        // create picker element
        picker = $compile(template)(scope);
        scope.$digest();

        scope.$on('setDate', function (event) {
          updateInput(event);
          if (dismiss) {
            clear();
          }
        });

        scope.$on('$destroy', clear);

        // move picker below input element

        if (position === 'absolute') {
          var pos = angular.extend(element.offset(), { height: element[0].offsetHeight });
          picker.css({ top: pos.top + pos.height, left: pos.left, display: 'block', position: position});
          body.append(picker);
        } else {
          // relative
          container = angular.element('

');
          element[0].parentElement.insertBefore(container[0], element[0]);
          container.append(picker);
//          this approach doesn't work
//          element.before(picker);
          picker.css({top: element[0].offsetHeight + 'px', display: 'block'});
        }

        picker.bind('mousedown', function (evt) {
          evt.preventDefault();
        });
      }

      element.bind('focus', showPicker);
      element.bind('blur', clear);
    }
  };
});
<commit_msg>fix(input): fixed dateTimeAppend : works without jQuery<commit_after>'use strict';

var PRISTINE_CLASS = 'ng-pristine',
    DIRTY_CLASS = 'ng-dirty';

var Module = angular.module('datePicker');

Module.constant('dateTimeConfig', {
  template: function (attrs) {
    return '' +
        '

';
  },
  format: 'yyyy-MM-dd HH:mm',
  views: ['date', 'year', 'month', 'hours', 'minutes', 'month'],
  dismiss: false,
  position: 'relative'
});

Module.directive('dateTimeAppend', function () {
  return {
    link: function (scope, element) {
      element.bind('click', function () {
        element.find('input')[0].focus();
      });
    }
  };
});

Module.directive('dateTime', function ($compile, $document, $filter, dateTimeConfig, $parse) {
  var body = $document.find('body');
  var dateFilter = $filter('date');

  return {
    require: 'ngModel',
    scope:true,
    link: function (scope, element, attrs, ngModel) {
      var format = attrs.format || dateTimeConfig.format;
      var parentForm = element.inheritedData('$formController');
      var views = $parse(attrs.views)(scope) || dateTimeConfig.views.concat();
      var view = attrs.view || views[0];
      var index = views.indexOf(view);
      var dismiss = attrs.dismiss ? $parse(attrs.dismiss)(scope) : dateTimeConfig.dismiss;
      var picker = null;
      var position = attrs.position || dateTimeConfig.position;
      var container = null;

      if (index === -1) {
        views.splice(index, 1);
      }

      views.unshift(view);

      function formatter(value) {
        return dateFilter(value, format);
      }

      function parser() {
        return ngModel.$modelValue;
      }

      ngModel.$formatters.push(formatter);
      ngModel.$parsers.unshift(parser);

      var template = dateTimeConfig.template(attrs);

      function updateInput(event) {
        event.stopPropagation();
        if (ngModel.$pristine) {
          ngModel.$dirty = true;
          ngModel.$pristine = false;
          element.removeClass(PRISTINE_CLASS).addClass(DIRTY_CLASS);
          if (parentForm) {
            parentForm.$setDirty();
          }
          ngModel.$render();
        }
      }

      function clear() {
        if (picker) {
          picker.remove();
          picker = null;
        }
        if (container) {
          container.remove();
          container = null;
        }
      }

      function showPicker() {
        if (picker) {
          return;
        }
        // create picker element
        picker = $compile(template)(scope);
        scope.$digest();

        scope.$on('setDate', function (event) {
          updateInput(event);
          if (dismiss) {
            clear();
          }
        });

        scope.$on('$destroy', clear);

        // move picker below input element

        if (position === 'absolute') {
          var pos = angular.extend(element.offset(), { height: element[0].offsetHeight });
          picker.css({ top: pos.top + pos.height, left: pos.left, display: 'block', position: position});
          body.append(picker);
        } else {
          // relative
          container = angular.element('

');
          element[0].parentElement.insertBefore(container[0], element[0]);
          container.append(picker);
//          this approach doesn't work
//          element.before(picker);
          picker.css({top: element[0].offsetHeight + 'px', display: 'block'});
        }

        picker.bind('mousedown', function (evt) {
          evt.preventDefault();
        });
      }

      element.bind('focus', showPicker);
      element.bind('blur', clear);
    }
  };
});
<|endoftext|>


<commit_before>"use babel";
// @flow

import { Map } from "immutable";
import { connect } from "react-redux";
import { compose, withState, withProps, lifecycle } from "recompose";
import { splitControlPanel } from "../Actions/SplitControlPanel";
import Panel from "../Presenters/Panel";
import { getPackagePanelsFromState } from "../Model/Factory";
import type { DisplayParams } from "../Types/types";
import {
  selectDiagnosticsReducer,
  selectTasksReducer,
  selectPlansReducer,
} from "../../../GlobalSystem/Selectors";
import type { State } from "../../../GlobalSystem/types.js.flow";
import { runTask } from "../../TaskExecutionFeature/Actions/RunTask";
import { killTask } from "../../TaskExecutionFeature/Actions/KillTask";
import {
  selectPertinentTaskID,
  selectTasksOfPlan,
} from "../../TaskExecutionFeature/Selectors/Tasks";
import type { Task } from "../../TaskExecutionFeature/Types/types";
import { unpinPlanConfig } from "../../PlanConfigurationFeature/Actions/UnpinPlanConfig";
import { pinPlanConfig } from "../../PlanConfigurationFeature/Actions/PinPlanConfig";
import { removePlanConfig } from "../../PlanConfigurationFeature/Actions/RemovePlanConfig";
import { openPlanConfigurer } from "../../PlanConfigurationFeature/Actions/OpenPlanConfigurer";
import { selectAllPlans } from "../../PlanConfigurationFeature/Selectors/PlanConfigs";
import type { PlanConfig } from "../../PlanConfigurationFeature/Types/types.js.flow";
import ExecutionsController from "../../LanguageServerProtocolFeature/Model/ExecutionsController";
import type { Range } from "../../LanguageServerProtocolFeature/Types/standard";
import { jumpTo } from "../../DiagnosticsFeature/Actions/JumpTo";
import { selectDiagnosticsOfTask } from "../../DiagnosticsFeature/Selectors/Diagnostics";
import { createTerminal } from "../../TerminalFeature/Actions/CreateTerminal";
import { removeTerminal } from "../../TerminalFeature/Actions/RemoveTerminal";
import type { DevTool } from "../../DevToolsSummaryFeature/Types/types.js.flow";
import TerminalsController from "../../TerminalFeature/Model/TerminalsController";
import { updateSourceStatus } from "../../ConsoleFeature/Actions/UpdateSourceStatus";
import { selectConsoleSourcesReducer } from "../../../GlobalSystem/Selectors";

const selectPertinentTaskIDForPanel = (
  state,
  toolId: string,
  plan: PlanConfig,
) => {
  if (plan === undefined) return "";
  return selectPertinentTaskID(
    selectTasksOfPlan(selectTasksReducer(state), plan),
  );
};

const TaskState = withState(
  "selectedTaskId",
  "setSelectedTaskId",
  ({
    state,
    toolId,
    plan,
  }: {
    state: State,
    toolId: string,
    plan: PlanConfig,
  }) =>
    selectPertinentTaskIDForPanel(state, plan ? plan.tool.id : toolId, plan),
);

const PertinentTaskSelector = lifecycle({
  componentWillReceiveProps(nextProps) {
    let prevPertinentTaskID = selectPertinentTaskIDForPanel(
      this.props.state,
      this.props.toolId,
      this.props.plan,
    );
    let nextPertinentTaskID = selectPertinentTaskIDForPanel(
      nextProps.state,
      nextProps.toolId,
      nextProps.plan,
    );
    if (prevPertinentTaskID != nextPertinentTaskID) {
      this.props.setSelectedTaskId(nextPertinentTaskID);
    }
  },
});

const DiagnosticsSelector = withProps(
  ({ state, selectedTaskId, selection }) => {
    return {
      diagnostics:
        selection.mode && selection.mode.type === "unified-diagnostics"
          ? selectAllPlans(selectPlansReducer(state)).reduce(
              (acc, cur) =>
                cur.packageInfo.path.startsWith(selection.mode.pkg)
                  ? acc.mergeDeep(
                      selectTasksOfPlan(selectTasksReducer(state), cur).reduce(
                        (map, task) =>
                          map.mergeDeep(
                            selectDiagnosticsOfTask(
                              selectDiagnosticsReducer(state),
                              task.id,
                            ),
                          ),
                        Map(),
                      ),
                    )
                  : acc,
              Map(),
            )
          : selectDiagnosticsOfTask(
              selectDiagnosticsReducer(state),
              selectedTaskId,
            ),
    };
  },
);

const ExecutionSelector = withProps(({ getExecution, selectedTaskId }) => {
  const execution = getExecution(selectedTaskId);
  return {
    xtermInstance:
      execution != null && execution.task.strategy.type === "terminal"
        ? execution.terminal
        : undefined,
  };
});

const TerminalSelector = withProps(({ getTerminalExecution, selection }) => {
  if (selection && selection.mode && selection.mode.type === "free-terminal") {
    const execution = getTerminalExecution(selection.mode.id);
    return {
      xtermInstance: execution != null ? execution.terminal : undefined,
    };
  } else return {};
});

const TaskChangeHandler = withProps(({ setSelectedTaskId }) => ({
  onTaskClick: (task: Task) => setSelectedTaskId(task.id),
}));

const TerminalsEventsHandler = lifecycle({
  onTerminalsChange(e) {
    if (e.type === "added") {
      this.props.setSelection({
        plan: null,
        mode: {
          type: "free-terminal",
          id: e.id,
        },
      });
    } else {
      this.props.setSelection({
        plan: null,
        mode: null,
      });
    }
  },
  componentDidMount() {
    this.onTerminalsChange = this.onTerminalsChange.bind(this);
    TerminalsController.eventEmitter.on("change", this.onTerminalsChange);
  },
  componentWillUnmount() {
    TerminalsController.eventEmitter.removeListener(
      "change",
      this.onTerminalsChange,
    );
  },
});

const getTypeSelection = (plan: PlanConfig, state) => {
  if (plan === undefined) return "";
  const lastTaskOfPlan = selectTasksOfPlan(
    selectTasksReducer(state),
    plan,
  ).last();
  if (lastTaskOfPlan) {
    let type =
      lastTaskOfPlan.strategy.type === "terminal" ? "terminal" : "diagnostics";
    if (
      type === "terminal" &&
      selectDiagnosticsOfTask(
        selectDiagnosticsReducer(state),
        lastTaskOfPlan.id,
      ).size > 0 &&
      lastTaskOfPlan.state === "running"
    )
      type = "diagnostics";
    return type;
  } else {
    return "diagnostics";
  }
};

export default compose(
  withState(
    "selection",
    "setSelection",
    (): DisplayParams => ({
      plan: null,
      mode: null,
    }),
  ),
  withProps(({ selection }) => ({
    plan: selection.plan,
    getExecution: selectedTask =>
      ExecutionsController.getExecution(selectedTask),
    getTerminalExecution: id => TerminalsController.getTerminalExecution(id),
  })),
  connect(
    (state: State) => ({
      packagePanels: getPackagePanelsFromState(state),
      isLoading: state.loadingProgress.ongoingPackageRefreshCount !== 0,
      sources: selectConsoleSourcesReducer(state),
      state,
    }),
    (dispatch: (action: Object) => void, props) => ({
      onStartPlan: (plan: PlanConfig) => {
        dispatch(runTask(plan, { type: "local" }));
      },
      onStopPlan: (plan: PlanConfig) => {
        dispatch(killTask(plan));
      },
      onPinPlan: (plan: PlanConfig) => {
        dispatch(pinPlanConfig(plan));
      },
      onUnPinPlan: (plan: PlanConfig) => {
        dispatch(unpinPlanConfig(plan));
      },
      onDeletePlan: (plan: PlanConfig) => {
        dispatch(removePlanConfig(plan));
      },
      onSplit: (plan: PlanConfig) => {
        dispatch(splitControlPanel(plan));
      },
      onNewPlan: devtool => {
        dispatch(openPlanConfigurer(devtool));
      },
      onJumpTo: (path: string, range: Range, pending: boolean) => {
        dispatch(jumpTo(path, range, pending));
      },
      onPackageTerminalAdd: (path: string) => {
        dispatch(createTerminal(path));
      },
      onPackageTerminalRemove: (id: string) => {
        dispatch(removeTerminal(id));
      },
      onIsChecked: (source: string, status: boolean) => {
        dispatch(updateSourceStatus(source, status));
      },
    }),
  ),
  lifecycle({
    componentDidMount() {
      if (this.props.defaultPlan) {
        this.props.setSelection({
          mode: {
            type: getTypeSelection(this.props.defaultPlan, this.props.state),
          },
          plan: this.props.defaultPlan,
        });
      }
    },
  }),
  TaskState,
  PertinentTaskSelector,
  ExecutionSelector,
  TerminalSelector,
  DiagnosticsSelector,
  TaskChangeHandler,
  TerminalsEventsHandler,
  withProps(
    ({ xtermInstance, diagnostics, tasks, setSelection, selection }) => ({
      onTerminalClick: (plan: PlanConfig) => {
        setSelection({
          plan,
          mode: {
            type: "terminal",
          },
        });
      },
      onDiagnosticClick: (plan: PlanConfig) => {
        setSelection({
          plan,
          mode: {
            type: "diagnostics",
          },
        });
      },
      onNewPlanClick: (devtool: DevTool) => {
        setSelection({
          plan: null,
          mode: {
            type: "plan-config",
            tool: devtool,
          },
        });
      },
      onConsolePanelClick: () => {
        setSelection({
          plan: null,
          mode: {
            type: "console-panel",
          },
        });
      },
      onUnifiedDiagnosticsClick: (pkg: string) => {
        setSelection({
          plan: null,
          mode: { type: "unified-diagnostics", pkg },
        });
      },
      onPackageTerminalClick: (id: string) => {
        setSelection({
          plan: null,
          mode: { type: "free-terminal", id },
        });
      },
      selection: {
        ...selection,
        mode: {
          ...selection.mode,
          xtermInstance,
          diagnostics,
          tasks,
        },
      },
    }),
  ),
)(Panel);
<commit_msg>Switches default stager to integrated (#449)<commit_after>"use babel";
// @flow

import { Map } from "immutable";
import { connect } from "react-redux";
import { compose, withState, withProps, lifecycle } from "recompose";
import { splitControlPanel } from "../Actions/SplitControlPanel";
import Panel from "../Presenters/Panel";
import { getPackagePanelsFromState } from "../Model/Factory";
import type { DisplayParams } from "../Types/types";
import {
  selectDiagnosticsReducer,
  selectTasksReducer,
  selectPlansReducer,
} from "../../../GlobalSystem/Selectors";
import type { State } from "../../../GlobalSystem/types.js.flow";
import { runTask } from "../../TaskExecutionFeature/Actions/RunTask";
import { killTask } from "../../TaskExecutionFeature/Actions/KillTask";
import {
  selectPertinentTaskID,
  selectTasksOfPlan,
} from "../../TaskExecutionFeature/Selectors/Tasks";
import type { Task } from "../../TaskExecutionFeature/Types/types";
import { unpinPlanConfig } from "../../PlanConfigurationFeature/Actions/UnpinPlanConfig";
import { pinPlanConfig } from "../../PlanConfigurationFeature/Actions/PinPlanConfig";
import { removePlanConfig } from "../../PlanConfigurationFeature/Actions/RemovePlanConfig";
import { openPlanConfigurer } from "../../PlanConfigurationFeature/Actions/OpenPlanConfigurer";
import { selectAllPlans } from "../../PlanConfigurationFeature/Selectors/PlanConfigs";
import type { PlanConfig } from "../../PlanConfigurationFeature/Types/types.js.flow";
import ExecutionsController from "../../LanguageServerProtocolFeature/Model/ExecutionsController";
import type { Range } from "../../LanguageServerProtocolFeature/Types/standard";
import { jumpTo } from "../../DiagnosticsFeature/Actions/JumpTo";
import { selectDiagnosticsOfTask } from "../../DiagnosticsFeature/Selectors/Diagnostics";
import { createTerminal } from "../../TerminalFeature/Actions/CreateTerminal";
import { removeTerminal } from "../../TerminalFeature/Actions/RemoveTerminal";
import type { DevTool } from "../../DevToolsSummaryFeature/Types/types.js.flow";
import TerminalsController from "../../TerminalFeature/Model/TerminalsController";
import { updateSourceStatus } from "../../ConsoleFeature/Actions/UpdateSourceStatus";
import { selectConsoleSourcesReducer } from "../../../GlobalSystem/Selectors";

const selectPertinentTaskIDForPanel = (
  state,
  toolId: string,
  plan: PlanConfig,
) => {
  if (plan === undefined) return "";
  return selectPertinentTaskID(
    selectTasksOfPlan(selectTasksReducer(state), plan),
  );
};

const TaskState = withState(
  "selectedTaskId",
  "setSelectedTaskId",
  ({
    state,
    toolId,
    plan,
  }: {
    state: State,
    toolId: string,
    plan: PlanConfig,
  }) =>
    selectPertinentTaskIDForPanel(state, plan ? plan.tool.id : toolId, plan),
);

const PertinentTaskSelector = lifecycle({
  componentWillReceiveProps(nextProps) {
    let prevPertinentTaskID = selectPertinentTaskIDForPanel(
      this.props.state,
      this.props.toolId,
      this.props.plan,
    );
    let nextPertinentTaskID = selectPertinentTaskIDForPanel(
      nextProps.state,
      nextProps.toolId,
      nextProps.plan,
    );
    if (prevPertinentTaskID != nextPertinentTaskID) {
      this.props.setSelectedTaskId(nextPertinentTaskID);
    }
  },
});

const DiagnosticsSelector = withProps(
  ({ state, selectedTaskId, selection }) => {
    return {
      diagnostics:
        selection.mode && selection.mode.type === "unified-diagnostics"
          ? selectAllPlans(selectPlansReducer(state)).reduce(
              (acc, cur) =>
                cur.packageInfo.path.startsWith(selection.mode.pkg)
                  ? acc.mergeDeep(
                      selectTasksOfPlan(selectTasksReducer(state), cur).reduce(
                        (map, task) =>
                          map.mergeDeep(
                            selectDiagnosticsOfTask(
                              selectDiagnosticsReducer(state),
                              task.id,
                            ),
                          ),
                        Map(),
                      ),
                    )
                  : acc,
              Map(),
            )
          : selectDiagnosticsOfTask(
              selectDiagnosticsReducer(state),
              selectedTaskId,
            ),
    };
  },
);

const ExecutionSelector = withProps(({ getExecution, selectedTaskId }) => {
  const execution = getExecution(selectedTaskId);
  return {
    xtermInstance:
      execution != null && execution.task.strategy.type === "terminal"
        ? execution.terminal
        : undefined,
  };
});

const TerminalSelector = withProps(({ getTerminalExecution, selection }) => {
  if (selection && selection.mode && selection.mode.type === "free-terminal") {
    const execution = getTerminalExecution(selection.mode.id);
    return {
      xtermInstance: execution != null ? execution.terminal : undefined,
    };
  } else return {};
});

const TaskChangeHandler = withProps(({ setSelectedTaskId }) => ({
  onTaskClick: (task: Task) => setSelectedTaskId(task.id),
}));

const TerminalsEventsHandler = lifecycle({
  onTerminalsChange(e) {
    if (e.type === "added") {
      this.props.setSelection({
        plan: null,
        mode: {
          type: "free-terminal",
          id: e.id,
        },
      });
    } else {
      this.props.setSelection({
        plan: null,
        mode: null,
      });
    }
  },
  componentDidMount() {
    this.onTerminalsChange = this.onTerminalsChange.bind(this);
    TerminalsController.eventEmitter.on("change", this.onTerminalsChange);
  },
  componentWillUnmount() {
    TerminalsController.eventEmitter.removeListener(
      "change",
      this.onTerminalsChange,
    );
  },
});

const getTypeSelection = (plan: PlanConfig, state) => {
  if (plan === undefined) return "";
  const lastTaskOfPlan = selectTasksOfPlan(
    selectTasksReducer(state),
    plan,
  ).last();
  if (lastTaskOfPlan) {
    let type =
      lastTaskOfPlan.strategy.type === "terminal" ? "terminal" : "diagnostics";
    if (
      type === "terminal" &&
      selectDiagnosticsOfTask(
        selectDiagnosticsReducer(state),
        lastTaskOfPlan.id,
      ).size > 0 &&
      lastTaskOfPlan.state === "running"
    )
      type = "diagnostics";
    return type;
  } else {
    return "diagnostics";
  }
};

export default compose(
  withState(
    "selection",
    "setSelection",
    (): DisplayParams => ({
      plan: null,
      mode: null,
    }),
  ),
  withProps(({ selection }) => ({
    plan: selection.plan,
    getExecution: selectedTask =>
      ExecutionsController.getExecution(selectedTask),
    getTerminalExecution: id => TerminalsController.getTerminalExecution(id),
  })),
  connect(
    (state: State) => ({
      packagePanels: getPackagePanelsFromState(state),
      isLoading: state.loadingProgress.ongoingPackageRefreshCount !== 0,
      sources: selectConsoleSourcesReducer(state),
      state,
    }),
    (dispatch: (action: Object) => void, props) => ({
      onStartPlan: (plan: PlanConfig) => {
        dispatch(runTask(plan, { type: "integrated" }));
      },
      onStopPlan: (plan: PlanConfig) => {
        dispatch(killTask(plan));
      },
      onPinPlan: (plan: PlanConfig) => {
        dispatch(pinPlanConfig(plan));
      },
      onUnPinPlan: (plan: PlanConfig) => {
        dispatch(unpinPlanConfig(plan));
      },
      onDeletePlan: (plan: PlanConfig) => {
        dispatch(removePlanConfig(plan));
      },
      onSplit: (plan: PlanConfig) => {
        dispatch(splitControlPanel(plan));
      },
      onNewPlan: devtool => {
        dispatch(openPlanConfigurer(devtool));
      },
      onJumpTo: (path: string, range: Range, pending: boolean) => {
        dispatch(jumpTo(path, range, pending));
      },
      onPackageTerminalAdd: (path: string) => {
        dispatch(createTerminal(path));
      },
      onPackageTerminalRemove: (id: string) => {
        dispatch(removeTerminal(id));
      },
      onIsChecked: (source: string, status: boolean) => {
        dispatch(updateSourceStatus(source, status));
      },
    }),
  ),
  lifecycle({
    componentDidMount() {
      if (this.props.defaultPlan) {
        this.props.setSelection({
          mode: {
            type: getTypeSelection(this.props.defaultPlan, this.props.state),
          },
          plan: this.props.defaultPlan,
        });
      }
    },
  }),
  TaskState,
  PertinentTaskSelector,
  ExecutionSelector,
  TerminalSelector,
  DiagnosticsSelector,
  TaskChangeHandler,
  TerminalsEventsHandler,
  withProps(
    ({ xtermInstance, diagnostics, tasks, setSelection, selection }) => ({
      onTerminalClick: (plan: PlanConfig) => {
        setSelection({
          plan,
          mode: {
            type: "terminal",
          },
        });
      },
      onDiagnosticClick: (plan: PlanConfig) => {
        setSelection({
          plan,
          mode: {
            type: "diagnostics",
          },
        });
      },
      onNewPlanClick: (devtool: DevTool) => {
        setSelection({
          plan: null,
          mode: {
            type: "plan-config",
            tool: devtool,
          },
        });
      },
      onConsolePanelClick: () => {
        setSelection({
          plan: null,
          mode: {
            type: "console-panel",
          },
        });
      },
      onUnifiedDiagnosticsClick: (pkg: string) => {
        setSelection({
          plan: null,
          mode: { type: "unified-diagnostics", pkg },
        });
      },
      onPackageTerminalClick: (id: string) => {
        setSelection({
          plan: null,
          mode: { type: "free-terminal", id },
        });
      },
      selection: {
        ...selection,
        mode: {
          ...selection.mode,
          xtermInstance,
          diagnostics,
          tasks,
        },
      },
    }),
  ),
)(Panel);
<|endoftext|>


<commit_before>/**
 * @file DevTools Author Settings panel
 */
(function(
  w,        // Window
  ga,       // Google Analytics
  $,        // document.querySelectorAll
  storage   // Chrome Storage API
){
  'use strict';

  /**
   * Panel module
   * @namespace panel
   * @global
   */
  var panel = (function(){

    /** @private */
    var $select = $('#theme-options')[0];

    /** @private */
    var $range = $('#font-size-input')[0];

    /** @private */
    var $output = $('#font-size-output')[0];

    /** @private */
    var $fontInput = $('#font-family-input')[0];

    /** @private */
    var $palette = $('.palette')[0];

    /** @private */
    var $themeTitle = $('#currentTheme')[0];

    /** @private */
    var $footerLink = $('.footer a')[0];

    /** @private */
    var $alert = $('.alert')[0];

    /** @private */
    var _panel = _panel || {};

    /** @private */
    var _themeJSON = '/dist/scripts/themes.json';

    /** @private */
    var _defaultTheme = '3024';

    /** @private */
    var _defaultFontSize = 14;

    /** @private */
    var _defaultFontFamily = 'Hack';

    /**
     * Find theme colors
     * @function _themeLookUp
     * @param {String} theme - Theme name
     * @returns {Array} List of theme colors in hex
     */
    function _themeLookUp(theme){

      for (var i = 0; i < _panel.themes.length; i++){
        if (_panel.themes[i].name === theme) {
          return _panel.themes[i].colors;
        }
      }

    }

    /**
     * Creates HTML list of colors
     * @function _createLI
     * @param {Array} palette - List of theme colors in hex
     */
    function _createLI(palette){

      /** Filter palette to remove duplicate colors */
      palette = palette.filter(function(item, pos, self) {
        return self.indexOf(item) === pos;
      });

      for (var i = 0; i < palette.length; i++){
        /** Create list item */
        var item = document.createElement('li');

        /** Style list item */
        item.style.backgroundColor = palette[i];
        item.style.width = (100 / palette.length) + '%';

        /** Add item to the list */
        $palette.appendChild(item);
      }

    }

    /**
     * Build select menus like ngOptions
     * @function _buildSelectMenu
     * @param {HTMLElement} menu - Theme select menu element (empty)
     * @param {Object} model - Panel model containing available themes and current settings
     * @returns {HTMLElement} menu - Theme select menu element, with available themes appended
     */
    function _buildSelectMenu(menu, model){

      var options, array;

      /** Get the data attribute value */
      options = menu.dataset.options;

      /** Clean string and create array */
      options = options.replace(/in\s/g, '').split(' ');

      /**
       * Assign array from model by property name
       * using the value from the last item in options
       */
      array = model[options[options.length - 1]];

      for (var j = 0; j < array.length; j++){

        var option = document.createElement('option');

        /** Assign option value & text from array */
        option.value = array[j].name.replace(/\s+/g, '-').toLowerCase();
        option.text  = array[j].name;

        /** Select currentTheme option */
        if (model.currentTheme === array[j].name){
          option.selected = 'selected';
        }

        menu.add(option, null);
      }

      return menu;

    }

    /**
     * Object.observe handler for panel model settings updates
     * @function _observer
     * @param {Array} changes - Array of change objects from Object.observe
     */
    function _observer(changes){

      /** Recreate $palette using current theme */
      function updatePalette(theme){
        var children = $palette.querySelectorAll('li');

        if (children.length){
          for (var i = 0; i < children.length; i++){
            $palette.removeChild(children[i]);
          }
        }

        _createLI(_themeLookUp(theme));
      }

      console.log(changes);

      /** Update UI element text based on change */
      changes.forEach(function(change){
        if (change.name === 'currentTheme') {
          $themeTitle.innerHTML = change.object.currentTheme;
          updatePalette(change.object.currentTheme);
        }

        else if (change.name === 'currentFontSize') {
          $range.value = $output.value = change.object.currentFontSize;
        }

        else if (change.name === 'currentFontFamily') {
          $fontInput.value = change.object.currentFontFamily;
        }

        if (change.type === 'update'){
          $alert.style.display = 'block';
        }
      });

    }

    /**
     * Setup event listeners and get settings from storage
     * @function _panelSetup
     */
    function _panelSetup(){

      /** Observe changes to _panel model */
      Object.observe(_panel, _observer, ['add', 'update']);

      /** Listen for changes to the select menu */
      $select.addEventListener('change', setTheme);

      /** Listen for changes to the text input */
      $fontInput.addEventListener('change', setFontFamily);

      /** Listen for changes to the range input */
      $range.addEventListener('change', setFontSize);

      /** Listen for click on footer element */
      $footerLink.addEventListener('click', function(){
        ga('send', 'event', 'Link', 'Click', 'Mike King on GitHub');
      });

      /** Get current theme setting from storage */
      storage.get('devtools-theme', function(object){
        _panel.currentTheme = getTheme( _panel.themes, object['devtools-theme'] );
        _buildSelectMenu($select, _panel);

        /** Send Google Analytics 'Install' event on initial install */
        if (!object['devtools-theme'] && _panel.currentTheme === _defaultTheme){
          ga('send', 'event', 'Install', 'Install', 'Devtools Author', 1);
        }
      });

      /** Get current `font-family` setting from storage */
      storage.get('devtools-fontFamily', function(object){
        _panel.currentFontFamily = getFontFamily(object['devtools-fontFamily']);
      });

      /** Get current `font-size` setting from storage */
      storage.get('devtools-fontSize', function(object){
        _panel.currentFontSize = getFontSize(object['devtools-fontSize']);
      });

    }

    /**
     * Set & save theme based on select menu change event
     * @function setTheme
     * @memberof! app
     * @param {Event} event - Event object
     * @param {Object} obj - Object for theme settings defaults
     */
    function setTheme(event, obj){

      function save(theme){
        storage.set({ 'devtools-theme': theme.value }, function(){
          _panel.currentTheme = theme.text;
        });
        return theme.value;
      }

      if (event && event.type === 'change'){
        var el     = event.target || event.srcElement;
        var option = el.options[el.selectedIndex];
        return save(option);
      } else if (event === null && obj){
        return save(obj);
      }

    }

    /**
     * Set & save `font-family` based on input change event
     * @function setFontFamily
     * @memberof! app
     * @param {Event} event - Event object
     * @param {Object} value - Value for `font-family` settings
     */
    function setFontFamily(event, value){

      function save(fontFamily){
        storage.set({ 'devtools-fontFamily': fontFamily }, function(){
          _panel.currentFontFamily = fontFamily;
        });
        return fontFamily;
      }

      if (event && event.type === 'change'){
        var el = event.target || event.srcElement;
        return save(el.value);
      } else if (event === null && value){
        return save(value);
      }

    }

    /**
     * Set & save `font-size` based on input menu change event
     * @function setFontSize
     * @memberof! app
     * @param {Event} event - Event object
     * @param {Object} value - Value for `font-size` settings
     */
    function setFontSize(event, value){

      function save(fontSize){
        storage.set({ 'devtools-fontSize': fontSize }, function(){
          _panel.currentFontSize = fontSize;
        });
        return fontSize;
      }

      if (event && event.type === 'change'){
        var el = event.target || event.srcElement;
        return save(el.value);
      } else if (event === null && value){
        return save(value);
      }

    }

    /**
     * Get theme settings
     * @function getTheme
     * @memberof! app
     * @param {Array} array - List of themes
     * @param {String} string - Value for theme settings
     * @returns {String} Theme name
     */
    function getTheme(array, string){

      if (!array || !string){
        setTheme(null, {
          value: _defaultTheme.replace(/\s+/g, '-').toLowerCase(),
          text: _defaultTheme
        });
        return _defaultTheme;
      }

      for (var i = 0; i < array.length; i++){
        if (array[i].name.replace(/\s+/g, '-').toLowerCase() === string){
          return array[i].name;
        }
      }

    }

    /**
     * Get `font-family` settings
     * @function getFontFamily
     * @memberof! app
     * @param {String} value - Value for `font-family` settings
     * @returns {String} value - Value for `font-family` settings
     */
    function getFontFamily(value){

      if (!value){
        setFontFamily(null, _defaultFontFamily);
        return _defaultFontFamily;
      } else {
        return value;
      }

    }

    /**
     * Get `font-size` settings
     * @function getFontSize
     * @memberof! app
     * @param {String} value - Value for `font-size` settings
     * @returns {String} value - Value for `font-size` settings
     */
    function getFontSize(value){

      if (!value){
        setFontSize(null, _defaultFontSize);
        return _defaultFontSize;
      } else {
        return value;
      }

    }

    /**
     * GET themes JSON and setup panel settings
     * @function init
     * @memberof! app
     */
    function init(){

      var ajax = new XMLHttpRequest();

      ajax.open('GET', _themeJSON);
      ajax.send(null);

      ajax.onreadystatechange = function(){
        if (ajax.readyState === 4) {
          if (ajax.status === 200) {
            _panel.themes = JSON.parse(ajax.responseText);

            _panel.themes.sort(function(a, b){
              if(a.name < b.name) { return -1; }
              if(a.name > b.name) { return 1; }
              return 0;
            });

            return _panelSetup();
          } else {
            return console.log('Status Code: ' + ajax.status + '\nThere was an error with your request');
          }
        }
      };

    }

    /** Public methods */
    return {
      init: init,
      getTheme: getTheme,
      setTheme: setTheme,
      getFontSize: getFontSize,
      setFontSize: setFontSize,
      getFontFamily: getFontFamily,
      setFontFamily: setFontFamily
    };
  })();

  /** Initialize panel */
  panel.init();

  /** Export as global */
  w.panel = panel;

})(
  /** Globals */
  window,
  window.ga,
  document.querySelectorAll.bind(document),
  chrome.storage.sync
);<commit_msg>Setup Object.defineProperty custom setters and getters for _panel model<commit_after>/**
 * @file DevTools Author Settings panel
 */
(function(
  w,        // Window
  ga,       // Google Analytics
  $,        // document.querySelectorAll
  storage   // Chrome Storage API
){
  'use strict';

  /**
   * Panel module
   * @namespace panel
   * @global
   */
  var panel = (function(){

    /** @private */
    var $select = $('#theme-options')[0];

    /** @private */
    var $range = $('#font-size-input')[0];

    /** @private */
    var $output = $('#font-size-output')[0];

    /** @private */
    var $fontInput = $('#font-family-input')[0];

    /** @private */
    var $palette = $('.palette')[0];

    /** @private */
    var $themeTitle = $('#currentTheme')[0];

    /** @private */
    var $footerLink = $('.footer a')[0];

    /** @private */
    var $alert = $('.alert')[0];

    /** @private */
    var _panel = _panel || {};

    /** @private */
    var _themeJSON = '/dist/scripts/themes.json';

    /** @private */
    var _defaultTheme = '3024';

    /** @private */
    var _defaultFontSize = 14;

    /** @private */
    var _defaultFontFamily = 'Hack';

    /** @private */
    var _currentTheme = null;

    /** @private */
    var _currentFontSize = null;

    /** @private */
    var _currentFontFamily = null;

    /**
     * Creates HTML list of colors
     * @function _createLI
     * @param {Array} palette - List of theme colors in hex
     */
    function _createLI(palette){

      /** Filter palette to remove duplicate colors */
      palette = palette.filter(function(item, pos, self) {
        return self.indexOf(item) === pos;
      });

      for (var i = 0; i < palette.length; i++){
        /** Create list item */
        var item = document.createElement('li');

        /** Style list item */
        item.style.backgroundColor = palette[i];
        item.style.width = (100 / palette.length) + '%';

        /** Add item to the list */
        $palette.appendChild(item);
      }

    }

    /**
     * Find theme colors
     * @function _themeLookUp
     * @param {String} theme - Theme name
     * @returns {Array} List of theme colors in hex
     */
    function _themeLookUp(theme){

      for (var i = 0; i < _panel.themes.length; i++){
        if (_panel.themes[i].name === theme) {
          return _panel.themes[i].colors;
        }
      }

    }

    /**
     * Recreate $palette using current theme
     * @function _updatePalette
     * @param {String} theme - Currently selected theme name
     */
    function _updatePalette(theme){
      var children = $palette.querySelectorAll('li');

      if (children.length){
        for (var i = 0; i < children.length; i++){
          $palette.removeChild(children[i]);
        }
      }

      _createLI(_themeLookUp(theme));
    }

    /**
     * Build select menus like ngOptions
     * @function _buildSelectMenu
     * @param {HTMLElement} menu - Theme select menu element (empty)
     * @param {Object} model - Panel model containing available themes and current settings
     * @returns {HTMLElement} menu - Theme select menu element, with available themes appended
     */
    function _buildSelectMenu(menu, model){

      var options, array;

      /** Get the data attribute value */
      options = menu.dataset.options;

      /** Clean string and create array */
      options = options.replace(/in\s/g, '').split(' ');

      /**
       * Assign array from model by property name
       * using the value from the last item in options
       */
      array = model[options[options.length - 1]];

      for (var j = 0; j < array.length; j++){

        var option = document.createElement('option');

        /** Assign option value & text from array */
        option.value = array[j].name.replace(/\s+/g, '-').toLowerCase();
        option.text  = array[j].name;

        /** Select currentTheme option */
        if (model.currentTheme === array[j].name){
          option.selected = 'selected';
        }

        menu.add(option, null);
      }

      return menu;

    }

    /**
     * Alert notification test
     * @function _notification
     * @param {String} oldValue - Original value for alert notification test
     * @param {String} newValue - New value for alert notification test
     */
    function _notification(oldValue, newValue){
      if (oldValue !== newValue){
        $alert.style.display = 'block';
      }
    }

    /**
     * Object.defineProperty custom setters and getters for _panel model
     * @function _panelModelSetup
     */
    function _panelModelSetup(){

      /** Observe changes to _panel.currentTheme */
      Object.defineProperty(_panel, 'currentTheme', {
        enumerable: true,
        configurable: true,
        get: function() {
          return _currentTheme;
        },
        set: function(newValue) {
          _notification(_currentTheme, newValue);
          $themeTitle.innerHTML = _currentTheme = newValue;
          _updatePalette(_currentTheme);
        }
      });

      /** Observe changes to _panel.currentFontSize */
      Object.defineProperty(_panel, 'currentFontSize', {
        enumerable: true,
        configurable: true,
        get: function() {
          return _currentFontSize;
        },
        set: function(newValue) {
          _notification(_currentFontSize, newValue);
          $range.value = $output.value = _currentFontSize = newValue;
        }
      });

      /** Observe changes to _panel.currentFontFamily */
      Object.defineProperty(_panel, 'currentFontFamily', {
        enumerable: true,
        configurable: true,
        get: function() {
          return _currentFontFamily;
        },
        set: function(newValue) {
          _notification(_currentFontFamily, newValue);
          $fontInput.value = _currentFontFamily = newValue;
        }
      });
    }

    /**
     * Setup event listeners and get settings from storage
     * @function _panelSetup
     */
    function _panelSetup(){

      /** Observe changes to _panel model */
      _panelModelSetup();

      /** Listen for changes to the select menu */
      $select.addEventListener('change', setTheme);

      /** Listen for changes to the text input */
      $fontInput.addEventListener('change', setFontFamily);

      /** Listen for changes to the range input */
      $range.addEventListener('change', setFontSize);

      /** Listen for click on footer element */
      $footerLink.addEventListener('click', function(){
        ga('send', 'event', 'Link', 'Click', 'Mike King on GitHub');
      });

      /** Get current theme setting from storage */
      storage.get('devtools-theme', function(object){
        _panel.currentTheme = _currentTheme = getTheme( _panel.themes, object['devtools-theme'] );
        _buildSelectMenu($select, _panel);

        /** Send Google Analytics 'Install' event on initial install */
        if (!object['devtools-theme'] && _panel.currentTheme === _defaultTheme){
          ga('send', 'event', 'Install', 'Install', 'Devtools Author', 1);
        }
      });

      /** Get current `font-family` setting from storage */
      storage.get('devtools-fontFamily', function(object){
        _panel.currentFontFamily = _currentFontFamily = getFontFamily(object['devtools-fontFamily']);
      });

      /** Get current `font-size` setting from storage */
      storage.get('devtools-fontSize', function(object){
        _panel.currentFontSize = _currentFontSize = getFontSize(object['devtools-fontSize']);
      });

    }

    /**
     * Set & save theme based on select menu change event
     * @function setTheme
     * @memberof! app
     * @param {Event} event - Event object
     * @param {Object} obj - Object for theme settings defaults
     */
    function setTheme(event, obj){

      function save(theme){
        storage.set({ 'devtools-theme': theme.value }, function(){
          _panel.currentTheme = theme.text;
        });
        return theme.value;
      }

      if (event && event.type === 'change'){
        var el     = event.target || event.srcElement;
        var option = el.options[el.selectedIndex];
        return save(option);
      } else if (event === null && obj){
        return save(obj);
      }

    }

    /**
     * Set & save `font-family` based on input change event
     * @function setFontFamily
     * @memberof! app
     * @param {Event} event - Event object
     * @param {Object} value - Value for `font-family` settings
     */
    function setFontFamily(event, value){

      function save(fontFamily){
        storage.set({ 'devtools-fontFamily': fontFamily }, function(){
          _panel.currentFontFamily = fontFamily;
        });
        return fontFamily;
      }

      if (event && event.type === 'change'){
        var el = event.target || event.srcElement;
        return save(el.value);
      } else if (event === null && value){
        return save(value);
      }

    }

    /**
     * Set & save `font-size` based on input menu change event
     * @function setFontSize
     * @memberof! app
     * @param {Event} event - Event object
     * @param {Object} value - Value for `font-size` settings
     */
    function setFontSize(event, value){

      function save(fontSize){
        storage.set({ 'devtools-fontSize': fontSize }, function(){
          _panel.currentFontSize = fontSize;
        });
        return fontSize;
      }

      if (event && event.type === 'change'){
        var el = event.target || event.srcElement;
        return save(el.value);
      } else if (event === null && value){
        return save(value);
      }

    }

    /**
     * Get theme settings
     * @function getTheme
     * @memberof! app
     * @param {Array} array - List of themes
     * @param {String} string - Value for theme settings
     * @returns {String} Theme name
     */
    function getTheme(array, string){

      if (!array || !string){
        setTheme(null, {
          value: _defaultTheme.replace(/\s+/g, '-').toLowerCase(),
          text: _defaultTheme
        });
        return _defaultTheme;
      }

      for (var i = 0; i < array.length; i++){
        if (array[i].name.replace(/\s+/g, '-').toLowerCase() === string){
          return array[i].name;
        }
      }

    }

    /**
     * Get `font-family` settings
     * @function getFontFamily
     * @memberof! app
     * @param {String} value - Value for `font-family` settings
     * @returns {String} value - Value for `font-family` settings
     */
    function getFontFamily(value){

      if (!value){
        setFontFamily(null, _defaultFontFamily);
        return _defaultFontFamily;
      } else {
        return value;
      }

    }

    /**
     * Get `font-size` settings
     * @function getFontSize
     * @memberof! app
     * @param {String} value - Value for `font-size` settings
     * @returns {String} value - Value for `font-size` settings
     */
    function getFontSize(value){

      if (!value){
        setFontSize(null, _defaultFontSize);
        return _defaultFontSize;
      } else {
        return value;
      }

    }

    /**
     * GET themes JSON and setup panel settings
     * @function init
     * @memberof! app
     */
    function init(){

      var ajax = new XMLHttpRequest();

      ajax.open('GET', _themeJSON);
      ajax.send(null);

      ajax.onreadystatechange = function(){
        if (ajax.readyState === 4) {
          if (ajax.status === 200) {
            _panel.themes = JSON.parse(ajax.responseText);

            _panel.themes.sort(function(a, b){
              if(a.name < b.name) { return -1; }
              if(a.name > b.name) { return 1; }
              return 0;
            });

            return _panelSetup();
          } else {
            return console.log('Status Code: ' + ajax.status + '\nThere was an error with your request');
          }
        }
      };

    }

    /** Public methods */
    return {
      init: init,
      getTheme: getTheme,
      setTheme: setTheme,
      getFontSize: getFontSize,
      setFontSize: setFontSize,
      getFontFamily: getFontFamily,
      setFontFamily: setFontFamily
    };
  })();

  /** Initialize panel */
  panel.init();

  /** Export as global */
  w.panel = panel;

})(
  /** Globals */
  window,
  window.ga,
  document.querySelectorAll.bind(document),
  chrome.storage.sync
);<|endoftext|>


<commit_before>// Copyright 2015, University of Colorado Boulder

/**
 * Light bulb, made to 'glow' by modulating opacity of the 'on' image.
 *
 * @author Chris Malley (PixelZoom, Inc.)
 */
define( function( require ) {
  'use strict';

  // modules
  var Image = require( 'SCENERY/nodes/Image' );
  var inherit = require( 'PHET_CORE/inherit' );
  var Node = require( 'SCENERY/nodes/Node' );
  var Util = require( 'DOT/Util' );
  var LightRaysNode = require( 'SCENERY_PHET/LightRaysNode' );
  var sceneryPhet = require( 'SCENERY_PHET/sceneryPhet' );
  var Rectangle = require( 'DOT/Rectangle' );

  // images
  var onImage = require( 'mipmap!SCENERY_PHET/light-bulb-on.png' );
  var offImage = require( 'mipmap!SCENERY_PHET/light-bulb-off.png' );

  /**
   * @param {Property.<number>} brightnessProperty 0 (off) to 1 (full brightness)
   * @param {Object} [options]
   * @constructor
   */
  function LightBulbNode( brightnessProperty, options ) {

    var defaultOptions = {
      bulbImageScale: 0.33,
      rayStroke: 'yellow',
      minRays: 8,
      maxRays: 60,
      minRayLength: 0,
      maxRayLength: 200,
      longRayLineWidth: 1.5, // for long rays
      mediumRayLineWidth: 1, // for medium-length rays
      shortRayLineWidth: 0.5 // for short rays
    };

    options = _.extend( {}, defaultOptions, options ); // don't modify defaultOptions!

    // @private
    this.onNode = new Image( onImage, {
      scale: options.bulbImageScale,
      centerX: 0,
      bottom: 0
    } ); // @private

    var offNode = new Image( offImage, {
      scale: options.bulbImageScale,
      centerX: this.onNode.centerX,
      bottom: this.onNode.bottom
    } );

    // rays
    var bulbRadius = offNode.width / 2; // use 'off' node, the 'on' node is wider because it has a glow around it.
    var rayOptions = _.pick( options, _.keys( defaultOptions ) ); // cherry-pick options that are specific to rays
    rayOptions.x = this.onNode.centerX;
    rayOptions.y = offNode.top + bulbRadius;
    this.raysNode = new LightRaysNode( bulbRadius, rayOptions ); // @private

    options.children = [ this.raysNode, offNode, this.onNode ];
    Node.call( this, options );

    var brightnessObserver = function() { this.update(); }; // @private
    this.brightnessProperty = brightnessProperty; // @private
    this.brightnessProperty.link( this.brightnessObserver );

    // this.mouseArea = new Rectangle( 0, 0, 100, 100 );
    // this.touchArea = new Rectangle( 200, 200, 300, 400 );

    // @private
    this.disposeLightBulbNode = function() {
      brightnessProperty.unlink( brightnessObserver );
    };
  }

  sceneryPhet.register( 'LightBulbNode', LightBulbNode );

  inherit( Node, LightBulbNode, {

    // @public Ensures that this object is eligible for GC
    dispose: function() {
      this.disposeLightBulbNode();
    },

    // @private
    update: function() {
      if ( this.visible ) {
        var brightness = this.brightnessProperty.value;
        assert && assert( brightness >= 0 && brightness <= 1 );
        this.onNode.visible = ( brightness > 0 );
        if ( this.onNode.visible ) {
          this.onNode.opacity = Util.linear( 0, 1, 0.3, 1, brightness );
        }
        this.raysNode.setBrightness( brightness );
      }
    },

    // @override update when this node becomes visible
    setVisible: function( visible ) {
      var wasVisible = this.visible;
      Node.prototype.setVisible.call( this, visible );
      if ( !wasVisible && visible ) {
        this.update();
      }
    }
  } );

  return LightBulbNode;
} );<commit_msg>Cleanup in LightBulbNode, see https://github.com/phetsims/circuit-construction-kit-black-box-study/issues/5<commit_after>// Copyright 2015, University of Colorado Boulder

/**
 * Light bulb, made to 'glow' by modulating opacity of the 'on' image.
 *
 * @author Chris Malley (PixelZoom, Inc.)
 */
define( function( require ) {
  'use strict';

  // modules
  var Image = require( 'SCENERY/nodes/Image' );
  var inherit = require( 'PHET_CORE/inherit' );
  var Node = require( 'SCENERY/nodes/Node' );
  var Util = require( 'DOT/Util' );
  var LightRaysNode = require( 'SCENERY_PHET/LightRaysNode' );
  var sceneryPhet = require( 'SCENERY_PHET/sceneryPhet' );
  var Rectangle = require( 'DOT/Rectangle' );

  // images
  var onImage = require( 'mipmap!SCENERY_PHET/light-bulb-on.png' );
  var offImage = require( 'mipmap!SCENERY_PHET/light-bulb-off.png' );

  /**
   * @param {Property.<number>} brightnessProperty 0 (off) to 1 (full brightness)
   * @param {Object} [options]
   * @constructor
   */
  function LightBulbNode( brightnessProperty, options ) {

    var defaultOptions = {
      bulbImageScale: 0.33,
      rayStroke: 'yellow',
      minRays: 8,
      maxRays: 60,
      minRayLength: 0,
      maxRayLength: 200,
      longRayLineWidth: 1.5, // for long rays
      mediumRayLineWidth: 1, // for medium-length rays
      shortRayLineWidth: 0.5 // for short rays
    };

    options = _.extend( {}, defaultOptions, options ); // don't modify defaultOptions!

    // @private
    this.onNode = new Image( onImage, {
      scale: options.bulbImageScale,
      centerX: 0,
      bottom: 0
    } ); // @private

    var offNode = new Image( offImage, {
      scale: options.bulbImageScale,
      centerX: this.onNode.centerX,
      bottom: this.onNode.bottom
    } );

    // rays
    var bulbRadius = offNode.width / 2; // use 'off' node, the 'on' node is wider because it has a glow around it.
    var rayOptions = _.pick( options, _.keys( defaultOptions ) ); // cherry-pick options that are specific to rays
    rayOptions.x = this.onNode.centerX;
    rayOptions.y = offNode.top + bulbRadius;
    this.raysNode = new LightRaysNode( bulbRadius, rayOptions ); // @private

    options.children = [ this.raysNode, offNode, this.onNode ];
    Node.call( this, options );
    this.brightnessProperty = brightnessProperty;

    var brightnessObserver = function() { this.update(); }; // @private
    brightnessProperty.link( brightnessObserver );

    // this.mouseArea = new Rectangle( 0, 0, 100, 100 );
    // this.touchArea = new Rectangle( 200, 200, 300, 400 );

    // @private
    this.disposeLightBulbNode = function() {
      brightnessProperty.unlink( brightnessObserver );
    };
  }

  sceneryPhet.register( 'LightBulbNode', LightBulbNode );

  inherit( Node, LightBulbNode, {

    // @public Ensures that this object is eligible for GC
    dispose: function() {
      this.disposeLightBulbNode();
    },

    // @private
    update: function() {
      if ( this.visible ) {
        var brightness = this.brightnessProperty.value;
        assert && assert( brightness >= 0 && brightness <= 1 );
        this.onNode.visible = ( brightness > 0 );
        if ( this.onNode.visible ) {
          this.onNode.opacity = Util.linear( 0, 1, 0.3, 1, brightness );
        }
        this.raysNode.setBrightness( brightness );
      }
    },

    // @override update when this node becomes visible
    setVisible: function( visible ) {
      var wasVisible = this.visible;
      Node.prototype.setVisible.call( this, visible );
      if ( !wasVisible && visible ) {
        this.update();
      }
    }
  } );

  return LightBulbNode;
} );<|endoftext|>


<commit_before><commit_msg>Eventable class.<commit_after>export default class Eventable {
  constructor() {
    this._eventListeners = {};
  }

  addEventListener(event_name, callback) {
    if (!this._eventListeners.hasOwnProperty(event_name))
      this._eventListeners[event_name] = [];

    this._eventListeners[event_name].push(callback);
  }

  removeEventListener(event_name, callback) {
    let index;

    if (!this._eventListeners.hasOwnProperty(event_name)) return false;

    if ((index = this._eventListeners[event_name].indexOf(callback)) >= 0) {
      this._eventListeners[event_name].splice(index, 1);
      return true;
    }

    return false;
  }

  dispatchEvent(event_name) {
    let i;
    const parameters = Array.prototype.splice.call(arguments, 1);

    if (this._eventListeners.hasOwnProperty(event_name)) {
      for (i = 0; i < this._eventListeners[event_name].length; i++)
        this._eventListeners[event_name][i].apply(this, parameters);
    }
  }

  static make(obj) {
    obj.prototype.addEventListener = Eventable.prototype.addEventListener;
    obj.prototype.removeEventListener = Eventable.prototype.removeEventListener;
    obj.prototype.dispatchEvent = Eventable.prototype.dispatchEvent;
  }
}
<|endoftext|>


<commit_before>import { chain } from 'lodash'

export default function resolveUnions(data, sqlAST) {
  if (!data || (Array.isArray(data) && data.length === 0)) {
    return
  }

  if (sqlAST.type === 'union') {
    for (let typeName in sqlAST.typedChildren) {
      const suffix = '@' + typeName
      const children = sqlAST.typedChildren[typeName]
      for (let child of children) {
        const fieldName = child.fieldName
        const qualifiedName = child.fieldName + suffix
        if (Array.isArray(data)) {
          for (let obj of data) {
            const qualifiedValue = obj[qualifiedName]
            delete obj[qualifiedName]
            if (obj[fieldName] == null && qualifiedValue) {
              obj[fieldName] = qualifiedValue
            }
          }
          if (child.type === 'table' || child.type === 'union') {
            const nextLevelData = chain(data).filter(obj => obj !== null).flatMap(obj => obj[fieldName]).value()
            resolveUnions(nextLevelData, child)
          }
        } else {
          const qualifiedValue = data[qualifiedName]
          delete data[qualifiedName]
          if (data[fieldName] == null && qualifiedValue) {
            data[fieldName] = qualifiedValue
          }
          if (child.type === 'table' || child.type === 'union') {
            resolveUnions(data[fieldName], child)
          }
        }
      }
    }
  }
  if (sqlAST.type === 'table' || sqlAST.type === 'union') {
    for (let child of sqlAST.children) {
      if ((child.type === 'table' || child.type === 'union') && !child.sqlBatch) {
        const fieldName = child.fieldName
        if (Array.isArray(data)) {
          const nextLevelData = chain(data).filter(obj => obj !== null).flatMap(obj => obj[fieldName]).value()
          resolveUnions(nextLevelData, child)
        } else {
          resolveUnions(data[fieldName], child)
        }
      }
    }
  }
}
<commit_msg>fix bug<commit_after>import { chain } from 'lodash'

export default function resolveUnions(data, sqlAST) {
  if (!data || (Array.isArray(data) && data.length === 0)) {
    return
  }

  if (sqlAST.type === 'union') {
    for (let typeName in sqlAST.typedChildren) {
      const suffix = '@' + typeName
      const children = sqlAST.typedChildren[typeName]
      for (let child of children) {
        const fieldName = child.fieldName
        const qualifiedName = child.fieldName + suffix
        if (Array.isArray(data)) {
          for (let obj of data) {
            const qualifiedValue = obj[qualifiedName]
            delete obj[qualifiedName]
            if (obj[fieldName] == null && qualifiedValue) {
              obj[fieldName] = qualifiedValue
            }
          }
          if (child.type === 'table' || child.type === 'union') {
            const nextLevelData = chain(data)
              .filter(obj => obj !== null)
              .flatMap(obj => obj[fieldName])
              .filter(obj => obj !== null)
              .value()
            resolveUnions(nextLevelData, child)
          }
        } else {
          const qualifiedValue = data[qualifiedName]
          delete data[qualifiedName]
          if (data[fieldName] == null && qualifiedValue) {
            data[fieldName] = qualifiedValue
          }
          if (child.type === 'table' || child.type === 'union') {
            resolveUnions(data[fieldName], child)
          }
        }
      }
    }
  }
  if (sqlAST.type === 'table' || sqlAST.type === 'union') {
    for (let child of sqlAST.children) {
      if ((child.type === 'table' || child.type === 'union') && !child.sqlBatch) {
        const fieldName = child.fieldName
        if (Array.isArray(data)) {
          const nextLevelData = chain(data)
            .filter(obj => obj !== null)
            .flatMap(obj => obj[fieldName])
            .filter(obj => obj !== null)
            .value()
          resolveUnions(nextLevelData, child)
        } else {
          resolveUnions(data[fieldName], child)
        }
      }
    }
  }
}
<|endoftext|>


<commit_before>javascript: (function () {

var w = null;
var kDoc = null;
var kObj = null;

if (typeof window.KindleReaderContextMenu !== 'undefined') {
    w = window;
} else if (window.length) {
    for (var i=0;i<window.length;i++) {
        if (typeof window[i].KindleReaderContextMenu !== 'undefined') {
            w = window[i];
            break;
        }
    }
}

if (typeof w === 'object') {
    kObj = w.KindleReaderContextMenu;
    kDoc = w.document;

    if (typeof kObj.ACRExtensions === 'undefined') {
        kObj.ACRExtensions = true;
        var oldMethod = kObj.show;
        kObj.show = function () {
            var res = oldMethod.apply(kObj, arguments);
            if (typeof (arguments[3]) !== 'undefined' && typeof (arguments[3]['start']) !== 'undefined') {
                var sId = arguments[3].start;
                var eId = arguments[3].end;
                var outArr = {};
                $('iframe', kDoc).each(function (j, textIframe) {
                    for (var elId=sId;elId<=eId;elId++) {
                        $('#'+elId, $(textIframe).contents()).each(function (k, textSpan) {
                            outArr[elId] = $(textSpan).text();
                        });
                    }
                });

                var outStr = '';
                for (var p in outArr) outStr += ' ' + outArr[p];
            }

            $('#ACRExtensions_copyB_sep', kDoc).remove();
            $('#ACRExtensions_copyB', kDoc).remove();
            var sepEl = $('

');
            var copyB = $('
Copy
');
            $('#kindle_menu_border', kDoc).append(sepEl).append(copyB);
            $('#ACRExtensions_copyB', kDoc).click(function (evt) {
                w.prompt('Selection:', outStr);
            });

            return res;
        };

        alert('ACRExtensions is now active.');
    } else {
        alert('ACRExtensions is already active.');
    }
} else {
    alert('Error: ACRExtensions is not active. Te Amazon Cloud Reader window could not be found.');
}
})();

<commit_msg>WIP switch to a document range mechanism with popup<commit_after>javascript: (function () {

var w = null;
var kDoc = null;
var kObj = null;

if (typeof window.KindleReaderContextMenu !== 'undefined') {
    w = window;
} else if (window.length) {
    for (var i=0;i<window.length;i++) {
        if (typeof window[i].KindleReaderContextMenu !== 'undefined') {
            w = window[i];
            break;
        }
    }
}

if (typeof w === 'object') {
    kObj = w.KindleReaderContextMenu;
    kDoc = w.document;

    if (typeof kObj.ACRExtensions === 'undefined') {
        kObj.ACRExtensions = true;
        var oldMethod = kObj.show;
        kObj.show = function () {
            var res = oldMethod.apply(kObj, arguments);
            var txtDoc = null;
            var r = null;

            if (typeof (arguments[3]) !== 'undefined' && typeof (arguments[3]['start']) !== 'undefined') {
                var sId = arguments[3]['start'];
                var eId = arguments[3]['end'];

                $('iframe', kDoc).each(function (j, textIframe) {
                    if ($('#'+sId, $(textIframe))) {
                        txtDoc = $(textIframe).contents();
                        return false;
                    }
                });

                if (txtDoc) {
                    r = txtDoc.createRange();
                    r.setStartBefore($('#'+sId, txtDoc).first());
                    r.setEndAfter($('#'+eId, txtDoc).first());
                }
            }

            $('#ACRExtensions_copyB_sep', kDoc).remove();
            $('#ACRExtensions_copyB', kDoc).remove();
            var sepEl = $('

');
            var copyB = $('
Copy
');
            $('#kindle_menu_border', kDoc).append(sepEl).append(copyB);
            $('#ACRExtensions_copyB', kDoc).click(function (evt) {
                if (r) {
                    var newW = window.open(null, null, "height=400,width=400");
                    newW.document.body.appendChild(r.cloneContents());
                }
            });

            return res;
        };

        alert('ACRExtensions is now active.');
    } else {
        alert('ACRExtensions is already active.');
    }
} else {
    alert('Error: ACRExtensions is not active. Te Amazon Cloud Reader window could not be found.');
}
})();

<|endoftext|>


<commit_before>;(function($) {
    var DEFAULT_OPTIONS = {
        delay: 250
    }

    $.fn.hoverPopover = function(options) {
        var options = $.extend({}, DEFAULT_OPTIONS, options)

        this.each(function() {
            var $this = $(this)
            var popover = $this.data('bs.popover')

            var hovered = false

            $this.mouseover(function(event) {
                if (!popover.$tip || !popover.$tip.is(':visible')) {
                    $this.popover('show')
                }
            })
            .mouseleave(function(event) {
                setTimeout(function() {
                    if (!hovered) {
                        $this.popover('hide')
                    }
                }, options.delay)
            })

            var timeout = new Timeout(function() {
                hovered = false
                $this.popover('hide')
            }, options.delay)

            $this.one('shown.bs.popover', function(event) {
                popover.$tip.mouseenter(function(event) {
                    timeout.clear()
                    hovered = true
                })
                .mouseleave(function(event) {
                    timeout.set()
                })
            })
        })

        return this
    }

    var Timeout = function(callback, delay) {
        this.callback = callback
        this.delay = delay
        this.timeout = undefined
    }

    Timeout.prototype.set = function() {
        var self = this
        if (this.timeout === undefined) {
            this.timeout = setTimeout(function() {
                self.callback()
                self.timeout = undefined
            }, this.delay)
        }
    }

    Timeout.prototype.clear = function() {
        this.timeout = clearTimeout(this.timeout)
    }
}(jQuery))
<commit_msg>hiding moved to clearable single instance timeout<commit_after>;(function($) {
    var DEFAULT_OPTIONS = {
        delay: 250
    }

    $.fn.hoverPopover = function(options) {
        var options = $.extend({}, DEFAULT_OPTIONS, options)

        this.each(function() {
            var $this = $(this)
            var popover = $this.data('bs.popover')

            var hideTimeout = new Timeout(function() {
                $this.popover('hide')
            }, options.delay)

            $this.mouseover(function(event) {
                if (!popover.$tip || !popover.$tip.is(':visible')) {
                    $this.popover('show')
                }
                hideTimeout.clear()
            })
            .mouseleave(function(event) {
                hideTimeout.set()
            })

            $this.one('shown.bs.popover', function(event) {
                popover.$tip.mouseenter(function(event) {
                    hideTimeout.clear()
                })
                .mouseleave(function(event) {
                    hideTimeout.set()
                })
            })
        })

        return this
    }

    var Timeout = function(callback, delay) {
        this.callback = callback
        this.delay = delay
        this.timeout = undefined
    }

    Timeout.prototype.set = function() {
        var self = this
        if (this.timeout === undefined) {
            this.timeout = setTimeout(function() {
                self.callback()
                self.timeout = undefined
            }, this.delay)
        }
    }

    Timeout.prototype.clear = function() {
        this.timeout = clearTimeout(this.timeout)
    }
}(jQuery))
<|endoftext|>


<commit_before>var fontOptionsEle;
var fs;
var xhr = new XMLHttpRequest();
var ajaxMethod;
var ajaxUrl;
var message = {};
var recommendLoaded = false;
var recommendInner = document.getElementById('story-recommend');

message.head = {};
message.head.transactiontype = '61008';
message.head.source = 'web';
message.body = {};
message.body.ielement = {};
message.body.ielement.storyid = '';

if (/127\.0|localhost|192\.168/.test(window.location.href)) {
	ajaxMethod = 'GET';
	ajaxUrl = '/api/page/recommend.json';
} else {
	ajaxMethod = 'POST';
	ajaxUrl = '/eaclient/apijson.php';
}

ga('send','event','Recommend Story API: 61008', 'Load', '', {'nonInteraction':1});
xhr.open(ajaxMethod, encodeURI(ajaxUrl));
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onload = function() {
    if (xhr.status === 200) {
        var data = JSON.parse(xhr.responseText);
        var maxItem = 8;
        var itemCount = 0;
        var itemHTML = '';
        if (data.body.oelement.errorcode === '0') {
        	if (data.body.odatalist && data.body.odatalist.length > 0) {
        		for (var i=0; i<data.body.odatalist.length; i++) {
        			var itemClass = 'XL3 L3 M6 S6 P12';
        			var itemHeadline = data.body.odatalist[i].cheadline;
        			var itemImage = data.body.odatalist[i].piclink;
        			var itemId = data.body.odatalist[i].storyid;
                    var itemT = data.body.odatalist[i].t;
                    if(itemT === undefined || itemT === null) {itemT = '';}
        			var itemTop = '';
        			var itemTopClass = 'PT';
        			if (itemCount % 4 === 0) {
        				itemTopClass += ' XLT LT';
        			}
        			if (itemCount % 2 === 0) {
        				itemTopClass += ' MT ST';
        			}
        			if (itemTopClass !== '' && itemCount >0) {
        				itemTop = '

';
        			}

        			if (itemCount<maxItem && itemImage && itemImage !== '') {
	        			itemHTML += itemTop + '

'+itemHeadline+'

';
	        			itemCount += 1;
        			}
        		}
                recommendInner.innerHTML = itemHTML;
                document.getElementById('story-recommend-container').style.display = 'block';
                loadImages();
                recommendLoaded = true;
                ga('send','event','Recommend Story API', 'Success', '', {'nonInteraction':1});
        	} else {
                ga('send','event','Recommend Story API', 'No Data', '', {'nonInteraction':1});
            }
        } else {
            ga('send','event','Recommend Story API', 'Parse Fail', data.body.oelement.errorcode, {'nonInteraction':1});
        }
    } else if (xhr.status !== 200) {
        ga('send','event','Recommend Story API', 'Request Fail', '', {'nonInteraction':1});
        //alert('Request failed.  Returned status of ' + xhr.status);
    }

};
xhr.send(JSON.stringify(message));

//set font
fontOptionsEle = document.getElementById('font-options');

//fontOptionsDivs = fontOptionsEle.querySelectorAll('div');

//click to change font size and set cookie (fs)
//Dom Delegate doesn't work here on iOS
fontOptionsEle.onclick = function (e) {
    var currentClass = e.target.className || '';
    var selectedClass;
    var storyContainerClass = document.querySelector('.story-container').className;
    if (currentClass.indexOf('selected') <0) {
        if (fontOptionsEle.querySelector('.selected')) {
            selectedClass = fontOptionsEle.querySelector('.selected').className || '';
        } else {
            selectedClass = '';
        }
        selectedClass = selectedClass.replace(/ selected/g, '');
        if (fontOptionsEle.querySelector('.selected')) {
            fontOptionsEle.querySelector('.selected').className = selectedClass;
        }
        e.target.className = currentClass + ' selected';
        /* jshint ignore:start */
        SetCookie('fs',currentClass,'','/');
        /* jshint ignore:end */
        storyContainerClass = storyContainerClass.replace(/ (normal|bigger|biggest|smaller|smallest)/g,'');
        document.querySelector('.story-container').className = storyContainerClass + ' ' + currentClass;
        stickyBottomPrepare();
        stickyAdsPrepare();
        setResizeClass();
    }
};

//click to change font size and set cookie (fs)
// delegate.on('click', '.font-options div', function(){
//     var currentClass = this.className || '';
//     var selectedClass;
//     var storyContainerClass = document.querySelector('.story-container').className;
//     if (currentClass.indexOf('selected') <0) {
//         selectedClass = fontOptionsEle.querySelector('.selected').className;
//         selectedClass = selectedClass.replace(/ selected/g, '');
//         fontOptionsEle.querySelector('.selected').className = selectedClass;
//         this.className = currentClass + ' selected';
//         /* jshint ignore:start */
//         SetCookie('fs',currentClass,'','/');
//         /* jshint ignore:end */
//         storyContainerClass = storyContainerClass.replace(/ (normal|bigger|biggest|smaller|smallest)/g,'');
//         document.querySelector('.story-container').className = storyContainerClass + ' ' + currentClass;
//         stickyBottomPrepare();
//         stickyAdsPrepare();
//         setResizeClass();
//     }
// });

//set font by getting user cookie (fs)
/* jshint ignore:start */
fs = GetCookie('fs');
/* jshint ignore:end */
if (typeof fs === 'string' && fs !== null && fs !== '' && document.getElementById('font-options') && document.querySelector('.story-container')) {
    document.getElementById('font-options').querySelector('.' + fs.replace(/ /g, '.')).className = fs + ' selected';
    document.querySelector('.story-container').className = document.querySelector('.story-container').className + ' ' + fs;
    setResizeClass();
} else {
    document.getElementById('font-setting').querySelector('.normal').className = 'normal selected';
}

/* jshint ignore:start */
// var bpage=0;
// function viewhistory() {
//     var username=GetCookie("USER_NAME"),
//         unixday=Math.round(new Date().getTime()/1000),
//         viewstart=GetCookie ("viewstart"),
//         clearhistory=0,
//         v,
//         k,
//         barrierversion,
//         ie6,
//         isIE;
//     if (typeof storyid==="string" && storyid!=="" && (username===''||username===null) && (location.href.match(/\/story\/[0-9]{9}$/g)!==null||location.href.indexOf("barrierversion")>0)) {

//         if (viewstart===null || viewstart==="") {
//             viewstart=unixday;
//             SetCookie("viewstart",unixday,86400*100,"/");
//         } else if (unixday-viewstart>=30*86400) {
//             DeleteCookie ("viewstart");
//             DeleteCookie ("viewhistory");
//             SetCookie("viewstart",unixday,86400*100,"/");
//             clearhistory=1;
//         }

//         v=GetCookie ("viewhistory");
//         if (v===null || clearhistory===1) {
//             v="";
//         }
//         v=v.replace(storyid,"").replace(/[\|]+/g,"|");
//         v=v+"|"+storyid;
//         v=v.replace(/^\|+/g,"").replace(/^[0-9]{1,8}\|/g,"");
//         if (v.length>=120) {
//             v=v.replace(/^[0-9]+\|/g,"");
//         }
//         DeleteCookie ("viewhistory");
//         SetCookie("viewhistory",v,86400*100,"/");
//         if (v.length>=50  && (document.referrer.indexOf("ftchinese.com")>=0 ||location.href.indexOf("barrierversion")>0)) {
//             bpage=1;
//             if (location.href.indexOf("ftchinese.com")>=0) {

//                 //if(i<0.3){bpage=2}else if(i<0.5){bpage=3}
//                 if (v.length>=100) {bpage=3;}
//                 k=GetCookie("bp");
//                 if (k!==null&&k!==""&&k>=2){bpage=k;}
//                 barrierversion=paravalue(window.location.href,"barrierversion");
//                 if (barrierversion!==null && barrierversion!==""){bpage=parseInt(barrierversion,0);}
//                 //如果是IE6，则不弹出全屏模式，但是一定让他登录才能看文章
//                 ie6=!!window.ActiveXObject&&!window.XMLHttpRequest;
//                 isIE=!!window.ActiveXObject;
//                 if (ie6 && v.length>=100) {
//                     bpage=6;
//                     $.get("/m/marketing/reg.html", function(data){
//                         $("#bodytext p").slice(2).remove();
//                         $("#bodytext p").eq(1).after(data.replace(/5篇以上文章/g,"10篇以上文章")+"
友好提示：我们注意到您还在使用IE6浏览，这会带来安全隐患。建议您升级到更高的版本，或使用最新的FireFox或Chrome等浏览器。
");
//                     });
//                 } else if (isIE && v.length>=100) {
//                     $.get("/m/marketing/reg.html", function(data){
//                         $("#bodytext p").slice(2).remove();
//                         $("#bodytext p").eq(1).after(data.replace(/5篇以上文章/g,"10篇以上文章"));
//                     });
//                 } else if (bpage>=2 && v.length>=100 && $(window).width()>1024 && (window.Modernizr === undefined || !window.Modernizr.touch)) {
//                     $.get("/m/marketing/reg"+bpage+".html", function(data){
//                     if (data.indexOf("用户名或电子邮件")>0) {
//                         $("#bodytext").html(data);
//                         $("#rail-content").empty();
//                         $(".story_list,#top590x60,#commentheader,#logincomment,#nologincomment,.commentcontainer,#sharelinks,.announce").remove();
//                         SetCookie("bp",bpage,86400*100,"/");
//                         }
//                     });
//                 } else {
//                     $.get("/m/marketing/reg.html", function(data){
//                         $("#bodytext p").eq(1).after(data);
//                     });
//                 }
//             }
//         }
//     }
// }
/* jshint ignore:end */<commit_msg>Fixed the label name<commit_after>var fontOptionsEle;
var fs;
var xhr = new XMLHttpRequest();
var ajaxMethod;
var ajaxUrl;
var message = {};
var recommendLoaded = false;
var recommendInner = document.getElementById('story-recommend');

message.head = {};
message.head.transactiontype = '61008';
message.head.source = 'web';
message.body = {};
message.body.ielement = {};
message.body.ielement.storyid = '';

if (/127\.0|localhost|192\.168/.test(window.location.href)) {
	ajaxMethod = 'GET';
	ajaxUrl = '/api/page/recommend.json';
} else {
	ajaxMethod = 'POST';
	ajaxUrl = '/eaclient/apijson.php';
}

ga('send','event','Recommend Story API', 'Load', '', {'nonInteraction':1});
xhr.open(ajaxMethod, encodeURI(ajaxUrl));
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onload = function() {
    if (xhr.status === 200) {
        var data = JSON.parse(xhr.responseText);
        var maxItem = 8;
        var itemCount = 0;
        var itemHTML = '';
        if (data.body.oelement.errorcode === '0') {
        	if (data.body.odatalist && data.body.odatalist.length > 0) {
        		for (var i=0; i<data.body.odatalist.length; i++) {
        			var itemClass = 'XL3 L3 M6 S6 P12';
        			var itemHeadline = data.body.odatalist[i].cheadline;
        			var itemImage = data.body.odatalist[i].piclink;
        			var itemId = data.body.odatalist[i].storyid;
                    var itemT = data.body.odatalist[i].t;
                    if(itemT === undefined || itemT === null) {itemT = '';}
        			var itemTop = '';
        			var itemTopClass = 'PT';
        			if (itemCount % 4 === 0) {
        				itemTopClass += ' XLT LT';
        			}
        			if (itemCount % 2 === 0) {
        				itemTopClass += ' MT ST';
        			}
        			if (itemTopClass !== '' && itemCount >0) {
        				itemTop = '

';
        			}

        			if (itemCount<maxItem && itemImage && itemImage !== '') {
	        			itemHTML += itemTop + '

'+itemHeadline+'

';
	        			itemCount += 1;
        			}
        		}
                recommendInner.innerHTML = itemHTML;
                document.getElementById('story-recommend-container').style.display = 'block';
                loadImages();
                recommendLoaded = true;
                ga('send','event','Recommend Story API', 'Success', '', {'nonInteraction':1});
        	} else {
                ga('send','event','Recommend Story API', 'No Data', '', {'nonInteraction':1});
            }
        } else {
            ga('send','event','Recommend Story API', 'Parse Fail', data.body.oelement.errorcode, {'nonInteraction':1});
        }
    } else if (xhr.status !== 200) {
        ga('send','event','Recommend Story API', 'Request Fail', '', {'nonInteraction':1});
        //alert('Request failed.  Returned status of ' + xhr.status);
    }

};
xhr.send(JSON.stringify(message));

//set font
fontOptionsEle = document.getElementById('font-options');

//fontOptionsDivs = fontOptionsEle.querySelectorAll('div');

//click to change font size and set cookie (fs)
//Dom Delegate doesn't work here on iOS
fontOptionsEle.onclick = function (e) {
    var currentClass = e.target.className || '';
    var selectedClass;
    var storyContainerClass = document.querySelector('.story-container').className;
    if (currentClass.indexOf('selected') <0) {
        if (fontOptionsEle.querySelector('.selected')) {
            selectedClass = fontOptionsEle.querySelector('.selected').className || '';
        } else {
            selectedClass = '';
        }
        selectedClass = selectedClass.replace(/ selected/g, '');
        if (fontOptionsEle.querySelector('.selected')) {
            fontOptionsEle.querySelector('.selected').className = selectedClass;
        }
        e.target.className = currentClass + ' selected';
        /* jshint ignore:start */
        SetCookie('fs',currentClass,'','/');
        /* jshint ignore:end */
        storyContainerClass = storyContainerClass.replace(/ (normal|bigger|biggest|smaller|smallest)/g,'');
        document.querySelector('.story-container').className = storyContainerClass + ' ' + currentClass;
        stickyBottomPrepare();
        stickyAdsPrepare();
        setResizeClass();
    }
};

//click to change font size and set cookie (fs)
// delegate.on('click', '.font-options div', function(){
//     var currentClass = this.className || '';
//     var selectedClass;
//     var storyContainerClass = document.querySelector('.story-container').className;
//     if (currentClass.indexOf('selected') <0) {
//         selectedClass = fontOptionsEle.querySelector('.selected').className;
//         selectedClass = selectedClass.replace(/ selected/g, '');
//         fontOptionsEle.querySelector('.selected').className = selectedClass;
//         this.className = currentClass + ' selected';
//         /* jshint ignore:start */
//         SetCookie('fs',currentClass,'','/');
//         /* jshint ignore:end */
//         storyContainerClass = storyContainerClass.replace(/ (normal|bigger|biggest|smaller|smallest)/g,'');
//         document.querySelector('.story-container').className = storyContainerClass + ' ' + currentClass;
//         stickyBottomPrepare();
//         stickyAdsPrepare();
//         setResizeClass();
//     }
// });

//set font by getting user cookie (fs)
/* jshint ignore:start */
fs = GetCookie('fs');
/* jshint ignore:end */
if (typeof fs === 'string' && fs !== null && fs !== '' && document.getElementById('font-options') && document.querySelector('.story-container')) {
    document.getElementById('font-options').querySelector('.' + fs.replace(/ /g, '.')).className = fs + ' selected';
    document.querySelector('.story-container').className = document.querySelector('.story-container').className + ' ' + fs;
    setResizeClass();
} else {
    document.getElementById('font-setting').querySelector('.normal').className = 'normal selected';
}

/* jshint ignore:start */
// var bpage=0;
// function viewhistory() {
//     var username=GetCookie("USER_NAME"),
//         unixday=Math.round(new Date().getTime()/1000),
//         viewstart=GetCookie ("viewstart"),
//         clearhistory=0,
//         v,
//         k,
//         barrierversion,
//         ie6,
//         isIE;
//     if (typeof storyid==="string" && storyid!=="" && (username===''||username===null) && (location.href.match(/\/story\/[0-9]{9}$/g)!==null||location.href.indexOf("barrierversion")>0)) {

//         if (viewstart===null || viewstart==="") {
//             viewstart=unixday;
//             SetCookie("viewstart",unixday,86400*100,"/");
//         } else if (unixday-viewstart>=30*86400) {
//             DeleteCookie ("viewstart");
//             DeleteCookie ("viewhistory");
//             SetCookie("viewstart",unixday,86400*100,"/");
//             clearhistory=1;
//         }

//         v=GetCookie ("viewhistory");
//         if (v===null || clearhistory===1) {
//             v="";
//         }
//         v=v.replace(storyid,"").replace(/[\|]+/g,"|");
//         v=v+"|"+storyid;
//         v=v.replace(/^\|+/g,"").replace(/^[0-9]{1,8}\|/g,"");
//         if (v.length>=120) {
//             v=v.replace(/^[0-9]+\|/g,"");
//         }
//         DeleteCookie ("viewhistory");
//         SetCookie("viewhistory",v,86400*100,"/");
//         if (v.length>=50  && (document.referrer.indexOf("ftchinese.com")>=0 ||location.href.indexOf("barrierversion")>0)) {
//             bpage=1;
//             if (location.href.indexOf("ftchinese.com")>=0) {

//                 //if(i<0.3){bpage=2}else if(i<0.5){bpage=3}
//                 if (v.length>=100) {bpage=3;}
//                 k=GetCookie("bp");
//                 if (k!==null&&k!==""&&k>=2){bpage=k;}
//                 barrierversion=paravalue(window.location.href,"barrierversion");
//                 if (barrierversion!==null && barrierversion!==""){bpage=parseInt(barrierversion,0);}
//                 //如果是IE6，则不弹出全屏模式，但是一定让他登录才能看文章
//                 ie6=!!window.ActiveXObject&&!window.XMLHttpRequest;
//                 isIE=!!window.ActiveXObject;
//                 if (ie6 && v.length>=100) {
//                     bpage=6;
//                     $.get("/m/marketing/reg.html", function(data){
//                         $("#bodytext p").slice(2).remove();
//                         $("#bodytext p").eq(1).after(data.replace(/5篇以上文章/g,"10篇以上文章")+"
友好提示：我们注意到您还在使用IE6浏览，这会带来安全隐患。建议您升级到更高的版本，或使用最新的FireFox或Chrome等浏览器。
");
//                     });
//                 } else if (isIE && v.length>=100) {
//                     $.get("/m/marketing/reg.html", function(data){
//                         $("#bodytext p").slice(2).remove();
//                         $("#bodytext p").eq(1).after(data.replace(/5篇以上文章/g,"10篇以上文章"));
//                     });
//                 } else if (bpage>=2 && v.length>=100 && $(window).width()>1024 && (window.Modernizr === undefined || !window.Modernizr.touch)) {
//                     $.get("/m/marketing/reg"+bpage+".html", function(data){
//                     if (data.indexOf("用户名或电子邮件")>0) {
//                         $("#bodytext").html(data);
//                         $("#rail-content").empty();
//                         $(".story_list,#top590x60,#commentheader,#logincomment,#nologincomment,.commentcontainer,#sharelinks,.announce").remove();
//                         SetCookie("bp",bpage,86400*100,"/");
//                         }
//                     });
//                 } else {
//                     $.get("/m/marketing/reg.html", function(data){
//                         $("#bodytext p").eq(1).after(data);
//                     });
//                 }
//             }
//         }
//     }
// }
/* jshint ignore:end */<|endoftext|>