<commit_before>function Window(routing_id, nobind, predefined_id) {
    // Get and set id.
    native function CallObjectMethod();
    native function CallObjectMethodSync();
    native function AllocateId();

    var id;
    if (predefined_id)
        id = predefined_id;
    else
        id = AllocateId();

    Object.defineProperty(this, 'id', {
        value: id,
        writable: false
    });

    // Store routing id (need for IPC since we are in node's context).
    this.routing_id = routing_id;

    // Store myself in node's context.
    global.__nwWindowsStore[id] = this;
    global.__nwObjectsRegistry.set(id, this);

    // Tell Shell I'm the js delegate of it.
    native function BindToShell();
    if (!nobind)
        BindToShell(this.routing_id, this.id);

    var that = this;
    this.cookies = {
        req_id : 0,
        get : function(details, cb) {
            this.req_id++;
            if (typeof cb == 'function') {
                that.once('__nw_gotcookie' + this.req_id, function(cookie) {
                    if (cookie.length > 0)
                        cb(cookie[0]);
                    else
                        cb(null);
                });
            }
            CallObjectMethod(that, 'CookieGet', [ this.req_id, details ]);
        },
        getAll : function(details, cb) {
            this.req_id++;
            if (typeof cb == 'function') {
                that.once('__nw_gotcookie' + this.req_id, function(cookie) {
                    cb(cookie);
                });
            }
            CallObjectMethod(that, 'CookieGetAll', [ this.req_id, details ]);
        },
        remove : function(details, cb) {
            this.req_id++;
            if (typeof cb == 'function') {
                that.once('__nw_gotcookie' + this.req_id, function(details) {
                    cb(details);
                });
            }
            CallObjectMethod(that, 'CookieRemove', [ this.req_id, details ]);
        },
        set : function(details, cb) {
            this.req_id++;
            if (typeof cb == 'function') {
                that.once('__nw_gotcookie' + this.req_id, function(cookie) {
                    cb(cookie);
                });
            }
            CallObjectMethod(that, 'CookieSet', [ this.req_id, details ]);
        },
        onChanged : {
            addListener : function(cb) {
                that.on('__nw_cookie_changed', cb);
            },
            removeListener : function(cb) {
                that.removeListener('__nw_cookie_changed', cb);
            }
        }
    }
}

// Window will inherit EventEmitter in "third_party/node/src/node.js", do
// not inherit here becuase this file is loaded before everything else.

// And init everything after the inheritance.
Window.init = function() {

var v8_util = process.binding('v8_util');
var EventEmitter = process.EventEmitter;

native function CallObjectMethod();
native function CallObjectMethodSync();

// Override the addListener method.
Window.prototype.on = Window.prototype.addListener = function(ev, callback) {
  // Save window id of where the callback is created.
  var closure = v8_util.getCreationContext(callback);
  if (v8_util.getConstructorName(closure) == 'Window' &&
      closure.hasOwnProperty('nwDispatcher')) {
    v8_util.setHiddenValue(callback, '__nwWindowId',
        closure.nwDispatcher.requireNwGui().Window.get().id);
  }

  // Call parent.
  EventEmitter.prototype.addListener.apply(this, arguments);
}

// Route events.
Window.prototype.handleEvent = function(ev) {
  // Filter invalid callbacks.
  var listeners_copy = this.listeners(ev).slice(0);
  for (var i = 0; i < listeners_copy.length; ++i) {
    var original_closure = v8_util.getCreationContext(listeners_copy[i]);

    // Skip for node context.
    if (v8_util.getConstructorName(original_closure) != 'Window')
      continue;

    var window_id = v8_util.getHiddenValue(listeners_copy[i], '__nwWindowId');

    // Remove callback if original window is closed (not in __nwWindowsStore).
    if (global.__nwWindowsStore.hasOwnProperty(window_id)) {
      // Check hashes and see if the window context of Shell has been changed,
      // this happens when we refresh the Shell or change it's locations.
      var original_hash = v8_util.getObjectHash(original_closure);
      var current_hash = v8_util.getObjectHash(
          global.__nwWindowsStore[window_id].window);

      // Do nothing if nothing is changed.
      if (original_hash == current_hash)
        continue;
    }

    console.warn('Remove zombie callback for window id ' + window_id);
    this.removeListener(ev, listeners_copy[i]);
  }

  // Route events to EventEmitter.
  this.emit.apply(this, arguments);

  // If no one is listening to 'close' then close directly
  if (ev == 'close' && this.listeners(ev).length == 0) {
    this.close(true);
    return;
  } else if (ev == 'closed') { // Clear me.
    delete global.__nwWindowsStore[this.id];
    return;
  }
}

// Return current window object of Shell's DOM.
Window.prototype.__defineGetter__('window', function() {
  native function GetWindowObject();
  return GetWindowObject(this.routing_id);
});

Window.prototype.__defineSetter__('x', function(x) {
  this.moveTo(x, this.y);
});

Window.prototype.__defineGetter__('x', function() {
  return CallObjectMethodSync(this, 'GetPosition', [])[0];
});

Window.prototype.__defineSetter__('y', function(y) {
  this.moveTo(this.x, y);
});

Window.prototype.__defineGetter__('y', function() {
  return CallObjectMethodSync(this, 'GetPosition', [])[1];
});

Window.prototype.__defineSetter__('width', function(width) {
  this.resizeTo(width, this.height);
});

Window.prototype.__defineGetter__('width', function() {
  return CallObjectMethodSync(this, 'GetSize', [])[0];
});

Window.prototype.__defineSetter__('height', function(height) {
  this.resizeTo(this.width, height);
});

Window.prototype.__defineGetter__('height', function() {
  return CallObjectMethodSync(this, 'GetSize', [])[1];
});

Window.prototype.__defineSetter__('title', function(title) {
  this.window.document.title = title;
});

Window.prototype.__defineGetter__('title', function() {
  return this.window.document.title;
});

Window.prototype.__defineSetter__('zoomLevel', function(level) {
  CallObjectMethodSync(this, 'SetZoomLevel', level);
});

Window.prototype.__defineGetter__('zoomLevel', function() {
  return CallObjectMethodSync(this, 'GetZoomLevel', [])[0];
});

Window.prototype.__defineSetter__('menu', function(menu) {
  if (v8_util.getConstructorName(menu) != 'Menu')
    throw new String("'menu' property requries a valid Menu");

  if (menu.type != 'menubar')
    throw new String('Only menu of type "menubar" can be used as this.window menu');

  v8_util.setHiddenValue(this, 'menu', menu);
  CallObjectMethod(this, 'SetMenu', [ menu.id ]);
});

Window.prototype.__defineGetter__('menu', function() {
  return v8_util.getHiddenValue(this, 'menu');
});

Window.prototype.__defineSetter__('isFullscreen', function(flag) {
  if (flag)
    this.enterFullscreen();
  else
    this.leaveFullscreen();
});

Window.prototype.isDevToolsOpen = function () {
    var result = CallObjectMethodSync(this, 'IsDevToolsOpen', []);
    return Boolean(result[0]);
}

Window.prototype.__defineGetter__('isFullscreen', function() {
  var result = CallObjectMethodSync(this, 'IsFullscreen', []);
  return Boolean(result[0]);
});

Window.prototype.__defineSetter__('isKioskMode', function(flag) {
  if (flag)
    this.enterKioskMode();
  else
    this.leaveKioskMode();
});

Window.prototype.__defineGetter__('isKioskMode', function() {
  var result = CallObjectMethodSync(this, 'IsKioskMode', []);
  return Boolean(result[0]);
});

Window.prototype.moveTo = function(x, y) {
  CallObjectMethod(this, 'MoveTo', [ Number(x), Number(y) ]);
}

Window.prototype.moveBy = function(x, y) {
  var position = CallObjectMethodSync(this, 'GetPosition', []);
  this.moveTo(position[0] + x, position[1] + y);
}

Window.prototype.resizeTo = function(width, height) {
  CallObjectMethod(this, 'ResizeTo', [ Number(width), Number(height) ]);
}

Window.prototype.resizeBy = function(width, height) {
  var size = CallObjectMethodSync(this, 'GetSize', []);
  this.resizeTo(size[0] + width, size[1] + height);
}

Window.prototype.focus = function(flag) {
  if (typeof flag == 'undefined' || Boolean(flag)) {
      if (this.__nw_is_devtools)
          CallObjectMethod(this, 'Focus', []);
      else
          this.window.focus();
  } else
    this.blur();
};

Window.prototype.blur = function() {
    if (this.__nw_is_devtools)
        CallObjectMethod(this, 'Blur', []);
    else
        this.window.blur();
};

Window.prototype.show = function(flag) {
  if (typeof flag == 'undefined' || Boolean(flag))
    CallObjectMethod(this, 'Show', []);
  else
    this.hide();
}

Window.prototype.hide = function() {
  CallObjectMethod(this, 'Hide', []);
}

Window.prototype.hide = function() {
  CallObjectMethod(this, 'Hide', []);
}

Window.prototype.close = function(force) {
  CallObjectMethod(this, 'Close', [ Boolean(force) ]);
}

Window.prototype.maximize = function() {
  CallObjectMethod(this, 'Maximize', []);
}

Window.prototype.unmaximize = function() {
  CallObjectMethod(this, 'Unmaximize', []);
}

Window.prototype.minimize = function() {
  CallObjectMethod(this, 'Minimize', []);
}

Window.prototype.restore = function() {
  CallObjectMethod(this, 'Restore', []);
}

Window.prototype.enterFullscreen = function() {
  CallObjectMethod(this, 'EnterFullscreen', []);
}

Window.prototype.leaveFullscreen = function() {
  CallObjectMethod(this, 'LeaveFullscreen', []);
}

Window.prototype.toggleFullscreen = function() {
  CallObjectMethod(this, 'ToggleFullscreen', []);
}

Window.prototype.enterKioskMode = function() {
  CallObjectMethod(this, 'EnterKioskMode', []);
}

Window.prototype.leaveKioskMode = function() {
  CallObjectMethod(this, 'LeaveKioskMode', []);
}

Window.prototype.toggleKioskMode = function() {
  CallObjectMethod(this, 'ToggleKioskMode', []);
}

Window.prototype.closeDevTools = function() {
  CallObjectMethod(this, 'CloseDevTools', []);
}

Window.prototype.showDevTools = function(frm, headless) {
    var id = '';
    if (typeof frm === 'string') {
        id = frm;
        this._pending_devtools_jail = null;
    }else{
        this._pending_devtools_jail = frm;
    }
    var win_id = CallObjectMethodSync(this, 'ShowDevTools', [id, Boolean(headless)])[0];
    var ret;
    if (typeof win_id == 'number' && win_id > 0) {
        ret = global.__nwWindowsStore[win_id];
        if (!ret) {
            ret = new global.Window(this.window.nwDispatcher.getRoutingIDForCurrentContext(), true, win_id);
            ret.__nw_is_devtools = true;
        }
        return ret;
    }
}

Window.prototype.__setDevToolsJail = function(id) {
    var frm = null;
    if (id)
        frm = this.window.document.getElementById(id);
    else
        frm = this._pending_devtools_jail || null;
    CallObjectMethod(this, 'setDevToolsJail', frm);
}

Window.prototype.setMinimumSize = function(width, height) {
  CallObjectMethod(this, 'SetMinimumSize', [ width, height ]);
}

Window.prototype.setMaximumSize = function(width, height) {
  CallObjectMethod(this, 'SetMaximumSize', [ width, height ]);
}

Window.prototype.setResizable = function(resizable) {
  resizable = Boolean(resizable);
  CallObjectMethod(this, 'SetResizable', [ resizable ]);
}

Window.prototype.setAlwaysOnTop = function(flag) {
  CallObjectMethod(this, 'SetAlwaysOnTop', [ Boolean(flag) ]);
}

Window.prototype.requestAttention = function(flash) {
  flash = Boolean(flash);
  CallObjectMethod(this, 'RequestAttention', [ flash ]);
}

Window.prototype.setPosition = function(position) {
  if (position != 'center' && position != 'mouse')
    throw new String('Invalid postion');
  CallObjectMethod(this, 'SetPosition', [ position ]);
}

Window.prototype.reload = function(type) {
  // type is default to 0 (RELOAD).
  if (!(typeof type == 'number' && 0 <= type && type <= 3))
    type = 0;

  CallObjectMethod(this, 'Reload', [ type ]);
}

Window.prototype.reloadIgnoringCache = function() {
  this.reload(1);
}

Window.prototype.reloadOriginalRequestURL = function() {
  this.reload(2);
}

Window.prototype.reloadDev = function() {
  this.reload(3);
}

Window.prototype.capturePage = function(callback, image_format) {
  if (image_format != 'jpeg' && image_format != 'png') {
    image_format = 'jpeg';
  }

  if (typeof callback == 'function') {
    this.once('__nw_capturepagedone', function(imgdata) {
      callback(imgdata);
    });
  }

  CallObjectMethod(this, 'CapturePage', [image_format]);
};

    Window.prototype.eval = function(frame, script) {
        return CallObjectMethod(this, 'EvaluateScript', frame, script);
    };

}  // function Window.init
<commit_msg>methods for the policy object in 'new-win-policy'<commit_after>function Window(routing_id, nobind, predefined_id) {
    // Get and set id.
    native function CallObjectMethod();
    native function CallObjectMethodSync();
    native function AllocateId();

    var id;
    if (predefined_id)
        id = predefined_id;
    else
        id = AllocateId();

    Object.defineProperty(this, 'id', {
        value: id,
        writable: false
    });

    // Store routing id (need for IPC since we are in node's context).
    this.routing_id = routing_id;

    // Store myself in node's context.
    global.__nwWindowsStore[id] = this;
    global.__nwObjectsRegistry.set(id, this);

    // Tell Shell I'm the js delegate of it.
    native function BindToShell();
    if (!nobind)
        BindToShell(this.routing_id, this.id);

    var that = this;
    this.cookies = {
        req_id : 0,
        get : function(details, cb) {
            this.req_id++;
            if (typeof cb == 'function') {
                that.once('__nw_gotcookie' + this.req_id, function(cookie) {
                    if (cookie.length > 0)
                        cb(cookie[0]);
                    else
                        cb(null);
                });
            }
            CallObjectMethod(that, 'CookieGet', [ this.req_id, details ]);
        },
        getAll : function(details, cb) {
            this.req_id++;
            if (typeof cb == 'function') {
                that.once('__nw_gotcookie' + this.req_id, function(cookie) {
                    cb(cookie);
                });
            }
            CallObjectMethod(that, 'CookieGetAll', [ this.req_id, details ]);
        },
        remove : function(details, cb) {
            this.req_id++;
            if (typeof cb == 'function') {
                that.once('__nw_gotcookie' + this.req_id, function(details) {
                    cb(details);
                });
            }
            CallObjectMethod(that, 'CookieRemove', [ this.req_id, details ]);
        },
        set : function(details, cb) {
            this.req_id++;
            if (typeof cb == 'function') {
                that.once('__nw_gotcookie' + this.req_id, function(cookie) {
                    cb(cookie);
                });
            }
            CallObjectMethod(that, 'CookieSet', [ this.req_id, details ]);
        },
        onChanged : {
            addListener : function(cb) {
                that.on('__nw_cookie_changed', cb);
            },
            removeListener : function(cb) {
                that.removeListener('__nw_cookie_changed', cb);
            }
        }
    }
}

