<commit_before>/**
 * @flow
 */

import 'instapromise';

import ProgressBar from 'progress';
import _ from 'lodash-node';
import bunyan from 'bunyan';
import crayon from '@ccheever/crayon';
import glob from 'glob';
import path from 'path';
import simpleSpinner from '@exponent/simple-spinner';
import url from 'url';

import program, { Command } from 'commander';
import {
  Analytics,
  Binaries,
  Config,
  Doctor,
  Logger,
  PackagerLogsStream,
  NotificationCode,
  ProjectUtils,
  User as UserManager,
} from 'xdl';

import { loginOrRegisterIfLoggedOut } from './accounts';
import log from './log';
import update from './update';
import urlOpts from './urlOpts';

if (process.env.NODE_ENV === 'development') {
  require('source-map-support').install();
}

Command.prototype.urlOpts = function() {
  urlOpts.addOptions(this);
  return this;
};

Command.prototype.allowOffline = function() {
  this.option('--offline', 'Allows this command to run while offline');
  return this;
};

Command.prototype.allowNonInteractive = function() {
  this.option(
    '--non-interactive',
    'Fails if an interactive prompt would be required to continue.'
  );
  return this;
};

Command.prototype.asyncAction = function(asyncFn, skipUpdateCheck) {
  return this.action(async (...args) => {
    if (!skipUpdateCheck) {
      try {
        await checkForUpdateAsync();
      } catch (e) {}
    }

    try {
      let options = _.last(args);
      if (options.output === 'raw') {
        log.config.raw = true;
      }
      if (options.offline) {
        Config.offline = true;
      }
      await asyncFn(...args);
    } catch (err) {
      if (err._isCommandError) {
        log.error(err.message);
      } else if (err._isApiError) {
        log.error(crayon.red(err.message));
      } else if (err.isXDLError) {
        log.error(err.message);
      } else {
        log.error(err.message);
        crayon.gray.error(err.stack);
      }
      process.exit(1);
    }
  });
};

Command.prototype.asyncActionProjectDir = function(
  asyncFn,
  skipProjectValidation,
  skipAuthCheck
) {
  return this.asyncAction(
    async (projectDir, ...args) => {
      try {
        await checkForUpdateAsync();
      } catch (e) {}

      const opts = args[0];
      if (!skipAuthCheck && !opts.nonInteractive && !opts.offline) {
        await loginOrRegisterIfLoggedOut();
      }

      if (!skipAuthCheck) {
        await UserManager.ensureLoggedInAsync();
      }

      if (!projectDir) {
        projectDir = process.cwd();
      } else {
        projectDir = path.resolve(process.cwd(), projectDir);
      }

      const logLines = (msg, logFn) => {
        for (let line of msg.split('\n')) {
          logFn(line);
        }
      };

      const logWithLevel = chunk => {
        if (!chunk.msg) {
          return;
        }
        if (chunk.level <= bunyan.INFO) {
          logLines(chunk.msg, log);
        } else if (chunk.level === bunyan.WARN) {
          logLines(chunk.msg, log.warn);
        } else {
          logLines(chunk.msg, log.error);
        }
      };

      let bar;
      let packagerLogsStream = new PackagerLogsStream({
        projectRoot: projectDir,
        onStartBuildBundle: () => {
          bar = new ProgressBar('Building JavaScript bundle [:bar] :percent', {
            total: 100,
            clear: true,
            complete: '=',
            incomplete: ' ',
          });

          log.setBundleProgressBar(bar);
        },
        onProgressBuildBundle: percent => {
          if (!bar || bar.complete) return;
          let ticks = percent - bar.curr;
          ticks > 0 && bar.tick(ticks);
        },
        onFinishBuildBundle: () => {
          if (bar && !bar.complete) {
            bar.tick(100 - bar.curr);
          }

          if (bar) {
            log.setBundleProgressBar(null);
            bar = null;
            log(crayon.green('Finished building JavaScript bundle'));
          }
        },
        updateLogs: updater => {
          let newLogChunks = updater([]);
          newLogChunks.forEach(newLogChunk => {
            logWithLevel(newLogChunk);
          });
        },
      });

      // needed for validation logging to function
      ProjectUtils.attachLoggerStream(projectDir, {
        stream: {
          write: chunk => {
            if (chunk.tag === 'device') {
              logWithLevel(chunk);
            }
          },
        },
        type: 'raw',
      });

      // the existing CLI modules only pass one argument to this function, so skipProjectValidation
      // will be undefined in most cases. we can explicitly pass a truthy value here to avoid validation (eg for init)
      if (!skipProjectValidation) {
        log('Making sure project is set up correctly...');
        simpleSpinner.start();
        // validate that this is a good projectDir before we try anything else
        let status = await Doctor.validateLowLatencyAsync(projectDir);
        if (status === Doctor.FATAL) {
          throw new Error(
            `Invalid project directory. See above logs for information.`
          );
        }
        simpleSpinner.stop();
        log('Your project looks good!');
      }

      return asyncFn(projectDir, ...args);
    },
    true
  );
};

function runAsync() {
  try {
    Analytics.setSegmentNodeKey('vGu92cdmVaggGA26s3lBX6Y5fILm8SQ7');
    Analytics.setVersionName(require('../package.json').version);
    _registerLogs();

    if (process.env.SERVER_URL) {
      let serverUrl = process.env.SERVER_URL;
      if (!serverUrl.startsWith('http')) {
        serverUrl = `http://${serverUrl}`;
      }
      let parsedUrl = url.parse(serverUrl);
      Config.api.host = parsedUrl.hostname;
      Config.api.port = parsedUrl.port;
    }

    Config.developerTool = 'exp';

    program.name = 'exp';
    program
      .version(require('../package.json').version)
      .option('-o, --output [format]', 'Output format. pretty (default), raw');
    glob
      .sync('commands/*.js', {
        cwd: __dirname,
      })
      .forEach(file => {
        const commandModule = require(`./${file}`);
        if (typeof commandModule === 'function') {
          commandModule(program);
        } else if (typeof commandModule.default === 'function') {
          commandModule.default(program);
        } else {
          log.error(`'${file}.js' is not a properly formatted command.`);
        }
      });

    if (process.env.EXPO_DEBUG) {
      glob
        .sync('debug_commands/*.js', {
          cwd: __dirname,
        })
        .forEach(file => {
          require(`./${file}`)(program);
        });
    }

    program.parse(process.argv);

    let subCommand = process.argv[2];
    if (subCommand) {
      let commands = [];
      program.commands.forEach(command => {
        commands.push(command['_name']);
        let alias = command['_alias'];
        if (alias) {
          commands.push(alias);
        }
      });
      if (!_.includes(commands, subCommand)) {
        console.log(
          `"${subCommand}" is not an exp command. See "exp --help" for the full list of commands.`
        );
      }
    } else {
      program.help();
    }
  } catch (e) {
    console.error(e);
    throw e;
  }
}

async function checkForUpdateAsync() {
  let { state, current, latest } = await update.checkForExpUpdateAsync();
  let message;
  switch (state) {
    case 'up-to-date':
      break;

    case 'out-of-date':
      message = `There is a new version of exp available (${latest}).
You are currently using exp ${current}
Run \`npm install -g exp\` to get the latest version`;
      crayon.green.error(message);
      break;

    case 'ahead-of-published':
      // if the user is ahead of npm, we're going to assume they know what they're doing
      break;

    default:
      log.error('Confused about what version of exp you have?');
  }
}

function _registerLogs() {
  let stream = {
    stream: {
      write: chunk => {
        if (chunk.code) {
          switch (chunk.code) {
            case NotificationCode.START_LOADING:
              simpleSpinner.start();
              return;
            case NotificationCode.STOP_LOADING:
              simpleSpinner.stop();
              return;
            case NotificationCode.DOWNLOAD_CLI_PROGRESS:
              return;
          }
        }

        if (chunk.level === bunyan.INFO) {
          log(chunk.msg);
        } else if (chunk.level === bunyan.WARN) {
          log.warn(chunk.msg);
        } else if (chunk.level >= bunyan.ERROR) {
          log.error(chunk.msg);
        }
      },
    },
    type: 'raw',
  };

  Logger.notifications.addStream(stream);
  Logger.global.addStream(stream);
}

async function writePathAsync() {
  let subCommand = process.argv[2];
  if (subCommand === 'prepare-detached-build') {
    // This is being run from Android Studio or Xcode. Don't want to write PATH in this case.
    return;
  }

  await Binaries.writePathToUserSettingsAsync();
}

export function run() {
  (async function() {
    await Promise.all([writePathAsync(), runAsync()]);
  })().catch(e => {
    console.error('Uncaught Error', e);
    process.exit(1);
  });
}
<commit_msg>Differentiate between bundle build success and error<commit_after>/**
 * @flow
 */

import 'instapromise';

import ProgressBar from 'progress';
import _ from 'lodash-node';
import bunyan from 'bunyan';
import crayon from '@ccheever/crayon';
import glob from 'glob';
import path from 'path';
import simpleSpinner from '@exponent/simple-spinner';
import url from 'url';

import program, { Command } from 'commander';
import {
  Analytics,
  Binaries,
  Config,
  Doctor,
  Logger,
  PackagerLogsStream,
  NotificationCode,
  ProjectUtils,
  User as UserManager,
} from 'xdl';

import { loginOrRegisterIfLoggedOut } from './accounts';
import log from './log';
import update from './update';
import urlOpts from './urlOpts';

if (process.env.NODE_ENV === 'development') {
  require('source-map-support').install();
}

Command.prototype.urlOpts = function() {
  urlOpts.addOptions(this);
  return this;
};

Command.prototype.allowOffline = function() {
  this.option('--offline', 'Allows this command to run while offline');
  return this;
};

Command.prototype.allowNonInteractive = function() {
  this.option(
    '--non-interactive',
    'Fails if an interactive prompt would be required to continue.'
  );
  return this;
};

Command.prototype.asyncAction = function(asyncFn, skipUpdateCheck) {
  return this.action(async (...args) => {
    if (!skipUpdateCheck) {
      try {
        await checkForUpdateAsync();
      } catch (e) {}
    }

    try {
      let options = _.last(args);
      if (options.output === 'raw') {
        log.config.raw = true;
      }
      if (options.offline) {
        Config.offline = true;
      }
      await asyncFn(...args);
    } catch (err) {
      if (err._isCommandError) {
        log.error(err.message);
      } else if (err._isApiError) {
        log.error(crayon.red(err.message));
      } else if (err.isXDLError) {
        log.error(err.message);
      } else {
        log.error(err.message);
        crayon.gray.error(err.stack);
      }
      process.exit(1);
    }
  });
};

