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

/**
 * @fileoverview The launcher for the End-To-End extension. Establishes
 * communication with the content scripts. Instantiates the required UI bits
 * that allow the user to interact with the extension.
 */

goog.provide('e2e.ext.AppLauncher');
goog.provide('e2e.ext.ExtensionLauncher');
goog.provide('e2e.ext.Launcher');

goog.require('e2e.ext.Preferences');
goog.require('e2e.ext.api.Api');

goog.scope(function() {
var ext = e2e.ext;
var constants = e2e.ext.constants;
var messages = e2e.ext.messages;

/**
 * Base class for the End-To-End launcher.
 * @param {!e2e.openpgp.Context} pgpContext The OpenPGP context to use.
 * @param {!goog.storage.mechanism.IterableMechanism} preferencesStorage
 *    Storage mechanism for user preferences.
 * @constructor
 */
ext.Launcher = function(pgpContext, preferencesStorage) {

  /**
   * Whether the launcher was started correctly.
   * @type {boolean}
   * @private
   */
  this.started_ = false;

  /**
   * The OpenPGP context used by the extension.
   * @type {!e2e.openpgp.Context}
   * @private
   */
  this.pgpContext_ = pgpContext;

  /**
   * Object for accessing user preferences.
   * @type {!e2e.ext.Preferences}
   * @private
   */
  this.preferences_ = new e2e.ext.Preferences(preferencesStorage);

  /**
   * The context API that the rest of the extension can use to communicate with
   * the PGP context.
   * @type {!ext.api.Api}
   * @private
   */
  this.ctxApi_ = new ext.api.Api();
};

/**
 * Asks for the keyring passphrase and start the launcher.
 * @param {string=} opt_passphrase The passphrase of the keyring.
 * @return {!goog.async.Deferred} Async result. If the passphrase is wrong, an
 * errback of that result will be executed.
 * @export
 */
ext.Launcher.prototype.start = function(opt_passphrase) {
  return this.start_(opt_passphrase || '');
};

/**
 * Starts the launcher.
 * @param {string} passphrase The passphrase of the keyring.
 * @return {!goog.async.Deferred} Async result.
 * @private
 */
ext.Launcher.prototype.start_ = function(passphrase) {
  return this.pgpContext_.initializeKeyRing(passphrase).addCallback(
      function() {
        if (goog.global.chrome &&
        goog.global.chrome.runtime &&
        goog.global.chrome.runtime.getManifest) {
          var manifest = chrome.runtime.getManifest();
          return this.pgpContext_.setArmorHeader(
          'Version',
          manifest.name + ' v' + manifest.version);
        }
      }, this).addCallback(this.completeStart_, this);
};

/** @private */
ext.Launcher.prototype.completeStart_ = function() {
  this.ctxApi_.installApi();
  this.started_ = true;
  this.preferences_.initDefaults();

  this.showWelcomeScreen();
  this.updatePassphraseWarning();
};

/**
 * Returns the PGP context used within the extension.
 * @return {e2e.openpgp.Context} The PGP context.
 * @export
 */
ext.Launcher.prototype.getContext = function() {
  return this.pgpContext_;
};

/**
 * Returns the Preferences object used within the extension.
 * @return {e2e.ext.Preferences} The Preferences object.
 * @export
 */
ext.Launcher.prototype.getPreferences = function() {
  return this.preferences_;
};

/**
 * Indicates if the keyring was loaded with the correct passphrase.
 * @return {boolean} True if the keyring was loaded with the correct passphrase.
 * @export
 */
ext.Launcher.prototype.hasPassphrase = function() {
  return this.started_;
};

/**
 * Display a warning to the user if there is no available passphrase to access
 * the keyring.
 * @protected
 */
ext.Launcher.prototype.updatePassphraseWarning = goog.abstractMethod;

/**
 * Creates a window displaying a document from an internal End-To-End URL.
 * @param {string} url URL of the document.
 * @param {boolean} isForeground Should the focus be moved to the new window.
 * @param {!function(...)} callback Function to call once the window has been
 *     created.
 * @protected
 */
ext.Launcher.prototype.createWindow = goog.abstractMethod;

/**
 * Shows the welcome screen to first-time users.
 * @protected
 */
ext.Launcher.prototype.showWelcomeScreen = function() {
  if (this.preferences_.isWelcomePageEnabled()) {
    this.createWindow('welcome.html', true, goog.nullFunction);
  }
};

/**
 * Constructor to use in End-To-End Chrome extension.
 * @param {!e2e.openpgp.Context} pgpContext The OpenPGP context to use.
 * @param {!goog.storage.mechanism.IterableMechanism} preferencesStorage Storage
 * mechanism for user preferences.
 * @constructor
 * @extends {ext.Launcher}
 */
ext.ExtensionLauncher = function(pgpContext, preferencesStorage) {
  ext.ExtensionLauncher.base(this, 'constructor', pgpContext,
      preferencesStorage);
};
goog.inherits(ext.ExtensionLauncher, ext.Launcher);

/** @override */
ext.ExtensionLauncher.prototype.updatePassphraseWarning = function() {
  if (this.hasPassphrase()) {
    chrome.browserAction.setBadgeText({text: ''});
    chrome.browserAction.setTitle({
      title: chrome.i18n.getMessage('extName')
    });
  } else {
    chrome.browserAction.setBadgeText({text: '!'});
    chrome.browserAction.setTitle({
      title: chrome.i18n.getMessage('passphraseEmptyWarning')
    });
  }
};

/** @override */
ext.ExtensionLauncher.prototype.createWindow = function(url, isForeground,
    callback) {
  chrome.tabs.create({
    url: url,
    active: isForeground
  }, callback);
};

/**
 * Constructor to use in End-To-End Chrome app.
 * @param {!e2e.openpgp.Context} pgpContext The OpenPGP context to use.
 * @param {!goog.storage.mechanism.IterableMechanism} preferencesStorage Storage
 * mechanism for user preferences.
 * @constructor
 * @extends {ext.Launcher}
 */
ext.AppLauncher = function(pgpContext, preferencesStorage) {
  ext.AppLauncher.base(this, 'constructor', pgpContext, preferencesStorage);
  chrome.app.runtime.onLaunched.addListener(function() {
    chrome.app.window.create(
        'webview.html',
        /** @type {!chrome.app.window.CreateWindowOptions} */ ({
          innerBounds: {
            width: 960,
            height: 580
          }
        }));
  });
};
goog.inherits(ext.AppLauncher, ext.Launcher);

/** @override */
ext.AppLauncher.prototype.updatePassphraseWarning = function() {
  // TODO(evn): Implement.
};

/** @override */
ext.AppLauncher.prototype.createWindow = function(url, isForeground, callback) {
  chrome.app.window.create(
      url,
      /** @type {!chrome.app.window.CreateWindowOptions} */ ({
        focused: isForeground,
        innerBounds: {
          width: 900,
          height: 700
        }
      }),
      callback);
};

});  // goog.scope
<commit_msg>updatePassphraseWarning() for wrong passphrase<commit_after>/**
 * @license
 * Copyright 2013 Google Inc. All rights reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @fileoverview The launcher for the End-To-End extension. Establishes
 * communication with the content scripts. Instantiates the required UI bits
 * that allow the user to interact with the extension.
 */

goog.provide('e2e.ext.AppLauncher');
goog.provide('e2e.ext.ExtensionLauncher');
goog.provide('e2e.ext.Launcher');

goog.require('e2e.ext.Preferences');
goog.require('e2e.ext.api.Api');

goog.scope(function() {
var ext = e2e.ext;
var constants = e2e.ext.constants;
var messages = e2e.ext.messages;

/**
 * Base class for the End-To-End launcher.
 * @param {!e2e.openpgp.Context} pgpContext The OpenPGP context to use.
 * @param {!goog.storage.mechanism.IterableMechanism} preferencesStorage
 *    Storage mechanism for user preferences.
 * @constructor
 */
ext.Launcher = function(pgpContext, preferencesStorage) {

  /**
   * Whether the launcher was started correctly.
   * @type {boolean}
   * @private
   */
  this.started_ = false;

  /**
   * The OpenPGP context used by the extension.
   * @type {!e2e.openpgp.Context}
   * @private
   */
  this.pgpContext_ = pgpContext;

  /**
   * Object for accessing user preferences.
   * @type {!e2e.ext.Preferences}
   * @private
   */
  this.preferences_ = new e2e.ext.Preferences(preferencesStorage);

  /**
   * The context API that the rest of the extension can use to communicate with
   * the PGP context.
   * @type {!ext.api.Api}
   * @private
   */
  this.ctxApi_ = new ext.api.Api();
};

/**
 * Asks for the keyring passphrase and start the launcher.
 * @param {string=} opt_passphrase The passphrase of the keyring.
 * @return {!goog.async.Deferred} Async result. If the passphrase is wrong, an
 * errback of that result will be executed.
 * @export
 */
ext.Launcher.prototype.start = function(opt_passphrase) {
  return this.start_(opt_passphrase || '');
};

/**
 * Starts the launcher.
 * @param {string} passphrase The passphrase of the keyring.
 * @return {!goog.async.Deferred} Async result.
 * @private
 */
ext.Launcher.prototype.start_ = function(passphrase) {
  return this.pgpContext_.initializeKeyRing(passphrase).addCallbacks(
      function() {
        if (goog.global.chrome &&
        goog.global.chrome.runtime &&
        goog.global.chrome.runtime.getManifest) {
          var manifest = chrome.runtime.getManifest();
          return this.pgpContext_.setArmorHeader(
          'Version',
          manifest.name + ' v' + manifest.version);
        }
      }, function(e) {
        this.updatePassphraseWarning();
        throw e;
      }, this).addCallback(this.completeStart_, this);
};

/** @private */
ext.Launcher.prototype.completeStart_ = function() {
  this.ctxApi_.installApi();
  this.started_ = true;
  this.preferences_.initDefaults();

  this.showWelcomeScreen();
  this.updatePassphraseWarning();
};

/**
 * Returns the PGP context used within the extension.
 * @return {e2e.openpgp.Context} The PGP context.
 * @export
 */
ext.Launcher.prototype.getContext = function() {
  return this.pgpContext_;
};

/**
 * Returns the Preferences object used within the extension.
 * @return {e2e.ext.Preferences} The Preferences object.
 * @export
 */
ext.Launcher.prototype.getPreferences = function() {
  return this.preferences_;
};

/**
 * Indicates if the keyring was loaded with the correct passphrase.
 * @return {boolean} True if the keyring was loaded with the correct passphrase.
 * @export
 */
ext.Launcher.prototype.hasPassphrase = function() {
  return this.started_;
};

/**
 * Display a warning to the user if there is no available passphrase to access
 * the keyring.
 * @protected
 */
ext.Launcher.prototype.updatePassphraseWarning = goog.abstractMethod;

/**
 * Creates a window displaying a document from an internal End-To-End URL.
 * @param {string} url URL of the document.
 * @param {boolean} isForeground Should the focus be moved to the new window.
 * @param {!function(...)} callback Function to call once the window has been
 *     created.
 * @protected
 */
ext.Launcher.prototype.createWindow = goog.abstractMethod;

/**
 * Shows the welcome screen to first-time users.
 * @protected
 */
ext.Launcher.prototype.showWelcomeScreen = function() {
  if (this.preferences_.isWelcomePageEnabled()) {
    this.createWindow('welcome.html', true, goog.nullFunction);
  }
};

/**
 * Constructor to use in End-To-End Chrome extension.
 * @param {!e2e.openpgp.Context} pgpContext The OpenPGP context to use.
 * @param {!goog.storage.mechanism.IterableMechanism} preferencesStorage Storage
 * mechanism for user preferences.
 * @constructor
 * @extends {ext.Launcher}
 */
ext.ExtensionLauncher = function(pgpContext, preferencesStorage) {
  ext.ExtensionLauncher.base(this, 'constructor', pgpContext,
      preferencesStorage);
};
goog.inherits(ext.ExtensionLauncher, ext.Launcher);

/** @override */
ext.ExtensionLauncher.prototype.updatePassphraseWarning = function() {
  if (this.hasPassphrase()) {
    chrome.browserAction.setBadgeText({text: ''});
    chrome.browserAction.setTitle({
      title: chrome.i18n.getMessage('extName')
    });
  } else {
    chrome.browserAction.setBadgeText({text: '!'});
    chrome.browserAction.setTitle({
      title: chrome.i18n.getMessage('passphraseEmptyWarning')
    });
  }
};

/** @override */
ext.ExtensionLauncher.prototype.createWindow = function(url, isForeground,
    callback) {
  chrome.tabs.create({
    url: url,
    active: isForeground
  }, callback);
};

/**
 * Constructor to use in End-To-End Chrome app.
 * @param {!e2e.openpgp.Context} pgpContext The OpenPGP context to use.
 * @param {!goog.storage.mechanism.IterableMechanism} preferencesStorage Storage
 * mechanism for user preferences.
 * @constructor
 * @extends {ext.Launcher}
 */
ext.AppLauncher = function(pgpContext, preferencesStorage) {
  ext.AppLauncher.base(this, 'constructor', pgpContext, preferencesStorage);
  chrome.app.runtime.onLaunched.addListener(function() {
    chrome.app.window.create(
        'webview.html',
        /** @type {!chrome.app.window.CreateWindowOptions} */ ({
          innerBounds: {
            width: 960,
            height: 580
          }
        }));
  });
};
goog.inherits(ext.AppLauncher, ext.Launcher);

/** @override */
ext.AppLauncher.prototype.updatePassphraseWarning = function() {
  // TODO(evn): Implement.
};

/** @override */
ext.AppLauncher.prototype.createWindow = function(url, isForeground, callback) {
  chrome.app.window.create(
      url,
      /** @type {!chrome.app.window.CreateWindowOptions} */ ({
        focused: isForeground,
        innerBounds: {
          width: 900,
          height: 700
        }
      }),
      callback);
};

});  // goog.scope
<|endoftext|>


