<commit_before>// Manager module

// Package dependencies
var scripts = require('child_process');
var config = require('../config.js');
var common = require('./_common.js');
var rebootScript =

// /reboot
// Reboots the system
exports.reboot = function (req, res) {
  // Reboots the system
  scripts.exec('sudo /sbin/reboot', function (error, stdout, stderr) {
    if (error) {
      common.logError(stderr);
      common.sendJSON('reboot_error', res, 500);
      return;
    }
    common.sendJSON('reboot_ok', res, 200);
  });
};<commit_msg>Minor fix<commit_after>// Manager module

// Package dependencies
var scripts = require('child_process');
var config = require('../config.js');
var common = require('./_common.js');
var rebootScript =

// /reboot
// Reboots the system
exports.reboot = function (req, res) {
  // Reboots the system
  scripts.exec('sudo /sbin/reboot', function (error, stdout, stderr) {
    if (error) {
      common.logError(stderr);
      res.sendCode(500);
      return;
    }
    common.sendJSON('reboot_ok', res, 200);
  });
};<|endoftext|>


<commit_before>var EditSession = CodeMirror.Doc;

/**
 * @constructor
 * @param {DOM} elementId
 * @param {Settings} settings
 */
function EditorCodeMirror(editorElement, settings) {
  this.element_ = editorElement;
  this.settings_ = settings;
  this.cm_ = CodeMirror(editorElement, {'autofocus': true, 'value': ''});
  this.cm_.setSize(null, 'auto');
  this.searchCursor_ = null;
  this.setTheme();
}

/**
 * @param {string} opt_content
 * @return {EditSession}
 * Create an edit session for a new file. Each tab should have its own session.
 */
EditorCodeMirror.prototype.newSession = function(opt_content) {
  var session = new CodeMirror.Doc('');
  return session;
};
/**
 * @param {EditSession} session
 * Change the current session, usually to switch to another tab.
 */
EditorCodeMirror.prototype.setSession = function(session) {
  this.cm_.swapDoc(session);
};

EditorCodeMirror.prototype.find = function(string) {
  this.searchCursor_ = this.cm_.getSearchCursor(string, this.cm_.getCursor());
  this.findNext();
};

EditorCodeMirror.prototype.findNext = function() {
  if (this.searchCursor_ && this.searchCursor_.findNext()) {
    var from = this.searchCursor_.from();
    var to = this.searchCursor_.to();
    console.log(from, to);
    this.cm_.setSelection(to, from);
  }
};

EditorCodeMirror.prototype.clearSearch = function() {
  this.searchCursor_ = null;
};

EditorCodeMirror.prototype.onChange = function(e) {
};

EditorCodeMirror.prototype.undo = function() {
};

EditorCodeMirror.prototype.redo = function() {
};

EditorCodeMirror.prototype.focus = function() {
  this.cm_.focus();
};

/**
 * @param {Session} session
 * @param {string} extension
 */
EditorCodeMirror.prototype.setMode = function(session, extension) {
};

/**
 * The actual changing of the font size will be triggered by settings change
 * event.
 */
EditorCodeMirror.prototype.increaseFontSize = function() {
};

/**
 * The actual changing of the font size will be triggered by settings change
 * event.
 */
EditorCodeMirror.prototype.decreseFontSize = function() {
};

/**
 * @param {number} fontSize
 * Update font size from settings.
 */
EditorCodeMirror.prototype.setFontSize = function(fontSize) {
};

/**
 * @param {EditSession} session
 * @return {string}
 */
EditorCodeMirror.prototype.getContents = function(session) {
};

/**
 * @param {EditSession} session
 * @param {number} size
 */
EditorCodeMirror.prototype.setTabSize = function(session, size) {
  this.cm_.setOption('tabSize', size);
};

/**
 * @param {string} theme
 */
EditorCodeMirror.prototype.setTheme = function(theme) {
};

/**
 * @param {boolean} val
 */
EditorCodeMirror.prototype.showHideLineNumbers = function(val) {
  this.cm_.setOption('lineNumbers', val);
};

/**
 * @param {boolean} val
 */
EditorCodeMirror.prototype.setWrapLines = function(val) {
  this.cm_.setOption('lineWrapping', val);
};

/**
 * @param {boolean} show
 * @param {number} col
 */
EditorCodeMirror.prototype.showHideMargin = function(show, col) {

};

var Editor = EditorCodeMirror;

<commit_msg>Implement change event and getting contents of CodeMirror tab.<commit_after>var EditSession = CodeMirror.Doc;

/**
 * @constructor
 * @param {DOM} elementId
 * @param {Settings} settings
 */
function EditorCodeMirror(editorElement, settings) {
  this.element_ = editorElement;
  this.settings_ = settings;
  this.cm_ = CodeMirror(editorElement, {'autofocus': true, 'value': ''});
  this.cm_.setSize(null, 'auto');
  this.cm_.on('change', this.onChange.bind(this));
  this.searchCursor_ = null;
  this.setTheme();
}

/**
 * @param {string} opt_content
 * @return {EditSession}
 * Create an edit session for a new file. Each tab should have its own session.
 */
EditorCodeMirror.prototype.newSession = function(opt_content) {
  var session = new CodeMirror.Doc('');
  return session;
};
/**
 * @param {EditSession} session
 * Change the current session, usually to switch to another tab.
 */
EditorCodeMirror.prototype.setSession = function(session) {
  this.cm_.swapDoc(session);
};

EditorCodeMirror.prototype.find = function(string) {
  this.searchCursor_ = this.cm_.getSearchCursor(string, this.cm_.getCursor());
  this.findNext();
};

EditorCodeMirror.prototype.findNext = function() {
  if (this.searchCursor_ && this.searchCursor_.findNext()) {
    var from = this.searchCursor_.from();
    var to = this.searchCursor_.to();
    console.log(from, to);
    this.cm_.setSelection(to, from);
  }
};

EditorCodeMirror.prototype.clearSearch = function() {
  this.searchCursor_ = null;
};

EditorCodeMirror.prototype.onChange = function() {
  $.event.trigger('docchange', this.cm_.getDoc());
};

EditorCodeMirror.prototype.undo = function() {
};

EditorCodeMirror.prototype.redo = function() {
};

EditorCodeMirror.prototype.focus = function() {
  this.cm_.focus();
};

/**
 * @param {Session} session
 * @param {string} extension
 */
EditorCodeMirror.prototype.setMode = function(session, extension) {
};

/**
 * The actual changing of the font size will be triggered by settings change
 * event.
 */
EditorCodeMirror.prototype.increaseFontSize = function() {
};

/**
 * The actual changing of the font size will be triggered by settings change
 * event.
 */
EditorCodeMirror.prototype.decreseFontSize = function() {
};

/**
 * @param {number} fontSize
 * Update font size from settings.
 */
EditorCodeMirror.prototype.setFontSize = function(fontSize) {
};

/**
 * @param {EditSession} session
 * @return {string}
 */
EditorCodeMirror.prototype.getContents = function(session) {
  session.getValue();
};

/**
 * @param {EditSession} session
 * @param {number} size
 */
EditorCodeMirror.prototype.setTabSize = function(session, size) {
  this.cm_.setOption('tabSize', size);
};

/**
 * @param {string} theme
 */
EditorCodeMirror.prototype.setTheme = function(theme) {
};

/**
 * @param {boolean} val
 */
EditorCodeMirror.prototype.showHideLineNumbers = function(val) {
  this.cm_.setOption('lineNumbers', val);
};

/**
 * @param {boolean} val
 */
EditorCodeMirror.prototype.setWrapLines = function(val) {
  this.cm_.setOption('lineWrapping', val);
};

/**
 * @param {boolean} show
 * @param {number} col
 */
EditorCodeMirror.prototype.showHideMargin = function(show, col) {
};

var Editor = EditorCodeMirror;

<|endoftext|>


<commit_before>var config = module.exports = {
  base_dir        : __dirname + '/../',
  name            : 'AppName',

  default_controller  : 'app',

  router : {

    rules     : {
      'route_abbr'        : 'controller.action',
      'multi_route'       : [
        'controller1.some_action',
        'controller2.another_action'
      ]
    }
  },

  preload_components : [ 'log_router', 'files' ],

  components : {

    web_sockets_server  : true,
    user                : true,

    db                  : {
      type : 'mysql',
      user : 'username',
      pass : 'password',
      base : 'db_name',
      host : 'localhost',
      dbslayer : {
        host : 'localhost',
        port : 9090
      }
    },

    log_router          : {
      routes : {
        console : {
          levels : [ 'trace', 'info', 'warning', 'error' ]
        },
        file : {
          levels : [ 'trace', 'info', 'warning', 'error' ]
        }
      }
    },

    files : {
      default_folder : 'user_files'
    },

    mail : {
      smtp : {
        user : 'username',
        pass : 'password'//,
//        host : 'localhost,    - for example smtp.gmail.com
//        port : 25,
//        ssl  : false,
//        tls  : true
      },
      default_message : {
//        to      : 'user@host.com',
//        from    : 'another_user@host.com',
//        subject : 'subject'
      }
    }
  }
};<commit_msg>added params to common_config<commit_after>var config = module.exports = {
  base_dir        : __dirname + '/../',
  name            : 'AppName',

  params          : {},

  default_controller  : 'app',

  router : {

    rules     : {
      'route_abbr'        : 'controller.action',
      'multi_route'       : [
        'controller1.some_action',
        'controller2.another_action'
      ]
    }
  },

  preload_components : [ 'log_router', 'files' ],

  components : {

    web_sockets_server  : true,
    user                : true,

    db                  : {
      type : 'mysql',
      user : 'username',
      pass : 'password',
      base : 'db_name',
      host : 'localhost',
      dbslayer : {
        host : 'localhost',
        port : 9090
      }
    },

    log_router          : {
      routes : {
        console : {
          levels : [ 'trace', 'info', 'warning', 'error' ]
        },
        file : {
          levels : [ 'trace', 'info', 'warning', 'error' ]
        }
      }
    },

    files : {
      default_folder : 'user_files'
    },

    mail : {
      smtp : {
        user : 'username',
        pass : 'password'//,
//        host : 'localhost,    - for example smtp.gmail.com
//        port : 25,
//        ssl  : false,
//        tls  : true
      },
      default_message : {
//        to      : 'user@host.com',
//        from    : 'another_user@host.com',
//        subject : 'subject'
      }
    }
  }
};<|endoftext|>


