<commit_before>(function() {
  var module = angular.module('loom_conflict_service', []);

  // Private Variables
  var featureDiffService_ = null;
  var diffService_ = null;
  var pulldownService_ = null;
  var service_ = null;
  var mapService_ = null;
  var dialogService_ = null;
  var geogitService_ = null;
  var translate_ = null;
  var configService_ = null;

  module.provider('conflictService', function() {
    this.features = null;
    this.ours = null;
    this.theirs = null;
    this.ancestor = null;
    this.repoId = null;
    this.currentFeature = null;
    this.ourName = null;
    this.theirName = null;
    this.transaction = null;
    this.mergeBranch = null;

    this.$get = function($rootScope, $location, $translate, diffService, pulldownService, configService,
                         featureDiffService, mapService, dialogService, geogitService) {
      diffService_ = diffService;
      pulldownService_ = pulldownService;
      featureDiffService_ = featureDiffService;
      mapService_ = mapService;
      dialogService_ = dialogService;
      geogitService_ = geogitService;
      translate_ = $translate;
      configService_ = configService;
      service_ = this;
      return this;
    };

    this.abort = function() {
      if (goog.isDefAndNotNull(this.transaction)) {
        this.transaction.abort();
        this.transaction = null;
      }
      this.features = null;
      this.ours = null;
      this.ancestor = null;
      this.repoId = null;
      this.currentFeature = null;
      this.ourName = null;
      this.theirName = null;
    };

    this.selectFeature = function(index) {
      this.currentFeature = this.features[index];
    };

    this.resolveConflict = function(merges, removed) {
      this.currentFeature.resolved = true;
      this.currentFeature.removed = removed;
      this.currentFeature.merges = merges;
      diffService_.resolveFeature(this.currentFeature);
    };

    this.beginResolution = function() {
      if (!goog.isArray(service_.features)) {
        service_.features = [service_.features];
      }
      diffService_.setTitle(translate_('merge_results'));
      diffService_.clickCallback = featureClicked;
      diffService_.mergeDiff = true;
      diffService_.populate(service_.features,
          geogitService_.getRepoById(service_.repoId).name, service_.ourName, service_.theirName);
      pulldownService_.conflictsMode();
    };

    this.commit = function() {
      var conflicts = [];
      var i;
      for (i = 0; i < service_.features.length; i++) {
        var feature = service_.features[i];
        if (feature.change === 'CONFLICT') {
          conflicts.push(feature);
        }
      }

      var conflictsInError = 0;
      commitInternal(conflicts, conflictsInError);
    };

    this.buildMergeMessage = function(status, mergeBranch, useConflicts) {
      var message = {};
      message.merge_branch = mergeBranch;
      if (goog.isDefAndNotNull(status.staged)) {

        forEachArrayish(status.staged, function(entry) {
          var layer = null;
          if (goog.isDefAndNotNull(entry.path) && entry.path.length > 0) {
            layer = entry.path.split('/')[0];
          } else {
            layer = entry.newPath.split('/')[0];
          }
          if (!goog.isDefAndNotNull(message[layer])) {
            message[layer] = {};
          }
          switch (entry.changeType) {
            case 'ADDED':
              if (!goog.isDefAndNotNull(message[layer].added)) {
                message[layer].added = 0;
              }
              message[layer].added++;
              break;
            case 'REMOVED':
              if (!goog.isDefAndNotNull(message[layer].removed)) {
                message[layer].removed = 0;
              }
              message[layer].removed++;
              break;
            case 'MODIFIED':
              if (!goog.isDefAndNotNull(message[layer].modified)) {
                message[layer].modified = 0;
              }
              message[layer].modified++;
              break;
          }
        });
        if (goog.isDefAndNotNull(useConflicts) && useConflicts === true) {
          for (i = 0; i < service_.features.length; i++) {
            var feature = service_.features[i];
            if (feature.change === 'CONFLICT') {
              var layer = feature.id.split('/')[0];
              if (!goog.isDefAndNotNull(message[layer])) {
                message[layer] = {};
              }
              if (!goog.isDefAndNotNull(message[layer].conflicted)) {
                message[layer].conflicted = [];
              }
              message[layer].conflicted.push(feature.id);
            }
          }
        }
      }
      return JSON.stringify(message);
    };
  });

  function featureClicked(feature) {
    var fid = feature.layer + '/' + feature.feature;
    for (var i = 0; i < service_.features.length; i++) {
      if (fid === service_.features[i].id) {
        featureDiffService_.leftName = service_.ourName;
        featureDiffService_.rightName = service_.theirName;
        featureDiffService_.setFeature(
            service_.features[i], service_.ours, service_.theirs, service_.ancestor, 'WORK_HEAD', service_.repoId);
        $('#feature-diff-dialog').modal('show');
        service_.currentFeature = service_.features[i];
        break;
      }
    }
  }

  function commitInternal(conflictList, conflictsInError) {
    if (conflictList.length === 0) {
      if (conflictsInError === 0) {
        service_.transaction.command('status').then(function(response) {
          var commitOptions = new GeoGitCommitOptions();
          commitOptions.all = true;
          commitOptions.message = service_.buildMergeMessage(response, service_.mergeBranch, true);
          commitOptions.authorName = configService_.configuration.userprofilename;
          commitOptions.authorEmail = configService_.configuration.userprofileemail;
          service_.transaction.command('commit', commitOptions).then(function() {
            // commit successful
            service_.transaction.finalize().then(function() {
              // transaction complete
              diffService_.clearDiff();
              service_.transaction = null;
              service_.abort();
              pulldownService_.defaultMode();
              mapService_.dumpTileCache();
            }, function(endTransactionFailure) {
              if (goog.isObject(endTransactionFailure) &&
                  goog.isDefAndNotNull(endTransactionFailure.conflicts)) {
                handleConflicts(endTransactionFailure);
              } else {
                dialogService_.error(translate_('error'), translate_('conflict_unknown_error'));
                console.log('ERROR: EndTransaction failure: ', endTransactionFailure);
              }
            });
          }, function(reject) {
            // couldn't commit
            dialogService_.error(translate_('error'), translate_('conflict_unknown_error'));
            console.log('ERROR: Failed to commit merge: ', reject);
          });
        }, function(reject) {
        });
      } else {
        // couldn't resolve all conflicts
        dialogService_.error(translate_('error'), translate_('unable_to_resolve_conflicts', {value: conflictsInError}));
        console.log('ERROR: ' + conflictsInError + ' conflicts could not be resolved.');
      }
    } else {
      var conflict = conflictList.pop();

      if (goog.isDefAndNotNull(conflict.removed)) {
        var checkoutOptions = new GeoGitCheckoutOptions();
        checkoutOptions.path = conflict.id;
        if (conflict.removed.ours === true) {
          checkoutOptions.ours = true;
        } else {
          checkoutOptions.theirs = true;
        }
        service_.transaction.command('checkout', checkoutOptions).then(function() {
          var addOptions = new GeoGitAddOptions();
          addOptions.path = conflict.id.split('/')[0];
          service_.transaction.command('add', addOptions).then(function() {
            // add successful
            commitInternal(conflictList, conflictsInError);
          }, function(reject) {
            commitInternal(conflictList, conflictsInError + 1);
            console.log('ERROR: Failed to add resolved conflicts to the tree: ', conflict, reject);
          });
        }, function(reject) {
          commitInternal(conflictList, conflictsInError + 1);
          console.log('ERROR: Failed to checkout conflicted feature: ', conflict, reject);
        });

      } else {
        var resolveConflict = {
          path: conflict.id,
          ours: service_.ours,
          theirs: service_.theirs,
          merges: conflict.merges
        };

        geogitService_.post(service_.repoId, 'repo/mergefeature', resolveConflict).then(function(response) {
          var resolveConflictOptions = new GeoGitResolveConflictOptions();
          resolveConflictOptions.path = conflict.id;
          resolveConflictOptions.objectid = response.data;
          service_.transaction.command('resolveconflict', resolveConflictOptions).then(function() {
            // success
            commitInternal(conflictList, conflictsInError);
          }, function(reject) {
            commitInternal(conflictList, conflictsInError + 1);
            console.log('ERROR: Failed to resolve the conflict: ', conflict, reject);
          });
        }, function(reject) {
          commitInternal(conflictList, conflictsInError + 1);
          console.log('ERROR: Failed to merge the conflicted feature: ', conflict, reject);
        });
      }
    }
  }

  function handleConflicts(mergeFailure) {
    var myDialog = dialogService_.warn(translate_('merge_conflicts'), translate_('conflicts_encountered'),
        [translate_('abort'), translate_('resolve_conflicts')], false);

    myDialog.then(function(button) {
      switch (button) {
        case 0:
          service_.transaction.abort();
          break;
        case 1:
          service_.ourName = translate_('transaction');
          service_.theirName = translate_('repository');
          service_.ours = mergeFailure.ours;
          service_.theirs = mergeFailure.theirs;
          service_.ancestor = mergeFailure.ancestor;
          service_.features = mergeFailure.Feature;
          service_.mergeBranch = translate_('transaction');
          service_.beginResolution();
          break;
      }
    });
  }
}());
<commit_msg>changed merge message.<commit_after>(function() {
  var module = angular.module('loom_conflict_service', []);

  // Private Variables
  var featureDiffService_ = null;
  var diffService_ = null;
  var pulldownService_ = null;
  var service_ = null;
  var mapService_ = null;
  var dialogService_ = null;
  var geogitService_ = null;
  var translate_ = null;
  var configService_ = null;

  module.provider('conflictService', function() {
    this.features = null;
    this.ours = null;
    this.theirs = null;
    this.ancestor = null;
    this.repoId = null;
    this.currentFeature = null;
    this.ourName = null;
    this.theirName = null;
    this.transaction = null;
    this.mergeBranch = null;

    this.$get = function($rootScope, $location, $translate, diffService, pulldownService, configService,
                         featureDiffService, mapService, dialogService, geogitService) {
      diffService_ = diffService;
      pulldownService_ = pulldownService;
      featureDiffService_ = featureDiffService;
      mapService_ = mapService;
      dialogService_ = dialogService;
      geogitService_ = geogitService;
      translate_ = $translate;
      configService_ = configService;
      service_ = this;
      return this;
    };

    this.abort = function() {
      if (goog.isDefAndNotNull(this.transaction)) {
        this.transaction.abort();
        this.transaction = null;
      }
      this.features = null;
      this.ours = null;
      this.ancestor = null;
      this.repoId = null;
      this.currentFeature = null;
      this.ourName = null;
      this.theirName = null;
    };

    this.selectFeature = function(index) {
      this.currentFeature = this.features[index];
    };

    this.resolveConflict = function(merges, removed) {
      this.currentFeature.resolved = true;
      this.currentFeature.removed = removed;
      this.currentFeature.merges = merges;
      diffService_.resolveFeature(this.currentFeature);
    };

    this.beginResolution = function() {
      if (!goog.isArray(service_.features)) {
        service_.features = [service_.features];
      }
      diffService_.setTitle(translate_('merge_results'));
      diffService_.clickCallback = featureClicked;
      diffService_.mergeDiff = true;
      diffService_.populate(service_.features,
          geogitService_.getRepoById(service_.repoId).name, service_.ourName, service_.theirName);
      pulldownService_.conflictsMode();
    };

    this.commit = function() {
      var conflicts = [];
      var i;
      for (i = 0; i < service_.features.length; i++) {
        var feature = service_.features[i];
        if (feature.change === 'CONFLICT') {
          conflicts.push(feature);
        }
      }

      var conflictsInError = 0;
      commitInternal(conflicts, conflictsInError);
    };

    this.buildMergeMessage = function(status, mergeBranch, useConflicts) {
      var i = 0;
      var layer = null;
      var message = 'Merged branch \'' + mergeBranch + '\' ';
      if (goog.isDefAndNotNull(status.staged)) {
        var changes = {};
        if (goog.isDefAndNotNull(useConflicts) && useConflicts === true) {
          for (i = 0; i < service_.features.length; i++) {
            var feature = service_.features[i];
            if (feature.change === 'CONFLICT') {
              layer = feature.id.split('/')[0];
              if (!goog.isDefAndNotNull(changes[layer])) {
                changes[layer] = {};
              }
              if (!goog.isDefAndNotNull(changes[layer].conflicted)) {
                changes[layer].conflicted = [];
              }
              changes[layer].conflicted.push(feature.id);
            }
          }
        }

        for (var key in changes) {
          layer = changes[key];
          message += '\nConflicts in \'' + key + '\': ';
          for (i = 0; i < layer.conflicted.length; i++) {
            message += '\n' + layer.conflicted[i];
          }
          message += '\n';
        }
      }
      message += 'via MapLoom';
      return message;
    };
  });

  function featureClicked(feature) {
    var fid = feature.layer + '/' + feature.feature;
    for (var i = 0; i < service_.features.length; i++) {
      if (fid === service_.features[i].id) {
        featureDiffService_.leftName = service_.ourName;
        featureDiffService_.rightName = service_.theirName;
        featureDiffService_.setFeature(
            service_.features[i], service_.ours, service_.theirs, service_.ancestor, 'WORK_HEAD', service_.repoId);
        $('#feature-diff-dialog').modal('show');
        service_.currentFeature = service_.features[i];
        break;
      }
    }
  }

  function commitInternal(conflictList, conflictsInError) {
    if (conflictList.length === 0) {
      if (conflictsInError === 0) {
        service_.transaction.command('status').then(function(response) {
          var commitOptions = new GeoGitCommitOptions();
          commitOptions.all = true;
          commitOptions.message = service_.buildMergeMessage(response, service_.mergeBranch, true);
          commitOptions.authorName = configService_.configuration.userprofilename;
          commitOptions.authorEmail = configService_.configuration.userprofileemail;
          service_.transaction.command('commit', commitOptions).then(function() {
            // commit successful
            service_.transaction.finalize().then(function() {
              // transaction complete
              diffService_.clearDiff();
              service_.transaction = null;
              service_.abort();
              pulldownService_.defaultMode();
              mapService_.dumpTileCache();
            }, function(endTransactionFailure) {
              if (goog.isObject(endTransactionFailure) &&
                  goog.isDefAndNotNull(endTransactionFailure.conflicts)) {
                handleConflicts(endTransactionFailure);
              } else {
                dialogService_.error(translate_('error'), translate_('conflict_unknown_error'));
                console.log('ERROR: EndTransaction failure: ', endTransactionFailure);
              }
            });
          }, function(reject) {
            // couldn't commit
            dialogService_.error(translate_('error'), translate_('conflict_unknown_error'));
            console.log('ERROR: Failed to commit merge: ', reject);
          });
        }, function(reject) {
        });
      } else {
        // couldn't resolve all conflicts
        dialogService_.error(translate_('error'), translate_('unable_to_resolve_conflicts', {value: conflictsInError}));
        console.log('ERROR: ' + conflictsInError + ' conflicts could not be resolved.');
      }
    } else {
      var conflict = conflictList.pop();

      if (goog.isDefAndNotNull(conflict.removed)) {
        var checkoutOptions = new GeoGitCheckoutOptions();
        checkoutOptions.path = conflict.id;
        if (conflict.removed.ours === true) {
          checkoutOptions.ours = true;
        } else {
          checkoutOptions.theirs = true;
        }
        service_.transaction.command('checkout', checkoutOptions).then(function() {
          var addOptions = new GeoGitAddOptions();
          addOptions.path = conflict.id.split('/')[0];
          service_.transaction.command('add', addOptions).then(function() {
            // add successful
            commitInternal(conflictList, conflictsInError);
          }, function(reject) {
            commitInternal(conflictList, conflictsInError + 1);
            console.log('ERROR: Failed to add resolved conflicts to the tree: ', conflict, reject);
          });
        }, function(reject) {
          commitInternal(conflictList, conflictsInError + 1);
          console.log('ERROR: Failed to checkout conflicted feature: ', conflict, reject);
        });

      } else {
        var resolveConflict = {
          path: conflict.id,
          ours: service_.ours,
          theirs: service_.theirs,
          merges: conflict.merges
        };

        geogitService_.post(service_.repoId, 'repo/mergefeature', resolveConflict).then(function(response) {
          var resolveConflictOptions = new GeoGitResolveConflictOptions();
          resolveConflictOptions.path = conflict.id;
          resolveConflictOptions.objectid = response.data;
          service_.transaction.command('resolveconflict', resolveConflictOptions).then(function() {
            // success
            commitInternal(conflictList, conflictsInError);
          }, function(reject) {
            commitInternal(conflictList, conflictsInError + 1);
            console.log('ERROR: Failed to resolve the conflict: ', conflict, reject);
          });
        }, function(reject) {
          commitInternal(conflictList, conflictsInError + 1);
          console.log('ERROR: Failed to merge the conflicted feature: ', conflict, reject);
        });
      }
    }
  }

  function handleConflicts(mergeFailure) {
    var myDialog = dialogService_.warn(translate_('merge_conflicts'), translate_('conflicts_encountered'),
        [translate_('abort'), translate_('resolve_conflicts')], false);

    myDialog.then(function(button) {
      switch (button) {
        case 0:
          service_.transaction.abort();
          break;
        case 1:
          service_.ourName = translate_('transaction');
          service_.theirName = translate_('repository');
          service_.ours = mergeFailure.ours;
          service_.theirs = mergeFailure.theirs;
          service_.ancestor = mergeFailure.ancestor;
          service_.features = mergeFailure.Feature;
          service_.mergeBranch = translate_('transaction');
          service_.beginResolution();
          break;
      }
    });
  }
}());
<|endoftext|>