Command.prototype.asyncActionProjectDir = function(
  asyncFn,
  skipProjectValidation,
  skipAuthCheck
) {
  return this.asyncAction(
    async (projectDir, ...args) => {
      try {
        await checkForUpdateAsync();
      } catch (e) {}

      const opts = args[0];
      if (!skipAuthCheck && !opts.nonInteractive && !opts.offline) {
        await loginOrRegisterIfLoggedOut();
      }

      if (!skipAuthCheck) {
        await UserManager.ensureLoggedInAsync();
      }

      if (!projectDir) {
        projectDir = process.cwd();
      } else {
        projectDir = path.resolve(process.cwd(), projectDir);
      }

      const logLines = (msg, logFn) => {
        for (let line of msg.split('\n')) {
          logFn(line);
        }
      };

      const logWithLevel = chunk => {
        if (!chunk.msg) {
          return;
        }
        if (chunk.level <= bunyan.INFO) {
          logLines(chunk.msg, log);
        } else if (chunk.level === bunyan.WARN) {
          logLines(chunk.msg, log.warn);
        } else {
          logLines(chunk.msg, log.error);
        }
      };

      let bar;
      let packagerLogsStream = new PackagerLogsStream({
        projectRoot: projectDir,
        onStartBuildBundle: () => {
          bar = new ProgressBar('Building JavaScript bundle [:bar] :percent', {
            total: 100,
            clear: true,
            complete: '=',
            incomplete: ' ',
          });

          log.setBundleProgressBar(bar);
        },
        onProgressBuildBundle: percent => {
          if (!bar || bar.complete) return;
          let ticks = percent - bar.curr;
          ticks > 0 && bar.tick(ticks);
        },
        onFinishBuildBundle: (err) => {
          if (bar && !bar.complete) {
            bar.tick(100 - bar.curr);
          }

          if (bar) {
            log.setBundleProgressBar(null);
            bar = null;

            if (err) {
              log(crayon.red('Failed building JavaScript bundle.'));
            } else {
              log(crayon.green('Finished building JavaScript bundle.'));
            }
          }
        },
        updateLogs: updater => {
          let newLogChunks = updater([]);
          newLogChunks.forEach(newLogChunk => {
            logWithLevel(newLogChunk);
          });
        },
      });

      // needed for validation logging to function
      ProjectUtils.attachLoggerStream(projectDir, {
        stream: {
          write: chunk => {
            if (chunk.tag === 'device') {
              logWithLevel(chunk);
            }
          },
        },
        type: 'raw',
      });

      // the existing CLI modules only pass one argument to this function, so skipProjectValidation
      // will be undefined in most cases. we can explicitly pass a truthy value here to avoid validation (eg for init)
      if (!skipProjectValidation) {
        log('Making sure project is set up correctly...');
        simpleSpinner.start();
        // validate that this is a good projectDir before we try anything else
        let status = await Doctor.validateLowLatencyAsync(projectDir);
        if (status === Doctor.FATAL) {
          throw new Error(
            `Invalid project directory. See above logs for information.`
          );
        }
        simpleSpinner.stop();
        log('Your project looks good!');
      }

      return asyncFn(projectDir, ...args);
    },
    true
  );
};

function runAsync() {
  try {
    Analytics.setSegmentNodeKey('vGu92cdmVaggGA26s3lBX6Y5fILm8SQ7');
    Analytics.setVersionName(require('../package.json').version);
    _registerLogs();

    if (process.env.SERVER_URL) {
      let serverUrl = process.env.SERVER_URL;
      if (!serverUrl.startsWith('http')) {
        serverUrl = `http://${serverUrl}`;
      }
      let parsedUrl = url.parse(serverUrl);
      Config.api.host = parsedUrl.hostname;
      Config.api.port = parsedUrl.port;
    }

    Config.developerTool = 'exp';

    program.name = 'exp';
    program
      .version(require('../package.json').version)
      .option('-o, --output [format]', 'Output format. pretty (default), raw');
    glob
      .sync('commands/*.js', {
        cwd: __dirname,
      })
      .forEach(file => {
        const commandModule = require(`./${file}`);
        if (typeof commandModule === 'function') {
          commandModule(program);
        } else if (typeof commandModule.default === 'function') {
          commandModule.default(program);
        } else {
          log.error(`'${file}.js' is not a properly formatted command.`);
        }
      });

    if (process.env.EXPO_DEBUG) {
      glob
        .sync('debug_commands/*.js', {
          cwd: __dirname,
        })
        .forEach(file => {
          require(`./${file}`)(program);
        });
    }

    program.parse(process.argv);

    let subCommand = process.argv[2];
    if (subCommand) {
      let commands = [];
      program.commands.forEach(command => {
        commands.push(command['_name']);
        let alias = command['_alias'];
        if (alias) {
          commands.push(alias);
        }
      });
      if (!_.includes(commands, subCommand)) {
        console.log(
          `"${subCommand}" is not an exp command. See "exp --help" for the full list of commands.`
        );
      }
    } else {
      program.help();
    }
  } catch (e) {
    console.error(e);
    throw e;
  }
}

async function checkForUpdateAsync() {
  let { state, current, latest } = await update.checkForExpUpdateAsync();
  let message;
  switch (state) {
    case 'up-to-date':
      break;

    case 'out-of-date':
      message = `There is a new version of exp available (${latest}).
You are currently using exp ${current}
Run \`npm install -g exp\` to get the latest version`;
      crayon.green.error(message);
      break;

    case 'ahead-of-published':
      // if the user is ahead of npm, we're going to assume they know what they're doing
      break;

    default:
      log.error('Confused about what version of exp you have?');
  }
}

function _registerLogs() {
  let stream = {
    stream: {
      write: chunk => {
        if (chunk.code) {
          switch (chunk.code) {
            case NotificationCode.START_LOADING:
              simpleSpinner.start();
              return;
            case NotificationCode.STOP_LOADING:
              simpleSpinner.stop();
              return;
            case NotificationCode.DOWNLOAD_CLI_PROGRESS:
              return;
          }
        }

        if (chunk.level === bunyan.INFO) {
          log(chunk.msg);
        } else if (chunk.level === bunyan.WARN) {
          log.warn(chunk.msg);
        } else if (chunk.level >= bunyan.ERROR) {
          log.error(chunk.msg);
        }
      },
    },
    type: 'raw',
  };

  Logger.notifications.addStream(stream);
  Logger.global.addStream(stream);
}

async function writePathAsync() {
  let subCommand = process.argv[2];
  if (subCommand === 'prepare-detached-build') {
    // This is being run from Android Studio or Xcode. Don't want to write PATH in this case.
    return;
  }

  await Binaries.writePathToUserSettingsAsync();
}

export function run() {
  (async function() {
    await Promise.all([writePathAsync(), runAsync()]);
  })().catch(e => {
    console.error('Uncaught Error', e);
    process.exit(1);
  });
}
<|endoftext|>


<commit_before>import $ from 'jquery';
import _ from 'lodash';
import Immutable from 'immutable';
import { componentTypes, NONE } from '../constants';

const UNHOVER_COMPONENT = 'UNHOVER_COMPONENT';
const HOVER_COMPONENT = 'HOVER_COMPONENT';

const ADD_VARIANT = 'ADD_VARIANT';
const MOVE_COMPONENT = 'MOVE_COMPONENT';
const DELETE_COMPONENT = 'DELETE_COMPONENT';

const SELECT_COMPONENT = 'SELECT_COMPONENT';

const UPDATE_TREE_VIEW_DROP_SPOTS = 'UPDATE_TREE_VIEW_DROP_SPOTS';
const RESET_TREE_VIEW_DROP_SPOTS = 'RESET_TREE_VIEW_DROP_SPOTS';

const CHANGE_COMPONENT_NAME = 'CHANGE_COMPONENT_NAME';
const CREATE_COMPONENT_BLOCK = 'CREATE_COMPONENT_BLOCK';
const SET_COMPONENT_ATTRIBUTE = 'SET_COMPONENT_ATTRIBUTE';

const privateCache = {};

// test for optional argument
export const componentTreeActions = {
  moveComponent(componentId, parentComponentId, insertionIndex) {
    return {
      type: MOVE_COMPONENT,
      componentId,
      parentComponentId,
      insertionIndex
    };
  },

  addVariant(componentId, parentComponentId, insertionIndex, spec) {
    return {
      type: ADD_VARIANT,
      componentId,
      parentComponentId,
      insertionIndex,
      spec: spec || {},
    };
  },

  deleteComponent(componentId) {
    return {
      type: DELETE_COMPONENT,
      componentId
    };
  },

  selectComponent(componentId) {
    return {
      type: SELECT_COMPONENT,
      componentId,
      _noUndo: true
    };
  },

  hoverComponent(componentId) {
    return {
      type: HOVER_COMPONENT,
      componentId,
      _noUndo: true
    }
  },

  unHoverComponent() {
    return {
      type: UNHOVER_COMPONENT,
      _noUndo: true
    }
  },

  updateTreeViewDropSpots(pos, draggedComponentId) {
    return {
      type: UPDATE_TREE_VIEW_DROP_SPOTS,
      pos,
      draggedComponentId,
      _noUndo: true
    };
  },

  resetTreeViewDropSpots() {
    return {
      type: RESET_TREE_VIEW_DROP_SPOTS,
      _noUndo: true
    };
  },

  changeComponentName(componentId, newName) {
    return {
      type: CHANGE_COMPONENT_NAME,
      componentId,
      newName
    };
  },

  createComponentBlock(newBlockId) {
    return {
      type: CREATE_COMPONENT_BLOCK,
      newBlockId
    };
  },

  setComponentAttribute(componentId, attrKey, newAttrValue) {
    return {
      type: SET_COMPONENT_ATTRIBUTE,
      componentId,
      attrKey,
      newAttrValue,
    };
  },
};

