<commit_before>jQuery.getScript = function(url, callback, cache) {
    jQuery.ajax({ type: "GET", url: url, success: callback, dataType: "script", cache: cache });
};

function tubepress_init(baseUrl) {
	tubepress_load_embedded_js(baseUrl);
    tubepress_load_players(baseUrl);
    tubepress_attach_listeners();
}

function tubepress_attach_listeners()
{
	jQuery("a[id^='tubepress_']").click(function () {
		var rel_split    = jQuery(this).attr("rel").split("_");
		var galleryId    = rel_split[3];
		var playerName   = rel_split[2];
		var embeddedName = rel_split[1];
		var videoId = jQuery(this).attr("id").substring(16, 27);

        _tubepress_swap_embedded(galleryId, videoId, embeddedName);
        _tubepress_call_player_js(galleryId, videoId, embeddedName, playerName);
    });
}

function _tubepress_swap_embedded(galleryId, videoId, embeddedName) {
    var matcher = window["tubepress_" + embeddedName + "_matcher"]();
    var wrapper = jQuery("#tubepress_embedded_object_" + galleryId);
    if (wrapper.html() != null) {
        var oldVideoId = wrapper.html().match(matcher)[1];
        wrapper.html(wrapper.html().replace(oldVideoId, videoId));
    }
}

function _tubepress_call_player_js(galleryId, videoId, embeddedName, playerName) {
    var playerFunctionName = "tubepress_" + playerName + "_player";
    window[playerFunctionName](galleryId, videoId);
}

function tubepress_load_players(baseUrl) {
	var playerNames = _tubepress_rel_parser(2);
    for(var i = 0; i < playerNames.length; i++) {
    	var name = playerNames[i];
        jQuery.getScript(baseUrl + "/ui/players/" + name + "/" + name + ".js",
        	_tubepress_player_loaded(name, baseUrl) , true);
    }
}

function _tubepress_player_loaded(playerName, baseUrl) {
	var funcName = 'tubepress_' + playerName + '_player_init';
	var f = function() { window[funcName](baseUrl); }
	_tubepress_call_when_true(function() { return typeof window[funcName] == 'function'; }, f);
}

function tubepress_load_embedded_js(baseUrl) {
    var embeddedNames = _tubepress_rel_parser(1);
    for(var i = 0; i < embeddedNames.length; i++) {
        jQuery.getScript(baseUrl + "/ui/embedded/" + embeddedNames[i] + "/" + embeddedNames[i] + ".js", function() {}, true);
    }
}

function _tubepress_rel_parser(index) {
    var returnValue = [];
    jQuery("a[rel^='tubepress_']").each( function() {
        var thisName = jQuery(this).attr("rel").split("_")[index];
        if (returnValue.indexOf(thisName) == -1) {
            returnValue.push(thisName);
        }
    });
    return returnValue;
}

function _tubepress_call_when_true(test, callback) {
	if (!test()) {
		setTimeout(function() {_tubepress_call_when_true(test, callback);}, 400);
		return;
	}
	callback();
}

function _tubepress_get_wait_call(scriptPath, test, callback) {
	jQuery.getScript(scriptPath, function() {
		_tubepress_call_when_true(test, callback);
    }, true);
}
<commit_msg>IE doesn't like "indexOf"<commit_after>jQuery.getScript = function(url, callback, cache) {
    jQuery.ajax({ type: "GET", url: url, success: callback, dataType: "script", cache: cache });
};

function tubepress_init(baseUrl) {
	tubepress_load_embedded_js(baseUrl);
    tubepress_load_players(baseUrl);
    tubepress_attach_listeners();
}

function tubepress_attach_listeners()
{
	jQuery("a[id^='tubepress_']").click(function () {
		var rel_split    = jQuery(this).attr("rel").split("_");
		var galleryId    = rel_split[3];
		var playerName   = rel_split[2];
		var embeddedName = rel_split[1];
		var videoId = jQuery(this).attr("id").substring(16, 27);

        _tubepress_swap_embedded(galleryId, videoId, embeddedName);
        _tubepress_call_player_js(galleryId, videoId, embeddedName, playerName);
    });
}

function _tubepress_swap_embedded(galleryId, videoId, embeddedName) {
    var matcher = window["tubepress_" + embeddedName + "_matcher"]();
    var wrapper = jQuery("#tubepress_embedded_object_" + galleryId);
    if (wrapper.html() != null) {
        var oldVideoId = wrapper.html().match(matcher)[1];
        wrapper.html(wrapper.html().replace(oldVideoId, videoId));
    }
}

function _tubepress_call_player_js(galleryId, videoId, embeddedName, playerName) {
    var playerFunctionName = "tubepress_" + playerName + "_player";
    window[playerFunctionName](galleryId, videoId);
}

function tubepress_load_players(baseUrl) {
	var playerNames = _tubepress_rel_parser(2);
    for(var i = 0; i < playerNames.length; i++) {
    	var name = playerNames[i];
        jQuery.getScript(baseUrl + "/ui/players/" + name + "/" + name + ".js",
        	_tubepress_player_loaded(name, baseUrl) , true);
    }
}

function _tubepress_player_loaded(playerName, baseUrl) {
	var funcName = 'tubepress_' + playerName + '_player_init';
	var f = function() { window[funcName](baseUrl); }
	_tubepress_call_when_true(function() { return typeof window[funcName] == 'function'; }, f);
}

function tubepress_load_embedded_js(baseUrl) {
    var embeddedNames = _tubepress_rel_parser(1);
    for(var i = 0; i < embeddedNames.length; i++) {
        jQuery.getScript(baseUrl + "/ui/embedded/" + embeddedNames[i] + "/" + embeddedNames[i] + ".js", function() {}, true);
    }
}

function _tubepress_rel_parser(index) {
    var returnValue = [];
    jQuery("a[rel^='tubepress_']").each( function() {
        var thisName = jQuery(this).attr("rel").split("_")[index];
        if (jQuery.inArray(thisName, returnValue) == -1) {
            returnValue.push(thisName);
        }
    });
    return returnValue;
}

function _tubepress_call_when_true(test, callback) {
	if (!test()) {
		setTimeout(function() {_tubepress_call_when_true(test, callback);}, 400);
		return;
	}
	callback();
}

function _tubepress_get_wait_call(scriptPath, test, callback) {
	jQuery.getScript(scriptPath, function() {
		_tubepress_call_when_true(test, callback);
    }, true);
}
<|endoftext|>


<commit_before>// @flow
import * as React from 'react';
import DataTable from '../components/dataTable';
import { TableHeaderColumn } from 'react-bootstrap-table';

import { Link } from 'react-router-dom';

import styled from 'styled-components';
import { getHouseholdList } from 'api/household';

import type { HouseholdType } from 'api/household';

const TD_STYLE_LARGE = {
  'min-width': '175px',
  'width': '175px'
 };

 const TD_STYLE = {
  'min-width': '150px',
  'width': '150px'
 };

 const TD_STYLE_SMALL = {
  'min-width': '75px',
  'width': '75px'
 };
 const TD_STYLE_XSMALL = {
  'min-width': '50px',
  'width': '50px'
 };

 const StyledButton = styled.button`
  margin-right: 5px;
 `;

export default class List extends React.Component<{}> {

  constructor(props) {
    super(props);
    this.currentPage = 1;
  }

  uploadedFormFormatter(_cell: any, _row: HouseholdType): React.Node {
    return ;
  }

  // Called by householdIndex when FeedbackModal is closed
  handlePageChange(pageNumber) {
    this.table.handlePageChange(pageNumber);
  }

  actionCellFormatter(cell: any, row: HouseholdType): React.Node {
    return (

        <Link to={`/dashboard/household/show/${row.id}`}>

        </Link>
        <Link to={`/dashboard/household/edit/${row.id}`}>

        </Link>

    );
  }

  nominatorCellFormatter(cell, row) {
    if (!row.nominator) {
      console.log('NOPE', row);
      return null;
    }
    return (
      <Link to={`/dashboard/user/${row.nominator.id}`}>
        {row.nominator.name_first} {row.nominator.name_last}
      </Link>
    );
  }

  reviewCellFormatter = (cell, row: HouseholdType): React.Node => {
    const { currentPage } = this;
    return (

        {row.reviewed !== true &&
          <button className="btn btn-sm btn-default" onClick={() => this.props.openHouseholdReview(row, currentPage)}>
            Review
          </button>
        }
        {row.reviewed && row.approved && }

    );
  }

  async fetch(
    page: number,
    search: ?string
  ): Promise<{ items: HouseholdType[], totalSize: number, sizePerPage: number }> {
    this.currentPage = page; // Used for refreshing list when submitting feedback
    const response: Object = await getHouseholdList(page, search);
    return { items: response.items, totalSize: response.totalSize, per_page: response.per_page };
  }

  render(): React.Node {
    return (
      <DataTable search={true} fetch={this.fetch.bind(this)} searchPlaceholder="Search by last name" ref={(table) => {
        this.table = table;
      }}>
        <TableHeaderColumn dataField="id" hidden isKey>
          Id
        </TableHeaderColumn>
        <TableHeaderColumn tdStyle={TD_STYLE} thStyle={TD_STYLE} dataField="name_first" dataFormat={(cell, row) => `${row.name_first} ${row.name_last}`}>
          Head of Household
        </TableHeaderColumn>
        <TableHeaderColumn tdStyle={TD_STYLE_XSMALL} thStyle={TD_STYLE_XSMALL} dataField="name_first" dataFormat={(cell, row) => row.children ? `${row.children.length}` : 0}>
          Children
        </TableHeaderColumn>
        {/* <TableHeaderColumn dataField="children" dataFormat={cell => cell.length}>Children</TableHeaderColumn> */}
        <TableHeaderColumn tdStyle={TD_STYLE} thStyle={TD_STYLE} dataField="nominator" dataFormat={this.nominatorCellFormatter}>
          Nominated by
        </TableHeaderColumn>
        <TableHeaderColumn tdStyle={TD_STYLE_SMALL} thStyle={TD_STYLE_SMALL} dataField="uploaded_form" dataFormat={this.uploadedFormFormatter} dataAlign="center">
          Form
        </TableHeaderColumn>
        <TableHeaderColumn tdStyle={TD_STYLE_LARGE} thStyle={TD_STYLE_LARGE} dataField="id" dataFormat={this.actionCellFormatter}>
          Actions
        </TableHeaderColumn>
        <TableHeaderColumn tdStyle={TD_STYLE_SMALL} thStyle={TD_STYLE_SMALL} dataField="surname" dataFormat={this.reviewCellFormatter}>
          Review
        </TableHeaderColumn>
      </DataTable>
    );
  }
}
<commit_msg>GIFT-228<commit_after>// @flow
import * as React from 'react';
import DataTable from '../components/dataTable';
import { TableHeaderColumn } from 'react-bootstrap-table';

import { Link } from 'react-router-dom';

import styled from 'styled-components';
import { getHouseholdList } from 'api/household';

import type { HouseholdType } from 'api/household';

const TD_STYLE_LARGE = {
  'min-width': '175px',
  'width': '175px'
 };

 const TD_STYLE = {
  'min-width': '150px',
  'width': '150px'
 };

 const TD_STYLE_SMALL = {
  'min-width': '75px',
  'width': '75px'
 };
 const TD_STYLE_XSMALL = {
  'min-width': '50px',
  'width': '50px'
 };

 const StyledButton = styled.button`
  margin-right: 5px;
 `;

export default class List extends React.Component<{}> {

  constructor(props) {
    super(props);
    this.currentPage = 1;
  }

  uploadedFormFormatter(_cell: any, _row: HouseholdType): React.Node {
    return ;
  }

  // Called by householdIndex when FeedbackModal is closed
  handlePageChange(pageNumber) {
    this.table.handlePageChange(pageNumber);
  }