<commit_before>(function(){
  var Pos = CodeMirror.Pos;

  function SearchCursor(doc, query, pos, caseFold) {
    this.atOccurrence = false; this.doc = doc;
    if (caseFold == null && typeof query == "string") caseFold = false;

    pos = pos ? doc.clipPos(pos) : Pos(0, 0);
    this.pos = {from: pos, to: pos};

    // The matches method is filled in based on the type of query.
    // It takes a position and a direction, and returns an object
    // describing the next occurrence of the query, or null if no
    // more matches were found.
    if (typeof query != "string") { // Regexp match
      if (!query.global) query = new RegExp(query.source, query.ignoreCase ? "ig" : "g");
      this.matches = function(reverse, pos) {
        if (reverse) {
          query.lastIndex = 0;
          var line = doc.getLine(pos.line).slice(0, pos.ch), cutOff = 0, match, start;
          for (;;) {
            query.lastIndex = cutOff;
            var newMatch = query.exec(line);
            if (!newMatch) break;
            match = newMatch;
            start = match.index;
            cutOff = match.index + (match[0].length || 1);
            if (cutOff == line.length) break;
          }
          var matchLen = (match && match[0].length) || 0;
          if (!matchLen) {
            if (start == 0 && line.length == 0) {match = undefined;}
            else if (start != doc.getLine(pos.line).length) {
              matchLen++;
            }
          }
        } else {
          query.lastIndex = pos.ch;
          var line = doc.getLine(pos.line), match = query.exec(line);
          var matchLen = (match && match[0].length) || 0;
          var start = match && match.index;
          if (start + matchLen != line.length && !matchLen) matchLen = 1;
        }
        if (match && matchLen)
          return {from: Pos(pos.line, start),
                  to: Pos(pos.line, start + matchLen),
                  match: match};
      };
    } else { // String query
      if (caseFold) query = query.toLowerCase();
      var fold = caseFold ? function(str){return str.toLowerCase();} : function(str){return str;};
      var target = query.split("\n");
      // Different methods for single-line and multi-line queries
      if (target.length == 1) {
        if (!query.length) {
          // Empty string would match anything and never progress, so
          // we define it to match nothing instead.
          this.matches = function() {};
        } else {
          this.matches = function(reverse, pos) {
            var line = fold(doc.getLine(pos.line)), len = query.length, match;
            if (reverse ? (pos.ch >= len && (match = line.lastIndexOf(query, pos.ch - len)) != -1)
                        : (match = line.indexOf(query, pos.ch)) != -1)
              return {from: Pos(pos.line, match),
                      to: Pos(pos.line, match + len)};
          };
        }
      } else {
        this.matches = function(reverse, pos) {
          var ln = pos.line, idx = (reverse ? target.length - 1 : 0), match = target[idx], line = fold(doc.getLine(ln));
          var offsetA = (reverse ? line.indexOf(match) + match.length : line.lastIndexOf(match));
          if (reverse ? offsetA >= pos.ch || offsetA != match.length
              : offsetA <= pos.ch || offsetA != line.length - match.length)
            return;
          for (;;) {
            if (reverse ? !ln : ln == doc.lineCount() - 1) return;
            line = fold(doc.getLine(ln += reverse ? -1 : 1));
            match = target[reverse ? --idx : ++idx];
            if (idx > 0 && idx < target.length - 1) {
              if (line != match) return;
              else continue;
            }
            var offsetB = (reverse ? line.lastIndexOf(match) : line.indexOf(match) + match.length);
            if (reverse ? offsetB != line.length - match.length : offsetB != match.length)
              return;
            var start = Pos(pos.line, offsetA), end = Pos(ln, offsetB);
            return {from: reverse ? end : start, to: reverse ? start : end};
          }
        };
      }
    }
  }

  SearchCursor.prototype = {
    findNext: function() {return this.find(false);},
    findPrevious: function() {return this.find(true);},

    find: function(reverse) {
      var self = this, pos = this.doc.clipPos(reverse ? this.pos.from : this.pos.to);
      function savePosAndFail(line) {
        var pos = Pos(line, 0);
        self.pos = {from: pos, to: pos};
        self.atOccurrence = false;
        return false;
      }

      for (;;) {
        if (this.pos = this.matches(reverse, pos)) {
          if (!this.pos.from || !this.pos.to) { console.log(this.matches, this.pos); }
          this.atOccurrence = true;
          return this.pos.match || true;
        }
        if (reverse) {
          if (!pos.line) return savePosAndFail(0);
          pos = Pos(pos.line-1, this.doc.getLine(pos.line-1).length);
        }
        else {
          var maxLine = this.doc.lineCount();
          if (pos.line == maxLine - 1) return savePosAndFail(maxLine);
          pos = Pos(pos.line + 1, 0);
        }
      }
    },

    from: function() {if (this.atOccurrence) return this.pos.from;},
    to: function() {if (this.atOccurrence) return this.pos.to;},

    replace: function(newText) {
      if (!this.atOccurrence) return;
      var lines = CodeMirror.splitLines(newText);
      this.doc.replaceRange(lines, this.pos.from, this.pos.to);
      this.pos.to = Pos(this.pos.from.line + lines.length - 1,
                        lines[lines.length - 1].length + (lines.length == 1 ? this.pos.from.ch : 0));
    }
  };

  CodeMirror.defineExtension("getSearchCursor", function(query, pos, caseFold) {
    return new SearchCursor(this.doc, query, pos, caseFold);
  });
  CodeMirror.defineDocExtension("getSearchCursor", function(query, pos, caseFold) {
    return new SearchCursor(this, query, pos, caseFold);
  });
})();
<commit_msg>[searchcursor addon] Fix multiple-line search<commit_after>(function(){
  var Pos = CodeMirror.Pos;

  function SearchCursor(doc, query, pos, caseFold) {
    this.atOccurrence = false; this.doc = doc;
    if (caseFold == null && typeof query == "string") caseFold = false;

    pos = pos ? doc.clipPos(pos) : Pos(0, 0);
    this.pos = {from: pos, to: pos};

    // The matches method is filled in based on the type of query.
    // It takes a position and a direction, and returns an object
    // describing the next occurrence of the query, or null if no
    // more matches were found.
    if (typeof query != "string") { // Regexp match
      if (!query.global) query = new RegExp(query.source, query.ignoreCase ? "ig" : "g");
      this.matches = function(reverse, pos) {
        if (reverse) {
          query.lastIndex = 0;
          var line = doc.getLine(pos.line).slice(0, pos.ch), cutOff = 0, match, start;
          for (;;) {
            query.lastIndex = cutOff;
            var newMatch = query.exec(line);
            if (!newMatch) break;
            match = newMatch;
            start = match.index;
            cutOff = match.index + (match[0].length || 1);
            if (cutOff == line.length) break;
          }
          var matchLen = (match && match[0].length) || 0;
          if (!matchLen) {
            if (start == 0 && line.length == 0) {match = undefined;}
            else if (start != doc.getLine(pos.line).length) {
              matchLen++;
            }
          }
        } else {
          query.lastIndex = pos.ch;
          var line = doc.getLine(pos.line), match = query.exec(line);
          var matchLen = (match && match[0].length) || 0;
          var start = match && match.index;
          if (start + matchLen != line.length && !matchLen) matchLen = 1;
        }
        if (match && matchLen)
          return {from: Pos(pos.line, start),
                  to: Pos(pos.line, start + matchLen),
                  match: match};
      };
    } else { // String query
      if (caseFold) query = query.toLowerCase();
      var fold = caseFold ? function(str){return str.toLowerCase();} : function(str){return str;};
      var target = query.split("\n");
      // Different methods for single-line and multi-line queries
      if (target.length == 1) {
        if (!query.length) {
          // Empty string would match anything and never progress, so
          // we define it to match nothing instead.
          this.matches = function() {};
        } else {
          this.matches = function(reverse, pos) {
            var line = fold(doc.getLine(pos.line)), len = query.length, match;
            if (reverse ? (pos.ch >= len && (match = line.lastIndexOf(query, pos.ch - len)) != -1)
                        : (match = line.indexOf(query, pos.ch)) != -1)
              return {from: Pos(pos.line, match),
                      to: Pos(pos.line, match + len)};
          };
        }
      } else {
        this.matches = function(reverse, pos) {
          var ln = pos.line, idx = (reverse ? target.length - 1 : 0), match = target[idx], line = fold(doc.getLine(ln));
          var offsetA = (reverse ? line.indexOf(match) + match.length : line.lastIndexOf(match));
          if (reverse ? offsetA > pos.ch || offsetA != match.length
              : offsetA < pos.ch || offsetA != line.length - match.length)
            return;
          for (;;) {
            if (reverse ? !ln : ln == doc.lineCount() - 1) return;
            line = fold(doc.getLine(ln += reverse ? -1 : 1));
            match = target[reverse ? --idx : ++idx];
            if (idx > 0 && idx < target.length - 1) {
              if (line != match) return;
              else continue;
            }
            var offsetB = (reverse ? line.lastIndexOf(match) : line.indexOf(match) + match.length);
            if (reverse ? offsetB != line.length - match.length : offsetB != match.length)
              return;
            var start = Pos(pos.line, offsetA), end = Pos(ln, offsetB);
            return {from: reverse ? end : start, to: reverse ? start : end};
          }
        };
      }
    }
  }

  SearchCursor.prototype = {
    findNext: function() {return this.find(false);},
    findPrevious: function() {return this.find(true);},

    find: function(reverse) {
      var self = this, pos = this.doc.clipPos(reverse ? this.pos.from : this.pos.to);
      function savePosAndFail(line) {
        var pos = Pos(line, 0);
        self.pos = {from: pos, to: pos};
        self.atOccurrence = false;
        return false;
      }

      for (;;) {
        if (this.pos = this.matches(reverse, pos)) {
          if (!this.pos.from || !this.pos.to) { console.log(this.matches, this.pos); }
          this.atOccurrence = true;
          return this.pos.match || true;
        }
        if (reverse) {
          if (!pos.line) return savePosAndFail(0);
          pos = Pos(pos.line-1, this.doc.getLine(pos.line-1).length);
        }
        else {
          var maxLine = this.doc.lineCount();
          if (pos.line == maxLine - 1) return savePosAndFail(maxLine);
          pos = Pos(pos.line + 1, 0);
        }
      }
    },

    from: function() {if (this.atOccurrence) return this.pos.from;},
    to: function() {if (this.atOccurrence) return this.pos.to;},

    replace: function(newText) {
      if (!this.atOccurrence) return;
      var lines = CodeMirror.splitLines(newText);
      this.doc.replaceRange(lines, this.pos.from, this.pos.to);
      this.pos.to = Pos(this.pos.from.line + lines.length - 1,
                        lines[lines.length - 1].length + (lines.length == 1 ? this.pos.from.ch : 0));
    }
  };

  CodeMirror.defineExtension("getSearchCursor", function(query, pos, caseFold) {
    return new SearchCursor(this.doc, query, pos, caseFold);
  });
  CodeMirror.defineDocExtension("getSearchCursor", function(query, pos, caseFold) {
    return new SearchCursor(this, query, pos, caseFold);
  });
})();
<|endoftext|>