export const componentTreeReducer = {
  [ADD_VARIANT](state, action) {
    let { componentId, parentComponentId, insertionIndex, spec } = action;
    let componentsContainer = state.get('componentsContainer');

    componentsContainer.addChild(
      parentComponentId,
      componentsContainer.createVariant(componentId, spec),
      insertionIndex
    );

    return state;
  },

  [MOVE_COMPONENT](state, action) {
    state.get('componentsContainer').moveComponent(
      action.componentId,
      action.parentComponentId,
      action.insertionIndex
    );

    return state;
  },

  [DELETE_COMPONENT](state, action) {
    let { componentId } = action;
    state.get('componentsContainer').deleteComponent(componentId);

    return state.update('activeComponentId', (activeComponentId) => {
      if (activeComponentId === componentId) {
        return undefined;
      } else {
        return activeComponentId;
      }
    });
  },

  [SELECT_COMPONENT](state, action) {
    return state.merge({
      activeComponentState: NONE,
      activeComponentBreakpoint: NONE,
      activeComponentId: action.componentId
    });
  },

  [UPDATE_TREE_VIEW_DROP_SPOTS](state, action) {
    const { pos, draggedComponentId } = action;
    const componentsContainer = state.get('componentsContainer');

    const componentTreeId = state.getIn([
      'pages',
      state.get('currentPageId'),
      'componentTreeId'
    ]);

    if (!privateCache.treeViewInsertionPoints) {
      const insertionPoints = [];
      const draggedComponentParentId = componentsContainer.components
                                                          .getIn([draggedComponentId, 'parentId']);
      const beforeComponentIndex = componentsContainer.getIndex(draggedComponentId);
      const afterComponentIndex = beforeComponentIndex + 1;

      function getInsertionPoint(nodeId, nodeIndex, parentId) {
        let el;
        if (!nodeId) {
          el = $('.treeDropSpot_' + parentId + '_emptyChild');
        } else {
          el = $('.treeDropSpot_' + nodeId + '_' + nodeIndex);
        }

        const w = el.width();
        const pos = el.offset();

        return Immutable.Map({
          insertionIndex: nodeIndex,
          parentId,
          y: pos.top,
          points: [
            { x: pos.left, y: pos.top },
            { x: pos.left + w, y: pos.top }
          ],
          isDraggedComponent: (
            parentId === draggedComponentParentId &&
            (nodeIndex === beforeComponentIndex || nodeIndex === afterComponentIndex)
          )
        });
      }

      componentsContainer.walkChildren(componentTreeId, function (node, ind, cancel) {
        // Before
        let nodeParentId = node.get('parentId');
        let nodeId = node.get('id');

        if (ind === 0) {
          insertionPoints.push(getInsertionPoint(nodeId, ind, nodeParentId));
        }

        // After
        insertionPoints.push(getInsertionPoint(nodeId, ind + 1, nodeParentId));

        if (node.get('id') === draggedComponentId) {
          // Can't drag component inside itself
          cancel();
        } else if (node.get('componentType') === componentTypes.CONTAINER &&
                   node.get('childIds').size === 0) {
          // Inside
          insertionPoints.push(getInsertionPoint(undefined, 0, nodeId));
        }
      });

      privateCache.treeViewInsertionPoints = _.sortBy(insertionPoints, function (insertionPoint) {
        return insertionPoint.get('y');
      });
    }

    // Binary search to find 3 closest nodes
    const insertionPoints = privateCache.treeViewInsertionPoints;
    let left = 0, right = insertionPoints.length - 1;
    let middle;
    while (left < right) {
      middle = Math.floor((right - left) / 2);
      let point = insertionPoints[middle];

      if (point.get('y') === pos.y) {
        break;
      } else if (pos.y < point.get('y')) {
        right = middle - 1;
      } else {
        left = middle + 1;
      }
    }

    let minDist = Math.abs(pos.y - insertionPoints[middle].get('y'));
    let closestIndex = [
      middle - 1,
      middle + 1
    ].reduce((closestIndex, ind) => {
      let dist = Math.abs(pos.y - insertionPoints[ind].get('y'))
      if (dist < minDist) {
        minDist = dist;
        return ind;
      } else {
        return closestIndex;
      }
    }, middle);

    return state.merge({
      otherPossibleTreeViewDropSpots: Immutable.List([
        insertionPoints[closestIndex - 1],
        insertionPoints[closestIndex + 1],
      ]),
      selectedTreeViewDropSpot: insertionPoints[closestIndex]
    })
  },

  [RESET_TREE_VIEW_DROP_SPOTS](state) {
    delete privateCache.treeViewInsertionPoints;
    return state.merge({
      otherPossibleTreeViewDropSpots: undefined,
      selectedTreeViewDropSpot: undefined
    });
  },

  [CHANGE_COMPONENT_NAME](state, action) {
    let componentsContainer = state.get('componentsContainer');
    componentsContainer.components = componentsContainer.components.setIn(
      [action.componentId, 'name'],
      action.newName
    );

    return state;
  },

  [CREATE_COMPONENT_BLOCK](state, action) {
    const { newBlockId } = action;
    const componentsContainer = state.get('componentsContainer');

    let newComponents = componentsContainer.components.withMutations((components) => {
      const newBlockParentId = components.getIn([newBlockId, 'parentId']);
      components.mergeIn([newBlockId, 'name'],
                         {
                           name: 'New Component',
                           parentId: undefined
                         });

      /* Replace self with a variant */
      const variantId = components.createVariant(newBlockId, {
        parentId: newBlockParentId
      });

      components.updateIn([newBlockParentId, 'childIds'], (childIds) => {
        return childIds.map((childId) => {
          if (childId === newBlockId) {
            return variantId;
          } else {
            return childId;
          }
        });
      });
    });

    componentsContainer.components = newComponents;

    return state.update('yourComponentBoxes', (yourComponentBoxes) => {
      return yourComponentBoxes.push(newBlockId);
    });
  },

  [SET_COMPONENT_ATTRIBUTE](state, action) {
    state.get('componentsContainer').setAttribute(
      action.componentId,
      action.attrKey,
      action.newAttrValue,
      {
        breakpoint: state.activeComponentBreakpoint,
        state: state.activeComponentState
      }
    )

    return state;
  },

  [UNHOVER_COMPONENT](state) {
    return state.set('hoveredComponentId', undefined);
  },

  [HOVER_COMPONENT](state, action) {
    return state.set('hoveredComponentId', action.componentId);
  },
};
<commit_msg>testing<commit_after>import $ from 'jquery';
import _ from 'lodash';
import Immutable from 'immutable';
import { componentTypes, NONE } from '../constants';

const UNHOVER_COMPONENT = 'UNHOVER_COMPONENT';
const HOVER_COMPONENT = 'HOVER_COMPONENT';

const ADD_VARIANT = 'ADD_VARIANT';
const MOVE_COMPONENT = 'MOVE_COMPONENT';
const DELETE_COMPONENT = 'DELETE_COMPONENT';

const SELECT_COMPONENT = 'SELECT_COMPONENT';

const UPDATE_TREE_VIEW_DROP_SPOTS = 'UPDATE_TREE_VIEW_DROP_SPOTS';
const RESET_TREE_VIEW_DROP_SPOTS = 'RESET_TREE_VIEW_DROP_SPOTS';

const CHANGE_COMPONENT_NAME = 'CHANGE_COMPONENT_NAME';
const CREATE_COMPONENT_BLOCK = 'CREATE_COMPONENT_BLOCK';
const SET_COMPONENT_ATTRIBUTE = 'SET_COMPONENT_ATTRIBUTE';

const privateCache = {};

// test for optional argument
export const componentTreeActions = {
  moveComponent(componentId, parentComponentId, insertionIndex) {
    return {
      type: MOVE_COMPONENT,
      componentId,
      parentComponentId,
      insertionIndex
    };
  },

  addVariant(componentId, parentComponentId, insertionIndex, spec) {
    return {
      type: ADD_VARIANT,
      componentId,
      parentComponentId,
      insertionIndex,
      spec: spec || {},
    };
  },

  deleteComponent(componentId) {
    return {
      type: DELETE_COMPONENT,
      componentId
    };
  },

  selectComponent(componentId) {
    return {
      type: SELECT_COMPONENT,
      componentId,
      _noUndo: true
    };
  },

  hoverComponent(componentId) {
    return {
      type: HOVER_COMPONENT,
      componentId,
      _noUndo: true
    }
  },

  unHoverComponent() {
    return {
      type: UNHOVER_COMPONENT,
      _noUndo: true
    }
  },

  updateTreeViewDropSpots(pos, draggedComponentId) {
    return {
      type: UPDATE_TREE_VIEW_DROP_SPOTS,
      pos,
      draggedComponentId,
      _noUndo: true
    };
  },

  resetTreeViewDropSpots() {
    return {
      type: RESET_TREE_VIEW_DROP_SPOTS,
      _noUndo: true
    };
  },

  changeComponentName(componentId, newName) {
    return {
      type: CHANGE_COMPONENT_NAME,
      componentId,
      newName
    };
  },

  createComponentBlock(newBlockId) {
    return {
      type: CREATE_COMPONENT_BLOCK,
      newBlockId
    };
  },

  setComponentAttribute(componentId, attrKey, newAttrValue) {
    return {
      type: SET_COMPONENT_ATTRIBUTE,
      componentId,
      attrKey,
      newAttrValue,
    };
  },
};

