<commit_before>/*
 * This file is part of the GOsa project -  http://gosa-project.org
 *
 * Copyright:
 *    (C) 2010-2017 GONICUS GmbH, Germany, http://www.gonicus.de
 *
 * License:
 *    LGPL-2.1: http://www.gnu.org/licenses/lgpl-2.1.html
 *
 * See the LICENSE file in the project's top-level directory for details.
 */

/*
#asset(gosa/*)
*/

qx.Class.define("gosa.ui.dialogs.ItemSelector", {

  extend: gosa.ui.dialogs.Dialog,
  include: gosa.ui.table.MColumnSettings,

  construct: function(title, current_values, extension, attribute, columnSettings, single, modelFilter, sortByColumn, mode, options) {
    this.base(arguments);
    this.setCaption(title);
    this.setResizable(true, true, true, true);
    this.setWidth(500);
    this.setLayout(new qx.ui.layout.VBox(0));
    this._sortByColumn = sortByColumn;

    this.__isSingleSelection = !!single;

    this._detailsRpc = mode || "searchForObjectDetails";

    this.debouncedUpdate = qx.util.Function.debounce(this._updateValues, 500, false).bind(this);

    var searchOptions = {fullText: true};
    var queryFilter =  "";
    if (options && options.hasOwnProperty('queryFilter')) {
      queryFilter = options.queryFilter;
    } else {
      searchOptions.limit = 100;
    }
    if (modelFilter) {
      searchOptions.filter = modelFilter.getSearchOptions();
      modelFilter.setDelegateFilterPropertyName('key');
    }

    this._selectorOptions = options || {};

    this._searchArgs = {
      extension: extension,
      attribute: attribute,
      queryFilter: queryFilter,
      columnKeys: columnSettings.ids,
      currentValues: current_values,
      options: searchOptions,
      modelFilter: modelFilter
    };

    var allowedTypes = new qx.data.Array();
    this.setAllowedTypes(allowedTypes);

    if (searchOptions.hasOwnProperty("filter") && searchOptions.filter.hasOwnProperty("_type")) {
      this._typeFilter = searchOptions.filter._type;
      var defaultType = this._typeFilter.values.length === 1 ? this._typeFilter.values[0] : null;

      // get complete list of allowed types from backend (and use this._typeFilter to filter them)
      gosa.io.Rpc.getInstance().cA('getAvailableObjectNames', false, null, gosa.Config.getLocale()).then(function (res) {
        // add the empty type
        allowedTypes.push(new gosa.data.KeyValue('-', ''));
        Object.keys(res).forEach(function (type) {
          var kvItem = new gosa.data.KeyValue(type, res[type]);
          if (type === defaultType) {
            this._defaultType = kvItem;
          }
          allowedTypes.push(kvItem);
        }, this);
        this.__initWidgets(columnSettings, extension, attribute);
      }, this);
    } else {
      this.__initWidgets(columnSettings, extension, attribute);
    }

    if (!this._selectorOptions.skipInitialSearch) {
      this._updateValues();
    }
  },

  events: {
    "selected": "qx.event.type.Data"
  },

  /*
  *****************************************************************************
     PROPERTIES
  *****************************************************************************
  */
  properties: {
    allowedTypes: {
      check: 'qx.data.Array',
      init: null
    }
  },

  members : {
    __table : null,
    __tableModel : null,
    _tableContainer: null,
    __isSingleSelection : false,
    _sortByColumn: null,
    _detailsRpc: null,
    _throbber: null,
    _filter: null,
    _typeFilter: null,
    _columnSettings: null,
    _selectorOptions: null,
    _defaultType: null,

    _updateValues: function() {
      if (!this.hasChildControl("filter-button") || !this.getChildControl("filter-button").isEnabled()) {
        return;
      }
      var queryFilter = this._searchArgs.queryFilter;
      if (this.hasChildControl("search-field")) {
        queryFilter = this.getChildControl("search-field").getValue() || this._searchArgs.queryFilter;
      }
      if (this.hasChildControl("type-selector")) {
        var selection = this.getChildControl("type-selector").getSelection();
        var selectedTypes = [];
        selection.forEach(function(sel) {
          if (sel.getKey() && sel.getKey() !== '-') {
            selectedTypes.push(sel.getKey());
          }
        });
        if (selectedTypes.length > 0) {
          this._searchArgs.options.filter._type = selectedTypes;
        } else if (this._typeFilter.limit === true) {
          this._searchArgs.options.filter._type = this._typeFilter.values;
        } else {
          delete this._searchArgs.options.filter._type;
        }
      }
      if (this.hasChildControl("base-selector")) {
        var selectedParentDn = gosa.ui.widgets.Widget.getSingleValue(this.getChildControl("base-selector").getValue());
        if (selectedParentDn) {
          if (this.getChildControl('subtree-checkbox').getValue() === true) {
            this._searchArgs.options.filter[this._selectorOptions.filters.base.use] = "%" + selectedParentDn;
          } else {
            this._searchArgs.options.filter[this._selectorOptions.filters.base.use] = selectedParentDn;
          }
        } else if (this.getChildControl('subtree-checkbox').getValue() === false) {
          // use base as parent (no subtree search)
          this._searchArgs.options.filter[this._selectorOptions.filters.base.use] =
            this.getChildControl("base-selector").getRoot().getChildren().getItem(0).getDn();
        } else {
          delete this._searchArgs.options.filter[this._selectorOptions.filters.base.use];
        }
      }
      if (!this._throbber) {
        this._throbber = new gosa.ui.Throbber();
        this._throbber.addState("blocking");
        this._tableContainer.add(this._throbber, {edge: 0});
      } else {
        this._throbber.show();
      }
      gosa.io.Rpc.getInstance().cA(
        this._detailsRpc,
        this._searchArgs.extension,
        this._searchArgs.attribute,
        queryFilter,
        this._searchArgs.columnKeys,
        this._searchArgs.currentValues,
        this._searchArgs.options)
        .then(function (result) {
          this._throbber.exclude();
          if (this._searchArgs.modelFilter) {
            result = this._searchArgs.modelFilter.filter(result);
          }
          this.__tableModel.setDataAsMapArray(result, true, false);
          if (this._sortByColumn) {
            this.__tableModel.sortByColumn(this.__tableModel.getColumnIndexById(this._sortByColumn), true);
          }
        }, this);
    },

    __initWidgets : function(columnSettings, extension, attribute) {
      if (this._selectorOptions.hasOwnProperty("filters")) {
        for (var filterName in this._selectorOptions.filters) {
          switch (filterName) {
            case "search":
              if (this._selectorOptions.filters.search === true) {
                // search filter field
                this._createChildControl('search-field');
              }
              break;

            case "base":
              if (!this.hasChildControl('base-selector')) {
                this._createChildControl('base-selector');
              }
              if (!this.hasChildControl('subtree-checkbox')) {
                this._createChildControl('subtree-checkbox');
              }
              break;

            case "type":
              if (this.getAllowedTypes().length > 0) {
                this.getChildControl('type-selector').setModel(this.getAllowedTypes());
                if (this._defaultType) {
                  this.getChildControl('type-selector').getSelection().replace([this._defaultType])
                }
              }
              break;

            default:
              this.warn("unsupported filter type: ", filterName);
              break;
          }
        }
        this._createChildControl("filter-button");
      }

      this._tableContainer = new qx.ui.container.Composite(new qx.ui.layout.Canvas());
      this.__tableModel = new qx.ui.table.model.Simple();
      this.__tableModel.setColumns(columnSettings.names, columnSettings.ids);
      this.__table = new gosa.ui.table.Table(this.__tableModel);
      this.__table.setDecorator("table");
      this.__table.setStatusBarVisible(false);
      if (!this.__isSingleSelection) {
        this.__table.getSelectionModel().setSelectionMode(qx.ui.table.selection.Model.MULTIPLE_INTERVAL_SELECTION);
      }
      this.__table.addListener("dblclick", this.__onOk, this);
      this._tableContainer.add(this.__table, {edge: 0});

      this.add(this._tableContainer, {flex: 1});
      this.__table.setPreferenceTableName(extension + ":" + attribute + "Edit");

      this._applyColumnSettings(this.__table, columnSettings);

      // Add button static button line for the moment
      var paneLayout = new qx.ui.layout.HBox().set({
        spacing: 4, alignX : "right"
      });
      var buttonPane = new qx.ui.container.Composite(paneLayout).set({
        paddingTop: 11
      });

      var okButton;
      if (this.__isSingleSelection) {
        okButton = new qx.ui.form.Button(this.tr("OK"), "@Ligature/check/22");
      } else {
        okButton = new qx.ui.form.Button(this.tr("Add"), "@Ligature/plus/22");
      }

      okButton.setAppearance("button-primary");

      var cancelButton = new qx.ui.form.Button(this.tr("Cancel"), "@Ligature/ban/22");
      buttonPane.add(okButton);
      buttonPane.add(cancelButton);

      this.add(buttonPane);

      cancelButton.addListener("execute", this.close, this);
      okButton.addListener("execute", this.__onOk, this);
    },

    __onOk : function() {
      var list = [];
      this.__table.getSelectionModel().iterateSelection(function(index) {
        list.push(this._detailsRpc === "searchForObjectDetails" ? this.__tableModel.getRowData(index)['__identifier__'] : this.__tableModel.getRowData(index));
      }, this);
      this.fireDataEvent("selected", list);
      this.close();
    },

    __maintainSearchButton: function() {
      if (!this.hasChildControl("filter-button")) {
        return;
      }
      var button = this.getChildControl("filter-button");
      if (this.hasChildControl("search-field") && this.getChildControl("search-field").getValue()) {
        button.setEnabled(true);
        return;
      }
      if (this.hasChildControl("type-selector")) {
        var selection = this.getChildControl("type-selector").getSelection();
        var selectedTypes = [];
        selection.some(function(sel) {
          if (sel.getKey() !== '-') {
            selectedTypes.push(sel.getKey());
            return true;
          }
        });
        if (selectedTypes.length > 0) {
          button.setEnabled(true);
          return;
        }
      }
      if (this.hasChildControl("base-selector")) {
        if (gosa.ui.widgets.Widget.getSingleValue(this.getChildControl("base-selector").getValue())) {
          button.setEnabled(true);
          return;
        }
      }

      button.setEnabled(false);
    },

    // overridden
    _createChildControlImpl: function(id) {
      var control;

      switch(id) {
        case 'filter-container':
          control = new qx.ui.container.Composite(new qx.ui.layout.VBox(8));
          this.add(control);
          break;

        case 'search-field':
          control = new qx.ui.form.TextField().set({
            placeholder: this.tr("Search..."),
            liveUpdate: true,
            allowGrowX: true
          });
          control.addListener("changeValue", this.__maintainSearchButton, this);
          var label = new qx.ui.basic.Label(this.tr("Search"));
          var container = new qx.ui.container.Composite(new qx.ui.layout.HBox());
          container.add(label, {width: "20%"});
          container.add(control, {flex: 1});
          this.getChildControl('filter-container').addAt(container, 4);
          break;

        case 'type-selector':
          control = new qx.ui.form.VirtualSelectBox();
          control.setLabelPath('value');
          control.setDelegate({
            filter: function (data) {
              return data.getKey() === '-' || !this._searchArgs.modelFilter || this._searchArgs.modelFilter.delegateFilter(data);
            }.bind(this),

            sorter: function (a, b) {
              return a.getValue().localeCompare(b.getValue());
            }
          });
          control.getSelection().addListener("change", this.__maintainSearchButton, this);
          var label = new qx.ui.basic.Label(this.tr("Type"));
          var container = new qx.ui.container.Composite(new qx.ui.layout.HBox());
          container.add(label, {width: "20%"});
          container.add(control, {flex: 1});
          this.getChildControl('filter-container').addAt(container, 3);
          break;

        case 'base-selector':
          control = new gosa.ui.widgets.QBaseSelectorWidget();
          control.addListener("resize", function () {
            this.center();
          }, this);
          control.addListener("changeValue", this.__maintainSearchButton, this);
          this.getChildControl('filter-container').addAt(new qx.ui.basic.Label(this.tr("Select Base")), 0);
          this.getChildControl('filter-container').addAt(control, 1);
          break;

        case 'subtree-checkbox':
          control = new qx.ui.form.CheckBox(this.tr('Search in subtree'));
          var container = new qx.ui.container.Composite(new qx.ui.layout.HBox());
          container.add(new qx.ui.core.Spacer(), {width: "20%"});
          container.add(control, {flex: 1});
          control.addListener("changeValue", this.__maintainSearchButton, this);
          this.getChildControl('filter-container').addAt(container, 2);
          break;

        case 'filter-button':
          control = new qx.ui.form.Button(this.tr("Filter"), '@Ligature/search/22');
          control.setEnabled(false);
          this.getChildControl('filter-container').addAt(control, 5);
          control.addListener("execute", this._updateValues, this);
          break;
      }

      return control || this.base(arguments, id);
    }

  },

  destruct : function()
  {
    this._disposeObjects("__tableModel", "__table", "_tableContainer", "_filter", "_throbber");
  }
});<commit_msg>only skip if we have a disable filter button<commit_after>/*
 * This file is part of the GOsa project -  http://gosa-project.org
 *
 * Copyright:
 *    (C) 2010-2017 GONICUS GmbH, Germany, http://www.gonicus.de
 *
 * License:
 *    LGPL-2.1: http://www.gnu.org/licenses/lgpl-2.1.html
 *
 * See the LICENSE file in the project's top-level directory for details.
 */

