<commit_before>$(document).ready(function() {
    $("#surname").blur(function() {
        matchVolunteerPerson($("#forename").val(), $("#surname").val(), $("#personId"));
    });

    $("#emergencyContactSurname").blur(function() {
        matchEmergencyContactPerson(
            $("#emergencyContactForename").val(),
            $("#emergencyContactSurname").val(),
            $("#emergencyContactPersonId")
        );
    });

    $(".datepicker").datepicker({
        dateFormat: "dd/mm/yy",
        changeYear: true
    });

    $("#congregationName").typeahead({
        source: roms.common.congregationTypeAheadSource,
        minLength: 2
    });

    $("#volunteer").validate({
        rules: {
            forename: {
                minlength: 2,
                required: true
            },
            surname: {
                minlength: 2,
                required: true
            },
            gender: {
                required: true
            },
            birthDate: {
                required: true
            },
            baptismDate: {
                required: true
            },
            street: {
                minlength: 2,
                required: true
            },
            town: {
                minlength: 2,
                required: true
            },
            postcode: {
                minlength: 2,
                required: true
            },
            email: {
                required: true,
                email: true
            },
            maritalStatusId: {
                required: true
            },
            emergencyContactForename: {
                minlength: 2,
                required: true
            },
            emergencyContactSurname: {
                minlength: 2,
                required: true
            },
            emergencyContactStreet: {
                minlength: 2,
                required: true
            },
            emergencyContactTown: {
                minlength: 2,
                required: true
            },
            emergencyRelationshipId: {
                required: true
            },
            congregationName: {
                required: true,
                remote: {
                    // check for an exact match. Populate the congregation id
                    url: roms.common.relativePath + "congregations/search",
                    contentType: "application/json",
                    dataType: "json",
                    data: {
                        name: function() {
                            return $("#congregationName").val();
                        }
                    },
                    dataFilter: function(rawData) {
                        var data = JSON.parse(rawData)
                        if (data.results && data.results[0].name == $("#congregationName").val()) {
                            $("#congregationId").val(data.results[0].id);
                            return true;

                        }
                        return false;
                    }
                }
            },
            congregationId: {
                required: true
            },
            formDate: {
                required: true
            }
        },
        errorPlacement: roms.common.validatorErrorPlacement
    });

    $("#emergency-contact-linked button.close").click(function() {
        populateEmergencyContactFromPerson(null, $("#emergencyContactPersonId"));
    });

    /**
     * Match the entered name of the volunteer with an existing person/volunteer
     * @param forename entered forename
     * @param surname entered surname
     * @param $personId jquery reference to the hidden field containing the person id
     */
    function matchVolunteerPerson(forename, surname, $personId) {

       if(!forename || !surname) {
           return;
       }

       var existingPersonName = $personId.data("full-name");
       if (existingPersonName == forename + " " + surname) {
           // no change in value
           return;
       }
       this.findVolunteerPerson(forename, surname, $personId, existingPersonName);

       $personId.data("full-name", forename + " " + surname);
    }

    /**
     * Look up the person matching the name and show a popover
     * to allow the user the select the match, if any
     */
    function findVolunteerPerson(forename, surname, $personId, existingPersonName)  {
        var _parent = this;
        var existingPersonId = $personId.val();
        $.ajax({
            url: roms.common.relativePath + 'persons/search',
            contentType: "application/json",
            dataType: 'json',
            data:  {
                forename: forename,
                surname: surname,
                checkVolunteer: true
            },
            success: function(data) {
                // no match, and no person linked. We don't show anything
                if (!data.results && !existingPersonId) {
                    return;
                }

                // enrich the results, splitting out the volunters from the persons.
                // if we are matching an existing volunteer we don't want to create a new one
                var volunteers = new Array();
                var persons = new Array();
                if (data.results) {
                    for (var i = 0; i < data.results.length; i++) {
                        var result = data.results[i];

                        if (result.personId != existingPersonId) {
                            if (result.volunteer) {
                                volunteers.push(result);
                            } else {
                                persons.push(result);
                            }
                        }
                    }
                }

                data.existingPersonId = existingPersonId;
                data.existingPersonName = existingPersonName;
                if (volunteers.length > 0) {
                    data.matchedVolunteers = true;
                    data.volunteers = volunteers;
                }

                if (persons.length > 0) {
                    data.matchedPersons = true;
                    data.persons = persons;
                }

                var template = $("#volunteer-person-search-form").html();
                var html = Mustache.to_html(template, data);

                $("#volunteer-person-modal .modal-body").html(html)
                var modalElement = $("#volunteer-person-modal")

                modalElement.modal('show')

                // if they select the person id, set it to the hidden volunteer person id field
                $("a.matched-person").on("click", function(event){
                    _parent.populateVolunteerFromPerson($(this).data("person-id"), $personId);
                    modalElement.modal('hide')
                });
            }
        });
    }

    /**
     * Populate the volunteer form from the existing person
     */
    function populateVolunteerFromPerson(selectedPersonId, $personId) {
        // chosen nobody. Clear the existing value
        if (!selectedPersonId) {
            $personId.val(selectedPersonId);
            return;
        }
        var existingPersonId = $personId.val();

        if (existingPersonId == selectedPersonId) {
            return;
        }

        // new person - pull the person data and populate the form.
        $.ajax({
            url: roms.common.relativePath + 'persons/' + selectedPersonId  + "/reference",
            contentType: "application/json",
            dataType: 'json',
            success: function(data) {
                $("#birthDate").val(data.birthDate);
                $("input[name='middleName']").val(data.middleName);
                $("input[name='telephone']").val(data.telephone);
                $("input[name='mobile']").val(data.mobile);
                $("input[name='workPhone']").val(data.workPhone);
                $("input[name='email']").val(data.email);
                if(data.congregation) {
                    $("input[name='congregationId']").val(data.congregation.congregationId);
                }
                if (data.address) {
                    $("input[name='street']").val(data.address.street);
                    $("input[name='town']").val(data.address.town);
                    $("input[name='county']").val(data.address.county);
                    $("input[name='postcode']").val(data.address.postcode);
                }
            }
        });
        $personId.val(selectedPersonId);
    }

    function matchEmergencyContactPerson(forename, surname, $personId) {
        if(!forename || !surname) {
            return;
        }

        var existingPersonName = $personId.data("full-name");
        if (existingPersonName == forename + " " + surname) {
            // no change in value
            return;
        }
        var existingPersonId = $personId.val();

        $.ajax({
            url: roms.common.relativePath + 'persons/search',
            contentType: "application/json",
            dataType: 'json',
            data:  {
                forename: forename,
                surname: surname,
                checkVolunteer: false
            },
            success: function(data) {
                // no match, and no person linked. We don't show anything
                if (!data.results && !existingPersonId) {
                    return;
                }

                data.existingPersonId = existingPersonId;
                data.existingPersonName = existingPersonName;

                if (data.results) {
                    data.matchedPersons = true;
                }

                var template = $("#volunteer-emergency-contact-search-form").html();
                var html = Mustache.to_html(template, data);

                $("#volunteer-person-modal .modal-body").html(html)
                var modalElement = $("#volunteer-person-modal")

                modalElement.modal('show')

                // if they select the person id, set it to the hidden volunteer person id field
                $("a.matched-person").on("click", function(event){
                    populateEmergencyContactFromPerson($(this).data("person-id"), $personId);
                    modalElement.modal('hide')
                });
            }
        });

        $personId.data("full-name", forename + " " + surname);
    }

    function populateEmergencyContactFromPerson(selectedPersonId, $personId) {

        if (selectedPersonId) {
            // disable all the additional fields. include the text that indicates we are
            $("#emergency-contact-additional-fields input").prop("disabled", true);
            $("#emergency-contact-additional-fields").hide("fast");
            $("#emergency-contact-linked").show("fast");
        } else {
            $("#emergency-contact-additional-fields input").prop("disabled", false)
            $("#emergency-contact-additional-fields").show("fast");
            $("#emergency-contact-linked").hide("fast");
        }
    }

});
<commit_msg>[#42842865] elder and MS checkboxes are exclusive. To save messing up the display with the pioneer 3rd option, toggle using javascript<commit_after>$(document).ready(function() {
    $("#surname").blur(function() {
        matchVolunteerPerson($("#forename").val(), $("#surname").val(), $("#personId"));
    });

    $("#emergencyContactSurname").blur(function() {
        matchEmergencyContactPerson(
            $("#emergencyContactForename").val(),
            $("#emergencyContactSurname").val(),
            $("#emergencyContactPersonId")
        );
    });

    $(".datepicker").datepicker({
        dateFormat: "dd/mm/yy",
        changeYear: true
    });

    // elder and ministerial values are exclusive
    $("input[name='elder']").change(function() {
        if($(this).is(':checked')) {
            $("input[name='ministerialServant']").prop("checked", false);
        }
    });
    $("input[name='ministerialServant']").change(function() {
        if($(this).is(':checked')) {
            $("input[name='elder']").prop("checked", false);
        }
    });

    $("#congregationName").typeahead({
        source: roms.common.congregationTypeAheadSource,
        minLength: 2
    });

    $("#volunteer").validate({
        rules: {
            forename: {
                minlength: 2,
                required: true
            },
            surname: {
                minlength: 2,
                required: true
            },
            gender: {
                required: true
            },
            birthDate: {
                required: true
            },
            baptismDate: {
                required: true
            },
            street: {
                minlength: 2,
                required: true
            },
            town: {
                minlength: 2,
                required: true
            },
            postcode: {
                minlength: 2,
                required: true
            },
            email: {
                required: true,
                email: true
            },
            maritalStatusId: {
                required: true
            },
            emergencyContactForename: {
                minlength: 2,
                required: true
            },
            emergencyContactSurname: {
                minlength: 2,
                required: true
            },
            emergencyContactStreet: {
                minlength: 2,
                required: true
            },
            emergencyContactTown: {
                minlength: 2,
                required: true
            },
            emergencyRelationshipId: {
                required: true
            },
            congregationName: {
                required: true,
                remote: {
                    // check for an exact match. Populate the congregation id
                    url: roms.common.relativePath + "congregations/search",
                    contentType: "application/json",
                    dataType: "json",
                    data: {
                        name: function() {
                            return $("#congregationName").val();
                        }
                    },
                    dataFilter: function(rawData) {
                        var data = JSON.parse(rawData)
                        if (data.results && data.results[0].name == $("#congregationName").val()) {
                            $("#congregationId").val(data.results[0].id);
                            return true;

                        }
                        return false;
                    }
                }
            },
            congregationId: {
                required: true
            },
            formDate: {
                required: true
            }
        },
        errorPlacement: roms.common.validatorErrorPlacement
    });

    $("#emergency-contact-linked button.close").click(function() {
        populateEmergencyContactFromPerson(null, $("#emergencyContactPersonId"));
    });

    /**
     * Match the entered name of the volunteer with an existing person/volunteer
     * @param forename entered forename
     * @param surname entered surname
     * @param $personId jquery reference to the hidden field containing the person id
     */
    function matchVolunteerPerson(forename, surname, $personId) {

       if(!forename || !surname) {
           return;
       }

       var existingPersonName = $personId.data("full-name");
       if (existingPersonName == forename + " " + surname) {
           // no change in value
           return;
       }
       this.findVolunteerPerson(forename, surname, $personId, existingPersonName);

       $personId.data("full-name", forename + " " + surname);
    }

    /**
     * Look up the person matching the name and show a popover
     * to allow the user the select the match, if any
     */
    function findVolunteerPerson(forename, surname, $personId, existingPersonName)  {
        var _parent = this;
        var existingPersonId = $personId.val();
        $.ajax({
            url: roms.common.relativePath + 'persons/search',
            contentType: "application/json",
            dataType: 'json',
            data:  {
                forename: forename,
                surname: surname,
                checkVolunteer: true
            },
            success: function(data) {
                // no match, and no person linked. We don't show anything
                if (!data.results && !existingPersonId) {
                    return;
                }

                // enrich the results, splitting out the volunters from the persons.
                // if we are matching an existing volunteer we don't want to create a new one
                var volunteers = new Array();
                var persons = new Array();
                if (data.results) {
                    for (var i = 0; i < data.results.length; i++) {
                        var result = data.results[i];

                        if (result.personId != existingPersonId) {
                            if (result.volunteer) {
                                volunteers.push(result);
                            } else {
                                persons.push(result);
                            }
                        }
                    }
                }

                data.existingPersonId = existingPersonId;
                data.existingPersonName = existingPersonName;
                if (volunteers.length > 0) {
                    data.matchedVolunteers = true;
                    data.volunteers = volunteers;
                }

                if (persons.length > 0) {
                    data.matchedPersons = true;
                    data.persons = persons;
                }

                var template = $("#volunteer-person-search-form").html();
                var html = Mustache.to_html(template, data);

                $("#volunteer-person-modal .modal-body").html(html)
                var modalElement = $("#volunteer-person-modal")

                modalElement.modal('show')

                // if they select the person id, set it to the hidden volunteer person id field
                $("a.matched-person").on("click", function(event){
                    _parent.populateVolunteerFromPerson($(this).data("person-id"), $personId);
                    modalElement.modal('hide')
                });
            }
        });
    }

    /**
     * Populate the volunteer form from the existing person
     */
    function populateVolunteerFromPerson(selectedPersonId, $personId) {
        // chosen nobody. Clear the existing value
        if (!selectedPersonId) {
            $personId.val(selectedPersonId);
            return;
        }
        var existingPersonId = $personId.val();

        if (existingPersonId == selectedPersonId) {
            return;
        }

        // new person - pull the person data and populate the form.
        $.ajax({
            url: roms.common.relativePath + 'persons/' + selectedPersonId  + "/reference",
            contentType: "application/json",
            dataType: 'json',
            success: function(data) {
                $("#birthDate").val(data.birthDate);
                $("input[name='middleName']").val(data.middleName);
                $("input[name='telephone']").val(data.telephone);
                $("input[name='mobile']").val(data.mobile);
                $("input[name='workPhone']").val(data.workPhone);
                $("input[name='email']").val(data.email);
                if(data.congregation) {
                    $("input[name='congregationId']").val(data.congregation.congregationId);
                }
                if (data.address) {
                    $("input[name='street']").val(data.address.street);
                    $("input[name='town']").val(data.address.town);
                    $("input[name='county']").val(data.address.county);
                    $("input[name='postcode']").val(data.address.postcode);
                }
            }
        });
        $personId.val(selectedPersonId);
    }

    function matchEmergencyContactPerson(forename, surname, $personId) {
        if(!forename || !surname) {
            return;
        }

        var existingPersonName = $personId.data("full-name");
        if (existingPersonName == forename + " " + surname) {
            // no change in value
            return;
        }
        var existingPersonId = $personId.val();

        $.ajax({
            url: roms.common.relativePath + 'persons/search',
            contentType: "application/json",
            dataType: 'json',
            data:  {
                forename: forename,
                surname: surname,
                checkVolunteer: false
            },
            success: function(data) {
                // no match, and no person linked. We don't show anything
                if (!data.results && !existingPersonId) {
                    return;
                }

                data.existingPersonId = existingPersonId;
                data.existingPersonName = existingPersonName;

                if (data.results) {
                    data.matchedPersons = true;
                }

                var template = $("#volunteer-emergency-contact-search-form").html();
                var html = Mustache.to_html(template, data);

                $("#volunteer-person-modal .modal-body").html(html)
                var modalElement = $("#volunteer-person-modal")

                modalElement.modal('show')

                // if they select the person id, set it to the hidden volunteer person id field
                $("a.matched-person").on("click", function(event){
                    populateEmergencyContactFromPerson($(this).data("person-id"), $personId);
                    modalElement.modal('hide')
                });
            }
        });

        $personId.data("full-name", forename + " " + surname);
    }

    function populateEmergencyContactFromPerson(selectedPersonId, $personId) {

        if (selectedPersonId) {
            // disable all the additional fields. include the text that indicates we are
            $("#emergency-contact-additional-fields input").prop("disabled", true);
            $("#emergency-contact-additional-fields").hide("fast");
            $("#emergency-contact-linked").show("fast");
        } else {
            $("#emergency-contact-additional-fields input").prop("disabled", false)
            $("#emergency-contact-additional-fields").show("fast");
            $("#emergency-contact-linked").hide("fast");
        }
    }

});
<|endoftext|>