export const componentTreeReducer = {
  [ADD_VARIANT](state, action) {
    let { componentId, parentComponentId, insertionIndex, spec } = action;
    let componentsContainer = state.get('componentsContainer');

    componentsContainer.addChild(
      parentComponentId,
      componentsContainer.createVariant(componentId, spec),
      insertionIndex
    );

    return state;
  },

  [MOVE_COMPONENT](state, action) {
    state.get('componentsContainer').moveComponent(
      action.componentId,
      action.parentComponentId,
      action.insertionIndex
    );

    return state;
  },

  [DELETE_COMPONENT](state, action) {
    let { componentId } = action;
    state.get('componentsContainer').deleteComponent(componentId);

    return state.update('activeComponentId', (activeComponentId) => {
      if (activeComponentId === componentId) {
        return undefined;
      } else {
        return activeComponentId;
      }
    });
  },

  [SELECT_COMPONENT](state, action) {
    return state.merge({
      activeComponentState: NONE,
      activeComponentBreakpoint: NONE,
      activeComponentId: action.componentId
    });
  },

  [UPDATE_TREE_VIEW_DROP_SPOTS](state, action) {

    // TD: fix strange freezing here

    const { pos, draggedComponentId } = action;
    const componentsContainer = state.get('componentsContainer');

    const componentTreeId = state.getIn([
      'pages',
      state.get('currentPageId'),
      'componentTreeId'
    ]);

    if (!privateCache.treeViewInsertionPoints) {
      const insertionPoints = [];
      const draggedComponentParentId = componentsContainer.components
                                                          .getIn([draggedComponentId, 'parentId']);
      const beforeComponentIndex = componentsContainer.getIndex(draggedComponentId);
      const afterComponentIndex = beforeComponentIndex + 1;

      function getInsertionPoint(nodeId, nodeIndex, parentId) {
        let el;
        if (!nodeId) {
          el = $('.treeDropSpot_' + parentId + '_emptyChild');
        } else {
          el = $('.treeDropSpot_' + nodeId + '_' + nodeIndex);
        }

        const w = el.width();
        const pos = el.offset();

        return Immutable.Map({
          insertionIndex: nodeIndex,
          parentId,
          y: pos.top,
          points: [
            { x: pos.left, y: pos.top },
            { x: pos.left + w, y: pos.top }
          ],
          isDraggedComponent: (
            parentId === draggedComponentParentId &&
            (nodeIndex === beforeComponentIndex || nodeIndex === afterComponentIndex)
          )
        });
      }

      componentsContainer.walkChildren(componentTreeId, function (node, ind, cancel) {
        // Before
        let nodeParentId = node.get('parentId');
        let nodeId = node.get('id');

        if (ind === 0) {
          insertionPoints.push(getInsertionPoint(nodeId, ind, nodeParentId));
        }

        // After
        insertionPoints.push(getInsertionPoint(nodeId, ind + 1, nodeParentId));

        if (node.get('id') === draggedComponentId) {
          // Can't drag component inside itself
          cancel();
        } else if (node.get('componentType') === componentTypes.CONTAINER &&
                   node.get('childIds').size === 0) {
          // Inside
          insertionPoints.push(getInsertionPoint(undefined, 0, nodeId));
        }
      });

      privateCache.treeViewInsertionPoints = _.sortBy(insertionPoints, function (insertionPoint) {
        return insertionPoint.get('y');
      });
    }

    // Binary search to find 3 closest nodes
    const insertionPoints = privateCache.treeViewInsertionPoints;
    let left = 0, right = insertionPoints.length - 1;
    let middle;

    // This does not terminate

    while (left < right) {
      middle = Math.floor((right - left) / 2);
      let point = insertionPoints[middle];

      console.log(left, right);

      if (point.get('y') === pos.y) {
        break;
      } else if (pos.y < point.get('y')) {
        right = middle - 1;
      } else {
        left = middle + 1;
      }
    }

    let minDist = Math.abs(pos.y - insertionPoints[middle].get('y'));
    let closestIndex = [
      middle - 1,
      middle + 1
    ].reduce((closestIndex, ind) => {
      let dist = Math.abs(pos.y - insertionPoints[ind].get('y'));
      if (dist < minDist) {
        minDist = dist;
        return ind;
      } else {
        return closestIndex;
      }
    }, middle);

    return state.merge({
      otherPossibleTreeViewDropSpots: Immutable.List([
        insertionPoints[closestIndex - 1],
        insertionPoints[closestIndex + 1],
      ]),
      selectedTreeViewDropSpot: insertionPoints[closestIndex]
    })
  },

  [RESET_TREE_VIEW_DROP_SPOTS](state) {
    delete privateCache.treeViewInsertionPoints;
    return state.merge({
      otherPossibleTreeViewDropSpots: undefined,
      selectedTreeViewDropSpot: undefined
    });
  },

  [CHANGE_COMPONENT_NAME](state, action) {
    let componentsContainer = state.get('componentsContainer');
    componentsContainer.components = componentsContainer.components.setIn(
      [action.componentId, 'name'],
      action.newName
    );

    return state;
  },

  [CREATE_COMPONENT_BLOCK](state, action) {
    const { newBlockId } = action;
    const componentsContainer = state.get('componentsContainer');

    let newComponents = componentsContainer.components.withMutations((components) => {
      const newBlockParentId = components.getIn([newBlockId, 'parentId']);
      components.mergeIn([newBlockId, 'name'],
                         {
                           name: 'New Component',
                           parentId: undefined
                         });

      /* Replace self with a variant */
      const variantId = components.createVariant(newBlockId, {
        parentId: newBlockParentId
      });

      components.updateIn([newBlockParentId, 'childIds'], (childIds) => {
        return childIds.map((childId) => {
          if (childId === newBlockId) {
            return variantId;
          } else {
            return childId;
          }
        });
      });
    });

    componentsContainer.components = newComponents;

    return state.update('yourComponentBoxes', (yourComponentBoxes) => {
      return yourComponentBoxes.push(newBlockId);
    });
  },

  [SET_COMPONENT_ATTRIBUTE](state, action) {
    state.get('componentsContainer').setAttribute(
      action.componentId,
      action.attrKey,
      action.newAttrValue,
      {
        breakpoint: state.activeComponentBreakpoint,
        state: state.activeComponentState
      }
    )

    return state;
  },

  [UNHOVER_COMPONENT](state) {
    return state.set('hoveredComponentId', undefined);
  },

  [HOVER_COMPONENT](state, action) {
    return state.set('hoveredComponentId', action.componentId);
  },
};
<|endoftext|>


<commit_before>// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts

const { SpecReporter } = require('jasmine-spec-reporter');

exports.config = {
  SELENIUM_PROMISE_MANAGER: false,
  allScriptsTimeout: 11000,
  specs: [
    './src/**/*.e2e-spec.ts'
  ],
  capabilities: {
    browserName: process.env.PROTRACTOR_BROWSER || 'chrome',
    chromeOptions: {
      binary: process.env.PROTRACTOR_CHROME_BIN || undefined,
      args: process.env.PROTRACTOR_CHROME_ARGS ? JSON.parse(process.env.PROTRACTOR_CHROME_ARGS) : ['lang=en-US'],
      prefs: {
        intl: { accept_languages: 'en-US' }
      }
    }
  },
  // Only works with Chrome and Firefox
  directConnect: true,
  baseUrl: 'http://localhost:4200/',
  framework: 'jasmine2',
  jasmineNodeOpts: {
    showColors: true,
    defaultTimeoutInterval: 30000,
    print: function() {}
  },
  onPrepare() {
    require('ts-node').register({
      project: require('path').join(__dirname, './tsconfig.e2e.json')
    });

    // Better console spec reporter
    jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
  }
};
<commit_msg>fix: spec reporter warning<commit_after>// @ts-check
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts

const { SpecReporter } = require('jasmine-spec-reporter');

exports.config = {
  SELENIUM_PROMISE_MANAGER: false,
  allScriptsTimeout: 11000,
  specs: [
    './src/**/*.e2e-spec.ts'
  ],
  capabilities: {
    browserName: process.env.PROTRACTOR_BROWSER || 'chrome',
    chromeOptions: {
      binary: process.env.PROTRACTOR_CHROME_BIN || undefined,
      args: process.env.PROTRACTOR_CHROME_ARGS ? JSON.parse(process.env.PROTRACTOR_CHROME_ARGS) : ['lang=en-US'],
      prefs: {
        intl: { accept_languages: 'en-US' }
      }
    }
  },
  // Only works with Chrome and Firefox
  directConnect: true,
  baseUrl: 'http://localhost:4200/',
  framework: 'jasmine2',
  jasmineNodeOpts: {
    showColors: true,
    defaultTimeoutInterval: 30000,
    print: function() {}
  },
  onPrepare() {
    require('ts-node').register({
      project: require('path').join(__dirname, './tsconfig.e2e.json')
    });

    // Better console spec reporter
    jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: 'pretty' } }));
  }
};
<|endoftext|>


<commit_before>import { parentNode, polyfilled, slotted } from './data';
import canPatchNativeAccessors from '../util/can-patch-native-accessors';

const configurable = true;
const lightProps = {
  parentElement: {
    configurable,
    get () {
      if (slotted.get(this)) {
        const parent = this.parentNode;
        return parent.nodeType === 1 ? parent : null;
      }
      return this.__parentElement;
    }
  },
  parentNode: {
    configurable,
    get () {
      return parentNode.get(this) || this.__parentNode || null;
    }
  },
  nextSibling: {
    configurable,
    get () {
      if (slotted.get(this)) {
        let index;
        const parChs = this.parentNode.childNodes;
        const parChsLen = parChs.length;
        for (let a = 0; a < parChsLen; a++) {
          if (parChs[a] === this) {
            index = a;
            continue;
          }
        }
        return typeof index === 'number' ? parChs[index + 1] : null;
      }
      return this.__nextSibling;
    }
  },
  nextElementSibling: {
    configurable,
    get () {
      if (slotted.get(this)) {
        let next;
        while ((next = this.nextSibling)) {
          if (next.nodeType === 1) {
            return next;
          }
        }
        return null;
      }
      return this.__nextElementSibling;
    }
  },
  previousSibling: {
    configurable,
    get () {
      if (slotted.get(this)) {
        let index;
        const parChs = this.parentNode.childNodes;
        const parChsLen = parChs.length;
        for (let a = 0; a < parChsLen; a++) {
          if (parChs[a] === this) {
            index = a;
            continue;
          }
        }
        return typeof index === 'number' ? parChs[index - 1] : null;
      }
      return this.__previousSibling;
    }
  },
  previousElementSibling: {
    configurable,
    get () {
      if (slotted.get(this)) {
        let prev;
        while ((prev = this.previousSibling)) {
          if (prev.nodeType === 1) {
            return prev;
          }
        }
        return null;
      }
      return this.__previousElementSibling;
    }
  }
};

// If we can patch native accessors, we can safely apply light DOM accessors to
// all HTML elements. This is faster than polyfilling them individually as they
// are added, if possible, and doesn't have a measurable impact on performance
// when they're not marked as light DOM.
const nodeProto = Node.prototype;
const elProto = Element.prototype;
if (canPatchNativeAccessors) {
  for (let name in lightProps) {
    const proto = nodeProto.hasOwnProperty(name) ? nodeProto : elProto;
    Object.defineProperty(proto, '__' + name, Object.getOwnPropetyDescriptor(proto, name));
    Object.defineProperty(proto, name, lightProps[name]);
  }
}

export default function (light) {
  if (!canPatchNativeAccessors && !polyfilled.get(light)) {
    polyfilled.set(light, true);
    Object.defineProperties(light, lightProps);
  }
}
<commit_msg>Fix misspelling of method name.<commit_after>import { parentNode, polyfilled, slotted } from './data';
import canPatchNativeAccessors from '../util/can-patch-native-accessors';

const configurable = true;
const lightProps = {
  parentElement: {
    configurable,
    get () {
      if (slotted.get(this)) {
        const parent = this.parentNode;
        return parent.nodeType === 1 ? parent : null;
      }
      return this.__parentElement;
    }
  },
  parentNode: {
    configurable,
    get () {
      return parentNode.get(this) || this.__parentNode || null;
    }
  },
  nextSibling: {
    configurable,
    get () {
      if (slotted.get(this)) {
        let index;
        const parChs = this.parentNode.childNodes;
        const parChsLen = parChs.length;
        for (let a = 0; a < parChsLen; a++) {
          if (parChs[a] === this) {
            index = a;
            continue;
          }
        }
        return typeof index === 'number' ? parChs[index + 1] : null;
      }
      return this.__nextSibling;
    }
  },
  nextElementSibling: {
    configurable,
    get () {
      if (slotted.get(this)) {
        let next;
        while ((next = this.nextSibling)) {
          if (next.nodeType === 1) {
            return next;
          }
        }
        return null;
      }
      return this.__nextElementSibling;
    }
  },
  previousSibling: {
    configurable,
    get () {
      if (slotted.get(this)) {
        let index;
        const parChs = this.parentNode.childNodes;
        const parChsLen = parChs.length;
        for (let a = 0; a < parChsLen; a++) {
          if (parChs[a] === this) {
            index = a;
            continue;
          }
        }
        return typeof index === 'number' ? parChs[index - 1] : null;
      }
      return this.__previousSibling;
    }
  },
  previousElementSibling: {
    configurable,
    get () {
      if (slotted.get(this)) {
        let prev;
        while ((prev = this.previousSibling)) {
          if (prev.nodeType === 1) {
            return prev;
          }
        }
        return null;
      }
      return this.__previousElementSibling;
    }
  }
};