/*
#asset(gosa/*)
*/

qx.Class.define("gosa.ui.dialogs.ItemSelector", {

  extend: gosa.ui.dialogs.Dialog,
  include: gosa.ui.table.MColumnSettings,

  construct: function(title, current_values, extension, attribute, columnSettings, single, modelFilter, sortByColumn, mode, options) {
    this.base(arguments);
    this.setCaption(title);
    this.setResizable(true, true, true, true);
    this.setWidth(500);
    this.setLayout(new qx.ui.layout.VBox(0));
    this._sortByColumn = sortByColumn;

    this.__isSingleSelection = !!single;

    this._detailsRpc = mode || "searchForObjectDetails";

    this.debouncedUpdate = qx.util.Function.debounce(this._updateValues, 500, false).bind(this);

    var searchOptions = {fullText: true};
    var queryFilter =  "";
    if (options && options.hasOwnProperty('queryFilter')) {
      queryFilter = options.queryFilter;
    } else {
      searchOptions.limit = 100;
    }
    if (modelFilter) {
      searchOptions.filter = modelFilter.getSearchOptions();
      modelFilter.setDelegateFilterPropertyName('key');
    }

    this._selectorOptions = options || {};

    this._searchArgs = {
      extension: extension,
      attribute: attribute,
      queryFilter: queryFilter,
      columnKeys: columnSettings.ids,
      currentValues: current_values,
      options: searchOptions,
      modelFilter: modelFilter
    };

    var allowedTypes = new qx.data.Array();
    this.setAllowedTypes(allowedTypes);

    if (searchOptions.hasOwnProperty("filter") && searchOptions.filter.hasOwnProperty("_type")) {
      this._typeFilter = searchOptions.filter._type;
      var defaultType = this._typeFilter.values.length === 1 ? this._typeFilter.values[0] : null;

      // get complete list of allowed types from backend (and use this._typeFilter to filter them)
      gosa.io.Rpc.getInstance().cA('getAvailableObjectNames', false, null, gosa.Config.getLocale()).then(function (res) {
        // add the empty type
        allowedTypes.push(new gosa.data.KeyValue('-', ''));
        Object.keys(res).forEach(function (type) {
          var kvItem = new gosa.data.KeyValue(type, res[type]);
          if (type === defaultType) {
            this._defaultType = kvItem;
          }
          allowedTypes.push(kvItem);
        }, this);
        this.__initWidgets(columnSettings, extension, attribute);
      }, this);
    } else {
      this.__initWidgets(columnSettings, extension, attribute);
    }

    if (!this._selectorOptions.skipInitialSearch) {
      this._updateValues();
    }
  },

  events: {
    "selected": "qx.event.type.Data"
  },

  /*
  *****************************************************************************
     PROPERTIES
  *****************************************************************************
  */
  properties: {
    allowedTypes: {
      check: 'qx.data.Array',
      init: null
    }
  },

  members : {
    __table : null,
    __tableModel : null,
    _tableContainer: null,
    __isSingleSelection : false,
    _sortByColumn: null,
    _detailsRpc: null,
    _throbber: null,
    _filter: null,
    _typeFilter: null,
    _columnSettings: null,
    _selectorOptions: null,
    _defaultType: null,

    _updateValues: function() {
      if (this.hasChildControl("filter-button") && !this.getChildControl("filter-button").isEnabled()) {
        return;
      }
      var queryFilter = this._searchArgs.queryFilter;
      if (this.hasChildControl("search-field")) {
        queryFilter = this.getChildControl("search-field").getValue() || this._searchArgs.queryFilter;
      }
      if (this.hasChildControl("type-selector")) {
        var selection = this.getChildControl("type-selector").getSelection();
        var selectedTypes = [];
        selection.forEach(function(sel) {
          if (sel.getKey() && sel.getKey() !== '-') {
            selectedTypes.push(sel.getKey());
          }
        });
        if (selectedTypes.length > 0) {
          this._searchArgs.options.filter._type = selectedTypes;
        } else if (this._typeFilter.limit === true) {
          this._searchArgs.options.filter._type = this._typeFilter.values;
        } else {
          delete this._searchArgs.options.filter._type;
        }
      }
      if (this.hasChildControl("base-selector")) {
        var selectedParentDn = gosa.ui.widgets.Widget.getSingleValue(this.getChildControl("base-selector").getValue());
        if (selectedParentDn) {
          if (this.getChildControl('subtree-checkbox').getValue() === true) {
            this._searchArgs.options.filter[this._selectorOptions.filters.base.use] = "%" + selectedParentDn;
          } else {
            this._searchArgs.options.filter[this._selectorOptions.filters.base.use] = selectedParentDn;
          }
        } else if (this.getChildControl('subtree-checkbox').getValue() === false) {
          // use base as parent (no subtree search)
          this._searchArgs.options.filter[this._selectorOptions.filters.base.use] =
            this.getChildControl("base-selector").getRoot().getChildren().getItem(0).getDn();
        } else {
          delete this._searchArgs.options.filter[this._selectorOptions.filters.base.use];
        }
      }
      if (!this._throbber) {
        this._throbber = new gosa.ui.Throbber();
        this._throbber.addState("blocking");
        this._tableContainer.add(this._throbber, {edge: 0});
      } else {
        this._throbber.show();
      }
      gosa.io.Rpc.getInstance().cA(
        this._detailsRpc,
        this._searchArgs.extension,
        this._searchArgs.attribute,
        queryFilter,
        this._searchArgs.columnKeys,
        this._searchArgs.currentValues,
        this._searchArgs.options)
        .then(function (result) {
          this._throbber.exclude();
          if (this._searchArgs.modelFilter) {
            result = this._searchArgs.modelFilter.filter(result);
          }
          this.__tableModel.setDataAsMapArray(result, true, false);
          if (this._sortByColumn) {
            this.__tableModel.sortByColumn(this.__tableModel.getColumnIndexById(this._sortByColumn), true);
          }
        }, this);
    },

    __initWidgets : function(columnSettings, extension, attribute) {
      if (this._selectorOptions.hasOwnProperty("filters")) {
        for (var filterName in this._selectorOptions.filters) {
          switch (filterName) {
            case "search":
              if (this._selectorOptions.filters.search === true) {
                // search filter field
                this._createChildControl('search-field');
              }
              break;

            case "base":
              if (!this.hasChildControl('base-selector')) {
                this._createChildControl('base-selector');
              }
              if (!this.hasChildControl('subtree-checkbox')) {
                this._createChildControl('subtree-checkbox');
              }
              break;

            case "type":
              if (this.getAllowedTypes().length > 0) {
                this.getChildControl('type-selector').setModel(this.getAllowedTypes());
                if (this._defaultType) {
                  this.getChildControl('type-selector').getSelection().replace([this._defaultType])
                }
              }
              break;

            default:
              this.warn("unsupported filter type: ", filterName);
              break;
          }
        }
        this._createChildControl("filter-button");
      }

      this._tableContainer = new qx.ui.container.Composite(new qx.ui.layout.Canvas());
      this.__tableModel = new qx.ui.table.model.Simple();
      this.__tableModel.setColumns(columnSettings.names, columnSettings.ids);
      this.__table = new gosa.ui.table.Table(this.__tableModel);
      this.__table.setDecorator("table");
      this.__table.setStatusBarVisible(false);
      if (!this.__isSingleSelection) {
        this.__table.getSelectionModel().setSelectionMode(qx.ui.table.selection.Model.MULTIPLE_INTERVAL_SELECTION);
      }
      this.__table.addListener("dblclick", this.__onOk, this);
      this._tableContainer.add(this.__table, {edge: 0});

      this.add(this._tableContainer, {flex: 1});
      this.__table.setPreferenceTableName(extension + ":" + attribute + "Edit");

      this._applyColumnSettings(this.__table, columnSettings);

      // Add button static button line for the moment
      var paneLayout = new qx.ui.layout.HBox().set({
        spacing: 4, alignX : "right"
      });
      var buttonPane = new qx.ui.container.Composite(paneLayout).set({
        paddingTop: 11
      });

      var okButton;
      if (this.__isSingleSelection) {
        okButton = new qx.ui.form.Button(this.tr("OK"), "@Ligature/check/22");
      } else {
        okButton = new qx.ui.form.Button(this.tr("Add"), "@Ligature/plus/22");
      }

      okButton.setAppearance("button-primary");

      var cancelButton = new qx.ui.form.Button(this.tr("Cancel"), "@Ligature/ban/22");
      buttonPane.add(okButton);
      buttonPane.add(cancelButton);

      this.add(buttonPane);

      cancelButton.addListener("execute", this.close, this);
      okButton.addListener("execute", this.__onOk, this);
    },

    __onOk : function() {
      var list = [];
      this.__table.getSelectionModel().iterateSelection(function(index) {
        list.push(this._detailsRpc === "searchForObjectDetails" ? this.__tableModel.getRowData(index)['__identifier__'] : this.__tableModel.getRowData(index));
      }, this);
      this.fireDataEvent("selected", list);
      this.close();
    },

    __maintainSearchButton: function() {
      if (!this.hasChildControl("filter-button")) {
        return;
      }
      var button = this.getChildControl("filter-button");
      if (this.hasChildControl("search-field") && this.getChildControl("search-field").getValue()) {
        button.setEnabled(true);
        return;
      }
      if (this.hasChildControl("type-selector")) {
        var selection = this.getChildControl("type-selector").getSelection();
        var selectedTypes = [];
        selection.some(function(sel) {
          if (sel.getKey() !== '-') {
            selectedTypes.push(sel.getKey());
            return true;
          }
        });
        if (selectedTypes.length > 0) {
          button.setEnabled(true);
          return;
        }
      }
      if (this.hasChildControl("base-selector")) {
        if (gosa.ui.widgets.Widget.getSingleValue(this.getChildControl("base-selector").getValue())) {
          button.setEnabled(true);
          return;
        }
      }

      button.setEnabled(false);
    },

    // overridden
    _createChildControlImpl: function(id) {
      var control;

      switch(id) {
        case 'filter-container':
          control = new qx.ui.container.Composite(new qx.ui.layout.VBox(8));
          this.add(control);
          break;

        case 'search-field':
          control = new qx.ui.form.TextField().set({
            placeholder: this.tr("Search..."),
            liveUpdate: true,
            allowGrowX: true
          });
          control.addListener("changeValue", this.__maintainSearchButton, this);
          var label = new qx.ui.basic.Label(this.tr("Search"));
          var container = new qx.ui.container.Composite(new qx.ui.layout.HBox());
          container.add(label, {width: "20%"});
          container.add(control, {flex: 1});
          this.getChildControl('filter-container').addAt(container, 4);
          break;

        case 'type-selector':
          control = new qx.ui.form.VirtualSelectBox();
          control.setLabelPath('value');
          control.setDelegate({
            filter: function (data) {
              return data.getKey() === '-' || !this._searchArgs.modelFilter || this._searchArgs.modelFilter.delegateFilter(data);
            }.bind(this),

            sorter: function (a, b) {
              return a.getValue().localeCompare(b.getValue());
            }
          });
          control.getSelection().addListener("change", this.__maintainSearchButton, this);
          var label = new qx.ui.basic.Label(this.tr("Type"));
          var container = new qx.ui.container.Composite(new qx.ui.layout.HBox());
          container.add(label, {width: "20%"});
          container.add(control, {flex: 1});
          this.getChildControl('filter-container').addAt(container, 3);
          break;

        case 'base-selector':
          control = new gosa.ui.widgets.QBaseSelectorWidget();
          control.addListener("resize", function () {
            this.center();
          }, this);
          control.addListener("changeValue", this.__maintainSearchButton, this);
          this.getChildControl('filter-container').addAt(new qx.ui.basic.Label(this.tr("Select Base")), 0);
          this.getChildControl('filter-container').addAt(control, 1);
          break;

        case 'subtree-checkbox':
          control = new qx.ui.form.CheckBox(this.tr('Search in subtree'));
          var container = new qx.ui.container.Composite(new qx.ui.layout.HBox());
          container.add(new qx.ui.core.Spacer(), {width: "20%"});
          container.add(control, {flex: 1});
          control.addListener("changeValue", this.__maintainSearchButton, this);
          this.getChildControl('filter-container').addAt(container, 2);
          break;

        case 'filter-button':
          control = new qx.ui.form.Button(this.tr("Filter"), '@Ligature/search/22');
          control.setEnabled(false);
          this.getChildControl('filter-container').addAt(control, 5);
          control.addListener("execute", this._updateValues, this);
          break;
      }

      return control || this.base(arguments, id);
    }

  },

  destruct : function()
  {
    this._disposeObjects("__tableModel", "__table", "_tableContainer", "_filter", "_throbber");
  }
});<|endoftext|>