<commit_before>import AppBar from 'material-ui/AppBar';
import React, { Component } from 'react';
import SearchBar from 'material-ui-search-bar'
import { connect } from 'react-redux'
import _ from 'lodash'
import { push } from 'react-router-redux'
import LinearProgress from 'material-ui/LinearProgress';

import './index.css'
import logo from './OpenChemistry_Logo.svg';
import { searchDatasetsByText } from '../../redux/ducks/datasets'
import Menu from './menu'
import Login from './login'
import selectors from '../../redux/selectors';

const style = {
    backgroundColor: '#FAFAFA'
}

const titleStyle = {
  margin: 0,
  paddingTop: '8px',
  paddingLeft: '10px',

  lineHeight: 'normal',
  color: '#424242',
}

const searchBarStyle = {
  margin: '15px 50px',
  maxWidth: 800,
  width: '70%'
};

const iconStyleRight = {
  width: '50%'
}

const divStyle = {
  width: '100%',
  display: 'flex',
}

const loginMenuStyle = {
  'margin-top': '18px'
}

class RightElement extends Component {

  constructor(props)
  {
    super(props)
    this.state = {
      searchText: null
    }
  }

  componentWillMount = () => {
    this.props.dispatch(searchDatasetsByText());
  }

  onChange = (searchText) => {
    this.setState({
      searchText
    })
  }

  onRequestSearch = () => {
    this.props.dispatch(push('/'))
    if (_.isString(this.state.searchText) && !_.isEmpty(this.state.searchText)) {
      const text = this.state.searchText.toLowerCase();
      this.props.dispatch(searchDatasetsByText(text.split(/\s/)))
    }
    else {
      this.props.dispatch(searchDatasetsByText());
    }
  }

  render = () => {
    return (

        <SearchBar
          hintText={'Search by author, paper, microscope, atomic species'}
          onChange={this.onChange}
          onRequestSearch={this.onRequestSearch}
          style={searchBarStyle}
          className={'mdb-searchbar'}
        />

          {!this.props.isAuthenticated ? <Login/> : <Menu/>}

);
  }
}

function mapStateToProps(state) {
  const isAuthenticated = selectors.girder.isAuthenticated(state);

  return {
    isAuthenticated,
  }
}

RightElement = connect(mapStateToProps)(RightElement)

class Header extends Component {
  render = () => {
  const progressStyle = {}

  if (!this.props.progress) {
    progressStyle['display'] = 'none';
  }
  return (

      <AppBar
        title={

Material Data Bank

An Information Portal for 3D atomic electron tomography data

        }
        titleStyle={titleStyle}
        style={style}
        iconElementLeft={}
        iconElementRight={<RightElement/>}
        iconStyleRight={iconStyleRight} />
      <LinearProgress
        style={progressStyle}
        mode="indeterminate"
      />

  );
  }
}

function mapStateToPropsHeader(state) {

  const progress = selectors.app.progress(state);

  return {
    progress,
  }
}

export default connect(mapStateToPropsHeader)(Header)
<commit_msg>Material => Materials<commit_after>import AppBar from 'material-ui/AppBar';
import React, { Component } from 'react';
import SearchBar from 'material-ui-search-bar'
import { connect } from 'react-redux'
import _ from 'lodash'
import { push } from 'react-router-redux'
import LinearProgress from 'material-ui/LinearProgress';

import './index.css'
import logo from './OpenChemistry_Logo.svg';
import { searchDatasetsByText } from '../../redux/ducks/datasets'
import Menu from './menu'
import Login from './login'
import selectors from '../../redux/selectors';