<commit_before>var app = angular.module("loklak", ['ngRoute']);
app.controller("status", function($scope, $http) {
  $http.get("http://api.susi.ai/aggregation/status.json").
    success(function(data, status, headers, config) {
      $scope.index = data.index;
    });
});

app.controller("search", function($scope, $http) {
  $scope.query = '';
  $scope.results = [];
  $scope.search = function() {
    if ($scope.query != '') {
      $scope.results = [];
      $http.get("http://api.susi.ai/aaa/search.json?q=" + $scope.query).
        success(function(data, status, headers, config) {
          for (var i = 0; i < data.statuses.length; i++) {
            $scope.results.push(data.statuses[i].text);
          }
        });
    }
  }
});

app.filter("reverse", function() {
  return function(items) {
    if (!items || !items.length) {
      return;
    }
    return items.slice().reverse();
  };
});

angular.element(document).ready(function () {
  var navString = "";
  var winLocation = window.location.href;
  $.getJSON("http://api.susi.ai/cms/topmenu.json", function(data) {
    navItems = data.items;
    navItems = navItems.reverse();
    var count = 0;
    $.each( navItems, function(index, itemData) {
      name = Object.keys(itemData);
      link = itemData[name];
      // Now construct the li items
      liItem = "
";
      if (winLocation.indexOf(link) != -1 && count != 1) {
        liItem = "
";
        count = count + 1;
      }
      if(name == "Blog") { // The Blog tab redirects to the loklak blog (http://blog.loklak.net/)
        liItem += ""+name+"
";
      }
      else {
        liItem += ""+name+"
";
      }
      liItem = $(liItem);
      $('#navbar > ul').prepend(liItem);
    });
  });
});
<commit_msg>Broken Navigation bar fixed (#31)<commit_after>var app = angular.module("loklak", ['ngRoute']);
app.controller("status", function($scope, $http) {
  $http.get("http://api.susi.ai/aggregation/status.json").
    success(function(data, status, headers, config) {
      $scope.index = data.index;
    });
});

app.controller("search", function($scope, $http) {
  $scope.query = '';
  $scope.results = [];
  $scope.search = function() {
    if ($scope.query != '') {
      $scope.results = [];
      $http.get("http://api.susi.ai/aaa/search.json?q=" + $scope.query).
        success(function(data, status, headers, config) {
          for (var i = 0; i < data.statuses.length; i++) {
            $scope.results.push(data.statuses[i].text);
          }
        });
    }
  }
});

app.filter("reverse", function() {
  return function(items) {
    if (!items || !items.length) {
      return;
    }
    return items.slice().reverse();
  };
});

angular.element(document).ready(function () {
  var navString = "";
  var winLocation = window.location.href;
  var navString = "";
  var winLocation = window.location.href;
  var navItems = [];
  var count = 0;
  $.ajax("http://api.susi.ai/cms/topmenu.json", {
    data: { checkLogin: true },
    dataType: "jsonp",
    success: function (response) {
      navItems = response.items;
      navItems = navItems.reverse();
      $.each( navItems, function(index, itemData) {
        name = Object.keys(itemData);
        link = itemData[name];
        liItem = "
";
        if (winLocation.indexOf(link) != -1 && count != 1) {
        liItem = "
";
        count = count + 1;
        }
        if(name == "Blog") { // The Blog tab redirects to the loklak blog (http://blog.loklak.net/)
        liItem += ""+name+"
";
        }
        else {
        liItem += ""+name+"
";
        }
        liItem = $(liItem);
        $('#navbar > ul').prepend(liItem);
        });
      },
    error: function (xhr, ajaxOptions, thrownError) {
    },
  });
});
<|endoftext|>


<commit_before>'use strict';

/*global angular, cytoscape*/

angular.module('app').service('graphService', function(tracingService, dataService, $mdDialog) {

    var _this = this;

    var _cy;
    var _data;
    var _mergeDeliveries = false;
    var _nodeSize = 10;
    var _fontSize = 10;

    _this.init = function(container, data) {
        _data = data;

        if (_cy === undefined) {
            _cy = cytoscape({
                container: container,

                elements: {
                    nodes: createNodes(),
                    edges: createEdges()
                },

                layout: {
                    name: 'random'
                },

                style: createStyle(),
                minZoom: 0.01,
                maxZoom: 10,
                wheelSensitivity: 0.5,
            });
        }
        else {
            var json = _cy.json();

            _cy = cytoscape({
                container: container,

                elements: {
                    nodes: createNodes(),
                    edges: createEdges()
                },

                layout: {
                    name: 'preset',
                    positions: function(node) {
                        return json.elements.nodes.find(function(n) {
                            return n.data.id === node.id();
                        }).position;
                    },
                    zoom: json.zoom,
                    pan: json.pan
                },

                style: createStyle(),
                minZoom: json.minZoom,
                maxZoom: json.maxZoom,
                wheelSensitivity: json.wheelSensitivity,
            });
        }

        _cy.panzoom();

        _cy.on('zoom', function(event) {
            _this.setFontSize(_fontSize);
        });
        _cy.on('select', function(event) {
            setSelected(event.cyTarget, true);
        });
        _cy.on('unselect', function(event) {
            setSelected(event.cyTarget, false);
        });
        _cy.on('cxttap', function(event) {
            var element = event.cyTarget;
            var origin = {
                bounds: {
                    top: event.originalEvent.pageY,
                    left: event.originalEvent.pageX,
                    height: 1,
                    width: 1
                }
            };

            if (element.length === undefined) {
                showGraphContextMenu(origin);
            }
            else if (element.group() === 'nodes') {
                showStationContextMenu(element, origin);
            }
            else if (element.group() === 'edges') {
                showDeliveryContextMenu(element, origin);
            }
        });

        tracingService.init(data);
    };

    _this.setMergeDeliveries = function(mergeDeliveries) {
        _mergeDeliveries = mergeDeliveries;
        updateEdges();
    };

    _this.setNodeSize = function(nodeSize) {
        var maxScore = 0;

        for (let s of _data.stations) {
            maxScore = Math.max(maxScore, s.data.score);
        }

        if (maxScore > 0) {
            for (let s of _data.stations) {
                s.data._size = (0.5 + 0.5 * s.data.score / maxScore) * nodeSize;
            }
        }
        else {
            for (let s of _data.stations) {
                s.data._size = nodeSize;
            }
        }

        _nodeSize = nodeSize;
        repaint();
    };

    _this.setFontSize = function(fontSize) {
        _fontSize = fontSize;

        _cy.nodes().style({
            'font-size': Math.max(fontSize / _cy.zoom(), fontSize)
        });
    };

    function repaint() {
        if (_mergeDeliveries) {
            updateEdges();
            _cy.nodes().data('_update', true);
        }
        else {
            _cy.elements().data('_update', true);
        }
    }

    function updateEdges() {
        var edges = createEdges();

        for (let e of edges) {
            e.group = "edges";
        }

        _cy.edges().remove();
        _cy.add(edges);
    }

    function createNodes() {
        var stations = [];

        for (let s of _data.stations) {
            stations.push({
                data: s.data,
                selected: s.data.selected
            });
        }

        return stations;
    }

    function createEdges() {
        var deliveries = [];

        if (_mergeDeliveries) {
            var sourceTargetMap = new Map();

            for (let d of _data.deliveries) {
                let key = d.data.source + '->' + d.data.target;
                let value = sourceTargetMap.get(key);

                sourceTargetMap.set(key, value !== undefined ? value.concat(d) : [d]);
            }

            for (let value of sourceTargetMap.values()) {
                let delivery;

                if (value.length === 1) {
                    delivery = {
                        data: value[0].data,
                        selected: value[0].data.selected,
                    };

                    delivery.data.merged = false;
                }
                else {
                    let source = value[0].data.source;
                    let target = value[0].data.target;

                    delivery = {
                        data: {
                            id: source + '->' + target,
                            source: source,
                            target: target,
                            backward: value.find(function(d) {
                                return d.data.backward === true;
                            }) !== undefined,
                            forward: value.find(function(d) {
                                return d.data.forward === true;
                            }) !== undefined,
                            merged: value.length > 1,
                            contains: value.map(function(d) {
                                return d.data.id;
                            })
                        },
                        selected: value.find(function(d) {
                            return d.data.selected === true;
                        }) !== undefined
                    };
                }

                deliveries.push(delivery);
            }
        }
        else {
            for (let d of _data.deliveries) {
                let delivery = {
                    data: d.data,
                    selected: d.data.selected,
                };

                delivery.data.merged = false;
                deliveries.push(delivery);
            }
        }

        return deliveries;
    }

    function setSelected(element, selected) {
        if (element.data('contains') !== undefined) {
            for (let id of element.data('contains')) {
                tracingService.setSelected(id, selected);
            }
        }
        else {
            tracingService.setSelected(element.id(), selected);
        }
    }

    function createStyle() {
        var sizeFunction = function(node) {
            return node.data('_size') !== undefined ? node.data('_size') : _nodeSize;
        };

        var style = cytoscape.stylesheet()
            .selector('node')
            .style({
                'content': 'data(name)',
                'height': sizeFunction,
                'width': sizeFunction,
                'background-color': '#FFFFFF',
                'border-width': 3,
                'border-color': '#000000',
                'text-valign': 'bottom',
                'text-halign': 'right',
                'color': '#000000'
            })
            .selector('edge')
            .style({
                'target-arrow-shape': 'triangle',
                'width': 6,
                'line-color': '#000000',
                'target-arrow-color': '#FF0000',
                'curve-style': 'bezier'
            })
            .selector('node:selected')
            .style({
                'background-color': '#8080FF',
                'border-width': 6,
                'border-color': '#0000FF',
                'color': '#0000FF'
            })
            .selector('edge:selected')
            .style({
                'width': 12
            });

        var nodeProps = {
            'forward': dataService.COLORS.forward,
            'backward': dataService.COLORS.backward,
            'observed': dataService.COLORS.observed,
            'outbreak': dataService.COLORS.outbreak
        };

        var edgeProps = {
            'forward': dataService.COLORS.forward,
            'backward': dataService.COLORS.backward,
            'observed': dataService.COLORS.observed
        };

        for (let combination of getAllCombination(Object.keys(nodeProps))) {
            var s = [];
            var c1 = [];
            var c2 = [];

            for (let prop of combination) {
                s.push('[?' + prop + ']');
                c1.push(nodeProps[prop]);
                c2.push(dataService.mixColors(nodeProps[prop], [0, 0, 255]));
            }

            style = style.selector('node' + s.join('')).style(createNodeBackground(c1));
            style = style.selector('node:selected' + s.join('')).style(createNodeBackground(c2));
        }

        for (let prop of Object.keys(edgeProps)) {
            style = style.selector('edge[?' + prop + ']').style(createEdgeColor(edgeProps[prop]));
        }

        return style;
    }

    function getAllCombination(values) {
        var n = Math.pow(2, values.length);
        var combinations = [];

        for (let i = 1; i < n; i++) {
            var bits = i.toString(2).split('').reverse().join('');
            var combination = [];

            for (let j = 0; j < values.length; j++) {
                if (bits[j] === '1') {
                    combination.push(values[j]);
                }
            }

            combinations.push(combination);
        }

        combinations.sort(function(c1, c2) {
            return c1.length - c2.length;
        });

        return combinations;
    }

    function createNodeBackground(colors) {
        if (colors.length == 1) {
            return {
                'background-color': dataService.colorToCss(colors[0])
            };
        }

        var style = {};

        for (var i = 0; i < colors.length; i++) {
            style['pie-' + (i + 1) + '-background-color'] = dataService.colorToCss(colors[i]);
            style['pie-' + (i + 1) + '-background-size'] = 100 / colors.length;
        }

        return style;
    }

    function createEdgeColor(color) {
        return {
            'line-color': dataService.colorToCss(color)
        };
    }

    function isDeliveryTracePossible(delivery) {
        if (delivery.data('merged')) {
            $mdDialog
                .show($mdDialog.alert({
                    title: 'Error',
                    textContent: 'Showing Trace of merged delivery is not supported!',
                    ok: 'Close'
                }));

            return false;
        }
        else {
            return true;
        }
    }

    function showGraphContextMenu(origin) {
        $mdDialog.show({
            controller: function($scope) {
                $scope.options = {
                    'Apply Layout': showLayoutMenu,
                    'Zoom to Graph': function() {
                        _cy.fit();
                    },
                    'Clear Trace': function() {
                        tracingService.clearTrace();
                        repaint();
                    }
                };

                $scope.select = function(value) {
                    $mdDialog.hide(value);
                };
            },
            template: `
                <md-dialog aria-label="Graph Menu">
                <md-toolbar><dialog-toolbar title="Graph Menu"></dialog-toolbar></md-toolbar>
                <md-dialog-content><context-menu options="options" on-select="select(value)"></context-menu></md-dialog-content>
                </md-dialog>
            `,
            origin: origin,
            parent: angular.element(document.body),
            clickOutsideToClose: true
        }).then(function(value) {
            value.call();
        });
    }

    function showStationContextMenu(station, origin) {
        $mdDialog.show({
            controller: function($scope) {
                $scope.options = {
                    'Show Forward Trace': function() {
                        tracingService.clearTrace();
                        tracingService.showStationForwardTrace(station.id());
                        repaint();
                    },
                    'Show Backward Trace': function() {
                        tracingService.clearTrace();
                        tracingService.showStationBackwardTrace(station.id());
                        repaint();
                    },
                    'Show Whole Trace': function() {
                        tracingService.clearTrace();
                        tracingService.showStationForwardTrace(station.id());
                        tracingService.showStationBackwardTrace(station.id());
                        repaint();
                    },
                    'Mark/Unmark as Outbreak': function() {
                        tracingService.toggleOutbreakStation(station.id());
                        _this.setNodeSize(_nodeSize);
                    }
                };

                $scope.select = function(value) {
                    $mdDialog.hide(value);
                };
            },
            template: `
                <md-dialog aria-label="Station Menu">
                <md-toolbar><dialog-toolbar title="Station Menu"></dialog-toolbar></md-toolbar>
                <md-dialog-content><context-menu options="options" on-select="select(value)"></context-menu></md-dialog-content>
                </md-dialog>
            `,
            origin: origin,
            parent: angular.element(document.body),
            clickOutsideToClose: true
        }).then(function(value) {
            value.call();
        });
    }

    function showDeliveryContextMenu(delivery, origin) {
        $mdDialog.show({
            controller: function($scope) {
                $scope.options = {
                    'Show Forward Trace': function() {
                        if (isDeliveryTracePossible(delivery)) {
                            tracingService.clearTrace();
                            tracingService.showDeliveryForwardTrace(delivery.id());
                            repaint();
                        }
                    },
                    'Show Backward Trace': function() {
                        if (isDeliveryTracePossible(delivery)) {
                            tracingService.clearTrace();
                            tracingService.showDeliveryBackwardTrace(delivery.id());
                            repaint();
                        }
                    },
                    'Show Whole Trace': function() {
                        if (isDeliveryTracePossible(delivery)) {
                            tracingService.clearTrace();
                            tracingService.showDeliveryForwardTrace(delivery.id());
                            tracingService.showDeliveryBackwardTrace(delivery.id());
                            repaint();
                        }
                    }
                };

                $scope.select = function(value) {
                    $mdDialog.hide(value);
                };
            },
            template: `
                <md-dialog aria-label="Delivery Menu">
                <md-toolbar><dialog-toolbar title="Delivery Menu"></dialog-toolbar></md-toolbar>
                <md-dialog-content><context-menu options="options" on-select="select(value)"></context-menu></md-dialog-content>
                </md-dialog>
            `,
            origin: origin,
            parent: angular.element(document.body),
            clickOutsideToClose: true
        }).then(function(value) {
            value.call();
        });
    }

    function showLayoutMenu() {
        $mdDialog.show({
            controller: function($scope) {
                $scope.select = function(layout) {
                    $mdDialog.hide(layout);
                };
            },
            template: `
                <md-dialog aria-label="Apply Layout">
                <md-toolbar><dialog-toolbar title="Apply Layout"></dialog-toolbar></md-toolbar>
                <md-dialog-content><layout-select on-select="select(layout)"></layout-select></md-dialog-content>
                </md-dialog>
            `,
            parent: angular.element(document.body),
            clickOutsideToClose: true
        }).then(function(layout) {
            _cy.layout(layout);
        });
    }
});
<commit_msg>refactoring<commit_after>'use strict';

/*global angular, cytoscape*/

angular.module('app').service('graphService', function(tracingService, dataService, $mdDialog) {

    var _this = this;

    var _cy;
    var _data;
    var _mergeDeliveries = false;
    var _nodeSize = 10;
    var _fontSize = 10;

    _this.init = function(container, data) {
        _data = data;

        if (_cy === undefined) {
            _cy = cytoscape({
                container: container,

                elements: {
                    nodes: createNodes(),
                    edges: createEdges()
                },

                layout: {
                    name: 'random'
                },

                style: createStyle(),
                minZoom: 0.01,
                maxZoom: 10,
                wheelSensitivity: 0.5,
            });
        }
        else {
            var json = _cy.json();

            _cy = cytoscape({
                container: container,

                elements: {
                    nodes: createNodes(),
                    edges: createEdges()
                },

                layout: {
                    name: 'preset',
                    positions: function(node) {
                        return json.elements.nodes.find(function(n) {
                            return n.data.id === node.id();
                        }).position;
                    },
                    zoom: json.zoom,
                    pan: json.pan
                },

                style: createStyle(),
                minZoom: json.minZoom,
                maxZoom: json.maxZoom,
                wheelSensitivity: json.wheelSensitivity,
            });
        }

        _cy.panzoom();

        _cy.on('zoom', function(event) {
            _this.setFontSize(_fontSize);
        });
        _cy.on('select', function(event) {
            setSelected(event.cyTarget, true);
        });
        _cy.on('unselect', function(event) {
            setSelected(event.cyTarget, false);
        });
        _cy.on('cxttap', function(event) {
            var element = event.cyTarget;
            var origin = {
                bounds: {
                    top: event.originalEvent.pageY,
                    left: event.originalEvent.pageX,
                    height: 1,
                    width: 1
                }
            };

            if (element.length === undefined) {
                showGraphContextMenu(origin);
            }
            else if (element.group() === 'nodes') {
                showStationContextMenu(element, origin);
            }
            else if (element.group() === 'edges') {
                showDeliveryContextMenu(element, origin);
            }
        });

        tracingService.init(data);
    };

    _this.setMergeDeliveries = function(mergeDeliveries) {
        _mergeDeliveries = mergeDeliveries;
        updateEdges();
    };

    _this.setNodeSize = function(nodeSize) {
        var maxScore = 0;

        for (let s of _data.stations) {
            maxScore = Math.max(maxScore, s.data.score);
        }

        if (maxScore > 0) {
            for (let s of _data.stations) {
                s.data._size = (0.5 + 0.5 * s.data.score / maxScore) * nodeSize;
            }
        }
        else {
            for (let s of _data.stations) {
                s.data._size = nodeSize;
            }
        }

        _nodeSize = nodeSize;
        repaint();
    };

    _this.setFontSize = function(fontSize) {
        _fontSize = fontSize;

        _cy.nodes().style({
            'font-size': Math.max(fontSize / _cy.zoom(), fontSize)
        });
    };

    function repaint() {
        if (_mergeDeliveries) {
            updateEdges();
            _cy.nodes().data('_update', true);
        }
        else {
            _cy.elements().data('_update', true);
        }
    }

    function updateEdges() {
        var edges = createEdges();

        for (let e of edges) {
            e.group = "edges";
        }

        _cy.edges().remove();
        _cy.add(edges);
    }

    function createNodes() {
        var stations = [];

        for (let s of _data.stations) {
            stations.push({
                data: s.data,
                selected: s.data.selected
            });
        }

        return stations;
    }

    function createEdges() {
        var deliveries = [];

        if (_mergeDeliveries) {
            var sourceTargetMap = new Map();

            for (let d of _data.deliveries) {
                let key = d.data.source + '->' + d.data.target;
                let value = sourceTargetMap.get(key);

                sourceTargetMap.set(key, value !== undefined ? value.concat(d) : [d]);
            }

            for (let value of sourceTargetMap.values()) {
                let delivery;

                if (value.length === 1) {
                    delivery = {
                        data: value[0].data,
                        selected: value[0].data.selected,
                    };

                    delivery.data.merged = false;
                }
                else {
                    let source = value[0].data.source;
                    let target = value[0].data.target;

                    delivery = {
                        data: {
                            id: source + '->' + target,
                            source: source,
                            target: target,
                            backward: value.find(function(d) {
                                return d.data.backward === true;
                            }) !== undefined,
                            forward: value.find(function(d) {
                                return d.data.forward === true;
                            }) !== undefined,
                            merged: value.length > 1,
                            contains: value.map(function(d) {
                                return d.data.id;
                            })
                        },
                        selected: value.find(function(d) {
                            return d.data.selected === true;
                        }) !== undefined
                    };
                }

                deliveries.push(delivery);
            }
        }
        else {
            for (let d of _data.deliveries) {
                let delivery = {
                    data: d.data,
                    selected: d.data.selected,
                };

                delivery.data.merged = false;
                deliveries.push(delivery);
            }
        }

        return deliveries;
    }

    function setSelected(element, selected) {
        if (element.data('contains') !== undefined) {
            for (let id of element.data('contains')) {
                tracingService.setSelected(id, selected);
            }
        }
        else {
            tracingService.setSelected(element.id(), selected);
        }
    }

    function createStyle() {
        var sizeFunction = function(node) {
            return node.data('_size') !== undefined ? node.data('_size') : _nodeSize;
        };

        var style = cytoscape.stylesheet()
            .selector('node')
            .style({
                'content': 'data(name)',
                'height': sizeFunction,
                'width': sizeFunction,
                'background-color': '#FFFFFF',
                'border-width': 3,
                'border-color': '#000000',
                'text-valign': 'bottom',
                'text-halign': 'right',
                'color': '#000000'
            })
            .selector('edge')
            .style({
                'target-arrow-shape': 'triangle',
                'width': 6,
                'line-color': '#000000',
                'target-arrow-color': '#FF0000',
                'curve-style': 'bezier'
            })
            .selector('node:selected')
            .style({
                'background-color': '#8080FF',
                'border-width': 6,
                'border-color': '#0000FF',
                'color': '#0000FF'
            })
            .selector('edge:selected')
            .style({
                'width': 12
            });

        var nodeProps = {
            'forward': dataService.COLORS.forward,
            'backward': dataService.COLORS.backward,
            'observed': dataService.COLORS.observed,
            'outbreak': dataService.COLORS.outbreak
        };

        var edgeProps = {
            'forward': dataService.COLORS.forward,
            'backward': dataService.COLORS.backward,
            'observed': dataService.COLORS.observed
        };

        for (let combination of getAllCombination(Object.keys(nodeProps))) {
            var s = [];
            var c1 = [];
            var c2 = [];

            for (let prop of combination) {
                s.push('[?' + prop + ']');
                c1.push(nodeProps[prop]);
                c2.push(dataService.mixColors(nodeProps[prop], [0, 0, 255]));
            }

            style = style.selector('node' + s.join('')).style(createNodeBackground(c1));
            style = style.selector('node:selected' + s.join('')).style(createNodeBackground(c2));
        }

        for (let prop of Object.keys(edgeProps)) {
            style = style.selector('edge[?' + prop + ']').style(createEdgeColor(edgeProps[prop]));
        }

        return style;
    }

    function getAllCombination(values) {
        var n = Math.pow(2, values.length);
        var combinations = [];

        for (let i = 1; i < n; i++) {
            var bits = i.toString(2).split('').reverse().join('');
            var combination = [];

            for (let j = 0; j < values.length; j++) {
                if (bits[j] === '1') {
                    combination.push(values[j]);
                }
            }

            combinations.push(combination);
        }

        combinations.sort(function(c1, c2) {
            return c1.length - c2.length;
        });

        return combinations;
    }

    function createNodeBackground(colors) {
        if (colors.length == 1) {
            return {
                'background-color': dataService.colorToCss(colors[0])
            };
        }

        var style = {};

        for (var i = 0; i < colors.length; i++) {
            style['pie-' + (i + 1) + '-background-color'] = dataService.colorToCss(colors[i]);
            style['pie-' + (i + 1) + '-background-size'] = 100 / colors.length;
        }

        return style;
    }

    function createEdgeColor(color) {
        return {
            'line-color': dataService.colorToCss(color)
        };
    }

    function isDeliveryTracePossible(delivery) {
        if (delivery.data('merged')) {
            $mdDialog
                .show($mdDialog.alert({
                    title: 'Error',
                    textContent: 'Showing Trace of merged delivery is not supported!',
                    ok: 'Close'
                }));

            return false;
        }
        else {
            return true;
        }
    }

    function showGraphContextMenu(origin) {
        showContextMenu("Graph Menu", {
            'Apply Layout': showLayoutMenu,
            'Zoom to Graph': function() {
                _cy.fit();
            },
            'Clear Trace': function() {
                tracingService.clearTrace();
                repaint();
            }
        }, origin);
    }

    function showStationContextMenu(station, origin) {
        showContextMenu("Station Menu", {
            'Show Forward Trace': function() {
                tracingService.clearTrace();
                tracingService.showStationForwardTrace(station.id());
                repaint();
            },
            'Show Backward Trace': function() {
                tracingService.clearTrace();
                tracingService.showStationBackwardTrace(station.id());
                repaint();
            },
            'Show Whole Trace': function() {
                tracingService.clearTrace();
                tracingService.showStationForwardTrace(station.id());
                tracingService.showStationBackwardTrace(station.id());
                repaint();
            },
            'Mark/Unmark as Outbreak': function() {
                tracingService.toggleOutbreakStation(station.id());
                _this.setNodeSize(_nodeSize);
            }
        }, origin);
    }

    function showDeliveryContextMenu(delivery, origin) {
        showContextMenu('Delivery Menu', {
            'Show Forward Trace': function() {
                if (isDeliveryTracePossible(delivery)) {
                    tracingService.clearTrace();
                    tracingService.showDeliveryForwardTrace(delivery.id());
                    repaint();
                }
            },
            'Show Backward Trace': function() {
                if (isDeliveryTracePossible(delivery)) {
                    tracingService.clearTrace();
                    tracingService.showDeliveryBackwardTrace(delivery.id());
                    repaint();
                }
            },
            'Show Whole Trace': function() {
                if (isDeliveryTracePossible(delivery)) {
                    tracingService.clearTrace();
                    tracingService.showDeliveryForwardTrace(delivery.id());
                    tracingService.showDeliveryBackwardTrace(delivery.id());
                    repaint();
                }
            }
        }, origin);
    }

    function showContextMenu(title, options, origin) {
        $mdDialog.show({
            controller: function($scope) {
                $scope.title = title;
                $scope.options = options;

                $scope.select = function(value) {
                    $mdDialog.hide(value);
                };
            },
            template: `
                <md-dialog aria-label="{{title}}">
                <md-toolbar><dialog-toolbar title="{{title}}"></dialog-toolbar></md-toolbar>
                <md-dialog-content><context-menu options="options" on-select="select(value)"></context-menu></md-dialog-content>
                </md-dialog>
            `,
            origin: origin,
            parent: angular.element(document.body),
            clickOutsideToClose: true
        }).then(function(value) {
            value.call();
        });
    }

    function showLayoutMenu() {
        $mdDialog.show({
            controller: function($scope) {
                $scope.select = function(layout) {
                    $mdDialog.hide(layout);
                };
            },
            template: `
                <md-dialog aria-label="Apply Layout">
                <md-toolbar><dialog-toolbar title="Apply Layout"></dialog-toolbar></md-toolbar>
                <md-dialog-content><layout-select on-select="select(layout)"></layout-select></md-dialog-content>
                </md-dialog>
            `,
            parent: angular.element(document.body),
            clickOutsideToClose: true
        }).then(function(layout) {
            _cy.layout(layout);
        });
    }
});
<|endoftext|>


<commit_before>/**
 * This file is part of Shoop.
 *
 * Copyright (c) 2012-2015, Shoop Ltd. All rights reserved.
 *
 * This source code is licensed under the AGPLv3 license found in the
 * LICENSE file in the root directory of this source tree.
 */
const style = require("style!css!autoprefixer!less!./script-editor.less");  // eslint-disable-line no-unused-vars
const cx = require("classnames");
const Messages = window.Messages;

var settings = {};
const names = {};
const infos = {};
var controller = null;
const optionLists = {};

function showSuccessAndError(data) {
    if (data.error) {
        Messages.enqueue({
            text: _.isString(data.error) ? data.error : "An error occurred.",
            tags: "error"
        });
    }
    if (data.success) {
        Messages.enqueue({
            text: _.isString(data.success) ? data.success : "Success.",
            tags: "success"
        });
    }
}

function apiRequest(command, data, options) {
    const request = _.extend({}, {"command": command}, data || {});
    const req = m.request(_.extend({
        method: "POST",
        url: settings.apiUrl,
        data: request,
        config: function(xhr) {
            xhr.setRequestHeader("X-CSRFToken", window.ShoopAdminConfig.csrf);
        }
    }, options));
    req.then(function(response) {
        showSuccessAndError(response);
    }, function() {
        Messages.enqueue({text: "An unspecified error occurred.", tags: "error"});
    });
    return req;
}

function Controller() {
    const ctrl = this;
    ctrl.steps = m.prop([]);
    ctrl.currentItem = m.prop(null);
    ctrl.newStepItemModalInfo = m.prop(null);

    apiRequest("getData").then(function(data) {
        ctrl.steps(data.steps);
    });

    ctrl.removeStepItem = function(step, itemType, item) {
        const listName = itemType + "s";
        step[listName] = _.reject(step[listName], function(i) {
            return i === item;
        });
        if(ctrl.currentItem() === item) {
            ctrl.activateStepItem(null, null, null);
        }
    };

    ctrl.addStepItem = function(step, itemType, identifier, activateForEdit) {
        const item = {"identifier": identifier};
        const listName = itemType + "s";
        step[listName].push(item);
        if (activateForEdit) {
            ctrl.activateStepItem(step, itemType, item);
        }
    };
    ctrl.setStepItemEditorState = function(state) {
        if(!!state) {
            document.getElementById("step-item-wrapper").style.display = "block";
        } else {
            document.getElementById("step-item-wrapper").style.display = "none";
            document.getElementById("step-item-frame").src = "about:blank";
        }
    };
    ctrl.activateStepItem = function(step, itemType, item) {
        if (step && item) {
            ctrl.currentItem(item);
            const frm = _.extend(document.createElement("form"), {
                target: "step-item-frame",
                method: "POST",
                action: settings.itemEditorUrl
            });
            frm.appendChild(_.extend(document.createElement("input"), {
                name: "init_data",
                type: "hidden",
                value: JSON.stringify({
                    eventIdentifier: settings.eventIdentifier,
                    itemType: itemType,
                    data: item
                })
            }));
            document.body.appendChild(frm);
            frm.submit();
            ctrl.setStepItemEditorState(true);
        } else {
            ctrl.currentItem(null);
            ctrl.setStepItemEditorState(false);
        }
    };
    ctrl.receiveItemEditData = function(data) {
        const currentItem = ctrl.currentItem();
        if(!currentItem) {
            alert("Unexpected edit data received.");
            return;
        }
        m.startComputation();
        ctrl.currentItem(_.extend(currentItem, data));
        m.endComputation();
    };
    ctrl.saveState = function() {
        apiRequest("saveData", {
            steps: ctrl.steps()
        });
        // TODO: Handle errors here?
    };
    ctrl.deleteStep = function(step) {
        ctrl.steps(_.reject(ctrl.steps(), function(s) {
            return s === step;
        }));
    };
    ctrl.addNewStep = function() {
        const step = {
            actions: [],
            conditions: [],
            enabled: true,
            next: "continue",
            condOp: "and"
        };
        const steps = ctrl.steps();
        steps.push(step);
        ctrl.steps(steps);
    };
    ctrl.moveStep = function(step, delta) {
        const steps = ctrl.steps();
        const oldIndex = _.indexOf(steps, step);
        if (oldIndex === -1) {
            return false;
        }
        const newIndex = oldIndex + delta;
        steps.splice(newIndex, 0, steps.splice(oldIndex, 1)[0]);
        ctrl.steps(steps);
    };
    ctrl.promptForNewStepItem = function(step, itemType) {
        ctrl.newStepItemModalInfo({
            step: step,
            itemType: itemType,
            title: "Add new " + itemType
        });
    };
    ctrl.closeNewStepItemModal = function() {
        ctrl.newStepItemModalInfo(null);
    };
    ctrl.createNewStepItemFromModal = function(identifier) {
        const info = ctrl.newStepItemModalInfo();
        ctrl.closeNewStepItemModal();
        if (info === null) {
            return;
        }
        ctrl.addStepItem(info.step, info.itemType, identifier, true);
    };
}

function workflowItemList(ctrl, step, itemType) {
    const listName = itemType + "s";
    const nameMap = names[itemType];
    const items = step[listName];
    const list = m("ul.action-list", items.map(function(item) {
        const name = nameMap[item.identifier] || item.identifier;
        var tag = "li";
        const current = (ctrl.currentItem() === item);
        if(current) {
            tag += ".current";
        }
        return m(tag,
            [
                m("a", {
                    href: "#",
                    onclick: (!current ? _.partial(ctrl.activateStepItem, step, itemType, item) : null)
                }, name),
                " ",
                m("a.delete", {
                    href: "#", onclick: function() {
                        if (!confirm("Delete this item?\nThis can not be undone.")) {
                            return;
                        }
                        ctrl.removeStepItem(step, itemType, item);
                    }
                }, m("i.fa.fa-trash"))
            ]
        );
    }));
    return m("div", [
        list,
        m("div.action-new", [m("a.btn.btn-xs.btn-primary", {
            href: "#",
            onclick: _.partial(ctrl.promptForNewStepItem, step, itemType)
        }, m("i.fa.fa-plus"), " New " + itemType)])
    ]);
}

function stepTableRows(ctrl) {
    return _.map(ctrl.steps(), function(step, index) {
        const condOpSelect = m("select", {
            value: step.cond_op,
            onchange: m.withAttr("value", function(value) {
                step.cond_op = value;  // eslint-disable-line camelcase
            })
        }, optionLists.condOps);
        const stepNextSelect = m("select", {
            value: step.next,
            onchange: m.withAttr("value", function(value) {
                step.next = value;
            })
        }, optionLists.stepNexts);

        return m("div", {
            className: cx("step", {disabled: !step.enabled}),
            key: step.id
        }, [
            m("div.step-buttons", [
                (index > 0 ? m("a", {
                    href: "#",
                    title: "Move Up",
                    onclick: _.partial(ctrl.moveStep, step, -1)
                }, m("i.fa.fa-caret-up")) : null),
                (index < ctrl.steps().length - 1 ? m("a", {
                    href: "#",
                    title: "Move Down",
                    onclick: _.partial(ctrl.moveStep, step, +1)
                }, m("i.fa.fa-caret-down")) : null),
                (step.enabled ?
                    m("a", {
                        href: "#", title: "Disable", onclick: function() {
                            step.enabled = false;
                        }
                    }, m("i.fa.fa-ban")) :
                    m("a", {
                        href: "#", title: "Enable", onclick: function() {
                            step.enabled = true;
                        }
                    }, m("i.fa.fa-check-circle"))
                ),
                m("a", {
                    href: "#", title: "Delete", onclick: function() {
                        if (confirm("Are you sure you wish to delete this step?")) {
                            ctrl.deleteStep(step);
                        }
                    }
                }, m("i.fa.fa-trash"))
            ]),
            m("div.step-conds", [
                m("span.hint", "If ", condOpSelect, " of these conditions hold..."),
                workflowItemList(ctrl, step, "condition")
            ]),
            m("div.step-actions", [
                m("span.hint", "then execute these actions..."),
                workflowItemList(ctrl, step, "action")
            ]),
            m("div.step-next", [
                m("span.hint", "and then..."),
                stepNextSelect
            ])
        ]);
    });
}

function renderNewStepItemModal(ctrl, modalInfo) {
    return m("div.new-step-item-modal-overlay", {onclick: ctrl.closeNewStepItemModal}, [
        m("div.new-step-item-modal", [
            m("div.title", modalInfo.title),
            m("div.item-options", _.map(_.sortBy(_.values(infos[modalInfo.itemType]), "name"), function(item) {
                return m("div.item-option", {onclick: _.partial(ctrl.createNewStepItemFromModal, item.identifier)}, [
                    m("div.item-name", item.name),
                    (item.description ? m("div.item-description", item.description) : null)
                ]);
            }))
        ])
    ]);
}

function view(ctrl) {
    var modal = null, modalInfo = null;
    if ((modalInfo = ctrl.newStepItemModalInfo()) !== null) {
        modal = renderNewStepItemModal(ctrl, modalInfo);
    }
    return m("div.step-list-wrapper", [
        m("div.steps", [
            stepTableRows(ctrl),
            m("hr.script-separator"),
            m("a.new-step-link.btn.btn-info.btn-sm", {href: "#", onclick: ctrl.addNewStep}, m("i.fa.fa-plus"), " New step")
        ]),
        modal
    ]);
}

function generateItemOptions(nameMap) {
    return _.sortBy(_.map(nameMap, function(name, value) {
        return m("option", {value: value}, name);
    }), function(o) {
        return o.children[0].toLowerCase();
    });
}

function itemInfosToNameMap(itemInfos) {
    return _(itemInfos).map((itemInfo, identifier) => [identifier, itemInfo.name]).zipObject().value();
}

function init(iSettings) {
    settings = _.extend({}, iSettings);
    infos.condition = settings.conditionInfos;
    infos.action = settings.actionInfos;
    names.condition = itemInfosToNameMap(infos.condition);
    names.action = itemInfosToNameMap(infos.action);
    optionLists.condOps = generateItemOptions(settings.condOps);
    optionLists.stepNexts = generateItemOptions(settings.stepNexts);

    controller = m.mount(document.getElementById("step-table-container"), {
        controller: Controller,
        view: view
    });
    window.addEventListener("message", function(event) {
        if(event.data.new_data) {
            controller.receiveItemEditData(event.data.new_data);
        }
    }, false);
}

function save() {
    controller.saveState();
}

module.exports.init = init;
module.exports.save = save;
module.exports.hideEditModal = function() {
    if(controller) {
        m.startComputation();
        controller.setStepItemEditorState(false);
        controller.activateStepItem(null);  // Deactivate the modal once data is received
        m.endComputation();
    }
};
<commit_msg>Fix Eslint complaints in shoop/notify<commit_after>/**
 * This file is part of Shoop.
 *
 * Copyright (c) 2012-2015, Shoop Ltd. All rights reserved.
 *
 * This source code is licensed under the AGPLv3 license found in the
 * LICENSE file in the root directory of this source tree.
 */
const style = require("style!css!autoprefixer!less!./script-editor.less");  // eslint-disable-line no-unused-vars
const cx = require("classnames");
const Messages = window.Messages;

var settings = {};
const names = {};
const infos = {};
var controller = null;
const optionLists = {};

function showSuccessAndError(data) {
    if (data.error) {
        Messages.enqueue({
            text: _.isString(data.error) ? data.error : "An error occurred.",
            tags: "error"
        });
    }
    if (data.success) {
        Messages.enqueue({
            text: _.isString(data.success) ? data.success : "Success.",
            tags: "success"
        });
    }
}

function apiRequest(command, data, options) {
    const request = _.extend({}, {"command": command}, data || {});
    const req = m.request(_.extend({
        method: "POST",
        url: settings.apiUrl,
        data: request,
        config: function(xhr) {
            xhr.setRequestHeader("X-CSRFToken", window.ShoopAdminConfig.csrf);
        }
    }, options));
    req.then(function(response) {
        showSuccessAndError(response);
    }, function() {
        Messages.enqueue({text: "An unspecified error occurred.", tags: "error"});
    });
    return req;
}

function Controller() {
    const ctrl = this;
    ctrl.steps = m.prop([]);
    ctrl.currentItem = m.prop(null);
    ctrl.newStepItemModalInfo = m.prop(null);

    apiRequest("getData").then(function(data) {
        ctrl.steps(data.steps);
    });

    ctrl.removeStepItem = function(step, itemType, item) {
        const listName = itemType + "s";
        step[listName] = _.reject(step[listName], function(i) {
            return i === item;
        });
        if(ctrl.currentItem() === item) {
            ctrl.activateStepItem(null, null, null);
        }
    };

    ctrl.addStepItem = function(step, itemType, identifier, activateForEdit) {
        const item = {"identifier": identifier};
        const listName = itemType + "s";
        step[listName].push(item);
        if (activateForEdit) {
            ctrl.activateStepItem(step, itemType, item);
        }
    };
    ctrl.setStepItemEditorState = function(state) {
        if(state) {
            document.getElementById("step-item-wrapper").style.display = "block";
        } else {
            document.getElementById("step-item-wrapper").style.display = "none";
            document.getElementById("step-item-frame").src = "about:blank";
        }
    };
    ctrl.activateStepItem = function(step, itemType, item) {
        if (step && item) {
            ctrl.currentItem(item);
            const frm = _.extend(document.createElement("form"), {
                target: "step-item-frame",
                method: "POST",
                action: settings.itemEditorUrl
            });
            frm.appendChild(_.extend(document.createElement("input"), {
                name: "init_data",
                type: "hidden",
                value: JSON.stringify({
                    eventIdentifier: settings.eventIdentifier,
                    itemType: itemType,
                    data: item
                })
            }));
            document.body.appendChild(frm);
            frm.submit();
            ctrl.setStepItemEditorState(true);
        } else {
            ctrl.currentItem(null);
            ctrl.setStepItemEditorState(false);
        }
    };
    ctrl.receiveItemEditData = function(data) {
        const currentItem = ctrl.currentItem();
        if(!currentItem) {
            alert("Unexpected edit data received.");
            return;
        }
        m.startComputation();
        ctrl.currentItem(_.extend(currentItem, data));
        m.endComputation();
    };
    ctrl.saveState = function() {
        apiRequest("saveData", {
            steps: ctrl.steps()
        });
        // TODO: Handle errors here?
    };
    ctrl.deleteStep = function(step) {
        ctrl.steps(_.reject(ctrl.steps(), function(s) {
            return s === step;
        }));
    };
    ctrl.addNewStep = function() {
        const step = {
            actions: [],
            conditions: [],
            enabled: true,
            next: "continue",
            condOp: "and"
        };
        const steps = ctrl.steps();
        steps.push(step);
        ctrl.steps(steps);
    };
    ctrl.moveStep = function(step, delta) {
        const steps = ctrl.steps();
        const oldIndex = _.indexOf(steps, step);
        if (oldIndex === -1) {
            return false;
        }
        const newIndex = oldIndex + delta;
        steps.splice(newIndex, 0, steps.splice(oldIndex, 1)[0]);
        ctrl.steps(steps);
    };
    ctrl.promptForNewStepItem = function(step, itemType) {
        ctrl.newStepItemModalInfo({
            step: step,
            itemType: itemType,
            title: "Add new " + itemType
        });
    };
    ctrl.closeNewStepItemModal = function() {
        ctrl.newStepItemModalInfo(null);
    };
    ctrl.createNewStepItemFromModal = function(identifier) {
        const info = ctrl.newStepItemModalInfo();
        ctrl.closeNewStepItemModal();
        if (info === null) {
            return;
        }
        ctrl.addStepItem(info.step, info.itemType, identifier, true);
    };
}

function workflowItemList(ctrl, step, itemType) {
    const listName = itemType + "s";
    const nameMap = names[itemType];
    const items = step[listName];
    const list = m("ul.action-list", items.map(function(item) {
        const name = nameMap[item.identifier] || item.identifier;
        var tag = "li";
        const current = (ctrl.currentItem() === item);
        if(current) {
            tag += ".current";
        }
        return m(tag,
            [
                m("a", {
                    href: "#",
                    onclick: (!current ? _.partial(ctrl.activateStepItem, step, itemType, item) : null)
                }, name),
                " ",
                m("a.delete", {
                    href: "#", onclick: function() {
                        if (!confirm("Delete this item?\nThis can not be undone.")) {
                            return;
                        }
                        ctrl.removeStepItem(step, itemType, item);
                    }
                }, m("i.fa.fa-trash"))
            ]
        );
    }));
    return m("div", [
        list,
        m("div.action-new", [m("a.btn.btn-xs.btn-primary", {
            href: "#",
            onclick: _.partial(ctrl.promptForNewStepItem, step, itemType)
        }, m("i.fa.fa-plus"), " New " + itemType)])
    ]);
}

function stepTableRows(ctrl) {
    return _.map(ctrl.steps(), function(step, index) {
        const condOpSelect = m("select", {
            value: step.cond_op,
            onchange: m.withAttr("value", function(value) {
                step.cond_op = value;  // eslint-disable-line camelcase
            })
        }, optionLists.condOps);
        const stepNextSelect = m("select", {
            value: step.next,
            onchange: m.withAttr("value", function(value) {
                step.next = value;
            })
        }, optionLists.stepNexts);

        return m("div", {
            className: cx("step", {disabled: !step.enabled}),
            key: step.id
        }, [
            m("div.step-buttons", [
                (index > 0 ? m("a", {
                    href: "#",
                    title: "Move Up",
                    onclick: _.partial(ctrl.moveStep, step, -1)
                }, m("i.fa.fa-caret-up")) : null),
                (index < ctrl.steps().length - 1 ? m("a", {
                    href: "#",
                    title: "Move Down",
                    onclick: _.partial(ctrl.moveStep, step, +1)
                }, m("i.fa.fa-caret-down")) : null),
                (step.enabled ?
                    m("a", {
                        href: "#", title: "Disable", onclick: function() {
                            step.enabled = false;
                        }
                    }, m("i.fa.fa-ban")) :
                    m("a", {
                        href: "#", title: "Enable", onclick: function() {
                            step.enabled = true;
                        }
                    }, m("i.fa.fa-check-circle"))
                ),
                m("a", {
                    href: "#", title: "Delete", onclick: function() {
                        if (confirm("Are you sure you wish to delete this step?")) {
                            ctrl.deleteStep(step);
                        }
                    }
                }, m("i.fa.fa-trash"))
            ]),
            m("div.step-conds", [
                m("span.hint", "If ", condOpSelect, " of these conditions hold..."),
                workflowItemList(ctrl, step, "condition")
            ]),
            m("div.step-actions", [
                m("span.hint", "then execute these actions..."),
                workflowItemList(ctrl, step, "action")
            ]),
            m("div.step-next", [
                m("span.hint", "and then..."),
                stepNextSelect
            ])
        ]);
    });
}

function renderNewStepItemModal(ctrl, modalInfo) {
    return m("div.new-step-item-modal-overlay", {onclick: ctrl.closeNewStepItemModal}, [
        m("div.new-step-item-modal", [
            m("div.title", modalInfo.title),
            m("div.item-options", _.map(_.sortBy(_.values(infos[modalInfo.itemType]), "name"), function(item) {
                return m("div.item-option", {onclick: _.partial(ctrl.createNewStepItemFromModal, item.identifier)}, [
                    m("div.item-name", item.name),
                    (item.description ? m("div.item-description", item.description) : null)
                ]);
            }))
        ])
    ]);
}

function view(ctrl) {
    var modal = null, modalInfo = null;
    if ((modalInfo = ctrl.newStepItemModalInfo()) !== null) {
        modal = renderNewStepItemModal(ctrl, modalInfo);
    }
    return m("div.step-list-wrapper", [
        m("div.steps", [
            stepTableRows(ctrl),
            m("hr.script-separator"),
            m("a.new-step-link.btn.btn-info.btn-sm", {href: "#", onclick: ctrl.addNewStep}, m("i.fa.fa-plus"), " New step")
        ]),
        modal
    ]);
}

function generateItemOptions(nameMap) {
    return _.sortBy(_.map(nameMap, function(name, value) {
        return m("option", {value: value}, name);
    }), function(o) {
        return o.children[0].toLowerCase();
    });
}

function itemInfosToNameMap(itemInfos) {
    return _(itemInfos).map((itemInfo, identifier) => [identifier, itemInfo.name]).zipObject().value();
}

function init(iSettings) {
    settings = _.extend({}, iSettings);
    infos.condition = settings.conditionInfos;
    infos.action = settings.actionInfos;
    names.condition = itemInfosToNameMap(infos.condition);
    names.action = itemInfosToNameMap(infos.action);
    optionLists.condOps = generateItemOptions(settings.condOps);
    optionLists.stepNexts = generateItemOptions(settings.stepNexts);

    controller = m.mount(document.getElementById("step-table-container"), {
        controller: Controller,
        view: view
    });
    window.addEventListener("message", function(event) {
        if(event.data.new_data) {
            controller.receiveItemEditData(event.data.new_data);
        }
    }, false);
}

function save() {
    controller.saveState();
}

module.exports.init = init;
module.exports.save = save;
module.exports.hideEditModal = function() {
    if(controller) {
        m.startComputation();
        controller.setStepItemEditorState(false);
        controller.activateStepItem(null);  // Deactivate the modal once data is received
        m.endComputation();
    }
};
<|endoftext|>


<commit_before>import CanvasClass from './CanvasClass';
import TextOverlay from './TextOverlay';
import mapboxgl from 'mapbox-gl';

/**
 * Location Lookup class - Binds Google places to text box and binds google places to map
 */
export default class LocationLookup {

    constructor(textOverlay, mapBox) {
        this.textOverlay = textOverlay;
        this.mapBox = mapBox;
    }

    locationLookupLoaded() {
        this.setupFields();
    }

    setupFields() {
        let addressField = document.getElementById('pac-input');
        var options = {
            types: ['(cities)']
        };
        let autoComplete = new google.maps.places.Autocomplete(addressField, options);
        console.log(this.autoComplete);
        let that = this;
        autoComplete.addListener('place_changed', () => {
            console.log(autoComplete);
            that.textOverlay.location = this.textOverlay.formatCoord(autoComplete.getPlace().geometry.location.lat(),
                autoComplete.getPlace().geometry.location.lng())
            that.mapBox.map.setCenter([autoComplete.getPlace().geometry.location.lng(),
                autoComplete.getPlace().geometry.location.lat()
            ]);
        });
    }
}<commit_msg>Remove location lookup console statements<commit_after>import CanvasClass from './CanvasClass';
import TextOverlay from './TextOverlay';
import mapboxgl from 'mapbox-gl';

/**
 * Location Lookup class - Binds Google places to text box and binds google places to map
 */
export default class LocationLookup {

    constructor(textOverlay, mapBox) {
        this.textOverlay = textOverlay;
        this.mapBox = mapBox;
    }

    locationLookupLoaded() {
        this.setupFields();
    }

    setupFields() {
        let addressField = document.getElementById('pac-input');
        var options = {
            types: ['(cities)']
        };
        let autoComplete = new google.maps.places.Autocomplete(addressField, options);
        let that = this;
        autoComplete.addListener('place_changed', () => {
            that.textOverlay.location = this.textOverlay.formatCoord(autoComplete.getPlace().geometry.location.lat(),
                autoComplete.getPlace().geometry.location.lng())
            that.mapBox.map.setCenter([autoComplete.getPlace().geometry.location.lng(),
                autoComplete.getPlace().geometry.location.lat()
            ]);
        });
    }
}<|endoftext|>


<commit_before>/**
 * Cleverfocus plugin
 * Set the focus to the desired form element when text is entered without a focus
 * Copyright (c) 2012 Mikhail Andreev (http://adw0rd.com/)
 */

if (!Array.indexOf) {
    // Implementation indexOf for IE
    Array.prototype.indexOf = function(obj) {
        for (var i=0; i<this.length; i++) {
            if (this[i] == obj){
                return i;
            }
        }
        return -1;
    }
}

(function($) {
    $.fn.cleverfocus = function(options) {
        var defaults = {
            keypress_limit: 0
        }
        var options = $.extend(defaults, options);
        var keypress_words = [];
        var current_position_in_keypress_words = 0;
        var has_focus = false;
        var input = $(this);

        // Special buttons
        var BACKSPACE = 8;
        var DELETE = 46;
        var END = 35;
        var HOME = 36;
        var LEFT = 37;
        var RIGHT = 39;

        $('input, textarea, button, select').live('focusin', function() {
            has_focus = true;
        }).live('focusout', function() {
            has_focus = false;
        });

        $(document).keypress(function(button) {
            if (!has_focus) {
                if ([BACKSPACE, DELETE, END, HOME, LEFT, RIGHT].indexOf(button.keyCode) != -1) {
                    // Handling special buttons
                    if (button.keyCode == BACKSPACE) {
                        current_position_in_keypress_words--;
                        keypress_words.splice(current_position_in_keypress_words, 1);
                    }
                    if (current_position_in_keypress_words && button.keyCode == DELETE) {
                        keypress_words.splice(current_position_in_keypress_words, 1);
                    }
                    if (button.keyCode == END) {
                        current_position_in_keypress_words = keypress_words.length;
                    }
                    if (button.keyCode == HOME) {
                        current_position_in_keypress_words = 0;
                    }
                    if (button.keyCode == LEFT && current_position_in_keypress_words != 0) {
                        current_position_in_keypress_words--;
                    }
                    if (button.keyCode == RIGHT && current_position_in_keypress_words != keypress_words.length) {
                        current_position_in_keypress_words++;
                    }
                } else if (button.which != 0 && !button.ctrlKey && !button.altKey) {
                    // Write a symbol
                    keypress_words.splice(current_position_in_keypress_words, 0, String.fromCharCode(button.which));
                    current_position_in_keypress_words++;
                }
                if (keypress_words.length >= options.keypress_limit) {
                    // Put a symbols to specified input
                    if (jQuery.browser.webkit || jQuery.browser.opera || jQuery.browser.msie) {
                        keypress_words.pop();
                    }
                    input.focus().val(input.val() + keypress_words.join(''));
                    keypress_words = [];
                }
                // console.log(current_position_in_keypress_words, keypress_words)
            }
        });
    }
}(jQuery));<commit_msg>Added compatibility with Chronium arrows (via keydown)<commit_after>/**
 * Cleverfocus plugin
 * Set the focus to the desired form element when text is entered without a focus
 * Copyright (c) 2012 Mikhail Andreev (http://adw0rd.com/)
 */

if (!Array.indexOf) {
    // Implementation indexOf for IE
    Array.prototype.indexOf = function(obj) {
        for (var i=0; i<this.length; i++) {
            if (this[i] == obj){
                return i;
            }
        }
        return -1;
    }
}

(function($) {
    $.fn.cleverfocus = function(options) {
        var defaults = {
            keypress_limit: 0
        }
        var options = $.extend(defaults, options);
        var keypress_words = [];
        var current_position_in_keypress_words = 0;
        var has_focus = false;
        var input = $(this);

        // Special buttons
        var BACKSPACE = 8;
        var DELETE = 46;
        var END = 35;
        var HOME = 36;
        var LEFT = 37;
        var RIGHT = 39;

        $('input, textarea, button, select').live('focusin', function() {
            has_focus = true;
        }).live('focusout', function() {
            has_focus = false;
        });

        $(document).keydown(function(button) {
            if (!has_focus) {
                if ([BACKSPACE, DELETE, END, HOME, LEFT, RIGHT].indexOf(button.keyCode) != -1) {
                    // Handling special buttons
                    if (button.keyCode == BACKSPACE) {
                        current_position_in_keypress_words--;
                        keypress_words.splice(current_position_in_keypress_words, 1);
                    }
                    if (current_position_in_keypress_words && button.keyCode == DELETE) {
                        keypress_words.splice(current_position_in_keypress_words, 1);
                    }
                    if (button.keyCode == END) {
                        current_position_in_keypress_words = keypress_words.length;
                    }
                    if (button.keyCode == HOME) {
                        current_position_in_keypress_words = 0;
                    }
                    if (button.keyCode == LEFT && current_position_in_keypress_words != 0) {
                        current_position_in_keypress_words--;
                    }
                    if (button.keyCode == RIGHT && current_position_in_keypress_words != keypress_words.length) {
                        current_position_in_keypress_words++;
                    }
                }
            }
        });
        $(document).keypress(function(button) {
            if (!has_focus) {
                if (button.which != 0 && !button.ctrlKey && !button.altKey) {
                    // Write a symbol
                    keypress_words.splice(current_position_in_keypress_words, 0, String.fromCharCode(button.which));
                    current_position_in_keypress_words++;
                }
                if (keypress_words.length >= options.keypress_limit) {
                    // Put a symbols to specified input
                    if (jQuery.browser.webkit || jQuery.browser.opera || jQuery.browser.msie) {
                        keypress_words.pop();
                    }
                    input.focus().val(input.val() + keypress_words.join(''));
                    keypress_words = [];
                }
                // console.log(current_position_in_keypress_words, keypress_words)
            }
        });
    }
}(jQuery));<|endoftext|>


<commit_before>(function (global) {
    var vow = ym.vow,
        configPromise = requireModulesFromConfig(),
        getParamsPromise = requireModulesFromParams(),
        domReady = document.readyState == 'complete',
        domDeferred = vow.defer(),
        domPromise = domReady ? vow.resolve() : domDeferred.promise(),
        mergeImportsPromise = null;

    if (!domReady) {
        function onDomReady () {
            if (!domReady) {
                domReady = true;
                domDeferred.resolve();
            }
        }

        if (document.addEventListener) {
            document.addEventListener('DOMContentLoaded', onDomReady, false);
            window.addEventListener('load', onDomReady, false);
        } else if (document.attachEvent) {
            window.attachEvent('onload', onDomReady);
        }
    }

    ym.ns.ready = ready;

    function ready () {
        var params = {};

        if (arguments.length) {
            if (arguments.length == 1 && typeof arguments[0] == 'object' && !arguments[0].length) {
                // Call with hash of params.
                params = arguments[0];
            } else if (typeof arguments[0] != 'function') {
                // Call with modules list as first parameter.
                params.require = typeof arguments[0] == 'string' ? [arguments[0]] : arguments[0];
                params.successCallback = arguments[1];
                params.errorCallback = arguments[2] && typeof arguments[2] == 'function' ? arguments[2] : null;
                params.context = arguments[2] && typeof arguments[2] == 'object' ? arguments[2] : arguments[3];
            } else {
                // Call with regular signature: `successCallback[, errorCallback], context`.
                params.successCallback = arguments[0];
                params.errorCallback = arguments[1] && typeof arguments[1] == 'function' ? arguments[1] : null;
                params.context = arguments[1] && typeof arguments[1] == 'object' ? arguments[1] : arguments[2];
            }
        }

        var readyParamsPromise = params.require ? ym.modules.require(params.require) : vow.resolve();

        return vow.all([
            getMergeImports(),
            readyParamsPromise,
            getParamsPromise,
            configPromise,
            domPromise
        ]).spread(function (mergeImports, readyParamsModulesValues) {
            if (isNotEmpty(readyParamsModulesValues)) {
                mergeImports.joinImports('package.ymaps', ym.ns, params.require, readyParamsModulesValues);
            }

            if (params.successCallback) {
                // Workaround for swallowing exceptions in user code by promises.
                ym.modules.nextTick(function () {
                    params.successCallback.call(params.context, ym.ns);
                });
            }

            return ym.ns
        }).fail(function (err) {
            if (params.errorCallback) {
                ym.modules.nextTick(function () {
                    params.errorCallback.call(params.context, err);
                });
            }

            return vow.reject(err);
        });
    }

    function getMergeImports () {
        if (!mergeImportsPromise) {
            mergeImportsPromise = ym.modules.require(['system.mergeImports']).spread(function (mergeImports) {
                return mergeImports;
            });
        }

        return mergeImportsPromise;
    }

    function requireModulesFromConfig () {
        var modulesNames = ym.project.preload;

        if (!isNotEmpty(modulesNames)) {
            return vow.resolve();
        }

        var promise = ym.modules.require(modulesNames);

        return vow.all([getMergeImports(), promise]).spread(function (mergeImports, modulesValues) {
            if (isNotEmpty(modulesValues)) {
                mergeImports.joinImports('package.ymaps', ym.ns, modulesNames, modulesValues);
            }
        });
    }

    function requireModulesFromParams () {
        var preload = ym.env.preload;

        if (!preload || !isNotEmpty(preload.load)) {
            return vow.resolve();
        }

        var modulesNames = preload.load.split(','),
            promise = ym.modules.require(modulesNames);

        if (preload.onError) {
            promise.fail(function (err) {
                ym.modules.nextTick(function () {
                    callUserMethod(0, preload.onError, err);
                });
            });
        }

        return vow.all([getMergeImports(), promise]).spread(function (mergeImports, modulesValues) {
            if (isNotEmpty(modulesValues)) {
                mergeImports.joinImports('package.ymaps', ym.ns, modulesNames, modulesValues);
            }

            if (preload.onLoad) {
                ym.modules.nextTick(function () {
                    callUserMethod(0, preload.onLoad, ym.ns);
                });
            }
        });
    }

    function callUserMethod (i, callback, value) {
        // Если функция обработчик описана ниже подключения АПИ, то в ситуации поднятия АПИ из кеша и синхронного
        // в результате этого выполнения кода, получаем ошибку при вызове несуществующей функции. Стабильно
        // повторяется в браузере Opera.
        var callbackData = getMethodByPath(global, callback);

        if (callbackData) {
            callbackData.method.call(callbackData.context, value);
        } else {
            window.setTimeout(function () {
                callUserMethod(++i, callback, value)
            }, Math.pow(2, i));
        }
    }

    function getMethodByPath (parentNs, path) {
        var subObj = parentNs;
        path = path.split('.');
        var i = 0, l = path.length - 1;
        for (; i < l; i++) {
            subObj = subObj[path[i]];
            if(!subObj){
                return undefined;
            }
        }
        return {
            method: subObj[path[l]],
            context: subObj
        };
    }

    function isNotEmpty (obj) {
        return obj && obj.length;
    }
})(this);<commit_msg>Support for empty `load` parameter<commit_after>(function (global) {
    var vow = ym.vow,
        configPromise = requireModulesFromConfig(),
        getParamsPromise = requireModulesFromParams(),
        domReady = document.readyState == 'complete',
        domDeferred = vow.defer(),
        domPromise = domReady ? vow.resolve() : domDeferred.promise(),
        mergeImportsPromise = null;

    if (!domReady) {
        function onDomReady () {
            if (!domReady) {
                domReady = true;
                domDeferred.resolve();
            }
        }

        if (document.addEventListener) {
            document.addEventListener('DOMContentLoaded', onDomReady, false);
            window.addEventListener('load', onDomReady, false);
        } else if (document.attachEvent) {
            window.attachEvent('onload', onDomReady);
        }
    }

    ym.ns.ready = ready;

    function ready () {
        var params = {};

        if (arguments.length) {
            if (arguments.length == 1 && typeof arguments[0] == 'object' && !arguments[0].length) {
                // Call with hash of params.
                params = arguments[0];
            } else if (typeof arguments[0] != 'function') {
                // Call with modules list as first parameter.
                params.require = typeof arguments[0] == 'string' ? [arguments[0]] : arguments[0];
                params.successCallback = arguments[1];
                params.errorCallback = arguments[2] && typeof arguments[2] == 'function' ? arguments[2] : null;
                params.context = arguments[2] && typeof arguments[2] == 'object' ? arguments[2] : arguments[3];
            } else {
                // Call with regular signature: `successCallback[, errorCallback], context`.
                params.successCallback = arguments[0];
                params.errorCallback = arguments[1] && typeof arguments[1] == 'function' ? arguments[1] : null;
                params.context = arguments[1] && typeof arguments[1] == 'object' ? arguments[1] : arguments[2];
            }
        }

        var readyParamsPromise = params.require ? ym.modules.require(params.require) : vow.resolve();

        return vow.all([
            getMergeImports(),
            readyParamsPromise,
            getParamsPromise,
            configPromise,
            domPromise
        ]).spread(function (mergeImports, readyParamsModulesValues) {
            if (isNotEmpty(readyParamsModulesValues)) {
                mergeImports.joinImports('package.ymaps', ym.ns, params.require, readyParamsModulesValues);
            }

            if (params.successCallback) {
                // Workaround for swallowing exceptions in user code by promises.
                ym.modules.nextTick(function () {
                    params.successCallback.call(params.context, ym.ns);
                });
            }

            return ym.ns
        }).fail(function (err) {
            if (params.errorCallback) {
                ym.modules.nextTick(function () {
                    params.errorCallback.call(params.context, err);
                });
            }

            return vow.reject(err);
        });
    }

    function getMergeImports () {
        if (!mergeImportsPromise) {
            mergeImportsPromise = ym.modules.require(['system.mergeImports']).spread(function (mergeImports) {
                return mergeImports;
            });
        }

        return mergeImportsPromise;
    }

    function requireModulesFromConfig () {
        var modulesNames = ym.project.preload;

        if (!isNotEmpty(modulesNames)) {
            return vow.resolve();
        }

        var promise = ym.modules.require(modulesNames);

        return vow.all([getMergeImports(), promise]).spread(function (mergeImports, modulesValues) {
            if (isNotEmpty(modulesValues)) {
                mergeImports.joinImports('package.ymaps', ym.ns, modulesNames, modulesValues);
            }
        });
    }

    function requireModulesFromParams () {
        var preload = ym.env.preload,
            modulesNames = preload.load && preload.load.length > 0 && preload.load.split(','),
            promise = modulesNames ? ym.modules.require(modulesNames) : vow.resolve();

        if (preload.onError) {
            promise.fail(function (err) {
                ym.modules.nextTick(function () {
                    callUserMethod(0, preload.onError, err);
                });
            });
        }

        return vow.all([getMergeImports(), promise, configPromise]).spread(function (mergeImports, modulesValues) {
            if (isNotEmpty(modulesValues)) {
                mergeImports.joinImports('package.ymaps', ym.ns, modulesNames, modulesValues);
            }

            if (preload.onLoad) {
                ym.modules.nextTick(function () {
                    callUserMethod(0, preload.onLoad, ym.ns);
                });
            }
        });
    }

    function callUserMethod (i, callback, value) {
        // Если функция обработчик описана ниже подключения АПИ, то в ситуации поднятия АПИ из кеша и синхронного
        // в результате этого выполнения кода, получаем ошибку при вызове несуществующей функции. Стабильно
        // повторяется в браузере Opera.
        var callbackData = getMethodByPath(global, callback);

        if (callbackData) {
            callbackData.method.call(callbackData.context, value);
        } else {
            window.setTimeout(function () {
                callUserMethod(++i, callback, value)
            }, Math.pow(2, i));
        }
    }

    function getMethodByPath (parentNs, path) {
        var subObj = parentNs;
        path = path.split('.');
        var i = 0, l = path.length - 1;
        for (; i < l; i++) {
            subObj = subObj[path[i]];
            if(!subObj){
                return undefined;
            }
        }
        return {
            method: subObj[path[l]],
            context: subObj
        };
    }

    function isNotEmpty (obj) {
        return obj && obj.length;
    }
})(this);<|endoftext|>


<commit_before>// ==UserScript==
// @name         10wallpaper downloader
// @namespace    http://baivong.github.io/
// @version      2.1.1
// @description  1-Click download on 10wallpaper. You should select the resolution before downloading.
// @icon         http://i.imgur.com/08zfJez.png
// @author       Zzbaivong
// @oujs:author  baivong
// @license      MIT; https://baivong.mit-license.org/license.txt
// @match        http://10wallpaper.com/*
// @match        http://www.10wallpaper.com/*
// @match        https://10wallpaper.com/*
// @match        https://www.10wallpaper.com/*
// @require      https://unpkg.com/file-saver@1.3.8/FileSaver.min.js
// @require      https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js?v=a834d46
// @noframes
// @connect      self
// @supportURL   https://github.com/lelinhtinh/Userscript/issues
// @run-at       document-idle
// @grant        GM.xmlHttpRequest
// @grant        GM.openInTab
// ==/UserScript==

(function () {
    'use strict';

    /**
     * Resolution config
     * @type {String} // Eg: 1920x1200, 1366x768, 1280x1024, ...
     */
    var resolution = '';

    // Do not change the code below this line, unless you know how.
    var list = document.querySelectorAll('a[href^="/view/"]'),
        res = location.pathname.match(/\d+x\d+/);
    if (!/\d+x\d+/.test(resolution)) resolution = screen.width + 'x' + screen.height;
    res = !res ? resolution : res[0];

    [].forEach.call(list, function (link) {
        var info = link.querySelector('span'),
            infoContent = info.innerHTML,
            img = link.querySelector('img'),
            imgName;

        if (!img) return;
        img = img.src.replace(/(\/|_)(small|medium)(\/|\.)/g, '$1' + res + '$3');
        imgName = img.replace(/.*\//, '');

        link.addEventListener('click', function (e) {
            e.preventDefault();
            info.innerHTML = 'Downloading...';

            GM.xmlHttpRequest({
                method: 'GET',
                url: img,
                responseType: 'blob',
                onprogress: function (e) {
                    var percent = Math.round((e.loaded / e.total) * 100);
                    info.innerHTML = percent + ' %';
                },
                onload: function (response) {
                    var blob = response.response;

                    info.innerHTML = infoContent;
                    link.setAttribute('href', URL.createObjectURL(blob));
                    link.setAttribute('download', imgName);

                    saveAs(blob, imgName);
                },
                onerror: function (err) {
                    console.error(err);
                }
            });
        });

        link.addEventListener('contextmenu', function (e) {
            e.preventDefault();
            GM.openInTab(img);
        });

        link.setAttribute('title', 'Click to download this image\nRight Click to open in new tab');
    });
})();
<commit_msg>Update 10wallpaper_downloader.user.js<commit_after>// ==UserScript==
// @name         10wallpaper downloader
// @namespace    http://baivong.github.io/
// @version      2.1.2
// @description  1-Click download on 10wallpaper. You should select the resolution before downloading.
// @icon         http://i.imgur.com/08zfJez.png
// @author       Zzbaivong
// @oujs:author  baivong
// @license      MIT; https://baivong.mit-license.org/license.txt
// @match        http://10wallpaper.com/*
// @match        http://www.10wallpaper.com/*
// @match        https://10wallpaper.com/*
// @match        https://www.10wallpaper.com/*
// @require      https://unpkg.com/file-saver@1.3.8/FileSaver.min.js
// @require      https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js?v=a834d46
// @noframes
// @connect      self
// @supportURL   https://github.com/lelinhtinh/Userscript/issues
// @run-at       document-idle
// @grant        GM.xmlHttpRequest
// @grant        GM_xmlhttpRequest
// @grant        GM.openInTab
// @grant        GM_openInTab
// ==/UserScript==

(function () {
    'use strict';

    /**
     * Resolution config
     * @type {String} // Eg: 1920x1200, 1366x768, 1280x1024, ...
     */
    var resolution = '';

    // Do not change the code below this line, unless you know how.
    var list = document.querySelectorAll('a[href^="/view/"]'),
        res = location.pathname.match(/\d+x\d+/);
    if (!/\d+x\d+/.test(resolution)) resolution = screen.width + 'x' + screen.height;
    res = !res ? resolution : res[0];

    [].forEach.call(list, function (link) {
        var info = link.querySelector('span'),
            infoContent = info.innerHTML,
            img = link.querySelector('img'),
            imgName;

        if (!img) return;
        img = img.src.replace(/(\/|_)(small|medium)(\/|\.)/g, '$1' + res + '$3');
        imgName = img.replace(/.*\//, '');

        link.addEventListener('click', function (e) {
            e.preventDefault();
            info.innerHTML = 'Downloading...';

            GM.xmlHttpRequest({
                method: 'GET',
                url: img,
                responseType: 'blob',
                onprogress: function (e) {
                    var percent = Math.round((e.loaded / e.total) * 100);
                    info.innerHTML = percent + ' %';
                },
                onload: function (response) {
                    var blob = response.response;

                    info.innerHTML = infoContent;
                    link.setAttribute('href', URL.createObjectURL(blob));
                    link.setAttribute('download', imgName);

                    saveAs(blob, imgName);
                },
                onerror: function (err) {
                    console.error(err);
                }
            });
        });

        link.addEventListener('contextmenu', function (e) {
            e.preventDefault();
            GM.openInTab(img);
        });

        link.setAttribute('title', 'Click to download this image\nRight Click to open in new tab');
    });
})();
<|endoftext|>