  actionCellFormatter(cell: any, row: HouseholdType): React.Node {
    return (

        <Link to={`/dashboard/household/show/${row.id}`}>

        </Link>
        <Link to={`/dashboard/household/edit/${row.id}`}>

        </Link>
        {/*  */}

    );
  }

  nominatorCellFormatter(cell, row) {
    if (!row.nominator) {
      console.log('NOPE', row);
      return null;
    }
    return (
      <Link to={`/dashboard/user/${row.nominator.id}`}>
        {row.nominator.name_first} {row.nominator.name_last}
      </Link>
    );
  }

  reviewCellFormatter = (cell, row: HouseholdType): React.Node => {
    const { currentPage } = this;
    return (

        {row.reviewed !== true &&
          <button className="btn btn-sm btn-default" onClick={() => this.props.openHouseholdReview(row, currentPage)}>
            Review
          </button>
        }
        {row.reviewed && row.approved && }

    );
  }

  async fetch(
    page: number,
    search: ?string
  ): Promise<{ items: HouseholdType[], totalSize: number, sizePerPage: number }> {
    this.currentPage = page; // Used for refreshing list when submitting feedback
    const response: Object = await getHouseholdList(page, search);
    return { items: response.items, totalSize: response.totalSize, per_page: response.per_page };
  }

  render(): React.Node {
    return (
      <DataTable search={true} fetch={this.fetch.bind(this)} searchPlaceholder="Search by last name" ref={(table) => {
        this.table = table;
      }}>
        <TableHeaderColumn dataField="id" hidden isKey>
          Id
        </TableHeaderColumn>
        <TableHeaderColumn tdStyle={TD_STYLE} thStyle={TD_STYLE} dataField="name_first" dataFormat={(cell, row) => `${row.name_first} ${row.name_last}`}>
          Head of Household
        </TableHeaderColumn>
        <TableHeaderColumn tdStyle={TD_STYLE_XSMALL} thStyle={TD_STYLE_XSMALL} dataField="name_first" dataFormat={(cell, row) => row.children ? `${row.children.length}` : 0}>
          Children
        </TableHeaderColumn>
        {/* <TableHeaderColumn dataField="children" dataFormat={cell => cell.length}>Children</TableHeaderColumn> */}
        <TableHeaderColumn tdStyle={TD_STYLE} thStyle={TD_STYLE} dataField="nominator" dataFormat={this.nominatorCellFormatter}>
          Nominated by
        </TableHeaderColumn>
        <TableHeaderColumn tdStyle={TD_STYLE_SMALL} thStyle={TD_STYLE_SMALL} dataField="uploaded_form" dataFormat={this.uploadedFormFormatter} dataAlign="center">
          Form
        </TableHeaderColumn>
        <TableHeaderColumn tdStyle={TD_STYLE_LARGE} thStyle={TD_STYLE_LARGE} dataField="id" dataFormat={this.actionCellFormatter}>
          Actions
        </TableHeaderColumn>
        <TableHeaderColumn tdStyle={TD_STYLE_SMALL} thStyle={TD_STYLE_SMALL} dataField="surname" dataFormat={this.reviewCellFormatter}>
          Review
        </TableHeaderColumn>
      </DataTable>
    );
  }
}
<|endoftext|>


<commit_before>
// Google Maps integration
var map = null;
var geocoder = null;

function _cdb_setGeoPoint(map, info, point) {
  if (map!=null)
    var marker = new google.maps.Marker({
      position: point,
      map: map,
      title:info+" "+point.lat()+" "+point.lng()
    });
}

function _cdb_addPersonToMap(map,near_lat,near_lng) {
  var image = new google.maps.MarkerImage("https://www.google.com/intl/en_us/mapfiles/ms/micons/blue-dot.png",
      new google.maps.Size(32, 32),
      new google.maps.Point(0, 0),
      new google.maps.Point(6, 12),
      new google.maps.Size(12, 12)
      );

  each(allPersons, function(k, a){
    if ((a.geolat!="")) {
      if ((near_lat==null) ||
           (((Math.abs(parseFloat(near_lng)-parseFloat(a.geolng))<0.06)) &&
           (Math.abs(parseFloat(near_lat)-parseFloat(a.geolat))<0.03))) {
        var myLatLng = new google.maps.LatLng(a.geolat, a.geolng);
        var beachMarker = new google.maps.Marker({
            position: myLatLng,
            map: map,
            icon: image,
            title: _("person")+": "+a.vorname+" "+a.name+" ["+a.id+"]"
        });
        google.maps.event.addDomListener(beachMarker, 'click', function() {
          churchInterface.setCurrentView(personView);
          personView.clearFilter();
          personView.setFilter("searchEntry",a.id);
          personView.renderView();
        });

      }
    }
  });
}

/**
 * The HomeControl adds a control to the map that simply
 * returns the user to Chicago. This constructor takes
 * the control DIV as an argument.
 */

function _cdb_addGroupButton2Maps(controlDiv, map) {

  // Set CSS styles for the DIV containing the control
  // Setting padding to 5 px will offset the control
  // from the edge of the map
  controlDiv.style.padding = '4px';

  // Set CSS for the control border
  var controlUI = document.createElement('DIV');
  controlUI.className = 'map-control-wrapper';
  controlUI.title = 'Klicke, um hier Gruppen anzuzeigen';
  controlDiv.appendChild(controlUI);

  // Set CSS for the control interior
  var controlText = document.createElement('DIV');
  controlText.className = 'map-control-label';
  controlText.innerHTML = _("groups");
  controlUI.appendChild(controlText);

  // Setup the click event listeners: simply set the map to
  // Chicago
  google.maps.event.addDomListener(controlUI, 'click', function() {
    if (map.getZoom()<11)
      alert("Bitte erst weiter reinzoomen!");
    else
      cdb_addGroupsToMap(map, map.getCenter().lat(), map.getCenter().lng());
  });
}
/**
 * The HomeControl adds a control to the map that simply
 * returns the user to Chicago. This constructor takes
 * the control DIV as an argument.
 */

function _cdb_addPersonButton2Maps(controlDiv, map) {

  // Set CSS styles for the DIV containing the control
  // Setting padding to 5 px will offset the control
  // from the edge of the map
  controlDiv.style.padding = '4px';

  // Set CSS for the control border
  var controlUI = document.createElement('DIV');
  controlUI.className = 'map-control-wrapper';
  controlUI.title = 'Klicke, um Personen in der Nähe anzuzeigen';
  controlDiv.appendChild(controlUI);

  // Set CSS for the control interior
  var controlText = document.createElement('DIV');
  controlText.className = 'map-control-label';
  controlText.innerHTML = _("persons");
  controlUI.appendChild(controlText);

  // Setup the click event listeners: simply set the map to
  // Chicago
  google.maps.event.addDomListener(controlUI, 'click', function() {
    if (map.getZoom()<12)
      alert("Bitte erst weiter reinzoomen!");
    else
    _cdb_addPersonToMap(map, map.getCenter().lat(), map.getCenter().lng());
  });
}

function _cdb_limitZoom(map) {
  google.maps.event.addListener(map, 'zoom_changed', function() {
    if (map.getZoom()>12) {
      map.setZoom(12);
      alert("Ein weiterer Zoom ist leider nicht erlaubt!");
    }
  });
}

function cdb_prepareMap(id,latlng) {
  var myOptions = {
    zoom: 11,
    center: latlng,
    mapTypeId: google.maps.MapTypeId.ROADMAP
  };
  var docId=document.getElementById(id);
  // Karte wird momentan nicht im Browser angezeigt, also brauche sie auch nicht zu f�llen
  if (docId==null)
    return null;

  var map =  new google.maps.Map(docId, myOptions);
  //Create the DIV to hold the control and
  // call the HomeControl() constructor passing
  // in this DIV.
  var groupControlDiv = document.createElement('DIV');
  var groupControl = new _cdb_addGroupButton2Maps(groupControlDiv, map);
  groupControlDiv.index = 1;
  map.controls[google.maps.ControlPosition.TOP_RIGHT].push(groupControlDiv);

  if (masterData.auth.viewalldata) {
    var personControlDiv = document.createElement('DIV');
    var personControl = new _cdb_addPersonButton2Maps(personControlDiv, map);
    personControlDiv.index = 1;
    map.controls[google.maps.ControlPosition.TOP_RIGHT].push(personControlDiv);
  }

  if (masterData.settings.googleMapLayer==1) {
    // Traffic Layer:
    var trafficLayer = new google.maps.TrafficLayer();
    trafficLayer.setMap(map);
  }
  else if (masterData.settings.googleMapLayer==2) {
    // Bike Layer
    var bikeLayer = new google.maps.BicyclingLayer();
    bikeLayer.setMap(map);
  }
  else if (masterData.settings.googleMapLayer==3) {
    //Transit Layer
    var transitOptions = {
        getTileUrl: function(coord, zoom) {
          return "http://mt1.google.com/vt/lyrs=m@155076273,transit:comp|vm:&" +
          "hl=en&opts=r&s=Galil&z=" + zoom + "&x=" + coord.x + "&y=" + coord.y;
        },
        tileSize: new google.maps.Size(256, 256),
        isPng: true
      };
    var transitMapType = new google.maps.ImageMapType(transitOptions);
    map.overlayMapTypes.insertAt(0, transitMapType);
  }

  return map;
}

/**
 *
 * @param {Object} address - Adresse in Textform
 * @param {Object} id - person_id
 */
function cdb_showGeoPerson(address, id, limit) {
  if (geocoder) {
    // Wenn Geo-Daten schon vorliegen
    if (allPersons[id].geolat!="") {
      var latlng = new google.maps.LatLng(allPersons[id].geolat, allPersons[id].geolng);
      map=cdb_prepareMap("map_canvas"+id,latlng);
      _cdb_setGeoPoint(map,address,latlng);
      if (limit==true)
        _cdb_limitZoom(map);
    }
    // Geo-Daten müssen erst geholt werden
    else {
      geocoder.geocode( { 'address': address}, function(results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
          map=cdb_prepareMap("map_canvas"+id,results[0].geometry.location);
          _cdb_setGeoPoint(map,address, results[0].geometry.location);
          // Speichern in das Array im Browser und in die Datenbank per AJAX
          var obj=new Object();
          obj["id"]=id;
          obj["func"] = "f_geocode_person";
          obj["lat"]=results[0].geometry.location.lat();
          obj["lng"]=results[0].geometry.location.lng();
          allPersons[id].geolat=results[0].geometry.location.lat();
          allPersons[id].geolng=results[0].geometry.location.lng();
          churchInterface.jsendWrite(obj, function(ok, json) {
            if (!ok) alert("Fehler beim Speichern der Geocode-Daten: "+json);
          });

        } else {
          jQuery("#map_canvas"+id).html("Geocoding war nicht erfolgreich:" + status);
        }
      });
    }
  }
}

/**
 *
 * @param {Object} address - Adresse in Textform
 * @param {Object} id - group_id
 */
function cdb_showGeoGruppe(address, id) {
  if (geocoder) {
    // Wenn Geo-Daten schon vorliegen
    if (masterData.groups[id].geolat!="") {
      var latlng = new google.maps.LatLng(masterData.groups[id].geolat, masterData.groups[id].geolng);
      map=cdb_prepareMap("map_canvasg"+id,latlng);
      _cdb_setGeoPoint(map,address,latlng);
    }
    // Geo-Daten müssen erst geholt werden
    else {
      geocoder.geocode( { 'address': address}, function(results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
          map=cdb_prepareMap("map_canvasg"+id,results[0].geometry.location);
          _cdb_setGeoPoint(map,address, results[0].geometry.location);
          // Speichern in das Array im Browser und in die Datenbank per AJAX
          var obj=new Object();
          obj["id"]=id;
          obj["func"] = "f_geocode_gruppe";
          obj["lat"]=results[0].geometry.location.lat();
          obj["lng"]=results[0].geometry.location.lng();
          masterData.groups[id].geolat=results[0].geometry.location.lat();
          masterData.groups[id].geolng=results[0].geometry.location.lng();
          churchInterface.jsendWrite(obj, function(ok, json) {
            if (!ok) alert("Fehler beim Speichern der Geocode-Daten: "+json);
          });

        } else {
          jQuery("#map_canvas"+id).html("Geocoding war nicht erfolgreich:" + status);
        }
      });
    }
  }
}