<commit_before>import {
  BadRequest,
  InternalServerError,
  NotImplemented,
  NotFound,
  Codes
} from 'netiam-errors'
import {
  ONE_TO_MANY,
  MANY_TO_ONE
} from '../rest/relationships'
import jsonapi from '../rest/jsonapi'
import {normalize, params} from '../rest/query'
import filter from '../rest/odata/filter'
import {getCollectionByIdentity} from '../db'
import dbg from 'debug'

const debug = dbg('netiam:plugins:jsonapi')

function request() {
  return Promise.reject(
    new NotImplemnted(Codes.E1000, 'jsonapi#request is not implemented'))
}

function response(spec) {
  const collection = getCollectionByIdentity(spec.collection)
  const {relationshipField} = spec
  const relationshipCollection = getCollectionByIdentity(spec.relationshipCollection)
  const {map} = spec
  const {idField = 'id'} = spec
  const {relationship} = spec

  function numTotalDocuments(req, query) {
    // filter
    let f = filter(query.filter)

    // handle relationships
    if (relationship === MANY_TO_ONE &&
      relationshipField &&
      relationshipCollection &&
      map) {

      const key = Object.keys(map)[0]
      const val = req.params[map[key].substr(1)]

      return collection
        .findOne({[key]: val})
        .then(doc => {
          if (!doc) {
            throw new NotFound(Codes.E1000, 'Base document not found')
          }

          // query
          return relationshipCollection
            .count(f.toObject())
            .where({[idField]: doc[relationshipField]})
        })
    }

    if (relationship === ONE_TO_MANY) {
      f = f.where(params({
        req,
        map
      }))

      // query
      return collection.count(f.toObject())
    }

    // query
    // FIXME ONE_TO_MANY and no relationship is different
    return collection.count()
  }

  return (req, res) => {
    if (!res.body) {
      return res
        .status(204)
        .end()
    }

    const queryNormalized = normalize({
      req,
      idField
    })

    return numTotalDocuments(req, queryNormalized)
      .then(count => {
        res
          .set('Content-Type', 'application/vnd.api+json')
          .json(jsonapi.transform({
            req,
            res,
            count,
            itemsPerPage: queryNormalized.itemsPerPage,
            collection
          }))
      })
  }

}

export default Object.freeze({
  req: request,
  res: response
})
<commit_msg>fix: catch potential errors<commit_after>import {
  BadRequest,
  InternalServerError,
  NotImplemented,
  NotFound,
  Codes
} from 'netiam-errors'
import {
  ONE_TO_MANY,
  MANY_TO_ONE
} from '../rest/relationships'
import jsonapi from '../rest/jsonapi'
import {normalize, params} from '../rest/query'
import filter from '../rest/odata/filter'
import {getCollectionByIdentity} from '../db'
import dbg from 'debug'

const debug = dbg('netiam:plugins:jsonapi')

function request() {
  return Promise.reject(
    new NotImplemnted(Codes.E1000, 'jsonapi#request is not implemented'))
}

function response(spec) {
  const collection = getCollectionByIdentity(spec.collection)
  const {relationshipField} = spec
  const relationshipCollection = getCollectionByIdentity(spec.relationshipCollection)
  const {map} = spec
  const {idField = 'id'} = spec
  const {relationship} = spec

  function numTotalDocuments(req, query) {
    // filter
    let f = filter(query.filter)

    // handle relationships
    if (relationship === MANY_TO_ONE &&
      relationshipField &&
      relationshipCollection &&
      map) {

      const key = Object.keys(map)[0]
      const val = req.params[map[key].substr(1)]

      return collection
        .findOne({[key]: val})
        .then(doc => {
          if (!doc) {
            throw new NotFound(Codes.E1000, 'Base document not found')
          }

          // query
          return relationshipCollection
            .count(f.toObject())
            .where({[idField]: doc[relationshipField]})
        })
    }

    if (relationship === ONE_TO_MANY) {
      f = f.where(params({
        req,
        map
      }))

      // query
      return collection.count(f.toObject())
    }

    // query
    // FIXME ONE_TO_MANY and no relationship is different
    return collection.count()
  }

  return (req, res) => {
    if (!res.body) {
      return res
        .status(204)
        .end()
    }

    const queryNormalized = normalize({
      req,
      idField
    })

    return numTotalDocuments(req, queryNormalized)
      .then(count => {
        try {
          res.body = jsonapi.transform({
            req,
            res,
            count,
            itemsPerPage: queryNormalized.itemsPerPage,
            collection
          })
          res
            .set('Content-Type', 'application/vnd.api+json')
            .json(res.body)
        } catch (err) {
          console.log(err.stack)
          return Promise.reject(new InternalServerError(Codes.E1000, err))
        }
      })
  }

}

export default Object.freeze({
  req: request,
  res: response
})
<|endoftext|>


<commit_before>/**
 * LookupElement is a mixin that creates a {@link OO.ui.MenuSelectWidget menu} of suggested
 * values for a {@link OO.ui.TextInputWidget text input widget}. Suggested values are based on
 * the characters the user types into the text input field and, in general, the menu is only
 * displayed when the user types. If a suggested value is chosen from the lookup menu, that value
 * becomes the value of the input field.
 *
 * Note that a new menu of suggested items is displayed when a value is chosen from the
 * lookup menu. If this is not the desired behavior, disable lookup menus with the
 * #setLookupsDisabled method, then set the value, then re-enable lookups.
 *
 * See the [OOUI demos][1] for an example.
 *
 * [1]: https://doc.wikimedia.org/oojs-ui/master/demos/#LookupElement-try-inputting-an-integer
 *
 * @class
 * @abstract
 * @mixins OO.ui.mixin.RequestManager
 *
 * @constructor
 * @param {Object} [config] Configuration options
 * @cfg {jQuery} [$overlay] Overlay for the lookup menu; defaults to relative positioning.
 *  See <https://www.mediawiki.org/wiki/OOUI/Concepts#Overlays>.
 * @cfg {jQuery} [$container=this.$element] The container element. The lookup menu is rendered
 *  beneath the specified element.
 * @cfg {Object} [menu] Configuration options to pass to
 *  {@link OO.ui.MenuSelectWidget menu select widget}
 * @cfg {boolean} [allowSuggestionsWhenEmpty=false] Request and display a lookup menu when the
 *  text input is empty.
 *  By default, the lookup menu is not generated and displayed until the user begins to type.
 * @cfg {boolean} [highlightFirst=true] Whether the first lookup result should be highlighted
 *  (so, that the user can take it over into the input with simply pressing return) automatically
 *  or not.
 * @cfg {boolean} [showSuggestionsOnFocus=true] Show suggestions when focusing the input. If this
 *  is set to false, suggestions will still be shown on a mousedown triggered focus. This matches
 *  browser autocomplete behavior.
 */
