<commit_before>Application.Controllers.controller('ProjectTreeController',
                                   ["$scope", "toastr", "mcapi", "projectFiles", "pubsub", "ProjectPath",
                                    "$state", "Tags", "User", "dateGenerate", "$filter", "model.projects",
                                    "projectFileTabs", ProjectTreeController]);

function ProjectTreeController ($scope, toastr, mcapi, projectFiles, pubsub, ProjectPath, $state, Tags, User, dateGenerate, $filter,
                                projects, projectFileTabs) {

    $scope.addToReview = function(entry, review){
        var item = {'id': entry.id, 'path': entry.fullname, 'name': entry.name, 'type': entry.type};
        var index = _.indexOf(review.items, function (each_review) {
            return each_review.id === item.id;
        });

        if (index == -1){
            review.items.push(item);
            mcapi('/reviews/%', review.id)
                .success(function (data) {
                    pubsub.send('update-items.change');
                }).put({'items': review.items});
        }
    };

    pubsub.waitOn($scope, "project.tree", function (treeVisible) {
        $scope.treeActive = treeVisible;
    });

    pubsub.waitOn($scope, "tags.change", function () {
        $scope.user_tags  = Tags.getUserTags();
    });

    $scope.openFolder = function (item) {
        var e = _.find($scope.trail, function (trailItem) {
            return trailItem.id === item.id;
        });
        if (typeof e === 'undefined') {
            // first level is 0 so we need to add 1 to our test
            if (item.level + 1 <= $scope.trail.length) {
                // Remove everything at this level and above
                $scope.trail = $scope.trail.splice(0, item.level);
            }
            $scope.trail.push(item);
        }
        $scope.dir = item.children;
        ProjectPath.update_dir(item);
        $scope.loaded = true;
    };

    $scope.backToFolder = function (item) {
        $scope.dir = ProjectPath.update_dir(item);
        var i = _.indexOf($scope.trail, function (each_trail) {
            return (item.id === each_trail.id);
        });
        if(i!= -1){
            $scope.trail = $scope.trail.splice(0, i + 1);
        }
    };

    $scope.openFile = function (f) {
        ProjectPath.populate($scope.trail, $scope.dir);
        projectFileTabs.add($scope.projectId, f);
        $state.go("projects.project.files.view", {fileid: f.id});
    };

    $scope.loadReviews = function (id) {
        mcapi('/project/%/reviews', id)
            .success(function (reviews) {
                $scope.open_reviews = $filter('reviewFilter')(reviews, 'open');
            }).jsonp();

    };

    $scope.selectProject = function (projectId) {
        $scope.trail = [];
        $scope.projectId = projectId;
        $scope.tree_data = [];
        $scope.loaded = false;
        if (!(projectId in $scope.model.projects)) {
            mcapi('/projects/%/tree2', projectId)
                .success(function (data) {
                    if (data[0]) {
                        $scope.tree_data = data;
                        $scope.dir = $scope.tree_data[0].children;
                        ProjectPath.update_dir($scope.tree_data[0]);
                        var obj = {};
                        obj.dir = $scope.tree_data[0];
                        $scope.model.projects[projectId] = obj;
                        $scope.loaded = true;
                        $scope.trail.push(data[0]);
                    }
                }).jsonp();
        } else {
            $scope.loaded = true;
            $scope.model.projects = projectFiles.model.projects;
            $scope.dir = $scope.model.projects[projectId].dir.children;
            ProjectPath.update_dir($scope.model.projects[projectId]);
            $scope.trail.push($scope.model.projects[projectId].dir);
        }
    };

    $scope.fileSelected = function (entry) {
            entry.selected = !entry.selected;
            var channel = projectFiles.channel;
            if (channel !== null) {
                pubsub.send(channel, entry);
            }
    };

    $scope.truncateTrail = function (currentTrail, currentItem) {
        var i = _.indexOf(currentTrail, function(item) {
            return item.displayname == currentItem.displayname;
        });

        return currentTrail.slice(0, i+1);
    };

    $scope.addTag = function(entry, selected_tag){
        //Filling tag join table
        var item2tag = {};
        item2tag.item_id = entry.id;
        item2tag.item_name = entry.name;
        item2tag.item_type = entry.type;
        item2tag.user = User.u();
        item2tag.tag =  selected_tag;
        if (entry.type === 'datafile'){
            item2tag.fullname = entry.fullname;
        }
        mcapi('/item/tag/new')
            .success(function (data) {
                var i;
                i = _.indexOf($scope.dir, function (item) {
                    return item.id === entry.id;
                });
                if(i != -1){
                    if ((Object.keys($scope.dir[i]['tags'])).indexOf($scope.user) === 0){
                        $scope.dir[i]['tags'][$scope.user].push(selected_tag);
                    }
                    else{
                        $scope.dir[i]['tags'][$scope.user] = [selected_tag];
                    }
                }
            }).error(function(e){
                toastr.error(e.error, 'Error', {
                    closeButton: true
                });
            }) .post(item2tag);
    };

    $scope.addReview = function () {
        if ($scope.model.new_review === "" || $scope.model.title === "" || $scope.model.assigned_to === "") {
            return;
        }
        $scope.review = {messages: []};
        $scope.review.items = [{'item_id': $scope.dfitem.id, 'item_type': $scope.dfitem.type, 'item_name': $scope.dfitem.name}];
        $scope.review.project = $scope.project;
        $scope.review.author = User.u();
        $scope.review.assigned_to = $scope.model.assigned_to;
        $scope.review.status = 'open';
        $scope.review.title = $scope.model.title;
        $scope.review.messages.push({'message': $scope.model.new_review, 'who': User.u(), 'date': dateGenerate.new_date()});
        $scope.saveData();
    };

    $scope.saveData = function () {
        mcapi('/reviews')
            .success(function (data) {
                $scope.model.new_review = "";
            }).post($scope.review);
    };

    $scope.showFileCheckbox = function() {
        var active = projectFiles.isActive($scope.projectID);
        return active;
    };

    $scope.init = function() {
        $scope.user = User.u();
        $scope.model = {
            new_review: "",
            assigned_to: "",
            title: ""
        };

        $scope.user_tags = User.attr().preferences.tags;
        if ($scope.from == 'true') {
            $scope.project = ProjectPath.get_project();
            var currentTrail = ProjectPath.get_trail();
            var item = ProjectPath.get_current_item();
            $scope.trail = $scope.truncateTrail(currentTrail, item);
            $scope.openFolder(item);
        } else {
            $scope.model = projectFiles.model;
            ProjectPath.set_project($scope.project);
            $scope.selectProject($scope.project);
        }

        projects.get($scope.project).then(function(p) {
            var totalFiles = 0;
            var key;
            $scope.projectID = p.id;
            $scope.users = p.users;
            $scope.projectSize = bytesToSizeStr(p.size);
            for (key in p.mediatypes) {
                totalFiles += p.mediatypes[key].count;
            }
            $scope.fileCount = numberWithCommas(totalFiles);
        });

        $scope.loadReviews($scope.project);
    };

    $scope.init();
}

Application.Directives.directive('projectTree', projectTreeDirective);

function projectTreeDirective () {
    return {
        restrict: "E",
        controller: "ProjectTreeController",
        transclude: false,
        replace: true,
        scope: {
            ngModel: "@",
            project: "@project",
            from: "@from",
            color: "@color",
            treeOverview: "=",
            checkBox: "="
        },
        link: function (scope, element, attrs) {
            scope.$watch('project', function(newValue, oldValue) {
                if (newValue !== oldValue) {
                    scope.init();

                }
            }, true);

        },
        templateUrl: "application/directives/projecttree.html"
    };
}
<commit_msg>Assign entry into variable. For some reason the value wasn't being preserved.<commit_after>Application.Controllers.controller('ProjectTreeController',
                                   ["$scope", "toastr", "mcapi", "projectFiles", "pubsub", "ProjectPath",
                                    "$state", "Tags", "User", "dateGenerate", "$filter", "model.projects",
                                    "projectFileTabs", ProjectTreeController]);