// If we can patch native accessors, we can safely apply light DOM accessors to
// all HTML elements. This is faster than polyfilling them individually as they
// are added, if possible, and doesn't have a measurable impact on performance
// when they're not marked as light DOM.
const nodeProto = Node.prototype;
const elProto = Element.prototype;
if (canPatchNativeAccessors) {
  for (let name in lightProps) {
    const proto = nodeProto.hasOwnProperty(name) ? nodeProto : elProto;
    Object.defineProperty(proto, '__' + name, Object.getOwnPropertyDescriptor(proto, name));
    Object.defineProperty(proto, name, lightProps[name]);
  }
}

export default function (light) {
  if (!canPatchNativeAccessors && !polyfilled.get(light)) {
    polyfilled.set(light, true);
    Object.defineProperties(light, lightProps);
  }
}
<|endoftext|>


<commit_before>/**
 * Created by Jonas on 2016-05-12.
 */

var FAQInfo = React.createClass({
    render: function () {

        return (

FAQ

Question 1

Hejsan

Question 2

Hejsan

Question 1

Hejsan

Question 2

Hejsan

Question 1

Hejsan

Question 2

Hejsan

Question 1

Hejsan

Question 2

Hejsan

Question 1

Hejsan

                        <button className="md-close">Close</button>

        );
    }

});

window.FAQInfo = FAQInfo;<commit_msg>Added some fancy shit FAQ<commit_after>/**
 * Created by Jonas on 2016-05-12.
 */

var FAQInfo = React.createClass({
    render: function () {

        return (

FAQ

Vad är detta?

Här ska en relevant fråga som en användare vill få svar på, besvaras. Detta
                         medför att ansvarige för systemet slipper svara på återkommande frågor.

Hur lägger man till frågor?

Du går in i FAQinfo.js  i projektet student-capture och lägger till en ny.
                           Man kan då också ta bort denna  + den ovanstående och ersätta dessa med
                           mer relevant information

Hur svara man på frågan?

Samma sak som ovanstående, men inom en paragraf istället.

Question 3

Hejsan

Question 4

Hejsan

Question 5

Hejsan

Question 6

Hejsan

Question 7

Hejsan

Question 8

Hejsan

                        <button className="md-close">Close</button>

        );
    }

});

window.FAQInfo = FAQInfo;<|endoftext|>


<commit_before>export default {
  el: {
    colorpicker: {
      confirm: 'Labi',
      clear: 'Notīrīt'
    },
    datepicker: {
      now: 'Tagad',
      today: 'Šodien',
      cancel: 'Atcelt',
      clear: 'Notīrīt',
      confirm: 'Labi',
      selectDate: 'Izvēlēties datumu',
      selectTime: 'Izvēlēties laiku',
      startDate: 'Sākuma Datums',
      startTime: 'Sākuma Laiks',
      endDate: 'Beigu Datums',
      endTime: 'Beigu Laiks',
      year: '',
      month1: 'Jan',
      month2: 'Feb',
      month3: 'Mar',
      month4: 'Apr',
      month5: 'Mai',
      month6: 'Jūn',
      month7: 'Jūl',
      month8: 'Aug',
      month9: 'Sep',
      month10: 'Okt',
      month11: 'Nov',
      month12: 'Dec',
      // week: 'nedēļa',
      weeks: {
        sun: 'Sv',
        mon: 'Pr',
        tue: 'Ot',
        wed: 'Tr',
        thu: 'Ce',
        fri: 'Pk',
        sat: 'Se'
      },
      months: {
        jan: 'Jan',
        feb: 'Feb',
        mar: 'Mar',
        apr: 'Apr',
        may: 'Mai',
        jun: 'Jūn',
        jul: 'Jūl',
        aug: 'Aug',
        sep: 'Sep',
        oct: 'Okt',
        nov: 'Nov',
        dec: 'Dec'
      }
    },
    select: {
      loading: 'Ielādē',
      noMatch: 'Nav atbilstošu datu',
      noData: 'Nav datu',
      placeholder: 'Izvēlēties'
    },
    cascader: {
      noMatch: 'Nav atbilstošu datu',
      loading: 'Ielādē',
      placeholder: 'Izvēlēties'
    },
    pagination: {
      goto: 'Iet uz',
      pagesize: '/page',
      total: 'Kopā {total}',
      pageClassifier: ''
    },
    messagebox: {
      title: 'Paziņojums',
      confirm: 'Labi',
      cancel: 'Atcelt',
      error: 'Nederīga ievade'
    },
    upload: {
      delete: 'Dzēst',
      preview: 'Priekšskatīt',
      continue: 'Turpināt'
    },
    table: {
      emptyText: 'Nav Datu',
      confirmFilter: 'Apstiprināt',
      resetFilter: 'Reset',
      clearFilter: 'Visi',
      sumText: 'Summa'
    },
    tree: {
      emptyText: 'Nav Datu'
    },
    transfer: {
      noMatch: 'Nav atbilstošu datu',
      noData: 'Nav datu',
      titles: ['Saraksts 1', 'Saraksts 2'],
      filterPlaceholder: 'Ievadīt atslēgvārdu',
      noCheckedFormat: '{total} vienības',
      hasCheckedFormat: '{checked}/{total} atzīmēti'
    }
  }
};
<commit_msg>[Locale] lv.js - use full month names. (#5396)<commit_after>export default {
  el: {
    colorpicker: {
      confirm: 'Labi',
      clear: 'Notīrīt'
    },
    datepicker: {
      now: 'Tagad',
      today: 'Šodien',
      cancel: 'Atcelt',
      clear: 'Notīrīt',
      confirm: 'Labi',
      selectDate: 'Izvēlēties datumu',
      selectTime: 'Izvēlēties laiku',
      startDate: 'Sākuma datums',
      startTime: 'Sākuma laiks',
      endDate: 'Beigu datums',
      endTime: 'Beigu laiks',
      year: '',
      month1: 'Janvāris',
      month2: 'Februāris',
      month3: 'Marts',
      month4: 'Aprīlis',
      month5: 'Maijs',
      month6: 'Jūnijs',
      month7: 'Jūlijs',
      month8: 'Augusts',
      month9: 'Septembris',
      month10: 'Oktobris',
      month11: 'Novembris',
      month12: 'Decembris',
      // week: 'nedēļa',
      weeks: {
        sun: 'Sv',
        mon: 'Pr',
        tue: 'Ot',
        wed: 'Tr',
        thu: 'Ce',
        fri: 'Pk',
        sat: 'Se'
      },
      months: {
        jan: 'Jan',
        feb: 'Feb',
        mar: 'Mar',
        apr: 'Apr',
        may: 'Mai',
        jun: 'Jūn',
        jul: 'Jūl',
        aug: 'Aug',
        sep: 'Sep',
        oct: 'Okt',
        nov: 'Nov',
        dec: 'Dec'
      }
    },
    select: {
      loading: 'Ielādē',
      noMatch: 'Nav atbilstošu datu',
      noData: 'Nav datu',
      placeholder: 'Izvēlēties'
    },
    cascader: {
      noMatch: 'Nav atbilstošu datu',
      loading: 'Ielādē',
      placeholder: 'Izvēlēties'
    },
    pagination: {
      goto: 'Iet uz',
      pagesize: '/page',
      total: 'Kopā {total}',
      pageClassifier: ''
    },
    messagebox: {
      title: 'Paziņojums',
      confirm: 'Labi',
      cancel: 'Atcelt',
      error: 'Nederīga ievade'
    },
    upload: {
      delete: 'Dzēst',
      preview: 'Priekšskatīt',
      continue: 'Turpināt'
    },
    table: {
      emptyText: 'Nav datu',
      confirmFilter: 'Apstiprināt',
      resetFilter: 'Reset',
      clearFilter: 'Visi',
      sumText: 'Summa'
    },
    tree: {
      emptyText: 'Nav datu'
    },
    transfer: {
      noMatch: 'Nav atbilstošu datu',
      noData: 'Nav datu',
      titles: ['Saraksts 1', 'Saraksts 2'],
      filterPlaceholder: 'Ievadīt atslēgvārdu',
      noCheckedFormat: '{total} vienības',
      hasCheckedFormat: '{checked}/{total} atzīmēti'
    }
  }
};
<|endoftext|>


