<commit_before>$(function(){
  // initial values
  var tile = $("a.tile");

  // update messages to players
  var updateMessage = function(playerMessage) {
    $('.player-message').html(playerMessage);
  };

  // change dice image
  var rollDice = function() {
    game.roll();
    $('#dice1').attr('src', 'img/face' + game.dice.dice1 +'.png');
    $('#dice2').attr('src', 'img/face' + game.dice.dice2 +'.png');
    var msg = "Roll Total: " + game.dice.sum;
    $('.roll-total').html(msg);
  };

  // Smaller or equal the dice roll, AND not used
  var titleisActive = function(tile) {
    return (tile <= game.dice.sum);
  };

  // if tile > dice roll then disable tiles
  var updateTiles = function() {
    for(var tile = 1; tile < 10; tile ++) {
      $tile = $('#p1-tile'+tile);

      if (titleisActive(tile)) {
        $tile.addClass('tile-active');
        $tile.removeClass('tile-disabled');
      } else {
        $tile.addClass('tile-disabled');
        $tile.removeClass('tile-active');
      }
    }
  };

  //add or remove player selected tiles
  var bindActiveTiles = function(){
    $("a.tile").off();

    var tile = $("a.tile");

    for (var i = 0; i < tile.length; i++) {
      var has_selected_tile = tile.eq(i).hasClass("player-selected");
      var has_disabled_tile = tile.eq(i).hasClass("tile-disabled");

      if ( !has_selected_tile && !has_disabled_tile ){
        tile.eq(i).on("click",function( event ) {
          var tileValue = parseInt($(this).html());
          var index = game.tilesPlayerSelected.indexOf(tileValue);

          if (index === -1) {
            $(this).addClass('player-selected');
            game.tilesPlayerSelected.push(tileValue);
          } else {
            game.tilesPlayerSelected.splice(index, 1);
            $(this).removeClass('player-selected');
          }

          confirmPlayerTileSelection();
        });
      }
    };
  };

  //check player selection with dice roll total and disable player selected tiles
  var confirmPlayerTileSelection = function () {
    if (game.started === true ){
      game.calculatePlayerTileSelection();
      if (game.dice.sum === game.playerTileTotal) {

        // for(var tile = 1; tile < 10; tile ++) {
        //   tile = $('.player-selected');
        //   tile.addClass('tile-disabled');
        //   tile.removeClass('tile-active');
        // }

        $('#confirm-tiles').removeAttr("disabled");

        console.log('tile sum correct');
      } else {
        console.log("it doesnt add up");
        // $('#roll-btn').addClass("hide");
      }
    }
  };

  //end player turn, calculate score and switch players
  $('#end-turn').on('click', function () {
    var points = 0

      for (var i = 0; i < tile.length; i++) {
        if (!tile.eq(i).hasClass('player-selected')) {
          var openTile = parseInt(tile.eq(i).html());
          points += openTile;
        }
      }

    game.players[game.currentPlayer]['points'] = points;

    if (game.currentPlayer === "Player1") {
      $('h3.player1').html(game.currentPlayer + ": " + game.players[game.currentPlayer]['points']);
    } else {
      $('h3.player2').html(game.currentPlayer + ": " + game.players[game.currentPlayer]['points']);
    }

    if (game.currentPlayer === "Player1"){
      game.currentPlayer = "Player2";
      updateMessage(game.currentPlayer + ": Click Roll the Dice");
    } else{
      updateMessage("Game Over");
        if ((game.players['Player1']['points']) > (game.players['Player2']['points'])) {
          alert("Player2 Wins!");
        } else if ((game.players['Player1']['points']) < (game.players['Player2']['points'])) {
          alert("Player1 Wins!");
        } else {
          alert("its a draw");
        }
    }
      game.tilesPlayerSelected = [];
      refreshBoard();
  });

  updateMessage("Player1: Click Roll the Dice to Start Game");

  //click button to roll the dice
  $('#roll-btn').on('click', function () {
    game.started = true;
    $('#roll-btn').addClass("hide");
    $('#confirm-tiles').removeClass("hide");
    $('#confirm-tiles').attr("disabled", "");

    updateMessage(game.currentPlayer + ": Select tiles to win");
    rollDice();
    updateTiles();
    bindActiveTiles();
  });

  // new game button function
  $('#new-game').on('click', function() {
      refreshBoard();
      game.tilesPlayerSelected = [];
      game.playerTileTotal = 0;
      this.openTileValue = [];
      game.currentPlayer = "Player1";
      game.players[game.currentPlayer]['points'] = 0;
      $('h3.player2').html("Player 2: " + game.players[game.currentPlayer]['points']);
      $('h3.player1').html("Player 1: " + game.players[game.currentPlayer]['points']);
      updateMessage(game.currentPlayer + ": Click Roll the Dice to Start Game");
  });

  //refresh the tiles
  var refreshBoard = function () {
    var tile = $("a.tile");
      for (var i = 0; i < tile.length; i++) {
        tile.eq(i).removeAttr("class");
        tile.eq(i).addClass("tile");
        tile.eq(i).addClass("tile-active")
      }
  }

  var game = new Game();

});<commit_msg>game working<commit_after>$(function(){
  // initial values
  var tile = $("a.tile");

  // update messages to players
  var updateMessage = function(playerMessage) {
    $('.player-message').html(playerMessage);
  };

  // change dice image
  var rollDice = function() {
    game.roll();
    $('#dice1').attr('src', 'img/face' + game.dice.dice1 +'.png');
    $('#dice2').attr('src', 'img/face' + game.dice.dice2 +'.png');
    var msg = "Roll Total: " + game.dice.sum;
    $('.roll-total').html(msg);
  };

  // Smaller or equal the dice roll, AND not used
  var titleisActive = function(tile) {
    return (tile <= game.dice.sum);
  };

  // if tile > dice roll then disable tiles
  var updateTiles = function() {
    for(var tile = 1; tile < 10; tile ++) {
      $tile = $('#p1-tile'+tile);

      if (titleisActive(tile)) {
        $tile.addClass('tile-active');
        $tile.removeClass('tile-disabled');
      } else {
        $tile.addClass('tile-disabled');
        $tile.removeClass('tile-active');
      }
    }
  };

  //add or remove player selected tiles
  var bindActiveTiles = function(){
    $("a.tile").off();

    var tile = $("a.tile");

    for (var i = 0; i < tile.length; i++) {
      var has_selected_tile = tile.eq(i).hasClass("player-selected");
      var has_disabled_tile = tile.eq(i).hasClass("tile-disabled");

      if ( !has_selected_tile && !has_disabled_tile ){
        tile.eq(i).on("click",function( event ) {
          var tileValue = parseInt($(this).html());
          var index = game.tilesPlayerSelected.indexOf(tileValue);

          if (index === -1) {
            $(this).addClass('player-selected');
            game.tilesPlayerSelected.push(tileValue);
          } else {
            game.tilesPlayerSelected.splice(index, 1);
            $(this).removeClass('player-selected');
          }

          confirmPlayerTileSelection();
        });
      }
    };
  };

  //check player selection with dice roll total and disable player selected tiles
  var confirmPlayerTileSelection = function () {
    if (game.started === true ){
      game.calculatePlayerTileSelection();
      if (game.dice.sum === game.playerTileTotal) {

        $('#confirm-tiles').removeAttr("disabled");

        console.log('tile sum correct');
        console.log(game.dice.sum, game.playerTileTotal, game.tilesPlayerSelected);
      } else {
        console.log("it doesnt add up");
        console.log(game.dice.sum, game.playerTileTotal, game.tilesPlayerSelected);
      }

    $('#confirm-tiles').on('click', function(){
      for(var tile = 1; tile < 10; tile ++) {
      $tile = $('.player-selected');
      $tile.addClass('tile-disabled');
      $tile.removeClass('tile-active');
      }

    $('#roll-btn').removeClass("hide");
    $('#confirm-tiles').addClass("hide");
    game.playerTileTotal = 0;
    game.tilesPlayerSelected = [];
    })
    }
  };

  //end player turn, calculate score and switch players
  $('#end-turn').on('click', function () {
    var points = 0

      for (var i = 0; i < tile.length; i++) {
        if (!tile.eq(i).hasClass('player-selected')) {
          var openTile = parseInt(tile.eq(i).html());
          points += openTile;
        }
      }

    game.players[game.currentPlayer]['points'] = points;

    if (game.currentPlayer === "Player1") {
      $('h3.player1').html(game.currentPlayer + ": " + game.players[game.currentPlayer]['points']);
    } else {
      $('h3.player2').html(game.currentPlayer + ": " + game.players[game.currentPlayer]['points']);
    }

    if (game.currentPlayer === "Player1"){
      game.currentPlayer = "Player2";
      updateMessage(game.currentPlayer + ": Click Roll the Dice");
      $('#roll-btn').removeClass("hide");
      $('#confirm-tiles').addClass("hide");
    } else{
      updateMessage("Game Over");
        if ((game.players['Player1']['points']) > (game.players['Player2']['points'])) {
          alert("Player2 Wins!");
        } else if ((game.players['Player1']['points']) < (game.players['Player2']['points'])) {
          alert("Player1 Wins!");
        } else {
          alert("its a draw");
        }
    }
      game.tilesPlayerSelected = [];
      refreshBoard();
  });

  updateMessage("Player1: Click Roll the Dice to Start Game");

  //click button to roll the dice
  $('#roll-btn').on('click', function () {
    game.started = true;
    $('#roll-btn').addClass("hide");
    $('#confirm-tiles').removeClass("hide");
    $('#confirm-tiles').attr("disabled", "");

    updateMessage(game.currentPlayer + ": Select tiles to win");
    rollDice();
    updateTiles();
    bindActiveTiles();
  });

  // new game button function
  $('#new-game').on('click', function() {
      refreshBoard();
      game.tilesPlayerSelected = [];
      game.playerTileTotal = 0;
      this.openTileValue = [];
      game.currentPlayer = "Player1";
      game.players[game.currentPlayer]['points'] = 0;
      $('h3.player2').html("Player 2: " + game.players[game.currentPlayer]['points']);
      $('h3.player1').html("Player 1: " + game.players[game.currentPlayer]['points']);
      updateMessage(game.currentPlayer + ": Click Roll the Dice to Start Game");
  });

  //refresh the tiles
  var refreshBoard = function () {
    var tile = $("a.tile");
      for (var i = 0; i < tile.length; i++) {
        tile.eq(i).removeAttr("class");
        tile.eq(i).addClass("tile");
        tile.eq(i).addClass("tile-active")
      }
  }

  var game = new Game();

});<|endoftext|>