OO.ui.mixin.LookupElement = function OoUiMixinLookupElement( config ) {
	// Configuration initialization
	config = $.extend( { highlightFirst: true }, config );

	// Mixin constructors
	OO.ui.mixin.RequestManager.call( this, config );

	// Properties
	this.$overlay = ( config.$overlay === true ?
		OO.ui.getDefaultOverlay() : config.$overlay ) || this.$element;
	this.lookupMenu = new OO.ui.MenuSelectWidget( $.extend( {
		widget: this,
		input: this,
		$floatableContainer: config.$container || this.$element
	}, config.menu ) );

	this.allowSuggestionsWhenEmpty = config.allowSuggestionsWhenEmpty || false;

	this.lookupsDisabled = false;
	this.lookupInputFocused = false;
	this.lookupHighlightFirstItem = config.highlightFirst;
	this.showSuggestionsOnFocus = config.showSuggestionsOnFocus !== false;

	// Events
	this.$input.on( {
		focus: this.onLookupInputFocus.bind( this ),
		blur: this.onLookupInputBlur.bind( this ),
		mousedown: this.onLookupInputMouseDown.bind( this )
	} );
	this.connect( this, {
		change: 'onLookupInputChange'
	} );
	this.lookupMenu.connect( this, {
		toggle: 'onLookupMenuToggle',
		choose: 'onLookupMenuItemChoose'
	} );

	// Initialization
	this.$input.attr( {
		role: 'combobox',
		'aria-owns': this.lookupMenu.getElementId(),
		'aria-autocomplete': 'list'
	} );
	this.$element.addClass( 'oo-ui-lookupElement' );
	this.lookupMenu.$element.addClass( 'oo-ui-lookupElement-menu' );
	this.$overlay.append( this.lookupMenu.$element );
};

/* Setup */

OO.mixinClass( OO.ui.mixin.LookupElement, OO.ui.mixin.RequestManager );

/* Methods */

/**
 * Handle input focus event.
 *
 * @protected
 * @param {jQuery.Event} e Input focus event
 */
OO.ui.mixin.LookupElement.prototype.onLookupInputFocus = function () {
	this.lookupInputFocused = true;
	if ( this.showSuggestionsOnFocus ) {
		this.populateLookupMenu();
	}
};

/**
 * Handle input blur event.
 *
 * @protected
 * @param {jQuery.Event} e Input blur event
 */
OO.ui.mixin.LookupElement.prototype.onLookupInputBlur = function () {
	this.closeLookupMenu();
	this.lookupInputFocused = false;
};

/**
 * Handle input mouse down event.
 *
 * @protected
 * @param {jQuery.Event} e Input mouse down event
 */
OO.ui.mixin.LookupElement.prototype.onLookupInputMouseDown = function () {
	if (
		!this.lookupMenu.isVisible() &&
		(
			// Open the menu if the input was already focused.
			// This way we allow the user to open the menu again after closing it with Escape (esc)
			// by clicking in the input.
			this.lookupInputFocused ||
			// If showSuggestionsOnFocus is disabled, still open the menu on mousedown.
			!this.showSuggestionsOnFocus
		)
	) {
		this.populateLookupMenu();
	}
};

/**
 * Handle input change event.
 *
 * @protected
 * @param {string} value New input value
 */
OO.ui.mixin.LookupElement.prototype.onLookupInputChange = function () {
	if ( this.lookupInputFocused ) {
		this.populateLookupMenu();
	}
};

/**
 * Handle the lookup menu being shown/hidden.
 *
 * @protected
 * @param {boolean} visible Whether the lookup menu is now visible.
 */
OO.ui.mixin.LookupElement.prototype.onLookupMenuToggle = function ( visible ) {
	if ( !visible ) {
		// When the menu is hidden, abort any active request and clear the menu.
		// This has to be done here in addition to closeLookupMenu(), because
		// MenuSelectWidget will close itself when the user presses Escape (esc).
		this.abortLookupRequest();
		this.lookupMenu.clearItems();
	}
};

/**
 * Handle menu item 'choose' event, updating the text input value to the value of the clicked item.
 *
 * @protected
 * @param {OO.ui.MenuOptionWidget} item Selected item
 */
OO.ui.mixin.LookupElement.prototype.onLookupMenuItemChoose = function ( item ) {
	this.setValue( item.getData() );
};

/**
 * Get lookup menu.
 *
 * @private
 * @return {OO.ui.MenuSelectWidget}
 */
OO.ui.mixin.LookupElement.prototype.getLookupMenu = function () {
	return this.lookupMenu;
};

/**
 * Disable or re-enable lookups.
 *
 * When lookups are disabled, calls to #populateLookupMenu will be ignored.
 *
 * @param {boolean} disabled Disable lookups
 */
OO.ui.mixin.LookupElement.prototype.setLookupsDisabled = function ( disabled ) {
	this.lookupsDisabled = !!disabled;
};

/**
 * Open the menu. If there are no entries in the menu, this does nothing.
 *
 * @private
 * @chainable
 * @return {OO.ui.Element} The element, for chaining
 */
OO.ui.mixin.LookupElement.prototype.openLookupMenu = function () {
	if ( !this.lookupMenu.isEmpty() ) {
		this.lookupMenu.toggle( true );
	}
	return this;
};

/**
 * Close the menu, empty it, and abort any pending request.
 *
 * @private
 * @chainable
 * @return {OO.ui.Element} The element, for chaining
 */
OO.ui.mixin.LookupElement.prototype.closeLookupMenu = function () {
	this.lookupMenu.toggle( false );
	this.abortLookupRequest();
	this.lookupMenu.clearItems();
	return this;
};

/**
 * Request menu items based on the input's current value, and when they arrive,
 * populate the menu with these items and show the menu.
 *
 * If lookups have been disabled with #setLookupsDisabled, this function does nothing.
 *
 * @private
 * @chainable
 * @return {OO.ui.Element} The element, for chaining
 */
OO.ui.mixin.LookupElement.prototype.populateLookupMenu = function () {
	var widget = this,
		value = this.getValue();

	if ( this.lookupsDisabled || this.isReadOnly() ) {
		return;
	}

	// If the input is empty, clear the menu, unless suggestions when empty are allowed.
	if ( !this.allowSuggestionsWhenEmpty && value === '' ) {
		this.closeLookupMenu();
	// Skip population if there is already a request pending for the current value
	} else if ( value !== this.lookupQuery ) {
		this.getLookupMenuItems()
			.done( function ( items ) {
				widget.lookupMenu.clearItems();
				if ( items.length ) {
					widget.lookupMenu
						.addItems( items )
						.toggle( true );
					widget.initializeLookupMenuSelection();
				} else {
					widget.lookupMenu.toggle( false );
				}
			} )
			.fail( function () {
				widget.lookupMenu.clearItems();
				widget.lookupMenu.toggle( false );
			} );
	}

	return this;
};

/**
 * Highlight the first selectable item in the menu, if configured.
 *
 * @private
 * @chainable
 */
OO.ui.mixin.LookupElement.prototype.initializeLookupMenuSelection = function () {
	if ( this.lookupHighlightFirstItem && !this.lookupMenu.findSelectedItem() ) {
		this.lookupMenu.highlightItem( this.lookupMenu.findFirstSelectableItem() );
	}
};

/**
 * Get lookup menu items for the current query.
 *
 * @private
 * @return {jQuery.Promise} Promise object which will be passed menu items as the first argument of
 *   the done event. If the request was aborted to make way for a subsequent request, this promise
 *   will not be rejected: it will remain pending forever.
 */
OO.ui.mixin.LookupElement.prototype.getLookupMenuItems = function () {
	return this.getRequestData().then( function ( data ) {
		return this.getLookupMenuOptionsFromData( data );
	}.bind( this ) );
};

/**
 * Abort the currently pending lookup request, if any.
 *
 * @private
 */
OO.ui.mixin.LookupElement.prototype.abortLookupRequest = function () {
	this.abortRequest();
};

/**
 * Get a new request object of the current lookup query value.
 *
 * @protected
 * @method
 * @abstract
 * @return {jQuery.Promise} jQuery AJAX object, or promise object with an .abort() method
 */
OO.ui.mixin.LookupElement.prototype.getLookupRequest = null;

/**
 * Pre-process data returned by the request from #getLookupRequest.
 *
 * The return value of this function will be cached, and any further queries for the given value
 * will use the cache rather than doing API requests.
 *
 * @protected
 * @method
 * @abstract
 * @param {Mixed} response Response from server
 * @return {Mixed} Cached result data
 */
OO.ui.mixin.LookupElement.prototype.getLookupCacheDataFromResponse = null;

/**
 * Get a list of menu option widgets from the (possibly cached) data returned by
 * #getLookupCacheDataFromResponse.
 *
 * @protected
 * @method
 * @abstract
 * @param {Mixed} data Cached result data, usually an array
 * @return {OO.ui.MenuOptionWidget[]} Menu items
 */
OO.ui.mixin.LookupElement.prototype.getLookupMenuOptionsFromData = null;

/**
 * Set the read-only state of the widget.
 *
 * This will also disable/enable the lookups functionality.
 *
 * @param {boolean} readOnly Make input read-only
 * @chainable
 * @return {OO.ui.Element} The element, for chaining
 */
OO.ui.mixin.LookupElement.prototype.setReadOnly = function ( readOnly ) {
	// Parent method
	// Note: Calling #setReadOnly this way assumes this is mixed into an OO.ui.TextInputWidget
	OO.ui.TextInputWidget.prototype.setReadOnly.call( this, readOnly );

	// During construction, #setReadOnly is called before the OO.ui.mixin.LookupElement constructor.
	if ( this.isReadOnly() && this.lookupMenu ) {
		this.closeLookupMenu();
	}

	return this;
};

/**
 * @inheritdoc OO.ui.mixin.RequestManager
 */
OO.ui.mixin.LookupElement.prototype.getRequestQuery = function () {
	return this.getValue();
};

/**
 * @inheritdoc OO.ui.mixin.RequestManager
 */
OO.ui.mixin.LookupElement.prototype.getRequest = function () {
	return this.getLookupRequest();
};

/**
 * @inheritdoc OO.ui.mixin.RequestManager
 */
OO.ui.mixin.LookupElement.prototype.getRequestCacheDataFromResponse = function ( response ) {
	return this.getLookupCacheDataFromResponse( response );
};
<commit_msg>[DEPRECATING CHANGE] LookupElement: Rename onLookupMenuItemChoose to onLookupMenuChoose<commit_after>/**
 * LookupElement is a mixin that creates a {@link OO.ui.MenuSelectWidget menu} of suggested
 * values for a {@link OO.ui.TextInputWidget text input widget}. Suggested values are based on
 * the characters the user types into the text input field and, in general, the menu is only
 * displayed when the user types. If a suggested value is chosen from the lookup menu, that value
 * becomes the value of the input field.
 *
 * Note that a new menu of suggested items is displayed when a value is chosen from the
 * lookup menu. If this is not the desired behavior, disable lookup menus with the
 * #setLookupsDisabled method, then set the value, then re-enable lookups.
 *
 * See the [OOUI demos][1] for an example.
 *
 * [1]: https://doc.wikimedia.org/oojs-ui/master/demos/#LookupElement-try-inputting-an-integer
 *
 * @class
 * @abstract
 * @mixins OO.ui.mixin.RequestManager
 *
 * @constructor
 * @param {Object} [config] Configuration options
 * @cfg {jQuery} [$overlay] Overlay for the lookup menu; defaults to relative positioning.
 *  See <https://www.mediawiki.org/wiki/OOUI/Concepts#Overlays>.
 * @cfg {jQuery} [$container=this.$element] The container element. The lookup menu is rendered
 *  beneath the specified element.
 * @cfg {Object} [menu] Configuration options to pass to
 *  {@link OO.ui.MenuSelectWidget menu select widget}
 * @cfg {boolean} [allowSuggestionsWhenEmpty=false] Request and display a lookup menu when the
 *  text input is empty.
 *  By default, the lookup menu is not generated and displayed until the user begins to type.
 * @cfg {boolean} [highlightFirst=true] Whether the first lookup result should be highlighted
 *  (so, that the user can take it over into the input with simply pressing return) automatically
 *  or not.
 * @cfg {boolean} [showSuggestionsOnFocus=true] Show suggestions when focusing the input. If this
 *  is set to false, suggestions will still be shown on a mousedown triggered focus. This matches
 *  browser autocomplete behavior.
 */