<commit_before>export default {
  el: {
    colorpicker: {
      confirm: 'OK',
      clear: 'Xóa'
    },
    datepicker: {
      now: 'Hiện tại',
      today: 'Hôm nay',
      cancel: 'Hủy',
      clear: 'Xóa',
      confirm: 'OK',
      selectDate: 'Chọn ngày',
      selectTime: 'Chọn giờ',
      startDate: 'Ngày bắt đầu',
      startTime: 'Thời gian bắt đầu',
      endDate: 'Ngày kết thúc',
      endTime: 'Thời gian kết thúc',
      year: 'Năm',
      month1: 'Tháng 1',
      month2: 'Tháng 2',
      month3: 'Tháng 3',
      month4: 'Tháng 4',
      month5: 'Tháng 5',
      month6: 'Tháng 6',
      month7: 'Tháng 7',
      month8: 'Tháng 8',
      month9: 'Tháng 9',
      month10: 'Tháng 10',
      month11: 'Tháng 11',
      month12: 'Tháng 12',
      // week: 'week',
      weeks: {
        sun: 'CN',
        mon: 'T2',
        tue: 'T3',
        wed: 'T4',
        thu: 'T5',
        fri: 'T6',
        sat: 'T7'
      },
      months: {
        jan: 'Th.1',
        feb: 'Th.2',
        mar: 'Th.3',
        apr: 'Th.4',
        may: 'Th.5',
        jun: 'Th.6',
        jul: 'Th.7',
        aug: 'Th.8',
        sep: 'Th.9',
        oct: 'Th.10',
        nov: 'Th.11',
        dec: 'Th.12'
      }
    },
    select: {
      loading: 'Loading',
      noMatch: 'Dữ liệu không phù hợp',
      noData: 'Không tìm thấy dữ liệu',
      placeholder: 'Chọn'
    },
    cascader: {
      noMatch: 'Dữ liệu không phù hợp',
      loading: 'Loading',
      placeholder: 'Chọn'
    },
    pagination: {
      goto: 'Nhảy tới',
      pagesize: '/trang',
      total: 'Tổng {total}',
      pageClassifier: ''
    },
    messagebox: {
      title: 'Thông báo',
      confirm: 'OK',
      cancel: 'Hủy',
      error: 'Dữ liệu không hợp lệ'
    },
    upload: {
      delete: 'Xóa',
      preview: 'Xem trước',
      continue: 'Tiếp tục'
    },
    table: {
      emptyText: 'Không có dữ liệu',
      confirmFilter: 'Xác nhận',
      resetFilter: 'Làm mới',
      clearFilter: 'Xóa hết',
      sumText: 'Sum' // to be translated
    },
    tree: {
      emptyText: 'Không có dữ liệu'
    },
    transfer: {
      noMatch: 'Dữ liệu không phù hợp',
      noData: 'Không tìm thấy dữ liệu',
      titles: ['List 1', 'List 2'], // to be translated
      filterPlaceholder: 'Enter keyword', // to be translated
      noCheckedFormat: '{total} items', // to be translated
      hasCheckedFormat: '{checked}/{total} checked' // to be translated
    }
  }
};
<commit_msg>Update better vietnamese translate. :octocat: <commit_after>export default {
  el: {
    colorpicker: {
      confirm: 'OK',
      clear: 'Xóa'
    },
    datepicker: {
      now: 'Hiện tại',
      today: 'Hôm nay',
      cancel: 'Hủy',
      clear: 'Xóa',
      confirm: 'OK',
      selectDate: 'Chọn ngày',
      selectTime: 'Chọn giờ',
      startDate: 'Ngày bắt đầu',
      startTime: 'Thời gian bắt đầu',
      endDate: 'Ngày kết thúc',
      endTime: 'Thời gian kết thúc',
      year: 'Năm',
      month1: 'Tháng 1',
      month2: 'Tháng 2',
      month3: 'Tháng 3',
      month4: 'Tháng 4',
      month5: 'Tháng 5',
      month6: 'Tháng 6',
      month7: 'Tháng 7',
      month8: 'Tháng 8',
      month9: 'Tháng 9',
      month10: 'Tháng 10',
      month11: 'Tháng 11',
      month12: 'Tháng 12',
      // week: 'week',
      weeks: {
        sun: 'CN',
        mon: 'T2',
        tue: 'T3',
        wed: 'T4',
        thu: 'T5',
        fri: 'T6',
        sat: 'T7'
      },
      months: {
        jan: 'Th.1',
        feb: 'Th.2',
        mar: 'Th.3',
        apr: 'Th.4',
        may: 'Th.5',
        jun: 'Th.6',
        jul: 'Th.7',
        aug: 'Th.8',
        sep: 'Th.9',
        oct: 'Th.10',
        nov: 'Th.11',
        dec: 'Th.12'
      }
    },
    select: {
      loading: 'Đang tải',
      noMatch: 'Dữ liệu không phù hợp',
      noData: 'Không tìm thấy dữ liệu',
      placeholder: 'Chọn'
    },
    cascader: {
      noMatch: 'Dữ liệu không phù hợp',
      loading: 'Đang tải',
      placeholder: 'Chọn'
    },
    pagination: {
      goto: 'Nhảy tới',
      pagesize: '/trang',
      total: 'Tổng {total}',
      pageClassifier: ''
    },
    messagebox: {
      title: 'Thông báo',
      confirm: 'OK',
      cancel: 'Hủy',
      error: 'Dữ liệu không hợp lệ'
    },
    upload: {
      delete: 'Xóa',
      preview: 'Xem trước',
      continue: 'Tiếp tục'
    },
    table: {
      emptyText: 'Không có dữ liệu',
      confirmFilter: 'Xác nhận',
      resetFilter: 'Làm mới',
      clearFilter: 'Xóa hết',
      sumText: 'Tổng' // to be translated
    },
    tree: {
      emptyText: 'Không có dữ liệu'
    },
    transfer: {
      noMatch: 'Dữ liệu không phù hợp',
      noData: 'Không tìm thấy dữ liệu',
      titles: ['Danh sách 1', 'Danh sách 2'], // to be translated
      filterPlaceholder: 'Nhập từ khóa', // to be translated
      noCheckedFormat: '{total} mục', // to be translated
      hasCheckedFormat: '{checked}/{total} đã chọn ' // to be translated
    }
  }
};
<|endoftext|>


<commit_before>/*

GPII Unit Testing for Windows

Copyright 2014 Lucendo Development Ltd.
Copyright 2016 Raising the Floor - US

Licensed under the New BSD license. You may not use this file except in
compliance with this License.

You may obtain a copy of the License at
https://github.com/gpii/universal/LICENSE.txt
*/

"use strict";

require("../index.js");

require("../gpii/node_modules/displaySettingsHandler/test/testDisplaySettingsHandler.js");
require("../gpii/node_modules/gpii-app-zoom/test/testAppZoom.js");
require("../gpii/node_modules/gpii-localisation/test/testLanguage.js");
require("../gpii/node_modules/nativeSettingsHandler/test/testNativeSettingsHandler.js");
require("../gpii/node_modules/processHandling/test/testProcessHandling");
require("../gpii/node_modules/processReporter/test/all-tests.js");
require("../gpii/node_modules/registeredAT/test/testRegisteredAT.js");
require("../gpii/node_modules/registrySettingsHandler/test/testRegistrySettingsHandler.js");
require("../gpii/node_modules/registryResolver/test/testRegistryResolver.js");
require("../gpii/node_modules/spiSettingsHandler/test/testSpiSettingsHandler.js");
require("../gpii/node_modules/systemSettingsHandler/test/testSystemSettingsHandler.js");
require("../gpii/node_modules/userListeners/test/all-tests.js");
require("../gpii/node_modules/windowMessages/test/windowMessagesTest.js");
require("../gpii/node_modules/windowsMetrics/test/WindowsMetricsTests.js");
require("../gpii/node_modules/windowsUtilities/test/WindowsUtilitiesTests.js");
require("../gpii/node_modules/wmiSettingsHandler/test/testWmiSettingsHandler.js");
<commit_msg>GPII-3802: Commenting out app zoom tests which fail fairly often in electron<commit_after>/*

GPII Unit Testing for Windows

Copyright 2014 Lucendo Development Ltd.
Copyright 2016 Raising the Floor - US

Licensed under the New BSD license. You may not use this file except in
compliance with this License.

You may obtain a copy of the License at
https://github.com/gpii/universal/LICENSE.txt
*/

"use strict";

require("../index.js");

require("../gpii/node_modules/displaySettingsHandler/test/testDisplaySettingsHandler.js");
// Commenting out App Zoom tests since these fail fairly often in CI and vagrant in electron - GPII-3802
// require("../gpii/node_modules/gpii-app-zoom/test/testAppZoom.js");
require("../gpii/node_modules/gpii-localisation/test/testLanguage.js");
require("../gpii/node_modules/nativeSettingsHandler/test/testNativeSettingsHandler.js");
require("../gpii/node_modules/processHandling/test/testProcessHandling");
require("../gpii/node_modules/processReporter/test/all-tests.js");
require("../gpii/node_modules/registeredAT/test/testRegisteredAT.js");
require("../gpii/node_modules/registrySettingsHandler/test/testRegistrySettingsHandler.js");
require("../gpii/node_modules/registryResolver/test/testRegistryResolver.js");
require("../gpii/node_modules/spiSettingsHandler/test/testSpiSettingsHandler.js");
require("../gpii/node_modules/systemSettingsHandler/test/testSystemSettingsHandler.js");
require("../gpii/node_modules/userListeners/test/all-tests.js");
require("../gpii/node_modules/windowMessages/test/windowMessagesTest.js");
require("../gpii/node_modules/windowsMetrics/test/WindowsMetricsTests.js");
require("../gpii/node_modules/windowsUtilities/test/WindowsUtilitiesTests.js");
require("../gpii/node_modules/wmiSettingsHandler/test/testWmiSettingsHandler.js");
<|endoftext|>


<commit_before>// -*- mode: java; c-basic-offset: 2; -*-
// Copyright © 2013-2016 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
/**
 * @license
 * @fileoverview Field in which mouseover displays flyout-like menu of blocks
 * and mouse click edits the field name.
 * Flydowns are used in App Inventor for displaying get/set blocks for parameter names
 * and callers for procedure declarations.
 * @author fturbak@wellesley.edu (Lyn Turbak)
 */

'use strict';

goog.provide('AI.Blockly.FieldFlydown');

goog.require('Blockly.FieldTextInput');
goog.require('Blockly.Options');

/**
 * Class for a clickable parameter field.
 * @param {string} text The initial parameter name in the field.
 * @param {boolean} isEditable Whether the user is allowed to change the name
 *     of this parameter or not.
 * @param {string=} opt_displayLocation The location to display the flydown at
 *     Either: Blockly.FieldFlydown.DISPLAY_BELOW,
 *             Blockly.FieldFlydown.DISPLAY_RIGHT
 *     Defaults to DISPLAY_RIGHT.
 * @param {Function} opt_changeHandler An optional function that is called
 *     to validate any constraints on what the user entered.  Takes the new
 *     text as an argument and returns the accepted text or null to abort
 *     the change. E.g., for an associated getter/setter this could change
 *     references to names in this field.
 * @extends {Blockly.FieldTextInput}
 * @constructor
 */
Blockly.FieldFlydown = function(name, isEditable, opt_displayLocation, opt_changeHandler) {
  // This by itself does not control editability
  this.EDITABLE = isEditable;
  // [lyn, 10/27/13] Make flydown direction an instance variable
  this.displayLocation = opt_displayLocation ||
      Blockly.FieldFlydown.DISPLAY_RIGHT;

  Blockly.FieldFlydown.superClass_.constructor.call(
      this, name, opt_changeHandler);
};
goog.inherits(Blockly.FieldFlydown, Blockly.FieldTextInput);

/**
 * Milliseconds to wait before showing flydown after mouseover event on flydown field.
 * @type {number}
 * @const
 */
Blockly.FieldFlydown.timeout = 500;

/**
 * Process ID for timer event to show flydown (scheduled by mouseover event)
 * @type {number}
 * @const
 */
Blockly.FieldFlydown.showPid_ = 0;

/**
 * Which instance of FieldFlydown (or a subclass) is an open flydown attached to?
 * @type {Blockly.FieldFlydown}
 * @private
 */