<commit_before>ngapp.service('contextMenuFactory', function() {
    let uneditableValueTypes = [xelib.vtUnknown, xelib.vtArray, xelib.vtStruct];

    let divider = {
        visible: (scope, items) => { return items.length > 0 && !items.last().divider; },
        build: (scope, items) => items.push({ divider: true })
    };

    let testNodes = function(nodes, testFn) {
        return nodes.reduce(function (b, node) {
            return b && testFn(node);
        }, true);
    };

    this.checkboxListItems = [{
        id: 'Select All',
        visible: () => { return true; },
        build: (scope, items) => {
            items.push({
                label: 'Select All',
                hotkey: 'Ctrl+A',
                callback: scope.selectAll
            });
        }
    }, {
        id: 'Toggle selected',
        visible: () => { return true; },
        build: (scope, items) => {
            items.push({
                label: 'Toggle selected',
                hotkey: 'Space',
                callback: () => scope.toggleSelected()
            });
        }
    }, {
        id: 'Check Selected',
        visible: () => { return true; },
        build: (scope, items) => {
            items.push({
                label: 'Check Selected',
                hotkey: 'Ctrl+Space',
                callback: () => scope.toggleSelected(true)
            });
        }
    }, {
        id: 'Uncheck Selected',
        visible: () => { return true; },
        build: (scope, items) => {
            items.push({
                label: 'Uncheck Selected',
                hotkey: 'Shift+Space',
                callback: () => scope.toggleSelected(false)
            });
        }
    }];

    this.mainTreeItems = [{
        id: 'Add',
        visible: (scope) => {
            let node = scope.selectedNodes.last();
            if (!node) return;
            return node.element_type !== xelib.etMainRecord && xelib.GetCanAdd(node.handle);
        },
        build: (scope, items) => {
            let node = scope.selectedNodes.last(),
                addList = xelib.GetAddList(node.handle),
                isFile = node.element_type === xelib.etFile;
            items.push({
                label: `Add ${isFile ? 'Group' : 'Record'}`,
                hotkey: 'Insert',
                disabled: !addList.length,
                children: addList.map(function(label) {
                    return {
                        label: label,
                        callback: () => scope.addElement(node, label)
                    };
                })
            });
        }
    }, {
        id: 'Add File',
        visible: (scope) => {
            return !scope.selectedNodes.length;
        },
        build: (scope, items) => {
            items.push({
                label: 'Add File',
                hotkey: 'Insert',
                callback: () => scope.addFile()
            });
        }
    }, {
        id: 'Delete',
        visible: (scope) => {
            if (!scope.selectedNodes.length) return;
            return testNodes(scope.selectedNodes, function(node) {
                return xelib.GetIsRemoveable(node.handle);
            });
        },
        build: (scope, items) => {
            items.push({
                label: 'Delete',
                hotkey: 'Del',
                callback: () => scope.deleteElements()
            });
        }
    }, {
        id: 'Refactor',
        visible: (scope) => {
            if (!scope.selectedNodes.length) return;
            let nodes = scope.selectedNodes, node = nodes.last();
            return node.element_type === xelib.etFile && xelib.GetIsEditable(node.handle) ||
                testNodes(nodes, function(node) {
                    return node.element_type === xelib.etMainRecord && xelib.GetIsEditable(node.handle);
                });
        },
        build: (scope, items) => {
            let node = scope.selectedNodes.last(),
                children = [];
            if (node.element_type === xelib.etFile) {
                children.push({
                    label: 'Rename File',
                    hotkey: 'F2, Alt+Shift+R',
                    callback: () => scope.changeFileName(node)
                }, {
                    label: 'Change Author',
                    hotkey: 'Alt+Shift+A',
                    callback: () => scope.changeFileAuthor(node)
                }, {
                    label: 'Change Description',
                    hotkey: 'Alt+Shift+D',
                    callback: () => scope.changeFileDescription(node)
                });
            } else if (node.element_type === xelib.etMainRecord) {
                children.push({
                    label: 'Rename',
                    hotkey: 'F2, Alt+Shift+R',
                    disabled: true,
                    callback: () => scope.$emit('openModal', 'refactor', {
                        refactorMode: 'Name'
                    })
                }, {
                    label: 'Change Editor IDs',
                    hotkey: 'Alt+Shift+E',
                    disabled: true,
                    callback: () => scope.$emit('openModal', 'refactor', {
                        refactorMode: 'EditorID'
                    })
                }, {
                    label: 'Change Form IDs',
                    hotkey: 'Alt+Shift+F',
                    disabled: true,
                    callback: () => scope.$emit('openModal', 'refactor', {
                        refactorMode: 'FormID'
                    })
                });
            }
            items.push({
                label: 'Refactor',
                children: children
            });
        }
    }, {
        id: 'Masters',
        visible: (scope) => {
            if (!scope.selectedNodes.length) return;
            let nodes = scope.selectedNodes, node = nodes.last();
            return node.element_type === xelib.etFile && xelib.GetIsEditable(node.handle);
        },
        build: (scope, items) => {
            let node = scope.selectedNodes.last();
            items.push({
                label: "Masters",
                children: [{
                    label: 'Add Masters',
                    callback: () => scope.addMasters(node)
                }, {
                    label: 'Sort Masters',
                    callback: () => xelib.SortMasters(node.handle)
                }, {
                    label: 'Clean Masters',
                    callback: () => xelib.CleanMasters(node.handle)
                }]
            });
        }
    },{
        id: 'Enable Editing',
        visible: (scope) => {
            if (!scope.selectedNodes.length) return;
            return testNodes(scope.selectedNodes, function(node) {
                return node.element_type === xelib.etFile && !xelib.GetIsEditable(node.handle);
            });
        },
        build: (scope, items) => {
            items.push({
                label: 'Enable Editing',
                hotkey: 'Ctrl+E',
                callback: () => scope.enableEditing()
            })
        }
    }, divider, {
        id: 'Automate',
        visible: () => { return true; },
        build: (scope, items) => {
            items.push({
                label: 'Automate',
                hotkey: 'Ctrl+M',
                callback: () => scope.$emit('openModal', 'automate', {
                    targetScope: scope
                })
            })
        }
    }, {
        id: 'Advanced Search',
        visible: () => { return true; },
        build: (scope, items) => {
            items.push({
                label: 'Advanced Search',
                hotkey: 'Ctrl+Shift+F',
                disabled: true,
                callback: () => scope.$emit('openModal', 'advancedSearch')
            })
        }
    }, {
        id: 'Open',
        visible: (scope) => {
            let node = scope.selectedNodes.last();
            if (!node) return;
            return node.element_type !== xelib.etGroupRecord;
        },
        build: (scope, items) => {
            let node = scope.selectedNodes.last();
            items.push({
                label: 'Open in Record View',
                hotkey: 'Enter',
                callback: () => scope.open(node)
            })
        }
    }, divider, {
        id: 'Copy to',
        visible: () => { return true; },
        build: (scope, items) => {
            items.push({
                label: 'Copy To',
                hotkey: 'Ctrl+Alt+C',
                disabled: true,
                callback: () => scope.copyNodesTo()
            })
        }
    },{
        id: 'Copy',
        visible: () => { return true; },
        build: (scope, items) => {
            let node = scope.selectedNodes.last();
            items.push({
                label: 'Copy',
                hotkey: 'Ctrl+C',
                disabled: true,//!node,
                callback: () => scope.copyNodes()
            })
        }
    }, {
        id: 'Copy Path',
        visible: () => { return true; },
        build: (scope, items) => {
            let node = scope.selectedNodes.last();
            items.push({
                label: 'Copy Path',
                hotkey: 'Ctrl+Shift+C',
                disabled: true,//!node,
                callback: () => scope.copyNodePaths()
            })
        }
    }, {
        id: 'Paste',
        visible: () => { return true },
        build: (scope, items) => {
            items.push({
                label: 'Paste',
                hotkey: 'Ctrl+V',
                disabled: true,//!scope.canPaste(),
                callback: () => scope.paste()
            })
        }
    }, {
        id: 'Paste as Override',
        visible: () => { return true; },
        build: (scope, items) => {
            items.push({
                label: 'Paste as Override',
                hotkey: 'Ctrl+Shift+V',
                disabled: true,//!scope.canPaste(true),
                callback: () => scope.paste(true)
            })
        }
    }];

    this.recordTreeItems = [{
        id: 'Add',
        visible: (scope) => {
            if (!scope.selectedNodes.length) return;
            let node = scope.selectedNodes.last(),
                index = scope.focusedIndex - 1,
                handle = node.handles[index],
                record = index ? scope.overrides[index - 1] : scope.record,
                parentAvailable = !node.depth || (node.parent && node.parent.handles[index]);
            if (!xelib.GetIsEditable(record)) return false;
            return parentAvailable && (handle === 0 || node.value_type === xelib.vtArray);
        },
        build: (scope, items) => {
            let node = scope.selectedNodes.last(),
                index = scope.focusedIndex - 1;
            items.push({
                label: 'Add',
                hotkey: 'Insert',
                callback: () => scope.addElement(node, index)
            });
        }
    }, {
        id: 'Edit',
        visible: (scope) => {
            if (!scope.selectedNodes.length) return;
            let node = scope.selectedNodes.last(),
                index = scope.focusedIndex - 1,
                handle = node.handles[index],
                record = index === 0 ? scope.record : scope.overrides[index - 1];
            if (!xelib.GetIsEditable(record)) return false;
            return handle !== 0 && !uneditableValueTypes.includes(node.value_type);
        },
        build: (scope, items) => {
            let node = scope.selectedNodes.last(),
                index = scope.focusedIndex;
            items.push({
                label: 'Edit',
                hotkey: 'Enter',
                callback: () => scope.editElement(node, index)
            });
        }
    }, {
        id: 'Delete',
        visible: (scope) => {
            if (!scope.selectedNodes.length) return;
            let index = scope.focusedIndex - 1;
            return testNodes(scope.selectedNodes, function(node) {
                let handle = node.handles[index];
                return handle && xelib.GetIsRemoveable(handle);
            });
        },
        build: (scope, items) => {
            items.push({
                label: 'Delete',
                hotkey: 'Del',
                callback: () => scope.deleteElements()
            });
        }
    }, divider, {
        id: 'Copy',
        visible: () => { return true; },
        build: (scope, items) => {
            let node = scope.selectedNodes.last();
            items.push({
                label: 'Copy',
                hotkey: 'Ctrl+C',
                disabled: true,//!node,
                callback: () => scope.copyNodes()
            })
        }
    }, {
        id: 'Copy Path',
        visible: () => { return true; },
        build: (scope, items) => {
            let node = scope.selectedNodes.last();
            items.push({
                label: 'Copy Path',
                hotkey: 'Ctrl+Shift+C',
                disabled: true,//!node,
                callback: () => scope.copyNodePaths()
            })
        }
    }, {
        id: 'Paste',
        visible: () => { return true },
        build: (scope, items) => {
            items.push({
                label: 'Paste',
                hotkey: 'Ctrl+V',
                disabled: true,//!scope.canPaste(),
                callback: () => scope.paste()
            })
        }
    }]
});
<commit_msg>enabled copy paste items and refactored code in context menu factory<commit_after>ngapp.service('contextMenuFactory', function() {
    let uneditableValueTypes = [xelib.vtUnknown, xelib.vtArray, xelib.vtStruct];

    let divider = {
        visible: (scope, items) => {
            return items.length > 0 && !items.last().divider;
        },
        build: (scope, items) => items.push({ divider: true })
    };

    let testNodes = function(nodes, testFn) {
        return nodes.reduce(function (b, node) {
            return b && testFn(node);
        }, true);
    };

    let isFileNode = function(node) {
        return node.element_type === xelib.etFile;
    };

    let isRecordNode = function(node) {
        return node.element_type === xelib.etMainRecord;
    };

    let isGroupNode = function(node) {
        return node.element_type === xelib.etGroupRecord;
    };

    let isEditableNode = function(node) {
        return xelib.GetIsEditable(node.handle);
    };

    this.checkboxListItems = [{
        id: 'Select All',
        visible: () => { return true; },
        build: (scope, items) => {
            items.push({
                label: 'Select All',
                hotkey: 'Ctrl+A',
                callback: scope.selectAll
            });
        }
    }, {
        id: 'Toggle selected',
        visible: () => { return true; },
        build: (scope, items) => {
            items.push({
                label: 'Toggle selected',
                hotkey: 'Space',
                callback: () => scope.toggleSelected()
            });
        }
    }, {
        id: 'Check Selected',
        visible: () => { return true; },
        build: (scope, items) => {
            items.push({
                label: 'Check Selected',
                hotkey: 'Ctrl+Space',
                callback: () => scope.toggleSelected(true)
            });
        }
    }, {
        id: 'Uncheck Selected',
        visible: () => { return true; },
        build: (scope, items) => {
            items.push({
                label: 'Uncheck Selected',
                hotkey: 'Shift+Space',
                callback: () => scope.toggleSelected(false)
            });
        }
    }];

    this.mainTreeItems = [{
        id: 'Add',
        visible: (scope) => {
            let node = scope.selectedNodes.last();
            return node && !isRecordNode(node) && xelib.GetCanAdd(node.handle);
        },
        build: (scope, items) => {
            let node = scope.selectedNodes.last(),
                addList = xelib.GetAddList(node.handle);
            items.push({
                label: `Add ${isFileNode(node) ? 'Group' : 'Record'}`,
                hotkey: 'Insert',
                disabled: !addList.length,
                children: addList.map(function(label) {
                    return {
                        label: label,
                        callback: () => scope.addElement(node, label)
                    };
                })
            });
        }
    }, {
        id: 'Add File',
        visible: (scope) => {
            return !scope.selectedNodes.length;
        },
        build: (scope, items) => {
            items.push({
                label: 'Add File',
                hotkey: 'Insert',
                callback: () => scope.addFile()
            });
        }
    }, {
        id: 'Delete',
        visible: (scope) => {
            if (!scope.selectedNodes.length) return;
            return testNodes(scope.selectedNodes, function(node) {
                return xelib.GetIsRemoveable(node.handle);
            });
        },
        build: (scope, items) => {
            items.push({
                label: 'Delete',
                hotkey: 'Del',
                callback: () => scope.deleteElements()
            });
        }
    }, {
        id: 'Refactor',
        visible: (scope) => {
            if (!scope.selectedNodes.length) return;
            let nodes = scope.selectedNodes,
                node = nodes.last();
            return isFileNode(node) && isEditableNode(node) ||
                testNodes(nodes, function(node) {
                    return isRecordNode(node) && isEditableNode(node);
                });
        },
        build: (scope, items) => {
            let node = scope.selectedNodes.last(),
                children = [];
            if (isFileNode(node)) {
                children.push({
                    label: 'Rename File',
                    hotkey: 'F2, Alt+Shift+R',
                    callback: () => scope.changeFileName(node)
                }, {
                    label: 'Change Author',
                    hotkey: 'Alt+Shift+A',
                    callback: () => scope.changeFileAuthor(node)
                }, {
                    label: 'Change Description',
                    hotkey: 'Alt+Shift+D',
                    callback: () => scope.changeFileDescription(node)
                });
            } else if (isRecordNode(node)) {
                children.push({
                    label: 'Rename',
                    hotkey: 'F2, Alt+Shift+R',
                    disabled: true,
                    callback: () => scope.$emit('openModal', 'refactor', {
                        refactorMode: 'Name'
                    })
                }, {
                    label: 'Change Editor IDs',
                    hotkey: 'Alt+Shift+E',
                    disabled: true,
                    callback: () => scope.$emit('openModal', 'refactor', {
                        refactorMode: 'EditorID'
                    })
                }, {
                    label: 'Change Form IDs',
                    hotkey: 'Alt+Shift+F',
                    disabled: true,
                    callback: () => scope.$emit('openModal', 'refactor', {
                        refactorMode: 'FormID'
                    })
                });
            }
            items.push({
                label: 'Refactor',
                children: children
            });
        }
    }, {
        id: 'Masters',
        visible: (scope) => {
            if (!scope.selectedNodes.length) return;
            let nodes = scope.selectedNodes, node = nodes.last();
            return isFileNode(node) && isEditableNode(node);
        },
        build: (scope, items) => {
            let node = scope.selectedNodes.last();
            items.push({
                label: "Masters",
                children: [{
                    label: 'Add Masters',
                    callback: () => scope.addMasters(node)
                }, {
                    label: 'Sort Masters',
                    callback: () => xelib.SortMasters(node.handle)
                }, {
                    label: 'Clean Masters',
                    callback: () => xelib.CleanMasters(node.handle)
                }]
            });
        }
    },{
        id: 'Enable Editing',
        visible: (scope) => {
            if (!scope.selectedNodes.length) return;
            return testNodes(scope.selectedNodes, function(node) {
                return isFileNode(node) && !isEditableNode(node);
            });
        },
        build: (scope, items) => {
            items.push({
                label: 'Enable Editing',
                hotkey: 'Ctrl+E',
                callback: () => scope.enableEditing()
            })
        }
    }, divider, {
        id: 'Automate',
        visible: () => { return true; },
        build: (scope, items) => {
            items.push({
                label: 'Automate',
                hotkey: 'Ctrl+M',
                callback: () => scope.$emit('openModal', 'automate', {
                    targetScope: scope
                })
            })
        }
    }, {
        id: 'Advanced Search',
        visible: () => { return true; },
        build: (scope, items) => {
            items.push({
                label: 'Advanced Search',
                hotkey: 'Ctrl+Shift+F',
                disabled: true,
                callback: () => scope.$emit('openModal', 'advancedSearch')
            })
        }
    }, {
        id: 'Open',
        visible: (scope) => {
            let node = scope.selectedNodes.last();
            return node && !isGroupNode(node);
        },
        build: (scope, items) => {
            let node = scope.selectedNodes.last();
            items.push({
                label: 'Open in Record View',
                hotkey: 'Enter',
                callback: () => scope.open(node)
            })
        }
    }, divider, {
        id: 'Copy to',
        visible: () => { return true; },
        build: (scope, items) => {
            items.push({
                label: 'Copy into',
                hotkey: 'Ctrl+Alt+C',
                disabled: scope.selectedNodes.length === 0,
                callback: () => scope.copyInto()
            })
        }
    },{
        id: 'Copy',
        visible: (scope) => { return scope.selectedNodes.length > 0 },
        build: (scope, items) => {
            items.push({
                label: 'Copy',
                hotkey: 'Ctrl+C',
                disabled: !scope.canCopy(),
                callback: () => scope.copyNodes()
            })
        }
    }, {
        id: 'Copy Path',
        visible: (scope) => { return scope.selectedNodes.length > 0 },
        build: (scope, items) => {
            items.push({
                label: 'Copy Path',
                hotkey: 'Ctrl+Shift+C',
                disabled: scope.selectedNodes.length === 0,
                callback: () => scope.copyPaths()
            })
        }
    }, {
        id: 'Paste',
        visible: (scope) => { return scope.selectedNodes.length > 0 },
        build: (scope, items) => {
            items.push({
                label: 'Paste',
                hotkey: 'Ctrl+V',
                disabled: !scope.canPaste(),
                callback: () => scope.pasteNodes(true)
            })
        }
    }, {
        id: 'Paste as Override',
        visible: (scope) => { return scope.selectedNodes.length > 0 },
        build: (scope, items) => {
            items.push({
                label: 'Paste as Override',
                hotkey: 'Ctrl+Shift+V',
                disabled: !scope.canPaste(),
                callback: () => scope.pasteNodes()
            })
        }
    }];

    this.recordTreeItems = [{
        id: 'Add',
        visible: (scope) => {
            if (!scope.selectedNodes.length) return;
            let node = scope.selectedNodes.last(),
                index = scope.focusedIndex - 1,
                handle = node.handles[index],
                record = index ? scope.overrides[index - 1] : scope.record,
                parentAvailable = !node.depth || (node.parent && node.parent.handles[index]);
            if (!xelib.GetIsEditable(record)) return false;
            return parentAvailable && (handle === 0 || node.value_type === xelib.vtArray);
        },
        build: (scope, items) => {
            let node = scope.selectedNodes.last(),
                index = scope.focusedIndex - 1;
            items.push({
                label: 'Add',
                hotkey: 'Insert',
                callback: () => scope.addElement(node, index)
            });
        }
    }, {
        id: 'Edit',
        visible: (scope) => {
            if (!scope.selectedNodes.length) return;
            let node = scope.selectedNodes.last(),
                index = scope.focusedIndex - 1,
                handle = node.handles[index],
                record = index === 0 ? scope.record : scope.overrides[index - 1];
            if (!xelib.GetIsEditable(record)) return false;
            return handle !== 0 && !uneditableValueTypes.includes(node.value_type);
        },
        build: (scope, items) => {
            let node = scope.selectedNodes.last(),
                index = scope.focusedIndex;
            items.push({
                label: 'Edit',
                hotkey: 'Enter',
                callback: () => scope.editElement(node, index)
            });
        }
    }, {
        id: 'Delete',
        visible: (scope) => {
            if (!scope.selectedNodes.length) return;
            let index = scope.focusedIndex - 1;
            return testNodes(scope.selectedNodes, function(node) {
                let handle = node.handles[index];
                return handle && xelib.GetIsRemoveable(handle);
            });
        },
        build: (scope, items) => {
            items.push({
                label: 'Delete',
                hotkey: 'Del',
                callback: () => scope.deleteElements()
            });
        }
    }, divider, {
        id: 'Copy',
        visible: () => { return true; },
        build: (scope, items) => {
            //let node = scope.selectedNodes.last();
            items.push({
                label: 'Copy',
                hotkey: 'Ctrl+C',
                disabled: true,//!node,
                callback: () => scope.copyNodes()
            })
        }
    }, {
        id: 'Copy Path',
        visible: () => { return true; },
        build: (scope, items) => {
            //let node = scope.selectedNodes.last();
            items.push({
                label: 'Copy Path',
                hotkey: 'Ctrl+Shift+C',
                disabled: true,//!node,
                callback: () => scope.copyNodePaths()
            })
        }
    }, {
        id: 'Paste',
        visible: () => { return true },
        build: (scope, items) => {
            items.push({
                label: 'Paste',
                hotkey: 'Ctrl+V',
                disabled: true,//!scope.canPaste(),
                callback: () => scope.paste()
            })
        }
    }]
});
<|endoftext|>


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

    angular
        .module('app')
        .directive('pimJoin', pimJoin);

    function pimJoin($uibModal, $timeout, EntityService, localStorageService){
        return {
            restrict: 'E',
            scope: {
                key: '=', config: '=', value: '=', isValid: '=', isSubmit: '=', onChangeCallback: '&'
            },
            templateUrl: function(){
                return '/ui/default/types/join/join.html?v=' + APP_VERSION
            },
            link: function(scope, element, attrs){
                var itemsPerPage = 10;
                var entity       = null;

                //Properties
                scope.chooserOpened     = false;
                scope.currentPage       = 1;
                scope.deletable         = false;
                scope.hide              = false;
                scope.propertyCount     = 0;
                scope.objects           = [];
                scope.schema            = null;
                scope.selectedIndex     = 0;
                scope.totalPages        = 1;
                scope.writable          = false;
                scope.writable_object   = false;

                //Functions
                scope.addNewObject  = addNewObject;
                scope.change        = change;
                scope.chooseObject  = chooseObject;
                scope.closeChooser  = closeChooser;
                scope.editObject    = editObject;
                scope.keyPressed    = keyPressed;
                scope.loadData      = loadData;
                scope.openChooser   = openChooser;
                scope.removeObject  = removeObject;
                scope.setSelectedIndex = setSelectedIndex;

                //Startup
                init();

                /////////////////////////////////////

                function addNewObject(){
                    var modalInstance = $uibModal.open({
                        templateUrl: '/ui/default/views/form.html',
                        controller: 'FormCtrl as vm',
                        resolve: {
                            entity: function(){ return entity;},
                            title: function(){ return 'Neues Objekt anlegen'; },
                            object: function(){ return null; }
                        },
                        size: 'xl'
                    });

                    modalInstance.result.then(
                        function (newObject) {
                            if(newObject){
                                chooseObject(newObject);
                            }
                        },
                        function () {}
                    );
                }

                function change(){
                    scope.currentPage = 1;
                    loadData();
                }

                function chooseObject(object){

                    scope.value = object;
                    scope.onChangeCallback({key: scope.key, value: object.id});

                    scope.selectedIndex = 0;
                    scope.currentPage = 1;

                    scope.search        = '';
                    scope.objects       = [];

                    closeChooser();

                }

                function closeChooser(){
                    scope.chooserOpened = false;
                }

                function editObject(){

                    var modalInstance = $uibModal.open({
                        templateUrl: '/ui/default/views/form.html',
                        controller: 'FormCtrl as vm',
                        resolve: {
                            entity: function(){ return entity;},
                            title: function(){ return 'Objekt ' + scope.value.id + ' bearbeiten'; },
                            object: function(){ return scope.value; }
                        },
                        size: 'xl'
                    });

                    modalInstance.result.then(
                        function (newObject) {
                            if(newObject){
                                scope.value = newObject;
                            }
                        },
                        function () {}
                    );
                }

                function init(){

                    if(scope.config.accept.substr(0, 18) == 'Areanet\\PIM\\Entity'){
                        entity = scope.config.accept.replace('Areanet\\PIM\\Entity', 'PIM');
                    }else{
                        var fullEntity = null;
                        fullEntity = scope.config.accept.split('\\');
                        entity = fullEntity[(fullEntity.length - 1)];
                    }

                    var permissions = localStorageService.get('permissions');
                    if(!permissions){
                        return;
                    }

                    if(parseInt(scope.value)){

                        var data = {
                            entity : entity,
                            id: scope.value
                        }

                        EntityService.single(data).then(
                            function(response){
                                scope.value = response.data.data;
                            },
                            function(data){

                                if(data.status == 401){
                                    var modalInstance = $uibModal.open({
                                        templateUrl: '/ui/default/views/partials/relogin.html?v=' + APP_VERSION,
                                        controller: 'ReloginCtrl as vm',
                                        backdrop: 'static'
                                    });

                                    modalInstance.result.then(
                                        function () {
                                            init();
                                        },
                                        function () {
                                            $uibModalInstance.close();
                                            $location.path('/logout');
                                        }
                                    );

                                }else {

                                    var modalInstance = $uibModal.open({
                                        templateUrl: '/ui/default/views/partials/modal.html?v=' + APP_VERSION,
                                        controller: 'ModalCtrl as vm',
                                        resolve: {
                                            title: function () {
                                                return data.statusText;
                                            },
                                            body: function () {
                                                return data.data.message;
                                            },
                                            hideCancelButton: function () {
                                                return false;
                                            }
                                        }
                                    });

                                    modalInstance.result.then(
                                        function (doDelete) {
                                            $uibModalInstance.close();
                                        },
                                        function () {
                                            $uibModalInstance.close();
                                        }
                                    );
                                }
                            }
                        );
                    }

                    scope.hide              = !permissions[entity].readable;
                    scope.writable_object   = permissions[entity].writable;
                    scope.writable          = parseInt(attrs.writable) > 0;

                    scope.schema    = localStorageService.get('schema')[entity];

                    scope.propertyCount = Object.keys(scope.schema.list).length;
                }

                function keyPressed(event){
                    switch(event.keyCode) {
                        case 40:
                            if (scope.selectedIndex < scope.objects.length - 1) scope.selectedIndex++;
                            break;
                        case 38:
                            if (scope.selectedIndex > 0) scope.selectedIndex--;
                            break;
                        case 13:
                            chooseObject(scope.objects[scope.selectedIndex]);
                            event.stopPropagation();
                            break;
                        case 39:
                            if (scope.currentPage < scope.totalPages){
                                scope.currentPage++;
                                loadData();
                            }
                            break;
                        case 37:
                            if(scope.currentPage > 1){
                                scope.currentPage--;
                                loadData();
                            }
                            break;
                        case 27:
                            closeChooser();
                            event.stopPropagation();
                            break;
                    }
                }

                function loadData(){
                    var where = scope.search ? {fulltext: scope.search} : {};

                    var properties = ['id', 'modified', 'created', 'user'];
                    if(scope.schema.settings.isSortable){
                        properties.push('sorting');
                    }
                    for (var key in scope.schema.list ) {
                        properties.push(scope.schema.list[key]);
                    }

                    var data = {
                        entity: entity,
                        currentPage: scope.currentPage,
                        itemsPerPage: itemsPerPage,
                        where: where,
                        properties: properties
                    };
                    EntityService.list(data).then(
                        function successCallback(response) {
                            scope.totalPages    = Math.ceil(response.data.totalItems / itemsPerPage);
                            scope.objects       = response.data.data;
                            scope.selectedIndex = 0;
                        },
                        function errorCallback(response) {
                            scope.objects = [];
                        }
                    );
                }

                function openChooser(){
                    scope.chooserOpened = true;

                    $timeout(function () {
                        element.find('#search').focus();
                    }, 50);

                    loadData();
                }

                function removeObject(){
                    scope.value = {};
                    scope.onChangeCallback({key: scope.key, value: ''});
                }

                function setSelectedIndex(index){
                    scope.selectedIndex = index;
                }

            }
        }
    }

})();
<commit_msg>Aufgabe #3463 (Erledigt): GUID-Strategie bei ID-Feldern optional einstellbar (für Synchronisierun...<commit_after>(function() {
    'use strict';

    angular
        .module('app')
        .directive('pimJoin', pimJoin);

    function pimJoin($uibModal, $timeout, EntityService, localStorageService){
        return {
            restrict: 'E',
            scope: {
                key: '=', config: '=', value: '=', isValid: '=', isSubmit: '=', onChangeCallback: '&'
            },
            templateUrl: function(){
                return '/ui/default/types/join/join.html?v=' + APP_VERSION
            },
            link: function(scope, element, attrs){
                var itemsPerPage = 10;
                var entity       = null;

                //Properties
                scope.chooserOpened     = false;
                scope.currentPage       = 1;
                scope.deletable         = false;
                scope.hide              = false;
                scope.propertyCount     = 0;
                scope.objects           = [];
                scope.schema            = null;
                scope.selectedIndex     = 0;
                scope.totalPages        = 1;
                scope.writable          = false;
                scope.writable_object   = false;

                //Functions
                scope.addNewObject  = addNewObject;
                scope.change        = change;
                scope.chooseObject  = chooseObject;
                scope.closeChooser  = closeChooser;
                scope.editObject    = editObject;
                scope.keyPressed    = keyPressed;
                scope.loadData      = loadData;
                scope.openChooser   = openChooser;
                scope.removeObject  = removeObject;
                scope.setSelectedIndex = setSelectedIndex;

                //Startup
                init();

                /////////////////////////////////////

                function addNewObject(){
                    var modalInstance = $uibModal.open({
                        templateUrl: '/ui/default/views/form.html',
                        controller: 'FormCtrl as vm',
                        resolve: {
                            entity: function(){ return entity;},
                            title: function(){ return 'Neues Objekt anlegen'; },
                            object: function(){ return null; }
                        },
                        size: 'xl'
                    });

                    modalInstance.result.then(
                        function (newObject) {
                            if(newObject){
                                chooseObject(newObject);
                            }
                        },
                        function () {}
                    );
                }

                function change(){
                    scope.currentPage = 1;
                    loadData();
                }

                function chooseObject(object){

                    scope.value = object;
                    scope.onChangeCallback({key: scope.key, value: object.id});

                    scope.selectedIndex = 0;
                    scope.currentPage = 1;

                    scope.search        = '';
                    scope.objects       = [];

                    closeChooser();

                }

                function closeChooser(){
                    scope.chooserOpened = false;
                }

                function editObject(){

                    var modalInstance = $uibModal.open({
                        templateUrl: '/ui/default/views/form.html',
                        controller: 'FormCtrl as vm',
                        resolve: {
                            entity: function(){ return entity;},
                            title: function(){ return 'Objekt ' + scope.value.id + ' bearbeiten'; },
                            object: function(){ return scope.value; }
                        },
                        size: 'xl'
                    });

                    modalInstance.result.then(
                        function (newObject) {
                            if(newObject){
                                scope.value = newObject;
                            }
                        },
                        function () {}
                    );
                }

                function isObject(val) {
                    if (val === null) { return false;}
                    return ( (typeof val === 'function') || (typeof val === 'object') );
                }

                function init(){

                    if(scope.config.accept.substr(0, 18) == 'Areanet\\PIM\\Entity'){
                        entity = scope.config.accept.replace('Areanet\\PIM\\Entity', 'PIM');
                    }else{
                        var fullEntity = null;
                        fullEntity = scope.config.accept.split('\\');
                        entity = fullEntity[(fullEntity.length - 1)];
                    }

                    var permissions = localStorageService.get('permissions');
                    if(!permissions){
                        return;
                    }

                    if(scope.value && !isObject(scope.value)){

                        var data = {
                            entity : entity,
                            id: scope.value
                        }

                        EntityService.single(data).then(
                            function(response){
                                scope.value = response.data.data;
                            },
                            function(data){

                                if(data.status == 401){
                                    var modalInstance = $uibModal.open({
                                        templateUrl: '/ui/default/views/partials/relogin.html?v=' + APP_VERSION,
                                        controller: 'ReloginCtrl as vm',
                                        backdrop: 'static'
                                    });

                                    modalInstance.result.then(
                                        function () {
                                            init();
                                        },
                                        function () {
                                            $uibModalInstance.close();
                                            $location.path('/logout');
                                        }
                                    );

                                }else {

                                    var modalInstance = $uibModal.open({
                                        templateUrl: '/ui/default/views/partials/modal.html?v=' + APP_VERSION,
                                        controller: 'ModalCtrl as vm',
                                        resolve: {
                                            title: function () {
                                                return data.statusText;
                                            },
                                            body: function () {
                                                return data.data.message;
                                            },
                                            hideCancelButton: function () {
                                                return false;
                                            }
                                        }
                                    });

                                    modalInstance.result.then(
                                        function (doDelete) {
                                            $uibModalInstance.close();
                                        },
                                        function () {
                                            $uibModalInstance.close();
                                        }
                                    );
                                }
                            }
                        );
                    }

                    scope.hide              = !permissions[entity].readable;
                    scope.writable_object   = permissions[entity].writable;
                    scope.writable          = parseInt(attrs.writable) > 0;

                    scope.schema    = localStorageService.get('schema')[entity];

                    scope.propertyCount = Object.keys(scope.schema.list).length;
                }

                function keyPressed(event){
                    switch(event.keyCode) {
                        case 40:
                            if (scope.selectedIndex < scope.objects.length - 1) scope.selectedIndex++;
                            break;
                        case 38:
                            if (scope.selectedIndex > 0) scope.selectedIndex--;
                            break;
                        case 13:
                            chooseObject(scope.objects[scope.selectedIndex]);
                            event.stopPropagation();
                            break;
                        case 39:
                            if (scope.currentPage < scope.totalPages){
                                scope.currentPage++;
                                loadData();
                            }
                            break;
                        case 37:
                            if(scope.currentPage > 1){
                                scope.currentPage--;
                                loadData();
                            }
                            break;
                        case 27:
                            closeChooser();
                            event.stopPropagation();
                            break;
                    }
                }

                function loadData(){
                    var where = scope.search ? {fulltext: scope.search} : {};

                    var properties = ['id', 'modified', 'created', 'user'];
                    if(scope.schema.settings.isSortable){
                        properties.push('sorting');
                    }
                    for (var key in scope.schema.list ) {
                        properties.push(scope.schema.list[key]);
                    }

                    var data = {
                        entity: entity,
                        currentPage: scope.currentPage,
                        itemsPerPage: itemsPerPage,
                        where: where,
                        properties: properties
                    };
                    EntityService.list(data).then(
                        function successCallback(response) {
                            scope.totalPages    = Math.ceil(response.data.totalItems / itemsPerPage);
                            scope.objects       = response.data.data;
                            scope.selectedIndex = 0;
                        },
                        function errorCallback(response) {
                            scope.objects = [];
                        }
                    );
                }

                function openChooser(){
                    scope.chooserOpened = true;

                    $timeout(function () {
                        element.find('#search').focus();
                    }, 50);

                    loadData();
                }

                function removeObject(){
                    scope.value = {};
                    scope.onChangeCallback({key: scope.key, value: ''});
                }

                function setSelectedIndex(index){
                    scope.selectedIndex = index;
                }

            }
        }
    }

})();
<|endoftext|>