// Window will inherit EventEmitter in "third_party/node/src/node.js", do
// not inherit here becuase this file is loaded before everything else.

// And init everything after the inheritance.
Window.init = function() {

var v8_util = process.binding('v8_util');
var EventEmitter = process.EventEmitter;

native function CallObjectMethod();
native function CallObjectMethodSync();

// Override the addListener method.
Window.prototype.on = Window.prototype.addListener = function(ev, callback) {
  // Save window id of where the callback is created.
  var closure = v8_util.getCreationContext(callback);
  if (v8_util.getConstructorName(closure) == 'Window' &&
      closure.hasOwnProperty('nwDispatcher')) {
    v8_util.setHiddenValue(callback, '__nwWindowId',
        closure.nwDispatcher.requireNwGui().Window.get().id);
  }

  // Call parent.
  EventEmitter.prototype.addListener.apply(this, arguments);
}

// Route events.
Window.prototype.handleEvent = function(ev) {
  // Filter invalid callbacks.
  var listeners_copy = this.listeners(ev).slice(0);
  for (var i = 0; i < listeners_copy.length; ++i) {
    var original_closure = v8_util.getCreationContext(listeners_copy[i]);

    // Skip for node context.
    if (v8_util.getConstructorName(original_closure) != 'Window')
      continue;

    var window_id = v8_util.getHiddenValue(listeners_copy[i], '__nwWindowId');

    // Remove callback if original window is closed (not in __nwWindowsStore).
    if (global.__nwWindowsStore.hasOwnProperty(window_id)) {
      // Check hashes and see if the window context of Shell has been changed,
      // this happens when we refresh the Shell or change it's locations.
      var original_hash = v8_util.getObjectHash(original_closure);
      var current_hash = v8_util.getObjectHash(
          global.__nwWindowsStore[window_id].window);

      // Do nothing if nothing is changed.
      if (original_hash == current_hash)
        continue;
    }

    console.warn('Remove zombie callback for window id ' + window_id);
    this.removeListener(ev, listeners_copy[i]);
  }

    if (ev == 'new-win-policy' && arguments.length > 3) {
        var policy = arguments[3];
        policy.ignore         =  function () { this.val = 'ignore'; };
        policy.forceCurrent   =  function () { this.val = 'current'; };
        policy.forceDownload  =  function () { this.val = 'download'; };
        policy.forceNewWindow =  function () { this.val = 'new-window'; };
        policy.forceNewPopup  =  function () { this.val = 'new-popup'; };
    }
  // Route events to EventEmitter.
  this.emit.apply(this, arguments);

  // If no one is listening to 'close' then close directly
  if (ev == 'close' && this.listeners(ev).length == 0) {
    this.close(true);
    return;
  } else if (ev == 'closed') { // Clear me.
    delete global.__nwWindowsStore[this.id];
    return;
  }
}

// Return current window object of Shell's DOM.
Window.prototype.__defineGetter__('window', function() {
  native function GetWindowObject();
  return GetWindowObject(this.routing_id);
});

Window.prototype.__defineSetter__('x', function(x) {
  this.moveTo(x, this.y);
});

Window.prototype.__defineGetter__('x', function() {
  return CallObjectMethodSync(this, 'GetPosition', [])[0];
});

Window.prototype.__defineSetter__('y', function(y) {
  this.moveTo(this.x, y);
});

Window.prototype.__defineGetter__('y', function() {
  return CallObjectMethodSync(this, 'GetPosition', [])[1];
});

Window.prototype.__defineSetter__('width', function(width) {
  this.resizeTo(width, this.height);
});

Window.prototype.__defineGetter__('width', function() {
  return CallObjectMethodSync(this, 'GetSize', [])[0];
});

Window.prototype.__defineSetter__('height', function(height) {
  this.resizeTo(this.width, height);
});

Window.prototype.__defineGetter__('height', function() {
  return CallObjectMethodSync(this, 'GetSize', [])[1];
});

Window.prototype.__defineSetter__('title', function(title) {
  this.window.document.title = title;
});

Window.prototype.__defineGetter__('title', function() {
  return this.window.document.title;
});

Window.prototype.__defineSetter__('zoomLevel', function(level) {
  CallObjectMethodSync(this, 'SetZoomLevel', level);
});

Window.prototype.__defineGetter__('zoomLevel', function() {
  return CallObjectMethodSync(this, 'GetZoomLevel', [])[0];
});

Window.prototype.__defineSetter__('menu', function(menu) {
  if (v8_util.getConstructorName(menu) != 'Menu')
    throw new String("'menu' property requries a valid Menu");

  if (menu.type != 'menubar')
    throw new String('Only menu of type "menubar" can be used as this.window menu');

  v8_util.setHiddenValue(this, 'menu', menu);
  CallObjectMethod(this, 'SetMenu', [ menu.id ]);
});

Window.prototype.__defineGetter__('menu', function() {
  return v8_util.getHiddenValue(this, 'menu');
});

Window.prototype.__defineSetter__('isFullscreen', function(flag) {
  if (flag)
    this.enterFullscreen();
  else
    this.leaveFullscreen();
});

Window.prototype.isDevToolsOpen = function () {
    var result = CallObjectMethodSync(this, 'IsDevToolsOpen', []);
    return Boolean(result[0]);
}

Window.prototype.__defineGetter__('isFullscreen', function() {
  var result = CallObjectMethodSync(this, 'IsFullscreen', []);
  return Boolean(result[0]);
});

Window.prototype.__defineSetter__('isKioskMode', function(flag) {
  if (flag)
    this.enterKioskMode();
  else
    this.leaveKioskMode();
});

Window.prototype.__defineGetter__('isKioskMode', function() {
  var result = CallObjectMethodSync(this, 'IsKioskMode', []);
  return Boolean(result[0]);
});

Window.prototype.moveTo = function(x, y) {
  CallObjectMethod(this, 'MoveTo', [ Number(x), Number(y) ]);
}

Window.prototype.moveBy = function(x, y) {
  var position = CallObjectMethodSync(this, 'GetPosition', []);
  this.moveTo(position[0] + x, position[1] + y);
}

Window.prototype.resizeTo = function(width, height) {
  CallObjectMethod(this, 'ResizeTo', [ Number(width), Number(height) ]);
}

Window.prototype.resizeBy = function(width, height) {
  var size = CallObjectMethodSync(this, 'GetSize', []);
  this.resizeTo(size[0] + width, size[1] + height);
}

Window.prototype.focus = function(flag) {
  if (typeof flag == 'undefined' || Boolean(flag)) {
      if (this.__nw_is_devtools)
          CallObjectMethod(this, 'Focus', []);
      else
          this.window.focus();
  } else
    this.blur();
};

Window.prototype.blur = function() {
    if (this.__nw_is_devtools)
        CallObjectMethod(this, 'Blur', []);
    else
        this.window.blur();
};

Window.prototype.show = function(flag) {
  if (typeof flag == 'undefined' || Boolean(flag))
    CallObjectMethod(this, 'Show', []);
  else
    this.hide();
}

Window.prototype.hide = function() {
  CallObjectMethod(this, 'Hide', []);
}

Window.prototype.hide = function() {
  CallObjectMethod(this, 'Hide', []);
}

Window.prototype.close = function(force) {
  CallObjectMethod(this, 'Close', [ Boolean(force) ]);
}

Window.prototype.maximize = function() {
  CallObjectMethod(this, 'Maximize', []);
}

Window.prototype.unmaximize = function() {
  CallObjectMethod(this, 'Unmaximize', []);
}

Window.prototype.minimize = function() {
  CallObjectMethod(this, 'Minimize', []);
}

Window.prototype.restore = function() {
  CallObjectMethod(this, 'Restore', []);
}

Window.prototype.enterFullscreen = function() {
  CallObjectMethod(this, 'EnterFullscreen', []);
}

Window.prototype.leaveFullscreen = function() {
  CallObjectMethod(this, 'LeaveFullscreen', []);
}

Window.prototype.toggleFullscreen = function() {
  CallObjectMethod(this, 'ToggleFullscreen', []);
}

Window.prototype.enterKioskMode = function() {
  CallObjectMethod(this, 'EnterKioskMode', []);
}

Window.prototype.leaveKioskMode = function() {
  CallObjectMethod(this, 'LeaveKioskMode', []);
}

Window.prototype.toggleKioskMode = function() {
  CallObjectMethod(this, 'ToggleKioskMode', []);
}

Window.prototype.closeDevTools = function() {
  CallObjectMethod(this, 'CloseDevTools', []);
}

Window.prototype.showDevTools = function(frm, headless) {
    var id = '';
    if (typeof frm === 'string') {
        id = frm;
        this._pending_devtools_jail = null;
    }else{
        this._pending_devtools_jail = frm;
    }
    var win_id = CallObjectMethodSync(this, 'ShowDevTools', [id, Boolean(headless)])[0];
    var ret;
    if (typeof win_id == 'number' && win_id > 0) {
        ret = global.__nwWindowsStore[win_id];
        if (!ret) {
            ret = new global.Window(this.window.nwDispatcher.getRoutingIDForCurrentContext(), true, win_id);
            ret.__nw_is_devtools = true;
        }
        return ret;
    }
}

Window.prototype.__setDevToolsJail = function(id) {
    var frm = null;
    if (id)
        frm = this.window.document.getElementById(id);
    else
        frm = this._pending_devtools_jail || null;
    CallObjectMethod(this, 'setDevToolsJail', frm);
}

Window.prototype.setMinimumSize = function(width, height) {
  CallObjectMethod(this, 'SetMinimumSize', [ width, height ]);
}

Window.prototype.setMaximumSize = function(width, height) {
  CallObjectMethod(this, 'SetMaximumSize', [ width, height ]);
}

Window.prototype.setResizable = function(resizable) {
  resizable = Boolean(resizable);
  CallObjectMethod(this, 'SetResizable', [ resizable ]);
}

Window.prototype.setAlwaysOnTop = function(flag) {
  CallObjectMethod(this, 'SetAlwaysOnTop', [ Boolean(flag) ]);
}

Window.prototype.requestAttention = function(flash) {
  flash = Boolean(flash);
  CallObjectMethod(this, 'RequestAttention', [ flash ]);
}

Window.prototype.setPosition = function(position) {
  if (position != 'center' && position != 'mouse')
    throw new String('Invalid postion');
  CallObjectMethod(this, 'SetPosition', [ position ]);
}

Window.prototype.reload = function(type) {
  // type is default to 0 (RELOAD).
  if (!(typeof type == 'number' && 0 <= type && type <= 3))
    type = 0;

  CallObjectMethod(this, 'Reload', [ type ]);
}

Window.prototype.reloadIgnoringCache = function() {
  this.reload(1);
}

Window.prototype.reloadOriginalRequestURL = function() {
  this.reload(2);
}

Window.prototype.reloadDev = function() {
  this.reload(3);
}

Window.prototype.capturePage = function(callback, image_format) {
  if (image_format != 'jpeg' && image_format != 'png') {
    image_format = 'jpeg';
  }

  if (typeof callback == 'function') {
    this.once('__nw_capturepagedone', function(imgdata) {
      callback(imgdata);
    });
  }

  CallObjectMethod(this, 'CapturePage', [image_format]);
};

    Window.prototype.eval = function(frame, script) {
        return CallObjectMethod(this, 'EvaluateScript', frame, script);
    };

}  // function Window.init
<|endoftext|>