function cdb_addGroupsToMap(map,near_lat,near_lng, func) {

  var shadow = new google.maps.MarkerImage(masterData.modulespath+"/images/gruppe_shadow.png",
      new google.maps.Size(50, 50),
      new google.maps.Point(0, 0),
      new google.maps.Point(10, 25),
      new google.maps.Size(25, 25)
      );

  if (masterData.groups!=null) {
    each(masterData.groups, function(k, a){
      if ((a.geolat!="") && (a.valid_yn==1) && (a.versteckt_yn==0) &&
             churchInterface.views.GroupView.isAllowedToSeeName(a.id, masterData.user_pid)) {
        if ((near_lat==null) ||
             (((Math.abs(parseFloat(near_lng)-parseFloat(a.geolng))<0.2)) &&
             (Math.abs(parseFloat(near_lat)-parseFloat(a.geolat))<0.1))) {

          url = "gruppe_standard.png";
          if ((a.distrikt_id!=null) && (masterData.districts[a.distrikt_id].imageurl!=null))
            url = masterData.districts[a.distrikt_id].imageurl;
          var image = new google.maps.MarkerImage(masterData.modulespath+"/images/"+url,
              new google.maps.Size(40, 50),
              new google.maps.Point(0, 0),
              new google.maps.Point(10, 25),
              new google.maps.Size(20, 25)
              );

          var myLatLng = new google.maps.LatLng(a.geolat, a.geolng);

          var title="Gruppe: "+a.bezeichnung+" ["+a.id+"]";
          if (a.distrikt_id!=null)
            title=title+"\n Distrikt: "+masterData.districts[a.distrikt_id].bezeichnung;
          if (a.treffzeit!="") title=title+"\n "+a.treffzeit;
          if ((a.treffpunkt!=null) && (a.treffpunkt!="")) title=title+"\n Ort: "+a.treffpunkt;
          if (a.treffname!="") title=title+"\n bei: "+a.treffname;
          if (a.zielgruppe!="") title=title+"\n Zielgruppe: "+a.zielgruppe;

          var beachMarker = new google.maps.Marker({
              position: myLatLng,
              map: map,
              icon: image,
              shadow: shadow,
              title: title
          });

          google.maps.event.addDomListener(beachMarker, 'click', function() {
            if (func!=null) func(a.id);
            else if (typeof(groupView)!='undefined'){
              churchInterface.setCurrentView(groupView);
              groupView.clearFilter();
              groupView.setFilter("searchEntry",a.id);
              groupView.renderView();
            }
          });

        }
      }
    });
  }
}

function cdb_initializeGoogleMaps() {
  churchInterface.setStatus("Initialisiere GoogleMap...");
  try {
     geocoder = new google.maps.Geocoder();
  }
  catch (e) {
    jQuery("#cdb_info").append('
GoogleMaps steht nicht zur Verfügung. ('+e.message+')
');
    window.setTimeout(function() {$("#cdb_info div.googlemaps").hide('slow');},5000);
  };
}
<commit_msg>(CDB) Fix javascript error in externmapvew<commit_after>
// Google Maps integration
var map = null;
var geocoder = null;

function _cdb_setGeoPoint(map, info, point) {
  if (map!=null)
    var marker = new google.maps.Marker({
      position: point,
      map: map,
      title:info+" "+point.lat()+" "+point.lng()
    });
}

function _cdb_addPersonToMap(map,near_lat,near_lng) {
  var image = new google.maps.MarkerImage("https://www.google.com/intl/en_us/mapfiles/ms/micons/blue-dot.png",
      new google.maps.Size(32, 32),
      new google.maps.Point(0, 0),
      new google.maps.Point(6, 12),
      new google.maps.Size(12, 12)
      );

  each(allPersons, function(k, a){
    if ((a.geolat!="")) {
      if ((near_lat==null) ||
           (((Math.abs(parseFloat(near_lng)-parseFloat(a.geolng))<0.06)) &&
           (Math.abs(parseFloat(near_lat)-parseFloat(a.geolat))<0.03))) {
        var myLatLng = new google.maps.LatLng(a.geolat, a.geolng);
        var beachMarker = new google.maps.Marker({
            position: myLatLng,
            map: map,
            icon: image,
            title: _("person")+": "+a.vorname+" "+a.name+" ["+a.id+"]"
        });
        google.maps.event.addDomListener(beachMarker, 'click', function() {
          churchInterface.setCurrentView(personView);
          personView.clearFilter();
          personView.setFilter("searchEntry",a.id);
          personView.renderView();
        });

      }
    }
  });
}

/**
 * The HomeControl adds a control to the map that simply
 * returns the user to Chicago. This constructor takes
 * the control DIV as an argument.
 */

function _cdb_addGroupButton2Maps(controlDiv, map) {

  // Set CSS styles for the DIV containing the control
  // Setting padding to 5 px will offset the control
  // from the edge of the map
  controlDiv.style.padding = '4px';

  // Set CSS for the control border
  var controlUI = document.createElement('DIV');
  controlUI.className = 'map-control-wrapper';
  controlUI.title = 'Klicke, um hier Gruppen anzuzeigen';
  controlDiv.appendChild(controlUI);

  // Set CSS for the control interior
  var controlText = document.createElement('DIV');
  controlText.className = 'map-control-label';
  controlText.innerHTML = _("groups");
  controlUI.appendChild(controlText);

  // Setup the click event listeners: simply set the map to
  // Chicago
  google.maps.event.addDomListener(controlUI, 'click', function() {
    if (map.getZoom()<11)
      alert("Bitte erst weiter reinzoomen!");
    else
      cdb_addGroupsToMap(map, map.getCenter().lat(), map.getCenter().lng());
  });
}
/**
 * The HomeControl adds a control to the map that simply
 * returns the user to Chicago. This constructor takes
 * the control DIV as an argument.
 */

function _cdb_addPersonButton2Maps(controlDiv, map) {

  // Set CSS styles for the DIV containing the control
  // Setting padding to 5 px will offset the control
  // from the edge of the map
  controlDiv.style.padding = '4px';

  // Set CSS for the control border
  var controlUI = document.createElement('DIV');
  controlUI.className = 'map-control-wrapper';
  controlUI.title = 'Klicke, um Personen in der Nähe anzuzeigen';
  controlDiv.appendChild(controlUI);

  // Set CSS for the control interior
  var controlText = document.createElement('DIV');
  controlText.className = 'map-control-label';
  controlText.innerHTML = _("persons");
  controlUI.appendChild(controlText);

  // Setup the click event listeners: simply set the map to
  // Chicago
  google.maps.event.addDomListener(controlUI, 'click', function() {
    if (map.getZoom()<12)
      alert("Bitte erst weiter reinzoomen!");
    else
    _cdb_addPersonToMap(map, map.getCenter().lat(), map.getCenter().lng());
  });
}

function _cdb_limitZoom(map) {
  google.maps.event.addListener(map, 'zoom_changed', function() {
    if (map.getZoom()>12) {
      map.setZoom(12);
      alert("Ein weiterer Zoom ist leider nicht erlaubt!");
    }
  });
}

function cdb_prepareMap(id,latlng) {
  var myOptions = {
    zoom: 11,
    center: latlng,
    mapTypeId: google.maps.MapTypeId.ROADMAP
  };
  var docId=document.getElementById(id);
  // Karte wird momentan nicht im Browser angezeigt, also brauche sie auch nicht zu f�llen
  if (docId==null)
    return null;

  var map =  new google.maps.Map(docId, myOptions);
  //Create the DIV to hold the control and
  // call the HomeControl() constructor passing
  // in this DIV.
  var groupControlDiv = document.createElement('DIV');
  var groupControl = new _cdb_addGroupButton2Maps(groupControlDiv, map);
  groupControlDiv.index = 1;
  map.controls[google.maps.ControlPosition.TOP_RIGHT].push(groupControlDiv);

  if (masterData.auth.viewalldata) {
    var personControlDiv = document.createElement('DIV');
    var personControl = new _cdb_addPersonButton2Maps(personControlDiv, map);
    personControlDiv.index = 1;
    map.controls[google.maps.ControlPosition.TOP_RIGHT].push(personControlDiv);
  }

  if (masterData.settings.googleMapLayer==1) {
    // Traffic Layer:
    var trafficLayer = new google.maps.TrafficLayer();
    trafficLayer.setMap(map);
  }
  else if (masterData.settings.googleMapLayer==2) {
    // Bike Layer
    var bikeLayer = new google.maps.BicyclingLayer();
    bikeLayer.setMap(map);
  }
  else if (masterData.settings.googleMapLayer==3) {
    //Transit Layer
    var transitOptions = {
        getTileUrl: function(coord, zoom) {
          return "http://mt1.google.com/vt/lyrs=m@155076273,transit:comp|vm:&" +
          "hl=en&opts=r&s=Galil&z=" + zoom + "&x=" + coord.x + "&y=" + coord.y;
        },
        tileSize: new google.maps.Size(256, 256),
        isPng: true
      };
    var transitMapType = new google.maps.ImageMapType(transitOptions);
    map.overlayMapTypes.insertAt(0, transitMapType);
  }

  return map;
}

/**
 *
 * @param {Object} address - Adresse in Textform
 * @param {Object} id - person_id
 */
function cdb_showGeoPerson(address, id, limit) {
  if (geocoder) {
    // Wenn Geo-Daten schon vorliegen
    if (allPersons[id].geolat!="") {
      var latlng = new google.maps.LatLng(allPersons[id].geolat, allPersons[id].geolng);
      map=cdb_prepareMap("map_canvas"+id,latlng);
      _cdb_setGeoPoint(map,address,latlng);
      if (limit==true)
        _cdb_limitZoom(map);
    }
    // Geo-Daten müssen erst geholt werden
    else {
      geocoder.geocode( { 'address': address}, function(results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
          map=cdb_prepareMap("map_canvas"+id,results[0].geometry.location);
          _cdb_setGeoPoint(map,address, results[0].geometry.location);
          // Speichern in das Array im Browser und in die Datenbank per AJAX
          var obj=new Object();
          obj["id"]=id;
          obj["func"] = "f_geocode_person";
          obj["lat"]=results[0].geometry.location.lat();
          obj["lng"]=results[0].geometry.location.lng();
          allPersons[id].geolat=results[0].geometry.location.lat();
          allPersons[id].geolng=results[0].geometry.location.lng();
          churchInterface.jsendWrite(obj, function(ok, json) {
            if (!ok) alert("Fehler beim Speichern der Geocode-Daten: "+json);
          });

        } else {
          jQuery("#map_canvas"+id).html("Geocoding war nicht erfolgreich:" + status);
        }
      });
    }
  }
}

/**
 *
 * @param {Object} address - Adresse in Textform
 * @param {Object} id - group_id
 */