<commit_before>/*
  A SOCKS5 proxy that runs in Chrome based on
    https://github.com/gvangool/node-socks

  For the RFC for socks, see:
    http://tools.ietf.org/html/rfc1928
*/
'use strict';

(function(exports) {
  // TODO: move to using freedom sockets.
  //var socket = freedom['core.socket']();
  var socket = chrome.socket;

  //----------------------------------------------------------------------------
  // SocksUtil
  //----------------------------------------------------------------------------
  var SocksUtil = {};
  /**
   * version 5 of socks
   * @const {number}
   */
  SocksUtil.VERSION5 = 0x05;

  /*
   * Authentication methods
   ************************
   * o  X'00' NO AUTHENTICATION REQUIRED
   * o  X'01' GSSAPI
   * o  X'02' USERNAME/PASSWORD
   * o  X'03' to X'7F' IANA ASSIGNED
   * o  X'80' to X'FE' RESERVED FOR PRIVATE METHODS
   * o  X'FF' NO ACCEPTABLE METHODS
   *
   * @enum {number}
   */
  SocksUtil.AUTHENTICATION = {
    NOAUTH: 0x00,
    GSSAPI: 0x01,
    USERPASS: 0x02,
    NONE: 0xFF
  };

  /*
   * o  CMD
   * o  CONNECT X'01'        // Connect to tcp
   * o  BIND X'02'           // Listen for tcp
   * o  UDP ASSOCIATE X'03'  // Connect to UDP association
   *
   * @enum {number}
   */
  SocksUtil.REQUEST_CMD = {
    CONNECT: 0x01,
    BIND: 0x02,
    UDP_ASSOCIATE: 0x03
  };

  /*
   * o  ATYP   address type of following address
   * o  IP V4 address: X'01'
   * o  DOMAINNAME: X'03'
   * o  IP V6 address: X'04'
   *
   * @enum {number}
   */
  SocksUtil.ATYP = {
    IP_V4: 0x01,
    DNS: 0x03,
    IP_V6: 0x04
  };

  /*
   * o  REP    Reply field:
   * o  X'00' succeeded
   * o  X'01' general SOCKS server failure
   * o  X'02' connection not allowed by ruleset
   * o  X'03' Network unreachable
   * o  X'04' Host unreachable
   * o  X'05' Connection refused
   * o  X'06' TTL expired
   * o  X'07' Command not supported
   * o  X'08' Address type not supported
   * o  X'09' to X'FF' unassigned
   *
   * @enum {number}
   */
  SocksUtil.RESPONSE = {
    SUCCEEDED: 0x00,
    FAILURE: 0x01,
    NOT_ALLOWED: 0x02,
    NETWORK_UNREACHABLE: 0x03,
    HOST_UNREACHABLE: 0x04,
    CONNECTION_REFUSED: 0x05,
    TTL_EXPIRED: 0x06,
    UNSUPPORTED_COMMAND: 0x07,
    ADDRESS_TYPE: 0x08,
    RESERVED: 0x00
  };

  /*
   The SOCKS request is formed as follows:
        +----+-----+-------+------+----------+----------+
        |VER | CMD |  RSV  | ATYP | DST.ADDR | DST.PORT |
        +----+-----+-------+------+----------+----------+
        | 1  |  1  | X'00' |  1   | Variable |    2     |
        +----+-----+-------+------+----------+----------+

     Where:
          o  VER    protocol version: X'05'
          o  CMD
             o  CONNECT X'01'
             o  BIND X'02'
             o  UDP ASSOCIATE X'03'
          o  RSV    RESERVED
          o  ATYP   address type of following address
             o  IP V4 address: X'01'
             o  DOMAINNAME: X'03'
             o  IP V6 address: X'04'
          o  DST.ADDR       desired destination address
          o  DST.PORT desired destination port in network octet
             order
  */
  SocksUtil.interpretSocksRequest = function(byteArray) {
    var result = {};

    if(byteArray.length < 9) {
      return null;
    }

    // Fail if client is not talking Socks version 5.
    result.version = byteArray[0];
    if (result.version !== SocksUtil.VERSION5) {
      result.failure = SocksUtil.RESPONSE.FAILURE;
      return result;
    }

    result.cmd = byteArray[1];
    // Fail unless we got a CONNECT (to TCP) command.
    if (result.cmd != SocksUtil.REQUEST_CMD.CONNECT) {
      result.failure = SocksUtil.RESPONSE.UNSUPPORTED_COMMAND;
      return;
    }

    // Parse address and port and set the callback to be handled by the
    // destination proxy (the bit that actually sends data to the destination).
    result.atyp = byteArray[3];

    if (result.atyp == SocksUtil.ATYP.IP_V4) {
      result.addressSize = 4;
      result.address = byteArray.subarray(4, result.addressSize);
      result.addressString = byteArray[4] + '.' + byteArray[5] + '.' +
          byteArray[6] + '.' + byteArray[7];
      result.portOffset = result.addressSize + 4;
    } else if (result.atyp == SocksUtil.ATYP.DNS) {
      result.addressSize = byteArray[4];
      result.address = byteArray.subarray(5, result.addressSize);
      result.addressString = '';
      for (var i = 0; i < result.addressSize; ++i) {
        result.addressString += String.fromCharCode(byteArray[5 + i]);
      }
      result.portOffset = result.addressSize + 5;
    } else if (result.atyp == SocksUtil.ATYP.IP_V6) {
      result.addressSize = 16;
      result.address = byteArray.subarray(5, result.addressSize);
      var byteDataView = new DataView(byteArray.buffer);
      result.addressString = byteDataView.getUint32(5).toString(16) + '.' +
                             byteDataView.getUint32(5 + 4).toString(16) +
                             byteDataView.getUint32(5 + 8).toString(16) +
                             byteDataView.getUint32(5 + 12).toString(16);
      result.portOffset = result.addressSize + 4;
    } else {
      return null;
    }
    result.portByte1 = byteArray[result.portOffset];
    result.portByte2 = byteArray[result.portOffset + 1];
    result.port = byteArray[result.portOffset] << 8 |
                  byteArray[result.portOffset + 1];
    result.dataOffset = result.portOffset + 2;
    result.data = byteArray.subarray(result.dataOffset,
                                     byteArray.length - result.dataOffset);
    console.log(result);
    return result;
  };

  //----------------------------------------------------------------------------
  // SocksServer
  //----------------------------------------------------------------------------
  /**
   * destination_callback = function(tcpConnection, address, port,
        connectedToDestinationCallback) {...}
   */
  function SocksServer(address, port, destinationCallback) {
    var self = this;
    // Holds index from socketId
    this.destinationCallback = destinationCallback;

    this.tcpServer = new window.TcpServer(address || 'localhost',
                                          port || 1080);

    // When we start listening, print it out.
    this.tcpServer.on('listening', function() {
      console.info('LISTENING %s:%d', self.tcpServer.addr,
                   self.tcpServer.port);
    });

    // When we receieve a new connection make a new SocksClientConnection.
    // and log to info.
    this.tcpServer.on('connection', function(tcpConnection) {
      console.info('CONNECTED(%d) %s:%d', tcpConnection.socketId,
          tcpConnection.socketInfo.peerAddress,
          tcpConnection.socketInfo.peerPort);
      tcpConnection.on('recv', function(buffer) {
        console.log('new SocksClientConnection (%s): \n* Got data: %s', tcpConnection.socketId, JSON.stringify(tcpConnection.state()),getHexStringOfArrayBuffer(buffer));
        tcpConnection.socksClient =
            new SocksClientConnection(tcpConnection, buffer,
                                      self.destinationCallback);
      }, {minByteLength: 3});
    });
  }

  SocksServer.prototype.disconnect = function() {
    this.tcpServer.disconnect();
  }

  //----------------------------------------------------------------------------
  // SocksClientConnection
  //----------------------------------------------------------------------------
  /**
   * Connection to a particular socks client
   */
  function SocksClientConnection(tcpConnection, buffer, destinationCallback) {
    this.tcpConnection = tcpConnection;  // to the client.
    this.destinationCallback = destinationCallback;
    this.method_count = 0;
    this.auth_methods = [];
    this.request = null;
    var self = this;
    var response;  // Uint8Array;

    console.log('SocksClientConnection(%d): Auth (length=%d)',
        this.tcpConnection.socketId, buffer.byteLength);

    // We are no longer at waiting for a proxy request on this tcp connection.
    // this.tcpConnection.on('recv', null);

    var byteArray = new Uint8Array(buffer);
    // Only SOCKS Version 5 is supported
    if (byteArray[0] != SocksUtil.VERSION5) {
      console.error('SocksClientConnection(%d): unsupported socks version: %d',
          this.tcpConnection.socketId, byteArray[0]);
      this.tcpConnection.disconnect();
      return;
    }

    // Number of authentication methods
    var methodCount = byteArray[1];
    // Get the supported authentication methods.
    // i starts on 1, since we've read byteArray 0 & 1 already
    for (var i = 2; i < methodCount + 2; i++) {
      this.auth_methods.push(byteArray[i]);
    }
    // Make sure the client supports no authentication.
    if (this.auth_methods.indexOf(SocksUtil.AUTHENTICATION.NOAUTH) <= -1) {
      console.error('SocksClientConnection: no auth methods',
          SocksUtil.AUTHENTICATION.NOAUTH);
      response = new Uint8Array(2);
      response[0] = SocksUtil.VERSION5;
      response[1] = SocksUtil.AUTHENTICATION.NONE;
      this.tcpConnection.sendRaw(response.buffer);
      this.tcpConnection.disconnect();
      return;
    }

    // Handle more data with request handler.
    this.tcpConnection.on('recv', this._handleRequest.bind(this));
    // Send request to use NOAUTH for authentication
    response = new Uint8Array(2);
    response[0] = SocksUtil.VERSION5;
    response[1] = SocksUtil.AUTHENTICATION.NOAUTH;
    this.tcpConnection.sendRaw(response.buffer);
  };

  // Given an array buffer of data (buffer) interpret the SOCKS request.
  SocksClientConnection.prototype._handleRequest = function(buffer) {
    // We only handle one request per tcp connection. Note that pending data
    // will be stored and sent to the next non-null callback.
    this.tcpConnection.on('recv', null);

    console.log(this.tcpConnection);
    console.log('SocksClientConnection(%d): handleRequest\n*got data: %s; \n data: %s', this.tcpConnection.socketId,
      JSON.stringify(this.tcpConnection.state()),
      getHexStringOfArrayBuffer(buffer));

    var byteArray = new Uint8Array(buffer);
    this.result = SocksUtil.interpretSocksRequest(byteArray);

    console.log('SocksClientConnection(%d): parsed request: %s', this.tcpConnection.socketId,
      JSON.stringify(this.result));

    if (this.result == null) {
      console.error('SocksClientConnection(%d): bad request (length %d)',
          this.tcpConnection.socketId, byteArray.length);
      this.tcpConnection.disconnect();
      return;
    } else if ('failure' in this.result) {
      var response = new Uint8Array(2);
      response[0] = SocksUtil.VERSION5;
      response[1] = this.result.failure;
      this.tcpConnection.sendRaw(response.buffer);
      this.tcpConnection.disconnect();
      console.error('SocksClientConnection(%d): unsupported request: %d',
          this.tcpConnection.socketId, this.result.failure);
      return;
    }

    console.log('SocksClientConnection(%d): Request: {cmd:%d, atyp:%d} ' +
        'to: %s:%s',
        this.tcpConnection.socketId,
        this.result.cmd, this.result.atyp, this.result.addressString,
        this.result.port);
    // TODO: add a handler for failure to reach destination.
    this.destinationCallback(this, this.result.address, this.result.port,
        this._connectedToDestination.bind(this));
  };

  /**
   * Called when the connection to the final destination site is made.
   * This tells the client the address of the destination reached.
   */
  SocksClientConnection.prototype._connectedToDestination = function(
      connectionDetails,
      continuation) {
    console.log('SocksClientConnection(%d): ' +
        'connected to destination %s:%d',
        this.tcpConnection.socketId,
        connectionDetails.ipAddrString, connectionDetails.port);
    var response = [];
    // creating response
    response[0] = SocksUtil.VERSION5;
    response[1] = SocksUtil.RESPONSE.SUCCEEDED;
    response[2] = 0x00;
    response[3] = SocksUtil.ATYP.IP_V4;

    var v4 = '([\\d]{1,3})';
    var v4d = '\\.';
    var v4complete = v4+v4d+v4+v4d+v4+v4d+v4
    var v4regex = new RegExp(v4complete);

    var ipv4 = connectionDetails.ipAddrString.match(v4regex);
    if (ipv4) {
      response[4] = parseInt(ipv4[1]);
      response[5] = parseInt(ipv4[2]);
      response[6] = parseInt(ipv4[3]);
      response[7] = parseInt(ipv4[3]);
    }
    // TODO: support IPv6
    response[8] = connectionDetails.port & 0xF0;
    response[9] = connectionDetails.port & 0x0F;
    var responseArray = new Uint8Array(response);
    /* var j = 4;
    if (this.result.atyp == ATYP.DNS) {
      response[j] = this.result.addressSize;
      j++;
    }
    for (var i = 0; i < this.result.addressSize; ++i) {
      response[i + j] = this.result.address[i];
    }
    response[this.result.addressSize + j] = this.result.portByte1;
    response[this.result.addressSize + j + 1] = this.result.portByte2;
    */
    this.tcpConnection.sendRaw(responseArray.buffer);
    if (continuation) { continuation(); }
  };

  //----------------------------------------------------------------------------
  exports.SocksUtil = SocksUtil;
  exports.SocksServer = SocksServer;
  exports.SocksClientConnection = SocksClientConnection;
})(window);
<commit_msg>Added passing of raw SOCKS connect data in request<commit_after>/*
  A SOCKS5 proxy that runs in Chrome based on
    https://github.com/gvangool/node-socks

  For the RFC for socks, see:
    http://tools.ietf.org/html/rfc1928
*/
'use strict';