function ProjectTreeController ($scope, toastr, mcapi, projectFiles, pubsub, ProjectPath, $state, Tags, User, dateGenerate, $filter,
                                projects, projectFileTabs) {

    $scope.addToReview = function(entry, review){
        var item = {'id': entry.id, 'path': entry.fullname, 'name': entry.name, 'type': entry.type};
        var index = _.indexOf(review.items, function (each_review) {
            return each_review.id === item.id;
        });

        if (index == -1){
            review.items.push(item);
            mcapi('/reviews/%', review.id)
                .success(function (data) {
                    pubsub.send('update-items.change');
                }).put({'items': review.items});
        }
    };

    pubsub.waitOn($scope, "project.tree", function (treeVisible) {
        $scope.treeActive = treeVisible;
    });

    pubsub.waitOn($scope, "tags.change", function () {
        $scope.user_tags  = Tags.getUserTags();
    });

    $scope.openFolder = function (item) {
        var e = _.find($scope.trail, function (trailItem) {
            return trailItem.id === item.id;
        });
        if (typeof e === 'undefined') {
            // first level is 0 so we need to add 1 to our test
            if (item.level + 1 <= $scope.trail.length) {
                // Remove everything at this level and above
                $scope.trail = $scope.trail.splice(0, item.level);
            }
            $scope.trail.push(item);
        }
        $scope.dir = item.children;
        ProjectPath.update_dir(item);
        $scope.loaded = true;
    };

    $scope.backToFolder = function (item) {
        $scope.dir = ProjectPath.update_dir(item);
        var i = _.indexOf($scope.trail, function (each_trail) {
            return (item.id === each_trail.id);
        });
        if(i!= -1){
            $scope.trail = $scope.trail.splice(0, i + 1);
        }
    };

    $scope.openFile = function (f) {
        ProjectPath.populate($scope.trail, $scope.dir);
        projectFileTabs.add($scope.projectId, f);
        $state.go("projects.project.files.view", {fileid: f.id});
    };

    $scope.loadReviews = function (id) {
        mcapi('/project/%/reviews', id)
            .success(function (reviews) {
                $scope.open_reviews = $filter('reviewFilter')(reviews, 'open');
            }).jsonp();

    };

    $scope.selectProject = function (projectId) {
        $scope.trail = [];
        $scope.projectId = projectId;
        $scope.tree_data = [];
        $scope.loaded = false;
        if (!(projectId in $scope.model.projects)) {
            mcapi('/projects/%/tree2', projectId)
                .success(function (data) {
                    if (data[0]) {
                        $scope.tree_data = data;
                        $scope.dir = $scope.tree_data[0].children;
                        ProjectPath.update_dir($scope.tree_data[0]);
                        var obj = {};
                        obj.dir = $scope.tree_data[0];
                        $scope.model.projects[projectId] = obj;
                        $scope.loaded = true;
                        $scope.trail.push(data[0]);
                    }
                }).jsonp();
        } else {
            $scope.loaded = true;
            $scope.model.projects = projectFiles.model.projects;
            $scope.dir = $scope.model.projects[projectId].dir.children;
            ProjectPath.update_dir($scope.model.projects[projectId]);
            $scope.trail.push($scope.model.projects[projectId].dir);
        }
    };

    $scope.fileSelected = function (entry) {
        var selected = entry.selected;
        entry.selected = selected;
        var channel = projectFiles.channel;
        if (channel !== null) {
            pubsub.send(channel, entry);
        }
    };

    $scope.truncateTrail = function (currentTrail, currentItem) {
        var i = _.indexOf(currentTrail, function(item) {
            return item.displayname == currentItem.displayname;
        });

        return currentTrail.slice(0, i+1);
    };

    $scope.addTag = function(entry, selected_tag){
        //Filling tag join table
        var item2tag = {};
        item2tag.item_id = entry.id;
        item2tag.item_name = entry.name;
        item2tag.item_type = entry.type;
        item2tag.user = User.u();
        item2tag.tag =  selected_tag;
        if (entry.type === 'datafile'){
            item2tag.fullname = entry.fullname;
        }
        mcapi('/item/tag/new')
            .success(function (data) {
                var i;
                i = _.indexOf($scope.dir, function (item) {
                    return item.id === entry.id;
                });
                if(i != -1){
                    if ((Object.keys($scope.dir[i]['tags'])).indexOf($scope.user) === 0){
                        $scope.dir[i]['tags'][$scope.user].push(selected_tag);
                    }
                    else{
                        $scope.dir[i]['tags'][$scope.user] = [selected_tag];
                    }
                }
            }).error(function(e){
                toastr.error(e.error, 'Error', {
                    closeButton: true
                });
            }) .post(item2tag);
    };

    $scope.addReview = function () {
        if ($scope.model.new_review === "" || $scope.model.title === "" || $scope.model.assigned_to === "") {
            return;
        }
        $scope.review = {messages: []};
        $scope.review.items = [{'item_id': $scope.dfitem.id, 'item_type': $scope.dfitem.type, 'item_name': $scope.dfitem.name}];
        $scope.review.project = $scope.project;
        $scope.review.author = User.u();
        $scope.review.assigned_to = $scope.model.assigned_to;
        $scope.review.status = 'open';
        $scope.review.title = $scope.model.title;
        $scope.review.messages.push({'message': $scope.model.new_review, 'who': User.u(), 'date': dateGenerate.new_date()});
        $scope.saveData();
    };

    $scope.saveData = function () {
        mcapi('/reviews')
            .success(function (data) {
                $scope.model.new_review = "";
            }).post($scope.review);
    };

    $scope.showFileCheckbox = function() {
        var active = projectFiles.isActive($scope.projectID);
        return active;
    };

    $scope.init = function() {
        $scope.user = User.u();
        $scope.model = {
            new_review: "",
            assigned_to: "",
            title: ""
        };

        $scope.user_tags = User.attr().preferences.tags;
        if ($scope.from == 'true') {
            $scope.project = ProjectPath.get_project();
            var currentTrail = ProjectPath.get_trail();
            var item = ProjectPath.get_current_item();
            $scope.trail = $scope.truncateTrail(currentTrail, item);
            $scope.openFolder(item);
        } else {
            $scope.model = projectFiles.model;
            ProjectPath.set_project($scope.project);
            $scope.selectProject($scope.project);
        }

        projects.get($scope.project).then(function(p) {
            var totalFiles = 0;
            var key;
            $scope.projectID = p.id;
            $scope.users = p.users;
            $scope.projectSize = bytesToSizeStr(p.size);
            for (key in p.mediatypes) {
                totalFiles += p.mediatypes[key].count;
            }
            $scope.fileCount = numberWithCommas(totalFiles);
        });

        $scope.loadReviews($scope.project);
    };

    $scope.init();
}

Application.Directives.directive('projectTree', projectTreeDirective);

function projectTreeDirective () {
    return {
        restrict: "E",
        controller: "ProjectTreeController",
        transclude: false,
        replace: true,
        scope: {
            ngModel: "@",
            project: "@project",
            from: "@from",
            color: "@color",
            treeOverview: "=",
            checkBox: "="
        },
        link: function (scope, element, attrs) {
            scope.$watch('project', function(newValue, oldValue) {
                if (newValue !== oldValue) {
                    scope.init();

                }
            }, true);

        },
        templateUrl: "application/directives/projecttree.html"
    };
}
<|endoftext|>


<commit_before>import React from 'react'
import colors from 'styles/colors'
import { mediaQueries } from 'styles/common'
import { Button, Card, Emoji, Heading, Text } from 'components'
import exampleSlackEmail from './example_slack_email.gif'
import slackValidationPage from './slack_validation_page.jpg'

const styles = {
  card: {
    marginTop: '20px',
    marginLeft: 'auto',
    marginRight: 'auto',
    maxWidth: '700px'
  },
  email: {
    fontWeight: 600
  },
  image: {
    [mediaQueries.smallUp]: {
      width: '100%',
      marginLeft: 0,
      marginRight: 0
    },
    [mediaQueries.mediumUp]: {
      width: '50%',
      marginLeft: '25%',
      marginRight: '25%'
    },
    boxShadow: `0px 1px 50px -15px ${colors.gray}`,
    border: `1px solid ${colors.outline}`
  },
  text: {
    marginTop: '16px'
  }
}

const InviteInfo = ({ tempEmail }) => {
  return (
    <Card style={[styles.card, styles.wideCard]}>
      <Text style={styles.text}>
        Your temporary email address is{' '}
        {tempEmail}. We've created an account
        for you using the temporary email and transferred it to your preferred
        email. You'll need to use the temporary email the first time you sign
        into your account. After that, you'll use your preferred email to sign
        up.
      </Text>
      <Heading>Here's the next step to join:</Heading>
      <Text style={styles.text}>
        You'll get an email in the next few minutes from Slack. Click this
        button:
      </Text>

      <Text style={styles.text}>
        The button will link to a page that looks like this:
      </Text>

      <Text style={styles.text}>
        Sign in with your temporary email address ({tempEmail})
        and your password. Once you've done that, you can use your preferred
        email address in the future.
      </Text>
      <Button type="link" state="success" href="https://hackclub.slack.com">
        Head to Slack <Emoji type="rocket" />
      </Button>
    </Card>
  )
}

export default InviteInfo
<commit_msg>Simplify Slack sign up instructions<commit_after>import React from 'react'
import colors from 'styles/colors'
import { mediaQueries } from 'styles/common'
import { Button, Card, Emoji, Heading, Text } from 'components'
import exampleSlackEmail from './example_slack_email.gif'
import slackValidationPage from './slack_validation_page.jpg'

const styles = {
  card: {
    marginTop: '20px',
    marginLeft: 'auto',
    marginRight: 'auto',
    maxWidth: '700px'
  },
  topEmail: {
    color: colors.primary,
    fontWeight: 600,
    fontSize: '24px',
    maxWidth: 'initial',
    width: 'auto',
    textAlign: 'center',
    margin: '0 auto'
  },
  bottomEmail: {
    fontWeight: 600
  },
  image: {
    [mediaQueries.smallUp]: {
      width: '100%',
      marginLeft: 0,
      marginRight: 0
    },
    [mediaQueries.mediumUp]: {
      width: '50%',
      marginLeft: '25%',
      marginRight: '25%'
    },
    boxShadow: `0px 1px 50px -15px ${colors.gray}`,
    border: `1px solid ${colors.outline}`
  },
  text: {
    marginTop: '16px'
  }
}

const InviteInfo = ({ tempEmail }) => {
  return (
    <Card style={[styles.card, styles.wideCard]}>
      <Heading>Here's the next step to join</Heading>
      <Text style={styles.text}>
        Copy this email address. You'll use it to sign into Slack for the first
        time:
      </Text>
      <Card style={styles.topEmail}>{tempEmail}</Card>
      <Text style={styles.text}>
        You'll get an email in the next few minutes from Slack. Click this
        button:
      </Text>

      <Text style={styles.text}>
        The button will link to a page that looks like this:
      </Text>

      <Text style={styles.text}>
        Sign in with your temporary email address ({tempEmail})
        and your password. Once you've done that, you can use the email address
        you signed up with in the future.
      </Text>
      <Button type="link" state="success" href="https://hackclub.slack.com">
        Head to Slack <Emoji type="rocket" />
      </Button>
    </Card>
  )
}

export default InviteInfo
<|endoftext|>


<commit_before>/* globals Erizo */
'use strict';
var serverUrl = '/';
var localStream, room, recording, recordingId;

function getParameterByName(name) {
  name = name.replace(/[\[]/, '\\\[').replace(/[\]]/, '\\\]');
  var regex = new RegExp('[\\?&]' + name + '=([^&#]*)'),
      results = regex.exec(location.search);
  return results == null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' '));
}

function testConnection () {  // jshint ignore:line
  window.location = '/connection_test.html';
}

function startRecording () {  // jshint ignore:line
  if (room !== undefined){
    if (!recording){
      room.startRecording(localStream, function(id) {
        recording = true;
        recordingId = id;
      });

    } else {
      room.stopRecording(recordingId);
      recording = false;
    }
  }
}

var slideShowMode = false;

function toggleSlideShowMode() {  // jshint ignore:line
  var streams = room.remoteStreams;
  var cb = function (evt){
      console.log('SlideShowMode changed', evt);
  };
  slideShowMode = !slideShowMode;
  for (var index in streams) {
    var stream = streams[index];
    if (localStream.getID() !== stream.getID()) {
      console.log('Updating config');
      stream.updateConfiguration({slideShowMode: slideShowMode}, cb);
    }
  }
}