OO.ui.mixin.LookupElement = function OoUiMixinLookupElement( config ) {
	// Configuration initialization
	config = $.extend( { highlightFirst: true }, config );

	// Mixin constructors
	OO.ui.mixin.RequestManager.call( this, config );

	// Properties
	this.$overlay = ( config.$overlay === true ?
		OO.ui.getDefaultOverlay() : config.$overlay ) || this.$element;
	this.lookupMenu = new OO.ui.MenuSelectWidget( $.extend( {
		widget: this,
		input: this,
		$floatableContainer: config.$container || this.$element
	}, config.menu ) );

	this.allowSuggestionsWhenEmpty = config.allowSuggestionsWhenEmpty || false;

	this.lookupsDisabled = false;
	this.lookupInputFocused = false;
	this.lookupHighlightFirstItem = config.highlightFirst;
	this.showSuggestionsOnFocus = config.showSuggestionsOnFocus !== false;

	// Events
	this.$input.on( {
		focus: this.onLookupInputFocus.bind( this ),
		blur: this.onLookupInputBlur.bind( this ),
		mousedown: this.onLookupInputMouseDown.bind( this )
	} );
	this.connect( this, {
		change: 'onLookupInputChange'
	} );
	this.lookupMenu.connect( this, {
		toggle: 'onLookupMenuToggle',
		choose: 'onLookupMenuChoose'
	} );

	// Initialization
	this.$input.attr( {
		role: 'combobox',
		'aria-owns': this.lookupMenu.getElementId(),
		'aria-autocomplete': 'list'
	} );
	this.$element.addClass( 'oo-ui-lookupElement' );
	this.lookupMenu.$element.addClass( 'oo-ui-lookupElement-menu' );
	this.$overlay.append( this.lookupMenu.$element );
};

/* Setup */

OO.mixinClass( OO.ui.mixin.LookupElement, OO.ui.mixin.RequestManager );

/* Methods */

/**
 * Handle input focus event.
 *
 * @protected
 * @param {jQuery.Event} e Input focus event
 */
OO.ui.mixin.LookupElement.prototype.onLookupInputFocus = function () {
	this.lookupInputFocused = true;
	if ( this.showSuggestionsOnFocus ) {
		this.populateLookupMenu();
	}
};

/**
 * Handle input blur event.
 *
 * @protected
 * @param {jQuery.Event} e Input blur event
 */
OO.ui.mixin.LookupElement.prototype.onLookupInputBlur = function () {
	this.closeLookupMenu();
	this.lookupInputFocused = false;
};

/**
 * Handle input mouse down event.
 *
 * @protected
 * @param {jQuery.Event} e Input mouse down event
 */
OO.ui.mixin.LookupElement.prototype.onLookupInputMouseDown = function () {
	if (
		!this.lookupMenu.isVisible() &&
		(
			// Open the menu if the input was already focused.
			// This way we allow the user to open the menu again after closing it with Escape (esc)
			// by clicking in the input.
			this.lookupInputFocused ||
			// If showSuggestionsOnFocus is disabled, still open the menu on mousedown.
			!this.showSuggestionsOnFocus
		)
	) {
		this.populateLookupMenu();
	}
};

/**
 * Handle input change event.
 *
 * @protected
 * @param {string} value New input value
 */
OO.ui.mixin.LookupElement.prototype.onLookupInputChange = function () {
	if ( this.lookupInputFocused ) {
		this.populateLookupMenu();
	}
};

/**
 * Handle the lookup menu being shown/hidden.
 *
 * @protected
 * @param {boolean} visible Whether the lookup menu is now visible.
 */
OO.ui.mixin.LookupElement.prototype.onLookupMenuToggle = function ( visible ) {
	if ( !visible ) {
		// When the menu is hidden, abort any active request and clear the menu.
		// This has to be done here in addition to closeLookupMenu(), because
		// MenuSelectWidget will close itself when the user presses Escape (esc).
		this.abortLookupRequest();
		this.lookupMenu.clearItems();
	}
};

/**
 * Handle menu item 'choose' event, updating the text input value to the value of the clicked item.
 *
 * @protected
 * @param {OO.ui.MenuOptionWidget} item Selected item
 */
OO.ui.mixin.LookupElement.prototype.onLookupMenuChoose = function ( item ) {
	if ( this.onLookupMenuItemChoose ) {
		// @since 0.35.2
		OO.ui.warnDeprecation(
			'onLookupMenuItemChoose is deprecated. ' +
			'Use onLookupMenuChoose instead.'
		);
		this.onLookupMenuItemChoose();
	} else {
		this.setValue( item.getData() );
	}
};

/**
 * Get lookup menu.
 *
 * @private
 * @return {OO.ui.MenuSelectWidget}
 */
OO.ui.mixin.LookupElement.prototype.getLookupMenu = function () {
	return this.lookupMenu;
};

/**
 * Disable or re-enable lookups.
 *
 * When lookups are disabled, calls to #populateLookupMenu will be ignored.
 *
 * @param {boolean} disabled Disable lookups
 */
OO.ui.mixin.LookupElement.prototype.setLookupsDisabled = function ( disabled ) {
	this.lookupsDisabled = !!disabled;
};

/**
 * Open the menu. If there are no entries in the menu, this does nothing.
 *
 * @private
 * @chainable
 * @return {OO.ui.Element} The element, for chaining
 */
OO.ui.mixin.LookupElement.prototype.openLookupMenu = function () {
	if ( !this.lookupMenu.isEmpty() ) {
		this.lookupMenu.toggle( true );
	}
	return this;
};

/**
 * Close the menu, empty it, and abort any pending request.
 *
 * @private
 * @chainable
 * @return {OO.ui.Element} The element, for chaining
 */
OO.ui.mixin.LookupElement.prototype.closeLookupMenu = function () {
	this.lookupMenu.toggle( false );
	this.abortLookupRequest();
	this.lookupMenu.clearItems();
	return this;
};

/**
 * Request menu items based on the input's current value, and when they arrive,
 * populate the menu with these items and show the menu.
 *
 * If lookups have been disabled with #setLookupsDisabled, this function does nothing.
 *
 * @private
 * @chainable
 * @return {OO.ui.Element} The element, for chaining
 */
OO.ui.mixin.LookupElement.prototype.populateLookupMenu = function () {
	var widget = this,
		value = this.getValue();

	if ( this.lookupsDisabled || this.isReadOnly() ) {
		return;
	}

	// If the input is empty, clear the menu, unless suggestions when empty are allowed.
	if ( !this.allowSuggestionsWhenEmpty && value === '' ) {
		this.closeLookupMenu();
	// Skip population if there is already a request pending for the current value
	} else if ( value !== this.lookupQuery ) {
		this.getLookupMenuItems()
			.done( function ( items ) {
				widget.lookupMenu.clearItems();
				if ( items.length ) {
					widget.lookupMenu
						.addItems( items )
						.toggle( true );
					widget.initializeLookupMenuSelection();
				} else {
					widget.lookupMenu.toggle( false );
				}
			} )
			.fail( function () {
				widget.lookupMenu.clearItems();
				widget.lookupMenu.toggle( false );
			} );
	}

	return this;
};

/**
 * Highlight the first selectable item in the menu, if configured.
 *
 * @private
 * @chainable
 */
OO.ui.mixin.LookupElement.prototype.initializeLookupMenuSelection = function () {
	if ( this.lookupHighlightFirstItem && !this.lookupMenu.findSelectedItem() ) {
		this.lookupMenu.highlightItem( this.lookupMenu.findFirstSelectableItem() );
	}
};

/**
 * Get lookup menu items for the current query.
 *
 * @private
 * @return {jQuery.Promise} Promise object which will be passed menu items as the first argument of
 *   the done event. If the request was aborted to make way for a subsequent request, this promise
 *   will not be rejected: it will remain pending forever.
 */
OO.ui.mixin.LookupElement.prototype.getLookupMenuItems = function () {
	return this.getRequestData().then( function ( data ) {
		return this.getLookupMenuOptionsFromData( data );
	}.bind( this ) );
};

/**
 * Abort the currently pending lookup request, if any.
 *
 * @private
 */
OO.ui.mixin.LookupElement.prototype.abortLookupRequest = function () {
	this.abortRequest();
};

/**
 * Get a new request object of the current lookup query value.
 *
 * @protected
 * @method
 * @abstract
 * @return {jQuery.Promise} jQuery AJAX object, or promise object with an .abort() method
 */
OO.ui.mixin.LookupElement.prototype.getLookupRequest = null;

/**
 * Pre-process data returned by the request from #getLookupRequest.
 *
 * The return value of this function will be cached, and any further queries for the given value
 * will use the cache rather than doing API requests.
 *
 * @protected
 * @method
 * @abstract
 * @param {Mixed} response Response from server
 * @return {Mixed} Cached result data
 */
OO.ui.mixin.LookupElement.prototype.getLookupCacheDataFromResponse = null;

/**
 * Get a list of menu option widgets from the (possibly cached) data returned by
 * #getLookupCacheDataFromResponse.
 *
 * @protected
 * @method
 * @abstract
 * @param {Mixed} data Cached result data, usually an array
 * @return {OO.ui.MenuOptionWidget[]} Menu items
 */
OO.ui.mixin.LookupElement.prototype.getLookupMenuOptionsFromData = null;

/**
 * Set the read-only state of the widget.
 *
 * This will also disable/enable the lookups functionality.
 *
 * @param {boolean} readOnly Make input read-only
 * @chainable
 * @return {OO.ui.Element} The element, for chaining
 */
OO.ui.mixin.LookupElement.prototype.setReadOnly = function ( readOnly ) {
	// Parent method
	// Note: Calling #setReadOnly this way assumes this is mixed into an OO.ui.TextInputWidget
	OO.ui.TextInputWidget.prototype.setReadOnly.call( this, readOnly );

	// During construction, #setReadOnly is called before the OO.ui.mixin.LookupElement constructor.
	if ( this.isReadOnly() && this.lookupMenu ) {
		this.closeLookupMenu();
	}

	return this;
};

/**
 * @inheritdoc OO.ui.mixin.RequestManager
 */
OO.ui.mixin.LookupElement.prototype.getRequestQuery = function () {
	return this.getValue();
};

/**
 * @inheritdoc OO.ui.mixin.RequestManager
 */
OO.ui.mixin.LookupElement.prototype.getRequest = function () {
	return this.getLookupRequest();
};

/**
 * @inheritdoc OO.ui.mixin.RequestManager
 */
OO.ui.mixin.LookupElement.prototype.getRequestCacheDataFromResponse = function ( response ) {
	return this.getLookupCacheDataFromResponse( response );
};
<|endoftext|>


<commit_before>import flatten from 'flat';
import jsonexport from 'jsonexport';
import React, { Component } from 'react';

class CSVExport extends Component {
	constructor(){
		super();

		this.exportFile = this.exportFile.bind(this);
	}

	convertFileType(data){

		const options = {
			headers: this.props.columns.map((column) => (column.value)),
			rename: this.props.columns.map((column) => (column.label)),
		};

		jsonexport(data, options, (err,csv) => {
			if(err) {
				return console.log(err);
			}
			this.exportToBroswer(csv);
		});

	}

	exportFile() {
		this.convertFileType(this.reformatColumns(this.props.filterItems(this.props.items,this.props.query)));
	}

	exportToBroswer(csv) {
		console.log(csv);
	}

	reformatColumns(items) {

		const flatList = items.map((item) => flatten(item, { maxDepth: 2 }));

		// convert columns
		const reformattedList = flatList.map((item) => {
			let reformattedItem = {
				[item['budgetHours.column']]: item['budgetHours.value'],
				total: item['budgetHours.value'],
				feature: item.feature,
			};

			for (const property in item) {
				if(Array.isArray(item[property])) {
					reformattedItem[property] = item[property];
				}
			}

			return reformattedItem;
		});

		let concatObj = {};

		// combine on feature
		reformattedList.map((item) => {
			if(typeof concatObj[item.feature] === 'undefined') {
				concatObj[item.feature] = item;
			} else {
				for (const property in item) {
					if(Array.isArray(item[property])) {
						concatObj[item.feature][property] = [...concatObj[item.feature][property], ...item[property]];
					} else if(typeof item[property] === 'number') {
						concatObj[item.feature][property] = concatObj[item.feature][property] + item[property] || item[property];
					}
				}
			}
		});

		// convert concatObj from properties to array elements
		let concatList = [];
		for (const element in concatObj) {
			concatList = [...concatList, concatObj[element]];
		}

		return concatList;
	}