<commit_before>const https = require('https');
const fileSystem = require('fs');
const exitHook = require('exit-hook');
const regex = require('./regexModule');
const descriptionParser = require('./descriptionParser');
const models = require('../db/models');
const Subreddit = models.Subreddit;
const Tag = models.Tag;

var batchSize = 1;

var logging = false;
var recusiveLogging = false;

var testingMode = false;
var triggerExit = false;

var statePath = "state.json";
var state = {
    after: "",
    maxDepthReached: 0,
    maxDepthSubreddit: ""
};

function getReddits(after) {
    return new Promise((resolve, reject) => {
        function get_json(url, callback) {
            console.log(`Querying ${url}`);
            https.get(url, function(res) {
                var body = '';
                res.on('data', function(chunk) {
                    body += chunk;
                });

                res.on('end', function() {
                    var response = JSON.parse(body);
                    callback(response);
                });

                res.on('error', function(error) {
                    reject(error);
                });
            });
        }

        get_json(buildURL(after, batchSize), function(response) {
            parseRecursive(response.data.children, 0, function() {
                resolve(response.data.after);
            });
        });
    });
}

function parseRecursive(subreddits, currIndex, resolveCallback) {
    console.log("Parsing Subreddit " + (currIndex + 1) + "/" + batchSize);
    parseSubreddit(subreddits[currIndex].data, function(name) {
        state.after = name;
        currIndex++;
        if (currIndex >= subreddits.length) {
            resolveCallback();
        } else {
            parseRecursive(subreddits, currIndex, resolveCallback);
        }
    });
}

function buildURL(after) {
    var url = "https://www.reddit.com/reddits.json";
    if (!!batchSize) {
        url += "?limit=" + batchSize;
    }
    if (!!after) {
        url += "&after=" + after;
    }
    return url;
}

function parseSubreddit(subredditData, callback) {
    subredditData.url = subredditData.url.toLowerCase();
    console.log("Found " + subredditData.url);
    if (!subredditData) {
        console.log("No data was provided");
    }
    Subreddit.findOneAndUpdate({
        url: subredditData.url
    }, {}, {
        new: true,
        upsert: true,
        setDefaultsOnInsert: true
    }, function(err, subreddit) {
        if (!!err) {
            console.log("error in parseSubreddit: " + err);
        }

        subreddit.numSubscribers = subredditData.subscribers;

        const csvMatcher = /\b[\w\s]+\b/gi;
        var tags = regex.getListOfMatches(subredditData.audience_target, csvMatcher);
        var i;
        for (i in tags) {
            updateTag(subreddit, {
                name: tags[i],
                distance: 0
            }, 0);

            // Put the tag in the overall tags table if it doesnt exist yet.
            Tag.findOneAndUpdate({
                name: tags[i]
            }, {
                name: tags[i]
            }, {
                upsert: true
            }, function(err, newTag) {
                if (!newTag) {
                    console.log("New Tag Discovered");
                }
            });
        }

        subreddit._relatedSubreddits = descriptionParser.getMentionedSubreddits(subredditData);

        updateSubreddit(subreddit, function(updatedSubreddit) {
            for (i = 0; i < subreddit._relatedSubreddits.length; i++) {
                var subredditURL = subreddit._relatedSubreddits[i];
                console.log("Updating (" + (i + 1) + "/" + subreddit._relatedSubreddits.length + "): " + subredditURL);
                propagateSubredditData(subredditURL, updatedSubreddit, 1, [updatedSubreddit.url]);
            }

            console.log(`Finished ${subredditData.url}`);

            process.nextTick(callback, subredditData.name);
        });
    });
}

function updateSubreddit(subreddit, callback) {
    updateData = {};
    if (!!subreddit.numSubscribers) {
        updateData.numSubscribers = subreddit.numSubscribers;
    }
    if (!!subreddit._relatedSubreddits) {
        updateData._relatedSubreddits = subreddit._relatedSubreddits;
    }
    if (!!subreddit.tags) {
        updateData.tags = subreddit.tags;
    }

    Subreddit.findOneAndUpdate({
        url: subreddit.url
    }, updateData, {
        new: true
    }, function(err, updatedSubreddit) {
        if (!!err) {
            console.log(err);
        }
        callback(updatedSubreddit);
    });
}