<commit_before>angular.module('froala', []).
value('froalaConfig', {})
.directive('froala', ['froalaConfig', function (froalaConfig) {
    "use strict"; //Scope strict mode to only this directive
    var generatedIds = 0;
    var defaultConfig = { immediateAngularModelUpdate: false};

    var scope = {
        froalaOptions: '=froala',
        initFunction: '&froalaInit'
    };

    froalaConfig = froalaConfig || {};

    // Constants
    var MANUAL = "manual";
    var AUTOMATIC = "automatic";

    return {
        restrict: 'A',
        require: 'ngModel',
        scope: scope,
        link: function (scope, element, attrs, ngModel) {

            var ctrl = {
                editorInitialized: false
            };

            scope.initMode = attrs.froalaInit ? MANUAL : AUTOMATIC;

            ctrl.init = function () {
                if (!attrs.id) {
                    // generate an ID if not present
                    attrs.$set('id', 'froala-' + generatedIds++);
                }

                //init the editor
                if (scope.initMode === AUTOMATIC) {
                    ctrl.createEditor();
                }

                //Instruct ngModel how to update the froala editor
                ngModel.$render = function () {
                    element.froalaEditor('html.set', ngModel.$viewValue || '', true);
                    //This will reset the undo stack everytime the model changes externally. Can we fix this?
                    element.froalaEditor('undo.reset');
                    element.froalaEditor('undo.saveStep');
                };

                ngModel.$isEmpty = function (value) {
                    var isEmpty = jQuery(jQuery.parseHTML(value)).text().trim().length <= 0;
                    return isEmpty;
                };
            };

            ctrl.createEditor = function () {
                ctrl.listeningEvents = ['froalaEditor'];
                if (!ctrl.editorInitialized) {
                    ctrl.options = angular.extend({}, defaultConfig, froalaConfig, scope.froalaOptions);

                    if (ctrl.options.immediateAngularModelUpdate) {
                        ctrl.listeningEvents.push('keyup');
                    }

                    // Register events provided in the options
                    // Registering events before initializing the editor will bind the initialized event correctly.
                    for (var eventName in ctrl.options.events) {
                        if (ctrl.options.events.hasOwnProperty(eventName)) {
                            ctrl.registerEventsWithCallbacks(eventName, ctrl.options.events[eventName]);
                        }
                    }

                    ctrl.froalaElement = element.froalaEditor(ctrl.options).data('froala.editor').$el;
                    ctrl.froalaEditor = angular.bind(element, element.froalaEditor);
                    ctrl.initListeners();

                    //assign the froala instance to the options object to make methods available in parent scope
                    if (scope.froalaOptions) {
                        scope.froalaOptions.froalaEditor = ctrl.froalaEditor;
                    }

                    ctrl.editorInitialized = ctrl.froalaEditor ? true : false;
                }
            };

            ctrl.initListeners = function () {
                if (ctrl.options.immediateAngularModelUpdate) {
                    ctrl.froalaElement.on('keyup', function () {
                        scope.$evalAsync(ctrl.updateModelView);
                    });
                }

                element.on('froalaEditor.contentChanged', function () {
                    scope.$evalAsync(ctrl.updateModelView);
                });

                scope.$on('$destroy', function () {
                    element.off(ctrl.listeningEvents.join(" "));
                    element.froalaEditor('destroy');
                });
            };

            ctrl.updateModelView = function () {
                var returnedHtml = element.froalaEditor('html.get');
                if (angular.isString(returnedHtml)) {
                    ngModel.$setViewValue(returnedHtml);
                }
            };

            ctrl.registerEventsWithCallbacks = function (eventName, callback) {
                if (eventName && callback) {
                    ctrl.listeningEvents.push(eventName);
                    element.on(eventName, callback);
                }
            };

            if (scope.initMode === MANUAL) {
                var _ctrl = ctrl;
                var controls = {
                    initialize: ctrl.createEditor,
                    destroy: function () {
                        if (_ctrl.froalaEditor) {
                            _ctrl.froalaEditor('destroy');
                            _ctrl.editorInitialized = false;
                        }
                    },
                    getEditor: function () {
                        return _ctrl.froalaEditor ? _ctrl.froalaEditor : null;
                    }
                };
                scope.initFunction({initControls: controls});
            }
            ctrl.init();
        }
    };
}])
.directive('froalaView', ['$sce', function ($sce) {
	return {
		restrict: 'ACM',
		scope: false,
		link: function (scope, element, attrs) {
			element.addClass('fr-view');
			scope.$watch(attrs.froalaView, function (nv) {
				if (nv || nv === ''){
					var explicitlyTrustedValue = $sce.trustAsHtml(nv);
					element.html(explicitlyTrustedValue.toString());
				}
			});
		}
	};
}]);
<commit_msg>Fixes froala/angular-froala#94.<commit_after>angular.module('froala', []).
value('froalaConfig', {})
.directive('froala', ['froalaConfig', function (froalaConfig) {
    "use strict"; //Scope strict mode to only this directive
    var generatedIds = 0;
    var defaultConfig = { immediateAngularModelUpdate: false};

    var scope = {
        froalaOptions: '=froala',
        initFunction: '&froalaInit'
    };

    froalaConfig = froalaConfig || {};

    // Constants
    var MANUAL = "manual";
    var AUTOMATIC = "automatic";

    return {
        restrict: 'A',
        require: 'ngModel',
        scope: scope,
        link: function (scope, element, attrs, ngModel) {

            var ctrl = {
                editorInitialized: false
            };

            scope.initMode = attrs.froalaInit ? MANUAL : AUTOMATIC;

            ctrl.init = function () {
                if (!attrs.id) {
                    // generate an ID if not present
                    attrs.$set('id', 'froala-' + generatedIds++);
                }

                //init the editor
                if (scope.initMode === AUTOMATIC) {
                    ctrl.createEditor();
                }

                //Instruct ngModel how to update the froala editor
                ngModel.$render = function () {
                    element.froalaEditor('html.set', ngModel.$viewValue || '', true);
                    //This will reset the undo stack everytime the model changes externally. Can we fix this?
                    element.froalaEditor('undo.reset');
                    element.froalaEditor('undo.saveStep');
                };

                ngModel.$isEmpty = function (value) {
                  var isEmpty = element.froalaEditor('node.isEmpty', jQuery('<div>' + value + '</div>').get(0));
                  return isEmpty;
                };
            };

            ctrl.createEditor = function () {
                ctrl.listeningEvents = ['froalaEditor'];
                if (!ctrl.editorInitialized) {
                    ctrl.options = angular.extend({}, defaultConfig, froalaConfig, scope.froalaOptions);

                    if (ctrl.options.immediateAngularModelUpdate) {
                        ctrl.listeningEvents.push('keyup');
                    }

                    // Register events provided in the options
                    // Registering events before initializing the editor will bind the initialized event correctly.
                    for (var eventName in ctrl.options.events) {
                        if (ctrl.options.events.hasOwnProperty(eventName)) {
                            ctrl.registerEventsWithCallbacks(eventName, ctrl.options.events[eventName]);
                        }
                    }

                    ctrl.froalaElement = element.froalaEditor(ctrl.options).data('froala.editor').$el;
                    ctrl.froalaEditor = angular.bind(element, element.froalaEditor);
                    ctrl.initListeners();

                    //assign the froala instance to the options object to make methods available in parent scope
                    if (scope.froalaOptions) {
                        scope.froalaOptions.froalaEditor = ctrl.froalaEditor;
                    }

                    ctrl.editorInitialized = ctrl.froalaEditor ? true : false;
                }
            };

            ctrl.initListeners = function () {
                if (ctrl.options.immediateAngularModelUpdate) {
                    ctrl.froalaElement.on('keyup', function () {
                        scope.$evalAsync(ctrl.updateModelView);
                    });
                }

                element.on('froalaEditor.contentChanged', function () {
                    scope.$evalAsync(ctrl.updateModelView);
                });

                scope.$on('$destroy', function () {
                    element.off(ctrl.listeningEvents.join(" "));
                    element.froalaEditor('destroy');
                });
            };

            ctrl.updateModelView = function () {
                var returnedHtml = element.froalaEditor('html.get');
                if (angular.isString(returnedHtml)) {
                    ngModel.$setViewValue(returnedHtml);
                }
            };

            ctrl.registerEventsWithCallbacks = function (eventName, callback) {
                if (eventName && callback) {
                    ctrl.listeningEvents.push(eventName);
                    element.on(eventName, callback);
                }
            };

            if (scope.initMode === MANUAL) {
                var _ctrl = ctrl;
                var controls = {
                    initialize: ctrl.createEditor,
                    destroy: function () {
                        if (_ctrl.froalaEditor) {
                            _ctrl.froalaEditor('destroy');
                            _ctrl.editorInitialized = false;
                        }
                    },
                    getEditor: function () {
                        return _ctrl.froalaEditor ? _ctrl.froalaEditor : null;
                    }
                };
                scope.initFunction({initControls: controls});
            }
            ctrl.init();
        }
    };
}])
.directive('froalaView', ['$sce', function ($sce) {
	return {
		restrict: 'ACM',
		scope: false,
		link: function (scope, element, attrs) {
			element.addClass('fr-view');
			scope.$watch(attrs.froalaView, function (nv) {
				if (nv || nv === ''){
					var explicitlyTrustedValue = $sce.trustAsHtml(nv);
					element.html(explicitlyTrustedValue.toString());
				}
			});
		}
	};
}]);
<|endoftext|>


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