const style = {
    backgroundColor: '#FAFAFA'
}

const titleStyle = {
  margin: 0,
  paddingTop: '8px',
  paddingLeft: '10px',

  lineHeight: 'normal',
  color: '#424242',
}

const searchBarStyle = {
  margin: '15px 50px',
  maxWidth: 800,
  width: '70%'
};

const iconStyleRight = {
  width: '50%'
}

const divStyle = {
  width: '100%',
  display: 'flex',
}

const loginMenuStyle = {
  'margin-top': '18px'
}

class RightElement extends Component {

  constructor(props)
  {
    super(props)
    this.state = {
      searchText: null
    }
  }

  componentWillMount = () => {
    this.props.dispatch(searchDatasetsByText());
  }

  onChange = (searchText) => {
    this.setState({
      searchText
    })
  }

  onRequestSearch = () => {
    this.props.dispatch(push('/'))
    if (_.isString(this.state.searchText) && !_.isEmpty(this.state.searchText)) {
      const text = this.state.searchText.toLowerCase();
      this.props.dispatch(searchDatasetsByText(text.split(/\s/)))
    }
    else {
      this.props.dispatch(searchDatasetsByText());
    }
  }

  render = () => {
    return (

        <SearchBar
          hintText={'Search by author, paper, microscope, atomic species'}
          onChange={this.onChange}
          onRequestSearch={this.onRequestSearch}
          style={searchBarStyle}
          className={'mdb-searchbar'}
        />

          {!this.props.isAuthenticated ? <Login/> : <Menu/>}

);
  }
}

function mapStateToProps(state) {
  const isAuthenticated = selectors.girder.isAuthenticated(state);

  return {
    isAuthenticated,
  }
}

RightElement = connect(mapStateToProps)(RightElement)

class Header extends Component {
  render = () => {
  const progressStyle = {}

  if (!this.props.progress) {
    progressStyle['display'] = 'none';
  }
  return (

      <AppBar
        title={

Materials Data Bank

An Information Portal for 3D atomic electron tomography data

        }
        titleStyle={titleStyle}
        style={style}
        iconElementLeft={}
        iconElementRight={<RightElement/>}
        iconStyleRight={iconStyleRight} />
      <LinearProgress
        style={progressStyle}
        mode="indeterminate"
      />

  );
  }
}

function mapStateToPropsHeader(state) {

  const progress = selectors.app.progress(state);

  return {
    progress,
  }
}

export default connect(mapStateToPropsHeader)(Header)
<|endoftext|>


<commit_before>/**
 * Created by ksinger on 20.08.2015.
 */
import angular from "angular";
import ngAnimate from "angular-animate";
import dropdownModule from "./covering-dropdown.js";
import accountMenuModule from "./account-menu.js";
import { attach, get, getIn } from "../utils.js";
import { actionCreators } from "../actions/actions.js";
import { connect2Redux } from "../won-utils.js";
import { isLoading } from "../selectors/process-selectors.js";
import * as viewSelectors from "../selectors/view-selectors.js";

import * as accountUtils from "../account-utils.js";

import "~/style/_responsiveness-utils.scss";
import "~/style/_topnav.scss";

const serviceDependencies = ["$ngRedux", "$scope", "$state", "$element"];

function genTopnavConf() {
  let template = `

                  {{ self.appTitle }}

                  —

                  {{ self.pageTitle }}

                <svg class="topnav__slideintoggle__icon">
                    <use xlink:href="#ico16_indicator_warning" href="#ico16_indicator_warning"></use>
                </svg>
                <svg class="topnav__slideintoggle__carret">
                    <use xlink:href="#ico16_arrow_down" href="#ico16_arrow_down"></use>
                </svg>

                <svg class="topnav__loading__spinner hspinner">
                    <use xlink:href="#ico_loading_anim" href="#ico_loading_anim"></use>
                </svg>

            <button ng-click="self.router__stateGo('signup')" class="topnav__signupbtn won-button--filled red" ng-if="!self.isSignUpView && (self.isAnonymous || !self.loggedIn)">
                Sign up
            </button>
            <won-account-menu>
            </won-account-menu>

    `;

  class Controller {
    constructor(/* arguments <- serviceDependencies */) {
      attach(this, serviceDependencies, arguments);

      window.tnc4dbg = this;

      const selectFromState = state => {
        const currentRoute = getIn(state, ["router", "currentState", "name"]);
        const accountState = get(state, "account");

        return {
          themeName: getIn(state, ["config", "theme", "name"]),
          appTitle: getIn(state, ["config", "theme", "title"]),
          loggedIn: accountUtils.isLoggedIn(accountState),
          isAnonymous: accountUtils.isAnonymous(accountState),
          isSignUpView: currentRoute === "signup",
          showLoadingIndicator: isLoading(state),
          showSlideInIndicator:
            viewSelectors.hasSlideIns(state) &&
            !viewSelectors.showSlideIns(state),
        };
      };

      connect2Redux(selectFromState, actionCreators, ["self.pageTitle"], this);
    }
  }
  Controller.$inject = serviceDependencies;

  return {
    restrict: "E",
    scope: {
      pageTitle: "=",
    }, //isolate scope to allow usage within other controllers/components
    controller: Controller,
    controllerAs: "self",
    bindToController: true, //scope-bindings -> ctrl
    template: template,
  };
}

export default angular
  .module("won.owner.components.topnav", [
    dropdownModule,
    accountMenuModule,
    ngAnimate,
  ])
  .directive("wonTopnav", genTopnavConf).name;
<commit_msg>Remove the page subtitle in the topnav header (for now)<commit_after>/**
 * Created by ksinger on 20.08.2015.
 */
import angular from "angular";
import ngAnimate from "angular-animate";
import dropdownModule from "./covering-dropdown.js";
import accountMenuModule from "./account-menu.js";
import { attach, get, getIn } from "../utils.js";
import { actionCreators } from "../actions/actions.js";
import { connect2Redux } from "../won-utils.js";
import { isLoading } from "../selectors/process-selectors.js";
import * as viewSelectors from "../selectors/view-selectors.js";

import * as accountUtils from "../account-utils.js";

import "~/style/_responsiveness-utils.scss";
import "~/style/_topnav.scss";

const serviceDependencies = ["$ngRedux", "$scope", "$state", "$element"];

function genTopnavConf() {
  let template = `

                  {{ self.appTitle }}

                <svg class="topnav__slideintoggle__icon">
                    <use xlink:href="#ico16_indicator_warning" href="#ico16_indicator_warning"></use>
                </svg>
                <svg class="topnav__slideintoggle__carret">
                    <use xlink:href="#ico16_arrow_down" href="#ico16_arrow_down"></use>
                </svg>

                <svg class="topnav__loading__spinner hspinner">
                    <use xlink:href="#ico_loading_anim" href="#ico_loading_anim"></use>
                </svg>

            <button ng-click="self.router__stateGo('signup')" class="topnav__signupbtn won-button--filled red" ng-if="!self.isSignUpView && (self.isAnonymous || !self.loggedIn)">
                Sign up
            </button>
            <won-account-menu>
            </won-account-menu>

    `;

  class Controller {
    constructor(/* arguments <- serviceDependencies */) {
      attach(this, serviceDependencies, arguments);

      window.tnc4dbg = this;

      const selectFromState = state => {
        const currentRoute = getIn(state, ["router", "currentState", "name"]);
        const accountState = get(state, "account");

        return {
          themeName: getIn(state, ["config", "theme", "name"]),
          appTitle: getIn(state, ["config", "theme", "title"]),
          loggedIn: accountUtils.isLoggedIn(accountState),
          isAnonymous: accountUtils.isAnonymous(accountState),
          isSignUpView: currentRoute === "signup",
          showLoadingIndicator: isLoading(state),
          showSlideInIndicator:
            viewSelectors.hasSlideIns(state) &&
            !viewSelectors.showSlideIns(state),
        };
      };

      connect2Redux(selectFromState, actionCreators, ["self.pageTitle"], this);
    }
  }
  Controller.$inject = serviceDependencies;

  return {
    restrict: "E",
    scope: {
      pageTitle: "=",
    }, //isolate scope to allow usage within other controllers/components
    controller: Controller,
    controllerAs: "self",
    bindToController: true, //scope-bindings -> ctrl
    template: template,
  };
}

export default angular
  .module("won.owner.components.topnav", [
    dropdownModule,
    accountMenuModule,
    ngAnimate,
  ])
  .directive("wonTopnav", genTopnavConf).name;
<|endoftext|>


<commit_before>/*******************************************************************************
 * Copyright 2012 University of Southern California
 *
 * 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.
 *
 * This code was developed by the Information Integration Group as part
 * of the Karma project at the Information Sciences Institute of the
 * University of Southern California.  For more information, publications,
 * and related projects, please see: http://www.isi.edu/integration
 ******************************************************************************/
function handleTableCellEditButton(event) {
	var tableCellDiv = $("div#tableCellEditDiv");
	var tdTagId = $("div#tableCellToolBarMenu").data("parentCellId");
	var tdTag = $("td#"+tdTagId);
	$("#editCellTextArea", tableCellDiv).remove();

	if(tdTag.hasClass("hasTruncatedValue")) {
		tableCellDiv.append($("<textarea>")
						.attr("id", "editCellTextArea")
						.text(tdTag.data("fullValue")));
	} else {
		tableCellDiv.append($("<textarea>")
						.attr("id", "editCellTextArea")
						.text($("#"+tdTagId + " span.cellValue").text()));
	}

	var positionArray = [event.clientX-150		// distance from left
					, event.clientY-10];	// distance from top

	tableCellDiv.dialog({ title: 'Edit Cell Value',
			buttons: { "Cancel": function() { $(this).dialog("close"); }, "Submit":submitEdit }, width: 300, height: 150, position: positionArray});
	tableCellDiv.data("tdTagId", tdTagId);
}