function propagateSubredditData(subredditURL, parentSubreddit, depth, searched) {
    // subredditURL is expected to be in the form of '/r/name'
    var loggingIndent = "";
    if (logging || recusiveLogging) {
        var count;
        for (count = 0; count < depth; count++) {
            loggingIndent += "  ";
        }
    }

    // Statistical analysis
    if (state.maxDepthReached < depth) {
        state.maxDepthReached = depth;
        state.maxDepthSubreddit = subredditURL;
    }

    // Handle self referential loops
    if (searched.indexOf(subredditURL) !== -1) {
        if (logging) {
            console.log(loggingIndent + "Already Searched: " + subredditURL);
        }
        return;
    }

    Subreddit.findOneAndUpdate({
        url: subredditURL
    }, {}, {
        new: true,
        upsert: true
    }, function(err, subreddit) {
        if (subreddit._relatedSubreddits.indexOf(parentSubreddit.url) === -1) {
            subreddit._relatedSubreddits.push(parentSubreddit.url);
        }
        if (!!err) {
            console.log("error in propagate: " + err);
        }

        // subreddit was either found or created, we want to update tags regardless next.
        var updatedTags = false;
        var i;
        for (i in parentSubreddit.tags) {
            updatedTags = updatedTags || updateTag(subreddit, parentSubreddit.tags[i], depth);
        }
        if (updatedTags) {
            // If the tags were modified we should update the subreddit
            updateSubreddit(subreddit, function(updatedSubreddit) {
                if (!!updatedSubreddit._relatedSubreddits) {
                    var relatedIndex;
                    for (relatedIndex = 0; relatedIndex < updatedSubreddit._relatedSubreddits.length; relatedIndex++) {
                        // we want to update any possible tags that weren't originally referenced.
                        var nextURL = updatedSubreddit._relatedSubreddits[relatedIndex];
                        var searchedIndex = searched.indexOf(nextURL);
                        if (searchedIndex > -1) {
                            searched.splice(searchedIndex, 1);
                            if (logging) {
                                console.log(loggingIndent + "Need to scan " + nextURL + " again in case changes relate.");
                            }
                        }
                        if (logging || recusiveLogging) {
                            console.log(
                                loggingIndent + "Updating (" + (relatedIndex + 1) + "/" + updatedSubreddit._relatedSubreddits.length +
                                "): " + updatedSubreddit.url + " => " + nextURL
                            );
                        }
                        propagateSubredditData(nextURL, updatedSubreddit, depth + 1, searched);
                    }
                }
            });
        } else {
            if (logging) {
                console.log(loggingIndent + "Finished: " + subredditURL);
            }
            searched.push(subredditURL);
        }
    });
}

// Tags are {name:"tagName", distance:X}
function updateTag(subreddit, newTag, depth) {
    var i;
    for (i in subreddit.tags) {
        if (subreddit.tags[i].name === newTag.name) {
            if (subreddit.tags[i].distance > (newTag.distance + depth)) {
                //console.log("Tag had better distance: " + newTag + "[" + subreddit.tags[i].distance + " => " + (newTag.distance + depth) + "]");
                subreddit.tags[i].distance = (newTag.distance + depth);
                return true;
            }
            //console.log("Tag had worse distance: " + newTag + "[" + subreddit.tags[i].distance + " < " + (newTag.distance + depth) + "]");
            return false;
        }
    }
    //console.log("Tag not found: " + newTag);
    subreddit.tags.push({
        name: newTag.name,
        distance: newTag.distance + depth
    });
    return true;
}

function continueSearch(after) {
    getReddits(after).then(
        function(after) {
            if (logging) {
                console.log("Resolved: " + after);
            }
            state.after = after;
            setTimeout(function() {
                continueSearch(after);
            }, 1000);
        }
    ).catch((err) => {
        console.log(err)
    });
}

function loadStateJSON(callback) {
    fileSystem.readFile(statePath, (err, data) => {
        if (err) {
            console.log("state.json file not initialized");
        } else {
            if (data.byteLength === 0) {
                console.log("state.json file is empty");
            } else {
                state = JSON.parse(data);
            }
        }
        callback(state.after);
    });
}

exitHook(function() {
    if (triggerExit) {
        if (logging) {
            console.log("Exit Hook Triggered");
        }
        if (!testingMode) {
            fileSystem.writeFileSync(statePath, JSON.stringify(state));
            console.log("    Crawler terminated, current state saved as " + state.after);
        }
        process.exit(0);
    }
});

module.exports = {
    crawl: function(size) {
        const startDb = require('../db');
        if (size > 100) {
            console.log("Max batch size is 100");
            size = 100;
        } else if (size < 0) {
            console.log("Min batch size is 1");
            size = 1;
        }
        batchSize = size;
        triggerExit = true;
        loadStateJSON(function(after) {
            console.log("Starting search from " + state.after);
            continueSearch(after);
        });
        return "Crawler Initialized";
    },
    _buildURL: function(after) {
        testingMode = true;
        logging = true;
        return buildURL(after);
    },
    _parseSubreddit: function(subreddit, callback) {
        testingMode = true;
        logging = true;
        return parseSubreddit(subreddit, callback);
    },
    _parseRecursive: function(subredditsData, callback) {
        testingMode = true;
        logging = true;
        return parseRecursive(subredditsData, 0, callback);
    },
    _updateSubreddit: function(subredditData, callback) {
        testingMode = true;
        logging = true;
        return updateSubreddit(subredditData, callback);
    },
    _propagateSubredditData: function(subredditURL, parentSubreddit, depth, searched) {
        testingMode = true;
        logging = true;
        return propagateSubredditData(subredditURL, parentSubreddit, depth, searched);
    },
    _updateTag: function(subredditData, newTag, depth) {
        testingMode = true;
        logging = true;
        return updateTag(subredditData, newTag, depth);
    }
};

require('make-runnable/custom')({
    printOutputFrame: false
});
<commit_msg>I think the memory leak is fixed<commit_after>const https = require('https');
const fileSystem = require('fs');
const exitHook = require('exit-hook');
const regex = require('./regexModule');
const descriptionParser = require('./descriptionParser');
const models = require('../db/models');
const Subreddit = models.Subreddit;
const Tag = models.Tag;

var batchSize = 1;

var logging = false;
var recusiveLogging = false;

var testingMode = false;
var triggerExit = false;

var statePath = "state.json";
var state = {
    after: "",
    maxDepthReached: 0,
    maxDepthSubreddit: ""
};

function getReddits(after) {
    return new Promise((resolve, reject) => {
        function get_json(url, callback) {
            console.log(`Querying ${url}`);
            https.get(url, function(res) {
                var body = '';
                res.on('data', function(chunk) {
                    body += chunk;
                });

                res.on('end', function() {
                    var response = JSON.parse(body);
                    callback(response);
                });

                res.on('error', function(error) {
                    reject(error);
                });
            });
        }

        get_json(buildURL(after, batchSize), function(response) {
            parseRecursive(response.data.children, 0, function() {
                resolve(response.data.after);
            });
        });
    });
}

function parseRecursive(subreddits, currIndex, resolveCallback) {
    console.log("Parsing Subreddit " + (currIndex + 1) + "/" + batchSize);
    parseSubreddit(subreddits[currIndex].data, function() {
        currIndex++;
        if (currIndex >= subreddits.length) {
            resolveCallback();
        } else {
            parseRecursive(subreddits, currIndex, resolveCallback);
        }
    });
}

function buildURL(after) {
    var url = "https://www.reddit.com/reddits.json";
    if (!!batchSize) {
        url += "?limit=" + batchSize;
    }
    if (!!after) {
        url += "&after=" + after;
    }
    return url;
}

function parseSubreddit(subredditData, callback) {
    subredditData.url = subredditData.url.toLowerCase();
    console.log("Found " + subredditData.url);
    if (!subredditData) {
        console.log("No data was provided");
    }
    Subreddit.findOneAndUpdate({
        url: subredditData.url
    }, {}, {
        new: true,
        upsert: true,
        setDefaultsOnInsert: true
    }, function(err, subreddit) {
        if (!!err) {
            console.log("error in parseSubreddit: " + err);
        }

        subreddit.numSubscribers = subredditData.subscribers;

        const csvMatcher = /\b[\w\s]+\b/gi;
        var tags = regex.getListOfMatches(subredditData.audience_target, csvMatcher);
        var i;
        for (i in tags) {
            updateTag(subreddit, {
                name: tags[i],
                distance: 0
            }, 0);

            // Put the tag in the overall tags table if it doesnt exist yet.
            Tag.findOneAndUpdate({
                name: tags[i]
            }, {
                name: tags[i]
            }, {
                upsert: true
            }, function(err, newTag) {
                if (!newTag) {
                    console.log("New Tag Discovered");
                }
            });
        }

        subreddit._relatedSubreddits = descriptionParser.getMentionedSubreddits(subredditData);

        updateSubreddit(subreddit, function(updatedSubreddit) {
            /*for (i = 0; i < subreddit._relatedSubreddits.length; i++) {
                var subredditURL = subreddit._relatedSubreddits[i];
                console.log("Updating (" + (i + 1) + "/" + subreddit._relatedSubreddits.length + "): " + subredditURL);
                propagateSubredditData(subredditURL, updatedSubreddit, 1, [updatedSubreddit.url]);
            }*/
            if (!!updatedSubreddit._relatedSubreddits && updatedSubreddit._relatedSubreddits.length > 0) {
                propagateRecursive(updatedSubreddit._relatedSubreddits, updatedSubreddit, 1, [updatedSubreddit.url], false, 0, function() {
                    console.log(`Finished ${subredditData.url}`);
                    process.nextTick(callback);
                })
            } else {
                console.log(`Finished ${subredditData.url}`);
                process.nextTick(callback);
            }
        });
    });
}

function updateSubreddit(subreddit, callback) {
    updateData = {};
    if (!!subreddit.numSubscribers) {
        updateData.numSubscribers = subreddit.numSubscribers;
    }
    if (!!subreddit._relatedSubreddits) {
        updateData._relatedSubreddits = subreddit._relatedSubreddits;
    }
    if (!!subreddit.tags) {
        updateData.tags = subreddit.tags;
    }

    Subreddit.findOneAndUpdate({
        url: subreddit.url
    }, updateData, {
        new: true
    }, function(err, updatedSubreddit) {
        if (!!err) {
            console.log(err);
        }
        callback(updatedSubreddit);
    });
}