var RENDER_BASE_URL = window.location.protocol + "//" + window.location.host + window.location.pathname + "../render/?";

/* GraphiteComposer encapsulates a set of Ext UI Panels,
 * as well as a ParameterizedURL for the displayed graph. */
function GraphiteComposer () {
  this.url = new ParameterizedURL(RENDER_BASE_URL);
  this.state = {}; // For storing non-querystring state information
  this.window = createComposerWindow(this);
}

GraphiteComposer.prototype = {
  toggleTarget: function (target) {
    /* Add the given target to the graph if it does not exist,
     * otherwise remove it. */
    var targets = this.url.getParamList("target");
    var record = getTargetRecord(target);

    if (targets.indexOf(target) != -1) { // toggle it off
      this.url.removeParam("target", target);

      if (record) {
        TargetStore.remove(record);
      }

    } else { // toggle it on
      this.url.addParam("target", target);

      if (!record) {
        var newRecord = new TargetRecord({value: target});
        TargetStore.add( [newRecord] );
      }
    }

    this.updateImage();
  },

  loadMyGraph: function (name, url) {
    this.state.myGraphName = name;
    this.loadURL(url);
  },

  loadURL: function (url) {
    /* Take the targets out of the URL and add them to the store properly */
    TargetStore.removeAll();
    var tempUrl = new ParameterizedURL(RENDER_BASE_URL);
    tempUrl.copyQueryStringFromURL(url);
    var targets = tempUrl.getParamList('target');
    tempUrl.removeParam('target');
    this.url.copyQueryStringFromURL(tempUrl.queryString);
    Ext.each(targets, this.toggleTarget, this);

    /* Apply the query string from the given url to our graph image */
    this.url.copyQueryStringFromURL(url);
    // Fit the image into the window
    this.url.setParam('width', this.window.getInnerWidth());
    this.url.setParam('height', this.window.getInnerHeight());
    // And don't forget to update the time display widget
    var from = this.url.getParam('from');
    var until = this.url.getParam('until');
    var timeInfo = {};
    if (!from) { // No time interval specified, use the default
      timeInfo.mode = 'recent';
      timeInfo.quantity = '24';
      timeInfo.units = 'hours';
    } else {
      var match = from.match(/^-(\d+)(\w+)/);
      if (match) { // Relative time
        timeInfo.mode = 'recent';
        timeInfo.quantity = match[1];
        timeInfo.units = match[2];
      } else { // Absolute time
        timeInfo.mode = 'date-range';
        timeInfo.startDate = this.parseDate(from);
        timeInfo.endDate = this.parseDate(until);
      }
    }
    this.window.updateTimeDisplay(timeInfo);
    this.window.updateUI();
    this.updateImage();
  },

  updateImage: function () {
    /* Set the image's url to reflect this.url's current params */
    var img = this.window.getImage();
    if (img) {
      var now = new Date();
      var unixTime = now.valueOf() / 1000;
      this.url.setParam('_salt', unixTime.toString() );
      img.src = this.url.getURL();
    }
  },

  parseDate: function(dateString) { // Format is HH:MM_YYYYMMDD
    var hour = dateString.substr(0,2);
    var minute = dateString.substr(3,2);
    var year = dateString.substr(6,4);
    var month = dateString.substr(10,2);
    var day = dateString.substr(12,14);
    month = parseInt(month) - 1; // Date assumes months are zero-indexed
    return new Date(year, month, day, hour, minute, 0, 0);
  }
};

/* ParameterizedURL encapsulates a URL and
 * provides methods to access and modify the
 * query string parameters in a structured fashion.
 * This code should not be specific to Graphite or
 * the Composer in any way. */
function ParameterizedURL (baseURL) {
  this.baseURL = baseURL ? baseURL : "";
  this.params = {};
  this.queryString = "";
}