(function(exports) {
  // TODO: move to using freedom sockets.
  //var socket = freedom['core.socket']();
  var socket = chrome.socket;

  //----------------------------------------------------------------------------
  // SocksUtil
  //----------------------------------------------------------------------------
  var SocksUtil = {};
  /**
   * version 5 of socks
   * @const {number}
   */
  SocksUtil.VERSION5 = 0x05;

  /*
   * Authentication methods
   ************************
   * o  X'00' NO AUTHENTICATION REQUIRED
   * o  X'01' GSSAPI
   * o  X'02' USERNAME/PASSWORD
   * o  X'03' to X'7F' IANA ASSIGNED
   * o  X'80' to X'FE' RESERVED FOR PRIVATE METHODS
   * o  X'FF' NO ACCEPTABLE METHODS
   *
   * @enum {number}
   */
  SocksUtil.AUTHENTICATION = {
    NOAUTH: 0x00,
    GSSAPI: 0x01,
    USERPASS: 0x02,
    NONE: 0xFF
  };

  /*
   * o  CMD
   * o  CONNECT X'01'        // Connect to tcp
   * o  BIND X'02'           // Listen for tcp
   * o  UDP ASSOCIATE X'03'  // Connect to UDP association
   *
   * @enum {number}
   */
  SocksUtil.REQUEST_CMD = {
    CONNECT: 0x01,
    BIND: 0x02,
    UDP_ASSOCIATE: 0x03
  };

  /*
   * o  ATYP   address type of following address
   * o  IP V4 address: X'01'
   * o  DOMAINNAME: X'03'
   * o  IP V6 address: X'04'
   *
   * @enum {number}
   */
  SocksUtil.ATYP = {
    IP_V4: 0x01,
    DNS: 0x03,
    IP_V6: 0x04
  };

  /*
   * o  REP    Reply field:
   * o  X'00' succeeded
   * o  X'01' general SOCKS server failure
   * o  X'02' connection not allowed by ruleset
   * o  X'03' Network unreachable
   * o  X'04' Host unreachable
   * o  X'05' Connection refused
   * o  X'06' TTL expired
   * o  X'07' Command not supported
   * o  X'08' Address type not supported
   * o  X'09' to X'FF' unassigned
   *
   * @enum {number}
   */
  SocksUtil.RESPONSE = {
    SUCCEEDED: 0x00,
    FAILURE: 0x01,
    NOT_ALLOWED: 0x02,
    NETWORK_UNREACHABLE: 0x03,
    HOST_UNREACHABLE: 0x04,
    CONNECTION_REFUSED: 0x05,
    TTL_EXPIRED: 0x06,
    UNSUPPORTED_COMMAND: 0x07,
    ADDRESS_TYPE: 0x08,
    RESERVED: 0x00
  };

  /*
   The SOCKS request is formed as follows:
        +----+-----+-------+------+----------+----------+
        |VER | CMD |  RSV  | ATYP | DST.ADDR | DST.PORT |
        +----+-----+-------+------+----------+----------+
        | 1  |  1  | X'00' |  1   | Variable |    2     |
        +----+-----+-------+------+----------+----------+

     Where:
          o  VER    protocol version: X'05'
          o  CMD
             o  CONNECT X'01'
             o  BIND X'02'
             o  UDP ASSOCIATE X'03'
          o  RSV    RESERVED
          o  ATYP   address type of following address
             o  IP V4 address: X'01'
             o  DOMAINNAME: X'03'
             o  IP V6 address: X'04'
          o  DST.ADDR       desired destination address
          o  DST.PORT desired destination port in network octet
             order
  */
  SocksUtil.interpretSocksRequest = function(byteArray) {
    var result = {};

    if(byteArray.length < 9) {
      return null;
    }

    // Fail if client is not talking Socks version 5.
    result.version = byteArray[0];
    if (result.version !== SocksUtil.VERSION5) {
      result.failure = SocksUtil.RESPONSE.FAILURE;
      return result;
    }

    result.cmd = byteArray[1];
    // Fail unless we got a CONNECT (to TCP) command.
    if (result.cmd != SocksUtil.REQUEST_CMD.CONNECT) {
      result.failure = SocksUtil.RESPONSE.UNSUPPORTED_COMMAND;
      return;
    }

    // Parse address and port and set the callback to be handled by the
    // destination proxy (the bit that actually sends data to the destination).
    result.atyp = byteArray[3];

    if (result.atyp == SocksUtil.ATYP.IP_V4) {
      result.addressSize = 4;
      result.address = byteArray.subarray(4, result.addressSize);
      result.addressString = byteArray[4] + '.' + byteArray[5] + '.' +
          byteArray[6] + '.' + byteArray[7];
      result.portOffset = result.addressSize + 4;
    } else if (result.atyp == SocksUtil.ATYP.DNS) {
      result.addressSize = byteArray[4];
      result.address = byteArray.subarray(5, result.addressSize);
      result.addressString = '';
      for (var i = 0; i < result.addressSize; ++i) {
        result.addressString += String.fromCharCode(byteArray[5 + i]);
      }
      result.portOffset = result.addressSize + 5;
    } else if (result.atyp == SocksUtil.ATYP.IP_V6) {
      result.addressSize = 16;
      result.address = byteArray.subarray(5, result.addressSize);
      var byteDataView = new DataView(byteArray.buffer);
      result.addressString = byteDataView.getUint32(5).toString(16) + '.' +
                             byteDataView.getUint32(5 + 4).toString(16) +
                             byteDataView.getUint32(5 + 8).toString(16) +
                             byteDataView.getUint32(5 + 12).toString(16);
      result.portOffset = result.addressSize + 4;
    } else {
      return null;
    }
    result.portByte1 = byteArray[result.portOffset];
    result.portByte2 = byteArray[result.portOffset + 1];
    result.port = byteArray[result.portOffset] << 8 |
                  byteArray[result.portOffset + 1];
    result.dataOffset = result.portOffset + 2;
    result.raw = byteArray.subarray(0, result.dataOffset);
    result.data = byteArray.subarray(result.dataOffset,
                                     byteArray.length - result.dataOffset);
    console.log(result);
    return result;
  };

  //----------------------------------------------------------------------------
  // SocksServer
  //----------------------------------------------------------------------------
  /**
   * destination_callback = function(tcpConnection, address, port,
        connectedToDestinationCallback) {...}
   */
  function SocksServer(address, port, destinationCallback) {
    var self = this;
    // Holds index from socketId
    this.destinationCallback = destinationCallback;

    this.tcpServer = new window.TcpServer(address || 'localhost',
                                          port || 1080);

    // When we start listening, print it out.
    this.tcpServer.on('listening', function() {
      console.info('LISTENING %s:%d', self.tcpServer.addr,
                   self.tcpServer.port);
    });

    // When we receieve a new connection make a new SocksClientConnection.
    // and log to info.
    this.tcpServer.on('connection', function(tcpConnection) {
      console.info('CONNECTED(%d) %s:%d', tcpConnection.socketId,
          tcpConnection.socketInfo.peerAddress,
          tcpConnection.socketInfo.peerPort);
      tcpConnection.on('recv', function(buffer) {
        console.log('new SocksClientConnection (%s): \n* Got data: %s', tcpConnection.socketId, JSON.stringify(tcpConnection.state()),getHexStringOfArrayBuffer(buffer));
        tcpConnection.socksClient =
            new SocksClientConnection(tcpConnection, buffer,
                                      self.destinationCallback);
      }, {minByteLength: 3});
    });
  }

  SocksServer.prototype.disconnect = function() {
    this.tcpServer.disconnect();
  }

  //----------------------------------------------------------------------------
  // SocksClientConnection
  //----------------------------------------------------------------------------
  /**
   * Connection to a particular socks client
   */
  function SocksClientConnection(tcpConnection, buffer, destinationCallback) {
    this.tcpConnection = tcpConnection;  // to the client.
    this.destinationCallback = destinationCallback;
    this.method_count = 0;
    this.auth_methods = [];
    this.request = null;
    var self = this;
    var response;  // Uint8Array;

    console.log('SocksClientConnection(%d): Auth (length=%d)',
        this.tcpConnection.socketId, buffer.byteLength);

    // We are no longer at waiting for a proxy request on this tcp connection.
    // this.tcpConnection.on('recv', null);

    var byteArray = new Uint8Array(buffer);
    // Only SOCKS Version 5 is supported
    if (byteArray[0] != SocksUtil.VERSION5) {
      console.error('SocksClientConnection(%d): unsupported socks version: %d',
          this.tcpConnection.socketId, byteArray[0]);
      this.tcpConnection.disconnect();
      return;
    }

    // Number of authentication methods
    var methodCount = byteArray[1];
    // Get the supported authentication methods.
    // i starts on 1, since we've read byteArray 0 & 1 already
    for (var i = 2; i < methodCount + 2; i++) {
      this.auth_methods.push(byteArray[i]);
    }
    // Make sure the client supports no authentication.
    if (this.auth_methods.indexOf(SocksUtil.AUTHENTICATION.NOAUTH) <= -1) {
      console.error('SocksClientConnection: no auth methods',
          SocksUtil.AUTHENTICATION.NOAUTH);
      response = new Uint8Array(2);
      response[0] = SocksUtil.VERSION5;
      response[1] = SocksUtil.AUTHENTICATION.NONE;
      this.tcpConnection.sendRaw(response.buffer);
      this.tcpConnection.disconnect();
      return;
    }

    // Handle more data with request handler.
    this.tcpConnection.on('recv', this._handleRequest.bind(this));
    // Send request to use NOAUTH for authentication
    response = new Uint8Array(2);
    response[0] = SocksUtil.VERSION5;
    response[1] = SocksUtil.AUTHENTICATION.NOAUTH;
    this.tcpConnection.sendRaw(response.buffer);
  };

  // Given an array buffer of data (buffer) interpret the SOCKS request.
  SocksClientConnection.prototype._handleRequest = function(buffer) {
    // We only handle one request per tcp connection. Note that pending data
    // will be stored and sent to the next non-null callback.
    this.tcpConnection.on('recv', null);

    console.log(this.tcpConnection);
    console.log('SocksClientConnection(%d): handleRequest\n*got data: %s; \n data: %s', this.tcpConnection.socketId,
      JSON.stringify(this.tcpConnection.state()),
      getHexStringOfArrayBuffer(buffer));

    var byteArray = new Uint8Array(buffer);
    this.result = SocksUtil.interpretSocksRequest(byteArray);

    console.log('SocksClientConnection(%d): parsed request: %s', this.tcpConnection.socketId,
      JSON.stringify(this.result));

    if (this.result == null) {
      console.error('SocksClientConnection(%d): bad request (length %d)',
          this.tcpConnection.socketId, byteArray.length);
      this.tcpConnection.disconnect();
      return;
    } else if ('failure' in this.result) {
      var response = new Uint8Array(2);
      response[0] = SocksUtil.VERSION5;
      response[1] = this.result.failure;
      this.tcpConnection.sendRaw(response.buffer);
      this.tcpConnection.disconnect();
      console.error('SocksClientConnection(%d): unsupported request: %d',
          this.tcpConnection.socketId, this.result.failure);
      return;
    }

    console.log('SocksClientConnection(%d): Request: {cmd:%d, atyp:%d} ' +
        'to: %s:%s',
        this.tcpConnection.socketId,
        this.result.cmd, this.result.atyp, this.result.addressString,
        this.result.port);
    // TODO: add a handler for failure to reach destination.
    this.destinationCallback(this, this.result.address, this.result.port,
        this._connectedToDestination.bind(this));
  };

  /**
   * Called when the connection to the final destination site is made.
   * This tells the client the address of the destination reached.
   */
  SocksClientConnection.prototype._connectedToDestination = function(
      connectionDetails,
      continuation) {
    console.log('SocksClientConnection(%d): ' +
        'connected to destination %s:%d',
        this.tcpConnection.socketId,
        connectionDetails.ipAddrString, connectionDetails.port);
    var response = [];
    // creating response
    response[0] = SocksUtil.VERSION5;
    response[1] = SocksUtil.RESPONSE.SUCCEEDED;
    response[2] = 0x00;
    response[3] = SocksUtil.ATYP.IP_V4;

    var v4 = '([\\d]{1,3})';
    var v4d = '\\.';
    var v4complete = v4+v4d+v4+v4d+v4+v4d+v4
    var v4regex = new RegExp(v4complete);

    var ipv4 = connectionDetails.ipAddrString.match(v4regex);
    if (ipv4) {
      response[4] = parseInt(ipv4[1]);
      response[5] = parseInt(ipv4[2]);
      response[6] = parseInt(ipv4[3]);
      response[7] = parseInt(ipv4[3]);
    }
    // TODO: support IPv6
    response[8] = connectionDetails.port & 0xF0;
    response[9] = connectionDetails.port & 0x0F;
    var responseArray = new Uint8Array(response);
    /* var j = 4;
    if (this.result.atyp == ATYP.DNS) {
      response[j] = this.result.addressSize;
      j++;
    }
    for (var i = 0; i < this.result.addressSize; ++i) {
      response[i + j] = this.result.address[i];
    }
    response[this.result.addressSize + j] = this.result.portByte1;
    response[this.result.addressSize + j + 1] = this.result.portByte2;
    */
    this.tcpConnection.sendRaw(responseArray.buffer);
    if (continuation) { continuation(); }
  };

  //----------------------------------------------------------------------------
  exports.SocksUtil = SocksUtil;
  exports.SocksServer = SocksServer;
  exports.SocksClientConnection = SocksClientConnection;
})(window);
<|endoftext|>