window.onload = function () {
  recording = false;
  var screen = getParameterByName('screen');
  var roomName = getParameterByName('room') || 'basicExampleRoom';
  var roomType = getParameterByName('type') || 'erizo';
  var onlySubscribe = getParameterByName('onlySubscribe');
  console.log('Selected Room', roomName, 'of type', roomType);
  var config = {audio: true,
                video: true,
                data: true,
                screen: screen,
                videoSize: [640, 480, 640, 480],
                videoFrameRate: [10, 20]};
  // If we want screen sharing we have to put our Chrome extension id.
  // The default one only works in our Lynckia test servers.
  // If we are not using chrome, the creation of the stream will fail regardless.
  if (screen){
    config.extensionId = 'okeephmleflklcdebijnponpabbmmgeo';
  }
  localStream = Erizo.Stream(config);
  var createToken = function(roomData, callback) {

    var req = new XMLHttpRequest();
    var url = serverUrl + 'createToken/';

    req.onreadystatechange = function () {
      if (req.readyState === 4) {
        callback(req.responseText);
      }
    };

    req.open('POST', url, true);
    req.setRequestHeader('Content-Type', 'application/json');
    req.send(JSON.stringify(roomData));
  };

  var roomData  = {username: 'user', role: 'presenter', room: roomName, type: roomType};

  createToken(roomData, function (response) {
    var token = response;
    console.log(token);
    room = Erizo.Room({token: token});

    var subscribeToStreams = function (streams) {
      var cb = function (evt){
          console.log('Bandwidth Alert', evt.msg, evt.bandwidth);
      };
      for (var index in streams) {
        var stream = streams[index];
        if (localStream.getID() !== stream.getID()) {
          room.subscribe(stream, {slideShowMode: slideShowMode, metadata: {type: 'subscriber'}});
          stream.addEventListener('bandwidth-alert', cb);
        }
      }
    };

    room.addEventListener('room-connected', function (roomEvent) {
      var options = {metadata: {type: 'publisher'}};
      var enableSimulcast = getParameterByName('simulcast');
      if (enableSimulcast) options.simulcast = {numSpatialLayers: 2};

      if (!onlySubscribe) room.publish(localStream, options);
      subscribeToStreams(roomEvent.streams);
    });

    room.addEventListener('stream-subscribed', function(streamEvent) {
      var stream = streamEvent.stream;
      var div = document.createElement('div');
      div.setAttribute('style', 'width: 320px; height: 240px;float:left;');
      div.setAttribute('id', 'test' + stream.getID());

      document.getElementById('videoContainer').appendChild(div);
      stream.show('test' + stream.getID());

    });

    room.addEventListener('stream-added', function (streamEvent) {
      var streams = [];
      streams.push(streamEvent.stream);
      subscribeToStreams(streams);
      document.getElementById('recordButton').disabled = false;
    });

    room.addEventListener('stream-removed', function (streamEvent) {
      // Remove stream from DOM
      var stream = streamEvent.stream;
      if (stream.elementID !== undefined) {
        var element = document.getElementById(stream.elementID);
        document.getElementById('videoContainer').removeChild(element);
      }
    });

    room.addEventListener('stream-failed', function (){
        console.log('Stream Failed, act accordingly');
    });

    if (onlySubscribe) {
      room.connect();
    } else {
      var div = document.createElement('div');
      div.setAttribute('style', 'width: 320px; height: 240px; float:left');
      div.setAttribute('id', 'myVideo');
      document.getElementById('videoContainer').appendChild(div);

      localStream.addEventListener('access-accepted', function () {
        room.connect();
        localStream.show('myVideo');
      });
      localStream.init();
    }
  });
};
<commit_msg>Fix slideshow mode in basic example. (#959)<commit_after>/* globals Erizo */
'use strict';
var serverUrl = '/';
var localStream, room, recording, recordingId;

function getParameterByName(name) {
  name = name.replace(/[\[]/, '\\\[').replace(/[\]]/, '\\\]');
  var regex = new RegExp('[\\?&]' + name + '=([^&#]*)'),
      results = regex.exec(location.search);
  return results == null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' '));
}

function testConnection () {  // jshint ignore:line
  window.location = '/connection_test.html';
}

function startRecording () {  // jshint ignore:line
  if (room !== undefined){
    if (!recording){
      room.startRecording(localStream, function(id) {
        recording = true;
        recordingId = id;
      });

    } else {
      room.stopRecording(recordingId);
      recording = false;
    }
  }
}

var slideShowMode = false;

function toggleSlideShowMode() {  // jshint ignore:line
  var streams = room.remoteStreams;
  var cb = function (evt){
      console.log('SlideShowMode changed', evt);
  };
  slideShowMode = !slideShowMode;
  streams.forEach(function (stream) {
    if (localStream.getID() !== stream.getID()) {
      console.log('Updating config');
      stream.updateConfiguration({slideShowMode: slideShowMode}, cb);
    }
  });
}

window.onload = function () {
  recording = false;
  var screen = getParameterByName('screen');
  var roomName = getParameterByName('room') || 'basicExampleRoom';
  var roomType = getParameterByName('type') || 'erizo';
  var onlySubscribe = getParameterByName('onlySubscribe');
  console.log('Selected Room', roomName, 'of type', roomType);
  var config = {audio: true,
                video: true,
                data: true,
                screen: screen,
                videoSize: [640, 480, 640, 480],
                videoFrameRate: [10, 20]};
  // If we want screen sharing we have to put our Chrome extension id.
  // The default one only works in our Lynckia test servers.
  // If we are not using chrome, the creation of the stream will fail regardless.
  if (screen){
    config.extensionId = 'okeephmleflklcdebijnponpabbmmgeo';
  }
  localStream = Erizo.Stream(config);
  var createToken = function(roomData, callback) {

    var req = new XMLHttpRequest();
    var url = serverUrl + 'createToken/';

    req.onreadystatechange = function () {
      if (req.readyState === 4) {
        callback(req.responseText);
      }
    };

    req.open('POST', url, true);
    req.setRequestHeader('Content-Type', 'application/json');
    req.send(JSON.stringify(roomData));
  };

  var roomData  = {username: 'user', role: 'presenter', room: roomName, type: roomType};

  createToken(roomData, function (response) {
    var token = response;
    console.log(token);
    room = Erizo.Room({token: token});

    var subscribeToStreams = function (streams) {
      var cb = function (evt){
          console.log('Bandwidth Alert', evt.msg, evt.bandwidth);
      };
      for (var index in streams) {
        var stream = streams[index];
        if (localStream.getID() !== stream.getID()) {
          room.subscribe(stream, {slideShowMode: slideShowMode, metadata: {type: 'subscriber'}});
          stream.addEventListener('bandwidth-alert', cb);
        }
      }
    };

    room.addEventListener('room-connected', function (roomEvent) {
      var options = {metadata: {type: 'publisher'}};
      var enableSimulcast = getParameterByName('simulcast');
      if (enableSimulcast) options.simulcast = {numSpatialLayers: 2};

      if (!onlySubscribe) room.publish(localStream, options);
      subscribeToStreams(roomEvent.streams);
    });

    room.addEventListener('stream-subscribed', function(streamEvent) {
      var stream = streamEvent.stream;
      var div = document.createElement('div');
      div.setAttribute('style', 'width: 320px; height: 240px;float:left;');
      div.setAttribute('id', 'test' + stream.getID());

      document.getElementById('videoContainer').appendChild(div);
      stream.show('test' + stream.getID());

    });

    room.addEventListener('stream-added', function (streamEvent) {
      var streams = [];
      streams.push(streamEvent.stream);
      subscribeToStreams(streams);
      document.getElementById('recordButton').disabled = false;
    });

    room.addEventListener('stream-removed', function (streamEvent) {
      // Remove stream from DOM
      var stream = streamEvent.stream;
      if (stream.elementID !== undefined) {
        var element = document.getElementById(stream.elementID);
        document.getElementById('videoContainer').removeChild(element);
      }
    });

    room.addEventListener('stream-failed', function (){
        console.log('Stream Failed, act accordingly');
    });

    if (onlySubscribe) {
      room.connect();
    } else {
      var div = document.createElement('div');
      div.setAttribute('style', 'width: 320px; height: 240px; float:left');
      div.setAttribute('id', 'myVideo');
      document.getElementById('videoContainer').appendChild(div);

      localStream.addEventListener('access-accepted', function () {
        room.connect();
        localStream.show('myVideo');
      });
      localStream.init();
    }
  });
};
<|endoftext|>


<commit_before>// need:
// ViewportCalibratedCanvas
// proxytools
// coordinateView (well, not really, but it'd be silly not to have)
// SideSplit

///////
// utils
function objToParamStr(obj) {
    var parts = [];
    for (var i in obj) {
        if (obj.hasOwnProperty(i)) {
          if (Array.isArray(obj[i])){
            // arrays are a list of strings with escaped quotes, surrounded by []
            parts.push(encodeURIComponent(i) + "=" + encodeURIComponent("[" + obj[i].map((x)=>'\"' + x + '\"').toString() + "]"));
          } else {
            parts.push(encodeURIComponent(i) + "=" + encodeURIComponent(obj[i]));
          }
        }
    }
    return parts.join("&");
}

function apiCall(callback, url, params){
  fetch(url + "?" + objToParamStr(params), {
    credentials: "same-origin"
  })
  .then((x)=> x.json())
  .then(function(response){
    callback(response);
  })
  .catch((x)=>console.warn(x));
}

class annotStore{
  /**
  * Annotation API Interactions
  * @param {string} id - the image id
  * @param {object} [options] - optional substitution for api urls
  */
  constructor(id, options){
    // image id
    this.id = id;
    // TODO cache??
    this.algDataUrl = options.algUrl || "api/Data/getMultipleAnnots.php";
    this.algListUrl = options.algListUrl || "api/Data/getAlgorithmsForImage.php";
  }

 /**
 * Get a list of avaliable algorithms for the image
 * @param {function} callback - callback for the result data
 */
 getAlgList(callback){
   var params = {"iid" : this.id}
   apiCall(callback, this.algListUrl, params);
 }

 /**
 * Get a list of avaliable algorithms for the image
 * @param {function} callback - callback for the result data
 */
 getAlgData(x1, y1, x2, y2, footprint, algs, callback){
   // sanitization/validation
   x1 = x1 < 0 ? 0 : x1;
   y1 = y1 < 0 ? 0 : y1;
   x2 = x2 < 0 ? 0 : x2;
   y2 = y2 < 0 ? 0 : y2;
   // set params object
   var params = {"iid": this.id, "x": x1, "x1": x2, "y" :y1, "y1": y2, "footprint": footprint, "algoritms": algs};
   apiCall(callback, this.algDataUrl, params);
 }
}
// see https://github.com/birm/OSDragonDemos/blob/master/coordinated_draw_annotool.html
function drawFromList(data, context){
  data.forEach(function(annotation){
    let id = annotation.provenance.analysis.execution_id;
    let color = "red";
    let type = annotation.geometry.type;
    let coords = annotation.geometry.coordinates[0];
    if (type == "Polygon"){
      // start
      context.beginPath();
      let first = coords.splice(1,1);
      context.moveTo(first[0], first[1])
      coords.forEach(function(coord){
        let x = coord[0];
        let y = coord[1];
        context.lineTo(x,y);
        console.log(x + ", " + y)
      });
      context.stroke();
      // stop
    } else {
      console.warn("Don't know how to draw '" + type + "'");
    }
  })
}
// TODO something to tell the viewer to redraw on move/zoom/open

class annotations{
  constructor(id, viewer, context, imagingHelper, options){
    this.id = id;
    this.store = new annotStore(id, options);
    this.viewer = viewer;
    this.options = options;
    this.selection = [];
    this.context = context;
    this.imagingHelper = imagingHelper;
    // TODO imagingHelper needed?
  }

  // draw using current viewer state
  draw(){
    this.x1 = this.imagingHelper._viewportOrigin['x'];
    this.y1 = this.imagingHelper._viewportOrigin['y'];
    this.x2 = this.x1 + this.imagingHelper._viewportWidth;
    this.y2 = this.y1 + this.imagingHelper._viewportHeight;

    var max = new OpenSeadragon.Point(this.imagingHelper.physicalToDataX(9), this.imagingHelper.physicalToDataY(9));
    var origin = new OpenSeadragon.Point(this.imagingHelper.physicalToDataX(0), this.imagingHelper.physicalToDataY(0));
    var footprint = (max.x - origin.x) * (max.y - origin.y);

    this.store.getAlgData(x, y, x1, y1, footprint, this.selection, function(data){
      drawFromList(data, this.context);
    });
  }