function submitEdit(value, settings) {
	$("#tableCellEditDiv").dialog("close");
	var edits = new Object();
	// console.log($("#tableCellEditDiv").data("tdTagId"));
	var tdTag = $("#" + $("#tableCellEditDiv").data("tdTagId"));

	edits["value"] = $("#editCellTextArea").val();
	edits["command"] = "EditCellCommand";
	edits["nodeId"] = $(tdTag).attr("id");
	edits["vWorksheetId"] = $(tdTag).parents(".Worksheet").attr("id");

	edits["workspaceId"] = $.workspaceGlobalInformation.id;

	var returned = $.ajax({
	   	url: "RequestController",
	   	type: "POST",
	   	data : edits,
	   	dataType : "json",
	   	complete :
	   		function (xhr, textStatus) {
	    		var json = $.parseJSON(xhr.responseText);
	    		parse(json);
		   	}
		});
 }

function openAddNewColumnDialog(event) {
    var columnHeadingMenu = $("div#columnHeadingDropDownMenu");
    var hNodeId = columnHeadingMenu.data("parentCellId");
    $("#addNewColumnNameInput").val("");
    $("#addNewColumnDefaultValueInput").val("");
    $("div#addNewColumnDialogDiv span.error").hide();

    var addNewColumnDiv = $("div#addNewColumnDialogDiv");
    var positionArray = [event.clientX-100		// distance from left
        , event.clientY-10];	// distance from top
    addNewColumnDiv.dialog({ title: 'Add new column',
        buttons: { "Cancel": function() { $(this).dialog("close"); }, "Submit":submitAddNewColumn },
        width: 300,
        height: 150,
        position: positionArray
    });
}

function submitAddNewColumn() {
    var columnHeadingMenu = $("div#columnHeadingDropDownMenu");
    var selectedHNodeId = columnHeadingMenu.data("parentCellId");
    var worksheetId = $("td#" + selectedHNodeId).parents("table.WorksheetTable").attr("id");
    var newColumnValue = $.trim($("#addNewColumnNameInput").val());
    var defaultValue = $.trim($("#addNewColumnDefaultValueInput").val());

    var validationResult = true;
    if (!newColumnValue)
        validationResult = false;
    // Check if the column name already exists
    var columnNameDivs = $("#" + worksheetId + " div.ColumnHeadingNameDiv");
    $.each(columnNameDivs, function(index, element) {
        if ($.trim($(element).text()) == newColumnValue) {
            validationResult = false;
        }
    });
    if (!validationResult) {
        $("div#addNewColumnDialogDiv span.error").show();
        $("#addNewColumnNameInput").focus();
        return false;
    }

    $("div#addNewColumnDialogDiv").dialog("close");

    var info = new Object();
    info["vWorksheetId"] = $("td#" + selectedHNodeId).parents("table.WorksheetTable").attr("id");
    info["workspaceId"] = $.workspaceGlobalInformation.id;
    info["hNodeId"] = selectedHNodeId
    info["hTableId"] = ""
    info["newColumnName"] = "new_column"
    info["command"] = "AddColumnCommand";

    var newInfo = [];	// Used for commands that take JSONArray as input
    newInfo.push(getParamObject("hNodeId", selectedHNodeId,"hNodeId"));
    newInfo.push(getParamObject("hTableId", "","other"));
    newInfo.push(getParamObject("vWorksheetId", $("td#" + selectedHNodeId).parents("table.WorksheetTable").attr("id"),"vWorksheetId"));
    newInfo.push(getParamObject("newColumnName", newColumnValue,"other"));
    newInfo.push(getParamObject("defaultValue", defaultValue,"other"));
    info["newInfo"] = JSON.stringify(newInfo);

    //console.log(info["vWorksheetId"]);
    showLoading(info["vWorksheetId"]);

    var returned = $.ajax({
        url: "RequestController",
        type: "POST",
        data : info,
        dataType : "json",
        complete :
            function (xhr, textStatus) {
                //alert(xhr.responseText);
                var json = $.parseJSON(xhr.responseText);
                parse(json);
                hideLoading(info["vWorksheetId"]);
            },
        error :
            function (xhr, textStatus) {
                alert("Error occured while removing semantic types!" + textStatus);
                hideLoading(info["vWorksheetId"]);
            }
    });
}

function assignHandlersToRenameButton(event) {
    var columnHeadingMenu = $("div#columnHeadingDropDownMenu");
    var hNodeId = columnHeadingMenu.data("parentCellId");

    $("#renameColumnNameInput").val($("td#" + hNodeId + " div.ColumnHeadingNameDiv").text());
    var renameColumnDiv = $("div#renameColumnDiv");
    var positionArray = [event.clientX-100		// distance from left
        , event.clientY-10];	// distance from top
    renameColumnDiv.dialog({ title: 'Rename column',
        buttons: { "Cancel": function() { $(this).dialog("close"); }, "Submit":submitRenameColumn }, width: 180, height: 180, position: positionArray});
}

function submitRenameColumn(value, settings) {
    var newColumnValue = $.trim($("#renameColumnNameInput").val());
    if (!newColumnValue) {
        $("div#renameColumnDiv span.error").show();
        return false;
    }

    $("div#renameColumnDiv").dialog("close");

    var columnHeadingMenu = $("div#columnHeadingDropDownMenu");
    var hNodeId = columnHeadingMenu.data("parentCellId");
    var vWorksheetId = $("td#" + hNodeId).parents("table.WorksheetTable").attr("id");

    var info = new Object();
    var newInfo = [];   // for input parameters
    newInfo.push(getParamObject("vWorksheetId", vWorksheetId ,"vWorksheetId"));
    newInfo.push(getParamObject("hNodeId", hNodeId,"hNodeId"));
    newInfo.push(getParamObject("newColumnName", newColumnValue, "other"));
    newInfo.push(getParamObject("getAlignmentUpdate", ($("#svgDiv_" + vWorksheetId).length >0), "other"));
    info["newInfo"] = JSON.stringify(newInfo);
    info["workspaceId"] = $.workspaceGlobalInformation.id;
    info["command"] = "RenameColumnCommand";

    var returned = $.ajax({
        url: "RequestController",
        type: "POST",
        data : info,
        dataType : "json",
        complete :
            function (xhr, textStatus) {
                var json = $.parseJSON(xhr.responseText);
                parse(json);
            },
        error :
            function (xhr, textStatus) {
                $.sticky("Error occured while renaming column!");
            }
    });
}

function handlePublishModelToStoreButton(event) {
	var tableCellDiv = $("div#r2rmlModelNameDiv");
	var positionArray = [event.clientX-150		// distance from left
					, event.clientY-10];	// distance from top
	$('#txtR2RMLModelName').val('');

	var r2rmlDialogBox = $("div#PublishR2RMLModelDialogBox");
	 $('#txtR2RML_ID').val('');
	 $('#txtR2RML_URL').val('http://'+window.location.host + '/triplestore/repositories/dim_repo');
	// Show the dialog box
	r2rmlDialogBox.dialog({width: 300
		, buttons: { "Cancel": function() { $(this).dialog("close"); }, "Submit": submitModelName }});

	/*
	tableCellDiv.dialog({ title: 'R2RML Model Name',
			buttons: { "Cancel": function() { $(this).dialog("close"); }, "Submit":submitModelName }, width: 300, height: 150, position: positionArray});
		*/
}

function submitModelName(value, settings) {
	$("div#PublishR2RMLModelDialogBox").dialog("close");

	var info = new Object();
	info["vWorksheetId"] = $("div#WorksheetOptionsDiv").data("worksheetId");
	info["workspaceId"] = $.workspaceGlobalInformation.id;
	info["command"] = "GenerateR2RMLModelCommand";
	info['modelName'] = $('#txtR2RML_ID').val();
	info['tripleStoreUrl'] = $('#txtR2RML_URL').val();

    showLoading(info["vWorksheetId"]);
    var returned = $.ajax({
        url: "RequestController",
        type: "POST",
        data : info,
        dataType : "json",
        complete :
            function (xhr, textStatus) {
                //alert(xhr.responseText);
                var json = $.parseJSON(xhr.responseText);
                parse(json);
                hideLoading(info["vWorksheetId"]);
            },
        error :
            function (xhr, textStatus) {
                alert("Error occured while exporting CSV!" + textStatus);
                hideLoading(info["vWorksheetId"]);
            }
    });
 }

function submitSelectedModelNameToBeLoaded() {
	$('div#modelListDiv').dialog("close");
	var optionsDiv = $("div#WorksheetOptionsDiv");

	var value = $("#modelListRadioBtnGrp").find("input:checked");
    var returned = $.ajax({
		url: "RequestController?workspaceId=" + $.workspaceGlobalInformation.id +
		"&command=ApplyR2RMLModelCommand&vWorksheetId="+optionsDiv.data("worksheetId") + '&modelName='+value.val(),
		type: "POST",
//		data : '',
		dataType : "json",
		complete :
			function (xhr, textStatus) {
			var json = $.parseJSON(xhr.responseText);
			parse(json);
		},
		error :
			function (xhr, textStatus) {
			alert("Error occured while applying model from Triple Store!" + textStatus);
		}
	});
 }<commit_msg>removed the r2rml identier for js<commit_after>/*******************************************************************************
 * Copyright 2012 University of Southern California
 *
 * 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.
 *
 * This code was developed by the Information Integration Group as part
 * of the Karma project at the Information Sciences Institute of the
 * University of Southern California.  For more information, publications,
 * and related projects, please see: http://www.isi.edu/integration
 ******************************************************************************/
function handleTableCellEditButton(event) {
	var tableCellDiv = $("div#tableCellEditDiv");
	var tdTagId = $("div#tableCellToolBarMenu").data("parentCellId");
	var tdTag = $("td#"+tdTagId);
	$("#editCellTextArea", tableCellDiv).remove();

	if(tdTag.hasClass("hasTruncatedValue")) {
		tableCellDiv.append($("<textarea>")
						.attr("id", "editCellTextArea")
						.text(tdTag.data("fullValue")));
	} else {
		tableCellDiv.append($("<textarea>")
						.attr("id", "editCellTextArea")
						.text($("#"+tdTagId + " span.cellValue").text()));
	}

	var positionArray = [event.clientX-150		// distance from left
					, event.clientY-10];	// distance from top

	tableCellDiv.dialog({ title: 'Edit Cell Value',
			buttons: { "Cancel": function() { $(this).dialog("close"); }, "Submit":submitEdit }, width: 300, height: 150, position: positionArray});
	tableCellDiv.data("tdTagId", tdTagId);
}