<commit_before>angular.module('ionic.services.core', [])

/**
 * A core Ionic account identity provider.
 *
 * Usage:
 * angular.module('myApp', ['ionic', 'ionic.services.common'])
 * .config(['$ionicAppProvider', function($ionicAccountProvider) {
 *   $ionicAppProvider.identify({
 *     app_id: 'x34dfxjydi23dx'
 *   });
 * }]);
 */
.provider('$ionicApp', function() {
  var app = {};

  var settings = {
    'api_server': 'http://ionic.io'
  };

  this.identify = function(opts) {
    app = opts;
  };

  /**
   * Set a config property.
   */
  this.set = function(k, v) {
    settings[k] = v;
  };

  this.setApiServer = function(server) {
    settings.api_server = server;
  };

  this.$get = [function() {
    return {
      getValue: function(k) {
        return settings[k];
      },
      getApiWriteKey: function() {
        return app.api_write_key;
      },
      getApiReadKey: function() {
        return app.api_read_key;
      },
      getApiUrl: function() {
        return this.getValue('api_server');
      },

      getApiEndpoint: function(service) {
        var app = this.getApp();
        if(!app) return null;

        return this.getApiUrl() + '/api/v1/' + app.app_id + '/' + service;
      },

      /**
       * Get the registered app for all commands.
       */
      getApp: function() {
        return app;
      }
    }
  }];
});
<commit_msg>Singular module name<commit_after>angular.module('ionic.service.core', [])