Blockly.FieldFlydown.openFieldFlydown_ = null;

// These control the positions of the flydown.
Blockly.FieldFlydown.DISPLAY_BELOW = "BELOW";
Blockly.FieldFlydown.DISPLAY_RIGHT = "RIGHT";
Blockly.FieldFlydown.DISPLAY_LOCATION = Blockly.FieldFlydown.DISPLAY_BELOW;

/**
 * Default CSS class name for the field itself
 * @type {string}
 * @const
 */
Blockly.FieldFlydown.prototype.fieldCSSClassName = 'blocklyFieldFlydownField';

/**
 * Default CSS class name for the flydown that flies down from the field
 * @type {string}
 * @const
 */
Blockly.FieldFlydown.prototype.flyoutCSSClassName = 'blocklyFieldFlydownFlydown';

// Override FieldTextInput's showEditor_ so it's only called for EDITABLE field.
Blockly.FieldFlydown.prototype.showEditor_ = function() {
  if (!this.EDITABLE) {
    return;
  }
  if (Blockly.FieldFlydown.showPid_) {  // cancel a pending flydown for editing
    clearTimeout(Blockly.FieldFlydown.showPid_);
    Blockly.FieldFlydown.showPid_ = 0;
    Blockly.hideChaff();
  }
  Blockly.FieldFlydown.superClass_.showEditor_.call(this);
};

Blockly.FieldFlydown.prototype.init = function(block) {
  Blockly.FieldFlydown.superClass_.init.call(this, block);

  // Remove inherited field css classes ...
  Blockly.utils.removeClass(/** @type {!Element} */ (this.fieldGroup_),
      'blocklyEditableText');
  Blockly.utils.removeClass(/** @type {!Element} */ (this.fieldGroup_),
      'blocklyNoNEditableText');
  // ... and add new ones, so that look and feel of flyout fields can be customized
  Blockly.utils.addClass(/** @type {!Element} */ (this.fieldGroup_),
      this.fieldCSSClassName);

  this.mouseOverWrapper_ =
      Blockly.bindEvent_(this.fieldGroup_, 'mouseover', this, this.onMouseOver_);
  this.mouseOutWrapper_ =
      Blockly.bindEvent_(this.fieldGroup_, 'mouseout', this, this.onMouseOut_);
};

Blockly.FieldFlydown.prototype.onMouseOver_ = function(e) {
  if (!this.sourceBlock_.isInFlyout) { // [lyn, 10/22/13] No flydowns in a flyout!
    Blockly.FieldFlydown.showPid_ =
        window.setTimeout(this.showFlydownMaker_(), Blockly.FieldFlydown.timeout);
  }
  // This event has been handled.  No need to bubble up to the document.
  e.stopPropagation();
};

Blockly.FieldFlydown.prototype.onMouseOut_ = function(e) {
  // Clear any pending timer event to show flydown
  window.clearTimeout(Blockly.FieldFlydown.showPid_);
  e.stopPropagation();
};

/**
 * Returns a thunk that creates a Flydown block of the getter and setter blocks for receiver field.
 *  @return A thunk (zero-parameter function).
 */
Blockly.FieldFlydown.prototype.showFlydownMaker_ = function() {
  var field = this; // Name receiver in variable so can close over this variable in returned thunk
  return function() {
    if (Blockly.FieldFlydown.showPid_ !== 0 &&
        Blockly.dragMode_ === Blockly.DRAG_NONE) {
      try {
        field.showFlydown_();
      } catch (e) {
        console.error('Failed to show flydown', e);
      }
    }
    Blockly.FieldFlydown.showPid_ = 0;
  };
};

/**
 * Shows the blocks generated by flydownBlocksXML_ in the flydown. Xml should be
 * wrapped in <xml> tags.
 */
Blockly.FieldFlydown.prototype.showFlydown_ = function() {
  Blockly.hideChaff();
  var flydown = Blockly.getMainWorkspace().getFlydown();

  // Add flydown to top-level svg, *not* to main workspace svg
  // This is essential for correct positioning of flydown via translation
  // (If it's in workspace svg, it will be additionally translated by
  //  workspace svg translation relative to Blockly.svg.)
  Blockly.getMainWorkspace().getParentSvg().appendChild(flydown.svgGroup_);

  // Adjust scale for current zoom level
  var scale = flydown.targetWorkspace_.scale;
  flydown.workspace_.setScale(scale);

  flydown.setCSSClass(this.flyoutCSSClassName);

  var blocksXMLText = this.flydownBlocksXML_();
  var blocksDom = Blockly.Xml.textToDom(blocksXMLText);
  // [lyn, 11/10/13] Use goog.dom.getChildren rather than .children or
  //    .childNodes to make this code work across browsers.
  var blocksXMLList = goog.dom.getChildren(blocksDom);

  var xy = Blockly.getMainWorkspace().getSvgXY(this.borderRect_);
  var borderBBox = this.borderRect_.getBBox();
  if (this.displayLocation == Blockly.FieldFlydown.DISPLAY_BELOW) {
    xy.y += borderBBox.height * scale;
  } else { // Display right.
    xy.x += borderBBox.width * scale;
  }

  flydown.showAt(blocksXMLList, xy.x, xy.y);
  Blockly.FieldFlydown.openFieldFlydown_ = this;
};

/**
 * Hide the flydown menu and squash any timer-scheduled flyout creation
 */
Blockly.FieldFlydown.hide = function() {
  // Clear any pending timer event to show flydown.
  window.clearTimeout(Blockly.FieldFlydown.showPid_);
  // Hide any displayed flydown.
  var flydown = Blockly.getMainWorkspace().getFlydown();
  if (flydown) {
    flydown.hide();
  }
};

// TODO: Changing how validators work is not very future proof.
// Override Blockly's behavior; they call the validator after setting the text,
// which is incompatible with how our validators work (we expect to be called
// before the change since in order to find the old references to be renamed).
Blockly.FieldFlydown.prototype.onHtmlInputChange_ = function(e) {
  goog.asserts.assertObject(Blockly.FieldTextInput.htmlInput_);
  var htmlInput = Blockly.FieldTextInput.htmlInput_;
  var text = htmlInput.value;
  if (text !== htmlInput.oldValue_) {
    htmlInput.oldValue_ = text;
    var valid = true;
    if (this.sourceBlock_) {
      valid = this.callValidator(htmlInput.value);
    }
    if (valid === null) {
      Blockly.utils.addClass(htmlInput, 'blocklyInvalidInput');
    } else {
      Blockly.utils.removeClass(htmlInput, 'blocklyInvalidInput');
      this.setText(valid);
    }
  } else if (goog.userAgent.WEBKIT) {
    // Cursor key.  Render the source block to show the caret moving.
    // Chrome only (version 26, OS X).
    this.sourceBlock_.render();
  }
  this.resizeEditor_();
  Blockly.svgResize(this.sourceBlock_.workspace);
};

/**
 * Close the flydown and dispose of all UI.
 */