	render() {
		return (
			<button
				onClick={this.exportFile}
				className="btn btn-primary">
				Export
			</button>
		);
	}
}

CSVExport.defaultProps = {
	columns: [{
		value:'feature',
		label:'Page/Feature',
	},{
		value:'t&m',
		label:'T&M',
	},{
		value:'Discovery',
		label:'Disc',
	},{
		value:'Design',
		label:'Design',
	},{
		value:'Dev',
		label:'Dev',
	},{
		value:'Testing',
		label:'Testing',
	},{
		value:'Remediation',
		label:'Remediation',
	},{
		value:'Deploy',
		label:'Deploy',
	},{
		value:'PM',
		label:'PM',
	},{
		value:'total',
		label:'Total',
	},{
		value:'descriptions.budget',
		label:'Description',
	},{
		value:'descriptions.assumptions',
		label:'Assumptions',
	},{
		value:'descriptions.clientResponsibilities',
		label:'Client Responsibilities',
	},{
		value:'descriptions.exclusions',
		label:'Exclusions',
	},
	]
}

export default CSVExport;<commit_msg>Add CSV export to browser<commit_after>import flatten from 'flat';
import jsonexport from 'jsonexport';
import React, { Component } from 'react';
import { CSVLink } from 'react-csv';

class CSVExport extends Component {
	constructor(){
		super();

		this.exportFile = this.exportFile.bind(this);
	}

	convertFileType(data) {

		const options = {
			headers: this.props.columns.map((column) => (column.value)),
			rename: this.props.columns.map((column) => (column.label)),
		};

		jsonexport(data, options, (err,csv) => {
			if(err) {
				return console.log(err);
			}
			return csv;
		});
	}

	exportFile() {
		const data = this.reformatColumns(this.props.filterItems(this.props.items,this.props.query));
		console.log(data);
		return data;
	}

	reformatColumns(items) {

		const flatList = items.map((item) => flatten(item, { maxDepth: 2 }));

		// convert columns
		const reformattedList = flatList.map((item) => {
			let reformattedItem = {
				[item['budgetHours.column']]: item['budgetHours.value'],
				total: item['budgetHours.value'],
				feature: item.feature,
			};

			for (const property in item) {
				if(Array.isArray(item[property])) {
					reformattedItem[property] = item[property];
				}
			}

			return reformattedItem;
		});

		let concatObj = {};

		// combine on feature
		reformattedList.map((item) => {
			if(typeof concatObj[item.feature] === 'undefined') {
				concatObj[item.feature] = item;
			} else {
				for (const property in item) {
					if(Array.isArray(item[property])) {
						concatObj[item.feature][property] = [...concatObj[item.feature][property], ...item[property]];
					} else if(typeof item[property] === 'number') {
						concatObj[item.feature][property] = concatObj[item.feature][property] + item[property] || item[property];
					}
				}
			}
		});

		// convert concatObj from properties to array elements
		let concatList = [];
		for (const element in concatObj) {
			concatList = [...concatList, concatObj[element]];
		}

		return concatList;
	}

	render() {

		return (
			<div>
				<CSVLink
					data={this.exportFile()}
					headers={this.props.columns}
					filename={'Budget.csv'}
					className="btn btn-primary">
					Export to CSV
				</CSVLink>
			</div>
		);
	}
}

CSVExport.defaultProps = {
	columns: [{
		key:'feature',
		value:'feature',
		label:'Page/Feature',
	},{
		key:'t&m',
		value:'t&m',
		label:'T&M',
	},{
		key:'Discovery',
		value:'Discovery',
		label:'Disc',
	},{
		key:'Design',
		value:'Design',
		label:'Design',
	},{
		key:'Dev',
		value:'Dev',
		label:'Dev',
	},{
		key:'Testing',
		value:'Testing',
		label:'Testing',
	},{
		key:'Remediation',
		value:'Remediation',
		label:'Remediation',
	},{
		key:'Deploy',
		value:'Deploy',
		label:'Deploy',
	},{
		key:'PM',
		value:'PM',
		label:'PM',
	},{
		key:'total',
		value:'total',
		label:'Total',
	},{
		key:'descriptions.budget',
		value:'descriptions.budget',
		label:'Description',
	},{
		key:'descriptions.assumptions',
		value:'descriptions.assumptions',
		label:'Assumptions',
	},{
		key:'descriptions.clientResponsibilities',
		value:'descriptions.clientResponsibilities',
		label:'Client Responsibilities',
	},{
		key:'descriptions.exclusions',
		value:'descriptions.exclusions',
		label:'Exclusions',
	},
	]
}

export default CSVExport;<|endoftext|>


<commit_before>'use strict';

var config = require('./config'),
    express = require('express'),
    cookieParser = require('cookie-parser'),
    bodyParser = require('body-parser'),
    cookieSession = require('cookie-session'),
    http = require('http'),
    path = require('path'),
    passport = require('passport'),
    models = require('./models/index'),
    helmet = require('helmet'),
    csrf = require('csurf'),
    moment = require('moment');

var favicon = require('serve-favicon');

var pg = require('pg');
var db = require('./models');
var users = require('./routes/users');

var app = express();

//keep reference to config
app.config = config;

//setup the web server
app.server = http.createServer(app);

app.db = models;

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(require('morgan')('dev'));
app.use(require('compression')());
app.use(require('serve-static')(path.join(__dirname, 'public')));
app.use(require('method-override')());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
    extended: true
}));
app.use(cookieParser(config.cryptoKey));
app.use(cookieSession({
    resave: true,
    saveUninitialized: true,
    secret: config.cryptoKey,
    keys: ['key1', 'key2']
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(csrf({
    cookie: {
        signed: true
    }
}));
helmet(app);

//response locals
app.use(function(req, res, next) {
    res.cookie('_csrfToken', req.csrfToken());
    res.locals.user = {};
    res.locals.user.defaultReturnUrl = req.user && req.user.defaultReturnUrl();
    res.locals.user.username = req.user && req.user.username;
    next();
});

//global locals
app.locals.projectName = app.config.projectName;
app.locals.copyrightYear = new Date().getFullYear();
app.locals.copyrightName = app.config.companyName;
app.locals.cacheBreaker = 'br34k-01';
app.locals.signupEnabled = app.config.signupEnabled;
app.locals.moment =moment;
//setup passport
require('./passport')(app, passport);

//setup routes
require('./routes')(app, passport);

//custom (friendly) error handler
app.use(require('./views/http/index').http500);

//setup utilities
app.utility = {};
app.utility.sendmail = require('./util/sendmail');
app.utility.slugify = require('./util/slugify');
app.utility.workflow = require('./util/workflow');

// catch 404 and forward to error handler
app.use(function(req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    next(err);
});

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
    app.use(function(err, req, res, next) {
        res.status(err.status || 500);
        res.render('error', {
            message: err.message,
            error: err
        });
    });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
        message: err.message,
        error: {}
    });
});

/* Throw an error if the database sync does not occur */
db.sequelize.sync().then(function(promise) {
    console.log("DEBUG: DB in place");
}).catch(SyntaxError, function(e) {
    console.log("don't be evil: " + e);
});

module.exports = app;
<commit_msg>Correct the displayed copyright holder.<commit_after>'use strict';

var config = require('./config'),
    express = require('express'),
    cookieParser = require('cookie-parser'),
    bodyParser = require('body-parser'),
    cookieSession = require('cookie-session'),
    http = require('http'),
    path = require('path'),
    passport = require('passport'),
    models = require('./models/index'),
    helmet = require('helmet'),
    csrf = require('csurf'),
    moment = require('moment');

var favicon = require('serve-favicon');

var pg = require('pg');
var db = require('./models');
var users = require('./routes/users');

var app = express();

//keep reference to config
app.config = config;

//setup the web server
app.server = http.createServer(app);

app.db = models;

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(require('morgan')('dev'));
app.use(require('compression')());
app.use(require('serve-static')(path.join(__dirname, 'public')));
app.use(require('method-override')());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
    extended: true
}));
app.use(cookieParser(config.cryptoKey));
app.use(cookieSession({
    resave: true,
    saveUninitialized: true,
    secret: config.cryptoKey,
    keys: ['key1', 'key2']
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(csrf({
    cookie: {
        signed: true
    }
}));
helmet(app);

//response locals
app.use(function(req, res, next) {
    res.cookie('_csrfToken', req.csrfToken());
    res.locals.user = {};
    res.locals.user.defaultReturnUrl = req.user && req.user.defaultReturnUrl();
    res.locals.user.username = req.user && req.user.username;
    next();
});

//global locals
app.locals.projectName = app.config.projectName;
// This calculation of the copyright year is a kludge, but it'll
// probably be accurate enough most of the time, since it's likely
// that some code somewhere in the app changed in a given year.  Maybe
// in early January of the year it will be inaccurate, though!
app.locals.copyrightYear = new Date().getFullYear();
// Since this is open source software, it doesn't matter *too* much
// who owns the copyright, but for the record this is a work for hire
// so the customer is the copyright holder.
app.locals.copyrightName = "American Red Cross";
app.locals.cacheBreaker = 'br34k-01';
app.locals.signupEnabled = app.config.signupEnabled;
app.locals.moment =moment;
//setup passport
require('./passport')(app, passport);

//setup routes
require('./routes')(app, passport);

//custom (friendly) error handler
app.use(require('./views/http/index').http500);

//setup utilities
app.utility = {};
app.utility.sendmail = require('./util/sendmail');
app.utility.slugify = require('./util/slugify');
app.utility.workflow = require('./util/workflow');

// catch 404 and forward to error handler
app.use(function(req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    next(err);
});

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
    app.use(function(err, req, res, next) {
        res.status(err.status || 500);
        res.render('error', {
            message: err.message,
            error: err
        });
    });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
        message: err.message,
        error: {}
    });
});

/* Throw an error if the database sync does not occur */
db.sequelize.sync().then(function(promise) {
    console.log("DEBUG: DB in place");
}).catch(SyntaxError, function(e) {
    console.log("don't be evil: " + e);
});

module.exports = app;
<|endoftext|>


<commit_before>// Copyright 2014 Globo.com Player authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

var BaseObject = require('../../base/base_object');
var $ = require("jquery");
var _ = require('underscore');

var PipPlugin = BaseObject.extend({
  initialize: function(core) {
    this.core = core;
    this.masterContainer = core.containers[0];
    if (core.containers.length === 2) {
      this.pipContainer = core.containers[1];
      this.setPipStyle(this.pipContainer);
    }
  },
  setPipStyle: function(container) {
    container.setStyle({width: "30%", height: "30%", "z-index": 20, bottom: "7px", right: "7px"});
  },
  setMasterStyle: function(container) {
    container.setStyle({width: "100%", height: "100%", "z-index": 1, bottom: "0px", right: "0px"});
  },
  addPip: function(source) {
    this.discardPip();
    this.pipContainer = this.core.playbackHandler.createContainer(source);
    this.setPipStyle(this.pipContainer);
    this.core.containers.push(this.pipContainer);
    this.core.$el.append(this.pipContainer.render().el);
    this.masterContainer.getPluginByName('watermark').disable();
  },
  addMaster: function(source) {
    if (this.pipContainer) {
      this.discardPip();
    }
    if (this.masterContainer) {
      this.pipContainer = this.masterContainer;
      this.setPipStyle(this.pipContainer);
    }
    this.masterContainer = this.core.playbackHandler.createContainer(source);
    this.core.containers.push(this.masterContainer);
    this.core.$el.append(this.masterContainer.render().el);
    this.masterContainer.getPluginByName('watermark').enable();
  },
  discardPip: function() {
    if (this.pipContainer) {
      this.discardContainer(this.pipContainer);
      delete this.pipContainer;
    }
  },
  discardMaster: function() {
    if (this.masterContainer) {
      this.discardContainer(this.masterContainer);
      delete this.masterContainer;
    }
  },
  discardContainer: function(container) {
    this.core.containers = _.without(this.core.containers, _.findWhere(this.core.containers, container));
    container.destroy();
  },
  masterToPip: function() {
    this.discardPip();
    this.pipContainer = this.masterContainer;
    this.setPipStyle(this.pipContainer);
    delete this.masterContainer;
    this.pipContainer.getPluginByName('watermark').disable();
  },
  pipToMaster: function() {
    this.discardMaster();
    this.masterContainer = this.pipContainer;
    this.setMasterStyle(this.masterContainer);
    delete this.pipContainer;
    this.masterContainer.getPluginByName('watermark').enable();
  }

});