/**
 * A core Ionic account identity provider.
 *
 * Usage:
 * angular.module('myApp', ['ionic', 'ionic.service.core'])
 * .config(['$ionicAppProvider', function($ionicAccountProvider) {
 *   $ionicAppProvider.identify({
 *     app_id: 'x34dfxjydi23dx'
 *   });
 * }]);
 */
.provider('$ionicApp', function() {
  var app = {};

  var settings = {
    'api_server': 'https://ionic.io',
    'push_api_server': 'https://push.ionic.io/
  };

  this.identify = function(opts) {
    app = opts;
  };

  /**
   * Set a config property.
   */
  this.set = function(k, v) {
    settings[k] = v;
  };

  this.setApiServer = function(server) {
    settings.api_server = server;
  };

  this.$get = [function() {
    return {
      getValue: function(k) {
        return settings[k];
      },
      getApiWriteKey: function() {
        return app.api_write_key;
      },
      getApiReadKey: function() {
        return app.api_read_key;
      },
      getApiUrl: function() {
        return this.getValue('api_server');
      },

      getApiEndpoint: function(service) {
        var app = this.getApp();
        if(!app) return null;

        return this.getApiUrl() + '/api/v1/' + app.app_id + '/' + service;
      },

      /**
       * Get the registered app for all commands.
       */
      getApp: function() {
        return app;
      }
    }
  }];
});
<|endoftext|>