  select(alg){
    if(this.selection.indexOf(alg) == -1 ){
      this.selection.push(alg);
    }
  }

  deselect(alg){
    let pos = this.selection.indexOf(alg)
    if(pos > -1 ){
      this.selection.splice(pos, 1);
    }
  }

}
<commit_msg>rename bounds approprirately<commit_after>// need:
// ViewportCalibratedCanvas
// proxytools
// coordinateView (well, not really, but it'd be silly not to have)
// SideSplit

///////
// utils
function objToParamStr(obj) {
    var parts = [];
    for (var i in obj) {
        if (obj.hasOwnProperty(i)) {
          if (Array.isArray(obj[i])){
            // arrays are a list of strings with escaped quotes, surrounded by []
            parts.push(encodeURIComponent(i) + "=" + encodeURIComponent("[" + obj[i].map((x)=>'\"' + x + '\"').toString() + "]"));
          } else {
            parts.push(encodeURIComponent(i) + "=" + encodeURIComponent(obj[i]));
          }
        }
    }
    return parts.join("&");
}

function apiCall(callback, url, params){
  fetch(url + "?" + objToParamStr(params), {
    credentials: "same-origin"
  })
  .then((x)=> x.json())
  .then(function(response){
    callback(response);
  })
  .catch((x)=>console.warn(x));
}

class annotStore{
  /**
  * Annotation API Interactions
  * @param {string} id - the image id
  * @param {object} [options] - optional substitution for api urls
  */
  constructor(id, options){
    // image id
    this.id = id;
    // TODO cache??
    this.algDataUrl = options.algUrl || "api/Data/getMultipleAnnots.php";
    this.algListUrl = options.algListUrl || "api/Data/getAlgorithmsForImage.php";
  }

 /**
 * Get a list of avaliable algorithms for the image
 * @param {function} callback - callback for the result data
 */
 getAlgList(callback){
   var params = {"iid" : this.id}
   apiCall(callback, this.algListUrl, params);
 }

 /**
 * Get a list of avaliable algorithms for the image
 * @param {function} callback - callback for the result data
 */
 getAlgData(x1, y1, x2, y2, footprint, algs, callback){
   // sanitization/validation
   x1 = x1 < 0 ? 0 : x1;
   y1 = y1 < 0 ? 0 : y1;
   x2 = x2 < 0 ? 0 : x2;
   y2 = y2 < 0 ? 0 : y2;
   // set params object
   var params = {"iid": this.id, "x": x1, "x1": x2, "y" :y1, "y1": y2, "footprint": footprint, "algoritms": algs};
   apiCall(callback, this.algDataUrl, params);
 }
}
// see https://github.com/birm/OSDragonDemos/blob/master/coordinated_draw_annotool.html
function drawFromList(data, context){
  data.forEach(function(annotation){
    let id = annotation.provenance.analysis.execution_id;
    let color = "red";
    let type = annotation.geometry.type;
    let coords = annotation.geometry.coordinates[0];
    if (type == "Polygon"){
      // start
      context.beginPath();
      let first = coords.splice(1,1);
      context.moveTo(first[0], first[1])
      coords.forEach(function(coord){
        let x = coord[0];
        let y = coord[1];
        context.lineTo(x,y);
        console.log(x + ", " + y)
      });
      context.stroke();
      // stop
    } else {
      console.warn("Don't know how to draw '" + type + "'");
    }
  })
}
// TODO something to tell the viewer to redraw on move/zoom/open

class annotations{
  constructor(id, viewer, context, imagingHelper, options){
    this.id = id;
    this.store = new annotStore(id, options);
    this.viewer = viewer;
    this.options = options;
    this.selection = [];
    this.context = context;
    this.imagingHelper = imagingHelper;
    // TODO imagingHelper needed?
  }

  // draw using current viewer state
  draw(){
    let x1 = this.imagingHelper._viewportOrigin['x'];
    let y1 = this.imagingHelper._viewportOrigin['y'];
    let x2 = x1 + this.imagingHelper._viewportWidth;
    let y2 = y1 + this.imagingHelper._viewportHeight;

    var max = new OpenSeadragon.Point(this.imagingHelper.physicalToDataX(9), this.imagingHelper.physicalToDataY(9));
    var origin = new OpenSeadragon.Point(this.imagingHelper.physicalToDataX(0), this.imagingHelper.physicalToDataY(0));
    var footprint = (max.x - origin.x) * (max.y - origin.y);

    this.store.getAlgData(x1, y1, x2, y2, footprint, this.selection, function(data){
      drawFromList(data, this.context);
    });
  }

  select(alg){
    if(this.selection.indexOf(alg) == -1 ){
      this.selection.push(alg);
    }
  }

  deselect(alg){
    let pos = this.selection.indexOf(alg)
    if(pos > -1 ){
      this.selection.splice(pos, 1);
    }
  }

}
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from 'material-ui/styles';
import AppBar from 'material-ui/AppBar';
import Toolbar from 'material-ui/Toolbar';
import Typography from 'material-ui/Typography';
import Grid from 'material-ui/Grid';
import Button from 'material-ui/Button';
import { grey } from 'material-ui/colors';

const styles = {
  root: {
    width: '100%',
    height: '100%',
  },
  subheader: {
    borderBottom: `solid 1px ${grey[500]}`,
  },
  flex: {
    flex: 1,
  },
};

class Header extends React.Component {
  render() {
    const { classes } = this.props;
    return (

        <AppBar position="static">
          <Toolbar>
            <Typography type="title" color="inherit" className={classes.flex}>
              enow
            </Typography>
            IT勉強会・イベント検索
          </Toolbar>
        </AppBar>
        <Toolbar className={classes.subheader}>
          <Grid container direction="row" align="center" justify="center">
            <Grid item>
              <Button raised>検索する</Button>
            </Grid>
            <Grid>
              <Button raised>マイページ</Button>
            </Grid>
          </Grid>
        </Toolbar>
        {this.props.children}

    );
  }
}

Header.propTypes = {
  classes: PropTypes.shape({
    root: PropTypes.shape({
      width: PropTypes.string,
    }),
    flex: PropTypes.shape({
      flex: PropTypes.number,
    }),
  }),
  children: PropTypes.element.isRequired,
};

Header.defaultProps = {
  classes: styles,
};

export default withStyles(styles)(Header);
<commit_msg>軽微な修正。<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from 'material-ui/styles';
import AppBar from 'material-ui/AppBar';
import Toolbar from 'material-ui/Toolbar';
import Typography from 'material-ui/Typography';
import Grid from 'material-ui/Grid';
import Button from 'material-ui/Button';
import { grey } from 'material-ui/colors';

const styles = {
  root: {
    width: '100%',
    height: '100%',
  },
  subheader: {
    borderBottom: `solid 1px ${grey[500]}`,
  },
  flex: {
    flex: 1,
  },
};

class Header extends React.Component {
  render() {
    const { classes } = this.props;
    return (

        <AppBar position="static">
          <Toolbar>
            <Typography type="title" color="inherit" className={classes.flex}>
              enow
            </Typography>
            IT勉強会・イベント検索
          </Toolbar>
        </AppBar>
        <Toolbar className={classes.subheader}>
          <Grid container direction="row" align="center" justify="space-around">
            <Grid item>
              <Button raised>検索する</Button>
            </Grid>
            <Grid>
              <Button raised>マイページ</Button>
            </Grid>
          </Grid>
        </Toolbar>
        {this.props.children}

    );
  }
}

Header.propTypes = {
  classes: PropTypes.shape({
    root: PropTypes.shape({
      width: PropTypes.string,
    }),
    flex: PropTypes.shape({
      flex: PropTypes.number,
    }),
  }),
  children: PropTypes.element.isRequired,
};

Header.defaultProps = {
  classes: styles,
};

export default withStyles(styles)(Header);
<|endoftext|>


<commit_before>// Copyright 2002-2013, University of Colorado Boulder

/**
 * Google analytics collection for HTML5 sims.
 * Code provided by Google and Hewlett, possibly doctored by PhET.
 * Include this script as the last thing in your DOM's head, like this:
 * <script src='common/phetcommon/js/analytics/google-analytics.js'></script>
 *
 * NOTE: Please be careful about modifications, as it relies on external scripts.
 *
 * @author Sam Reid
 */