Blockly.FieldFlydown.prototype.dispose = function() {
  if (Blockly.FieldFlydown.openFieldFlydown_ == this) {
    Blockly.FieldFlydown.hide();
  }
  // Call parent's destructor.
  Blockly.FieldTextInput.prototype.dispose.call(this);
};
<commit_msg>Fix parameter moving under cursor cancels field editing (#2405)<commit_after>// -*- mode: java; c-basic-offset: 2; -*-
// Copyright © 2013-2016 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
/**
 * @license
 * @fileoverview Field in which mouseover displays flyout-like menu of blocks
 * and mouse click edits the field name.
 * Flydowns are used in App Inventor for displaying get/set blocks for parameter names
 * and callers for procedure declarations.
 * @author fturbak@wellesley.edu (Lyn Turbak)
 */

'use strict';

goog.provide('AI.Blockly.FieldFlydown');

goog.require('Blockly.FieldTextInput');
goog.require('Blockly.Options');

/**
 * Class for a clickable parameter field.
 * @param {string} text The initial parameter name in the field.
 * @param {boolean} isEditable Whether the user is allowed to change the name
 *     of this parameter or not.
 * @param {string=} opt_displayLocation The location to display the flydown at
 *     Either: Blockly.FieldFlydown.DISPLAY_BELOW,
 *             Blockly.FieldFlydown.DISPLAY_RIGHT
 *     Defaults to DISPLAY_RIGHT.
 * @param {Function} opt_changeHandler An optional function that is called
 *     to validate any constraints on what the user entered.  Takes the new
 *     text as an argument and returns the accepted text or null to abort
 *     the change. E.g., for an associated getter/setter this could change
 *     references to names in this field.
 * @extends {Blockly.FieldTextInput}
 * @constructor
 */
Blockly.FieldFlydown = function(name, isEditable, opt_displayLocation, opt_changeHandler) {
  // This by itself does not control editability
  this.EDITABLE = isEditable;
  // [lyn, 10/27/13] Make flydown direction an instance variable
  this.displayLocation = opt_displayLocation ||
      Blockly.FieldFlydown.DISPLAY_RIGHT;

  Blockly.FieldFlydown.superClass_.constructor.call(
      this, name, opt_changeHandler);
};
goog.inherits(Blockly.FieldFlydown, Blockly.FieldTextInput);

/**
 * Milliseconds to wait before showing flydown after mouseover event on flydown field.
 * @type {number}
 * @const
 */
Blockly.FieldFlydown.timeout = 500;

/**
 * Process ID for timer event to show flydown (scheduled by mouseover event)
 * @type {number}
 * @const
 */
Blockly.FieldFlydown.showPid_ = 0;

/**
 * Which instance of FieldFlydown (or a subclass) is an open flydown attached to?
 * @type {Blockly.FieldFlydown}
 * @private
 */
Blockly.FieldFlydown.openFieldFlydown_ = null;

// These control the positions of the flydown.
Blockly.FieldFlydown.DISPLAY_BELOW = "BELOW";
Blockly.FieldFlydown.DISPLAY_RIGHT = "RIGHT";
Blockly.FieldFlydown.DISPLAY_LOCATION = Blockly.FieldFlydown.DISPLAY_BELOW;

/**
 * Default CSS class name for the field itself
 * @type {string}
 * @const
 */
Blockly.FieldFlydown.prototype.fieldCSSClassName = 'blocklyFieldFlydownField';

/**
 * Default CSS class name for the flydown that flies down from the field
 * @type {string}
 * @const
 */
Blockly.FieldFlydown.prototype.flyoutCSSClassName = 'blocklyFieldFlydownFlydown';

// Override FieldTextInput's showEditor_ so it's only called for EDITABLE field.
Blockly.FieldFlydown.prototype.showEditor_ = function() {
  if (!this.EDITABLE) {
    return;
  }
  if (Blockly.FieldFlydown.showPid_) {  // cancel a pending flydown for editing
    clearTimeout(Blockly.FieldFlydown.showPid_);
    Blockly.FieldFlydown.showPid_ = 0;
    Blockly.hideChaff();
  }
  Blockly.FieldFlydown.superClass_.showEditor_.call(this);
};

Blockly.FieldFlydown.prototype.init = function(block) {
  Blockly.FieldFlydown.superClass_.init.call(this, block);

  // Remove inherited field css classes ...
  Blockly.utils.removeClass(/** @type {!Element} */ (this.fieldGroup_),
      'blocklyEditableText');
  Blockly.utils.removeClass(/** @type {!Element} */ (this.fieldGroup_),
      'blocklyNoNEditableText');
  // ... and add new ones, so that look and feel of flyout fields can be customized
  Blockly.utils.addClass(/** @type {!Element} */ (this.fieldGroup_),
      this.fieldCSSClassName);

  this.mouseOverWrapper_ =
      Blockly.bindEvent_(this.fieldGroup_, 'mouseover', this, this.onMouseOver_);
  this.mouseOutWrapper_ =
      Blockly.bindEvent_(this.fieldGroup_, 'mouseout', this, this.onMouseOut_);
};

Blockly.FieldFlydown.prototype.onMouseOver_ = function(e) {
  if (!this.sourceBlock_.isInFlyout) { // [lyn, 10/22/13] No flydowns in a flyout!
    Blockly.FieldFlydown.showPid_ =
        window.setTimeout(this.showFlydownMaker_(), Blockly.FieldFlydown.timeout);
  }
  // This event has been handled.  No need to bubble up to the document.
  e.stopPropagation();
};

Blockly.FieldFlydown.prototype.onMouseOut_ = function(e) {
  // Clear any pending timer event to show flydown
  window.clearTimeout(Blockly.FieldFlydown.showPid_);
  e.stopPropagation();
};

/**
 * Returns a thunk that creates a Flydown block of the getter and setter blocks for receiver field.
 *  @return A thunk (zero-parameter function).
 */
Blockly.FieldFlydown.prototype.showFlydownMaker_ = function() {
  var field = this; // Name receiver in variable so can close over this variable in returned thunk
  return function() {
    if (Blockly.FieldFlydown.showPid_ !== 0 &&
        Blockly.dragMode_ === Blockly.DRAG_NONE &&
        Blockly.FieldTextInput.htmlInput_ === null) {
      try {
        field.showFlydown_();
      } catch (e) {
        console.error('Failed to show flydown', e);
      }
    }
    Blockly.FieldFlydown.showPid_ = 0;
  };
};

/**
 * Shows the blocks generated by flydownBlocksXML_ in the flydown. Xml should be
 * wrapped in <xml> tags.
 */
Blockly.FieldFlydown.prototype.showFlydown_ = function() {
  Blockly.hideChaff();
  var flydown = Blockly.getMainWorkspace().getFlydown();

  // Add flydown to top-level svg, *not* to main workspace svg
  // This is essential for correct positioning of flydown via translation
  // (If it's in workspace svg, it will be additionally translated by
  //  workspace svg translation relative to Blockly.svg.)
  Blockly.getMainWorkspace().getParentSvg().appendChild(flydown.svgGroup_);

  // Adjust scale for current zoom level
  var scale = flydown.targetWorkspace_.scale;
  flydown.workspace_.setScale(scale);

  flydown.setCSSClass(this.flyoutCSSClassName);

  var blocksXMLText = this.flydownBlocksXML_();
  var blocksDom = Blockly.Xml.textToDom(blocksXMLText);
  // [lyn, 11/10/13] Use goog.dom.getChildren rather than .children or
  //    .childNodes to make this code work across browsers.
  var blocksXMLList = goog.dom.getChildren(blocksDom);

  var xy = Blockly.getMainWorkspace().getSvgXY(this.borderRect_);
  var borderBBox = this.borderRect_.getBBox();
  if (this.displayLocation == Blockly.FieldFlydown.DISPLAY_BELOW) {
    xy.y += borderBBox.height * scale;
  } else { // Display right.
    xy.x += borderBBox.width * scale;
  }

  flydown.showAt(blocksXMLList, xy.x, xy.y);
  Blockly.FieldFlydown.openFieldFlydown_ = this;
};

/**
 * Hide the flydown menu and squash any timer-scheduled flyout creation
 */
Blockly.FieldFlydown.hide = function() {
  // Clear any pending timer event to show flydown.
  window.clearTimeout(Blockly.FieldFlydown.showPid_);
  // Hide any displayed flydown.
  var flydown = Blockly.getMainWorkspace().getFlydown();
  if (flydown) {
    flydown.hide();
  }
};

// TODO: Changing how validators work is not very future proof.
// Override Blockly's behavior; they call the validator after setting the text,
// which is incompatible with how our validators work (we expect to be called
// before the change since in order to find the old references to be renamed).
Blockly.FieldFlydown.prototype.onHtmlInputChange_ = function(e) {
  goog.asserts.assertObject(Blockly.FieldTextInput.htmlInput_);
  var htmlInput = Blockly.FieldTextInput.htmlInput_;
  var text = htmlInput.value;
  if (text !== htmlInput.oldValue_) {
    htmlInput.oldValue_ = text;
    var valid = true;
    if (this.sourceBlock_) {
      valid = this.callValidator(htmlInput.value);
    }
    if (valid === null) {
      Blockly.utils.addClass(htmlInput, 'blocklyInvalidInput');
    } else {
      Blockly.utils.removeClass(htmlInput, 'blocklyInvalidInput');
      this.setText(valid);
    }
  } else if (goog.userAgent.WEBKIT) {
    // Cursor key.  Render the source block to show the caret moving.
    // Chrome only (version 26, OS X).
    this.sourceBlock_.render();
  }
  this.resizeEditor_();
  Blockly.svgResize(this.sourceBlock_.workspace);
};

/**
 * Close the flydown and dispose of all UI.
 */
Blockly.FieldFlydown.prototype.dispose = function() {
  if (Blockly.FieldFlydown.openFieldFlydown_ == this) {
    Blockly.FieldFlydown.hide();
  }
  // Call parent's destructor.
  Blockly.FieldTextInput.prototype.dispose.call(this);
};
<|endoftext|>


<commit_before>import Ember from 'ember'

export default Ember.Component.extend({
  classNames: 'af-form',

  showAllErrors: false,
  fields: Ember.computed(() => Ember.A()),
  fieldsWithError: Ember.computed.filterBy('fields', 'hasError'),
  haveErrors: Ember.computed.notEmpty('fieldsWithError'),

  _pokeObservedComputed: Ember.on('init', function () {
    // We need to do this explicitly to force the observers to run.
    // Computed KVO isn't wired up until a 'get' is run.
    this.getProperties('haveErrors', 'showAllErrors')
  }),

  _haveErrorsObserver: Ember.observer('haveErrors', function () {
    Ember.run.scheduleOnce('actions', this, this._sendActionHaveErrorsChanged)
  }),

  _sendActionHaveErrorsChanged () {
    this.sendAction('haveErrorsChanged', this, this.get('haveErrors'))
  },

  _showAllErrorsObserver: Ember.observer('showAllErrors', function () {
    if (this.get('showAllErrors')) {
      this.displayFieldErrors()
    }
  }),

  displayFieldErrors () {
    this.get('fields').forEach((field) => {
      field.set('hideError', false)
    })
  },

  scrollToErrorField (index = 0) {
    let field = this.get('fieldsWithError').objectAt(index)
    if (field) {
      let offset = field.$().offset()
      Ember.$('html, body').animate({ scrollTop: offset.top - 20 }, 200)
    }
  },

  addField (component) {
    if (this.get('showAllErrors')) {
      component.set('hideError', false)
    }
    this.get('fields').addObject(component)
  },

  removeField (component) {
    this.get('fields').removeObject(component)
  },

  scrollTo (component, { paddingTop = 0 } = {}) {
    let offset = component.$().offset()
    Ember.$('html, body').animate({ scrollTop: offset.top - paddingTop }, 200)
  },

  actions: {
    domSubmit () {
      if (this.get('haveErrors')) {
        this.displayFieldErrors()
        this.sendAction('error', this)
      } else {
        this.sendAction('submit', this)
        this.sendAction('action', this)
      }
    }
  }
})
<commit_msg>Fix render bug using scheduleOnce<commit_after>import Ember from 'ember'

export default Ember.Component.extend({
  classNames: 'af-form',

  showAllErrors: false,
  fields: Ember.computed(() => Ember.A()),
  fieldsWithError: Ember.computed.filterBy('fields', 'hasError'),
  haveErrors: Ember.computed.notEmpty('fieldsWithError'),

  _pokeObservedComputed: Ember.on('init', function () {
    // We need to do this explicitly to force the observers to run.
    // Computed KVO isn't wired up until a 'get' is run.
    this.getProperties('haveErrors', 'showAllErrors')
  }),

  _haveErrorsObserver: Ember.observer('haveErrors', function () {
    Ember.run.scheduleOnce('actions', this, this._sendActionHaveErrorsChanged)
  }),

  _sendActionHaveErrorsChanged () {
    this.sendAction('haveErrorsChanged', this, this.get('haveErrors'))
  },

  _showAllErrorsObserver: Ember.observer('showAllErrors', function () {
    if (this.get('showAllErrors')) {
      this.displayFieldErrors()
    }
  }),

  displayFieldErrors () {
    Ember.run.scheduleOnce('afterRender', this, this._doDisplayFieldErrors)
  },

  _doDisplayFieldErrors () {
    this.get('fields').forEach((field) => {
      field.set('hideError', false)
    })
  },

  scrollToErrorField (index = 0) {
    let field = this.get('fieldsWithError').objectAt(index)
    if (field) {
      let offset = field.$().offset()
      Ember.$('html, body').animate({ scrollTop: offset.top - 20 }, 200)
    }
  },

  addField (component) {
    this.get('fields').addObject(component)

    // Ideally this should be a simple .set(), but it plays havoc with displayFieldErrors()
    // component.set('hideError', false)
    if (this.get('showAllErrors')) {
      this.displayFieldErrors()
    }
  },

  removeField (component) {
    this.get('fields').removeObject(component)
  },

  scrollTo (component, { paddingTop = 0 } = {}) {
    let offset = component.$().offset()
    Ember.$('html, body').animate({ scrollTop: offset.top - paddingTop }, 200)
  },

  actions: {
    domSubmit () {
      if (this.get('haveErrors')) {
        this.displayFieldErrors()
        this.sendAction('error', this)
      } else {
        this.sendAction('submit', this)
        this.sendAction('action', this)
      }
    }
  }
})
<|endoftext|>