function cdb_showGeoGruppe(address, id) {
  if (geocoder) {
    // Wenn Geo-Daten schon vorliegen
    if (masterData.groups[id].geolat!="") {
      var latlng = new google.maps.LatLng(masterData.groups[id].geolat, masterData.groups[id].geolng);
      map=cdb_prepareMap("map_canvasg"+id,latlng);
      _cdb_setGeoPoint(map,address,latlng);
    }
    // Geo-Daten müssen erst geholt werden
    else {
      geocoder.geocode( { 'address': address}, function(results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
          map=cdb_prepareMap("map_canvasg"+id,results[0].geometry.location);
          _cdb_setGeoPoint(map,address, results[0].geometry.location);
          // Speichern in das Array im Browser und in die Datenbank per AJAX
          var obj=new Object();
          obj["id"]=id;
          obj["func"] = "f_geocode_gruppe";
          obj["lat"]=results[0].geometry.location.lat();
          obj["lng"]=results[0].geometry.location.lng();
          masterData.groups[id].geolat=results[0].geometry.location.lat();
          masterData.groups[id].geolng=results[0].geometry.location.lng();
          churchInterface.jsendWrite(obj, function(ok, json) {
            if (!ok) alert("Fehler beim Speichern der Geocode-Daten: "+json);
          });

        } else {
          jQuery("#map_canvas"+id).html("Geocoding war nicht erfolgreich:" + status);
        }
      });
    }
  }
}

function cdb_addGroupsToMap(map,near_lat,near_lng, func) {

  var shadow = new google.maps.MarkerImage(masterData.modulespath+"/images/gruppe_shadow.png",
      new google.maps.Size(50, 50),
      new google.maps.Point(0, 0),
      new google.maps.Point(10, 25),
      new google.maps.Size(25, 25)
      );

  if (masterData.groups!=null) {
    each(masterData.groups, function(k, a){
      if ((a.geolat!="") && (a.valid_yn==1) && (a.versteckt_yn==0) &&
          (churchInterface.views.GroupView == null || churchInterface.views.GroupView.isAllowedToSeeName(a.id, masterData.user_pid))) {
        if ((near_lat==null) ||
             (((Math.abs(parseFloat(near_lng)-parseFloat(a.geolng))<0.2)) &&
             (Math.abs(parseFloat(near_lat)-parseFloat(a.geolat))<0.1))) {

          url = "gruppe_standard.png";
          if ((a.distrikt_id!=null) && (masterData.districts[a.distrikt_id].imageurl!=null))
            url = masterData.districts[a.distrikt_id].imageurl;
          var image = new google.maps.MarkerImage(masterData.modulespath+"/images/"+url,
              new google.maps.Size(40, 50),
              new google.maps.Point(0, 0),
              new google.maps.Point(10, 25),
              new google.maps.Size(20, 25)
              );

          var myLatLng = new google.maps.LatLng(a.geolat, a.geolng);

          var title="Gruppe: "+a.bezeichnung+" ["+a.id+"]";
          if (a.distrikt_id!=null)
            title=title+"\n Distrikt: "+masterData.districts[a.distrikt_id].bezeichnung;
          if (a.treffzeit!="") title=title+"\n "+a.treffzeit;
          if ((a.treffpunkt!=null) && (a.treffpunkt!="")) title=title+"\n Ort: "+a.treffpunkt;
          if (a.treffname!="") title=title+"\n bei: "+a.treffname;
          if (a.zielgruppe!="") title=title+"\n Zielgruppe: "+a.zielgruppe;

          var beachMarker = new google.maps.Marker({
              position: myLatLng,
              map: map,
              icon: image,
              shadow: shadow,
              title: title
          });

          google.maps.event.addDomListener(beachMarker, 'click', function() {
            if (func!=null) func(a.id);
            else if (typeof(groupView)!='undefined'){
              churchInterface.setCurrentView(groupView);
              groupView.clearFilter();
              groupView.setFilter("searchEntry",a.id);
              groupView.renderView();
            }
          });

        }
      }
    });
  }
}