function propagateRecursive(relatedSubreddits, parentSubreddit, depth, searched, backtrack, currIndex, resolveCallback) {
    var loggingIndent = "  ";
    if (logging || recusiveLogging) {
        var count;
        for (count = 0; count < depth; count++) {
            loggingIndent += "  ";
        }
    }
    var subredditURL = relatedSubreddits[currIndex];
    if (backtrack) {
        var searchedIndex = searched.indexOf(subredditURL);
        if (searchedIndex > -1) {
            searched.splice(searchedIndex, 1);
            if (logging) {
                console.log(loggingIndent + "Need to scan " + subredditURL + " again in case changes relate.");
            }
        }
        if (logging || recusiveLogging) {
            console.log(
                loggingIndent + "Updating (" + (currIndex + 1) + "/" + relatedSubreddits.length + "): " + parentSubreddit.url + " => " + subredditURL
            );
        }
    } else {
        console.log(loggingIndent + "Updating (" + (currIndex + 1) + "/" + relatedSubreddits.length + "): " + subredditURL);
    }

    propagateSubredditData(subredditURL, parentSubreddit, depth, searched, function() {
        if (logging) {
            console.log(loggingIndent + "Finished: " + subredditURL);
        }
        currIndex++;
        if (currIndex >= relatedSubreddits.length) {
            resolveCallback();
        } else {
            propagateRecursive(relatedSubreddits, parentSubreddit, depth, searched, backtrack, currIndex, resolveCallback);
        }
    });
}

function propagateSubredditData(subredditURL, parentSubreddit, depth, searched, callback) {
    // subredditURL is expected to be in the form of '/r/name'

    // Statistical analysis
    if (state.maxDepthReached < depth) {
        state.maxDepthReached = depth;
        state.maxDepthSubreddit = subredditURL;
    }

    if (searched.indexOf(null) !== -1) {
        // Pray this never happens.
        console.log(searched + "aaaaaaaa" + parentSubreddit);
    }

    // Handle self referential loops
    if (searched.indexOf(subredditURL) !== -1) {
        if (logging) {
            console.log("Already Searched: " + subredditURL);
        }
        callback();
    } else {
        Subreddit.findOneAndUpdate({
            url: subredditURL
        }, {}, {
            new: true,
            upsert: true
        }, function(err, subreddit) {
            if (subreddit._relatedSubreddits.indexOf(parentSubreddit.url) === -1) {
                subreddit._relatedSubreddits.push(parentSubreddit.url);
            }
            if (!!err) {
                console.log("error in propagate: " + err);
            }

            // subreddit was either found or created, we want to update tags regardless next.
            var updatedTags = false;
            var i;
            for (i in parentSubreddit.tags) {
                updatedTags = updatedTags || updateTag(subreddit, parentSubreddit.tags[i], depth);
            }
            if (updatedTags) {
                // If the tags were modified we should update the subreddit
                updateSubreddit(subreddit, function(updatedSubreddit) {
                    if (!!updatedSubreddit._relatedSubreddits && updatedSubreddit._relatedSubreddits.length > 0) {
                        propagateRecursive(updatedSubreddit._relatedSubreddits, updatedSubreddit, depth + 1, searched, true, 0, function() {
                            callback();
                        });
                    } else {
                        callback();
                    }
                });
            } else {
                searched.push(subredditURL);
                callback();
            }
        });
    }
}

// Tags are {name:"tagName", distance:X}
function updateTag(subreddit, newTag, depth) {
    var i;
    for (i in subreddit.tags) {
        if (subreddit.tags[i].name === newTag.name) {
            if (subreddit.tags[i].distance > (newTag.distance + depth)) {
                //console.log("Tag had better distance: " + newTag + "[" + subreddit.tags[i].distance + " => " + (newTag.distance + depth) + "]");
                subreddit.tags[i].distance = (newTag.distance + depth);
                return true;
            }
            //console.log("Tag had worse distance: " + newTag + "[" + subreddit.tags[i].distance + " < " + (newTag.distance + depth) + "]");
            return false;
        }
    }
    //console.log("Tag not found: " + newTag);
    subreddit.tags.push({
        name: newTag.name,
        distance: newTag.distance + depth
    });
    return true;
}

function continueSearch(after) {
    getReddits(after).then(
        function(after) {
            if (logging) {
                console.log("Resolved: " + after);
            }
            state.after = after;
            setTimeout(function() {
                continueSearch(after);
            }, 1000);
        }
    ).catch((err) => {
        console.log(err)
    });
}

function loadStateJSON(callback) {
    fileSystem.readFile(statePath, (err, data) => {
        if (err) {
            console.log("state.json file not initialized");
        } else {
            if (data.byteLength === 0) {
                console.log("state.json file is empty");
            } else {
                state = JSON.parse(data);
            }
        }
        callback(state.after);
    });
}

exitHook(function() {
    if (triggerExit) {
        if (logging) {
            console.log("Exit Hook Triggered");
        }
        if (!testingMode) {
            fileSystem.writeFileSync(statePath, JSON.stringify(state));
            console.log("    Crawler terminated, current state saved as " + state.after);
        }
        process.exit(0);
    }
});

module.exports = {
    crawl: function(size) {
        const startDb = require('../db');
        if (size > 100) {
            console.log("Max batch size is 100");
            size = 100;
        } else if (size < 0) {
            console.log("Min batch size is 1");
            size = 1;
        }
        batchSize = size;
        triggerExit = true;
        loadStateJSON(function(after) {
            console.log("Starting search from " + state.after);
            continueSearch(after);
        });
        return "Crawler Initialized";
    },
    _buildURL: function(after) {
        testingMode = true;
        logging = true;
        return buildURL(after);
    },
    _parseSubreddit: function(subreddit, callback) {
        testingMode = true;
        logging = true;
        return parseSubreddit(subreddit, callback);
    },
    _parseRecursive: function(subredditsData, callback) {
        testingMode = true;
        logging = true;
        return parseRecursive(subredditsData, 0, callback);
    },
    _updateSubreddit: function(subredditData, callback) {
        testingMode = true;
        logging = true;
        return updateSubreddit(subredditData, callback);
    },
    _propagateSubredditData: function(subredditURL, parentSubreddit, depth, searched) {
        testingMode = true;
        logging = true;
        return propagateSubredditData(subredditURL, parentSubreddit, depth, searched);
    },
    _updateTag: function(subredditData, newTag, depth) {
        testingMode = true;
        logging = true;
        return updateTag(subredditData, newTag, depth);
    }
};

require('make-runnable/custom')({
    printOutputFrame: false
});
<|endoftext|>


<commit_before>import express from 'express';
import bodyParser from 'body-parser';
import config from '../src/config';
import * as actions from './actions/index';
import {mapUrl} from 'utils/url.js';
import PrettyError from 'pretty-error';
import http from 'http';
import SocketIo from 'socket.io';
import passport from'passport';
const TwitterStrategy = require('passport-twitter').Strategy;

const session = require('express-session');
const MongoStore = require('connect-mongo')(session);
const pretty = new PrettyError();

const app = express();
const server = new http.Server(app);
const io = new SocketIo(server);
io.path('/ws');

app.use(bodyParser.json());
app.use(session({
    secret: config.sessionKey,
    store: new MongoStore({
        url: 'mongodb://localhost/eyfApp'
    })
}));

console.log('_______ config: ', config);
const twitterCallbackUrl = `${config.host}:${config.port}/login/twitter/return`;
console.log('return api: ', twitterCallbackUrl);

var twitterConfig = require('./../keys/twitter.json');
var keys = Object.assign({
    callbackUrl: twitterCallbackUrl
}, {
    consumerKey: twitterConfig.consumer_key,
    consumerSecret: twitterConfig.consumer_secret
});

passport.use(new TwitterStrategy(keys,
    function (token, tokenSecret, profile, cb) {
        console.log('profile: ', profile);
        cb(null, profile);
    }
));
passport.serializeUser(function(user, cb) {
    cb(null, user);
});

passport.deserializeUser(function(obj, cb) {
    cb(null, obj);
});

app.use(passport.initialize());
app.use(passport.session());

app.get('/login/twitter',
    passport.authenticate('twitter'));

app.get('/login/twitter/auth',
    passport.authenticate('twitter', {failureRedirect: `$(config.host}:${config.port}/login`}),
    function (req, res) {
        res.redirect(`$(config.host}:${config.port}/`);
    });
/* passport.authenticate('twitter', {failureRedirect: `$(config.host}:${config.port}/login`}),
 function (req, res) {
 res.redirect(`$(config.host}:${config.port}/`);
 }); */

app.use((req, res) => {
    const splittedUrlPath = req.url.split('?')[0].split('/').slice(1);

    const {action, params} = mapUrl(actions, splittedUrlPath);

    if (action) {
        action(req, params)
            .then((result) => {
                if (result instanceof Function) {
                    result(res);
                } else {
                    res.json(result);
                }
            }, (reason) => {
                if (reason && reason.redirect) {
                    res.redirect(reason.redirect);
                } else {
                    console.error('API ERROR:', pretty.render(reason));
                    res.status(reason.status || 500).json(reason);
                }
            });
    } else {
        res.status(404).end('NOT FOUND');
    }
});

const bufferSize = 100;
const messageBuffer = new Array(bufferSize);
let messageIndex = 0;

if (config.apiPort) {
    const runnable = app.listen(config.apiPort, (err) => {
        if (err) {
            console.error(err);
        }
        console.info('----\n==> 🌎  API is running on port %s', config.apiPort);
        console.info('==> 💻  Send requests to http://%s:%s', config.apiHost, config.apiPort);
    });

    io.on('connection', (socket) => {
        socket.emit('news', {msg: `'Hello World!' from server`});

        socket.on('history', () => {
            for (let index = 0; index < bufferSize; index++) {
                const msgNo = (messageIndex + index) % bufferSize;
                const msg = messageBuffer[msgNo];
                if (msg) {
                    socket.emit('msg', msg);
                }
            }
        });

        socket.on('msg', (data) => {
            data.id = messageIndex;
            messageBuffer[messageIndex % bufferSize] = data;
            messageIndex++;
            io.emit('msg', data);
        });
    });
    io.listen(runnable);
} else {
    console.error('==>     ERROR: No PORT environment variable has been specified');
}
<commit_msg>work on twitter API<commit_after>import express from 'express';
import bodyParser from 'body-parser';
import config from '../src/config';
import * as actions from './actions/index';
import {mapUrl} from 'utils/url.js';
import PrettyError from 'pretty-error';
import http from 'http';
import SocketIo from 'socket.io';
import passport from'passport';
const TwitterStrategy = require('passport-twitter').Strategy;

const session = require('express-session');
const MongoStore = require('connect-mongo')(session);
const pretty = new PrettyError();

const app = express();
const server = new http.Server(app);
const io = new SocketIo(server);
io.path('/ws');

app.use(bodyParser.json());
app.use(session({
    secret: config.sessionKey,
    store: new MongoStore({
        url: 'mongodb://localhost/eyfApp'
    })
}));