<commit_before>import { runQuery } from '../apiBase/APIRequestUtils';

import PostModel from '../models2/PostModel';
import Subreddit from '../models2/Subreddit';
import { POST_TYPE } from '../models2/thingTypes';

const getPath = (query) => {
  let path = '';

  if (query.subreddit) {
    path = `r/${query.subreddit}/`;
  }

  return `${path}search.json`;
};

const formatQuery = (query) => {
  if (query.subreddit) {
    query.restrict_sr = 'on';
    delete query.subreddit;
  }

  return query;
};

const listsFromResponse = (res) => {
  const { body } = res;
  if (!body) { return []; }

  // If only one type is returned body will be an object;
  return Array.isArray(body) ? body : [body];
};

const parseBody = (res, apiResponse) => {
  const lists = listsFromResponse(res);
  console.log('lists.length?', lists.length);
  console.log(res.body);

  lists.forEach((listing) => {
    if (listing.data.children.length) {
      if (listing.data.children[0].kind === POST_TYPE) {
        listing.data.children.forEach((link) => {
          apiResponse.addResult(PostModel.fromJSON(link.data));
        });

        apiResponse.meta.after = listing.data.after;
        apiResponse.meta.before = listing.data.before;
      } else {
        listing.data.children.forEach((subreddit) => {
          apiResponse.addResult(Subreddit.fromJSON(subreddit.data));
        });
      }
    }
  });
};

export default {
  get(apiOptions, query) {
    const path = getPath(query);
    const apiQuery = formatQuery({ ...query });

    return runQuery(apiOptions, 'get', path, apiQuery, query, parseBody);
  },
};
<commit_msg>Remove console.logs from SearchEndpoint.js<commit_after>import { runQuery } from '../apiBase/APIRequestUtils';

import PostModel from '../models2/PostModel';
import Subreddit from '../models2/Subreddit';
import { POST_TYPE } from '../models2/thingTypes';

const getPath = (query) => {
  let path = '';

  if (query.subreddit) {
    path = `r/${query.subreddit}/`;
  }

  return `${path}search.json`;
};

const formatQuery = (query) => {
  if (query.subreddit) {
    query.restrict_sr = 'on';
    delete query.subreddit;
  }

  return query;
};

const listsFromResponse = (res) => {
  const { body } = res;
  if (!body) { return []; }

  // If only one type is returned body will be an object;
  return Array.isArray(body) ? body : [body];
};

const parseBody = (res, apiResponse) => {
  const lists = listsFromResponse(res);

  lists.forEach((listing) => {
    if (listing.data.children.length) {
      if (listing.data.children[0].kind === POST_TYPE) {
        listing.data.children.forEach((link) => {
          apiResponse.addResult(PostModel.fromJSON(link.data));
        });

        apiResponse.meta.after = listing.data.after;
        apiResponse.meta.before = listing.data.before;
      } else {
        listing.data.children.forEach((subreddit) => {
          apiResponse.addResult(Subreddit.fromJSON(subreddit.data));
        });
      }
    }
  });
};

export default {
  get(apiOptions, query) {
    const path = getPath(query);
    const apiQuery = formatQuery({ ...query });

    return runQuery(apiOptions, 'get', path, apiQuery, query, parseBody);
  },
};
<|endoftext|>