module.exports = PipPlugin;
<commit_msg>pip: remove watermark enable/disable and improve addMaster()<commit_after>// Copyright 2014 Globo.com Player authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

var BaseObject = require('../../base/base_object');
var $ = require("jquery");
var _ = require('underscore');

var PipPlugin = BaseObject.extend({
  initialize: function(core) {
    this.core = core;
    this.masterContainer = core.containers[0];
    if (core.containers.length === 2) {
      this.pipContainer = core.containers[1];
      this.setPipStyle(this.pipContainer);
    }
  },
  setPipStyle: function(container) {
    container.setStyle({width: "30%", height: "30%", "z-index": 20, bottom: "7px", right: "7px"});
  },
  setMasterStyle: function(container) {
    container.setStyle({width: "100%", height: "100%", "z-index": 1, bottom: "0px", right: "0px"});
  },
  addPip: function(source) {
    this.discardPip();
    this.pipContainer = this.core.playbackHandler.createContainer(source);
    this.setPipStyle(this.pipContainer);
    this.core.containers.push(this.pipContainer);
    this.core.$el.append(this.pipContainer.render().el);
  },
  addMaster: function(source) {
    if (this.pipContainer && this.masterContainer) {
      this.discardPip();
      this.pipContainer = this.masterContainer;
      this.setPipStyle(this.pipContainer);
    }
    this.masterContainer = this.core.playbackHandler.createContainer(source);
    this.core.containers.push(this.masterContainer);
    this.core.$el.append(this.masterContainer.render().el);
  },
  discardPip: function() {
    if (this.pipContainer) {
      this.discardContainer(this.pipContainer);
      delete this.pipContainer;
    }
  },
  discardMaster: function() {
    if (this.masterContainer) {
      this.discardContainer(this.masterContainer);
      delete this.masterContainer;
    }
  },
  discardContainer: function(container) {
    this.core.containers = _.without(this.core.containers, _.findWhere(this.core.containers, container));
    container.destroy();
  },
  masterToPip: function() {
    this.discardPip();
    this.pipContainer = this.masterContainer;
    this.setPipStyle(this.pipContainer);
    delete this.masterContainer;
  },
  pipToMaster: function() {
    this.discardMaster();
    this.masterContainer = this.pipContainer;
    this.setMasterStyle(this.masterContainer);
    delete this.pipContainer;
  }

});

module.exports = PipPlugin;
<|endoftext|>


<commit_before>var Loader = require('./loader');

var WebLoader = Loader.extend({
    init: function(baseURL, neverUpdate) {
        // It's easy to use precompiled templates: just include them
        // before you configure nunjucks and this will automatically
        // pick it up and use it
        this.precompiled = window.nunjucksPrecompiled || {};

        this.baseURL = baseURL || '';
        this.neverUpdate = neverUpdate;
    },

    getSource: function(name) {
        if(this.precompiled[name]) {
            return {
                src: { type: "code",
                       obj: this.precompiled[name] },
                path: name
            };
        }
        else {
            var src = this.fetch(this.baseURL + '/' + name);
            if(!src) {
                return null;
            }

            return { src: src,
                     path: name,
                     noCache: this.neverUpdate };
        }
    },

    fetch: function(url, callback) {
        // Only in the browser please
        var ajax;
        var loading = true;
        var src;

        if(window.XMLHttpRequest) { // Mozilla, Safari, ...
            ajax = new XMLHttpRequest();
        }
        else if(window.ActiveXObject) { // IE 8 and older
            ajax = new ActiveXObject("Microsoft.XMLHTTP");
        }

        ajax.onreadystatechange = function() {
            if(ajax.readyState === 4 && (ajax.status === 0 || ajax.status === 200) && loading) {
                loading = false;
                src = ajax.responseText;
            }
        };

        url += (url.indexOf('?') === -1 ? '?' : '&') + 's=' +
               (new Date().getTime());

        // Synchronous because this API shouldn't be used in
        // production (pre-load compiled templates instead)
        ajax.open('GET', url, false);
        ajax.send();

        return src;
    }
});

module.exports = {
    WebLoader: WebLoader
};
<commit_msg>fixed WebLoader neverUpdate mistake, noCache should be the opposite of neverUpdate<commit_after>var Loader = require('./loader');

var WebLoader = Loader.extend({
    init: function(baseURL, neverUpdate) {
        // It's easy to use precompiled templates: just include them
        // before you configure nunjucks and this will automatically
        // pick it up and use it
        this.precompiled = window.nunjucksPrecompiled || {};

        this.baseURL = baseURL || '';
        this.neverUpdate = neverUpdate;
    },

    getSource: function(name) {
        if(this.precompiled[name]) {
            return {
                src: { type: "code",
                       obj: this.precompiled[name] },
                path: name
            };
        }
        else {
            var src = this.fetch(this.baseURL + '/' + name);
            if(!src) {
                return null;
            }

            return { src: src,
                     path: name,
                     noCache: !this.neverUpdate };
        }
    },

    fetch: function(url, callback) {
        // Only in the browser please
        var ajax;
        var loading = true;
        var src;

        if(window.XMLHttpRequest) { // Mozilla, Safari, ...
            ajax = new XMLHttpRequest();
        }
        else if(window.ActiveXObject) { // IE 8 and older
            ajax = new ActiveXObject("Microsoft.XMLHTTP");
        }

        ajax.onreadystatechange = function() {
            if(ajax.readyState === 4 && (ajax.status === 0 || ajax.status === 200) && loading) {
                loading = false;
                src = ajax.responseText;
            }
        };

        url += (url.indexOf('?') === -1 ? '?' : '&') + 's=' +
               (new Date().getTime());

        // Synchronous because this API shouldn't be used in
        // production (pre-load compiled templates instead)
        ajax.open('GET', url, false);
        ajax.send();

        return src;
    }
});

module.exports = {
    WebLoader: WebLoader
};
<|endoftext|>


<commit_before>var canvas;
var gl;
var theta = [ 0, 0, 0 ];
var temptheta = [ 0, 0, 0 ];
var spin = [0,0,0];

var lowdef = true;
//var lowdef = false;
//var eye = vec3.create([0.0,0.0,2.0]);
var eye = vec3.create([6.0,6.0,6.0]);
var at = vec3.create([0.0,-2.0,0.0]);
var up = vec3.create([0.0,1.0,0.0]);

var lightPosition = vec4.create([5.0, 5.0, 5.0, 1.0] );
var lightAmbient =  vec4.create([0.5, 0.5, 0.5, 1.0  ]);
var lightDiffuse =  vec4.create([ 1.0, 1.0, 1.0, 1.0 ]);
var lightSpecular = vec4.create([ 1.0, 1.0, 1.0, 1.0 ]);

var materialAmbient =  vec4.create([ 0.5, 0.5, 0.5, 1.0 ]);
var materialDiffuse =  vec4.create([ 0.4824, 0.5647, 0.5843, 1.0 ]);
var materialSpecular = vec4.create([  1, 1, 1, 1.0 ]);
var materialShininess = 100;

var ambientProduct,diffuseProduct,specularProduct;
var modelViewM;
var projectionM;

var shouldQuit = false;
var shouldUpdate = true;
var shouldSingleStep = false;

var pyramid;
var entityManager;
var tebert;
var plyReader = PlyReader();

var distFromEdgeOfScreen = 22;
window.onload = function init() {

    canvas = document.getElementById( "gl-canvas" );
    canvas.width = window.innerWidth-distFromEdgeOfScreen;
    canvas.height = window.innerHeight-distFromEdgeOfScreen;

    gl = WebGLUtils.setupWebGL( canvas );
    if ( !gl ) { alert( "WebGL isn't available" ); }

    gl.viewport( 0, 0, canvas.width, canvas.height );
    gl.clearColor( 0.0, 0.0, 0.0, 1.0 );

    gl.enable(gl.DEPTH_TEST);

    //
    //  Load shaders and initialize attribute buffers
    //
    var program = loadShaders( gl, "vshader.glsl" , "fshader.glsl" );

    gl.useProgram( program );
    //gl.cBuffer = gl.createBuffer();
    //gl.nBuffer = gl.createBuffer();
    //gl.vBuffer = gl.createBuffer();

    gl.vNormal = gl.getAttribLocation( program, "vNormal" );
    gl.vTex = gl.getAttribLocation( program, "vTexCoord" );
    gl.vPosition = gl.getAttribLocation( program, "vPosition" );
    gl.vColor = gl.getAttribLocation( program, "vColor" );
    gl.lightPos = gl.getUniformLocation(program, "lightPosition");

    if(gl.vColor && gl.vColor > 0){
	gl.enableVertexAttribArray( gl.vColor );
    }
    gl.enableVertexAttribArray( gl.vNormal );
    gl.enableVertexAttribArray( gl.vTex );
    gl.enableVertexAttribArray( gl.vPosition );

    //gl.tBuffer = gl.createBuffer();

    gl.lineWidth(3);

    gl.mVMLoc = gl.getUniformLocation(program, "modelViewMatrix");
    gl.pMLoc = gl.getUniformLocation(program, "projectionMatrix");
    gl.objMLoc = gl.getUniformLocation(program, "objectMatrix");
    gl.thetaLoc = gl.getUniformLocation(program, "theta");

    ambientProduct =  vec4.mult(lightAmbient, materialAmbient);
    diffuseProduct =  vec4.mult(lightDiffuse, materialDiffuse);
    specularProduct = vec4.mult(lightSpecular, materialSpecular);

    gl.uniform4fv( gl.getUniformLocation(program,
       "ambientProduct"),ambientProduct );
    gl.uniform4fv( gl.getUniformLocation(program,
       "diffuseProduct"),diffuseProduct );
    gl.uniform4fv( gl.getUniformLocation(program,
       "specularProduct"),specularProduct );
    gl.uniform4fv( gl.getUniformLocation(program,
       "lightPosition"),[eye[0],eye[1],eye[2],1]);

    gl.uniform1f( gl.getUniformLocation(program,
       "shininess"),materialShininess );

    //plyReader.read("teapot.ply",onModelReady);
    //plyReader.read("cube.ply",onModelReady);
    //cube = new Cube();
    //cube2 = new Cube();
    //plyReader.read("teapot-n.ply",onModelReady);
    //tebert = new Tebert({"loc":[0,1,0,1]});
    //tebert = new Tebert({"loc":[0,0.5,0,1], "color": [0.5,0.5,0.5,1.0]});
    pyramid = new Pyramid();
    entityManager.init();
    //ball = new Ball({"loc":[0,0.5,0,1], "color": [1.0,0.0,0.0,1.0]});
    //entityManager.generateSam();
    start();
};