ParameterizedURL.prototype = {
  /*   Parameter access methods   */
  getParam: function (key) {
    /* Return the first value of this parameter */
    var values = this.params[key];
    return values ? values[0] : null;
  },

  getParamList: function (key) {
    /* Return an array of all values for this parameter */
    var values = this.params[key];
    return values ? values : new Array();
  },

  getURL: function () {
    /* Return the current URL */
    return this.baseURL + this.queryString;
  },

  /*   Parameter modification methods   */
  addParam: function (key, value) {
    /* Add a parameter value */
    var values = this.getParamList(key);
    values.push(value);
    this.params[key] = values;
    this.syncQueryString();
  },

  removeParam: function (key, value) {
    /* Remove one or all values for a given parameter */
    if (value == null) { //Remove all values
      this.params[key] = null; // in case it didn't exist, delete won't break now
      delete this.params[key];
    } else { //Remove a specific value
      var newValues = this.getParamList(key);
      newValues.remove(value);
      if (newValues.length) {
        this.params[key] = newValues;
      } else {
        this.params[key] = null;
        delete this.params[key];
      }
    }
    this.syncQueryString();
  },

  setParam: function (key, value) {
    /* Give the param only the given value */
    this.params[key] = [value];
    this.syncQueryString();
  },

  setParamList: function (key, values) {
    /* Give the param a given list of values */
    this.params[key] = values;
    this.syncQueryString();
  },

  setParamHash: function (params) {
    /* Use the given params Hash (and update this.queryString to match) */
    this.params = params;
    this.syncQueryString();
  },

  syncParams: function () {
    /* Set the value of this.params to reflect the parameters in this.queryString
     * Call this whenever you modify this.queryString */
    var params = Ext.urlDecode( this.queryString );

    Ext.iterate(params, function(key, value) { //We want all of our param values to be arrays
      if ( Ext.isString(value) ) {
        params[key] = [value];
      }
      if (value == "undefined" || value == undefined) {
        params[key] = null;
        delete params[key];
      }
    });
    this.params = params;
  },

  setQueryString: function (qs) {
    /* Use the given query string (and update this.params to match) */
    this.queryString = qs.replace(/#/,"%23");
    this.syncParams();
    this.syncQueryString();
  },

  syncQueryString: function () {
    /* Set the value of this.queryString to reflect the parameters in this.params
     * Call this whenever you modify this.params */
    this.queryString = Ext.urlEncode(this.params).replace(/#/,"%23");
  },

  copyQueryStringFromURL: function (url) {
    /* Make this object reflect the parameters of the given url */
    var i = url.indexOf("?");
    if (i == -1) { // No query string
      this.setParamHash({});
      return;
    }
    var queryString = url.substr(i+1);
    this.setQueryString(queryString);
  }
};
<commit_msg>fixed bug with using /composer url path<commit_after>/* Copyright 2008 Orbitz WorldWide
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License. */

var RENDER_BASE_URL = window.location.protocol + "//" + window.location.host + window.location.pathname;
RENDER_BASE_URL = RENDER_BASE_URL.replace(/\/composer\/?.*$/, '/render/?');

/* GraphiteComposer encapsulates a set of Ext UI Panels,
 * as well as a ParameterizedURL for the displayed graph. */
function GraphiteComposer () {
  this.url = new ParameterizedURL(RENDER_BASE_URL);
  this.state = {}; // For storing non-querystring state information
  this.window = createComposerWindow(this);
}

GraphiteComposer.prototype = {
  toggleTarget: function (target) {
    /* Add the given target to the graph if it does not exist,
     * otherwise remove it. */
    var targets = this.url.getParamList("target");
    var record = getTargetRecord(target);

    if (targets.indexOf(target) != -1) { // toggle it off
      this.url.removeParam("target", target);

      if (record) {
        TargetStore.remove(record);
      }

    } else { // toggle it on
      this.url.addParam("target", target);

      if (!record) {
        var newRecord = new TargetRecord({value: target});
        TargetStore.add( [newRecord] );
      }
    }

    this.updateImage();
  },

  loadMyGraph: function (name, url) {
    this.state.myGraphName = name;
    this.loadURL(url);
  },

  loadURL: function (url) {
    /* Take the targets out of the URL and add them to the store properly */
    TargetStore.removeAll();
    var tempUrl = new ParameterizedURL(RENDER_BASE_URL);
    tempUrl.copyQueryStringFromURL(url);
    var targets = tempUrl.getParamList('target');
    tempUrl.removeParam('target');
    this.url.copyQueryStringFromURL(tempUrl.queryString);
    Ext.each(targets, this.toggleTarget, this);

    /* Apply the query string from the given url to our graph image */
    this.url.copyQueryStringFromURL(url);
    // Fit the image into the window
    this.url.setParam('width', this.window.getInnerWidth());
    this.url.setParam('height', this.window.getInnerHeight());
    // And don't forget to update the time display widget
    var from = this.url.getParam('from');
    var until = this.url.getParam('until');
    var timeInfo = {};
    if (!from) { // No time interval specified, use the default
      timeInfo.mode = 'recent';
      timeInfo.quantity = '24';
      timeInfo.units = 'hours';
    } else {
      var match = from.match(/^-(\d+)(\w+)/);
      if (match) { // Relative time
        timeInfo.mode = 'recent';
        timeInfo.quantity = match[1];
        timeInfo.units = match[2];
      } else { // Absolute time
        timeInfo.mode = 'date-range';
        timeInfo.startDate = this.parseDate(from);
        timeInfo.endDate = this.parseDate(until);
      }
    }
    this.window.updateTimeDisplay(timeInfo);
    this.window.updateUI();
    this.updateImage();
  },

  updateImage: function () {
    /* Set the image's url to reflect this.url's current params */
    var img = this.window.getImage();
    if (img) {
      var now = new Date();
      var unixTime = now.valueOf() / 1000;
      this.url.setParam('_salt', unixTime.toString() );
      img.src = this.url.getURL();
    }
  },

  parseDate: function(dateString) { // Format is HH:MM_YYYYMMDD
    var hour = dateString.substr(0,2);
    var minute = dateString.substr(3,2);
    var year = dateString.substr(6,4);
    var month = dateString.substr(10,2);
    var day = dateString.substr(12,14);
    month = parseInt(month) - 1; // Date assumes months are zero-indexed
    return new Date(year, month, day, hour, minute, 0, 0);
  }
};

/* ParameterizedURL encapsulates a URL and
 * provides methods to access and modify the
 * query string parameters in a structured fashion.
 * This code should not be specific to Graphite or
 * the Composer in any way. */
function ParameterizedURL (baseURL) {
  this.baseURL = baseURL ? baseURL : "";
  this.params = {};
  this.queryString = "";
}

ParameterizedURL.prototype = {
  /*   Parameter access methods   */
  getParam: function (key) {
    /* Return the first value of this parameter */
    var values = this.params[key];
    return values ? values[0] : null;
  },

  getParamList: function (key) {
    /* Return an array of all values for this parameter */
    var values = this.params[key];
    return values ? values : new Array();
  },

  getURL: function () {
    /* Return the current URL */
    return this.baseURL + this.queryString;
  },

  /*   Parameter modification methods   */
  addParam: function (key, value) {
    /* Add a parameter value */
    var values = this.getParamList(key);
    values.push(value);
    this.params[key] = values;
    this.syncQueryString();
  },

  removeParam: function (key, value) {
    /* Remove one or all values for a given parameter */
    if (value == null) { //Remove all values
      this.params[key] = null; // in case it didn't exist, delete won't break now
      delete this.params[key];
    } else { //Remove a specific value
      var newValues = this.getParamList(key);
      newValues.remove(value);
      if (newValues.length) {
        this.params[key] = newValues;
      } else {
        this.params[key] = null;
        delete this.params[key];
      }
    }
    this.syncQueryString();
  },

  setParam: function (key, value) {
    /* Give the param only the given value */
    this.params[key] = [value];
    this.syncQueryString();
  },

  setParamList: function (key, values) {
    /* Give the param a given list of values */
    this.params[key] = values;
    this.syncQueryString();
  },

  setParamHash: function (params) {
    /* Use the given params Hash (and update this.queryString to match) */
    this.params = params;
    this.syncQueryString();
  },

  syncParams: function () {
    /* Set the value of this.params to reflect the parameters in this.queryString
     * Call this whenever you modify this.queryString */
    var params = Ext.urlDecode( this.queryString );

    Ext.iterate(params, function(key, value) { //We want all of our param values to be arrays
      if ( Ext.isString(value) ) {
        params[key] = [value];
      }
      if (value == "undefined" || value == undefined) {
        params[key] = null;
        delete params[key];
      }
    });
    this.params = params;
  },

  setQueryString: function (qs) {
    /* Use the given query string (and update this.params to match) */
    this.queryString = qs.replace(/#/,"%23");
    this.syncParams();
    this.syncQueryString();
  },

  syncQueryString: function () {
    /* Set the value of this.queryString to reflect the parameters in this.params
     * Call this whenever you modify this.params */
    this.queryString = Ext.urlEncode(this.params).replace(/#/,"%23");
  },

  copyQueryStringFromURL: function (url) {
    /* Make this object reflect the parameters of the given url */
    var i = url.indexOf("?");
    if (i == -1) { // No query string
      this.setParamHash({});
      return;
    }
    var queryString = url.substr(i+1);
    this.setQueryString(queryString);
  }
};
<|endoftext|>


<commit_before>var Opbeat = require('./opbeat')
var TraceBuffer = require('./instrumentation/traceBuffer')
var transactionStore = require('./instrumentation/transactionStore')

var utils = require('./instrumentation/utils')
var logger = require('./lib/logger')

function ngOpbeatProvider () {
  this.config = function config (properties) {
    Opbeat.config(properties)
  }

  this.install = function install () {
    Opbeat.install()
  }

  this.$get = [
    function () {
      return {
        getConfig: function config () {
          return Opbeat.config()
        },
        captureException: function captureException (exception, cause) {
          Opbeat.captureException(exception, cause)
        },

        setUserContext: function setUser (user) {
          Opbeat.setUserContext(user)
        },

        setExtraContext: function setExtraContext (data) {
          Opbeat.setExtraContext(data)
        }
      }
    }
  ]
}

function $opbeatErrorProvider ($provide) {
  $provide.decorator('$exceptionHandler', ['$delegate', '$opbeat', function $ExceptionHandlerDecorator ($delegate, $opbeat) {
    return function $ExceptionHandler (exception, cause) {
      $opbeat.captureException(exception)
      return $delegate(exception, cause)
    }
  }])
}

function $opbeatInstrumentationProvider ($provide, $opbeat) {
  var config = $opbeat.$get[0]().getConfig()
  var transactionOptions = {
    config: config
  }

  // Before controller intialize transcation
  var traceBuffer = new TraceBuffer('beforeControllerTransaction', transactionOptions)

  // Route controller Instrumentation
  $provide.decorator('$controller', ['$delegate', '$location', '$rootScope', '$injector', function ($delegate, $location, $rootScope, $injector) {
    transactionStore.init($injector)

    var onRouteChange = function (e, current) {

      logger.log('opbeat.decorator.controller.onRouteChange')

      var routeControllerName
      var routeController

      // Detect controller
      if(current.controller) {
        routeController = current.controller
      } else if(current.views) {
        var keys = Object.keys(current.views)
        if(keys) {
          routeController = current.views[keys[0]].controller
        }
      }

      // Extract controller name
      if(typeof(routeController) === 'string') {
        routeControllerName = routeController
      }

      if(!routeControllerName) {
        logger.log('%c opbeat.decorator.controller.onRouteChange.error.routeControllerName.missing', 'background-color: #ffff00', current)
        return
      }

      var transaction = Opbeat.startTransaction('app.angular.controller.' + routeControllerName, 'transaction', transactionOptions)
      transaction.metadata.controllerName = routeControllerName

      // Update transaction store
      transactionStore.pushToUrl($location.absUrl(), transaction)

      // Update transaction reference in traceBuffer
      traceBuffer.setTransactionReference(transaction)

      // Lock traceBuffer, as we only want to migrate the initial traces to the first transaction
      traceBuffer.lock()
    }

    $rootScope.$on('$routeChangeStart', onRouteChange) // ng-router
    $rootScope.$on('$stateChangeSuccess', onRouteChange) // ui-router

    return function () {
      logger.log('opbeat.decorator.controller.ctor')

      var args = Array.prototype.slice.call(arguments)

      var url = $injector.get('$location').absUrl()
      var transaction = transactionStore.getRecentByUrl(url)

      var controllerInfo = utils.getControllerInfoFromArgs(args)
      var controllerName = controllerInfo.name
      var controllerScope = controllerInfo.scope
      var isRouteController = controllerName && transaction && transaction.metadata.controllerName === controllerName

      var result = $delegate.apply(this, args)

      var onViewFinished = function(argument) {
        logger.log('opbeat.angular.controller.$onViewFinished')

        transactionStore.getAllByUrl(url).forEach(function (trans) {
          transaction.end()
        })
        transactionStore.clearByUrl(url)
      }

      var onScopeDestroyed = function() {
        logger.log('opbeat.angular.controller.destroy')
      }

      if (isRouteController && controllerScope) {
        logger.log('opbeat.angular.controller', controllerName)
        controllerScope.$on('$destroy', onScopeDestroyed)
        controllerScope.$on('$ionicView.enter', onViewFinished);
        controllerScope.$on('$viewContentLoaded', onViewFinished)
      }

      logger.log('opbeat.decorator.controller.end')
      return result
    }
  }])

  $provide.decorator('$controller', ['$delegate', '$rootScope', '$rootElement', function ($delegate, $rootScope, $rootElement) {
    $rootScope._opbeatHasInstrumentedFactories = false
    $rootScope._opbeatHasInstrumentedDirectives = false

    var directivesInstrumentation = require('./instrumentation/angular/directives')($provide, traceBuffer)

    // Factory instrumentation
    if (!$rootScope._opbeatHasInstrumentedFactories) {
      var factories = utils.resolveAngularDependenciesByType($rootElement, 'factory')
      require('./instrumentation/angular/factories')($provide, traceBuffer).instrumentAll(factories)
      $rootScope._opbeatHasInstrumentedFactories = true
    }

    if (!$rootScope._opbeatHasInstrumentedDirectives) {
      // Custom directive instrumentation
      var directives = utils.resolveAngularDependenciesByType($rootElement, 'directive')
      directivesInstrumentation.instrumentAll(directives)
      $rootScope._opbeatHasInstrumentedDirectives = true

      // Core directives instrumentation
      directivesInstrumentation.instrumentCore()
    }

    return $delegate
  }])

  // Angular Core Instrumentation
  require('./instrumentation/angular/cacheFactory')($provide, traceBuffer)
  require('./instrumentation/angular/compile')($provide, traceBuffer)
  require('./instrumentation/angular/controller')($provide, traceBuffer)
  require('./instrumentation/angular/http')($provide, traceBuffer)
  require('./instrumentation/angular/httpBackend')($provide, traceBuffer)
  require('./instrumentation/angular/resource')($provide, traceBuffer)
  require('./instrumentation/angular/templateRequest')($provide, traceBuffer)
}

window.angular.module('ngOpbeat', [])
  .provider('$opbeat', ngOpbeatProvider)
  .config(['$provide', '$opbeatProvider', $opbeatErrorProvider])
  .config(['$provide', '$opbeatProvider', $opbeatInstrumentationProvider])

window.angular.module('angular-opbeat', ['ngOpbeat'])
<commit_msg>Don’t instrument if platform isn’t supported. Fixes #10 & #8<commit_after>var Opbeat = require('./opbeat')
var TraceBuffer = require('./instrumentation/traceBuffer')
var transactionStore = require('./instrumentation/transactionStore')

var utils = require('./instrumentation/utils')
var logger = require('./lib/logger')

function ngOpbeatProvider () {
  this.config = function config (properties) {
    Opbeat.config(properties)
  }

  this.install = function install () {
    Opbeat.install()
  }

  this.$get = [
    function () {
      return {
        getConfig: function config () {
          return Opbeat.config()
        },
        captureException: function captureException (exception, cause) {
          Opbeat.captureException(exception, cause)
        },

        setUserContext: function setUser (user) {
          Opbeat.setUserContext(user)
        },

        setExtraContext: function setExtraContext (data) {
          Opbeat.setExtraContext(data)
        }
      }
    }
  ]
}

function $opbeatErrorProvider ($provide) {
  $provide.decorator('$exceptionHandler', ['$delegate', '$opbeat', function $ExceptionHandlerDecorator ($delegate, $opbeat) {
    return function $ExceptionHandler (exception, cause) {
      $opbeat.captureException(exception)
      return $delegate(exception, cause)
    }
  }])
}

function $opbeatInstrumentationProvider ($provide, $opbeat) {
  var config = $opbeat.$get[0]().getConfig()
  var transactionOptions = {
    config: config
  }

  if (!config.get('isInstalled')) {
    logger.log('opbeat.instrumentation.platform.unsupported')
    return
  }

  // Before controller intialize transcation
  var traceBuffer = new TraceBuffer('beforeControllerTransaction', transactionOptions)

  // Route controller Instrumentation
  $provide.decorator('$controller', ['$delegate', '$location', '$rootScope', '$injector', function ($delegate, $location, $rootScope, $injector) {
    transactionStore.init($injector)

    var onRouteChange = function (e, current) {

      logger.log('opbeat.decorator.controller.onRouteChange')

      var routeControllerName
      var routeController

      // Detect controller
      if(current.controller) {
        routeController = current.controller
      } else if(current.views) {
        var keys = Object.keys(current.views)
        if(keys) {
          routeController = current.views[keys[0]].controller
        }
      }

      // Extract controller name
      if(typeof(routeController) === 'string') {
        routeControllerName = routeController
      }

      if(!routeControllerName) {
        logger.log('%c opbeat.decorator.controller.onRouteChange.error.routeControllerName.missing', 'background-color: #ffff00', current)
        return
      }

      var transaction = Opbeat.startTransaction('app.angular.controller.' + routeControllerName, 'transaction', transactionOptions)
      transaction.metadata.controllerName = routeControllerName

      // Update transaction store
      transactionStore.pushToUrl($location.absUrl(), transaction)

      // Update transaction reference in traceBuffer
      traceBuffer.setTransactionReference(transaction)

      // Lock traceBuffer, as we only want to migrate the initial traces to the first transaction
      traceBuffer.lock()
    }

    $rootScope.$on('$routeChangeStart', onRouteChange) // ng-router
    $rootScope.$on('$stateChangeSuccess', onRouteChange) // ui-router

    return function () {
      logger.log('opbeat.decorator.controller.ctor')

      var args = Array.prototype.slice.call(arguments)

      var url = $injector.get('$location').absUrl()
      var transaction = transactionStore.getRecentByUrl(url)

      var controllerInfo = utils.getControllerInfoFromArgs(args)
      var controllerName = controllerInfo.name
      var controllerScope = controllerInfo.scope
      var isRouteController = controllerName && transaction && transaction.metadata.controllerName === controllerName

      var result = $delegate.apply(this, args)

      var onViewFinished = function(argument) {
        logger.log('opbeat.angular.controller.$onViewFinished')

        transactionStore.getAllByUrl(url).forEach(function (trans) {
          transaction.end()
        })
        transactionStore.clearByUrl(url)
      }

      var onScopeDestroyed = function() {
        logger.log('opbeat.angular.controller.destroy')
      }

      if (isRouteController && controllerScope) {
        logger.log('opbeat.angular.controller', controllerName)
        controllerScope.$on('$destroy', onScopeDestroyed)
        controllerScope.$on('$ionicView.enter', onViewFinished);
        controllerScope.$on('$viewContentLoaded', onViewFinished)
      }

      logger.log('opbeat.decorator.controller.end')
      return result
    }
  }])

  $provide.decorator('$controller', ['$delegate', '$rootScope', '$rootElement', function ($delegate, $rootScope, $rootElement) {
    $rootScope._opbeatHasInstrumentedFactories = false
    $rootScope._opbeatHasInstrumentedDirectives = false

    var directivesInstrumentation = require('./instrumentation/angular/directives')($provide, traceBuffer)

    // Factory instrumentation
    if (!$rootScope._opbeatHasInstrumentedFactories) {
      var factories = utils.resolveAngularDependenciesByType($rootElement, 'factory')
      require('./instrumentation/angular/factories')($provide, traceBuffer).instrumentAll(factories)
      $rootScope._opbeatHasInstrumentedFactories = true
    }

    if (!$rootScope._opbeatHasInstrumentedDirectives) {
      // Custom directive instrumentation
      var directives = utils.resolveAngularDependenciesByType($rootElement, 'directive')
      directivesInstrumentation.instrumentAll(directives)
      $rootScope._opbeatHasInstrumentedDirectives = true

      // Core directives instrumentation
      directivesInstrumentation.instrumentCore()
    }

    return $delegate
  }])

  // Angular Core Instrumentation
  require('./instrumentation/angular/cacheFactory')($provide, traceBuffer)
  require('./instrumentation/angular/compile')($provide, traceBuffer)
  require('./instrumentation/angular/controller')($provide, traceBuffer)
  require('./instrumentation/angular/http')($provide, traceBuffer)
  require('./instrumentation/angular/httpBackend')($provide, traceBuffer)
  require('./instrumentation/angular/resource')($provide, traceBuffer)
  require('./instrumentation/angular/templateRequest')($provide, traceBuffer)
}

window.angular.module('ngOpbeat', [])
  .provider('$opbeat', ngOpbeatProvider)
  .config(['$provide', '$opbeatProvider', $opbeatErrorProvider])
  .config(['$provide', '$opbeatProvider', $opbeatInstrumentationProvider])

window.angular.module('angular-opbeat', ['ngOpbeat'])
<|endoftext|>


<commit_before>var _ = require('underscore');
var async = require('async');
var Data = require ('../../lib/data/data');
var Filters = require('./filters');
var Util = require('./util');

// Document
// --------------------------

var Document = {};

// Fetch a single node from the graph
function fetchNode(id, callback) {
  db.get(id, function(err, node) {
    if (err) return callback(err);
    callback(null, node);
  });
}

// Stats
// -----------

// Document usage grouped by day
function getUsage(documentId, callback) {
  db.view('substance/document_views_by_day', {group: true}, function(err, res) {
    err ? callback(err) : callback(null, res.rows);
  });
}

// There's a duplicate version in filters.js
function isAuthorized(node, username, callback) {
  if ("/user/"+username === node.creator) return callback(null, true);

  // Fetch list of collaborators
  db.view('substance/collaborators', {key: ["/user/"+username, node._id]}, function(err, res) {
    if (res.rows.length > 0) {
      return callback(null, res.rows[0].value.mode === "edit" ? true : false);
    } else {
      // Already published?
      db.view('substance/versions', {endkey: [node._id], startkey: [node._id, {}], limit: 1, descending: true}, function(err, res) {
        if (err || res.rows.length === 0) return callback({error: "unauthorized"});
        return callback(null, false);
      });
    }
  });
}

function fetchDocuments(documents, username, callback) {
  var graph = new Data.Graph(seed).connect('couch', {url: config.couchdb_url});
  var result = {};

  function getHeadVersion(id, callback) {
    db.get(id, function(err, doc) {
      db.get(doc.published_version, function(err, version) {
        if (err || !version) return callback('not found');
        var data = version.data;
        data[id].name = doc.name;
        data[id].published_on = version.created_at;
        callback(null, data[id]);
      });
    });
  }

  var qry = {
    "_id": documents,
    "subjects": {},
    "entities": {},
    "creator": {}
  };

  graph.fetch(qry, function(err, nodes) {
    if (err) return callback(err);
    _.extend(result, nodes.toJSON());

    // Asynchronously fetch the right versions for the doc browser
    async.forEach(documents, function(documentId, callback) {
      getHeadVersion(documentId, function(err, head) {
        if (err) return callback(); // skip if there's no version
        isAuthorized(result[documentId], username, function(err, edit) {
          if (edit) {
            result[documentId].published_on = head.published_on;
            callback(); // skip if user has edit privileges
          } else {
            result[documentId] = head;
            callback();
          }
        });
      });
    }, function() {
      callback(null, result, documents.length);
    });
  });
}

Document.recent = function(limit, username, callback) {
  db.view('substance/recent_versions', {limit: parseInt(limit*2), descending: true}, function(err, res) {
    if (err) return callback(err);
    var documents = res.rows.map(function(d) { return d.value; });
    documents = _.select(_.uniq(documents), function(d, index) {
      return index < limit;
    });
    fetchDocuments(documents, username, callback);
  });
};

Document.subscribed = function(username, callback) {
  var graph = new Data.Graph(seed).connect('couch', {url: config.couchdb_url});

  var qry = {
    "type": "/type/subscription",
    "user": "/user/"+username
  };

  graph.fetch(qry, function(err, nodes) {
    var documents = nodes.map(function(n) {
      return n.get('document')._id
    }).values();
    fetchDocuments(documents, username, callback);
  });
};

// We are aware that this is not a performant solution.
// But search functionality needed to be there, quickly.
// We'll replace it with a speedy fulltext search asap.
Document.find = function(searchstr, type, username, callback) {
  db.view('substance/documents_by_keyword', function(err, res) {
    if (err) return callback(err);

    var documents = [];
    function add (row) { documents.push(row.value._id); }

    async.forEach(res.rows, function(row, callback) {
      var matched = type === "keyword"
                  ? row.key && row.key.match(new RegExp("("+searchstr+")", "i"))
                  : row.value.creator.match(new RegExp("/user/("+searchstr+")$", "i"));

      if (matched && documents.length < 200) {
        if (row.value.creator === '/user/'+username) {
          console.log('JOJO');
          add(row); return callback();
        } else {
          db.get(row.value._id, function(err, node) {
            if (err || !node) return callback();
            add(row); return callback(null, false);
          });
        }
      } else {
        callback();
      }
    }, function () {
      console.log(documents);
      fetchDocuments(documents, fetchDocuments, function(err, nodes, count) {
        if (type === "user" && !nodes["/user/"+searchstr]) {
          db.get("/user/"+searchstr, function(err, node) {
            if (!err) nodes[node._id] = node;
            callback(null, nodes, count);
          });
        } else {
          callback(err, nodes, count);
        }
      });
    });
  });
};

Document.dashboard = function (username, callback) {
  var userId = '/user/' + username,
      graph = new Data.Graph(seed).connect('couch', {url: config.couchdb_url}),
      bins = {
        user: {
          user: {
            name: "My documents"
          },
          involved: {
            name: "Involved documents"
          },
          subscribed: {
            name: "Subscribed documents"
          }
        },
        networks: {}
      };

  async.parallel([
    // The user's own documents
    function (cb) {
      db.view('document/key', { startkey: [userId], endkey: [userId, {}] }, function (err, res) {
        if (err) {
          cb(err, null);
        } else {
          bins.user.user.documents = _.map(res.rows, function (row) { return row.value._id; });
          cb(null, bins.user.user.documents);
        }
      });
    },

    // Subscribed documents
    function (cb) {
      db.view('subscription/by_user', { key: [userId] }, function (err, res) {
        if (err) {
          cb(err, null);
        } else {
          bins.user.subscribed.documents = _.map(res.rows, function (row) { return row.value.document; });
          cb(null, bins.user.subscribed.documents);
        }
      });
    },

    // Documents the user has contributed to
    function (cb) {
      db.view('collaborator/by_user', { key: [userId] }, function (err, res) {
        if (err) {
          cb(err, null);
        } else {
          bins.user.involved.documents = _.map(res.rows, function (row) { return row.value.document; });
          cb(null, bins.user.involved.documents);
        }
      });
    },

    // Documents resulting from network memberships
    function (cb) {
      graph.fetch({type: "/type/membership", user: userId}, function(err, memberships) {
        var networks = memberships.map(function(m) { return m.get('network')._id; }).values();
        var results = [];

        async.forEach(networks, function(network, cb) {
          graph.fetch({type: "/type/publication", network: network }, function(err, publications) {
            graph.fetch({_id: network}, function(err, nodes) {
              bins.networks[network] = {
                name: nodes.first().get('name'),
                cover: nodes.first().get('cover'),
                documents: publications.map(function(m) { return m.get('document')._id; }).values()
              };
              results = results.concat(bins.networks[network].documents);
              cb();
            });
          });
        }, function(err) {
          cb(null, results);
        });
      });
    }
  ], function (err, results) {
    fetchDocuments(_.uniq(_.flatten(results)), username, function(err, g, count) {
      callback(err, g, count, bins);
    });
  });
};

Document.getContent = function(documentId, callback) {
  var qry = {
    "_id": documentId,
    "children": {
      "_recursive": true
    }
  };

  var graph = new Data.Graph(seed).connect('couch', {url: config.couchdb_url});
  graph.fetch(qry, function(err, nodes) {
    var result = nodes.toJSON(),
        doc = result[documentId];

    callback(null, result, doc._id);
  });
};

function loadDocument(id, version, reader, edit, callback) {

  var graph = new Data.Graph(seed).connect('couch', {
    url: config.couchdb_url
  });

  var result = {};
  var published_on = null; // based on version.created_at

  function load(callback) {

    // Load current Head Version
    // ------------------

    function loadHead(callback) {
      console.log("Loading head version.");
      var qry = {
        "_id": id,
        "children": {
          "_recursive": true
        }
      };

      graph.fetch(qry, function(err, nodes) {
        if (err) return callback(err);
        _.extend(result, nodes.toJSON());

        if (!nodes.get(id).get('published_version')) return callback(null, result, edit, null);
        graph.fetch({_id: nodes.get(id).get('published_version')._id}, function(err, nodes) {
          published_on = nodes.length > 0 ? nodes.first().get('created_at') : null;
          callback(null, result, edit, null);
        });
      });
    }

    // Load published version, if exists
    // ------------------

    function loadPublishedVersion(callback) {
      console.log('Loading published version.');

      graph.fetch({"type": "/type/document", "_id": id}, function(err, nodes) {
        var doc = nodes.first(),
            version = doc.get('published_version');
        if (!version) return callback('not_found');

        graph.fetch({"type": "/type/version", "_id": version._id}, function(err, nodes) {
          var data = nodes.first().get('data');
          data[id].published_version = doc.get('published_version')._id;
          _.extend(result, data);
          published_on = nodes.first().get('created_at');
          callback(null, result, false, nodes.first()._id.split('/')[3]);
        });
      });
    }

    // Load a specific version
    // ------------------

    function loadVersion(version, callback) {
      console.log('loading version: '+ version);

      graph.fetch({_id: "/version/"+id.split('/')[3]+"/"+version, document: {}}, function(err, nodes) {
        if (err || nodes.length === 0) return callback('not_found');

        var doc = nodes.select(function(n) {
          return n.type._id === "/type/version"
        }).first();

        var data = doc.get('data');
        data[id].published_version = doc.get('document').get('published_version')._id;
        _.extend(result, data);

        published_on = nodes.first().get('created_at');
        callback(null, result, false, version);
      });
    }

    // Start the fun
    if (edit) {
      version ? loadVersion(version, callback) : loadHead(callback);
    } else if (version) {
      loadVersion(version, callback);
    } else {
      loadPublishedVersion(function(err, result, authorized, version) {
        if (err) return loadHead(callback);
        callback(null, result, false, version);
      });
    }
  }

  // Attach Meta Info
  function addMetaInfo(callback) {

    function calcCommentCount(callback) {
      async.forEach(_.keys(result), function(nodeId, callback) {
        var node = result[nodeId];
        if (_.include(node.type, "/type/document")) return callback();

        db.view('comment/by_node', {key: [node._id]}, function(err, res) {
          if (!err) node.comment_count = res.rows.length;
          callback();
        });
      }, callback);
    }

    function fetchAttributesAndUser(callback) {
      var doc = result[id];
      graph.fetch({_id: [doc.creator].concat(doc.entities).concat(doc.subjects) }, function(err, nodes) {
        if (err) return callback();
        _.extend(result, nodes.toJSON());
        callback();
      });
    }

    result[id].published_on = published_on;

    Util.count('/counter/document/'+id.split('/')[3]+'/views', function(err, views) {
      result[id].views = views;
      // Check subscriptions
      graph.fetch({type: "/type/subscription", "document": id}, function(err, nodes) {
        if (err) return callback(err);
        result[id].subscribed = graph.find({"user": "/user/"+reader, "document": id}).length > 0 ? true : false;
        result[id].subscribers = nodes.length;

        calcCommentCount(function() {
          fetchAttributesAndUser(callback);
        });
      });
    });
  }

  load(function(err, data, authorized, version) {
    if (err) return callback(err);

    addMetaInfo(function() {
      // Check if already published
      // TODO: shift to authorized method, as its duplicate effort now
      db.view('substance/versions', {endkey: [id], startkey: [id, {}], limit: 1, descending: true}, function(err, res) {
        callback(null, result, edit, version, !err && res.rows.length > 0);
      });
    });
  });
}

// Get a specific version of a document from the database, including all associated content nodes
Document.get = function(username, docname, version, reader, callback) {
  db.view('substance/documents', {key: username+'/'+docname}, function(err, res) {

    if (err) return callback(err);
    if (res.rows.length == 0) return callback("not_found");

    var node = res.rows[0].value;

    isAuthorized(node, reader, function(err, edit) {
      if (err) return callback("not_authorized");

      loadDocument(node._id, version, reader, edit, function(err, result, edit, version, published) {
        if (err) return callback("not_found");
        callback(null, result, node._id, edit, version, published);
      });
    });
  });
};

module.exports = Document;
<commit_msg>Use correct names and covers.<commit_after>var _ = require('underscore');
var async = require('async');
var Data = require ('../../lib/data/data');
var Filters = require('./filters');
var Util = require('./util');

// Document
// --------------------------

var Document = {};

// Fetch a single node from the graph
function fetchNode(id, callback) {
  db.get(id, function(err, node) {
    if (err) return callback(err);
    callback(null, node);
  });
}

// Stats
// -----------

// Document usage grouped by day
function getUsage(documentId, callback) {
  db.view('substance/document_views_by_day', {group: true}, function(err, res) {
    err ? callback(err) : callback(null, res.rows);
  });
}

// There's a duplicate version in filters.js
function isAuthorized(node, username, callback) {
  if ("/user/"+username === node.creator) return callback(null, true);

  // Fetch list of collaborators
  db.view('substance/collaborators', {key: ["/user/"+username, node._id]}, function(err, res) {
    if (res.rows.length > 0) {
      return callback(null, res.rows[0].value.mode === "edit" ? true : false);
    } else {
      // Already published?
      db.view('substance/versions', {endkey: [node._id], startkey: [node._id, {}], limit: 1, descending: true}, function(err, res) {
        if (err || res.rows.length === 0) return callback({error: "unauthorized"});
        return callback(null, false);
      });
    }
  });
}

function fetchDocuments(documents, username, callback) {
  var graph = new Data.Graph(seed).connect('couch', {url: config.couchdb_url});
  var result = {};

  function getHeadVersion(id, callback) {
    db.get(id, function(err, doc) {
      db.get(doc.published_version, function(err, version) {
        if (err || !version) return callback('not found');
        var data = version.data;
        data[id].name = doc.name;
        data[id].cover = doc.cover;
        data[id].published_on = version.created_at;
        callback(null, data[id]);
      });
    });
  }

  var qry = {
    "_id": documents,
    "subjects": {},
    "entities": {},
    "creator": {}
  };

  graph.fetch(qry, function(err, nodes) {
    if (err) return callback(err);
    _.extend(result, nodes.toJSON());

    // Asynchronously fetch the right versions for the doc browser
    async.forEach(documents, function(documentId, callback) {
      getHeadVersion(documentId, function(err, head) {
        if (err) return callback(); // skip if there's no version
        isAuthorized(result[documentId], username, function(err, edit) {
          if (edit) {
            result[documentId].published_on = head.published_on;
            callback(); // skip if user has edit privileges
          } else {
            result[documentId] = head;
            callback();
          }
        });
      });
    }, function() {
      callback(null, result, documents.length);
    });
  });
}

Document.recent = function(limit, username, callback) {
  db.view('substance/recent_versions', {limit: parseInt(limit*2), descending: true}, function(err, res) {
    if (err) return callback(err);
    var documents = res.rows.map(function(d) { return d.value; });
    documents = _.select(_.uniq(documents), function(d, index) {
      return index < limit;
    });
    fetchDocuments(documents, username, callback);
  });
};

Document.subscribed = function(username, callback) {
  var graph = new Data.Graph(seed).connect('couch', {url: config.couchdb_url});

  var qry = {
    "type": "/type/subscription",
    "user": "/user/"+username
  };

  graph.fetch(qry, function(err, nodes) {
    var documents = nodes.map(function(n) {
      return n.get('document')._id
    }).values();
    fetchDocuments(documents, username, callback);
  });
};

// We are aware that this is not a performant solution.
// But search functionality needed to be there, quickly.
// We'll replace it with a speedy fulltext search asap.
Document.find = function(searchstr, type, username, callback) {
  db.view('substance/documents_by_keyword', function(err, res) {
    if (err) return callback(err);

    var documents = [];
    function add (row) { documents.push(row.value._id); }

    async.forEach(res.rows, function(row, callback) {
      var matched = type === "keyword"
                  ? row.key && row.key.match(new RegExp("("+searchstr+")", "i"))
                  : row.value.creator.match(new RegExp("/user/("+searchstr+")$", "i"));

      if (matched && documents.length < 200) {
        if (row.value.creator === '/user/'+username) {
          add(row); return callback();
        } else {
          db.get(row.value._id, function(err, node) {
            if (err || !node) return callback();
            add(row); return callback(null, false);
          });
        }
      } else {
        callback();
      }
    }, function () {
      console.log(documents);
      fetchDocuments(documents, fetchDocuments, function(err, nodes, count) {
        if (type === "user" && !nodes["/user/"+searchstr]) {
          db.get("/user/"+searchstr, function(err, node) {
            if (!err) nodes[node._id] = node;
            callback(null, nodes, count);
          });
        } else {
          callback(err, nodes, count);
        }
      });
    });
  });
};

Document.dashboard = function (username, callback) {
  var userId = '/user/' + username,
      graph = new Data.Graph(seed).connect('couch', {url: config.couchdb_url}),
      bins = {
        user: {
          user: {
            name: "My documents"
          },
          involved: {
            name: "Involved documents"
          },
          subscribed: {
            name: "Subscribed documents"
          }
        },
        networks: {}
      };

  async.parallel([
    // The user's own documents
    function (cb) {
      db.view('document/key', { startkey: [userId], endkey: [userId, {}] }, function (err, res) {
        if (err) {
          cb(err, null);
        } else {
          bins.user.user.documents = _.map(res.rows, function (row) { return row.value._id; });
          cb(null, bins.user.user.documents);
        }
      });
    },

    // Subscribed documents
    function (cb) {
      db.view('subscription/by_user', { key: [userId] }, function (err, res) {
        if (err) {
          cb(err, null);
        } else {
          bins.user.subscribed.documents = _.map(res.rows, function (row) { return row.value.document; });
          cb(null, bins.user.subscribed.documents);
        }
      });
    },

    // Documents the user has contributed to
    function (cb) {
      db.view('collaborator/by_user', { key: [userId] }, function (err, res) {
        if (err) {
          cb(err, null);
        } else {
          bins.user.involved.documents = _.map(res.rows, function (row) { return row.value.document; });
          cb(null, bins.user.involved.documents);
        }
      });
    },

    // Documents resulting from network memberships
    function (cb) {
      graph.fetch({type: "/type/membership", user: userId}, function(err, memberships) {
        var networks = memberships.map(function(m) { return m.get('network')._id; }).values();
        var results = [];

        async.forEach(networks, function(network, cb) {
          graph.fetch({type: "/type/publication", network: network }, function(err, publications) {
            graph.fetch({_id: network}, function(err, nodes) {
              bins.networks[network] = {
                name: nodes.first().get('name'),
                cover: nodes.first().get('cover'),
                documents: publications.map(function(m) { return m.get('document')._id; }).values()
              };
              results = results.concat(bins.networks[network].documents);
              cb();
            });
          });
        }, function(err) {
          cb(null, results);
        });
      });
    }
  ], function (err, results) {
    fetchDocuments(_.uniq(_.flatten(results)), username, function(err, g, count) {
      callback(err, g, count, bins);
    });
  });
};

Document.getContent = function(documentId, callback) {
  var qry = {
    "_id": documentId,
    "children": {
      "_recursive": true
    }
  };

  var graph = new Data.Graph(seed).connect('couch', {url: config.couchdb_url});
  graph.fetch(qry, function(err, nodes) {
    var result = nodes.toJSON(),
        doc = result[documentId];

    callback(null, result, doc._id);
  });
};

function loadDocument(id, version, reader, edit, callback) {

  var graph = new Data.Graph(seed).connect('couch', {
    url: config.couchdb_url
  });

  var result = {};
  var published_on = null; // based on version.created_at

  function load(callback) {

    // Load current Head Version
    // ------------------

    function loadHead(callback) {
      console.log("Loading head version.");
      var qry = {
        "_id": id,
        "children": {
          "_recursive": true
        }
      };

      graph.fetch(qry, function(err, nodes) {
        if (err) return callback(err);
        _.extend(result, nodes.toJSON());

        if (!nodes.get(id).get('published_version')) return callback(null, result, edit, null);
        graph.fetch({_id: nodes.get(id).get('published_version')._id}, function(err, nodes) {
          published_on = nodes.length > 0 ? nodes.first().get('created_at') : null;
          callback(null, result, edit, null);
        });
      });
    }

    // Load published version, if exists
    // ------------------

    function loadPublishedVersion(callback) {
      console.log('Loading published version.');

      graph.fetch({"type": "/type/document", "_id": id}, function(err, nodes) {
        var doc = nodes.first(),
            version = doc.get('published_version');
        if (!version) return callback('not_found');

        graph.fetch({"type": "/type/version", "_id": version._id}, function(err, nodes) {
          var data = nodes.first().get('data');
          data[id].published_version = doc.get('published_version')._id;
          data[id].name = doc.get('name');
          data[id].cover = doc.get('cover');
          _.extend(result, data);
          published_on = nodes.first().get('created_at');
          callback(null, result, false, nodes.first()._id.split('/')[3]);
        });
      });
    }

    // Load a specific version
    // ------------------

    function loadVersion(version, callback) {
      console.log('loading version: '+ version);

      graph.fetch({_id: "/version/"+id.split('/')[3]+"/"+version, document: {}}, function(err, nodes) {
        if (err || nodes.length === 0) return callback('not_found');

        var doc = nodes.select(function(n) {
          return n.type._id === "/type/version"
        }).first();

        var data = doc.get('data');
        data[id].published_version = doc.get('document').get('published_version')._id;

        db.get(id, function(err, doc) {
          if (err || !doc) return callback('not found');
          data[id].name = doc.name;
          data[id].cover = doc.cover;
          _.extend(result, data);
          published_on = nodes.first().get('created_at');
          callback(null, result, false, version);
        });
      });
    }

    // Start the fun
    if (edit) {
      version ? loadVersion(version, callback) : loadHead(callback);
    } else if (version) {
      loadVersion(version, callback);
    } else {
      loadPublishedVersion(function(err, result, authorized, version) {
        if (err) return loadHead(callback);
        callback(null, result, false, version);
      });
    }
  }

  // Attach Meta Info
  function addMetaInfo(callback) {

    function calcCommentCount(callback) {
      async.forEach(_.keys(result), function(nodeId, callback) {
        var node = result[nodeId];
        if (_.include(node.type, "/type/document")) return callback();

        db.view('comment/by_node', {key: [node._id]}, function(err, res) {
          if (!err) node.comment_count = res.rows.length;
          callback();
        });
      }, callback);
    }

    function fetchAttributesAndUser(callback) {
      var doc = result[id];
      graph.fetch({_id: [doc.creator].concat(doc.entities).concat(doc.subjects) }, function(err, nodes) {
        if (err) return callback();
        _.extend(result, nodes.toJSON());
        callback();
      });
    }

    result[id].published_on = published_on;

    Util.count('/counter/document/'+id.split('/')[3]+'/views', function(err, views) {
      result[id].views = views;
      // Check subscriptions
      graph.fetch({type: "/type/subscription", "document": id}, function(err, nodes) {
        if (err) return callback(err);
        result[id].subscribed = graph.find({"user": "/user/"+reader, "document": id}).length > 0 ? true : false;
        result[id].subscribers = nodes.length;

        calcCommentCount(function() {
          fetchAttributesAndUser(callback);
        });
      });
    });
  }

  load(function(err, data, authorized, version) {
    if (err) return callback(err);

    addMetaInfo(function() {
      // Check if already published
      // TODO: shift to authorized method, as its duplicate effort now
      db.view('substance/versions', {endkey: [id], startkey: [id, {}], limit: 1, descending: true}, function(err, res) {
        callback(null, result, edit, version, !err && res.rows.length > 0);
      });
    });
  });
}

// Get a specific version of a document from the database, including all associated content nodes
Document.get = function(username, docname, version, reader, callback) {
  db.view('substance/documents', {key: username+'/'+docname}, function(err, res) {

    if (err) return callback(err);
    if (res.rows.length == 0) return callback("not_found");

    var node = res.rows[0].value;

    isAuthorized(node, reader, function(err, edit) {
      if (err) return callback("not_authorized");

      loadDocument(node._id, version, reader, edit, function(err, result, edit, version, published) {
        if (err) return callback("not_found");
        callback(null, result, node._id, edit, version, published);
      });
    });
  });
};

module.exports = Document;
<|endoftext|>


<commit_before>var mbaasApi = require('fh-mbaas-api');
var express = require('express');
var mbaasExpress = mbaasApi.mbaasExpress();
var cors = require('cors');

// list the endpoints which you want to make securable here
var securableEndpoints;
// fhlint-begin: securable-endpoints
securableEndpoints = ['/hello'];
// fhlint-end

var app = express();

// Enable CORS for all requests
app.use(cors());

// Note: add this first to override mbaas api
app.get('/mbaas/forms/:appId/:formId', function(req, res, next) {
  console.log("Lookup form: " + req.params.formId);
  if (req.params.formId == '560c2d68d1596bad10c427d3') {
    mbaasApi.forms.getForm({
     "_id": req.params.formId
    }, function (err, form) {
     if (err) return res.status(500).json(err);
     console.log("Retrieved form: " + form.name + " = " + form.description);
     var options = {
        "act": "list",
        "type": "cliente", // Entity/Collection name
     };
     mbaasApi.db(options, function (err, data) {
        if (err) return res.status(500).json(err);
        console.log(JSON.stringify(data));
        return res.json(form);
     });
    });
  } else {
    next();
  }
});

// Note: the order which we add middleware to Express here is important!
app.use('/sys', mbaasExpress.sys(securableEndpoints));
app.use('/mbaas', mbaasExpress.mbaas);

// allow serving of static files from the public directory
app.use(express.static(__dirname + '/public'));

// Note: important that this is added just before your own Routes
app.use(mbaasExpress.fhmiddleware());

// fhlint-begin: custom-routes
//app.use('/hello', require('./lib/overrider.js')());
// fhlint-end

// Important that this is last!
app.use(mbaasExpress.errorHandler());

var port = process.env.FH_PORT || process.env.OPENSHIFT_NODEJS_PORT || 8001;
var host = process.env.OPENSHIFT_NODEJS_IP || '0.0.0.0';
var server = app.listen(port, host, function() {
  console.log("App started at: " + new Date() + " on port: " + port);
});
<commit_msg>update file /application.js<commit_after>var mbaasApi = require('fh-mbaas-api');
var express = require('express');
var mbaasExpress = mbaasApi.mbaasExpress();
var cors = require('cors');

// list the endpoints which you want to make securable here
var securableEndpoints;
// fhlint-begin: securable-endpoints
securableEndpoints = ['/hello'];
// fhlint-end

var app = express();

// Enable CORS for all requests
app.use(cors());

// Note: add this first to override mbaas api
app.get('/mbaas/forms/:appId/:formId', function(req, res, next) {
  console.log("Lookup form: " + req.params.formId);
  if (req.params.formId == '560c2d68d1596bad10c427d3') {
    mbaasApi.forms.getForm({
     "_id": req.params.formId
    }, function (err, form) {
     if (err) return res.status(500).json(err);
     console.log("Retrieved form: " + form.name + " = " + form.description);
     var options = {
        "act": "list",
        "type": "cliente", // Entity/Collection name
     };
     mbaasApi.db(options, function (err, data) {
        if (err) return res.status(500).json(err);
        //console.log(JSON.stringify(data));
        var field = form.page[1].fields[0].fieldOptions;
        console.log(JSON.stringify(field));
        return res.json(form);
     });
    });
  } else {
    next();
  }
});

// Note: the order which we add middleware to Express here is important!
app.use('/sys', mbaasExpress.sys(securableEndpoints));
app.use('/mbaas', mbaasExpress.mbaas);

// allow serving of static files from the public directory
app.use(express.static(__dirname + '/public'));

// Note: important that this is added just before your own Routes
app.use(mbaasExpress.fhmiddleware());

// fhlint-begin: custom-routes
//app.use('/hello', require('./lib/overrider.js')());
// fhlint-end

// Important that this is last!
app.use(mbaasExpress.errorHandler());

var port = process.env.FH_PORT || process.env.OPENSHIFT_NODEJS_PORT || 8001;
var host = process.env.OPENSHIFT_NODEJS_IP || '0.0.0.0';
var server = app.listen(port, host, function() {
  console.log("App started at: " + new Date() + " on port: " + port);
});
<|endoftext|>