<commit_before>(function($) {

    $.fn.dropSelect = function(options) {
        var opts = $.extend( {}, $.fn.dropSelect.defaults, options),
            fakeEl;

        //parse all items that meet the selector
        this.each(function() {
            var original = $(this),
                dropSelect = generate(original),
                width = (opts.width === "auto") ? dropSelect.width : opts.width;

            dropSelect = dropSelect.element;
            // We'll replace the element
            original.replaceWith(dropSelect);
            dropSelect.width(width);
            //set the onclick handler of the items
            dropSelect.find('div.items a').on("click", function () {
                var $this   = $(this),
                    display = $this.html(),
                    value = $this.data('value'),
                    selected = $this.parents().find('.selected');

                if (selected.attr('data-value') === value) {
                    return;
                }

                $this.siblings('.active').each(function () {
                    $(this).removeClass('active');
                });
                $this.addClass('active');
                selected.attr('data-value', value).html(display);
                if (typeof opts.callBack === "function") {
                    //call the callback if it's set
                    opts.callBack(value);
                }
                //trigger the change event.
                selected.parent().trigger("change");
            });
        });

        //for cleanup, we'll remove our fake sizing element
        if (fakeEl) {
            fakeEl.remove();
            fakeEl = null;
        }

        //This function will generate the divs used and add the appropriate classes.
        function generate(select) {
            var attrs = getAttrs(select),
                dropSelect = $('
'),
                items = $('
'),
                selected = $('
'),
                widths = [],
                attr;

            // Add the attributes from the select to the div
            for (attr in attrs) {
                if (! attrs.hasOwnProperty(attr)) {
                    continue;
                }
                dropSelect.attr(attr, attrs[attr]);
            }
            // Add our classname
            dropSelect.addClass(opts.className);

            // parse all the options.
            select.find('option').each(function (index) {
                var $this = $(this),
                    value =  $this.attr('value') || null,
                    name = ((typeof opts.formatter === "function") ? opts.formatter($this.text()) : $this.text()),
                    isSelected = $this.prop('selected'),
                    current = {};

                // we need to check how we handle empties based on the options.
                if (value === null) {
                    if (opts.includeEmpties) {
                        current = $('').html(name);
                    } else if (index !== 0 || !opts.allowFirstEmptyAsInit) {
                        return;
                    }
                } else {
                    current = $('').html(name).attr('data-value', value);
                }

                // setup our initial selection
                if ((isSelected && opts.setSelected === true) || (opts.forceSelected === value)) {
                    selected.html(name);
                }

                if (current.length) {
                    widths.push(getSize(current.clone()));
                    items.append(current);
                }
            });

            //If nothing is set as selected, the fist item will be auto selected, just like a select box
            if (selected.text() === "") {
                selected
                    .html(items.find(":first-child").html())
                    .attr('data-value', items.find(":first-child").attr('data-value'));
            }
            // Append our items to the div
            dropSelect
                .append(selected)
                .append('
')
                .append(items);

            //we return 2 things, the element and the calculated width.
            return {
                element: dropSelect,
                width: Math.max.apply(null, widths)
            };
        }

        // Get the size of the element.
        function getSize(element) {
            if (!fakeEl) {
                fakeEl = $('').hide().appendTo(document.body);
            }
            fakeEl.empty();
            fakeEl.append(element);
            // easiest way is to multiply the outerwidth by 2, seems to work every time.
            return fakeEl.outerWidth(true) * 2;
        }

        // Get all the attributes of the selectbox, we'll add them back to the item.
        function getAttrs(element) {
            var attributes = {};

            if (element.length) {
                $.each(element[0].attributes, function( index, attr ) {
                    attributes[ attr.name ] = attr.value;
                } );
            }

            return attributes;
        }
    };

    // Here we override the val() function to obtain the value or null if not set.
    $.fn.val = function(value) {
        return $(this).find('.selected').attr('data-value') || null;
    };

    // The default options
    $.fn.dropSelect.defaults = {
        className: "dropSelect", //the class name to use
        arrowClass: "icon-arrow-down", // the class name for the down arrow
        callBack: null, // the callback function when an item is selected
        formatter: null, // a callback to allow user formatting of the inner text
        includeEmpties: false, // Should all empty items be included
        allowFirstEmptyAsInit: true, // If the first item is empty, include it as initial text
        setSelected: true, // match the selected attribute
        forceSelected: null, // value of item to force as selected
        width: "auto" //the css width or auto for calculated based on item length
    };

}(jQuery));<commit_msg>Whitespace fixes<commit_after>(function ($) {
    $.fn.dropSelect = function (options) {
        var opts = $.extend({}, $.fn.dropSelect.defaults, options),
            fakeEl;

        // Parse all items that meet the selector
        this.each(function () {
            var original = $(this),
                dropSelect = generate(original),
                width = (opts.width === "auto") ? dropSelect.width : opts.width;

            dropSelect = dropSelect.element;
            // We'll replace the element
            original.replaceWith(dropSelect);
            dropSelect.width(width);
            // Set the onclick handler of the items
            dropSelect.find('div.items a').on("click", function () {
                var $this = $(this),
                    display = $this.html(),
                    value = $this.data('value'),
                    selected = $this.parents().find('.selected');

                if (selected.attr('data-value') === value) {
                    return;
                }

                $this.siblings('.active').each(function () {
                    $(this).removeClass('active');
                });
                $this.addClass('active');
                selected.attr('data-value', value).html(display);
                if (typeof opts.callBack === "function") {
                    // Call the callback if it's set
                    opts.callBack(value);
                }
                // Trigger the change event.
                selected.parent().trigger("change");
            });
        });

        // For cleanup, we'll remove our fake sizing element
        if (fakeEl) {
            fakeEl.remove();
            fakeEl = null;
        }

        // This function will generate the divs used and add the appropriate classes.
        function generate(select) {
            var attrs = getAttrs(select),
                dropSelect = $('
'),
                items = $('
'),
                selected = $('
'),
                widths = [],
                attr;

            // Add the attributes from the select to the div
            for (attr in attrs) {
                if (!attrs.hasOwnProperty(attr)) {
                    continue;
                }
                dropSelect.attr(attr, attrs[attr]);
            }
            // Add our classname
            dropSelect.addClass(opts.className);

            // Parse all the options.
            select.find('option').each(function (index) {
                var $this = $(this),
                    value = $this.attr('value') || null,
                    name = ((typeof opts.formatter === "function") ? opts.formatter($this.text()) : $this.text()),
                    isSelected = $this.prop('selected'),
                    current = {};

                // We need to check how we handle empties based on the options.
                if (value === null) {
                    if (opts.includeEmpties) {
                        current = $('').html(name);
                    } else if (index !== 0 || !opts.allowFirstEmptyAsInit) {
                        return;
                    }
                } else {
                    current = $('').html(name).attr('data-value', value);
                }

                // Setup our initial selection
                if ((isSelected && opts.setSelected === true) || (opts.forceSelected === value)) {
                    selected.html(name);
                }

                if (current.length) {
                    widths.push(getSize(current.clone()));
                    items.append(current);
                }
            });

            // If nothing is set as selected, the fist item will be auto selected, just like a select box
            if (selected.text() === "") {
                selected
                    .html(items.find(":first-child").html())
                    .attr('data-value', items.find(":first-child").attr('data-value'));
            }
            // Append our items to the div
            dropSelect
                .append(selected)
                .append('
')
                .append(items);

            // We return 2 things, the element and the calculated width.
            return {
                element: dropSelect,
                width:   Math.max.apply(null, widths)
            };
        }

        // Get the size of the element.
        function getSize(element) {
            if (!fakeEl) {
                fakeEl = $('').hide().appendTo(document.body);
            }
            fakeEl.empty();
            fakeEl.append(element);
            // Easiest way is to multiply the outerwidth by 2, seems to work every time.
            return fakeEl.outerWidth(true) * 2;
        }

        // Get all the attributes of the selectbox, we'll add them back to the item.
        function getAttrs(element) {
            var attributes = {};

            if (element.length) {
                $.each(element[0].attributes, function (index, attr) {
                    attributes[attr.name] = attr.value;
                });
            }

            return attributes;
        }
    };

    // Here we override the val() function to obtain the value or null if not set.
    $.fn.val = function (value) {
        return $(this).find('.selected').attr('data-value') || null;
    };

    // The default options
    $.fn.dropSelect.defaults = {
        className:             "dropSelect", // The class name to use
        arrowClass:            "icon-arrow-down", // The class name for the down arrow
        callBack:              null, // The callback function when an item is selected
        formatter:             null, // A callback to allow user formatting of the inner text
        includeEmpties:        false, // Should all empty items be included
        allowFirstEmptyAsInit: true, // If the first item is empty, include it as initial text
        setSelected:           true, // Match the selected attribute
        forceSelected:         null, // Value of item to force as selected
        width:                 "auto" // The css width or auto for calculated based on item length
    };

}(jQuery));<|endoftext|>


<commit_before>import request from 'superagent';
import moment from 'moment';

export const ADD_TITLE = 'ADD_TITLE';
export const ADD_CONTENT = 'ADD_CONTENT';
export const ADD_PRIORITY = 'ADD_PRIORITY';
export const ADD_START_DATE = 'ADD_START_DATE';
export const ADD_START_TIME = 'ADD_START_TIME';
export const ADD_END_DATE = 'ADD_END_DATE';
export const ADD_END_TIME = 'ADD_END_TIME';
export const SAVE = 'SAVE';
export const SAVING = 'SAVING';
export const SAVED = 'SAVED';
export const UPDATED = 'UPDATED';
export const NOT_SAVED = 'NOT_SAVED';
const API_ENDPOINT = 'http://localhost:3000';

export function addTitleAction(title) {
  return {
    type: ADD_TITLE,
    title
  };
}

export function addContentAction(content) {
  return {
    type: ADD_CONTENT,
    content
  };
}

export function addPriorityAction(priority) {
  return {
    type: ADD_PRIORITY,
    priority
  };
}

export function addStartDateAction(startDate) {
  return {
    type: ADD_START_DATE,
    startDate
  };
}

export function addStartTimeAction(startTime) {
  return {
    type: ADD_START_TIME,
    startTime
  };
}

export function addEndDateAction(endDate) {
  return {
    type: ADD_END_DATE,
    endDate
  };
}

export function addEndTimeAction(endTime) {
  return {
    type: ADD_END_TIME,
    endTime
  };
}

function _savingAction() {
  return {
    type: SAVING
  };
}

function _savedAction(event) {
  return {
    type: SAVED,
    event
  };
}

function _updatedAction(event) {
  return {
    type: UPDATED,
    event
  };
}

function _notSavedAction() {
  return {
    type: NOT_SAVED
  };
}

export function saveAction(data) {
  return dispatch => {
    dispatch(_savingAction());
    return request.post(API_ENDPOINT + '/event')
    .send(data)
    .end(function(err, res) {
      if(res && res.body.status !== 'error') {
        dispatch(_savedAction(res.body));
      } else {
        dispatch(_notSavedAction());
      }
    });
  };
}

export function updateAction(data) {
  return dispatch => {
    dispatch(_savingAction());
    return request.put(API_ENDPOINT + '/event/' + data._id)
    .send(data)
    .end(function(err, res) {
      if(res && res.body.status !== 'error') {
        dispatch(_updatedAction(data));
      } else {
        dispatch(_notSavedAction());
      }
    });
  };
}
<commit_msg>Update addActions.js<commit_after>import request from 'superagent';
import moment from 'moment';

export const ADD_TITLE = 'ADD_TITLE';
export const ADD_CONTENT = 'ADD_CONTENT';
export const ADD_PRIORITY = 'ADD_PRIORITY';
export const ADD_START_DATE = 'ADD_START_DATE';
export const ADD_START_TIME = 'ADD_START_TIME';
export const ADD_END_DATE = 'ADD_END_DATE';
export const ADD_END_TIME = 'ADD_END_TIME';
export const SAVE = 'SAVE';
export const SAVING = 'SAVING';
export const SAVED = 'SAVED';
export const UPDATED = 'UPDATED';
export const NOT_SAVED = 'NOT_SAVED';
const API_ENDPOINT = 'http://130.233.42.72:3000';

export function addTitleAction(title) {
  return {
    type: ADD_TITLE,
    title
  };
}

export function addContentAction(content) {
  return {
    type: ADD_CONTENT,
    content
  };
}

export function addPriorityAction(priority) {
  return {
    type: ADD_PRIORITY,
    priority
  };
}

export function addStartDateAction(startDate) {
  return {
    type: ADD_START_DATE,
    startDate
  };
}

export function addStartTimeAction(startTime) {
  return {
    type: ADD_START_TIME,
    startTime
  };
}

export function addEndDateAction(endDate) {
  return {
    type: ADD_END_DATE,
    endDate
  };
}

export function addEndTimeAction(endTime) {
  return {
    type: ADD_END_TIME,
    endTime
  };
}

function _savingAction() {
  return {
    type: SAVING
  };
}

function _savedAction(event) {
  return {
    type: SAVED,
    event
  };
}

function _updatedAction(event) {
  return {
    type: UPDATED,
    event
  };
}

function _notSavedAction() {
  return {
    type: NOT_SAVED
  };
}

export function saveAction(data) {
  return dispatch => {
    dispatch(_savingAction());
    return request.post(API_ENDPOINT + '/event')
    .send(data)
    .end(function(err, res) {
      if(res && res.body.status !== 'error') {
        dispatch(_savedAction(res.body));
      } else {
        dispatch(_notSavedAction());
      }
    });
  };
}

export function updateAction(data) {
  return dispatch => {
    dispatch(_savingAction());
    return request.put(API_ENDPOINT + '/event/' + data._id)
    .send(data)
    .end(function(err, res) {
      if(res && res.body.status !== 'error') {
        dispatch(_updatedAction(data));
      } else {
        dispatch(_notSavedAction());
      }
    });
  };
}
<|endoftext|>


<commit_before>import SegmentTrieNode from './segment-trie/segment-trie-node';
import DynamicSegment from './segment-trie/dynamic-segment';
import EpsilonSegment from './segment-trie/epsilon-segment';
import GlobNode from './segment-trie/glob-node';
import StaticSegment from './segment-trie/static-segment';

import { bind } from './polyfills';

function buildSegmentTrieNode(router, value) {
  if (value === undefined) {
    return new EpsilonSegment(...arguments);
  }
  switch (value.charCodeAt(0)) {
    case 58: return new DynamicSegment(router, value.substr(1)); // : => 58
    case 42: return new GlobNode(router, value.substr(1)); // * => 42
    default: return new StaticSegment(router, value);
  }
}

function matcher(source) {
  return function matcher(path, callback) {
    var leaf = this;
    path = path.replace(/^[\/]*/, '');
    path = path.replace(/[\/]*$/, '');

    var segments;
    if (path === '') {
      // Gets an epsilon segment.
      segments = [ undefined ];
    } else {
      segments = path.split('/');
    }

    // As we're adding segments we need to track the current leaf.
    for (var i = 0; i < segments.length; i++) {
      segments[i] = buildSegmentTrieNode(this.router, segments[i]);

      leaf = leaf.append(segments[i]);
    }

    if (callback) {
      // No handler, delegate back to the TrieNode's `to` method.
      leaf.to(undefined, callback, source);
    }

    return leaf;
  };
}

// So, this is sad, but we don't get circular references that do the right thing.
SegmentTrieNode.prototype.to = function to(handler, callback, source) {
  this.handler = handler;

  if (handler && this.router.addRouteCallback && source !== 'add') {
    var routes = [];
    var segmentTrieNode = this;
    var prefix = '';

    do {
      // We've found a new handler, start building it up again.
      if (segmentTrieNode.handler) {
        routes.unshift({
          path: '',
          handler: segmentTrieNode.handler
        });
      }

      switch (segmentTrieNode.type) {
        case 'dynamic': prefix = '/:'; break;
        case 'glob': prefix = '/*'; break;
        case 'epsilon': prefix = ''; break;
        default:
        case 'static':
          prefix = '/';
        break;
      }
      if (segmentTrieNode.type === 'epsilon' && routes[0].path === '') {
        routes[0].path = '/';
      }
      if (segmentTrieNode.type !== 'epsilon') {
        routes[0].path = prefix + segmentTrieNode.value + routes[0].path;
      }
    } while (segmentTrieNode = segmentTrieNode.parent);

    this.router.addRouteCallback(this.router, routes);
  }

  if (callback) {
    if (callback.length === 0) { throw new Error("You must have an argument in the function passed to `to`"); }
    callback(bind(matcher(source), this));
  }

  return this;
};

export { matcher };
<commit_msg>Consolidate again on adding a handler.<commit_after>import SegmentTrieNode from './segment-trie/segment-trie-node';
import DynamicSegment from './segment-trie/dynamic-segment';
import EpsilonSegment from './segment-trie/epsilon-segment';
import GlobNode from './segment-trie/glob-node';
import StaticSegment from './segment-trie/static-segment';

import { bind } from './polyfills';

function buildSegmentTrieNode(router, value) {
  if (value === undefined) {
    return new EpsilonSegment(...arguments);
  }
  switch (value.charCodeAt(0)) {
    case 58: return new DynamicSegment(router, value.substr(1)); // : => 58
    case 42: return new GlobNode(router, value.substr(1)); // * => 42
    default: return new StaticSegment(router, value);
  }
}

function matcher(source) {
  return function matcher(path, callback) {
    var leaf = this;
    path = path.replace(/^[\/]*/, '');
    path = path.replace(/[\/]*$/, '');

    var segments;
    if (path === '') {
      // Gets an epsilon segment.
      segments = [ undefined ];
    } else {
      segments = path.split('/');
    }

    // As we're adding segments we need to track the current leaf.
    for (var i = 0; i < segments.length; i++) {
      segments[i] = buildSegmentTrieNode(this.router, segments[i]);

      leaf = leaf.append(segments[i]);
    }

    if (callback) {
      // No handler, delegate back to the TrieNode's `to` method.
      leaf.to(undefined, callback, source);
    }

    return leaf;
  };
}

// So, this is sad, but we don't get circular references that do the right thing.
SegmentTrieNode.prototype.to = function to(handler, callback, source) {
  this.handler = handler;

  var targetNode = this._existingOrSelf();
  if (targetNode !== this) {
    this.haystack = this.haystack.splice(this.haystack.indexOf(this), 1);
    this.router.nodes[this.id] = undefined;
    return targetNode;
  }

  if (handler && this.router.addRouteCallback && source !== 'add') {
    var routes = [];
    var segmentTrieNode = this;
    var prefix = '';

    do {
      // We've found a new handler, start building it up again.
      if (segmentTrieNode.handler) {
        routes.unshift({
          path: '',
          handler: segmentTrieNode.handler
        });
      }

      switch (segmentTrieNode.type) {
        case 'dynamic': prefix = '/:'; break;
        case 'glob': prefix = '/*'; break;
        case 'epsilon': prefix = ''; break;
        default:
        case 'static':
          prefix = '/';
        break;
      }
      if (segmentTrieNode.type === 'epsilon' && routes[0].path === '') {
        routes[0].path = '/';
      }
      if (segmentTrieNode.type !== 'epsilon') {
        routes[0].path = prefix + segmentTrieNode.value + routes[0].path;
      }
    } while (segmentTrieNode = segmentTrieNode.parent);

    this.router.addRouteCallback(this.router, routes);
  }

  if (callback) {
    if (callback.length === 0) { throw new Error("You must have an argument in the function passed to `to`"); }
    callback(bind(matcher(source), this));
  }

  return this;
};

export { matcher };
<|endoftext|>


<commit_before>/* global Mousetrap */

import Ember from 'ember';

export default function(bindEvent, unbindEvent) {

  return Ember.Mixin.create({
    mousetraps:[],
    bindShortcuts: Ember.on(bindEvent, function() {
      const shortcuts = this.get('keyboardShortcuts');

      if (Ember.typeOf(shortcuts) !== 'object') {
        return;
      }

      this.mousetraps = [];

      Object.keys(shortcuts).forEach((shortcut) => {
        const actionObject   = shortcuts[shortcut];
        let mousetrap;
        let preventDefault = true;

        const invokeAction = (action, eventType) => {
          const type = Ember.typeOf(action);
          let   callback;
          if (type === 'string') {
            callback = function(){
              this.send(action);
              return preventDefault !== true;
            }
          }
          else if (type === 'function') {
            callback = action.bind(this)
          }
          else {
            throw new Error('Invalid value for keyboard shortcut: ' + action);
          }
          mousetrap.bind(shortcut, callback, eventType);
        }

        if (Ember.typeOf(actionObject) === 'object') {
          if (actionObject.global === false) {
            mousetrap = new Mousetrap(document.body);
          } else if (actionObject.scoped) {
            if (Ember.typeOf(actionObject.scoped) === 'boolean') {
              mousetrap = new Mousetrap(this.get('element'));
            } else if (Ember.typeOf(actionObject.scoped) === 'string') {
              mousetrap = new Mousetrap(document.querySelector(actionObject.scoped));
            }
          } else if (actionObject.targetElement) {
            mousetrap = new Mousetrap(actionObject.targetElement);
          }
          if (actionObject.preventDefault === false) {
            preventDefault = false;
          }
          invokeAction(actionObject.action, actionObject.eventType);
        } else {
          mousetrap = new Mousetrap(document.body);
          invokeAction(actionObject);
        }
        this.mousetraps.push(mousetrap);
      });

    }),

    unbindShortcuts: Ember.on(unbindEvent, function() {
      const _removeEvent = (object, type, callback) => {
        if (object.removeEventListener) {
          object.removeEventListener(type, callback, false);
          return;
        }
        object.detachEvent('on' + type, callback);
      }
      this.mousetraps.forEach(
        (mousetrap) => {
          // manually unbind JS event
          _removeEvent(mousetrap.target, 'keypress', mousetrap._handleKeyEvent);
          _removeEvent(mousetrap.target, 'keydown', mousetrap._handleKeyEvent);
          _removeEvent(mousetrap.target, 'keyup', mousetrap._handleKeyEvent);
          mousetrap.reset()
        }
      );
      this.mousetraps = []
    })

  });

}
<commit_msg>fix another this issue<commit_after>/* global Mousetrap */

import Ember from 'ember';

export default function(bindEvent, unbindEvent) {

  return Ember.Mixin.create({
    mousetraps:[],
    bindShortcuts: Ember.on(bindEvent, function() {
      const shortcuts = this.get('keyboardShortcuts');

      if (Ember.typeOf(shortcuts) !== 'object') {
        return;
      }

      this.mousetraps = [];

      Object.keys(shortcuts).forEach((shortcut) => {
        const actionObject   = shortcuts[shortcut];
        let mousetrap;
        let preventDefault = true;

        const invokeAction = (action, eventType) => {
          const type = Ember.typeOf(action);
          let   callback;
          if (type === 'string') {
            callback = () => {
              this.send(action);
              return preventDefault !== true;
            }
          }
          else if (type === 'function') {
            callback = action.bind(this)
          }
          else {
            throw new Error('Invalid value for keyboard shortcut: ' + action);
          }
          mousetrap.bind(shortcut, callback, eventType);
        }

        if (Ember.typeOf(actionObject) === 'object') {
          if (actionObject.global === false) {
            mousetrap = new Mousetrap(document.body);
          } else if (actionObject.scoped) {
            if (Ember.typeOf(actionObject.scoped) === 'boolean') {
              mousetrap = new Mousetrap(this.get('element'));
            } else if (Ember.typeOf(actionObject.scoped) === 'string') {
              mousetrap = new Mousetrap(document.querySelector(actionObject.scoped));
            }
          } else if (actionObject.targetElement) {
            mousetrap = new Mousetrap(actionObject.targetElement);
          }
          if (actionObject.preventDefault === false) {
            preventDefault = false;
          }
          invokeAction(actionObject.action, actionObject.eventType);
        } else {
          mousetrap = new Mousetrap(document.body);
          invokeAction(actionObject);
        }
        this.mousetraps.push(mousetrap);
      });

    }),

    unbindShortcuts: Ember.on(unbindEvent, function() {
      const _removeEvent = (object, type, callback) => {
        if (object.removeEventListener) {
          object.removeEventListener(type, callback, false);
          return;
        }
        object.detachEvent('on' + type, callback);
      }
      this.mousetraps.forEach(
        (mousetrap) => {
          // manually unbind JS event
          _removeEvent(mousetrap.target, 'keypress', mousetrap._handleKeyEvent);
          _removeEvent(mousetrap.target, 'keydown', mousetrap._handleKeyEvent);
          _removeEvent(mousetrap.target, 'keyup', mousetrap._handleKeyEvent);
          mousetrap.reset()
        }
      );
      this.mousetraps = []
    })

  });

}
<|endoftext|>


<commit_before>// -------------------------------------------------------------------------- \\
// File: GlobalKeyboardShortcuts.js                                           \\
// Module: Application                                                        \\
// Requires: Core, Foundation                                                 \\
// Author: Neil Jenkins                                                       \\
// License: © 2010–2012 Opera Software ASA. All rights reserved.              \\
// -------------------------------------------------------------------------- \\

"use strict";

( function ( NS ) {
/**
    Class: O.GlobalKeyboardShortcuts

    Extends: O.Object

    This class facilitates adding keyboard shortcuts to your application.
*/
var GlobalKeyboardShortcuts = NS.Class({

    Extends: NS.Object,

    /**
        Property: O.GlobalKeyboardShortcuts#isEnabled
        Type: Boolean
        Default: true

        Callbacks will only fire if this property is true when the instance
        handles the event.
    */
    isEnabled: true,

    /**
        Property (private): O.GlobalKeyboardShortcuts#_shortcuts
        Type: Object

        The map of shortcut key to an array of `[object, method]` tuples.
    */

    /**
        Constructor: O.GlobalKeyboardShortcuts
    */
    init: function ( options ) {
        this._shortcuts = {};
        GlobalKeyboardShortcuts.parent.init.call( this, options );
        var RootViewController = NS.RootViewController;
        RootViewController.kbShortcuts = this;
        RootViewController.queueResponder( this );
    },

    /**
        Method: O.GlobalKeyboardShortcuts#destroy

        Destructor.
    */
    destroy: function () {
        var RootViewController = NS.RootViewController;
        if ( RootViewController.kbShortcuts === this ) {
            delete NS.RootViewController.kbShortcuts;
        }
        RootViewController.removeResponder( this );
        GlobalKeyboardShortcuts.parent.destroy.call( this );
    },

    /**
        Method: O.GlobalKeyboardShortcuts#register

        Add a global keyboard shortcut. If a shortcut has already been
        registered for this key, it will be replaced, but will be restored when
        the new handler is removed.

        Parameters:
            key    - {String} The key to trigger the callback on. Modifier keys
                     (alt, ctrl, meta, shift) should be prefixed in alphabetical
                     order and with a hypen after each one. Letters should be
                     lower case. e.g. `ctrl-f`.
            object - {Object} The object to trigger the callback on.
            method - {String} The name of the method to trigger.

        Returns:
            {O.GlobalKeyboardShortcuts} Returns self.
    */
    register: function ( key, object, method ) {
        var shortcuts = this._shortcuts;
        ( shortcuts[ key ] || ( shortcuts[ key ] = [] ) )
            .push([ object, method ]);
        return this;
    },

    /**
        Method: O.GlobalKeyboardShortcuts#deregister

        Remove a global keyboard shortcut. Must use identical arguments to those
        which were used in the call to <O.GlobalKeyboardShortcuts#register>.

        Parameters:
            key    - {String} The key on which the callback was triggered.
            object - {Object} The object on which the callback was triggered.
            method - {String} The name of the method that was being triggered.

        Returns:
            {O.GlobalKeyboardShortcuts} Returns self.
   */
    deregister: function ( key, object, method ) {
        var current = this._shortcuts[ key ],
            length = current ? current.length : 0,
            l = length,
            item;
        while ( l-- ) {
            item = current[l];
            if ( item[0] === object && item[1] === method ) {
                if ( length === 1 ) {
                    delete this._shortcuts[ key ];
                } else {
                    current.splice( l, 1 );
                }
            }
        }
        return this;
    },

    /**
        Method: O.GlobalKeyboardShortcuts#getHandlerForKey

        Get the keyboard shortcut to be triggered by a key combo, represented as
        a string, as output by <O.DOMEvent#lookupKey>.

        Parameters:
            key - {String} The key combo to get the handler for.

        Returns:
            {Array|null} Returns the [ object, method ] tuple to be triggered by
            the event, or null if nothing is registered for this key press.
   */
    getHandlerForKey: function ( key ) {
        var shortcuts = this._shortcuts[ key ];
        if ( shortcuts && this.get( 'isEnabled' ) ) {
            return shortcuts[ shortcuts.length - 1 ];
        }
        return null;
    },

    /**
        Method (private): O.GlobalKeyboardShortcuts#_trigger

        Keypress event handler. Triggers any registered callback.

        Parameters:
            event - {DOMEvent} The keypress event.
   */
    _trigger: function ( event ) {
        var nodeName = event.target.nodeName;
        if ( ( nodeName === 'TEXTAREA' || nodeName === 'INPUT' ||
                ( event.targetView instanceof NS.RichTextView ) ) &&
                !( event.ctrlKey || event.metaKey ) ) {
            return;
        }
        var key = NS.DOMEvent.lookupKey( event ),
            isSpecialKey = ( key.lastIndexOf( '-' ) + 2 < key.length ),
            // Handle special keys on keydown, character keys on keypress
            handler = ( event.type === 'keydown' ) === isSpecialKey ?
                this.getHandlerForKey( key ) : null;
        if ( handler ) {
            handler[0][ handler[1] ]( event );
            event.preventDefault();
        }
    }.on( 'keypress', 'keydown' )
});

NS.GlobalKeyboardShortcuts = GlobalKeyboardShortcuts;

}( this.O ) );
<commit_msg>Fix Keyboard shortcuts firing when input focussed.<commit_after>// -------------------------------------------------------------------------- \\
// File: GlobalKeyboardShortcuts.js                                           \\
// Module: Application                                                        \\
// Requires: Core, Foundation                                                 \\
// Author: Neil Jenkins                                                       \\
// License: © 2010–2012 Opera Software ASA. All rights reserved.              \\
// -------------------------------------------------------------------------- \\

"use strict";

( function ( NS ) {

var allowedInputs = {
    checkbox: 1,
    radio: 1,
    file: 1,
    submit: 1
};

/**
    Class: O.GlobalKeyboardShortcuts

    Extends: O.Object

    This class facilitates adding keyboard shortcuts to your application.
*/
var GlobalKeyboardShortcuts = NS.Class({

    Extends: NS.Object,

    /**
        Property: O.GlobalKeyboardShortcuts#isEnabled
        Type: Boolean
        Default: true

        Callbacks will only fire if this property is true when the instance
        handles the event.
    */
    isEnabled: true,

    /**
        Property (private): O.GlobalKeyboardShortcuts#_shortcuts
        Type: Object

        The map of shortcut key to an array of `[object, method]` tuples.
    */

    /**
        Constructor: O.GlobalKeyboardShortcuts
    */
    init: function ( options ) {
        this._shortcuts = {};
        GlobalKeyboardShortcuts.parent.init.call( this, options );
        var RootViewController = NS.RootViewController;
        RootViewController.kbShortcuts = this;
        RootViewController.queueResponder( this );
    },

    /**
        Method: O.GlobalKeyboardShortcuts#destroy

        Destructor.
    */
    destroy: function () {
        var RootViewController = NS.RootViewController;
        if ( RootViewController.kbShortcuts === this ) {
            delete NS.RootViewController.kbShortcuts;
        }
        RootViewController.removeResponder( this );
        GlobalKeyboardShortcuts.parent.destroy.call( this );
    },

    /**
        Method: O.GlobalKeyboardShortcuts#register

        Add a global keyboard shortcut. If a shortcut has already been
        registered for this key, it will be replaced, but will be restored when
        the new handler is removed.

        Parameters:
            key    - {String} The key to trigger the callback on. Modifier keys
                     (alt, ctrl, meta, shift) should be prefixed in alphabetical
                     order and with a hypen after each one. Letters should be
                     lower case. e.g. `ctrl-f`.
            object - {Object} The object to trigger the callback on.
            method - {String} The name of the method to trigger.

        Returns:
            {O.GlobalKeyboardShortcuts} Returns self.
    */
    register: function ( key, object, method ) {
        var shortcuts = this._shortcuts;
        ( shortcuts[ key ] || ( shortcuts[ key ] = [] ) )
            .push([ object, method ]);
        return this;
    },

    /**
        Method: O.GlobalKeyboardShortcuts#deregister

        Remove a global keyboard shortcut. Must use identical arguments to those
        which were used in the call to <O.GlobalKeyboardShortcuts#register>.

        Parameters:
            key    - {String} The key on which the callback was triggered.
            object - {Object} The object on which the callback was triggered.
            method - {String} The name of the method that was being triggered.

        Returns:
            {O.GlobalKeyboardShortcuts} Returns self.
   */
    deregister: function ( key, object, method ) {
        var current = this._shortcuts[ key ],
            length = current ? current.length : 0,
            l = length,
            item;
        while ( l-- ) {
            item = current[l];
            if ( item[0] === object && item[1] === method ) {
                if ( length === 1 ) {
                    delete this._shortcuts[ key ];
                } else {
                    current.splice( l, 1 );
                }
            }
        }
        return this;
    },

    /**
        Method: O.GlobalKeyboardShortcuts#getHandlerForKey

        Get the keyboard shortcut to be triggered by a key combo, represented as
        a string, as output by <O.DOMEvent#lookupKey>.

        Parameters:
            key - {String} The key combo to get the handler for.

        Returns:
            {Array|null} Returns the [ object, method ] tuple to be triggered by
            the event, or null if nothing is registered for this key press.
   */
    getHandlerForKey: function ( key ) {
        var shortcuts = this._shortcuts[ key ];
        if ( shortcuts && this.get( 'isEnabled' ) ) {
            return shortcuts[ shortcuts.length - 1 ];
        }
        return null;
    },

    /**
        Method (private): O.GlobalKeyboardShortcuts#_trigger

        Keypress event handler. Triggers any registered callback.

        Parameters:
            event - {DOMEvent} The keypress event.
   */
    _trigger: function ( event ) {
        var target = event.target,
            nodeName = target.nodeName;
        if ( ( nodeName === 'TEXTAREA' ||
                ( nodeName === 'INPUT' && !allowedInputs[ target.type ] ) ||
                ( event.targetView instanceof NS.RichTextView )
             ) && !( event.ctrlKey || event.metaKey ) ) {
            return;
        }
        var key = NS.DOMEvent.lookupKey( event ),
            isSpecialKey = ( key.lastIndexOf( '-' ) + 2 < key.length ),
            // Handle special keys on keydown, character keys on keypress
            handler = ( event.type === 'keydown' ) === isSpecialKey ?
                this.getHandlerForKey( key ) : null;
        if ( handler ) {
            handler[0][ handler[1] ]( event );
            event.preventDefault();
        }
    }.on( 'keypress', 'keydown' )
});

NS.GlobalKeyboardShortcuts = GlobalKeyboardShortcuts;

}( this.O ) );
<|endoftext|>


<commit_before>define([
  'jquery',
  'underscore',
  'backbone',
  'mockup-ui-url/views/popover',
  'translate',
  'pat-registry'
], function($, _, Backbone, PopoverView, _t, registry) {
  'use strict';

  var PropertiesView = PopoverView.extend({
    events: {
      'click button.applyBtn': 'applyButtonClicked'
    },
    submitText: _t('Apply'),
    initialize: function(options) {
      var self = this;
      self.app = options.app;
      self.className = 'popover ' + options.id;
      self.title = options.form.title || options.title;
      self.submitText = options.form.submitText || _t('Apply');
      self.submitContext = options.form.submitContext || 'primary';
      self.data = {};

      self.content = _.template('<form>' + options.form.template + '</form>' +
        '<button class="btn btn-block btn-' + self.submitContext + ' applyBtn">' + self.submitText + ' </button>');

      PopoverView.prototype.initialize.apply(this, [options]);
    },
    getTemplateOptions: function(){
      var self = this;
      var items = [];
      self.app.selectedCollection.each(function(item){
        items.push(item.toJSON());
      });
      return $.extend({}, true, self.options, {
        items: items,
        data: self.data
      });
    },
    applyButtonClicked: function() {
      var self = this;
      var data = {};
      _.each(self.$el.find('form').serializeArray(), function(param){
        data[param.name] = param.value;
      });
      this.app.buttonClickEvent(this.triggerView, data);
      this.hide();
    },
    afterRender: function(){
      var self = this;
      if(self.options.form.dataUrl){
        $.ajax({
          url: self.options.form.dataUrl,
          dataType: 'json',
          type: 'POST',
          data: {
            selection: JSON.stringify(self.app.getSelectedUids()),
            transitions: true,
            render: 'yes'
          }
        }).done(function(data){
          self.data = data;
          self.renderContent();
          registry.scan(self.$el);
        });
      }else{
        registry.scan(self.$el);
      }
    },
    toggle: function(button, e) {
      PopoverView.prototype.toggle.apply(this, [button, e]);
      var self = this;
      if (!self.opened) {
        return;
      }else{
        this.$el.replaceWith(this.render().el);
      }
    }
  });

  return PropertiesView;
});
<commit_msg>be able to provide close btn for generic popover<commit_after>define([
  'jquery',
  'underscore',
  'backbone',
  'mockup-ui-url/views/popover',
  'translate',
  'pat-registry'
], function($, _, Backbone, PopoverView, _t, registry) {
  'use strict';

  var PropertiesView = PopoverView.extend({
    events: {
      'click button.applyBtn': 'applyButtonClicked',
      'click button.closeBtn': 'toggle'
    },
    submitText: _t('Apply'),
    initialize: function(options) {
      var self = this;
      self.app = options.app;
      self.className = 'popover ' + options.id;
      self.title = options.form.title || options.title;
      self.submitText = options.form.submitText || _t('Apply');
      self.submitContext = options.form.submitContext || 'primary';
      self.data = {};

      var html = '<form>' + options.form.template + '</form>' +
        '<button class="btn btn-block btn-' + self.submitContext + ' applyBtn">' + self.submitText + ' </button>';
      if(options.form.closeText){
        html += '<button class="btn btn-block btn-default closeBtn">' + options.form.closeText + ' </button>';
      }
      self.content = _.template(html);

      PopoverView.prototype.initialize.apply(this, [options]);
    },
    getTemplateOptions: function(){
      var self = this;
      var items = [];
      self.app.selectedCollection.each(function(item){
        items.push(item.toJSON());
      });
      return $.extend({}, true, self.options, {
        items: items,
        data: self.data
      });
    },
    applyButtonClicked: function() {
      var self = this;
      var data = {};
      _.each(self.$el.find('form').serializeArray(), function(param){
        data[param.name] = param.value;
      });
      this.app.buttonClickEvent(this.triggerView, data);
      this.hide();
    },
    afterRender: function(){
      var self = this;
      if(self.options.form.dataUrl){
        $.ajax({
          url: self.options.form.dataUrl,
          dataType: 'json',
          type: 'POST',
          data: {
            selection: JSON.stringify(self.app.getSelectedUids()),
            transitions: true,
            render: 'yes'
          }
        }).done(function(data){
          self.data = data;
          self.renderContent();
          registry.scan(self.$el);
        });
      }else{
        registry.scan(self.$el);
      }
    },
    toggle: function(button, e) {
      PopoverView.prototype.toggle.apply(this, [button, e]);
      var self = this;
      if (!self.opened) {
        return;
      }else{
        this.$el.replaceWith(this.render().el);
      }
    }
  });

  return PropertiesView;
});
<|endoftext|>


<commit_before>'use strict';

const Promise = require('bluebird');
const catalog = require('../../broker/lib/models/catalog');
const eventmesh = require('../../eventmesh');
const config = require('../../common/config');
const logger = require('../../common/logger');
const CONST = require('../../common/constants');
const bm = require('./');
const BaseManager = require('../BaseManager');
const DBManager = require('../../broker/lib/fabrik/DBManager');
const errors = require('../../common/errors');
const Conflict = errors.Conflict;

/* jshint nonew:false */
new DBManager(); //to start the BnRStatusPoller

class DefaultBackupManager extends BaseManager {

  static _processBackup(changeObjectBody) {
    const changedOptions = JSON.parse(changeObjectBody.spec.options);
    logger.info('Triggering backup with the following options:', changedOptions);
    const plan = catalog.getPlan(changedOptions.plan_id);
    return bm.createManager(plan)
      .then(manager => manager.startBackup(changedOptions));
  }

  static _processAbort(changeObjectBody) {
    const changedOptions = JSON.parse(changeObjectBody.spec.options);
    return eventmesh.apiServerClient.getOperationOptions({
        resourceId: changedOptions.instance_guid,
        operationName: CONST.APISERVER.ANNOTATION_NAMES.BACKUP,
        operationType: CONST.APISERVER.ANNOTATION_TYPES.BACKUP,
        operationId: changedOptions.guid
      })
      .then(options => {
        return Promise.try(() => {
          const plan = catalog.getPlan(options.plan_id);
          return bm.createManager(plan);
        }).then(manager => manager.abortLastBackup(options));
      });
  }

  static _processDelete(changeObjectBody) {
    const changedOptions = JSON.parse(changeObjectBody.spec.options);
    return eventmesh.apiServerClient.getOperationOptions({
        resourceId: changedOptions.instance_guid,
        operationName: CONST.APISERVER.ANNOTATION_NAMES.BACKUP,
        operationType: CONST.APISERVER.ANNOTATION_TYPES.BACKUP,
        operationId: changedOptions.guid
      })
      .then(options => {
        return Promise.try(() => {
          const plan = catalog.getPlan(options.plan_id);
          return bm.createManager(plan);
        }).then(manager => manager.deleteBackup(options));
      });
  }

  /**
   * @description Registers backup watcher with worker callback
   */
  // Register watcher is refreshed every 20 mins as API Server has a min time out of 30 mins after which it closes the watch.
  //TODO-PR - Extract it in a different function
  registerWatcher() {
    logger.debug(`Registering Backup watcher`);
    const queryString = `state in (${CONST.APISERVER.RESOURCE_STATE.IN_QUEUE},${CONST.OPERATION.ABORT},${CONST.APISERVER.RESOURCE_STATE.DELETE})`;
    return eventmesh.apiServerClient.registerWatcher('backup', 'defaultbackup', this.worker, queryString)
      .then(stream => {
        logger.info(`Successfully set watcher with query string:`, queryString);
        return setTimeout(() => {
          try {
            logger.info(`Refreshing stream after ${CONST.APISERVER.WATCHER_REFRESH_INTERVAL}`);
            stream.abort();
            return this.registerWatcher();
          } catch (err) {
            logger.error('Error caught in the set timout callback');
            throw err;
          }
        }, CONST.APISERVER.WATCHER_REFRESH_INTERVAL);
      })
      .catch(e => {
        logger.error('Failed registering watcher with error:', e);
        throw e;
      });
  }
  /**
   * @description This method does following in order
   * 1. Tries to acquire processing lock => In case of HA, Only one backup manager process will process the request
   * 2. Processes the request based on the state of the changed resource
   * 3. Release processing lock
   * @param {object} change - Change object that comes as part of apiserver watch event
   */

  //TODO-PR - Move the locking part of the code as part of the Base Manager,
  //Use something like this.
  // handleResource(change){
  // return this._preProcessResource(change)
  //             .then(()=> this.processResource(change))
  //             .then(()=> this.postProcessResource(change))
  //              .catch((err)=> logger.error(`Error occurred ....`)); //Dont need to care what type of error just log.
  //                //see if this can be put in finally.
  // }

  // _preProcessResource(){
  // //Code about acquiring processing lock goes here.
  // }

  // processResource(change){
  //   throw 'Must be implemented by subclass'; // Individual base manage managers just implement this.
  // }
  // _postProcessResource(){
  //  //code to handle release processing lock  goes here.
  // }
  worker(change) {

    logger.debug('Changed Resource:', change);
    logger.debug('Changed resource options:', change.object.spec.options);
    const changeObjectBody = change.object;
    const changedOptions = JSON.parse(changeObjectBody.spec.options);
    logger.debug('Changed resource options(parsed):', changedOptions);
    let processingLockConflict = false;
    if (changeObjectBody.metadata.annotations && changeObjectBody.metadata.annotations.lockedByManager === config.broker_ip) {
      // Don't have to process as this is event generated by acquireProcessLock
      logger.debug(`Backup request for guid ${changedOptions.guid} is already being processed by process with ip ${changeObjectBody.metadata.annotations.lockedByManager}`);
    } else {
      // Acquire processing lock so that in HA scenerio, only one backup-manager process processes the request
      return Promise.try(() => {
          if (!changeObjectBody.metadata.annotations || changeObjectBody.metadata.annotations.lockedByManager === '') {
            return BaseManager.acquireProcessingLock(changeObjectBody)
              .catch(err => {
                if (err instanceof Conflict) {
                  processingLockConflict = true;
                  logger.info(`Not able to acquire processing lock, Backup request for guid ${changedOptions.guid} is probably picked by other worker`);
                } else {
                  logger.error(`Error while trying to get processing lock for backup with guid ${changedOptions.guid}`, err);
                }
                throw err;
              });
          } else {
            processingLockConflict = true;
            logger.info(`Backup request for guid ${changedOptions.guid} is picked by other process with ip ${changeObjectBody.metadata.annotations.lockedByManager}`);
          }
        })
        .then(() => {
          if (!processingLockConflict) {
            if (changeObjectBody.status.state === CONST.APISERVER.RESOURCE_STATE.IN_QUEUE) {
              return DefaultBackupManager._processBackup(changeObjectBody);
            } else if (changeObjectBody.status.state === CONST.OPERATION.ABORT) {
              return DefaultBackupManager._processAbort(changeObjectBody);
            } else if (changeObjectBody.status.state === CONST.APISERVER.RESOURCE_STATE.DELETE) {
              return DefaultBackupManager._processDelete(changeObjectBody);
            }
          }
        })
        .catch(e => {
          // If conflict error is in acquiring processingLock then don't throw error
          if (!processingLockConflict) {
            logger.error(`Caught error while starting backup ${changedOptions.guid}`, e);
          }
        })
        .then(() => {
          if (!processingLockConflict) {
            return BaseManager.releaseProcessingLock(changeObjectBody)
              .catch(e => logger.error(`Caught error while releasing processing lock ${changedOptions}:`, e));
          }
        });
    }
  }
}

const defaultBackupManager = new DefaultBackupManager();
defaultBackupManager.registerWatcher();<commit_msg>Fix method name<commit_after>'use strict';

const Promise = require('bluebird');
const catalog = require('../../broker/lib/models/catalog');
const eventmesh = require('../../eventmesh');
const config = require('../../common/config');
const logger = require('../../common/logger');
const CONST = require('../../common/constants');
const bm = require('./');
const BaseManager = require('../BaseManager');
const DBManager = require('../../broker/lib/fabrik/DBManager');
const errors = require('../../common/errors');
const Conflict = errors.Conflict;

/* jshint nonew:false */
new DBManager(); //to start the BnRStatusPoller

class DefaultBackupManager extends BaseManager {

  static _processBackup(changeObjectBody) {
    const changedOptions = JSON.parse(changeObjectBody.spec.options);
    logger.info('Triggering backup with the following options:', changedOptions);
    const plan = catalog.getPlan(changedOptions.plan_id);
    return bm.createService(plan)
      .then(manager => manager.startBackup(changedOptions));
  }

  static _processAbort(changeObjectBody) {
    const changedOptions = JSON.parse(changeObjectBody.spec.options);
    return eventmesh.apiServerClient.getOperationOptions({
        resourceId: changedOptions.instance_guid,
        operationName: CONST.APISERVER.ANNOTATION_NAMES.BACKUP,
        operationType: CONST.APISERVER.ANNOTATION_TYPES.BACKUP,
        operationId: changedOptions.guid
      })
      .then(options => {
        return Promise.try(() => {
          const plan = catalog.getPlan(options.plan_id);
          return bm.createService(plan);
        }).then(manager => manager.abortLastBackup(options));
      });
  }

  static _processDelete(changeObjectBody) {
    const changedOptions = JSON.parse(changeObjectBody.spec.options);
    return eventmesh.apiServerClient.getOperationOptions({
        resourceId: changedOptions.instance_guid,
        operationName: CONST.APISERVER.ANNOTATION_NAMES.BACKUP,
        operationType: CONST.APISERVER.ANNOTATION_TYPES.BACKUP,
        operationId: changedOptions.guid
      })
      .then(options => {
        return Promise.try(() => {
          const plan = catalog.getPlan(options.plan_id);
          return bm.createService(plan);
        }).then(manager => manager.deleteBackup(options));
      });
  }

  /**
   * @description Registers backup watcher with worker callback
   */
  // Register watcher is refreshed every 20 mins as API Server has a min time out of 30 mins after which it closes the watch.
  //TODO-PR - Extract it in a different function
  registerWatcher() {
    logger.debug(`Registering Backup watcher`);
    const queryString = `state in (${CONST.APISERVER.RESOURCE_STATE.IN_QUEUE},${CONST.OPERATION.ABORT},${CONST.APISERVER.RESOURCE_STATE.DELETE})`;
    return eventmesh.apiServerClient.registerWatcher('backup', 'defaultbackup', this.worker, queryString)
      .then(stream => {
        logger.info(`Successfully set watcher with query string:`, queryString);
        return setTimeout(() => {
          try {
            logger.info(`Refreshing stream after ${CONST.APISERVER.WATCHER_REFRESH_INTERVAL}`);
            stream.abort();
            return this.registerWatcher();
          } catch (err) {
            logger.error('Error caught in the set timout callback');
            throw err;
          }
        }, CONST.APISERVER.WATCHER_REFRESH_INTERVAL);
      })
      .catch(e => {
        logger.error('Failed registering watcher with error:', e);
        throw e;
      });
  }
  /**
   * @description This method does following in order
   * 1. Tries to acquire processing lock => In case of HA, Only one backup manager process will process the request
   * 2. Processes the request based on the state of the changed resource
   * 3. Release processing lock
   * @param {object} change - Change object that comes as part of apiserver watch event
   */

  //TODO-PR - Move the locking part of the code as part of the Base Manager,
  //Use something like this.
  // handleResource(change){
  // return this._preProcessResource(change)
  //             .then(()=> this.processResource(change))
  //             .then(()=> this.postProcessResource(change))
  //              .catch((err)=> logger.error(`Error occurred ....`)); //Dont need to care what type of error just log.
  //                //see if this can be put in finally.
  // }

  // _preProcessResource(){
  // //Code about acquiring processing lock goes here.
  // }

  // processResource(change){
  //   throw 'Must be implemented by subclass'; // Individual base manage managers just implement this.
  // }
  // _postProcessResource(){
  //  //code to handle release processing lock  goes here.
  // }
  worker(change) {

    logger.debug('Changed Resource:', change);
    logger.debug('Changed resource options:', change.object.spec.options);
    const changeObjectBody = change.object;
    const changedOptions = JSON.parse(changeObjectBody.spec.options);
    logger.debug('Changed resource options(parsed):', changedOptions);
    let processingLockConflict = false;
    if (changeObjectBody.metadata.annotations && changeObjectBody.metadata.annotations.lockedByManager === config.broker_ip) {
      // Don't have to process as this is event generated by acquireProcessLock
      logger.debug(`Backup request for guid ${changedOptions.guid} is already being processed by process with ip ${changeObjectBody.metadata.annotations.lockedByManager}`);
    } else {
      // Acquire processing lock so that in HA scenerio, only one backup-manager process processes the request
      return Promise.try(() => {
          if (!changeObjectBody.metadata.annotations || changeObjectBody.metadata.annotations.lockedByManager === '') {
            return BaseManager.acquireProcessingLock(changeObjectBody)
              .catch(err => {
                if (err instanceof Conflict) {
                  processingLockConflict = true;
                  logger.info(`Not able to acquire processing lock, Backup request for guid ${changedOptions.guid} is probably picked by other worker`);
                } else {
                  logger.error(`Error while trying to get processing lock for backup with guid ${changedOptions.guid}`, err);
                }
                throw err;
              });
          } else {
            processingLockConflict = true;
            logger.info(`Backup request for guid ${changedOptions.guid} is picked by other process with ip ${changeObjectBody.metadata.annotations.lockedByManager}`);
          }
        })
        .then(() => {
          if (!processingLockConflict) {
            if (changeObjectBody.status.state === CONST.APISERVER.RESOURCE_STATE.IN_QUEUE) {
              return DefaultBackupManager._processBackup(changeObjectBody);
            } else if (changeObjectBody.status.state === CONST.OPERATION.ABORT) {
              return DefaultBackupManager._processAbort(changeObjectBody);
            } else if (changeObjectBody.status.state === CONST.APISERVER.RESOURCE_STATE.DELETE) {
              return DefaultBackupManager._processDelete(changeObjectBody);
            }
          }
        })
        .catch(e => {
          // If conflict error is in acquiring processingLock then don't throw error
          if (!processingLockConflict) {
            logger.error(`Caught error while starting backup ${changedOptions.guid}`, e);
          }
        })
        .then(() => {
          if (!processingLockConflict) {
            return BaseManager.releaseProcessingLock(changeObjectBody)
              .catch(e => logger.error(`Caught error while releasing processing lock ${changedOptions}:`, e));
          }
        });
    }
  }
}

const defaultBackupManager = new DefaultBackupManager();
defaultBackupManager.registerWatcher();<|endoftext|>


<commit_before>(function ($) {
    var showHelp = false;
    $(document).ready(function () {
        if ($('[data-help]').length > 0) {
            $('body').append(
                $('<div>', {'id': 'toggleHelpButton'}).append(
                    $('<div>').html('Help').css({
                        'float': 'right',
                        'margin-right': '5px',
                        'background': '#dddcdc',
                        'color': '#7f7c7c',
                        'padding': '5px',
                        'cursor': 'pointer',
                        'border': '1px solid #000',
                        'border-top': 'none'
                    })
                ).click(toggleHelp)
            );
        }

        function toggleHelp() {
            if (showHelp) {
                $('.help-question-mark').animate({'opacity': 0}, 500, function () {$(this).remove()})
            } else {
                $('.help-question-mark').remove();
                $('[data-help]').each(function () {
                    $('body').append(
                        $('<div>', {'class': 'help-question-mark'}).html('?').css({
                            'width': 20,
                            'height': 20,
                            'margin-top': '-10px',
                            'margin-left': '-10px',
                            'font-size': '16px',
                            'background': '#CB2C2C',
                            'border-radius': 10,
                            'text-align': 'center',
                            'line-height': '20px',
                            'color': '#fff',
                            'cursor': 'pointer',
                            'position': 'absolute',
                            'top': $(this).offset().top,
                            'left': $(this).offset().left + $(this).width(),
                            'opacity': 0
                        }).animate({'opacity': 1}, 500).data('text', $(this).data('help')).click(showHelpModal)
                    );
                });
            }
            showHelp = !showHelp;
        }

        function showHelpModal(e) {
            var modal = $('<div>', {'class': 'modal hide fade'}).append(
                $('<div>', {'class': 'modal-header'}).append(
                    $('<span>').html('Litus Admin'),
                    '/Help'
                ),
                $('<div>', {'class': 'modal-body'}).append(
                    $('<div>').append(
                        $('<p>').html($(e.target).data('text'))
                    ),
                    $('<div>', {'class': 'footer'}).append(
                        $('<input>', {'type': 'button', 'data-dismiss': 'modal', 'value': 'Close'})
                    )
                )
            );
            $('body').append(modal);
            modal.modal();
        }
    });
}) (jQuery);<commit_msg>Show help only for visible items<commit_after>(function ($) {
    var showHelp = false;
    $(document).ready(function () {
        if ($('[data-help]:visible').length > 0) {
            $('body').append(
                $('<div>', {'id': 'toggleHelpButton'}).append(
                    $('<div>').html('Help').css({
                        'float': 'right',
                        'margin-right': '5px',
                        'background': '#dddcdc',
                        'color': '#7f7c7c',
                        'padding': '5px',
                        'cursor': 'pointer',
                        'border': '1px solid #000',
                        'border-top': 'none'
                    })
                ).click(toggleHelp)
            );
        }

        function toggleHelp() {
            if (showHelp) {
                $('.help-question-mark').animate({'opacity': 0}, 500, function () {$(this).remove()})
            } else {
                $('.help-question-mark').remove();
                $('[data-help]').each(function () {
                    $('body').append(
                        $('<div>', {'class': 'help-question-mark'}).html('?').css({
                            'width': 20,
                            'height': 20,
                            'margin-top': '-10px',
                            'margin-left': '-10px',
                            'font-size': '16px',
                            'background': '#CB2C2C',
                            'border-radius': 10,
                            'text-align': 'center',
                            'line-height': '20px',
                            'color': '#fff',
                            'cursor': 'pointer',
                            'position': 'absolute',
                            'top': $(this).offset().top,
                            'left': $(this).offset().left + $(this).width(),
                            'opacity': 0
                        }).animate({'opacity': 1}, 500).data('text', $(this).data('help')).click(showHelpModal)
                    );
                });
            }
            showHelp = !showHelp;
        }

        function showHelpModal(e) {
            var modal = $('<div>', {'class': 'modal hide fade'}).append(
                $('<div>', {'class': 'modal-header'}).append(
                    $('<span>').html('Litus Admin'),
                    '/Help'
                ),
                $('<div>', {'class': 'modal-body'}).append(
                    $('<div>').append(
                        $('<p>').html($(e.target).data('text'))
                    ),
                    $('<div>', {'class': 'footer'}).append(
                        $('<input>', {'type': 'button', 'data-dismiss': 'modal', 'value': 'Close'})
                    )
                )
            );
            $('body').append(modal);
            modal.modal();
        }
    });
}) (jQuery);<|endoftext|>