function rotateTo(x,y){
    var sgnx = sign(x);
    var sgny = sign(y);
    var prevRot = theta[0];
    var newRot = 0;
    //Ignore change on middle
    if(sgnx == 0 || sgny == 0){
	return;
    }
    if(sgnx == 1 && sgny == 1){
	newRot = 0;
    }
    if(sgnx == -1 && sgny == 1){
	newRot = 45;
    }
    if(sgnx == 1 && sgny == -1){
	newRot = -45;
    }
    if(sgnx == -1 && sgny == -1){
	newRot = 90;
    }
   //theta[0] = newRot;
    startRotate(newRot);
};

var rotToAdd = 0;;
var targetRot = 0;
function startRotate(newRot){
    targetRot = newRot;
    var diff = newRot - theta[0];
    /*
    if(Math.abs(diff) == 180){
	theta[0] = newRot;
    }
    */
    rotToAdd = diff/10;
}

function start(){
    //tebert.translate([0.0,1.0,0.0]);
    //cube.scale([0.5,0.5,0.5]);
    //ball.scale([0.5,0.5,0.5]);
    //cube.translate([0,0,0]);
    //cube.swapColor();
    //cube.swapColor();
    //cube2.scale([0.5,0.5,0.5]);
    //cube2.swapColor();
    //cube2.translate([1,0,0]);
    window.requestAnimFrame(main);
};

var NOMINAL_UPDATE_INTERVAL = 16.666;
function update(dt) {
    var original_dt = dt;
    // Warn about very large dt values -- they may lead to error
    //
    if (dt > 200) {
        console.log("Big dt =", dt, ": CLAMPING TO NOMINAL");
        dt = NOMINAL_UPDATE_INTERVAL;
    }
    // If using variable time, divide the actual delta by the "nominal" rate,

    // giving us a conveniently scaled "du" to work with.
    //
    var du = (dt / NOMINAL_UPDATE_INTERVAL);
    entityManager.update(du);
    //tebert.update(du);
    if(targetRot != theta[0] % 360){
	theta[0] += rotToAdd;
   }
}

var lastUpdate = 0;

function main(currTime){
    var thisUpdate = currTime;
    if (shouldUpdate)
	update(thisUpdate-lastUpdate);
    if(shouldSingleStep){
	update(thisUpdate-lastUpdate);
	shouldSingleStep = false;
	}
    render();
    if (! shouldQuit)
	window.requestAnimFrame(main);
    lastUpdate = thisUpdate;
};

var prevTrueTheta = vec3.create([0,0,0]);
function render()
{
    gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    var rotM = mat4.identity(mat4.create());
    var truetheta = vec3.add(theta,temptheta,vec3.create());
    mat4.rotate(rotM,-2*radians(truetheta[0]),[0,1,0,0]);
    //mat4.rotate(rotM,-2*radians(truetheta[1]),[1,0,0,0]);
    var neye = vec4.create(eye);
    neye[3] = 1;
    neye = mat4.multiplyVec3(rotM,neye);
    neye = vec3.create(neye);
    if(neye[0] === 0 && neye[1] !== 0 && neye[2] === 0){
	neye[2] = 0.01;
    }
    var lp = vec4.create(neye);
    //var lp = vec4.negate(lp);
    lp[3] = 1;
    gl.uniform4fv( gl.lightPos,lp);
    modelViewM = mat4.lookAt(neye,at,up);
    //Setjum sma perspective til ad gera thetta thaeginlegra
    projectionM = mat4.perspective(45,canvas.width/canvas.height,0.1,100);
    gl.uniformMatrix4fv(gl.mVMLoc,false,modelViewM);
    gl.uniformMatrix4fv(gl.pMLoc, false,projectionM);

    //tebert.render(gl);
    pyramid.render(gl);
    entityManager.render(gl);

}

<commit_msg>turned HD on again<commit_after>var canvas;
var gl;
var theta = [ 0, 0, 0 ];
var temptheta = [ 0, 0, 0 ];
var spin = [0,0,0];

//var lowdef = true;
var lowdef = false;
//var eye = vec3.create([0.0,0.0,2.0]);
var eye = vec3.create([6.0,6.0,6.0]);
var at = vec3.create([0.0,-2.0,0.0]);
var up = vec3.create([0.0,1.0,0.0]);

var lightPosition = vec4.create([5.0, 5.0, 5.0, 1.0] );
var lightAmbient =  vec4.create([0.5, 0.5, 0.5, 1.0  ]);
var lightDiffuse =  vec4.create([ 1.0, 1.0, 1.0, 1.0 ]);
var lightSpecular = vec4.create([ 1.0, 1.0, 1.0, 1.0 ]);

var materialAmbient =  vec4.create([ 0.5, 0.5, 0.5, 1.0 ]);
var materialDiffuse =  vec4.create([ 0.4824, 0.5647, 0.5843, 1.0 ]);
var materialSpecular = vec4.create([  1, 1, 1, 1.0 ]);
var materialShininess = 100;

var ambientProduct,diffuseProduct,specularProduct;
var modelViewM;
var projectionM;

var shouldQuit = false;
var shouldUpdate = true;
var shouldSingleStep = false;

var pyramid;
var entityManager;
var tebert;
var plyReader = PlyReader();

var distFromEdgeOfScreen = 22;
window.onload = function init() {

    canvas = document.getElementById( "gl-canvas" );
    canvas.width = window.innerWidth-distFromEdgeOfScreen;
    canvas.height = window.innerHeight-distFromEdgeOfScreen;

    gl = WebGLUtils.setupWebGL( canvas );
    if ( !gl ) { alert( "WebGL isn't available" ); }

    gl.viewport( 0, 0, canvas.width, canvas.height );
    gl.clearColor( 0.0, 0.0, 0.0, 1.0 );

    gl.enable(gl.DEPTH_TEST);

    //
    //  Load shaders and initialize attribute buffers
    //
    var program = loadShaders( gl, "vshader.glsl" , "fshader.glsl" );

    gl.useProgram( program );
    //gl.cBuffer = gl.createBuffer();
    //gl.nBuffer = gl.createBuffer();
    //gl.vBuffer = gl.createBuffer();

    gl.vNormal = gl.getAttribLocation( program, "vNormal" );
    gl.vTex = gl.getAttribLocation( program, "vTexCoord" );
    gl.vPosition = gl.getAttribLocation( program, "vPosition" );
    gl.vColor = gl.getAttribLocation( program, "vColor" );
    gl.lightPos = gl.getUniformLocation(program, "lightPosition");

    if(gl.vColor && gl.vColor > 0){
	gl.enableVertexAttribArray( gl.vColor );
    }
    gl.enableVertexAttribArray( gl.vNormal );
    gl.enableVertexAttribArray( gl.vTex );
    gl.enableVertexAttribArray( gl.vPosition );

    //gl.tBuffer = gl.createBuffer();

    gl.lineWidth(3);

    gl.mVMLoc = gl.getUniformLocation(program, "modelViewMatrix");
    gl.pMLoc = gl.getUniformLocation(program, "projectionMatrix");
    gl.objMLoc = gl.getUniformLocation(program, "objectMatrix");
    gl.thetaLoc = gl.getUniformLocation(program, "theta");

    ambientProduct =  vec4.mult(lightAmbient, materialAmbient);
    diffuseProduct =  vec4.mult(lightDiffuse, materialDiffuse);
    specularProduct = vec4.mult(lightSpecular, materialSpecular);

    gl.uniform4fv( gl.getUniformLocation(program,
       "ambientProduct"),ambientProduct );
    gl.uniform4fv( gl.getUniformLocation(program,
       "diffuseProduct"),diffuseProduct );
    gl.uniform4fv( gl.getUniformLocation(program,
       "specularProduct"),specularProduct );
    gl.uniform4fv( gl.getUniformLocation(program,
       "lightPosition"),[eye[0],eye[1],eye[2],1]);

    gl.uniform1f( gl.getUniformLocation(program,
       "shininess"),materialShininess );

    //plyReader.read("teapot.ply",onModelReady);
    //plyReader.read("cube.ply",onModelReady);
    //cube = new Cube();
    //cube2 = new Cube();
    //plyReader.read("teapot-n.ply",onModelReady);
    //tebert = new Tebert({"loc":[0,1,0,1]});
    //tebert = new Tebert({"loc":[0,0.5,0,1], "color": [0.5,0.5,0.5,1.0]});
    pyramid = new Pyramid();
    entityManager.init();
    //ball = new Ball({"loc":[0,0.5,0,1], "color": [1.0,0.0,0.0,1.0]});
    //entityManager.generateSam();
    start();
};

function rotateTo(x,y){
    var sgnx = sign(x);
    var sgny = sign(y);
    var prevRot = theta[0];
    var newRot = 0;
    //Ignore change on middle
    if(sgnx == 0 || sgny == 0){
	return;
    }
    if(sgnx == 1 && sgny == 1){
	newRot = 0;
    }
    if(sgnx == -1 && sgny == 1){
	newRot = 45;
    }
    if(sgnx == 1 && sgny == -1){
	newRot = -45;
    }
    if(sgnx == -1 && sgny == -1){
	newRot = 90;
    }
   //theta[0] = newRot;
    startRotate(newRot);
};

var rotToAdd = 0;;
var targetRot = 0;
function startRotate(newRot){
    targetRot = newRot;
    var diff = newRot - theta[0];
    /*
    if(Math.abs(diff) == 180){
	theta[0] = newRot;
    }
    */
    rotToAdd = diff/10;
}

function start(){
    //tebert.translate([0.0,1.0,0.0]);
    //cube.scale([0.5,0.5,0.5]);
    //ball.scale([0.5,0.5,0.5]);
    //cube.translate([0,0,0]);
    //cube.swapColor();
    //cube.swapColor();
    //cube2.scale([0.5,0.5,0.5]);
    //cube2.swapColor();
    //cube2.translate([1,0,0]);
    window.requestAnimFrame(main);
};

var NOMINAL_UPDATE_INTERVAL = 16.666;
function update(dt) {
    var original_dt = dt;
    // Warn about very large dt values -- they may lead to error
    //
    if (dt > 200) {
        console.log("Big dt =", dt, ": CLAMPING TO NOMINAL");
        dt = NOMINAL_UPDATE_INTERVAL;
    }
    // If using variable time, divide the actual delta by the "nominal" rate,

    // giving us a conveniently scaled "du" to work with.
    //
    var du = (dt / NOMINAL_UPDATE_INTERVAL);
    entityManager.update(du);
    //tebert.update(du);
    if(targetRot != theta[0] % 360){
	theta[0] += rotToAdd;
   }
}

var lastUpdate = 0;

function main(currTime){
    var thisUpdate = currTime;
    if (shouldUpdate)
	update(thisUpdate-lastUpdate);
    if(shouldSingleStep){
	update(thisUpdate-lastUpdate);
	shouldSingleStep = false;
	}
    render();
    if (! shouldQuit)
	window.requestAnimFrame(main);
    lastUpdate = thisUpdate;
};

var prevTrueTheta = vec3.create([0,0,0]);
function render()
{
    gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    var rotM = mat4.identity(mat4.create());
    var truetheta = vec3.add(theta,temptheta,vec3.create());
    mat4.rotate(rotM,-2*radians(truetheta[0]),[0,1,0,0]);
    //mat4.rotate(rotM,-2*radians(truetheta[1]),[1,0,0,0]);
    var neye = vec4.create(eye);
    neye[3] = 1;
    neye = mat4.multiplyVec3(rotM,neye);
    neye = vec3.create(neye);
    if(neye[0] === 0 && neye[1] !== 0 && neye[2] === 0){
	neye[2] = 0.01;
    }
    var lp = vec4.create(neye);
    //var lp = vec4.negate(lp);
    lp[3] = 1;
    gl.uniform4fv( gl.lightPos,lp);
    modelViewM = mat4.lookAt(neye,at,up);
    //Setjum sma perspective til ad gera thetta thaeginlegra
    projectionM = mat4.perspective(45,canvas.width/canvas.height,0.1,100);
    gl.uniformMatrix4fv(gl.mVMLoc,false,modelViewM);
    gl.uniformMatrix4fv(gl.pMLoc, false,projectionM);

    //tebert.render(gl);
    pyramid.render(gl);
    entityManager.render(gl);

}

<|endoftext|>