function cdb_initializeGoogleMaps() {
  churchInterface.setStatus("Initialisiere GoogleMap...");
  try {
     geocoder = new google.maps.Geocoder();
  }
  catch (e) {
    jQuery("#cdb_info").append('
GoogleMaps steht nicht zur Verfügung. ('+e.message+')
');
    window.setTimeout(function() {$("#cdb_info div.googlemaps").hide('slow');},5000);
  };
}
<|endoftext|>


<commit_before>var enhancedEditor = {
    startFeature: function() {
        setTimeout(function() {
            $.each($('textarea[id^="wmd-input"].processed'), function() {
                enhancedEditor.init($(this).attr('id'));
            });

            $('.edit-post').click(function() {
                $that = $(this);
                setTimeout(function() {
                    enhancedEditor.init($that.parents('table').find('.inline-editor textarea.processed').attr('id'));
                }, 2000);
            });
        }, 2000);
    },

    init: function(wmd) {
        var urls = ['http://cdn.rawgit.com/dwieeb/jquery-textrange/1.x/jquery-textrange.js',
            'http://cdn.rawgit.com/jeresig/jquery.hotkeys/master/jquery.hotkeys.js',
            'http://rawgit.com/ajaxorg/ace-builds/master/src-noconflict/ace.js',
            'http://rawgit.com/ajaxorg/ace-builds/master/src-noconflict/ext-language_tools.js',
            'http://rawgit.com/ajaxorg/ace-builds/master/src-noconflict/theme-github.js',
            'http://rawgit.com/ajaxorg/ace-builds/master/src-noconflict/mode-javascript.js',
            'http://rawgit.com/ajaxorg/ace-builds/master/src-noconflict/snippets/javascript.js'];

        for (var i = 0; i < urls.length; i++) {
            script = document.createElement('script');
            script.src = urls[i];
            document.head.appendChild(script);
        }
        $('head').append("<link rel='stylesheet' type='text/css' href='https://rawgit.com/soscripted/sox/experimental/enhancedEditor/sox.enhancedEditor.css' />");

        $('[id^="enhancedEditor"]').remove();
        var s = '#'+wmd; //s is the selector we pass onto each function so the action is applied to the correct textarea (and not, for example the 'add answer' textarea *and* the 'edit' textarea!)
        enhancedEditor.startInsertLink(s);
        enhancedEditor.startInsertImages(s);
        enhancedEditor.betterTabKey(s);
        enhancedEditor.keyboardShortcuts(s);

        $(s).before(" Insert code (Ace editor) | Find & Replace | Auto correct");

        $('#startAce').click(function(e) {
            enhancedEditor.startAceEditor(s);
            e.preventDefault();
            e.stopPropagation();
        });
        $('#findReplace').click(function(e) {
            enhancedEditor.findReplace($(this).parent().attr('id').split('|')[1]);
            e.preventDefault();
            e.stopPropagation();
        });
        $('#autoCorrect').click(function(e) {
            enhancedEditor.autoCorrect($(this).parent().attr('id').split('|')[1]);
            e.preventDefault();
            e.stopPropagation();
        });
        $(document).on('click', '.enhancedEditor-closeDialog', function() {
            $(this).parent().hide();
        });

        $(document).click(function(event) {
            //doesn't work with #enhancedEditor-aceEditor for some reason... so skip it
            if(!$(event.target).closest('#enhancedEditor-insertLinkDialog, #enhancedEditor-insertImageDialog').length) {
                $('#enhancedEditor-insertLinkDialog, #enhancedEditor-insertImageDialog').hide()
            }
        });
    },

    startAceEditor: function(s) {
        var aceDiv = "
 \
              <select class='enhancedEditor-aceLanguages'></select>\
              <button class='enhancedEditor-addCode'>Add code</button>\
              x\

Ace Editor
\

\

";

        var languages = {
            'CoffeeScript': 'coffee',
            'CSS': 'css',
            'HTML': 'html',
            'JavaScript': 'javascript',
            'JSON': 'json',
            'PHP': 'php',
            'XML': 'xml',
            'AppleScript': 'applescript',
            'Cobol': 'cobol',
            'C#': 'csharp',
            'Python': 'python',
            'Ruby': 'ruby'
        };

        $('body').append(aceDiv);

        $.each(languages, function (lang, file) {
            $('select.enhancedEditor-aceLanguages').append("<option value='"+file+"'>"+lang+"</option>");
        });

        $('select.enhancedEditor-aceLanguages option[value="javascript"]').prop('selected', true);
        setTimeout(function() {
            editor = ace.edit("editor");
            editor.setTheme("ace/theme/github");
            editor.getSession().setMode("ace/mode/javascript");
            editor.setOptions({
                enableBasicAutocompletion: true,
                enableSnippets: true,
                enableLiveAutocompletion: true
            });
        }, 2000);

        $('select.enhancedEditor-aceLanguages').on('change', function() {
            editor = ace.edit("editor");
            editor.getSession().setMode("ace/mode/"+$(this).val());
        });

        $(document).on('click', '.enhancedEditor-addCode', function() {
            editor = ace.edit("editor");
            code = editor.getSession().getValue();
            var codeToAdd = '',
                gap = "    ",
                lines = code.split("\n"),
                pos = $(s).textrange('get', 'position'),
                oldVal = $(s).val();

            for(i = 0; i < lines.length; i++) {
                codeToAdd += gap + lines[i] + '\n';
            }

            //http://stackoverflow.com/a/15977052/3541881:
            $(s).val(oldVal.substring(0, pos) + codeToAdd + oldVal.substring(pos));

            enhancedEditor.refreshPreview();
        });
    },

    startInsertLink: function(s) {
        var linkDiv = "
 \
              x\

Insert link
\

\

Enter URL:\
                      <input class='ownURL' type='url' value='http://' />\
                      <input class='go' id='ownGo' type='button' value='insert' />\

\

\

\

\

\

\
                              <input class='go' id='suggestGo' type='button' value='insert' />\

\

\

\

\

\

Results from DuckDuckGo\

\

\

\

";
        $('body').append(linkDiv);

        setTimeout(function() {
            $('#wmd-link-button > span').click(function(e) {
                $('#DDG-header').html('');
                $('#DDG-text').html('');
                $('#DDG-credit a').attr('href', 'http://google.com');
                $('#enhancedEditor-insertLinkDialog').show(500);
                setTimeout(function () {
                    query = $(s).textrange();

                    $.getJSON("http://api.duckduckgo.com/?q=" + query.text + "&format=json&t=stackExchangeEditorPro&callback=?", function (json) {
                        $('#DDG-header').append("" + json.Heading + "");
                        $('#DDG-text').append(json.Abstract);
                        $('.DDG-credit a').attr('href', json.AbstractURL);
                    });

                    $('#ownGo').click(function() {
                        enhancedEditor.addLink(query, $(this).prev().val(), s);
                    });
                    $('#suggestGo').click(function() {
                        enhancedEditor.addLink(query, $('#DDG-header a').attr('href'), s);
                    });
                }, 1000);
                e.stopPropagation();
                e.preventDefault();
                return false;
            });
        }, 3000);
    },

    startInsertImages: function(s) {
        var imagesDiv = "
 \
              x\

Insert image
\

\

Select file:\
                      <input class='ownImage' type='file' />\
                      <input class='go' id='ownGoImage' type='button' value='insert' />\
                      <input type='checkbox' id='enhancedEditor-imageAsLink'>Insert smaller image with link to bigger?\

\

\

\

Enter URL:\
                      <input class='URLImage' type='url' value='http://' />\
                      <input class='go' id='goImage' type='button' value='insert' />\
                      <input type='checkbox' id='enhancedEditor-imageAsLink'>Insert smaller image with link to bigger?\

\

\

";
        $('body').append(imagesDiv);

        setTimeout(function() {
            $('#wmd-image-button > span').click(function(e) {
                $('#enhancedEditor-insertImageDialog').show(500);
                setTimeout(function () {
                    query = $(s).textrange();

                    $('#ownGoImage').click(function() {
                        $check = $(this).next();
                        enhancedEditor.uploadToImgur('file', $(this).prev(), function(url) {
                            enhancedEditor.addImageLink(query, url, $check, s);
                        });
                    });
                    $('#goImage').click(function() {
                        $check = $(this).next();
                        enhancedEditor.uploadToImgur('url', $(this).prev(), function(url) {
                            enhancedEditor.addImageLink(query, url, $check, s);
                        });
                    });
                }, 1000);
                e.stopPropagation();
                e.preventDefault();
                return false;
            });
        }, 3000);
    },

    betterTabKey: function(s) {
        $(s).on('keydown', function(e) {
            if(e.keyCode == 9) {
                pos = $(s).textrange('get', 'position');
                oldVal = $(s).val();

                //http://stackoverflow.com/a/15977052/3541881:
                $(s).val(oldVal.substring(0, pos) + '\t' + oldVal.substring(pos));

                return false;
                e.preventDefault();
            }
        });
    },

    findReplace: function(s) {
        $(s).prev().after("
<input id='find' type='text' placeholder='Find'><input id='modifier' type='text' placeholder='Modifier'><input id='replace' type='text' placeholder='Replace with'><input id='replaceGo' type='button' value='Go'>
");
        $(document).on('click', '.findReplace #replaceGo', function() {
            regex = new RegExp($('.findReplace #find').val(), $('.findReplace #modifier').val());
            oldval = $(s).val();
            newval = oldval.replace(regex, $('.findReplace #replace').val());
            $(s).val(newval);
            enhancedEditor.refreshPreview();
        });
    },

    autoCorrect: function(s) {
        var oldVal = $(s).val();
        var newVal = oldVal.replace(/\bi\b/g, "I") //capitalise 'I'
        .replace(/\.\.\.*/gi, "...") //truncate elipses
        .replace(/(?!\.\.\.*)([,.!?;:])(\S)/g, "$1 $2") //add space after punctuation
        .replace(/\s(\?|!)/g, "$1") //remove space before !/?
        .replace(/\bwud\b/gi, "would") //wud->would
        .replace(/\bcant\b/gi, "can't") //cant->can't
        .replace(/\bcud\b/gi, "could") //cud->could
        .replace(/\bwont\b/gi, "won't") //wont->won't
        .replace(/\bshud\b/gi, "should") //shud->should
        .replace(/\b(plz|pls)\b/gi, "please") //plz/pls->please
        .replace(/\bim\b/gi, "I'm") //im->I'm
        .replace(/\bu\b/gi, "you") //u->you
        .replace(/\bure?\b/gi, "your") //ur(e)->your
        .replace(/(^.)/gm,  function (txt) { //Capitalise new line first character
            return txt.toUpperCase();
        })
        .replace(/.+?[\.\?\!](\s|$)/g,  function (txt) { //Fix capitalisation. http://stackoverflow.com/a/20442069/3541881
            return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
        });
        $(s).val(newVal);

        enhancedEditor.refreshPreview();
    },

    addLink: function(query, url, s) {
        $(s).textrange('replace', '['+query.text+']('+url+')');
        $('#enhancedEditor-insertLinkDialog').hide();
        enhancedEditor.refreshPreview();
    },

    keyboardShortcuts: function(s) {
        $(s).bind('keydown', 'alt+a', function() { //ace editor
            $('#enhancedEditor-aceEditor').show(500);
        });
        $(s).bind('keydown', 'alt+f', function() { //find replace
            $('#findReplace').trigger('click');
        });

        //Replace default SE bindings
        $(document).keydown(function(e) {
            if(e.which == 71 && e.ctrlKey) { //alt+g (images)
                $('#enhancedEditor-insertImageDialog').show(500);
                e.stopPropagation();
                e.preventDefault();
                return false;
            }
            if(e.which == 76 && e.ctrlKey) { //alt+l (links)
                $('#enhancedEditor-insertLinkDialog').show(500);
                e.stopPropagation();
                e.preventDefault();
                return false;
            }
        });
    },

    uploadToImgur: function(type, $fileData, callback) {
        var formData = new FormData(),
            data = '';
        if (type=='file') {
            formData.append("image", $fileData[0].files[0]);
        } else {
            data = $fileData.val();
        }

        $.ajax({
            url: "https://api.imgur.com/3/image",
            type: "POST",
            headers: {
                'Authorization': 'Client-ID 1ebf24e58286774'
            },
            data: (type=='file' ? formData : data),
            success: function(response) {
                callback(response.data.link);
            },
            processData: false,
            contentType: false
        });

    },

    addImageLink: function(query, url, $check, s) {
        if($check.find('input').is(':checked')) {
            urlsplit = url.split('/')[3].split('.');
            urlToUse = 'http://i.imgur.com/'+urlsplit[0]+'m.'+urlsplit[1];
            $(s).textrange('replace', '[!['+query.text+']('+urlToUse+')]('+url+')\n\nclick image for larger variant');
        } else {
            $(s).textrange('replace', '!['+query.text+']('+url+')');
        }
        $('#enhancedEditor-insertImageDialog').hide();
        enhancedEditor.refreshPreview();
    },

    refreshPreview: function() {
        StackExchange.MarkdownEditor.refreshAllPreviews();
    }
};
<commit_msg>Update sox.enhancedEditor.js<commit_after>var enhancedEditor = {
    startFeature: function() {
        setTimeout(function() {
            $.each($('textarea[id^="wmd-input"].processed'), function() {
                enhancedEditor.init($(this).attr('id'));
            });

            $('.edit-post').click(function() {
                $that = $(this);
                setTimeout(function() {
                    enhancedEditor.init($that.parents('table').find('.inline-editor textarea.processed').attr('id'));
                }, 2000);
            });
        }, 2000);
    },

    init: function(wmd) {
        var urls = ['http://cdn.rawgit.com/dwieeb/jquery-textrange/1.x/jquery-textrange.js',
            'http://rawgit.com/ajaxorg/ace-builds/master/src-noconflict/ace.js',
            'http://rawgit.com/ajaxorg/ace-builds/master/src-noconflict/ext-language_tools.js',
            'http://rawgit.com/ajaxorg/ace-builds/master/src-noconflict/theme-github.js',
            'http://rawgit.com/ajaxorg/ace-builds/master/src-noconflict/mode-javascript.js',
            'http://rawgit.com/ajaxorg/ace-builds/master/src-noconflict/snippets/javascript.js'];

        for (var i = 0; i < urls.length; i++) {
            script = document.createElement('script');
            script.src = urls[i];
            document.head.appendChild(script);
        }
        $('head').append("<link rel='stylesheet' type='text/css' href='https://rawgit.com/soscripted/sox/experimental/enhancedEditor/sox.enhancedEditor.css' />");

        $('[id^="enhancedEditor"]').remove();
        var s = '#'+wmd; //s is the selector we pass onto each function so the action is applied to the correct textarea (and not, for example the 'add answer' textarea *and* the 'edit' textarea!)
        enhancedEditor.startInsertLink(s);
        enhancedEditor.startInsertImages(s);
        enhancedEditor.betterTabKey(s);
        enhancedEditor.keyboardShortcuts(s);

        $(s).before(" Insert code (Ace editor) | Find & Replace | Auto correct");

        $('#startAce').click(function(e) {
            enhancedEditor.startAceEditor(s);
            e.preventDefault();
            e.stopPropagation();
        });
        $('#findReplace').click(function(e) {
            enhancedEditor.findReplace($(this).parent().attr('id').split('|')[1]);
            e.preventDefault();
            e.stopPropagation();
        });
        $('#autoCorrect').click(function(e) {
            enhancedEditor.autoCorrect($(this).parent().attr('id').split('|')[1]);
            e.preventDefault();
            e.stopPropagation();
        });
        $(document).on('click', '.enhancedEditor-closeDialog', function() {
            $(this).parent().hide();
        });

        $(document).click(function(event) {
            //doesn't work with #enhancedEditor-aceEditor for some reason... so skip it
            if(!$(event.target).closest('#enhancedEditor-insertLinkDialog, #enhancedEditor-insertImageDialog').length) {
                $('#enhancedEditor-insertLinkDialog, #enhancedEditor-insertImageDialog').hide()
            }
        });
    },

    startAceEditor: function(s) {
        var aceDiv = "
 \
              <select class='enhancedEditor-aceLanguages'></select>\
              <button class='enhancedEditor-addCode'>Add code</button>\
              x\

Ace Editor
\

\

";

        var languages = {
            'CoffeeScript': 'coffee',
            'CSS': 'css',
            'HTML': 'html',
            'JavaScript': 'javascript',
            'JSON': 'json',
            'PHP': 'php',
            'XML': 'xml',
            'AppleScript': 'applescript',
            'Cobol': 'cobol',
            'C#': 'csharp',
            'Python': 'python',
            'Ruby': 'ruby'
        };

        $('body').append(aceDiv);

        $.each(languages, function (lang, file) {
            $('select.enhancedEditor-aceLanguages').append("<option value='"+file+"'>"+lang+"</option>");
        });

        $('select.enhancedEditor-aceLanguages option[value="javascript"]').prop('selected', true);
        setTimeout(function() {
            editor = ace.edit("editor");
            editor.setTheme("ace/theme/github");
            editor.getSession().setMode("ace/mode/javascript");
            editor.setOptions({
                enableBasicAutocompletion: true,
                enableSnippets: true,
                enableLiveAutocompletion: true
            });
        }, 2000);

        $('select.enhancedEditor-aceLanguages').on('change', function() {
            editor = ace.edit("editor");
            editor.getSession().setMode("ace/mode/"+$(this).val());
        });

        $(document).on('click', '.enhancedEditor-addCode', function() {
            editor = ace.edit("editor");
            code = editor.getSession().getValue();
            var codeToAdd = '',
                gap = "    ",
                lines = code.split("\n"),
                pos = $(s).textrange('get', 'position'),
                oldVal = $(s).val();

            for(i = 0; i < lines.length; i++) {
                codeToAdd += gap + lines[i] + '\n';
            }

            //http://stackoverflow.com/a/15977052/3541881:
            $(s).val(oldVal.substring(0, pos) + codeToAdd + oldVal.substring(pos));

            enhancedEditor.refreshPreview();
        });
    },

    startInsertLink: function(s) {
        var linkDiv = "
 \
              x\

Insert link
\

\

Enter URL:\
                      <input class='ownURL' type='url' value='http://' />\
                      <input class='go' id='ownGo' type='button' value='insert' />\

\

\

\

\

\

\
                              <input class='go' id='suggestGo' type='button' value='insert' />\

\

\

\

\

\

Results from DuckDuckGo\

\

\

\

";
        $('body').append(linkDiv);

        setTimeout(function() {
            $('#wmd-link-button > span').click(function(e) {
                $('#DDG-header').html('');
                $('#DDG-text').html('');
                $('#DDG-credit a').attr('href', 'http://google.com');
                $('#enhancedEditor-insertLinkDialog').show(500);
                setTimeout(function () {
                    query = $(s).textrange();

                    $.getJSON("http://api.duckduckgo.com/?q=" + query.text + "&format=json&t=stackExchangeEditorPro&callback=?", function (json) {
                        $('#DDG-header').append("" + json.Heading + "");
                        $('#DDG-text').append(json.Abstract);
                        $('.DDG-credit a').attr('href', json.AbstractURL);
                    });

                    $('#ownGo').click(function() {
                        enhancedEditor.addLink(query, $(this).prev().val(), s);
                    });
                    $('#suggestGo').click(function() {
                        enhancedEditor.addLink(query, $('#DDG-header a').attr('href'), s);
                    });
                }, 1000);
                e.stopPropagation();
                e.preventDefault();
                return false;
            });
        }, 3000);
    },

    startInsertImages: function(s) {
        var imagesDiv = "
 \
              x\

Insert image
\

\

Select file:\
                      <input class='ownImage' type='file' />\
                      <input class='go' id='ownGoImage' type='button' value='insert' />\
                      <input type='checkbox' id='enhancedEditor-imageAsLink'>Insert smaller image with link to bigger?\

\

\

\

Enter URL:\
                      <input class='URLImage' type='url' value='http://' />\
                      <input class='go' id='goImage' type='button' value='insert' />\
                      <input type='checkbox' id='enhancedEditor-imageAsLink'>Insert smaller image with link to bigger?\

\

\

";
        $('body').append(imagesDiv);

        setTimeout(function() {
            $('#wmd-image-button > span').click(function(e) {
                $('#enhancedEditor-insertImageDialog').show(500);
                setTimeout(function () {
                    query = $(s).textrange();

                    $('#ownGoImage').click(function() {
                        $check = $(this).next();
                        enhancedEditor.uploadToImgur('file', $(this).prev(), function(url) {
                            enhancedEditor.addImageLink(query, url, $check, s);
                        });
                    });
                    $('#goImage').click(function() {
                        $check = $(this).next();
                        enhancedEditor.uploadToImgur('url', $(this).prev(), function(url) {
                            enhancedEditor.addImageLink(query, url, $check, s);
                        });
                    });
                }, 1000);
                e.stopPropagation();
                e.preventDefault();
                return false;
            });
        }, 3000);
    },

    betterTabKey: function(s) {
        $(s).on('keydown', function(e) {
            if (keyCode === 9) { //http://stackoverflow.com/a/25430815/3541881
                e.preventDefault();
                var start = this.selectionStart;
                var end = this.selectionEnd;
                var val = this.value;
                var selected = val.substring(start, end);
                var re = /^/gm;
                var count = selected.match(re).length;

                this.value = val.substring(0, start) + selected.replace(re, '\t') + val.substring(end);
                this.selectionStart = start;
                this.selectionEnd = end + count;
            }
        });
    },

    findReplace: function(s) {
        $(s).prev().after("
<input id='find' type='text' placeholder='Find'><input id='modifier' type='text' placeholder='Modifier'><input id='replace' type='text' placeholder='Replace with'><input id='replaceGo' type='button' value='Go'>
");
        $(document).on('click', '.findReplace #replaceGo', function() {
            regex = new RegExp($('.findReplace #find').val(), $('.findReplace #modifier').val());
            oldval = $(s).val();
            newval = oldval.replace(regex, $('.findReplace #replace').val());
            $(s).val(newval);
            enhancedEditor.refreshPreview();
        });
    },

    autoCorrect: function(s) {
        var oldVal = $(s).val();
        var newVal = oldVal.replace(/\bi\b/g, "I") //capitalise 'I'
        .replace(/\.\.\.*/gi, "...") //truncate elipses
        .replace(/(?!\.\.\.*)([,.!?;:])(\S)/g, "$1 $2") //add space after punctuation
        .replace(/\s(\?|!)/g, "$1") //remove space before !/?
        .replace(/\bwud\b/gi, "would") //wud->would
        .replace(/\bcant\b/gi, "can't") //cant->can't
        .replace(/\bcud\b/gi, "could") //cud->could
        .replace(/\bwont\b/gi, "won't") //wont->won't
        .replace(/\bshud\b/gi, "should") //shud->should
        .replace(/\b(plz|pls)\b/gi, "please") //plz/pls->please
        .replace(/\bim\b/gi, "I'm") //im->I'm
        .replace(/\bu\b/gi, "you") //u->you
        .replace(/\bure?\b/gi, "your") //ur(e)->your
        .replace(/(^.)/gm,  function (txt) { //Capitalise new line first character
            return txt.toUpperCase();
        })
        .replace(/.+?[\.\?\!](\s|$)/g,  function (txt) { //Fix capitalisation. http://stackoverflow.com/a/20442069/3541881
            return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
        });
        $(s).val(newVal);

        enhancedEditor.refreshPreview();
    },

    addLink: function(query, url, s) {
        $(s).textrange('replace', '['+query.text+']('+url+')');
        $('#enhancedEditor-insertLinkDialog').hide();
        enhancedEditor.refreshPreview();
    },

    keyboardShortcuts: function(s) {
        //Replace default SE bindings
        $(document).keydown(function(e) {
            if(e.which == 71 && e.ctrlKey) { //ctrl+g (images)
                $('#enhancedEditor-insertImageDialog').show(500);
                e.stopPropagation();
                e.preventDefault();
                return false;
            }
            if(e.which == 76 && e.ctrlKey) { //ctrl+l (links)
                $('#enhancedEditor-insertLinkDialog').show(500);
                e.stopPropagation();
                e.preventDefault();
                return false;
            }
         });
         $(s).keydown(function(e) {
            if(e.which == 65 && e.ctrlKey) { //ctrl+a (ace editor)
                $('#enhancedEditor-aceEditor').show(500);
                e.stopPropagation();
                e.preventDefault();
                return false;
            }
            if(e.which == 70 && e.ctrlKey) { //ctrl+f (find+replace)
                $('#findReplace').trigger('click');
                e.stopPropagation();
                e.preventDefault();
                return false;
            }
        });
    },

    uploadToImgur: function(type, $fileData, callback) {
        var formData = new FormData(),
            data = '';
        if (type=='file') {
            formData.append("image", $fileData[0].files[0]);
        } else {
            data = $fileData.val();
        }

        $.ajax({
            url: "https://api.imgur.com/3/image",
            type: "POST",
            headers: {
                'Authorization': 'Client-ID 1ebf24e58286774'
            },
            data: (type=='file' ? formData : data),
            success: function(response) {
                callback(response.data.link);
            },
            processData: false,
            contentType: false
        });

    },

    addImageLink: function(query, url, $check, s) {
        if($check.find('input').is(':checked')) {
            urlsplit = url.split('/')[3].split('.');
            urlToUse = 'http://i.imgur.com/'+urlsplit[0]+'m.'+urlsplit[1];
            $(s).textrange('replace', '[!['+query.text+']('+urlToUse+')]('+url+')\n\nclick image for larger variant');
        } else {
            $(s).textrange('replace', '!['+query.text+']('+url+')');
        }
        $('#enhancedEditor-insertImageDialog').hide();
        enhancedEditor.refreshPreview();
    },

    refreshPreview: function() {
        StackExchange.MarkdownEditor.refreshAllPreviews();
    }
};
<|endoftext|>


<commit_before>/*!
 * viewport-units-buggyfill v0.6.1
 * @web: https://github.com/rodneyrehm/viewport-units-buggyfill/
 * @author: Rodney Rehm - http://rodneyrehm.de/en/
 */

(function() {
  (function(root, factory) {
    'use strict';
    if (typeof define === 'function' && define.amd) {
      // AMD. Register as an anonymous module.
      define([], factory);
    } else if (typeof exports === 'object') {
      // Node. Does not work with strict CommonJS, but
      // only CommonJS-like enviroments that support module.exports,
      // like Node.
      module.exports = factory();
    } else {
      // Browser globals (root is window)
      root.viewportUnitsBuggyfill = factory();
    }
  }(this, function() {
    'use strict';
    /* global document, window, navigator, location, XMLHttpRequest, XDomainRequest, CustomEvent */

    var initialized = false;
    var options;
    var userAgent = window.navigator.userAgent;
    var viewportUnitExpression = /([+-]?[0-9.]+)(vh|vw|vmin|vmax)/g;
    var forEach = [].forEach;
    var dimensions;
    var declarations;
    var styleNode;
    var isBuggyIE = /MSIE [0-9]\./i.test(userAgent);
    var isOldIE = /MSIE [0-8]\./i.test(userAgent);
    var isOperaMini = userAgent.indexOf('Opera Mini') > -1;

    var isMobileSafari = /(iPhone|iPod|iPad).+AppleWebKit/i.test(userAgent) && (function() {
      // Regexp for iOS-version tested against the following userAgent strings:
      // Example WebView UserAgents:
      // * iOS Chrome on iOS8: "Mozilla/5.0 (iPad; CPU OS 8_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) CriOS/39.0.2171.50 Mobile/12B410 Safari/600.1.4"
      // * iOS Facebook on iOS7: "Mozilla/5.0 (iPhone; CPU iPhone OS 7_1_1 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Mobile/11D201 [FBAN/FBIOS;FBAV/12.1.0.24.20; FBBV/3214247; FBDV/iPhone6,1;FBMD/iPhone; FBSN/iPhone OS;FBSV/7.1.1; FBSS/2; FBCR/AT&T;FBID/phone;FBLC/en_US;FBOP/5]"
      // Example Safari UserAgents:
      // * Safari iOS8: "Mozilla/5.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/600.1.3 (KHTML, like Gecko) Version/8.0 Mobile/12A4345d Safari/600.1.4"
      // * Safari iOS7: "Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A4449d Safari/9537.53"
      var iOSversion = userAgent.match(/OS (\d)/);
      // viewport units work fine in mobile Safari and webView on iOS 8+
      return iOSversion && iOSversion.length > 1 && parseInt(iOSversion[1]) < 10;
    })();

    var isBadStockAndroid = (function() {
      // Android stock browser test derived from
      // http://stackoverflow.com/questions/24926221/distinguish-android-chrome-from-stock-browser-stock-browsers-user-agent-contai
      var isAndroid = userAgent.indexOf(' Android ') > -1;
      if (!isAndroid) {
        return false;
      }

      var isStockAndroid = userAgent.indexOf('Version/') > -1;
      if (!isStockAndroid) {
        return false;
      }

      var versionNumber = parseFloat((userAgent.match('Android ([0-9.]+)') || [])[1]);
      // anything below 4.4 uses WebKit without *any* viewport support,
      // 4.4 has issues with viewport units within calc()
      return versionNumber <= 4.4;
    })();

    // added check for IE10, IE11 and Edge < 20, since it *still* doesn't understand vmax
    // http://caniuse.com/#feat=viewport-units
    if (!isBuggyIE) {
      isBuggyIE = !!navigator.userAgent.match(/MSIE 10\.|Trident.*rv[ :]*1[01]\.| Edge\/1\d\./);
    }

    // Polyfill for creating CustomEvents on IE9/10/11
    // from https://github.com/krambuhl/custom-event-polyfill
    try {
      // eslint-disable-next-line no-new, no-use-before-define
      new CustomEvent('test');
    } catch (e) {
      var CustomEvent = function(event, params) {
        var evt;
        params = params || {
          bubbles: false,
          cancelable: false,
          detail: undefined,
        };

        evt = document.createEvent('CustomEvent');
        evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
        return evt;
      };
      CustomEvent.prototype = window.Event.prototype;
      window.CustomEvent = CustomEvent; // expose definition to window
    }

    function debounce(func, wait) {
      var timeout;
      return function() {
        var context = this;
        var args = arguments;
        var callback = function() {
          func.apply(context, args);
        };

        clearTimeout(timeout);
        timeout = setTimeout(callback, wait);
      };
    }

    // from http://stackoverflow.com/questions/326069/how-to-identify-if-a-webpage-is-being-loaded-inside-an-iframe-or-directly-into-t
    function inIframe() {
      try {
        return window.self !== window.top;
      } catch (e) {
        return true;
      }
    }

    function initialize(initOptions) {
      if (initialized) {
        return;
      }

      if (initOptions === true) {
        initOptions = {
          force: true,
        };
      }

      options = initOptions || {};
      options.isMobileSafari = isMobileSafari;
      options.isBadStockAndroid = isBadStockAndroid;

      if (options.ignoreVmax && !options.force && !isOldIE) {
        // modern IE (10 and up) do not support vmin/vmax,
        // but chances are this unit is not even used, so
        // allow overwriting the "hacktivation"
        // https://github.com/rodneyrehm/viewport-units-buggyfill/issues/56
        isBuggyIE = false;
      }

      if (isOldIE || (!options.force && !isMobileSafari && !isBuggyIE && !isBadStockAndroid && !isOperaMini && (!options.hacks || !options.hacks.required(options)))) {
        // this buggyfill only applies to mobile safari, IE9-10 and the Stock Android Browser.
        if (window.console && isOldIE) {
          console.info('viewport-units-buggyfill requires a proper CSSOM and basic viewport unit support, which are not available in IE8 and below');
        }

        return {
          init: function() {},
        };
      }

      // fire a custom event that buggyfill was initialize
      window.dispatchEvent(new CustomEvent('viewport-units-buggyfill-init'));

      options.hacks && options.hacks.initialize(options);

      initialized = true;
      styleNode = document.createElement('style');
      styleNode.id = 'patched-viewport';
      document.head.appendChild(styleNode);

      // Issue #6: Cross Origin Stylesheets are not accessible through CSSOM,
      // therefore download and inject them as <style> to circumvent SOP.
      importCrossOriginLinks(function() {
        var _refresh = debounce(refresh, options.refreshDebounceWait || 100);
        // doing a full refresh rather than updateStyles because an orientationchange
        // could activate different stylesheets
        window.addEventListener('orientationchange', _refresh, true);
        // orientationchange might have happened while in a different window
        window.addEventListener('pageshow', _refresh, true);

        if (options.force || isBuggyIE || inIframe()) {
          window.addEventListener('resize', _refresh, true);
          options._listeningToResize = true;
        }

        options.hacks && options.hacks.initializeEvents(options, refresh, _refresh);

        refresh();
      });
    }

    function updateStyles() {
      styleNode.textContent = getReplacedViewportUnits();
      // move to the end in case inline <style>s were added dynamically
      styleNode.parentNode.appendChild(styleNode);
      // fire a custom event that styles were updated
      window.dispatchEvent(new CustomEvent('viewport-units-buggyfill-style'));
    }

    function refresh() {
      if (!initialized) {
        return;
      }

      findProperties();

      // iOS Safari will report window.innerWidth and .innerHeight as 0 unless a timeout is used here.
      // TODO: figure out WHY innerWidth === 0
      setTimeout(function() {
        updateStyles();
      }, 1);
    }

    // http://stackoverflow.com/a/23613052
    function processStylesheet(ss) {
      // cssRules respects same-origin policy, as per
      // https://code.google.com/p/chromium/issues/detail?id=49001#c10.
      try {
        if (!ss.cssRules) { return; }
      } catch (e) {
        if (e.name !== 'SecurityError') { throw e; }
        return;
      }
      // ss.cssRules is available, so proceed with desired operations.
      var rules = [];
      for (var i = 0; i < ss.cssRules.length; i++) {
        var rule = ss.cssRules[i];
        rules.push(rule);
      }
      return rules;
    }

    function findProperties() {
      declarations = [];
      forEach.call(document.styleSheets, function(sheet) {
        var cssRules = processStylesheet(sheet);

        if (!cssRules || sheet.ownerNode.id === 'patched-viewport' || sheet.ownerNode.getAttribute('data-viewport-units-buggyfill') === 'ignore') {
          // skip entire sheet because no rules are present, it's supposed to be ignored or it's the target-element of the buggyfill
          return;
        }

        if (sheet.media && sheet.media.mediaText && window.matchMedia && !window.matchMedia(sheet.media.mediaText).matches) {
          // skip entire sheet because media attribute doesn't match
          return;
        }

        forEach.call(cssRules, findDeclarations);
      });

      return declarations;
    }

    function findDeclarations(rule) {
      if (rule.type === 7) {
        var value;

        // there may be a case where accessing cssText throws an error.
        // I could not reproduce this issue, but the worst that can happen
        // this way is an animation not running properly.
        // not awesome, but probably better than a script error
        // see https://github.com/rodneyrehm/viewport-units-buggyfill/issues/21
        try {
          value = rule.cssText;
        } catch (e) {
          return;
        }

        viewportUnitExpression.lastIndex = 0;
        if (viewportUnitExpression.test(value)) {
          // KeyframesRule does not have a CSS-PropertyName
          declarations.push([rule, null, value]);
          options.hacks && options.hacks.findDeclarations(declarations, rule, null, value);
        }

        return;
      }

      if (!rule.style) {
        if (!rule.cssRules) {
          return;
        }

        forEach.call(rule.cssRules, function(_rule) {
          findDeclarations(_rule);
        });

        return;
      }

      forEach.call(rule.style, function(name) {
        var value = rule.style.getPropertyValue(name);
        // preserve those !important rules
        if (rule.style.getPropertyPriority(name)) {
          value += ' !important';
        }

        viewportUnitExpression.lastIndex = 0;
        if (viewportUnitExpression.test(value)) {
          declarations.push([rule, name, value]);
          options.hacks && options.hacks.findDeclarations(declarations, rule, name, value);
        }
      });
    }

    function getReplacedViewportUnits() {
      dimensions = getViewport();

      var css = [];
      var buffer = [];
      var open;
      var close;

      declarations.forEach(function(item) {
        var _item = overwriteDeclaration.apply(null, item);
        var _open = _item.selector.length ? (_item.selector.join(' {\n') + ' {\n') : '';
        var _close = new Array(_item.selector.length + 1).join('\n}');

        if (!_open || _open !== open) {
          if (buffer.length) {
            css.push(open + buffer.join('\n') + close);
            buffer.length = 0;
          }

          if (_open) {
            open = _open;
            close = _close;
            buffer.push(_item.content);
          } else {
            css.push(_item.content);
            open = null;
            close = null;
          }

          return;
        }

        if (_open && !open) {
          open = _open;
          close = _close;
        }

        buffer.push(_item.content);
      });

      if (buffer.length) {
        css.push(open + buffer.join('\n') + close);
      }

      // Opera Mini messes up on the content hack (it replaces the DOM node's innerHTML with the value).
      // This fixes it. We test for Opera Mini only since it is the most expensive CSS selector
      // see https://developer.mozilla.org/en-US/docs/Web/CSS/Universal_selectors
      if (isOperaMini) {
        css.push('* { content: normal !important; }');
      }

      return css.join('\n\n');
    }

    function overwriteDeclaration(rule, name, value) {
      var _value;
      var _selectors = [];

      _value = value.replace(viewportUnitExpression, replaceValues);

      if (options.hacks) {
        _value = options.hacks.overwriteDeclaration(rule, name, _value);
      }

      if (name) {
        // skipping KeyframesRule
        _selectors.push(rule.selectorText);
        _value = name + ': ' + _value + ';';
      }

      var _rule = rule.parentRule;
      while (_rule) {
        if (_rule.media) {
          _selectors.unshift('@media ' + _rule.media.mediaText);
        } else if (_rule.conditionText) {
          _selectors.unshift('@supports ' + _rule.conditionText);
        }

        _rule = _rule.parentRule;
      }

      return {
        selector: _selectors,
        content: _value,
      };
    }

    function replaceValues(match, number, unit) {
      var _base = dimensions[unit];
      var _number = parseFloat(number) / 100;
      return (_number * _base) + 'px';
    }

    function getViewport() {
      var vh = window.innerHeight;
      var vw = window.innerWidth;

      return {
        vh: vh,
        vw: vw,
        vmax: Math.max(vw, vh),
        vmin: Math.min(vw, vh),
      };
    }

    function importCrossOriginLinks(next) {
      var _waiting = 0;
      var decrease = function() {
        _waiting--;
        if (!_waiting) {
          next();
        }
      };

      forEach.call(document.styleSheets, function(sheet) {
        if (!sheet.href || origin(sheet.href) === origin(location.href) || sheet.ownerNode.getAttribute('data-viewport-units-buggyfill') === 'ignore') {
          // skip <style> and <link> from same origin or explicitly declared to ignore
          return;
        }

        _waiting++;
        convertLinkToStyle(sheet.ownerNode, decrease);
      });

      if (!_waiting) {
        next();
      }
    }

    function origin(url) {
      return url.slice(0, url.indexOf('/', url.indexOf('://') + 3));
    }

    function convertLinkToStyle(link, next) {
      getCors(link.href, function() {
        var style = document.createElement('style');
        style.media = link.media;
        style.setAttribute('data-href', link.href);
        style.textContent = this.responseText;
        link.parentNode.replaceChild(style, link);
        next();
      }, next);
    }

    function getCors(url, success, error) {
      var xhr = new XMLHttpRequest();
      if ('withCredentials' in xhr) {
        // XHR for Chrome/Firefox/Opera/Safari.
        xhr.open('GET', url, true);
      } else if (typeof XDomainRequest !== 'undefined') {
        // XDomainRequest for IE.
        xhr = new XDomainRequest();
        xhr.open('GET', url);
      } else {
        throw new Error('cross-domain XHR not supported');
      }

      xhr.onload = success;
      xhr.onerror = error;
      xhr.send();
      return xhr;
    }

    return {
      version: '0.6.1',
      findProperties: findProperties,
      getCss: getReplacedViewportUnits,
      init: initialize,
      refresh: refresh,
    };
  }));
})();
<commit_msg>fix(polyfill): do not consider URLs viable values for running the polyfill. (#78)<commit_after>/*!
 * viewport-units-buggyfill v0.6.1
 * @web: https://github.com/rodneyrehm/viewport-units-buggyfill/
 * @author: Rodney Rehm - http://rodneyrehm.de/en/
 */

(function() {
  (function(root, factory) {
    'use strict';
    if (typeof define === 'function' && define.amd) {
      // AMD. Register as an anonymous module.
      define([], factory);
    } else if (typeof exports === 'object') {
      // Node. Does not work with strict CommonJS, but
      // only CommonJS-like enviroments that support module.exports,
      // like Node.
      module.exports = factory();
    } else {
      // Browser globals (root is window)
      root.viewportUnitsBuggyfill = factory();
    }
  }(this, function() {
    'use strict';
    /* global document, window, navigator, location, XMLHttpRequest, XDomainRequest, CustomEvent */

    var initialized = false;
    var options;
    var userAgent = window.navigator.userAgent;
    var viewportUnitExpression = /([+-]?[0-9.]+)(vh|vw|vmin|vmax)/g;
    var urlExpression = /(https?:)?\/\//
    var forEach = [].forEach;
    var dimensions;
    var declarations;
    var styleNode;
    var isBuggyIE = /MSIE [0-9]\./i.test(userAgent);
    var isOldIE = /MSIE [0-8]\./i.test(userAgent);
    var isOperaMini = userAgent.indexOf('Opera Mini') > -1;

    var isMobileSafari = /(iPhone|iPod|iPad).+AppleWebKit/i.test(userAgent) && (function() {
      // Regexp for iOS-version tested against the following userAgent strings:
      // Example WebView UserAgents:
      // * iOS Chrome on iOS8: "Mozilla/5.0 (iPad; CPU OS 8_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) CriOS/39.0.2171.50 Mobile/12B410 Safari/600.1.4"
      // * iOS Facebook on iOS7: "Mozilla/5.0 (iPhone; CPU iPhone OS 7_1_1 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Mobile/11D201 [FBAN/FBIOS;FBAV/12.1.0.24.20; FBBV/3214247; FBDV/iPhone6,1;FBMD/iPhone; FBSN/iPhone OS;FBSV/7.1.1; FBSS/2; FBCR/AT&T;FBID/phone;FBLC/en_US;FBOP/5]"
      // Example Safari UserAgents:
      // * Safari iOS8: "Mozilla/5.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/600.1.3 (KHTML, like Gecko) Version/8.0 Mobile/12A4345d Safari/600.1.4"
      // * Safari iOS7: "Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A4449d Safari/9537.53"
      var iOSversion = userAgent.match(/OS (\d)/);
      // viewport units work fine in mobile Safari and webView on iOS 8+
      return iOSversion && iOSversion.length > 1 && parseInt(iOSversion[1]) < 10;
    })();

    var isBadStockAndroid = (function() {
      // Android stock browser test derived from
      // http://stackoverflow.com/questions/24926221/distinguish-android-chrome-from-stock-browser-stock-browsers-user-agent-contai
      var isAndroid = userAgent.indexOf(' Android ') > -1;
      if (!isAndroid) {
        return false;
      }

      var isStockAndroid = userAgent.indexOf('Version/') > -1;
      if (!isStockAndroid) {
        return false;
      }

      var versionNumber = parseFloat((userAgent.match('Android ([0-9.]+)') || [])[1]);
      // anything below 4.4 uses WebKit without *any* viewport support,
      // 4.4 has issues with viewport units within calc()
      return versionNumber <= 4.4;
    })();

    // added check for IE10, IE11 and Edge < 20, since it *still* doesn't understand vmax
    // http://caniuse.com/#feat=viewport-units
    if (!isBuggyIE) {
      isBuggyIE = !!navigator.userAgent.match(/MSIE 10\.|Trident.*rv[ :]*1[01]\.| Edge\/1\d\./);
    }

    // Polyfill for creating CustomEvents on IE9/10/11
    // from https://github.com/krambuhl/custom-event-polyfill
    try {
      // eslint-disable-next-line no-new, no-use-before-define
      new CustomEvent('test');
    } catch (e) {
      var CustomEvent = function(event, params) {
        var evt;
        params = params || {
          bubbles: false,
          cancelable: false,
          detail: undefined,
        };

        evt = document.createEvent('CustomEvent');
        evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
        return evt;
      };
      CustomEvent.prototype = window.Event.prototype;
      window.CustomEvent = CustomEvent; // expose definition to window
    }

    function debounce(func, wait) {
      var timeout;
      return function() {
        var context = this;
        var args = arguments;
        var callback = function() {
          func.apply(context, args);
        };

        clearTimeout(timeout);
        timeout = setTimeout(callback, wait);
      };
    }

    // from http://stackoverflow.com/questions/326069/how-to-identify-if-a-webpage-is-being-loaded-inside-an-iframe-or-directly-into-t
    function inIframe() {
      try {
        return window.self !== window.top;
      } catch (e) {
        return true;
      }
    }

    function initialize(initOptions) {
      if (initialized) {
        return;
      }

      if (initOptions === true) {
        initOptions = {
          force: true,
        };
      }

      options = initOptions || {};
      options.isMobileSafari = isMobileSafari;
      options.isBadStockAndroid = isBadStockAndroid;

      if (options.ignoreVmax && !options.force && !isOldIE) {
        // modern IE (10 and up) do not support vmin/vmax,
        // but chances are this unit is not even used, so
        // allow overwriting the "hacktivation"
        // https://github.com/rodneyrehm/viewport-units-buggyfill/issues/56
        isBuggyIE = false;
      }

      if (isOldIE || (!options.force && !isMobileSafari && !isBuggyIE && !isBadStockAndroid && !isOperaMini && (!options.hacks || !options.hacks.required(options)))) {
        // this buggyfill only applies to mobile safari, IE9-10 and the Stock Android Browser.
        if (window.console && isOldIE) {
          console.info('viewport-units-buggyfill requires a proper CSSOM and basic viewport unit support, which are not available in IE8 and below');
        }

        return {
          init: function() {},
        };
      }

      // fire a custom event that buggyfill was initialize
      window.dispatchEvent(new CustomEvent('viewport-units-buggyfill-init'));

      options.hacks && options.hacks.initialize(options);

      initialized = true;
      styleNode = document.createElement('style');
      styleNode.id = 'patched-viewport';
      document.head.appendChild(styleNode);

      // Issue #6: Cross Origin Stylesheets are not accessible through CSSOM,
      // therefore download and inject them as <style> to circumvent SOP.
      importCrossOriginLinks(function() {
        var _refresh = debounce(refresh, options.refreshDebounceWait || 100);
        // doing a full refresh rather than updateStyles because an orientationchange
        // could activate different stylesheets
        window.addEventListener('orientationchange', _refresh, true);
        // orientationchange might have happened while in a different window
        window.addEventListener('pageshow', _refresh, true);

        if (options.force || isBuggyIE || inIframe()) {
          window.addEventListener('resize', _refresh, true);
          options._listeningToResize = true;
        }

        options.hacks && options.hacks.initializeEvents(options, refresh, _refresh);

        refresh();
      });
    }

    function updateStyles() {
      styleNode.textContent = getReplacedViewportUnits();
      // move to the end in case inline <style>s were added dynamically
      styleNode.parentNode.appendChild(styleNode);
      // fire a custom event that styles were updated
      window.dispatchEvent(new CustomEvent('viewport-units-buggyfill-style'));
    }

    function refresh() {
      if (!initialized) {
        return;
      }

      findProperties();

      // iOS Safari will report window.innerWidth and .innerHeight as 0 unless a timeout is used here.
      // TODO: figure out WHY innerWidth === 0
      setTimeout(function() {
        updateStyles();
      }, 1);
    }

    // http://stackoverflow.com/a/23613052
    function processStylesheet(ss) {
      // cssRules respects same-origin policy, as per
      // https://code.google.com/p/chromium/issues/detail?id=49001#c10.
      try {
        if (!ss.cssRules) { return; }
      } catch (e) {
        if (e.name !== 'SecurityError') { throw e; }
        return;
      }
      // ss.cssRules is available, so proceed with desired operations.
      var rules = [];
      for (var i = 0; i < ss.cssRules.length; i++) {
        var rule = ss.cssRules[i];
        rules.push(rule);
      }
      return rules;
    }

    function findProperties() {
      declarations = [];
      forEach.call(document.styleSheets, function(sheet) {
        var cssRules = processStylesheet(sheet);

        if (!cssRules || sheet.ownerNode.id === 'patched-viewport' || sheet.ownerNode.getAttribute('data-viewport-units-buggyfill') === 'ignore') {
          // skip entire sheet because no rules are present, it's supposed to be ignored or it's the target-element of the buggyfill
          return;
        }

        if (sheet.media && sheet.media.mediaText && window.matchMedia && !window.matchMedia(sheet.media.mediaText).matches) {
          // skip entire sheet because media attribute doesn't match
          return;
        }

        forEach.call(cssRules, findDeclarations);
      });

      return declarations;
    }

    function findDeclarations(rule) {
      if (rule.type === 7) {
        var value;

        // there may be a case where accessing cssText throws an error.
        // I could not reproduce this issue, but the worst that can happen
        // this way is an animation not running properly.
        // not awesome, but probably better than a script error
        // see https://github.com/rodneyrehm/viewport-units-buggyfill/issues/21
        try {
          value = rule.cssText;
        } catch (e) {
          return;
        }

        viewportUnitExpression.lastIndex = 0;
        if (viewportUnitExpression.test(value) && !urlExpression.test(value)) {
          // KeyframesRule does not have a CSS-PropertyName
          declarations.push([rule, null, value]);
          options.hacks && options.hacks.findDeclarations(declarations, rule, null, value);
        }

        return;
      }

      if (!rule.style) {
        if (!rule.cssRules) {
          return;
        }

        forEach.call(rule.cssRules, function(_rule) {
          findDeclarations(_rule);
        });

        return;
      }

      forEach.call(rule.style, function(name) {
        var value = rule.style.getPropertyValue(name);
        // preserve those !important rules
        if (rule.style.getPropertyPriority(name)) {
          value += ' !important';
        }

        viewportUnitExpression.lastIndex = 0;
        if (viewportUnitExpression.test(value)) {
          declarations.push([rule, name, value]);
          options.hacks && options.hacks.findDeclarations(declarations, rule, name, value);
        }
      });
    }

    function getReplacedViewportUnits() {
      dimensions = getViewport();

      var css = [];
      var buffer = [];
      var open;
      var close;

      declarations.forEach(function(item) {
        var _item = overwriteDeclaration.apply(null, item);
        var _open = _item.selector.length ? (_item.selector.join(' {\n') + ' {\n') : '';
        var _close = new Array(_item.selector.length + 1).join('\n}');

        if (!_open || _open !== open) {
          if (buffer.length) {
            css.push(open + buffer.join('\n') + close);
            buffer.length = 0;
          }

          if (_open) {
            open = _open;
            close = _close;
            buffer.push(_item.content);
          } else {
            css.push(_item.content);
            open = null;
            close = null;
          }

          return;
        }

        if (_open && !open) {
          open = _open;
          close = _close;
        }

        buffer.push(_item.content);
      });

      if (buffer.length) {
        css.push(open + buffer.join('\n') + close);
      }

      // Opera Mini messes up on the content hack (it replaces the DOM node's innerHTML with the value).
      // This fixes it. We test for Opera Mini only since it is the most expensive CSS selector
      // see https://developer.mozilla.org/en-US/docs/Web/CSS/Universal_selectors
      if (isOperaMini) {
        css.push('* { content: normal !important; }');
      }

      return css.join('\n\n');
    }

    function overwriteDeclaration(rule, name, value) {
      var _value;
      var _selectors = [];

      _value = value.replace(viewportUnitExpression, replaceValues);

      if (options.hacks) {
        _value = options.hacks.overwriteDeclaration(rule, name, _value);
      }

      if (name) {
        // skipping KeyframesRule
        _selectors.push(rule.selectorText);
        _value = name + ': ' + _value + ';';
      }

      var _rule = rule.parentRule;
      while (_rule) {
        if (_rule.media) {
          _selectors.unshift('@media ' + _rule.media.mediaText);
        } else if (_rule.conditionText) {
          _selectors.unshift('@supports ' + _rule.conditionText);
        }

        _rule = _rule.parentRule;
      }

      return {
        selector: _selectors,
        content: _value,
      };
    }

    function replaceValues(match, number, unit) {
      var _base = dimensions[unit];
      var _number = parseFloat(number) / 100;
      return (_number * _base) + 'px';
    }

    function getViewport() {
      var vh = window.innerHeight;
      var vw = window.innerWidth;

      return {
        vh: vh,
        vw: vw,
        vmax: Math.max(vw, vh),
        vmin: Math.min(vw, vh),
      };
    }

    function importCrossOriginLinks(next) {
      var _waiting = 0;
      var decrease = function() {
        _waiting--;
        if (!_waiting) {
          next();
        }
      };

      forEach.call(document.styleSheets, function(sheet) {
        if (!sheet.href || origin(sheet.href) === origin(location.href) || sheet.ownerNode.getAttribute('data-viewport-units-buggyfill') === 'ignore') {
          // skip <style> and <link> from same origin or explicitly declared to ignore
          return;
        }

        _waiting++;
        convertLinkToStyle(sheet.ownerNode, decrease);
      });

      if (!_waiting) {
        next();
      }
    }

    function origin(url) {
      return url.slice(0, url.indexOf('/', url.indexOf('://') + 3));
    }

    function convertLinkToStyle(link, next) {
      getCors(link.href, function() {
        var style = document.createElement('style');
        style.media = link.media;
        style.setAttribute('data-href', link.href);
        style.textContent = this.responseText;
        link.parentNode.replaceChild(style, link);
        next();
      }, next);
    }

    function getCors(url, success, error) {
      var xhr = new XMLHttpRequest();
      if ('withCredentials' in xhr) {
        // XHR for Chrome/Firefox/Opera/Safari.
        xhr.open('GET', url, true);
      } else if (typeof XDomainRequest !== 'undefined') {
        // XDomainRequest for IE.
        xhr = new XDomainRequest();
        xhr.open('GET', url);
      } else {
        throw new Error('cross-domain XHR not supported');
      }

      xhr.onload = success;
      xhr.onerror = error;
      xhr.send();
      return xhr;
    }

    return {
      version: '0.6.1',
      findProperties: findProperties,
      getCss: getReplacedViewportUnits,
      init: initialize,
      refresh: refresh,
    };
  }));
})();
<|endoftext|>