console.log('_______ config: ', config);
const twitterCallbackUrl = `${config.apiHost}:${config.apiPort}/login/twitter/auth`;
console.log('return api: ', twitterCallbackUrl);

var twitterConfig = require('./../keys/twitter.json');
var keys = {
    callbackURL: twitterCallbackUrl,
    consumerKey: twitterConfig.consumer_key,
    consumerSecret: twitterConfig.consumer_secret
};

passport.use(new TwitterStrategy(keys,
    function (token, tokenSecret, profile, cb) {
        console.log('profile: ', profile);
        cb(null, profile);
    }
));
passport.serializeUser(function (user, cb) {
    cb(null, user);
});

passport.deserializeUser(function (obj, cb) {
    cb(null, obj);
});

app.get('/login/twitter/auth',
    passport.authenticate('twitter', {
        failureRedirect: `/login`,
        successRedirect: '/api/login'
    }));

app.use(passport.initialize());
app.use(passport.session());

app.get('/login/twitter',
    passport.authenticate('twitter'));

/* passport.authenticate('twitter', {failureRedirect: `$(config.host}:${config.port}/login`}),
 function (req, res) {
 res.redirect(`$(config.host}:${config.port}/`);
 }); */

app.use((req, res) => {
    const splittedUrlPath = req.url.split('?')[0].split('/').slice(1);

    const {action, params} = mapUrl(actions, splittedUrlPath);

    if (action) {
        action(req, params)
            .then((result) => {
                if (result instanceof Function) {
                    result(res);
                } else {
                    res.json(result);
                }
            }, (reason) => {
                if (reason && reason.redirect) {
                    res.redirect(reason.redirect);
                } else {
                    console.error('API ERROR:', pretty.render(reason));
                    res.status(reason.status || 500).json(reason);
                }
            });
    } else {
        res.status(404).end('NOT FOUND');
    }
});

const bufferSize = 100;
const messageBuffer = new Array(bufferSize);
let messageIndex = 0;

if (config.apiPort) {
    const runnable = app.listen(config.apiPort, (err) => {
        if (err) {
            console.error(err);
        }
        console.info('----\n==> 🌎  API is running on port %s', config.apiPort);
        console.info('==> 💻  Send requests to http://%s:%s', config.apiHost, config.apiPort);
    });

    io.on('connection', (socket) => {
        socket.emit('news', {msg: `'Hello World!' from server`});

        socket.on('history', () => {
            for (let index = 0; index < bufferSize; index++) {
                const msgNo = (messageIndex + index) % bufferSize;
                const msg = messageBuffer[msgNo];
                if (msg) {
                    socket.emit('msg', msg);
                }
            }
        });

        socket.on('msg', (data) => {
            data.id = messageIndex;
            messageBuffer[messageIndex % bufferSize] = data;
            messageIndex++;
            io.emit('msg', data);
        });
    });
    io.listen(runnable);
} else {
    console.error('==>     ERROR: No PORT environment variable has been specified');
}
<|endoftext|>


<commit_before>var vm = require('vm')
var extend = require('extend')
var clone = require('clone')
var EventEmitter = require('events').EventEmitter
var Contract = require('./contract.js')
var Transaction = require('./transaction.js')
var Wallet = require('./wallet.js')
var Block = require('./block.js')

module.exports = Simulator

function Simulator(opts) {
  if (!(this instanceof Simulator)) return new Simulator(opts)
  this._initialize(opts)
}

Simulator.prototype._initialize = function(opts) {
  this.contracts = {}
  this.wallets = {}
  this.transactions = {}
  this.blocks = {}
  extend(this,new EventEmitter())
}

Simulator.prototype.createContract = function(opts) {
  var wallet = opts.wallet = new Wallet({value: opts.value})
  var newContract = new Contract(opts)
  this.contracts[newContract.id] = newContract
  this.createBlock({newContracts:[newContract]})
  this.emit('contract',newContract.toJSON(),wallet.toJSON())
  return newContract
}

Simulator.prototype.createTransaction = function(opts) {
  var newTransaction = new Transaction(opts)
  this.transactions[newTransaction.id] = newTransaction
  this.processTransaction(newTransaction)
  return newTransaction
}

Simulator.prototype.createWallet = function(opts) {
  var newWallet = new Wallet(opts)
  this.wallets[newWallet.id] = newWallet
  this.emit('wallet',newWallet.toJSON())
  return newWallet
}

Simulator.prototype.processTransaction = function(transaction) {
  var targetContract = this.contracts[transaction.target],
      senderContract = this.contracts[transaction.sender],
      targetWallet, senderWallet

  // determine in sender+Target are contracts or simple wallets
  if (senderContract) {
    senderWallet = senderContract.wallet
  } else {
    senderWallet = this.wallets[transaction.sender]
  }
  if (targetContract) {
    targetWallet = targetContract.wallet
  } else {
    targetWallet = this.wallets[transaction.target]
  }

  // validate transaction
  var isValid = (true
    && transaction.value > 0
    && transaction.fee >= 0
    && (transaction.value+transaction.fee) <= senderWallet.value
  )
  if (!isValid) throw new Error('Invalid Transaction.')

  // announce activation of transaction
  this.emit('transaction',transaction.toJSON())

  // exchange values
  senderWallet.value -= (transaction.value + transaction.fee)
  targetWallet.value += transaction.value
  this.emit('wallet.update',senderWallet.toJSON())
  this.emit('wallet.update',targetWallet.toJSON())

  // update contracts, trigger contract run
  if (senderContract) {
    this.emit('contract.update',senderContract.toJSON(),senderWallet.toJSON())
  }
  if (targetContract) {
    this.emit('contract.update',targetContract.toJSON(),targetWallet.toJSON())
    this.runContract(targetContract, transaction)
  }

  // mine a block for this transaction
  this.createBlock({
    transactions:[transaction],
    runContracts: targetContract ? [targetContract] : [],
  })
}

Simulator.prototype.runContract = function(contract,transaction) {
  var sim = this

  // announce activation of contract
  this.emit('contract.activate',contract.toJSON(),transaction.toJSON())

  var programSrc = '(function(){\n\n\n'+contract.js+'\n\n\n})()'
  vm.runInNewContext(programSrc, {
    contract: {
      storage: contract.storage,
      mem: [],
    },
    tx: {
      sender: transaction.sender,
      value: transaction.value,
      fee: transaction.fee,
      data: clone(transaction.data),
      datan: transaction.datan,
    },
    block: {
      contract_storage: function(id) { return clone(sim.contracts[id].storage) },
      basefee: 1,
      // time in seconds
      timestamp: (new Date()).getTime()/1000,
    },
    mktx: function(target, value, fee, data) {
      this.createTransaction({
        target: target,
        sender: transaction.sender,
        value: value,
        fee: fee || 0,
        data: data || [],
      })
    },
  })
}

Simulator.prototype.createBlock = function(opts) {
  var newBlock = new Block(opts)
  this.blocks[newBlock.id] = newBlock
  this.emit('block',newBlock.toJSON())
}
<commit_msg>Allow zero-value transactions<commit_after>var vm = require('vm')
var extend = require('extend')
var clone = require('clone')
var EventEmitter = require('events').EventEmitter
var Contract = require('./contract.js')
var Transaction = require('./transaction.js')
var Wallet = require('./wallet.js')
var Block = require('./block.js')

module.exports = Simulator

function Simulator(opts) {
  if (!(this instanceof Simulator)) return new Simulator(opts)
  this._initialize(opts)
}

Simulator.prototype._initialize = function(opts) {
  this.contracts = {}
  this.wallets = {}
  this.transactions = {}
  this.blocks = {}
  extend(this,new EventEmitter())
}

Simulator.prototype.createContract = function(opts) {
  var wallet = opts.wallet = new Wallet({value: opts.value})
  var newContract = new Contract(opts)
  this.contracts[newContract.id] = newContract
  this.createBlock({newContracts:[newContract]})
  this.emit('contract',newContract.toJSON(),wallet.toJSON())
  return newContract
}

Simulator.prototype.createTransaction = function(opts) {
  var newTransaction = new Transaction(opts)
  this.transactions[newTransaction.id] = newTransaction
  this.processTransaction(newTransaction)
  return newTransaction
}

Simulator.prototype.createWallet = function(opts) {
  var newWallet = new Wallet(opts)
  this.wallets[newWallet.id] = newWallet
  this.emit('wallet',newWallet.toJSON())
  return newWallet
}

Simulator.prototype.processTransaction = function(transaction) {
  var targetContract = this.contracts[transaction.target],
      senderContract = this.contracts[transaction.sender],
      targetWallet, senderWallet

  // determine in sender+Target are contracts or simple wallets
  if (senderContract) {
    senderWallet = senderContract.wallet
  } else {
    senderWallet = this.wallets[transaction.sender]
  }
  if (targetContract) {
    targetWallet = targetContract.wallet
  } else {
    targetWallet = this.wallets[transaction.target]
  }

  // validate transaction
  var isValid = (true
    && transaction.value >= 0
    && transaction.fee >= 0
    && (transaction.value+transaction.fee) <= senderWallet.value
  )
  if (!isValid) throw new Error('Invalid Transaction.')

  // announce activation of transaction
  this.emit('transaction',transaction.toJSON())

  // exchange values
  senderWallet.value -= (transaction.value + transaction.fee)
  targetWallet.value += transaction.value
  this.emit('wallet.update',senderWallet.toJSON())
  this.emit('wallet.update',targetWallet.toJSON())

  // update contracts, trigger contract run
  if (senderContract) {
    this.emit('contract.update',senderContract.toJSON(),senderWallet.toJSON())
  }
  if (targetContract) {
    this.emit('contract.update',targetContract.toJSON(),targetWallet.toJSON())
    this.runContract(targetContract, transaction)
  }

  // mine a block for this transaction
  this.createBlock({
    transactions:[transaction],
    runContracts: targetContract ? [targetContract] : [],
  })
}

Simulator.prototype.runContract = function(contract,transaction) {
  var sim = this

  // announce activation of contract
  this.emit('contract.activate',contract.toJSON(),transaction.toJSON())

  var programSrc = '(function(){\n\n\n'+contract.js+'\n\n\n})()'
  vm.runInNewContext(programSrc, {
    contract: {
      storage: contract.storage,
      mem: [],
    },
    tx: {
      sender: transaction.sender,
      value: transaction.value,
      fee: transaction.fee,
      data: clone(transaction.data),
      datan: transaction.datan,
    },
    block: {
      contract_storage: function(id) { return clone(sim.contracts[id].storage) },
      basefee: 1,
      // time in seconds
      timestamp: (new Date()).getTime()/1000,
    },
    mktx: function(target, value, fee, data) {
      this.createTransaction({
        target: target,
        sender: transaction.sender,
        value: value,
        fee: fee || 0,
        data: data || [],
      })
    },
  })
}