function submitEdit(value, settings) {
	$("#tableCellEditDiv").dialog("close");
	var edits = new Object();
	// console.log($("#tableCellEditDiv").data("tdTagId"));
	var tdTag = $("#" + $("#tableCellEditDiv").data("tdTagId"));

	edits["value"] = $("#editCellTextArea").val();
	edits["command"] = "EditCellCommand";
	edits["nodeId"] = $(tdTag).attr("id");
	edits["vWorksheetId"] = $(tdTag).parents(".Worksheet").attr("id");

	edits["workspaceId"] = $.workspaceGlobalInformation.id;

	var returned = $.ajax({
	   	url: "RequestController",
	   	type: "POST",
	   	data : edits,
	   	dataType : "json",
	   	complete :
	   		function (xhr, textStatus) {
	    		var json = $.parseJSON(xhr.responseText);
	    		parse(json);
		   	}
		});
 }

function openAddNewColumnDialog(event) {
    var columnHeadingMenu = $("div#columnHeadingDropDownMenu");
    var hNodeId = columnHeadingMenu.data("parentCellId");
    $("#addNewColumnNameInput").val("");
    $("#addNewColumnDefaultValueInput").val("");
    $("div#addNewColumnDialogDiv span.error").hide();

    var addNewColumnDiv = $("div#addNewColumnDialogDiv");
    var positionArray = [event.clientX-100		// distance from left
        , event.clientY-10];	// distance from top
    addNewColumnDiv.dialog({ title: 'Add new column',
        buttons: { "Cancel": function() { $(this).dialog("close"); }, "Submit":submitAddNewColumn },
        width: 300,
        height: 150,
        position: positionArray
    });
}

function submitAddNewColumn() {
    var columnHeadingMenu = $("div#columnHeadingDropDownMenu");
    var selectedHNodeId = columnHeadingMenu.data("parentCellId");
    var worksheetId = $("td#" + selectedHNodeId).parents("table.WorksheetTable").attr("id");
    var newColumnValue = $.trim($("#addNewColumnNameInput").val());
    var defaultValue = $.trim($("#addNewColumnDefaultValueInput").val());

    var validationResult = true;
    if (!newColumnValue)
        validationResult = false;
    // Check if the column name already exists
    var columnNameDivs = $("#" + worksheetId + " div.ColumnHeadingNameDiv");
    $.each(columnNameDivs, function(index, element) {
        if ($.trim($(element).text()) == newColumnValue) {
            validationResult = false;
        }
    });
    if (!validationResult) {
        $("div#addNewColumnDialogDiv span.error").show();
        $("#addNewColumnNameInput").focus();
        return false;
    }

    $("div#addNewColumnDialogDiv").dialog("close");

    var info = new Object();
    info["vWorksheetId"] = $("td#" + selectedHNodeId).parents("table.WorksheetTable").attr("id");
    info["workspaceId"] = $.workspaceGlobalInformation.id;
    info["hNodeId"] = selectedHNodeId
    info["hTableId"] = ""
    info["newColumnName"] = "new_column"
    info["command"] = "AddColumnCommand";

    var newInfo = [];	// Used for commands that take JSONArray as input
    newInfo.push(getParamObject("hNodeId", selectedHNodeId,"hNodeId"));
    newInfo.push(getParamObject("hTableId", "","other"));
    newInfo.push(getParamObject("vWorksheetId", $("td#" + selectedHNodeId).parents("table.WorksheetTable").attr("id"),"vWorksheetId"));
    newInfo.push(getParamObject("newColumnName", newColumnValue,"other"));
    newInfo.push(getParamObject("defaultValue", defaultValue,"other"));
    info["newInfo"] = JSON.stringify(newInfo);

    //console.log(info["vWorksheetId"]);
    showLoading(info["vWorksheetId"]);

    var returned = $.ajax({
        url: "RequestController",
        type: "POST",
        data : info,
        dataType : "json",
        complete :
            function (xhr, textStatus) {
                //alert(xhr.responseText);
                var json = $.parseJSON(xhr.responseText);
                parse(json);
                hideLoading(info["vWorksheetId"]);
            },
        error :
            function (xhr, textStatus) {
                alert("Error occured while removing semantic types!" + textStatus);
                hideLoading(info["vWorksheetId"]);
            }
    });
}

function assignHandlersToRenameButton(event) {
    var columnHeadingMenu = $("div#columnHeadingDropDownMenu");
    var hNodeId = columnHeadingMenu.data("parentCellId");

    $("#renameColumnNameInput").val($("td#" + hNodeId + " div.ColumnHeadingNameDiv").text());
    var renameColumnDiv = $("div#renameColumnDiv");
    var positionArray = [event.clientX-100		// distance from left
        , event.clientY-10];	// distance from top
    renameColumnDiv.dialog({ title: 'Rename column',
        buttons: { "Cancel": function() { $(this).dialog("close"); }, "Submit":submitRenameColumn }, width: 180, height: 180, position: positionArray});
}

function submitRenameColumn(value, settings) {
    var newColumnValue = $.trim($("#renameColumnNameInput").val());
    if (!newColumnValue) {
        $("div#renameColumnDiv span.error").show();
        return false;
    }

    $("div#renameColumnDiv").dialog("close");

    var columnHeadingMenu = $("div#columnHeadingDropDownMenu");
    var hNodeId = columnHeadingMenu.data("parentCellId");
    var vWorksheetId = $("td#" + hNodeId).parents("table.WorksheetTable").attr("id");

    var info = new Object();
    var newInfo = [];   // for input parameters
    newInfo.push(getParamObject("vWorksheetId", vWorksheetId ,"vWorksheetId"));
    newInfo.push(getParamObject("hNodeId", hNodeId,"hNodeId"));
    newInfo.push(getParamObject("newColumnName", newColumnValue, "other"));
    newInfo.push(getParamObject("getAlignmentUpdate", ($("#svgDiv_" + vWorksheetId).length >0), "other"));
    info["newInfo"] = JSON.stringify(newInfo);
    info["workspaceId"] = $.workspaceGlobalInformation.id;
    info["command"] = "RenameColumnCommand";

    var returned = $.ajax({
        url: "RequestController",
        type: "POST",
        data : info,
        dataType : "json",
        complete :
            function (xhr, textStatus) {
                var json = $.parseJSON(xhr.responseText);
                parse(json);
            },
        error :
            function (xhr, textStatus) {
                $.sticky("Error occured while renaming column!");
            }
    });
}

function handlePublishModelToStoreButton(event) {
	var tableCellDiv = $("div#r2rmlModelNameDiv");
	var positionArray = [event.clientX-150		// distance from left
					, event.clientY-10];	// distance from top
	$('#txtR2RMLModelName').val('');

	var r2rmlDialogBox = $("div#PublishR2RMLModelDialogBox");
	 $('#txtR2RML_URL').val('http://'+window.location.host + '/openrdf-sesame/repositories/dim_repo');
	// Show the dialog box
	r2rmlDialogBox.dialog({
		width: 400,
		buttons: { "Cancel": function() { $(this).dialog("close"); }, "Submit": submitModelName },
		resize: function(event, ui) {
		}

	});
	/*
	tableCellDiv.dialog({ title: 'R2RML Model Name',
			buttons: { "Cancel": function() { $(this).dialog("close"); }, "Submit":submitModelName }, width: 300, height: 150, position: positionArray});
		*/
}

function submitModelName(value, settings) {
	$("div#PublishR2RMLModelDialogBox").dialog("close");

	var info = new Object();
	info["vWorksheetId"] = $("div#WorksheetOptionsDiv").data("worksheetId");
	info["workspaceId"] = $.workspaceGlobalInformation.id;
	info["command"] = "GenerateR2RMLModelCommand";
	info['tripleStoreUrl'] = $('#txtR2RML_URL').val();

    showLoading(info["vWorksheetId"]);
    var returned = $.ajax({
        url: "RequestController",
        type: "POST",
        data : info,
        dataType : "json",
        complete :
            function (xhr, textStatus) {
                //alert(xhr.responseText);
                var json = $.parseJSON(xhr.responseText);
                parse(json);
                hideLoading(info["vWorksheetId"]);
            },
        error :
            function (xhr, textStatus) {
                alert("Error occured while exporting CSV!" + textStatus);
                hideLoading(info["vWorksheetId"]);
            }
    });
 }

function submitSelectedModelNameToBeLoaded() {
	$('div#modelListDiv').dialog("close");
	var optionsDiv = $("div#WorksheetOptionsDiv");

	var value = $("#modelListRadioBtnGrp").find("input:checked");
    var returned = $.ajax({
		url: "RequestController?workspaceId=" + $.workspaceGlobalInformation.id +
		"&command=ApplyR2RMLModelCommand&vWorksheetId="+optionsDiv.data("worksheetId") + '&modelName='+value.val(),
		type: "POST",
//		data : '',
		dataType : "json",
		complete :
			function (xhr, textStatus) {
			var json = $.parseJSON(xhr.responseText);
			parse(json);
		},
		error :
			function (xhr, textStatus) {
			alert("Error occured while applying model from Triple Store!" + textStatus);
		}
	});
 }<|endoftext|>


<commit_before><commit_msg>Refix TextEvalInput<commit_after><|endoftext|>