<commit_before>import { rodata } from '../rodata'

const createTxtViewArea = (bun, allBunArr, i,verbBunHtml,isArrow)=>{

  console.log(verbBunHtml)
  //1つ1つのTextViewAreaをつくる
  createBox(i)
  /*  for(let i=bun.bunNo-3;i<=bun.bunNo+3;i++){
      console.log(allBunArr[i])
    }*/
  if(bun.bunNo!==0&&allBunArr[ bun.bunNo - 1]!==void 0){
    if(bun.bunNo!==1&&allBunArr[ bun.bunNo - 2]!==void 0){
      if(bun.bunNo!==2&&allBunArr[ bun.bunNo - 3]!==void 0){
        addBun('msg'+i, allBunArr[ bun.bunNo - 3], false)
      }
      addBun('msg'+i, allBunArr[ bun.bunNo - 2], false)
    }
    addBun('msg'+i, allBunArr[ bun.bunNo - 1], false)
  }

  //addBun('msg'+i,allBunArr[bun.bunNo], true)
  addWatchingBun(i,bun,true,verbBunHtml,isArrow)

  if( bun.bunNo + 1 !== allBunArr.length &&allBunArr[ bun.bunNo +1]!==void 0){
    addBun('msg'+i , allBunArr[bun.bunNo + 1], false)
    if( bun.bunNo + 2 !== allBunArr.length &&allBunArr[ bun.bunNo +2]!==void 0){
      addBun('msg'+i , allBunArr[bun.bunNo + 2], false)
      if( bun.bunNo + 3 !== allBunArr.length &&allBunArr[ bun.bunNo +3]!==void 0){
        addBun('msg'+i , allBunArr[bun.bunNo + 3], false)
      }
    }
  }
}