Simulator.prototype.createBlock = function(opts) {
  var newBlock = new Block(opts)
  this.blocks[newBlock.id] = newBlock
  this.emit('block',newBlock.toJSON())
}
<|endoftext|>


<commit_before>/*
 * This file is part of the GOsa project -  http://gosa-project.org
 *
 * Copyright:
 *    (C) 2010-2017 GONICUS GmbH, Germany, http://www.gonicus.de
 *
 * License:
 *    LGPL-2.1: http://www.gnu.org/licenses/lgpl-2.1.html
 *
 * See the LICENSE file in the project's top-level directory for details.
 */

qx.Class.define("gosa.ui.form.WebhookListItem", {
  extend: qx.ui.core.Widget,
  implement : [qx.ui.form.IModel],
  include : [qx.ui.form.MModelProperty],

  /*
  *****************************************************************************
     CONSTRUCTOR
  *****************************************************************************
  */
  construct : function() {
    this.base(arguments);
    this._setLayout(new qx.ui.layout.VBox());
  },

  /*
  *****************************************************************************
     PROPERTIES
  *****************************************************************************
  */
  properties : {
    appearance :
    {
      refine : true,
      init : "gosa-listitem-webhook"
    },

    label: {
      check: "String",
      nullable: true,
      apply: "_applyLabel"
    },

    mimeType: {
      check: "String",
      nullable: true
    },

    secret: {
      check: "String",
      nullable: true,
      apply: "_applySecret"
    },

    expanded: {
      check: "Boolean",
      init: false,
      apply: "_applyExpanded"
    },
    /**
     * How this list item should behave like group or normal ListItem
     */
    listItemType: {
      check: ['group', 'item'],
      init: 'item',
      apply: '_applyListItemType'
    }
  },

  /*
  *****************************************************************************
     MEMBERS
  *****************************************************************************
  */
  members : {

    // overridden
    _createChildControlImpl: function(id) {
      var control;

      switch(id) {

        case "label":
          control = new qx.ui.basic.Label();
          control.setAnonymous(true);
          this._addAt(control, 0);
          break;

        case "expansion":
          control = new qx.ui.container.Composite(new qx.ui.layout.Grid(5, 5));
          control.setAnonymous(true);
          control.exclude();
          this._addAt(control, 2, {flex: 1});
          break;

        case "hint":
          var headers = '

Content-Type: '+
                        this.getMimeType()+'

HTTP_X_HUB_SENDER: '+
                        this.getLabel()+'

HTTP_X_HUB_SIGNATURE: '+
                        this.tr("SHA2 hash of the content body encrypted with secret:")+' '+this.getSecret()+'

';
          var msg = this.tr("Use the following headers when you POST data to %1", ""+gosa.ui.settings.Webhooks.URL+"");
          msg += headers;
          control = new qx.ui.basic.Label(msg).set({rich: true, wrap: true});
          this.getChildControl("expansion").add(control, {row: 0, column: 0});
          break;
      }

      return control || this.base(arguments, id);
    },

    _applyExpanded: function(value) {
      if (value === true) {
        this.getChildControl("expansion").show();
      } else {
        this.getChildControl("expansion").exclude();
      }
    },

    // property apply
    _applyLabel: function(value) {
      this.__handleValue(this.getChildControl("label"), value);
    },

    // property apply
    _applySecret: function() {
      if (!this.hasChildControl("hint")) {
        this._createChildControl("hint");
      }
    },

    // property apply
    _applyListItemType: function(value) {
      if (value === "group") {
        this.setAppearance("gosa-listitem-webhook-group");
        this.setEnabled(false);
      } else {
        this.setAppearance("gosa-listitem-webhook");
        this.setEnabled(true);
      }
    },

    __handleValue: function(control, value) {
      if (value) {
        control.setValue(value);
        control.show();
      } else {
        control.exclude();
      }
    }
  }
});<commit_msg>use the correct hash function<commit_after>/*
 * This file is part of the GOsa project -  http://gosa-project.org
 *
 * Copyright:
 *    (C) 2010-2017 GONICUS GmbH, Germany, http://www.gonicus.de
 *
 * License:
 *    LGPL-2.1: http://www.gnu.org/licenses/lgpl-2.1.html
 *
 * See the LICENSE file in the project's top-level directory for details.
 */

qx.Class.define("gosa.ui.form.WebhookListItem", {
  extend: qx.ui.core.Widget,
  implement : [qx.ui.form.IModel],
  include : [qx.ui.form.MModelProperty],

  /*
  *****************************************************************************
     CONSTRUCTOR
  *****************************************************************************
  */
  construct : function() {
    this.base(arguments);
    this._setLayout(new qx.ui.layout.VBox());
  },

  /*
  *****************************************************************************
     PROPERTIES
  *****************************************************************************
  */
  properties : {
    appearance :
    {
      refine : true,
      init : "gosa-listitem-webhook"
    },

    label: {
      check: "String",
      nullable: true,
      apply: "_applyLabel"
    },

    mimeType: {
      check: "String",
      nullable: true
    },

    secret: {
      check: "String",
      nullable: true,
      apply: "_applySecret"
    },

    expanded: {
      check: "Boolean",
      init: false,
      apply: "_applyExpanded"
    },
    /**
     * How this list item should behave like group or normal ListItem
     */
    listItemType: {
      check: ['group', 'item'],
      init: 'item',
      apply: '_applyListItemType'
    }
  },

  /*
  *****************************************************************************
     MEMBERS
  *****************************************************************************
  */
  members : {

    // overridden
    _createChildControlImpl: function(id) {
      var control;

      switch(id) {

        case "label":
          control = new qx.ui.basic.Label();
          control.setAnonymous(true);
          this._addAt(control, 0);
          break;

        case "expansion":
          control = new qx.ui.container.Composite(new qx.ui.layout.Grid(5, 5));
          control.setAnonymous(true);
          control.exclude();
          this._addAt(control, 2, {flex: 1});
          break;

        case "hint":
          var headers = '

Content-Type: '+
                        this.getMimeType()+'

HTTP_X_HUB_SENDER: '+
                        this.getLabel()+'

HTTP_X_HUB_SIGNATURE: '+
                        this.tr("SHA-512 hash of the content body encrypted with secret:")+' '+this.getSecret()+'

';
          var msg = this.tr("Use the following headers when you POST data to %1", ""+gosa.ui.settings.Webhooks.URL+"");
          msg += headers;
          control = new qx.ui.basic.Label(msg).set({rich: true, wrap: true});
          this.getChildControl("expansion").add(control, {row: 0, column: 0});
          break;
      }

      return control || this.base(arguments, id);
    },

    _applyExpanded: function(value) {
      if (value === true) {
        this.getChildControl("expansion").show();
      } else {
        this.getChildControl("expansion").exclude();
      }
    },

    // property apply
    _applyLabel: function(value) {
      this.__handleValue(this.getChildControl("label"), value);
    },

    // property apply
    _applySecret: function() {
      if (!this.hasChildControl("hint")) {
        this._createChildControl("hint");
      }
    },

    // property apply
    _applyListItemType: function(value) {
      if (value === "group") {
        this.setAppearance("gosa-listitem-webhook-group");
        this.setEnabled(false);
      } else {
        this.setAppearance("gosa-listitem-webhook");
        this.setEnabled(true);
      }
    },

    __handleValue: function(control, value) {
      if (value) {
        control.setValue(value);
        control.show();
      } else {
        control.exclude();
      }
    }
  }
});<|endoftext|>


<commit_before>//You really need body parser for things to work correctly
var express = require('express'),
    mongoose = require('mongoose'),
    Schema = mongoose.Schema,
    bodyParser = require('body-parser'),
    http = require('http'),
    models = require('../models/models.js'),
    restify = require('express-restify-mongoose'),
    methodOverride = require('method-override'),
    compress = require('compression');

mongoose.connect('mongodb://localhost/lcbo');

var InventoryModel = mongoose.model('inventory', models.schema.inventory);
var StoreModel = mongoose.model('store', models.schema.store);
var ProductModel = mongoose.model('product', models.schema.product);

var app = express();
app.use(compress);
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(methodOverride('X-HTTP-Method-Override'));

var router = express.Router();
restify.serve(router, InventoryModel);
restify.serve(router, StoreModel);
restify.serve(router, ProductModel);

app.use(router);

app.listen(3000, function() {
    console.log("Express server listening on port 3000");
});<commit_msg>adding error handling and logging<commit_after>//You really need body parser for things to work correctly
var express = require('express'),
    mongoose = require('mongoose'),
    Schema = mongoose.Schema,
    bodyParser = require('body-parser'),
    http = require('http'),
    models = require('../models/models.js'),
    restify = require('express-restify-mongoose'),
    methodOverride = require('method-override'),
    compress = require('compression');

mongoose.connect('mongodb://localhost/lcbo');

var InventoryModel = mongoose.model('inventory', models.schema.inventory);
var StoreModel = mongoose.model('store', models.schema.store);
var ProductModel = mongoose.model('product', models.schema.product);

var app = express();
//app.use(compress);
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(methodOverride('X-HTTP-Method-Override'));

var router = express.Router();
restify.serve(router, InventoryModel);
restify.serve(router, StoreModel);
restify.serve(router, ProductModel);

app.use(router);

app.listen(3000, function() {
    console.log("Express server listening on port 3000");
});<|endoftext|>


<commit_before>'use strict';

// Loading dependencies.
var _ = require('underscore'),
    express = require('express'),
    bodyParser = require('body-parser'),
    data = require('./data.js');

// Instantiating the framework and a router for our requests.
var app = express(),
    router = express.Router();

// The port which this script will listen to.
var apiPort = 4000;

// Anti XSSI (Cross-site script inclusion) string.
var xssiString = ')]}\',';

// Application parses request bodies: application/json, application/x-www-form-urlencoded, and multipart/form-data.
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

// Handler for all requests.
router.use(function(req, res, next) {
    console.log('Request:', 'GET', req.originalUrl);
    next();
});