( function() {
  'use strict';

  var ua = navigator.userAgent;
  var hasIESecurityRestrictions = !!( ua.match( /MSIE/ ) || ua.match( /Trident\// ) || ua.match( /Edge\// ) );

  // If we're in some form of IE running offline, don't attempt to make a cross-origin request.
  // See https://github.com/phetsims/joist/issues/164
  if ( window.location.protocol === 'file:' && hasIESecurityRestrictions ) {
    return;
  }

  // Don't track sims that we didn't develop
  if ( phet.chipper.brand !== 'phet' && phet.chipper.brand !== 'phet-io' ) {
    return;
  }

  // Google Analytics snippet for loading the API
  (function( i, s, o, g, r, a, m ) {
    i.GoogleAnalyticsObject = r;
    i[ r ] = i[ r ] || function() {
      (i[ r ].q = i[ r ].q || []).push( arguments );
    }, i[ r ].l = 1 * new Date();
    a = s.createElement( o ), m = s.getElementsByTagName( o )[ 0 ];
    a.async = 1;
    a.src = g;
    m.parentNode.insertBefore( a, m );
  })( window, document, 'script', ( 'https:' === document.location.protocol ? 'https:' : 'http:' ) + '//www.google-analytics.com/analytics.js', 'googleAnalytics' );

  // Applies custom dimensions that are common for our main and third-party tracker
  var phetPageviewOptions = {};
  if ( phet.chipper ) {
    assert && assert( !phet.chipper.buildTimestamp ||
                      ( !!phet.chipper.project && !!phet.chipper.version && !!phet.chipper.locale ),
                      'Missing Google Analytics variable in' );

    if ( phet.chipper.project ) {
      phetPageviewOptions.dimension1 = phet.chipper.project; // simName custom dimension
    }
    if ( phet.chipper.version ) {
      phetPageviewOptions.dimension2 = phet.chipper.version; // simVersion custom dimension
    }
    if ( phet.chipper.locale ) {
      phetPageviewOptions.dimension3 = phet.chipper.locale; // simLocale custom dimension
    }
    if ( phet.chipper.buildTimestamp ) {
      phetPageviewOptions.dimension4 = phet.chipper.buildTimestamp; // simBuildTimestamp custom dimension
    }
  }

  // Main PhET tracker
  window.googleAnalytics( 'create', {
    trackingId: 'UA-5033201-1',
    cookieDomain: 'none'
  } );
  window.googleAnalytics( 'send', 'pageview', phetPageviewOptions );

  // Third-party PhET tracker (excludes non-third-party usage, see https://github.com/phetsims/yotta/issues/12)
  if ( window.location.protocol !== 'file:' &&
       !document.domain.match( /(.*\.colorado\.edu\.?$)|(^localhost$)|(^127\.0\.0\.1$)/ ) ) {
    window.googleAnalytics( 'create', {
      trackingId: 'UA-37615182-2',
      cookieDomain: 'none',
      name: 'thirdParty'
    } );
    window.googleAnalytics( 'thirdParty.send', 'pageview', phetPageviewOptions );
  }

  // Hewlett tracker
  window.googleAnalytics( 'create', {
    trackingId: 'UA-5033010-1',
    cookieDomain: 'phet.colorado.edu',
    name: 'hewlett'
  } );
  window.googleAnalytics( 'hewlett.send', 'pageview' );

} )();
<commit_msg>Adding phet-io brand tracker, see https://github.com/phetsims/phetcommon/issues/26<commit_after>// Copyright 2002-2013, University of Colorado Boulder

/**
 * Google analytics collection for HTML5 sims.
 * Code provided by Google and Hewlett, possibly doctored by PhET.
 * Include this script as the last thing in your DOM's head, like this:
 * <script src='common/phetcommon/js/analytics/google-analytics.js'></script>
 *
 * NOTE: Please be careful about modifications, as it relies on external scripts.
 *
 * @author Sam Reid
 */

( function() {
  'use strict';

  var ua = navigator.userAgent;
  var hasIESecurityRestrictions = !!( ua.match( /MSIE/ ) || ua.match( /Trident\// ) || ua.match( /Edge\// ) );

  // If we're in some form of IE running offline, don't attempt to make a cross-origin request.
  // See https://github.com/phetsims/joist/issues/164
  if ( window.location.protocol === 'file:' && hasIESecurityRestrictions ) {
    return;
  }

  // Don't track sims that we didn't develop
  if ( phet.chipper.brand !== 'phet' && phet.chipper.brand !== 'phet-io' ) {
    return;
  }

  // Google Analytics snippet for loading the API
  (function( i, s, o, g, r, a, m ) {
    i.GoogleAnalyticsObject = r;
    i[ r ] = i[ r ] || function() {
      (i[ r ].q = i[ r ].q || []).push( arguments );
    }, i[ r ].l = 1 * new Date();
    a = s.createElement( o ), m = s.getElementsByTagName( o )[ 0 ];
    a.async = 1;
    a.src = g;
    m.parentNode.insertBefore( a, m );
  })( window, document, 'script', ( 'https:' === document.location.protocol ? 'https:' : 'http:' ) + '//www.google-analytics.com/analytics.js', 'googleAnalytics' );

  // Applies custom dimensions that are common for our main and third-party tracker
  var phetPageviewOptions = {};
  if ( phet.chipper ) {
    assert && assert( !phet.chipper.buildTimestamp ||
                      ( !!phet.chipper.project && !!phet.chipper.version && !!phet.chipper.locale ),
                      'Missing Google Analytics variable in' );

    if ( phet.chipper.project ) {
      phetPageviewOptions.dimension1 = phet.chipper.project; // simName custom dimension
    }
    if ( phet.chipper.version ) {
      phetPageviewOptions.dimension2 = phet.chipper.version; // simVersion custom dimension
    }
    if ( phet.chipper.locale ) {
      phetPageviewOptions.dimension3 = phet.chipper.locale; // simLocale custom dimension
    }
    if ( phet.chipper.buildTimestamp ) {
      phetPageviewOptions.dimension4 = phet.chipper.buildTimestamp; // simBuildTimestamp custom dimension
    }
  }

  // Main PhET tracker
  window.googleAnalytics( 'create', {
    trackingId: 'UA-5033201-1',
    cookieDomain: 'none'
  } );
  window.googleAnalytics( 'send', 'pageview', phetPageviewOptions );

  // PhET iO tracker (see https://github.com/phetsims/phetcommon/issues/26)
  if ( phet.chipper.brand === 'phet-io' ) {
    window.googleAnalytics( 'create', {
      trackingId: 'UA-37615182-3',
      cookieDomain: 'none',
      name: 'io'
    } );
    window.googleAnalytics( 'io.send', 'pageview', phetPageviewOptions );
  }

  // Third-party PhET tracker (excludes non-third-party usage, see https://github.com/phetsims/yotta/issues/12)
  if ( window.location.protocol !== 'file:' &&
       !document.domain.match( /(.*\.colorado\.edu\.?$)|(^localhost$)|(^127\.0\.0\.1$)/ ) ) {
    window.googleAnalytics( 'create', {
      trackingId: 'UA-37615182-2',
      cookieDomain: 'none',
      name: 'thirdParty'
    } );
    window.googleAnalytics( 'thirdParty.send', 'pageview', phetPageviewOptions );
  }

  // Hewlett tracker
  window.googleAnalytics( 'create', {
    trackingId: 'UA-5033010-1',
    cookieDomain: 'phet.colorado.edu',
    name: 'hewlett'
  } );
  window.googleAnalytics( 'hewlett.send', 'pageview' );

} )();
<|endoftext|>


<commit_before>/*
 * DealPort
 * Copyright (c) 2014  DealPort B.V.
 *
 * This file is part of DealPort
 *
 * DealPort is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * DealPort is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with DealPort.  If not, see <http://www.gnu.org/licenses/>.
 *
 * In addition, the following supplemental terms apply, based on section 7 of
 * the GNU Affero General Public License (version 3):
 * a) Preservation of all legal notices and author attributions
 */

'use strict';

module.exports.pasteHtmlAtCaret = function(window, html, selectPastedContent)
{
        var document = window.document;
        //http://stackoverflow.com/questions/6690752/insert-html-at-caret-in-a-contenteditable-div/6691294#6691294
        var sel, range;
        if (window.getSelection)
        {
                // IE9 and non-IE
                sel = window.getSelection();
                if (sel.getRangeAt && sel.rangeCount)
                {
                        range = sel.getRangeAt(0);
                        range.deleteContents();

                        // Range.createContextualFragment() would be useful here but is
                        // only relatively recently standardized and is not supported in
                        // some browsers (IE9, for one)
                        var el = document.createElement('div');
                        el.innerHTML = html;
                        var frag = document.createDocumentFragment(), node, lastNode;
                        while ( (node = el.firstChild) )
                        {
                                lastNode = frag.appendChild(node);
                        }
                        var firstNode = frag.firstChild;
                        range.insertNode(frag);

                        // Preserve the selection
                        if (lastNode)
                        {
                                range = range.cloneRange();
                                range.setStartAfter(lastNode);
                                if (selectPastedContent)
                                {
                                        range.setStartBefore(firstNode);
                                }
                                else
                                {
                                        range.collapse(true);
                                }
                                sel.removeAllRanges();
                                sel.addRange(range);
                        }
                }
        }
        else if ( (sel = document.selection) && sel.type !== 'Control')
        {
                // IE < 9
                var originalRange = sel.createRange();
                originalRange.collapse(true);
                sel.createRange().pasteHTML(html);
                if (selectPastedContent)
                {
                        range = sel.createRange();
                        range.setEndPoint('StartToStart', originalRange);
                        range.select();
                }
        }
};<commit_msg>Utility function to sort an array of objects by a given string property<commit_after>/*
 * DealPort
 * Copyright (c) 2014  DealPort B.V.
 *
 * This file is part of DealPort
 *
 * DealPort is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * DealPort is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with DealPort.  If not, see <http://www.gnu.org/licenses/>.
 *
 * In addition, the following supplemental terms apply, based on section 7 of
 * the GNU Affero General Public License (version 3):
 * a) Preservation of all legal notices and author attributions
 */

'use strict';

module.exports.pasteHtmlAtCaret = function(window, html, selectPastedContent)
{
        var document = window.document;
        //http://stackoverflow.com/questions/6690752/insert-html-at-caret-in-a-contenteditable-div/6691294#6691294
        var sel, range;
        if (window.getSelection)
        {
                // IE9 and non-IE
                sel = window.getSelection();
                if (sel.getRangeAt && sel.rangeCount)
                {
                        range = sel.getRangeAt(0);
                        range.deleteContents();

                        // Range.createContextualFragment() would be useful here but is
                        // only relatively recently standardized and is not supported in
                        // some browsers (IE9, for one)
                        var el = document.createElement('div');
                        el.innerHTML = html;
                        var frag = document.createDocumentFragment(), node, lastNode;
                        while ( (node = el.firstChild) )
                        {
                                lastNode = frag.appendChild(node);
                        }
                        var firstNode = frag.firstChild;
                        range.insertNode(frag);

                        // Preserve the selection
                        if (lastNode)
                        {
                                range = range.cloneRange();
                                range.setStartAfter(lastNode);
                                if (selectPastedContent)
                                {
                                        range.setStartBefore(firstNode);
                                }
                                else
                                {
                                        range.collapse(true);
                                }
                                sel.removeAllRanges();
                                sel.addRange(range);
                        }
                }
        }
        else if ( (sel = document.selection) && sel.type !== 'Control')
        {
                // IE < 9
                var originalRange = sel.createRange();
                originalRange.collapse(true);
                sel.createRange().pasteHTML(html);
                if (selectPastedContent)
                {
                        range = sel.createRange();
                        range.setEndPoint('StartToStart', originalRange);
                        range.select();
                }
        }
};

module.exports.sortByStringProperty = function(arr, prop)
{
        arr.sort(function(a, b)
        {
                a = a[prop];
                b = b[prop];

                a = a ? a.toString() : '';
                b = b ? b.toString() : '';

                // Intl is not yet supported by node.js
                a = a.toLocaleLowerCase();
                b = b.toLocaleLowerCase();

                return a.localeCompare(b);
        });
};<|endoftext|>


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

import * as Common from '../common/common.js';
import * as UI from '../ui/ui.js';

import {SearchConfig, SearchResult, SearchScope} from './SearchConfig.js';  // eslint-disable-line no-unused-vars
import {SearchResultsPane} from './SearchResultsPane.js';

export class SearchView extends UI.Widget.VBox {
  /**
   * @param {string} settingKey
   */
  constructor(settingKey) {
    super(true);
    this.setMinimumSize(0, 40);
    this.registerRequiredCSS('search/searchView.css', {enableLegacyPatching: true});

    this._focusOnShow = false;
    this._isIndexing = false;
    this._searchId = 1;
    this._searchMatchesCount = 0;
    this._searchResultsCount = 0;
    this._nonEmptySearchResultsCount = 0;
    /** @type {?UI.Widget.Widget} */
    this._searchingView = null;
    /** @type {?UI.Widget.Widget} */
    this._notFoundView = null;
    /** @type {?SearchConfig} */
    this._searchConfig = null;
    /** @type {?SearchConfig} */
    this._pendingSearchConfig = null;
    /** @type {?SearchResultsPane} */
    this._searchResultsPane = null;
    /** @type {?UI.ProgressIndicator.ProgressIndicator} */
    this._progressIndicator = null;
    /** @type {?UI.Widget.Widget} */
    this._visiblePane = null;

    this.contentElement.classList.add('search-view');

    this._searchPanelElement = this.contentElement.createChild('div', 'search-drawer-header');
    this._searchPanelElement.addEventListener(
        'keydown', event => this._onKeyDown(/** @type {!KeyboardEvent} */ (event)), false);

    this._searchResultsElement = this.contentElement.createChild('div');
    this._searchResultsElement.className = 'search-results';

    const searchContainer = document.createElement('div');
    searchContainer.style.flex = 'auto';
    searchContainer.style.justifyContent = 'start';
    searchContainer.style.maxWidth = '300px';
    this._search = UI.HistoryInput.HistoryInput.create();
    searchContainer.appendChild(this._search);
    this._search.placeholder = Common.UIString.UIString('Search');
    this._search.setAttribute('type', 'text');
    this._search.setAttribute('results', '0');
    this._search.setAttribute('size', '42');
    UI.ARIAUtils.setAccessibleName(this._search, ls`Search Query`);
    const searchItem = new UI.Toolbar.ToolbarItem(searchContainer);

    const toolbar = new UI.Toolbar.Toolbar('search-toolbar', this._searchPanelElement);
    this._matchCaseButton = SearchView._appendToolbarToggle(toolbar, 'Aa', Common.UIString.UIString('Match Case'));
    this._regexButton =
        SearchView._appendToolbarToggle(toolbar, '.*', Common.UIString.UIString('Use Regular Expression'));
    toolbar.appendToolbarItem(searchItem);
    const refreshButton = new UI.Toolbar.ToolbarButton(Common.UIString.UIString('Refresh'), 'largeicon-refresh');
    const clearButton = new UI.Toolbar.ToolbarButton(Common.UIString.UIString('Clear'), 'largeicon-clear');
    toolbar.appendToolbarItem(refreshButton);
    toolbar.appendToolbarItem(clearButton);
    refreshButton.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, this._onAction.bind(this));
    clearButton.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, () => {
      this._resetSearch();

    });

    const searchStatusBarElement = this.contentElement.createChild('div', 'search-toolbar-summary');
    this._searchMessageElement = searchStatusBarElement.createChild('div', 'search-message');
    this._searchProgressPlaceholderElement = searchStatusBarElement.createChild('div', 'flex-centered');
    this._searchResultsMessageElement = searchStatusBarElement.createChild('div', 'search-message');

    this._advancedSearchConfig = Common.Settings.Settings.instance().createLocalSetting(
        settingKey + 'SearchConfig', new SearchConfig('', true, false).toPlainObject());

    this._load();
    /** @type {?SearchScope} */
    this._searchScope = null;
  }

  /**
   * @param {!UI.Toolbar.Toolbar} toolbar
   * @param {string} text
   * @param {string} tooltip
   * @return {!UI.Toolbar.ToolbarToggle}
   */
  static _appendToolbarToggle(toolbar, text, tooltip) {
    const toggle = new UI.Toolbar.ToolbarToggle(tooltip);
    toggle.setText(text);
    toggle.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, () => toggle.setToggled(!toggle.toggled()));
    toolbar.appendToolbarItem(toggle);
    return toggle;
  }

  /**
   * @return {!SearchConfig}
   */
  _buildSearchConfig() {
    return new SearchConfig(this._search.value, !this._matchCaseButton.toggled(), this._regexButton.toggled());
  }

  /**
   * @param {string} queryCandidate
   * @param {boolean=} searchImmediately
   */
  async toggle(queryCandidate, searchImmediately) {
    if (queryCandidate) {
      this._search.value = queryCandidate;
    }
    if (this.isShowing()) {
      this.focus();
    } else {
      this._focusOnShow = true;
    }

    this._initScope();
    if (searchImmediately) {
      this._onAction();
    } else {
      this._startIndexing();
    }
  }

  /**
   * @protected
   * @return {!SearchScope}
   */
  createScope() {
    throw new Error('Not implemented');
  }

  _initScope() {
    this._searchScope = this.createScope();
  }

  /**
   * @override
   */
  wasShown() {
    if (this._focusOnShow) {
      this.focus();
      this._focusOnShow = false;
    }
  }

  _onIndexingFinished() {
    if (!this._progressIndicator) {
      return;
    }

    const finished = !this._progressIndicator.isCanceled();
    this._progressIndicator.done();
    this._progressIndicator = null;
    this._isIndexing = false;
    this._indexingFinished(finished);
    if (!finished) {
      this._pendingSearchConfig = null;
    }
    if (!this._pendingSearchConfig) {
      return;
    }
    const searchConfig = this._pendingSearchConfig;
    this._pendingSearchConfig = null;
    this._innerStartSearch(searchConfig);
  }

  _startIndexing() {
    this._isIndexing = true;
    if (this._progressIndicator) {
      this._progressIndicator.done();
    }
    this._progressIndicator = new UI.ProgressIndicator.ProgressIndicator();
    this._searchMessageElement.textContent = Common.UIString.UIString('Indexing…');
    this._progressIndicator.show(this._searchProgressPlaceholderElement);
    if (this._searchScope) {
      this._searchScope.performIndexing(
          new Common.Progress.ProgressProxy(this._progressIndicator, this._onIndexingFinished.bind(this)));
    }
  }

  _onSearchInputClear() {
    this._search.value = '';
    this.focus();
  }

  /**
   * @param {number} searchId
   * @param {!SearchResult} searchResult
   */
  _onSearchResult(searchId, searchResult) {
    if (searchId !== this._searchId || !this._progressIndicator) {
      return;
    }
    if (this._progressIndicator && this._progressIndicator.isCanceled()) {
      this._onIndexingFinished();
      return;
    }
    this._addSearchResult(searchResult);
    if (!searchResult.matchesCount()) {
      return;
    }
    if (!this._searchResultsPane) {
      this._searchResultsPane = new SearchResultsPane(/** @type {!SearchConfig} */ (this._searchConfig));
      this._showPane(this._searchResultsPane);
    }
    this._searchResultsPane.addSearchResult(searchResult);
  }

  /**
   * @param {number} searchId
   * @param {boolean} finished
   */
  _onSearchFinished(searchId, finished) {
    if (searchId !== this._searchId || !this._progressIndicator) {
      return;
    }
    if (!this._searchResultsPane) {
      this._nothingFound();
    }
    this._searchFinished(finished);
    this._searchConfig = null;
    UI.ARIAUtils.alert(
        this._searchMessageElement.textContent + ' ' + this._searchResultsMessageElement.textContent,
        this._searchMessageElement);
  }

  /**
   * @param {!SearchConfig} searchConfig
   */
  async _startSearch(searchConfig) {
    this._resetSearch();
    ++this._searchId;
    this._initScope();
    if (!this._isIndexing) {
      this._startIndexing();
    }
    this._pendingSearchConfig = searchConfig;
  }

  /**
   *
   * @param {!SearchConfig} searchConfig
   */
  _innerStartSearch(searchConfig) {
    this._searchConfig = searchConfig;
    if (this._progressIndicator) {
      this._progressIndicator.done();
    }
    this._progressIndicator = new UI.ProgressIndicator.ProgressIndicator();
    this._searchStarted(this._progressIndicator);
    if (this._searchScope) {
      this._searchScope.performSearch(
          searchConfig, this._progressIndicator, this._onSearchResult.bind(this, this._searchId),
          this._onSearchFinished.bind(this, this._searchId));
    }
  }

  _resetSearch() {
    this._stopSearch();
    this._showPane(null);
    this._searchResultsPane = null;
    this._onSearchInputClear();
    this._clearSearchMessage();
  }

  _clearSearchMessage() {
    this._searchMessageElement.textContent = '';
    this._searchResultsMessageElement.textContent = '';
  }

  _stopSearch() {
    if (this._progressIndicator && !this._isIndexing) {
      this._progressIndicator.cancel();
    }
    if (this._searchScope) {
      this._searchScope.stopSearch();
    }
    this._searchConfig = null;
  }

  /**
   * @param {!UI.ProgressIndicator.ProgressIndicator} progressIndicator
   */
  _searchStarted(progressIndicator) {
    this._resetCounters();
    if (!this._searchingView) {
      this._searchingView = new UI.EmptyWidget.EmptyWidget(Common.UIString.UIString('Searching…'));
    }
    this._showPane(this._searchingView);
    this._searchMessageElement.textContent = Common.UIString.UIString('Searching…');
    progressIndicator.show(this._searchProgressPlaceholderElement);
    this._updateSearchResultsMessage();
  }

  /**
   * @param {boolean} finished
   */
  _indexingFinished(finished) {
    this._searchMessageElement.textContent = finished ? '' : Common.UIString.UIString('Indexing interrupted.');
  }

  _updateSearchResultsMessage() {
    if (this._searchMatchesCount && this._searchResultsCount) {
      if (this._searchMatchesCount === 1 && this._nonEmptySearchResultsCount === 1) {
        this._searchResultsMessageElement.textContent = Common.UIString.UIString('Found 1 matching line in 1 file.');
      } else if (this._searchMatchesCount > 1 && this._nonEmptySearchResultsCount === 1) {
        this._searchResultsMessageElement.textContent =
            Common.UIString.UIString('Found %d matching lines in 1 file.', this._searchMatchesCount);
      } else {
        this._searchResultsMessageElement.textContent = Common.UIString.UIString(
            'Found %d matching lines in %d files.', this._searchMatchesCount, this._nonEmptySearchResultsCount);
      }
    } else {
      this._searchResultsMessageElement.textContent = '';
    }
  }

  /**
   * @param {?UI.Widget.Widget} panel
   */
  _showPane(panel) {
    if (this._visiblePane) {
      this._visiblePane.detach();
    }
    if (panel) {
      panel.show(this._searchResultsElement);
    }
    this._visiblePane = panel;
  }

  _resetCounters() {
    this._searchMatchesCount = 0;
    this._searchResultsCount = 0;
    this._nonEmptySearchResultsCount = 0;
  }

  _nothingFound() {
    if (!this._notFoundView) {
      this._notFoundView = new UI.EmptyWidget.EmptyWidget(Common.UIString.UIString('No matches found.'));
    }
    this._showPane(this._notFoundView);
    this._searchResultsMessageElement.textContent = Common.UIString.UIString('No matches found.');
  }

  /**
   * @param {!SearchResult} searchResult
   */
  _addSearchResult(searchResult) {
    const matchesCount = searchResult.matchesCount();
    this._searchMatchesCount += matchesCount;
    this._searchResultsCount++;
    if (matchesCount) {
      this._nonEmptySearchResultsCount++;
    }
    this._updateSearchResultsMessage();
  }

  /**
   * @param {boolean} finished
   */
  _searchFinished(finished) {
    this._searchMessageElement.textContent =
        finished ? Common.UIString.UIString('Search finished.') : Common.UIString.UIString('Search interrupted.');
  }

  /**
   * @override
   */
  focus() {
    this._search.focus();
    this._search.select();
  }

  /**
   * @override
   */
  willHide() {
    this._stopSearch();
  }

  /**
   * @param {!KeyboardEvent} event
   */
  _onKeyDown(event) {
    switch (event.keyCode) {
      case UI.KeyboardShortcut.Keys.Enter.code:
        this._onAction();
        break;
    }
  }

  _save() {
    this._advancedSearchConfig.set(this._buildSearchConfig().toPlainObject());
  }

  _load() {
    const searchConfig = SearchConfig.fromPlainObject(this._advancedSearchConfig.get());
    this._search.value = searchConfig.query();
    this._matchCaseButton.setToggled(!searchConfig.ignoreCase());
    this._regexButton.setToggled(searchConfig.isRegex());
  }

  _onAction() {
    // Resetting alert variable to prime for next search query result.
    UI.ARIAUtils.alert(' ', this._searchMessageElement);
    const searchConfig = this._buildSearchConfig();
    if (!searchConfig.query() || !searchConfig.query().length) {
      return;
    }
    this._save();
    this._startSearch(searchConfig);
  }
}
<commit_msg>Clear network search input on new instance of DevTools<commit_after>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import * as Common from '../common/common.js';
import * as UI from '../ui/ui.js';

import {SearchConfig, SearchResult, SearchScope} from './SearchConfig.js';  // eslint-disable-line no-unused-vars
import {SearchResultsPane} from './SearchResultsPane.js';

export class SearchView extends UI.Widget.VBox {
  /**
   * @param {string} settingKey
   */
  constructor(settingKey) {
    super(true);
    this.setMinimumSize(0, 40);
    this.registerRequiredCSS('search/searchView.css', {enableLegacyPatching: true});

    this._focusOnShow = false;
    this._isIndexing = false;
    this._searchId = 1;
    this._searchMatchesCount = 0;
    this._searchResultsCount = 0;
    this._nonEmptySearchResultsCount = 0;
    /** @type {?UI.Widget.Widget} */
    this._searchingView = null;
    /** @type {?UI.Widget.Widget} */
    this._notFoundView = null;
    /** @type {?SearchConfig} */
    this._searchConfig = null;
    /** @type {?SearchConfig} */
    this._pendingSearchConfig = null;
    /** @type {?SearchResultsPane} */
    this._searchResultsPane = null;
    /** @type {?UI.ProgressIndicator.ProgressIndicator} */
    this._progressIndicator = null;
    /** @type {?UI.Widget.Widget} */
    this._visiblePane = null;

    this.contentElement.classList.add('search-view');

    this._searchPanelElement = this.contentElement.createChild('div', 'search-drawer-header');
    this._searchPanelElement.addEventListener(
        'keydown', event => this._onKeyDown(/** @type {!KeyboardEvent} */ (event)), false);

    this._searchResultsElement = this.contentElement.createChild('div');
    this._searchResultsElement.className = 'search-results';

    const searchContainer = document.createElement('div');
    searchContainer.style.flex = 'auto';
    searchContainer.style.justifyContent = 'start';
    searchContainer.style.maxWidth = '300px';
    this._search = UI.HistoryInput.HistoryInput.create();
    searchContainer.appendChild(this._search);
    this._search.placeholder = Common.UIString.UIString('Search');
    this._search.setAttribute('type', 'text');
    this._search.setAttribute('results', '0');
    this._search.setAttribute('size', '42');
    UI.ARIAUtils.setAccessibleName(this._search, ls`Search Query`);
    const searchItem = new UI.Toolbar.ToolbarItem(searchContainer);

    const toolbar = new UI.Toolbar.Toolbar('search-toolbar', this._searchPanelElement);
    this._matchCaseButton = SearchView._appendToolbarToggle(toolbar, 'Aa', Common.UIString.UIString('Match Case'));
    this._regexButton =
        SearchView._appendToolbarToggle(toolbar, '.*', Common.UIString.UIString('Use Regular Expression'));
    toolbar.appendToolbarItem(searchItem);
    const refreshButton = new UI.Toolbar.ToolbarButton(Common.UIString.UIString('Refresh'), 'largeicon-refresh');
    const clearButton = new UI.Toolbar.ToolbarButton(Common.UIString.UIString('Clear'), 'largeicon-clear');
    toolbar.appendToolbarItem(refreshButton);
    toolbar.appendToolbarItem(clearButton);
    refreshButton.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, this._onAction.bind(this));
    clearButton.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, () => {
      this._resetSearch();
      this._onSearchInputClear();
    });

    const searchStatusBarElement = this.contentElement.createChild('div', 'search-toolbar-summary');
    this._searchMessageElement = searchStatusBarElement.createChild('div', 'search-message');
    this._searchProgressPlaceholderElement = searchStatusBarElement.createChild('div', 'flex-centered');
    this._searchResultsMessageElement = searchStatusBarElement.createChild('div', 'search-message');

    this._advancedSearchConfig = Common.Settings.Settings.instance().createLocalSetting(
        settingKey + 'SearchConfig', new SearchConfig('', true, false).toPlainObject());

    this._load();
    /** @type {?SearchScope} */
    this._searchScope = null;
  }

  /**
   * @param {!UI.Toolbar.Toolbar} toolbar
   * @param {string} text
   * @param {string} tooltip
   * @return {!UI.Toolbar.ToolbarToggle}
   */
  static _appendToolbarToggle(toolbar, text, tooltip) {
    const toggle = new UI.Toolbar.ToolbarToggle(tooltip);
    toggle.setText(text);
    toggle.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, () => toggle.setToggled(!toggle.toggled()));
    toolbar.appendToolbarItem(toggle);
    return toggle;
  }

  /**
   * @return {!SearchConfig}
   */
  _buildSearchConfig() {
    return new SearchConfig(this._search.value, !this._matchCaseButton.toggled(), this._regexButton.toggled());
  }

  /**
   * @param {string} queryCandidate
   * @param {boolean=} searchImmediately
   */
  async toggle(queryCandidate, searchImmediately) {
    if (queryCandidate) {
      this._search.value = queryCandidate;
    }
    if (this.isShowing()) {
      this.focus();
    } else {
      this._focusOnShow = true;
    }

    this._initScope();
    if (searchImmediately) {
      this._onAction();
    } else {
      this._startIndexing();
    }
  }

  /**
   * @protected
   * @return {!SearchScope}
   */
  createScope() {
    throw new Error('Not implemented');
  }

  _initScope() {
    this._searchScope = this.createScope();
  }

  /**
   * @override
   */
  wasShown() {
    if (this._focusOnShow) {
      this.focus();
      this._focusOnShow = false;
    }
  }

  _onIndexingFinished() {
    if (!this._progressIndicator) {
      return;
    }

    const finished = !this._progressIndicator.isCanceled();
    this._progressIndicator.done();
    this._progressIndicator = null;
    this._isIndexing = false;
    this._indexingFinished(finished);
    if (!finished) {
      this._pendingSearchConfig = null;
    }
    if (!this._pendingSearchConfig) {
      return;
    }
    const searchConfig = this._pendingSearchConfig;
    this._pendingSearchConfig = null;
    this._innerStartSearch(searchConfig);
  }

  _startIndexing() {
    this._isIndexing = true;
    if (this._progressIndicator) {
      this._progressIndicator.done();
    }
    this._progressIndicator = new UI.ProgressIndicator.ProgressIndicator();
    this._searchMessageElement.textContent = Common.UIString.UIString('Indexing…');
    this._progressIndicator.show(this._searchProgressPlaceholderElement);
    if (this._searchScope) {
      this._searchScope.performIndexing(
          new Common.Progress.ProgressProxy(this._progressIndicator, this._onIndexingFinished.bind(this)));
    }
  }

  _onSearchInputClear() {
    this._search.value = '';
    this._save();
    this.focus();
  }

  /**
   * @param {number} searchId
   * @param {!SearchResult} searchResult
   */
  _onSearchResult(searchId, searchResult) {
    if (searchId !== this._searchId || !this._progressIndicator) {
      return;
    }
    if (this._progressIndicator && this._progressIndicator.isCanceled()) {
      this._onIndexingFinished();
      return;
    }
    this._addSearchResult(searchResult);
    if (!searchResult.matchesCount()) {
      return;
    }
    if (!this._searchResultsPane) {
      this._searchResultsPane = new SearchResultsPane(/** @type {!SearchConfig} */ (this._searchConfig));
      this._showPane(this._searchResultsPane);
    }
    this._searchResultsPane.addSearchResult(searchResult);
  }

  /**
   * @param {number} searchId
   * @param {boolean} finished
   */
  _onSearchFinished(searchId, finished) {
    if (searchId !== this._searchId || !this._progressIndicator) {
      return;
    }
    if (!this._searchResultsPane) {
      this._nothingFound();
    }
    this._searchFinished(finished);
    this._searchConfig = null;
    UI.ARIAUtils.alert(
        this._searchMessageElement.textContent + ' ' + this._searchResultsMessageElement.textContent,
        this._searchMessageElement);
  }

  /**
   * @param {!SearchConfig} searchConfig
   */
  async _startSearch(searchConfig) {
    this._resetSearch();
    ++this._searchId;
    this._initScope();
    if (!this._isIndexing) {
      this._startIndexing();
    }
    this._pendingSearchConfig = searchConfig;
  }

  /**
   *
   * @param {!SearchConfig} searchConfig
   */
  _innerStartSearch(searchConfig) {
    this._searchConfig = searchConfig;
    if (this._progressIndicator) {
      this._progressIndicator.done();
    }
    this._progressIndicator = new UI.ProgressIndicator.ProgressIndicator();
    this._searchStarted(this._progressIndicator);
    if (this._searchScope) {
      this._searchScope.performSearch(
          searchConfig, this._progressIndicator, this._onSearchResult.bind(this, this._searchId),
          this._onSearchFinished.bind(this, this._searchId));
    }
  }

  _resetSearch() {
    this._stopSearch();
    this._showPane(null);
    this._searchResultsPane = null;
    this._clearSearchMessage();
  }

  _clearSearchMessage() {
    this._searchMessageElement.textContent = '';
    this._searchResultsMessageElement.textContent = '';
  }

  _stopSearch() {
    if (this._progressIndicator && !this._isIndexing) {
      this._progressIndicator.cancel();
    }
    if (this._searchScope) {
      this._searchScope.stopSearch();
    }
    this._searchConfig = null;
  }

  /**
   * @param {!UI.ProgressIndicator.ProgressIndicator} progressIndicator
   */
  _searchStarted(progressIndicator) {
    this._resetCounters();
    if (!this._searchingView) {
      this._searchingView = new UI.EmptyWidget.EmptyWidget(Common.UIString.UIString('Searching…'));
    }
    this._showPane(this._searchingView);
    this._searchMessageElement.textContent = Common.UIString.UIString('Searching…');
    progressIndicator.show(this._searchProgressPlaceholderElement);
    this._updateSearchResultsMessage();
  }

  /**
   * @param {boolean} finished
   */
  _indexingFinished(finished) {
    this._searchMessageElement.textContent = finished ? '' : Common.UIString.UIString('Indexing interrupted.');
  }

  _updateSearchResultsMessage() {
    if (this._searchMatchesCount && this._searchResultsCount) {
      if (this._searchMatchesCount === 1 && this._nonEmptySearchResultsCount === 1) {
        this._searchResultsMessageElement.textContent = Common.UIString.UIString('Found 1 matching line in 1 file.');
      } else if (this._searchMatchesCount > 1 && this._nonEmptySearchResultsCount === 1) {
        this._searchResultsMessageElement.textContent =
            Common.UIString.UIString('Found %d matching lines in 1 file.', this._searchMatchesCount);
      } else {
        this._searchResultsMessageElement.textContent = Common.UIString.UIString(
            'Found %d matching lines in %d files.', this._searchMatchesCount, this._nonEmptySearchResultsCount);
      }
    } else {
      this._searchResultsMessageElement.textContent = '';
    }
  }

  /**
   * @param {?UI.Widget.Widget} panel
   */
  _showPane(panel) {
    if (this._visiblePane) {
      this._visiblePane.detach();
    }
    if (panel) {
      panel.show(this._searchResultsElement);
    }
    this._visiblePane = panel;
  }

  _resetCounters() {
    this._searchMatchesCount = 0;
    this._searchResultsCount = 0;
    this._nonEmptySearchResultsCount = 0;
  }

  _nothingFound() {
    if (!this._notFoundView) {
      this._notFoundView = new UI.EmptyWidget.EmptyWidget(Common.UIString.UIString('No matches found.'));
    }
    this._showPane(this._notFoundView);
    this._searchResultsMessageElement.textContent = Common.UIString.UIString('No matches found.');
  }

  /**
   * @param {!SearchResult} searchResult
   */
  _addSearchResult(searchResult) {
    const matchesCount = searchResult.matchesCount();
    this._searchMatchesCount += matchesCount;
    this._searchResultsCount++;
    if (matchesCount) {
      this._nonEmptySearchResultsCount++;
    }
    this._updateSearchResultsMessage();
  }

  /**
   * @param {boolean} finished
   */
  _searchFinished(finished) {
    this._searchMessageElement.textContent =
        finished ? Common.UIString.UIString('Search finished.') : Common.UIString.UIString('Search interrupted.');
  }

  /**
   * @override
   */
  focus() {
    this._search.focus();
    this._search.select();
  }

  /**
   * @override
   */
  willHide() {
    this._stopSearch();
  }

  /**
   * @param {!KeyboardEvent} event
   */
  _onKeyDown(event) {
    switch (event.keyCode) {
      case UI.KeyboardShortcut.Keys.Enter.code:
        this._onAction();
        break;
    }
  }

  _save() {
    this._advancedSearchConfig.set(this._buildSearchConfig().toPlainObject());
  }

  _load() {
    const searchConfig = SearchConfig.fromPlainObject(this._advancedSearchConfig.get());
    this._search.value = searchConfig.query();
    this._matchCaseButton.setToggled(!searchConfig.ignoreCase());
    this._regexButton.setToggled(searchConfig.isRegex());
  }

  _onAction() {
    // Resetting alert variable to prime for next search query result.
    UI.ARIAUtils.alert(' ', this._searchMessageElement);
    const searchConfig = this._buildSearchConfig();
    if (!searchConfig.query() || !searchConfig.query().length) {
      return;
    }
    this._save();
    this._startSearch(searchConfig);
  }
}
<|endoftext|>


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