const createBox=(i)=>{
  //箱を作る

  let msg = document.getElementById('box')
  msg.innerHTML += '
'
}

const addBun=(id,bun,bold,verbBunHtml,isArrow)=>{
  //箱に1文を追加。boldはboolean
  let msg = document.getElementById(id)
  const talker=""
  const color="#000000"
  const bunNo = bun.bunNo
  const bunContent=bun.surfaceForm
  if(bold){msg.innerHTML+=""}
  msg.innerHTML += '' + bunNo + '' + talker + ' 【'
  if(isArrow){
    msg.innerHTML +=  verbBunHtml
  }else{
    msg.innerHTML +=  bunContent
  }
  msg.innerHTML += '】

'
  if(bold){msg.innerHTML+=""}
}

const addWatchingBun = (i,bun,isBold,verbBunHtml,isArrow) => {

  if(isArrow){
    addBun('msg'+i,bun, true,verbBunHtml,true)
  }else{
    addBun('msg'+i,bun, true,null,false)
  }
}

export{createTxtViewArea}<commit_msg>update: add under line when we click circle.<commit_after>import { rodata } from '../rodata'

const createTxtViewArea = (bun, allBunArr, i,verbBunHtml,isArrow)=>{

  //console.log(verbBunHtml)
  //1つ1つのTextViewAreaをつくる
  createBox(i)
  /*  for(let i=bun.bunNo-3;i<=bun.bunNo+3;i++){
      console.log(allBunArr[i])
    }*/
  if(bun.bunNo!==0&&allBunArr[ bun.bunNo - 1]!==void 0){
    if(bun.bunNo!==1&&allBunArr[ bun.bunNo - 2]!==void 0){
      if(bun.bunNo!==2&&allBunArr[ bun.bunNo - 3]!==void 0){
        addBun('msg'+i, allBunArr[ bun.bunNo - 3], false)
      }
      addBun('msg'+i, allBunArr[ bun.bunNo - 2], false)
    }
    addBun('msg'+i, allBunArr[ bun.bunNo - 1], false)
  }

  //addBun('msg'+i,allBunArr[bun.bunNo], true)
  addWatchingBun(i,bun,true,verbBunHtml,isArrow)

  if( bun.bunNo + 1 !== allBunArr.length &&allBunArr[ bun.bunNo +1]!==void 0){
    addBun('msg'+i , allBunArr[bun.bunNo + 1], false)
    if( bun.bunNo + 2 !== allBunArr.length &&allBunArr[ bun.bunNo +2]!==void 0){
      addBun('msg'+i , allBunArr[bun.bunNo + 2], false)
      if( bun.bunNo + 3 !== allBunArr.length &&allBunArr[ bun.bunNo +3]!==void 0){
        addBun('msg'+i , allBunArr[bun.bunNo + 3], false)
      }
    }
  }
}

const createBox=(i)=>{
  //箱を作る

  let msg = document.getElementById('box')
  msg.innerHTML += '
'
}

const addBun=(id,bun,bold,verbBunHtml,isArrow)=>{
  //箱に1文を追加。boldはboolean
  let msg = document.getElementById(id)
  const talker=""
  const color="#000000"
  const bunNo = bun.bunNo
  const bunContent=bun.surfaceForm
  //if(bold){msg.innerHTML+=""}
  msg.innerHTML += '' + bunNo + '' + talker + ' 【'
  if(isArrow){
    msg.innerHTML +=  verbBunHtml
  }else{
    if(bold){
      //console.log("bold")
      msg.innerHTML += "" + bunContent +""

    }else{
      msg.innerHTML +=  bunContent
    }
  }
  msg.innerHTML += '】

'
  //if(bold){msg.innerHTML+=""}
}

const addWatchingBun = (i,bun,isBold,verbBunHtml,isArrow) => {

  if(isArrow){
    addBun('msg'+i,bun, true,verbBunHtml,true)
  }else{
    addBun('msg'+i,bun, true,null,false)
  }
}

export{createTxtViewArea}<|endoftext|>