// Route: Collection endpoint returning all records.
router.get('/avengers', function(request, response) {
    var returnData = [];

    data.forEach(function(record) {
        var subsetRecord = _.pick(record, 'id', 'alias');
        returnData.push(subsetRecord);
    });

    setTimeout(function() {
        response.type('application/json');
        response.send(xssiString + JSON.stringify(returnData));
    }, 3000);
});

// Route: Model endpoint returning an individual record.
router.get('/avengers/:id', function(request, response) {
    var individualRecord = _.findWhere(data, { id: request.params.id });

    setTimeout(function() {
        response.type('application/json');
        response.send(xssiString + JSON.stringify(individualRecord));
    }, 3000);
});

// Associate the router with our application, and prefix the routes.
app.use('/api', router);

// Listen for the above routes on the following port.
app.listen(apiPort);

// Debugging to the console that the server has started.
console.log('Mock API Server: http://localhost:' + apiPort + '/');<commit_msg>Adding CORS headers onto the API endpoints.<commit_after>'use strict';

// Loading dependencies.
var _ = require('underscore'),
    express = require('express'),
    bodyParser = require('body-parser'),
    data = require('./data.js');

// Instantiating the framework and a router for our requests.
var app = express(),
    router = express.Router();

// The port which this script will listen to.
var apiPort = 4000;

// Anti XSSI (Cross-site script inclusion) string.
var xssiString = ')]}\',';

// Application parses request bodies: application/json, application/x-www-form-urlencoded, and multipart/form-data.
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

// Handler for all requests. Responses are given CORS headers.
router.use(function(request, response, next) {
    console.log('Request:', 'GET', request.originalUrl);
    response.header('Access-Control-Allow-Origin', '*');
    next();
});

// Route: Collection endpoint returning all records.
router.get('/avengers', function(request, response) {
    var returnData = [];

    data.forEach(function(record) {
        var subsetRecord = _.pick(record, 'id', 'alias');
        returnData.push(subsetRecord);
    });

    setTimeout(function() {
        response.type('application/json');
        response.send(xssiString + JSON.stringify(returnData));
    }, 3000);
});

// Route: Model endpoint returning an individual record.
router.get('/avengers/:id', function(request, response) {
    var individualRecord = _.findWhere(data, { id: request.params.id });

    setTimeout(function() {
        response.type('application/json');
        response.send(xssiString + JSON.stringify(individualRecord));
    }, 3000);
});

// Associate the router with our application, and prefix the routes.
app.use('/api', router);

// Listen for the above routes on the following port.
app.listen(apiPort);

// Debugging to the console that the server has started.
console.log('Mock API Server: http://localhost:' + apiPort + '/');<|endoftext|>


<commit_before>'use babel';

import { CompositeDisposable } from 'atom';

export default {
  subscriptions: null,
  config: {
    autoHardWrap: {
      type: 'boolean',
      default: true
    },
    columnGuide: {
      type: 'integer',
      default: 80
    }
  },

  activate(state) {
    // Events subscribed to in atom's system can be easily cleaned up with a CompositeDisposable
    this.subscriptions = new CompositeDisposable();

    // Register command that toggles this view
    this.subscriptions.add(atom.commands.add('atom-workspace', {
      'slickwrap:toggle': () => this.toggle()
    }));
    var editor = atom.workspace.getActiveTextEditor();
    var editorView = atom.views.getView(editor);
    editorView.addEventListener('keyup', function(event) {
      // keycode: 32 -> space, 13 -> enter, 9 -> tab
      var code = event.keyCode;
      if (code == 32 || code == 13 || code == 9) {
        if (atom.config.get('slickwrap.autoHardWrap')) {
          adjust();
        }
      }
    });
  },

  deactivate() {
    this.subscriptions.dispose();
  },

  toggle() {
    adjust();
  },

};

function adjust() {
  var editor = atom.workspace.getActiveTextEditor();
  var endColumn = atom.config.get('slickwrap.columnGuide');
  var cursorPos = editor.getCursorBufferPosition();
  if (cursorPos.column <= endColumn) {
    return;
  }

  var text = editor.getText();
  var lines = text.split(/\r?\n/);
  var resultLines = [];
  lines.map(function(line) {
    resultLines.push.apply(resultLines, adjusted(line, endColumn));
  });

  var len = resultLines.length;
  if (len > 0) {
    var newText = resultLines.join('\n');
    editor.setText(newText);
    var lastRow = len - 1;
    var lastCol = resultLines[len - 1].length - 1;
    editor.setCursorBufferPosition([lastRow, lastCol]);
  }
}

function adjusted(line, limit) {
  // console.log('-------input');
  // console.log(line);
  var resultLines = [];
  if (line && line.length > limit) {
    var currentLength = 0;
    var currentLine = "";
    var lineRemaining = line;
    while (true) {
      var ws = lineRemaining.search(/\s/);
      if (ws < 0) {
        ws = lineRemaining.length - 1;
      }
      currentLength += (ws + 1);
      if (currentLength > limit) {
        break;
      }
      currentLine += lineRemaining.substring(0, ws + 1);
      lineRemaining = lineRemaining.substring(ws + 1);
    }
    resultLines.push(currentLine)
    resultLines.push.apply(resultLines, adjusted(lineRemaining, limit));
  }
  else {
    resultLines.push(line);
  }
  // console.log('-------output');
  // console.log(resultLines);
  return resultLines;
}
<commit_msg>refactorings to use Disposable<commit_after>'use babel';

import { CompositeDisposable, Disposable } from 'atom';

export default {
  subscriptions: null,
  config: {
    autoHardWrap: {
      type: 'boolean',
      default: true
    },
    columnGuide: {
      type: 'integer',
      default: 80
    }
  },

  activate(state) {
    // Events subscribed to in atom's system can be easily cleaned up with a CompositeDisposable
    this.subscriptions = new CompositeDisposable();

    // Register command that toggles this view
    this.subscriptions.add(atom.commands.add('atom-workspace', {
      'slickwrap:toggle': () => this.toggle()
    }));

    // Register keyboard event.
    var editor = atom.workspace.getActiveTextEditor();
    var editorView = atom.views.getView(editor);
    this.subscribeEvent(editorView, 'keyup', (event) => {
      // keycode: 32 -> space, 13 -> enter, 9 -> tab
      var code = event.keyCode;
      if (code == 32 || code == 13 || code == 9) {
        if (atom.config.get('slickwrap.autoHardWrap')) {
          this.adjust();
        }
      }
    });
  },

  subscribeEvent(observed, type, callback) {
    observed.addEventListener(type, callback);
    this.subscriptions.add(new Disposable(() => {
      observed.removeEventListener(type, callback)}));
  },

  deactivate() {
    this.subscriptions.dispose();
  },

  toggle() {
    this.adjust();
  },

  adjust() {
    var editor = atom.workspace.getActiveTextEditor();
    var endColumn = atom.config.get('slickwrap.columnGuide');
    var cursorPos = editor.getCursorBufferPosition();
    if (cursorPos.column <= endColumn) {
      return;
    }

    var text = editor.getText();
    var lines = text.split(/\r?\n/);
    var resultLines = [];
    lines.map((line) => {
      resultLines.push.apply(resultLines, this.adjusted(line, endColumn));
    });

    var len = resultLines.length;
    if (len > 0) {
      var newText = resultLines.join('\n');
      editor.setText(newText);
      var lastRow = len - 1;
      var lastCol = resultLines[len - 1].length - 1;
      editor.setCursorBufferPosition([lastRow, lastCol]);
    }
  },

  adjusted(line, limit) {
    var resultLines = [];
    if (line && line.length > limit) {
      var currentLength = 0;
      var currentLine = "";
      var lineRemaining = line;
      while (true) {
        var ws = lineRemaining.search(/\s/);
        if (ws < 0) {
          ws = lineRemaining.length - 1;
        }
        currentLength += (ws + 1);
        if (currentLength > limit) {
          break;
        }
        currentLine += lineRemaining.substring(0, ws + 1);
        lineRemaining = lineRemaining.substring(ws + 1);
      }
      resultLines.push(currentLine)
      resultLines.push.apply(resultLines, this.adjusted(lineRemaining, limit));
    }
    else {
      resultLines.push(line);
    }
    return resultLines;
  }

};
<|endoftext|>


<commit_before>var util = require('util');
var spawn = require('child_process').spawn

var createSlimPreprocessor = function(logger, basePath, config) {
  config = typeof config === 'object' ? config : {};

  var log = logger.create('preprocessor.slim');

  var stripPrefix = new RegExp('^' + (config.stripPrefix || ''));
  var prependPrefix = config.prependPrefix || '';
  var cacheIdFromPath = config && config.cacheIdFromPath || function(filepath) {
    return prependPrefix + filepath.replace(stripPrefix, '');
  };

  return function(content, file, done) {
    var child, html

    log.debug('Processing "%s".', file.originalPath);

    var htmlPath = cacheIdFromPath(file.originalPath.replace(basePath + '/', ''));

    var origPath = file.path
    // TODO ???
    file.path = file.path + '.js';

    // TODO
    origPath = origPath.split("queue-web-client/")[1]
    log.debug("Spawning", origPath)

    html = ''
    child = spawn("slimrb", [origPath])

    child.stdout.on('data', function (buf) {
      html += String(buf);
    });

    child.stdout.on('close', function (buf) {
      done(html);
    });

    child.stderr.on('data', function (buf) {
      throw String(buf);
    });
  };
};

createSlimPreprocessor.$inject = ['logger', 'config.basePath', 'config.ngHtml2JsPreprocessor'];

module.exports = createSlimPreprocessor;
<commit_msg>clean up unused parts of script<commit_after>var util = require('util');
var spawn = require('child_process').spawn

var createSlimPreprocessor = function(logger) {
  config = typeof config === 'object' ? config : {};

  var log = logger.create('preprocessor.slim');

  return function(content, file, done) {
    var child, html, origPath

    log.debug('Processing "%s".', file.originalPath);

    origPath = file.originalPath
    html = ''
    child = spawn("slimrb", [origPath])

    child.stdout.on('data', function (buf) {
      html += String(buf);
    });

    child.stdout.on('close', function (buf) {
      done(html);
    });

    child.stderr.on('data', function (buf) {
      throw String(buf);
    });
  };
};

createSlimPreprocessor.$inject = ['logger'];

module.exports = createSlimPreprocessor;
<|endoftext|>