CLASS({
  package: 'com.google.watlobby',
  name: 'Remote',
  extends: 'foam.graphics.CView',

  traits: [ 'com.google.watlobby.RemoteTrait' ],

  requires: [
    'com.google.watlobby.Bubble',
    'com.google.watlobby.PhotoBubble',
    'com.google.watlobby.Topic',
    'com.google.watlobby.TopicBubble',
    'com.google.watlobby.TopicDAO',
    'com.google.watlobby.VideoBubble',
    'foam.demos.physics.PhysicalCircle',
    'foam.graphics.ImageCView'
  ],

  imports: [
    'document',
    'window'
  ],

  properties: [
    {
      model_: 'BooleanProperty',
      name: 'clientMode',
      defaultValue: true
    },
    {
      name: 'topics',
      lazyFactory: function() {
        return this.TopicDAO.create({ clientMode: this.clientMode });
      }
    },
    { name: 'background', defaultValue: '#ccf' }
  ],

  listeners: [
    {
      name: 'updateState',
      isMerged: 200,
      code: function() {
        this.topics.find(EQ(this.Topic.TOPIC, this.symRoot), {
          put: function (t) {
            t = t.clone();
            t.selected = this.selected;
            t.dir = this.dir;
            this.topics.put(t);
          }.bind(this)
        });
      }
    },
    {
      name: 'layout',
      isFramed: true,
      code: function() {
        this.width  = this.window.innerWidth;
        this.height = this.window.innerHeight;

        while ( this.children.length ) {
          this.removeChild(this.children[this.children.length-1]);
        }

        if ( this.dir ) {
          this.putTopic(this.Topic.create({
            parentTopic: this.dir,
            topic: this.BACK_TOPIC,
            image: 'img/back.png',
            model: "Photo",
            color: 'gray',
            roundImage: true
          }));
        }
        this.topics.find(EQ(this.Topic.TOPIC, this.dir),{put:this.putTopic.bind(this)});
        this.topics.where(EQ(this.Topic.PARENT_TOPIC, this.dir)).select({put: this.putTopic.bind(this)});
      }
    }
  ],

  methods: [
    function initCView() {
      this.SUPER();

      this.window.addEventListener('resize', this.layout);
      this.topics.listen({put: function(t) { if ( t.topic !== this.symRoot ) this.layout(); }.bind(this), remove: this.layout});
      this.document.body.addEventListener('click', this.onClick);
      this.selected$.addListener(this.updateState);
      this.dir$.addListener(this.updateState);
      this.dir$.addListener(this.layout);
      this.layout();
    },

    function putTopic(t) {
      if ( this.maybeRedirect(t) ) return;
      if ( t.topic === this.symRoot ) return;

      if ( ! t.enabled ) {
        // Newly disabled, so re-layout.
        if ( this.findTopic(t.topic) ) this.layout();
        return;
      }

      t = t.clone();

      var h = (this.height-26) / 4;
      var i = this.children.length;
      var m = this.X.lookup('com.google.watlobby.' + t.model + 'Bubble');
      if ( ! m ) return;
      var c = m.create({
        x: Math.floor(i / 4) * h + h/2,
        y: ( i % 4 ) * h + h/2
      }, this.Y);
      c.topic = t;
      c.image = t.image;
      var r = h/2-20;
      t.r = c.r = r;
      c.scaleX = c.scaleY = 0.01;
      c.roundImage = t.roundImage;
      if ( t.color ) c.border = t.color;
      if ( t.background ) c.color = t.background;
      this.addChild(c);

      if ( t.topic === this.BACK_TOPIC ) c.alpha = 0.5;

      var close = this.ImageCView.create({alpha: 0.5, x: -r, y: -r, width: 2*r, height: 2*r, src: 'img/close.png'});
      var s = function() { c.scaleX = c.scaleY = ! this.selected ? 0.9 : this.selected === t.topic ? 1.02 : 0.75; }.bind(this);
      var l = function() { if ( this.selected === t.topic ) { c.addChild(close); } else { c.removeChild(close); } Movement.animate(300, s)(); }.bind(this);
      this.selected$.addListener(l);
      this.X.setTimeout(l,20);
    }
  ]
});
<commit_msg>WatLobby: Small timing changes.<commit_after>/**
 * @license
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

CLASS({
  package: 'com.google.watlobby',
  name: 'Remote',
  extends: 'foam.graphics.CView',

  traits: [ 'com.google.watlobby.RemoteTrait' ],

  requires: [
    'com.google.watlobby.Bubble',
    'com.google.watlobby.PhotoBubble',
    'com.google.watlobby.Topic',
    'com.google.watlobby.TopicBubble',
    'com.google.watlobby.TopicDAO',
    'com.google.watlobby.VideoBubble',
    'foam.demos.physics.PhysicalCircle',
    'foam.graphics.ImageCView'
  ],

  imports: [
    'document',
    'window'
  ],

  properties: [
    {
      model_: 'BooleanProperty',
      name: 'clientMode',
      defaultValue: true
    },
    {
      name: 'topics',
      lazyFactory: function() {
        return this.TopicDAO.create({ clientMode: this.clientMode });
      }
    },
    { name: 'background', defaultValue: '#ccf' }
  ],

  listeners: [
    {
      name: 'updateState',
      isMerged: 200,
      code: function() {
        this.topics.find(EQ(this.Topic.TOPIC, this.symRoot), {
          put: function (t) {
            t = t.clone();
            t.selected = this.selected;
            t.dir = this.dir;
            this.topics.put(t);
          }.bind(this)
        });
      }
    },
    {
      name: 'layout',
      isFramed: true,
      code: function() {
        this.width  = this.window.innerWidth;
        this.height = this.window.innerHeight;

        while ( this.children.length ) {
          this.removeChild(this.children[this.children.length-1]);
        }

        if ( this.dir ) {
          this.putTopic(this.Topic.create({
            parentTopic: this.dir,
            topic: this.BACK_TOPIC,
            image: 'img/back.png',
            model: "Photo",
            color: 'gray',
            roundImage: true
          }));
        }
        this.topics.find(EQ(this.Topic.TOPIC, this.dir),{put:this.putTopic.bind(this)});
        this.topics.where(EQ(this.Topic.PARENT_TOPIC, this.dir)).select({put: this.putTopic.bind(this)});
      }
    }
  ],

  methods: [
    function initCView() {
      this.SUPER();

      this.window.addEventListener('resize', this.layout);
      this.topics.listen({put: function(t) { if ( t.topic !== this.symRoot ) this.layout(); }.bind(this), remove: this.layout});
      this.document.body.addEventListener('click', this.onClick);
      this.selected$.addListener(this.updateState);
      this.dir$.addListener(this.updateState);
      this.dir$.addListener(this.layout);
      this.layout();
    },

    function putTopic(t) {
      if ( this.maybeRedirect(t) ) return;
      if ( t.topic === this.symRoot ) return;

      if ( ! t.enabled ) {
        // Newly disabled, so re-layout.
        if ( this.findTopic(t.topic) ) this.layout();
        return;
      }

      t = t.clone();

      var h = (this.height-26) / 4;
      var i = this.children.length;
      var m = this.X.lookup('com.google.watlobby.' + t.model + 'Bubble');
      if ( ! m ) return;
      var c = m.create({
        x: Math.floor(i / 4) * h + h/2,
        y: ( i % 4 ) * h + h/2
      }, this.Y);
      c.topic = t;
      c.image = t.image;
      var r = h/2-20;
      t.r = c.r = r;
      c.scaleX = c.scaleY = 0.001;
      c.roundImage = t.roundImage;
      if ( t.color ) c.border = t.color;
      if ( t.background ) c.color = t.background;
      this.addChild(c);

      if ( t.topic === this.BACK_TOPIC ) c.alpha = 0.5;

      var close = this.ImageCView.create({alpha: 0.5, x: -r, y: -r, width: 2*r, height: 2*r, src: 'img/close.png'});
      var s = function() { c.scaleX = c.scaleY = ! this.selected ? 0.9 : this.selected === t.topic ? 1.02 : 0.75; }.bind(this);
      var l = function() { if ( this.selected === t.topic ) { c.addChild(close); } else { c.removeChild(close); } Movement.animate(300, s)(); }.bind(this);
      this.selected$.addListener(l);
      this.X.setTimeout(l,100);
    }
  ]
});
<|endoftext|>