<commit_before>/* jslint browser: true */
/*global define*/
define([
	'utils/logger',
	'ol',
	'underscore',
	'views/BaseView',
	'utils/mapUtils',
	'utils/spatialUtils',
	'olLayerSwitcher'
], function (log, ol, _, BaseView, mapUtils, spatialUtils) {

	"use strict";
	var view = BaseView.extend({
		/**
		 * Renders the map.
		 * @returns {extended Backbone.View}
		 */
		render: function () {
			this.map.setTarget(this.mapDivId);
			this.listenTo(this.collection, 'update', function(collection) {
				this.updateRegionExtent(collection);
			}, this);

			this.updateRegionExtent(this.collection);

			$('#' + this.mapDivId).append('
Loading model ...
');
			if (!this.predictionModel.geoserverEndpoint) {
				$('#map-loading-div').show();
			}
			return this;
		},

		/*
		 * Gets the extent of the region of the model.
		 * @param {ModelCollection} collection
		 */
		updateRegionExtent : function(collection) {
			var metadata = collection.getModel(this.modelId);
			var regionId = '';

			if (metadata) {
				regionId = metadata.attributes.regionId;
			}
			spatialUtils.getRegionExtent(regionId, this).done(function(extent) {
				this.map.getView().fit(extent, this.map.getSize());
			});
		},
		/*
		 * @constructs
		 * @param {Object} options
		 *      @prop {String} mapDivId - Id of the div where the map will be rendered.
		 *      @prop {Boolean} enableZoom - Optional, set to false if the zoom control should be removed. Deafult is true
		 *      @prop {String} modelId
		 *      @prop {ModelCollection} collection
		 *      @prop {MapFilterModel} model
		 *      @prop {PredictionModel} predictionModel
		 */
		initialize: function (options) {
			this.mapDivId = options.mapDivId;
			this.modelId = options.modelId;

			// This model handles fetching the layer names and styles.
			this.predictionModel = options.predictionModel;

			this.listenTo(this.model, 'change:dataSeries', this.updatePredictionModel);
			this.listenTo(this.model, "change:state change:waterBody change:waterShed change:waterSheds", this.updateModelLayer);
			this.listenTo(this.collection, 'update', this.updateModelLayer);

			this.flowlineLayer = new ol.layer.Tile({
				title: 'Flowline',
				opacity: 1
			});
			this.catchmentLayer = new ol.layer.Tile({
				title: 'Catchment',
				opacity: 0.75
			});

			this.updatePredictionModel();

			this.map = new ol.Map({
				view: new ol.View({
					center: ol.extent.getCenter(mapUtils.CONUS_EXTENT),
					zoom: 4,
					minZoom: 3
				}),
				layers: [
					new ol.layer.Group({
						title: 'Base maps',
						layers: [
							mapUtils.createStamenTonerBaseLayer(true),
							mapUtils.createWorldTopoBaseLayer(false),
							mapUtils.createWorldImageryLayer(false),
							mapUtils.createWorldStreetMapBaseLayer(false)
						]
					}),
					new ol.layer.Group({
						title: 'Model layers',
						layers: [this.catchmentLayer, this.flowlineLayer]
					})
				],
				controls: ol.control.defaults().extend([
					new ol.control.ScaleLine(),
					new ol.control.LayerSwitcher({
						tipLabel: 'Switch base layers'
					})
				])
			});

			BaseView.prototype.initialize.apply(this, arguments);
			log.debug('ModelMapView initialized');
		},

		/*
		 * Fetch the prediction model and then update the model layer
		 */
		updatePredictionModel : function() {
			//NOTE: Don't put #map-loading-div jquery element in a variable. The view may not be
			// rendered when this is called but may be when the fetch is complete
			var self = this;

			$('#map-loading-div').show();
			this.predictionModel.fetch({data : {
				'model-id' : this.modelId,
				'data-series' : this.model.get('dataSeries')
			}}).done(function() {
				log.debug('Updated predictionModel');
				self.updateModelLayer();
			}).fail(function(){
				log.debug('Unable to retrieve predictionModel');
				alert('Unable to retrieve predictionModel');
			}).always(function() {
				$('#map-loading-div').hide();
			});
		},

		/*
		 * Update the flowline and catchment source's using the current contents of the
		 * predictionModel and map filter model (model).
		 */
		updateModelLayer: function () {
			var thisModel = this.collection.getModel(this.modelId);
			var regionId = (thisModel) ? thisModel.attributes.regionId : '';
			var geoserverEndpoint = this.predictionModel.get('geoserverEndpoint');

			var flowlineSource = new ol.source.TileWMS({
				serverType: 'geoserver',
				params: {
					LAYERS: this.predictionModel.get('flowlineLayerName'),
					VERSION: "1.1.1"
				},
				url: geoserverEndpoint
			});
			var catchmentSource = new ol.source.TileWMS({
				serverType: 'geoserver',
				params: {
					LAYERS: this.predictionModel.get('catchmentLayerName'),
					VERSION: "1.1.1"
				},
				url: geoserverEndpoint
			});

			// If there are states used, update the WMS request to include filtering
			if (this.model.get("state").length > 0) {
				_.each([flowlineSource, catchmentSource], function (src) {
					var stateFilter = _.map(this, function (state) {
						return "STATE_ABBR = ''" + state + "''";
					}).join(" OR ");

					src.updateParams({
						CQL_FILTER: "WITHIN(the_geom, collectGeometries(queryCollection('reference:states','the_geom','" + stateFilter + "')))"
					});
				}, this.model.get("state"));
			};

			// If there are watershed filters, update the WMS request to include filtering.
			if (this.model.get("waterShed") && (regionId)) {
				var waterShed = this.model.get("waterShed");
				var waterSheds = _.filter(this.model.get("waterSheds"), function (ws) {
					return ws.startsWith(this);
				}, waterShed);

				_.each([flowlineSource, catchmentSource], function (src) {

					var watershedFilter = "HUC8 LIKE ''" + waterShed + "%''";

					var params = src.getParams();
					if (params.CQL_FILTER) {
						params.CQL_FILTER = " AND ";
					} else {
						params.CQL_FILTER = "";
					}

					src.updateParams({
						CQL_FILTER: params.CQL_FILTER +"WITHIN(the_geom, collectGeometries(queryCollection('huc8-simplified-overlay:" + regionId + "','the_geom','" + watershedFilter + "')))"
					});
				}, waterSheds);
			}

			// Update the sources for flowline and catchment layers.
			this.flowlineLayer.setSource(flowlineSource);
			this.catchmentLayer.setSource(catchmentSource);
		},

		remove: function () {
			this.map.setTarget(null); // Needed to clean up ol 3 map.
			BaseView.prototype.remove.apply(this, arguments);
			return this;
		}
	});

	return view;
});

<commit_msg>Fix to allow combination  waterShed and state filters<commit_after>/* jslint browser: true */
/*global define*/
define([
	'utils/logger',
	'ol',
	'underscore',
	'views/BaseView',
	'utils/mapUtils',
	'utils/spatialUtils',
	'olLayerSwitcher'
], function (log, ol, _, BaseView, mapUtils, spatialUtils) {

	"use strict";
	var view = BaseView.extend({
		/**
		 * Renders the map.
		 * @returns {extended Backbone.View}
		 */
		render: function () {
			this.map.setTarget(this.mapDivId);
			this.listenTo(this.collection, 'update', function(collection) {
				this.updateRegionExtent(collection);
			}, this);

			this.updateRegionExtent(this.collection);

			$('#' + this.mapDivId).append('
Loading model ...
');
			if (!this.predictionModel.geoserverEndpoint) {
				$('#map-loading-div').show();
			}
			return this;
		},

		/*
		 * Gets the extent of the region of the model.
		 * @param {ModelCollection} collection
		 */
		updateRegionExtent : function(collection) {
			var metadata = collection.getModel(this.modelId);
			var regionId = '';

			if (metadata) {
				regionId = metadata.attributes.regionId;
			}
			spatialUtils.getRegionExtent(regionId, this).done(function(extent) {
				this.map.getView().fit(extent, this.map.getSize());
			});
		},
		/*
		 * @constructs
		 * @param {Object} options
		 *      @prop {String} mapDivId - Id of the div where the map will be rendered.
		 *      @prop {Boolean} enableZoom - Optional, set to false if the zoom control should be removed. Deafult is true
		 *      @prop {String} modelId
		 *      @prop {ModelCollection} collection
		 *      @prop {MapFilterModel} model
		 *      @prop {PredictionModel} predictionModel
		 */
		initialize: function (options) {
			this.mapDivId = options.mapDivId;
			this.modelId = options.modelId;

			// This model handles fetching the layer names and styles.
			this.predictionModel = options.predictionModel;

			this.listenTo(this.model, 'change:dataSeries', this.updatePredictionModel);
			this.listenTo(this.model, "change:state change:waterBody change:waterShed change:waterSheds", this.updateModelLayer);
			this.listenTo(this.collection, 'update', this.updateModelLayer);

			this.flowlineLayer = new ol.layer.Tile({
				title: 'Flowline',
				opacity: 1
			});
			this.catchmentLayer = new ol.layer.Tile({
				title: 'Catchment',
				opacity: 0.75
			});

			this.updatePredictionModel();

			this.map = new ol.Map({
				view: new ol.View({
					center: ol.extent.getCenter(mapUtils.CONUS_EXTENT),
					zoom: 4,
					minZoom: 3
				}),
				layers: [
					new ol.layer.Group({
						title: 'Base maps',
						layers: [
							mapUtils.createStamenTonerBaseLayer(true),
							mapUtils.createWorldTopoBaseLayer(false),
							mapUtils.createWorldImageryLayer(false),
							mapUtils.createWorldStreetMapBaseLayer(false)
						]
					}),
					new ol.layer.Group({
						title: 'Model layers',
						layers: [this.catchmentLayer, this.flowlineLayer]
					})
				],
				controls: ol.control.defaults().extend([
					new ol.control.ScaleLine(),
					new ol.control.LayerSwitcher({
						tipLabel: 'Switch base layers'
					})
				])
			});

			BaseView.prototype.initialize.apply(this, arguments);
			log.debug('ModelMapView initialized');
		},

		/*
		 * Fetch the prediction model and then update the model layer
		 */
		updatePredictionModel : function() {
			//NOTE: Don't put #map-loading-div jquery element in a variable. The view may not be
			// rendered when this is called but may be when the fetch is complete
			var self = this;

			$('#map-loading-div').show();
			this.predictionModel.fetch({data : {
				'model-id' : this.modelId,
				'data-series' : this.model.get('dataSeries')
			}}).done(function() {
				log.debug('Updated predictionModel');
				self.updateModelLayer();
			}).fail(function(){
				log.debug('Unable to retrieve predictionModel');
				alert('Unable to retrieve predictionModel');
			}).always(function() {
				$('#map-loading-div').hide();
			});
		},

		/*
		 * Update the flowline and catchment source's using the current contents of the
		 * predictionModel and map filter model (model).
		 */
		updateModelLayer: function () {
			var thisModel = this.collection.getModel(this.modelId);
			var regionId = (thisModel) ? thisModel.attributes.regionId : '';
			var geoserverEndpoint = this.predictionModel.get('geoserverEndpoint');

			var flowlineSource = new ol.source.TileWMS({
				serverType: 'geoserver',
				params: {
					LAYERS: this.predictionModel.get('flowlineLayerName'),
					VERSION: "1.1.1"
				},
				url: geoserverEndpoint
			});
			var catchmentSource = new ol.source.TileWMS({
				serverType: 'geoserver',
				params: {
					LAYERS: this.predictionModel.get('catchmentLayerName'),
					VERSION: "1.1.1"
				},
				url: geoserverEndpoint
			});

			// If there are states used, update the WMS request to include filtering
			if (this.model.get("state").length > 0) {
				_.each([flowlineSource, catchmentSource], function (src) {
					var stateFilter = _.map(this, function (state) {
						return "STATE_ABBR = ''" + state + "''";
					}).join(" OR ");

					src.updateParams({
						CQL_FILTER: "WITHIN(the_geom, collectGeometries(queryCollection('reference:states','the_geom','" + stateFilter + "')))"
					});
				}, this.model.get("state"));
			};

			// If there are watershed filters, update the WMS request to include filtering.
			if (this.model.get("waterShed") && (regionId)) {
				var waterShed = this.model.get("waterShed");
				var waterSheds = _.filter(this.model.get("waterSheds"), function (ws) {
					return ws.startsWith(this);
				}, waterShed);

				_.each([flowlineSource, catchmentSource], function (src) {

					var watershedFilter = "HUC8 LIKE ''" + waterShed + "%''";

					var params = src.getParams();
					if (params.CQL_FILTER) {
						params.CQL_FILTER += " AND ";
					} else {
						params.CQL_FILTER = "";
					}

					src.updateParams({
						CQL_FILTER: params.CQL_FILTER +"WITHIN(the_geom, collectGeometries(queryCollection('huc8-simplified-overlay:" + regionId + "','the_geom','" + watershedFilter + "')))"
					});
				}, waterSheds);
			}

			// Update the sources for flowline and catchment layers.
			this.flowlineLayer.setSource(flowlineSource);
			this.catchmentLayer.setSource(catchmentSource);
		},

		remove: function () {
			this.map.setTarget(null); // Needed to clean up ol 3 map.
			BaseView.prototype.remove.apply(this, arguments);
			return this;
		}
	});

	return view;
});

<|endoftext|>


<commit_before>/**
 * @license
 * Copyright The Closure Library Authors.
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @fileoverview A simple, sample component.
 */
goog.provide('goog.demos.SampleComponent');

goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.dom.classlist');
goog.require('goog.events.EventType');
goog.require('goog.events.KeyCodes');
goog.require('goog.events.KeyHandler');
goog.require('goog.ui.Component');
goog.requireType('goog.events.Event');

/**
 * A simple box that changes colour when clicked. This class demonstrates the
 * goog.ui.Component API, and is keyboard accessible, as per
 * http://wiki/Main/ClosureKeyboardAccessible
 * @final
 * @unrestricted
 */
goog.demos.SampleComponent = class extends goog.ui.Component {
  /**
   * @param {string=} opt_label A label to display. Defaults to "Click Me" if
   *     none provided.
   * @param {goog.dom.DomHelper=} opt_domHelper DOM helper to use.
   */
  constructor(opt_label, opt_domHelper) {
    super(opt_domHelper);

    /**
     * The label to display.
     * @type {string}
     * @private
     */
    this.initialLabel_ = opt_label || 'Click Me';

    /**
     * The current color.
     * @type {string}
     * @private
     */
    this.color_ = 'red';

    /**
     * Keyboard handler for this object. This object is created once the
     * component's DOM element is known.
     *
     * @type {goog.events.KeyHandler?}
     * @private
     */
    this.kh_ = null;
  }

  /**
   * Changes the color of the element.
   * @private
   */
  changeColor_() {
    if (this.color_ == 'red') {
      this.color_ = 'green';
    } else if (this.color_ == 'green') {
      this.color_ = 'blue';
    } else {
      this.color_ = 'red';
    }
    this.getElement().style.backgroundColor = this.color_;
  }

  /**
   * Creates an initial DOM representation for the component.
   * @override
   */
  createDom() {
    this.decorateInternal(this.dom_.createElement(goog.dom.TagName.DIV));
  }

  /**
   * Decorates an existing HTML DIV element as a SampleComponent.
   *
   * @param {Element} element The DIV element to decorate. The element's
   *    text, if any will be used as the component's label.
   * @override
   */
  decorateInternal(element) {
    super.decorateInternal(element);
    if (!this.getLabelText()) {
      this.setLabelText(this.initialLabel_);
    }

    var elem = this.getElement();
    goog.dom.classlist.add(elem, goog.getCssName('goog-sample-component'));
    elem.style.backgroundColor = this.color_;
    elem.tabIndex = 0;

    this.kh_ = new goog.events.KeyHandler(elem);
    this.getHandler().listen(
        this.kh_, goog.events.KeyHandler.EventType.KEY, this.onKey_);
  }

  /** @override */
  disposeInternal() {
    super.disposeInternal();
    if (this.kh_) {
      this.kh_.dispose();
    }
  }

  /**
   * Called when component's element is known to be in the document.
   * @override
   */
  enterDocument() {
    super.enterDocument();
    this.getHandler().listen(
        this.getElement(), goog.events.EventType.CLICK, this.onDivClicked_);
  }

  /**
   * Gets the current label text.
   *
   * @return {string} The current text set into the label, or empty string if
   *     none set.
   */
  getLabelText() {
    if (!this.getElement()) {
      return '';
    }
    return goog.dom.getTextContent(this.getElement());
  }

  /**
   * Handles DIV element clicks, causing the DIV's colour to change.
   * @param {goog.events.Event} event The click event.
   * @private
   */
  onDivClicked_(event) {
    this.changeColor_();
  }

  /**
   * Fired when user presses a key while the DIV has focus. If the user presses
   * space or enter, the color will be changed.
   * @param {goog.events.Event} event The key event.
   * @private
   */
  onKey_(event) {
    var keyCodes = goog.events.KeyCodes;
    if (event.keyCode == keyCodes.SPACE || event.keyCode == keyCodes.ENTER) {
      this.changeColor_();
    }
  }

  /**
   * Sets the current label text. Has no effect if component is not rendered.
   *
   * @param {string} text The text to set as the label.
   */
  setLabelText(text) {
    if (this.getElement()) {
      goog.dom.setTextContent(this.getElement(), text);
    }
  }
};
<commit_msg>Use ES6 const/let more throughout Closure Library. RELNOTES: n/a<commit_after>/**
 * @license
 * Copyright The Closure Library Authors.
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @fileoverview A simple, sample component.
 */
goog.provide('goog.demos.SampleComponent');

goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.dom.classlist');
goog.require('goog.events.EventType');
goog.require('goog.events.KeyCodes');
goog.require('goog.events.KeyHandler');
goog.require('goog.ui.Component');
goog.requireType('goog.events.Event');

/**
 * A simple box that changes colour when clicked. This class demonstrates the
 * goog.ui.Component API, and is keyboard accessible, as per
 * http://wiki/Main/ClosureKeyboardAccessible
 * @final
 * @unrestricted
 */
goog.demos.SampleComponent = class extends goog.ui.Component {
  /**
   * @param {string=} opt_label A label to display. Defaults to "Click Me" if
   *     none provided.
   * @param {goog.dom.DomHelper=} opt_domHelper DOM helper to use.
   */
  constructor(opt_label, opt_domHelper) {
    super(opt_domHelper);

    /**
     * The label to display.
     * @type {string}
     * @private
     */
    this.initialLabel_ = opt_label || 'Click Me';

    /**
     * The current color.
     * @type {string}
     * @private
     */
    this.color_ = 'red';

    /**
     * Keyboard handler for this object. This object is created once the
     * component's DOM element is known.
     *
     * @type {goog.events.KeyHandler?}
     * @private
     */
    this.kh_ = null;
  }

  /**
   * Changes the color of the element.
   * @private
   */
  changeColor_() {
    if (this.color_ == 'red') {
      this.color_ = 'green';
    } else if (this.color_ == 'green') {
      this.color_ = 'blue';
    } else {
      this.color_ = 'red';
    }
    this.getElement().style.backgroundColor = this.color_;
  }

  /**
   * Creates an initial DOM representation for the component.
   * @override
   */
  createDom() {
    this.decorateInternal(this.dom_.createElement(goog.dom.TagName.DIV));
  }

  /**
   * Decorates an existing HTML DIV element as a SampleComponent.
   *
   * @param {Element} element The DIV element to decorate. The element's
   *    text, if any will be used as the component's label.
   * @override
   */
  decorateInternal(element) {
    super.decorateInternal(element);
    if (!this.getLabelText()) {
      this.setLabelText(this.initialLabel_);
    }

    const elem = this.getElement();
    goog.dom.classlist.add(elem, goog.getCssName('goog-sample-component'));
    elem.style.backgroundColor = this.color_;
    elem.tabIndex = 0;

    this.kh_ = new goog.events.KeyHandler(elem);
    this.getHandler().listen(
        this.kh_, goog.events.KeyHandler.EventType.KEY, this.onKey_);
  }

  /** @override */
  disposeInternal() {
    super.disposeInternal();
    if (this.kh_) {
      this.kh_.dispose();
    }
  }

  /**
   * Called when component's element is known to be in the document.
   * @override
   */
  enterDocument() {
    super.enterDocument();
    this.getHandler().listen(
        this.getElement(), goog.events.EventType.CLICK, this.onDivClicked_);
  }

  /**
   * Gets the current label text.
   *
   * @return {string} The current text set into the label, or empty string if
   *     none set.
   */
  getLabelText() {
    if (!this.getElement()) {
      return '';
    }
    return goog.dom.getTextContent(this.getElement());
  }

  /**
   * Handles DIV element clicks, causing the DIV's colour to change.
   * @param {goog.events.Event} event The click event.
   * @private
   */
  onDivClicked_(event) {
    this.changeColor_();
  }

  /**
   * Fired when user presses a key while the DIV has focus. If the user presses
   * space or enter, the color will be changed.
   * @param {goog.events.Event} event The key event.
   * @private
   */
  onKey_(event) {
    const keyCodes = goog.events.KeyCodes;
    if (event.keyCode == keyCodes.SPACE || event.keyCode == keyCodes.ENTER) {
      this.changeColor_();
    }
  }

  /**
   * Sets the current label text. Has no effect if component is not rendered.
   *
   * @param {string} text The text to set as the label.
   */
  setLabelText(text) {
    if (this.getElement()) {
      goog.dom.setTextContent(this.getElement(), text);
    }
  }
};
<|endoftext|>


<commit_before>// Copyright 2005 The Closure Library Authors. 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.

/**
 * @fileoverview Trogedit constants for browser features and quirks that should
 * be used by the rich text editor.
 */

goog.provide('goog.editor.BrowserFeature');

goog.require('goog.editor.defines');
goog.require('goog.userAgent');
goog.require('goog.userAgent.product');
goog.require('goog.userAgent.product.isVersion');

/**
 * Maps browser quirks to boolean values, detailing what the current
 * browser supports.
 * @type {Object}
 */
goog.editor.BrowserFeature = {
  // Whether this browser uses the IE TextRange object.
  HAS_IE_RANGES: goog.userAgent.IE && !goog.userAgent.isDocumentMode(9),

  // Whether this browser uses the W3C standard Range object.
  // Assumes IE higher versions will be compliance with W3C standard.
  HAS_W3C_RANGES: goog.userAgent.GECKO || goog.userAgent.WEBKIT ||
      goog.userAgent.OPERA ||
      (goog.userAgent.IE && goog.userAgent.isDocumentMode(9)),

  // Has the contentEditable attribute, which makes nodes editable.
  //
  // NOTE(nicksantos): FF3 has contentEditable, but there are 3 major reasons
  // why we don't use it:
  // 1) In FF3, we listen for key events on the document, and we'd have to
  //    filter them properly. See TR_Browser.USE_DOCUMENT_FOR_KEY_EVENTS.
  // 2) In FF3, we listen for focus/blur events on the document, which
  //    simply doesn't make sense in contentEditable. focus/blur
  //    on contentEditable elements still has some quirks, which we're
  //    talking to Firefox-team about.
  // 3) We currently use Mutation events in FF3 to detect changes,
  //    and these are dispatched on the document only.
  // If we ever hope to support FF3/contentEditable, all 3 of these issues
  // will need answers. Most just involve refactoring at our end.
  HAS_CONTENT_EDITABLE: goog.userAgent.IE || goog.userAgent.WEBKIT ||
      goog.userAgent.OPERA ||
      (goog.editor.defines.USE_CONTENTEDITABLE_IN_FIREFOX_3 &&
       goog.userAgent.GECKO && goog.userAgent.isVersion('1.9')),

  // Whether to use mutation event types to detect changes
  // in the field contents.
  USE_MUTATION_EVENTS: goog.userAgent.GECKO,

  // Whether the browser has a functional DOMSubtreeModified event.
  // TODO(user): Enable for all FF3 once we're confident this event fires
  // reliably. Currently it's only enabled if using contentEditable in FF as
  // we have no other choice in that case but to use this event.
  HAS_DOM_SUBTREE_MODIFIED_EVENT: goog.userAgent.WEBKIT ||
      (goog.editor.defines.USE_CONTENTEDITABLE_IN_FIREFOX_3 &&
       goog.userAgent.GECKO && goog.userAgent.isVersion('1.9')),

  // Whether nodes can be copied from one document to another
  HAS_DOCUMENT_INDEPENDENT_NODES: goog.userAgent.GECKO,

  // Whether the cursor goes before or inside the first block element on
  // focus, e.g.,
foo
. FF will put the cursor before the
  // paragraph on focus, which is wrong.
  PUTS_CURSOR_BEFORE_FIRST_BLOCK_ELEMENT_ON_FOCUS: goog.userAgent.GECKO,

  // Whether the selection of one frame is cleared when another frame
  // is focused.
  CLEARS_SELECTION_WHEN_FOCUS_LEAVES:
      goog.userAgent.IE || goog.userAgent.WEBKIT || goog.userAgent.OPERA,

  // Whether "unselectable" is supported as an element style.
  HAS_UNSELECTABLE_STYLE: goog.userAgent.GECKO || goog.userAgent.WEBKIT,

  // Whether this browser's "FormatBlock" command does not suck.
  FORMAT_BLOCK_WORKS_FOR_BLOCKQUOTES: goog.userAgent.GECKO ||
      goog.userAgent.WEBKIT || goog.userAgent.OPERA,

  // Whether this browser's "FormatBlock" command may create multiple
  // blockquotes.
  CREATES_MULTIPLE_BLOCKQUOTES:
      (goog.userAgent.WEBKIT && !goog.userAgent.isVersion('534.16')) ||
      goog.userAgent.OPERA,

  // Whether this browser's "FormatBlock" command will wrap blockquotes
  // inside of divs, instead of replacing divs with blockquotes.
  WRAPS_BLOCKQUOTE_IN_DIVS: goog.userAgent.OPERA,

  // Whether the readystatechange event is more reliable than load.
  PREFERS_READY_STATE_CHANGE_EVENT: goog.userAgent.IE,

  // Whether hitting the tab key will fire a keypress event.
  // see http://www.quirksmode.org/js/keys.html
  TAB_FIRES_KEYPRESS: !goog.userAgent.IE,

  // Has a standards mode quirk where width=100% doesn't do the right thing,
  // but width=99% does.
  // TODO(user|user): This should be fixable by less hacky means
  NEEDS_99_WIDTH_IN_STANDARDS_MODE: goog.userAgent.IE,

  // Whether keyboard events only reliably fire on the document.
  // On Gecko without contentEditable, keyboard events only fire reliably on the
  // document element. With contentEditable, the field itself is focusable,
  // which means that it will fire key events.
  USE_DOCUMENT_FOR_KEY_EVENTS: goog.userAgent.GECKO &&
      !goog.editor.defines.USE_CONTENTEDITABLE_IN_FIREFOX_3,

  // Whether this browser shows non-standard attributes in innerHTML.
  SHOWS_CUSTOM_ATTRS_IN_INNER_HTML: goog.userAgent.IE,

  // Whether this browser shrinks empty nodes away to nothing.
  // (If so, we need to insert some space characters into nodes that
  //  shouldn't be collapsed)
  COLLAPSES_EMPTY_NODES:
      goog.userAgent.GECKO || goog.userAgent.WEBKIT || goog.userAgent.OPERA,

  // Whether we must convert  and  tags to , .
  CONVERT_TO_B_AND_I_TAGS: goog.userAgent.GECKO || goog.userAgent.OPERA,

  // Whether this browser likes to tab through images in contentEditable mode,
  // and we like to disable this feature.
  TABS_THROUGH_IMAGES: goog.userAgent.IE,

  // Whether this browser unescapes urls when you extract it from the href tag.
  UNESCAPES_URLS_WITHOUT_ASKING: goog.userAgent.IE &&
      !goog.userAgent.isVersion('7.0'),

  // Whether this browser supports execCommand("styleWithCSS") to toggle between
  // inserting html tags or inline styling for things like bold, italic, etc.
  HAS_STYLE_WITH_CSS:
      goog.userAgent.GECKO && goog.userAgent.isVersion('1.8') ||
      goog.userAgent.WEBKIT || goog.userAgent.OPERA,

  // Whether clicking on an editable link will take you to that site.
  FOLLOWS_EDITABLE_LINKS: goog.userAgent.WEBKIT,

  // Whether this browser has document.activeElement available.
  HAS_ACTIVE_ELEMENT:
      goog.userAgent.IE || goog.userAgent.OPERA ||
      goog.userAgent.GECKO && goog.userAgent.isVersion('1.9'),

  // Whether this browser supports the setCapture method on DOM elements.
  HAS_SET_CAPTURE: goog.userAgent.IE,

  // Whether this browser can't set background color when the selection
  // is collapsed.
  EATS_EMPTY_BACKGROUND_COLOR: goog.userAgent.GECKO ||
      goog.userAgent.WEBKIT && !goog.userAgent.isVersion('527'),

  // Whether this browser supports the "focusin" or "DOMFocusIn" event
  // consistently.
  // NOTE(nicksantos): FF supports DOMFocusIn, but doesn't seem to do so
  // consistently.
  SUPPORTS_FOCUSIN: goog.userAgent.IE || goog.userAgent.OPERA,

  // Whether clicking on an image will cause the selection to move to the image.
  // Note: Gecko moves the selection, but it won't always go to the image.
  // For example, if the image is wrapped in a div, and you click on the img,
  // anchorNode = focusNode = div, anchorOffset = 0, focusOffset = 1, so this
  // is another way of "selecting" the image, but there are too many special
  // cases like this so we will do the work manually.
  SELECTS_IMAGES_ON_CLICK: goog.userAgent.IE || goog.userAgent.OPERA,

  // Whether this browser moves