<commit_before>function Analysis(host)
{
    this.id = "mdAnalysis";
    this.title = "Analysis";

    this.width = 500;
    this.height = 310;
    this.posx = 0;
    this.posy = 195;

    this.host = host;
    this.dataTable = null;
}

Analysis.method("onDataLoaded", function(data){
});

Analysis.method("onRendered", function()
{
});

Analysis.method("getContent", function()
{
    var content = '
';

    content += '

';
    content += '

';

    content += '
';

    return content;
});

Analysis.method("getInitContent", function()
{
	return '';
});

Analysis.method("onSelectionChanged", function(list){
    var originalData = this.host.findModule("mdComparisonTable").dataTable;
    data = originalData.subsetByProducts(list);

    if (data.products.length <= 1)
    {
        $("#analysis #common").html("No Data");
        $("#analysis #unique").html("No Data");
    }

    var allFeatures = data.toSetOfFeatures();

    var commonData = data.getCommon(true); // ALL COMMON DATA
    var commonFeatures = commonData.toSetOfFeatures();

    var differentFeatures = allFeatures.difference(commonFeatures);
    var differentData = data.subsetByFeatures(differentFeatures.toArray()); // ALL DIFFERENT DATA
    differentData.title = "Differences";

    // get the products that are missing to make up the complete set.
    var missingProducts = originalData.getMissingProductsInCommonData(data.getCommon(false), list);

    var clearButton = '<button id="clearAnalysis">Clear</button>
';
    var label = clearButton;

    if (commonFeatures.length > 0)
    {
        if (missingProducts.length > 0)
        {
            if (missingProducts.length <= 10) // reasonable to add products to make the set complete
            {
                var addButton = '<button id="addMissing">add</button>';
                label += "[Not Complete], " + addButton + " [" + missingProducts.toString() + "]";
            }
            else
            {
                var addButton = '<button id="addMissing">add</button>';
                label += "[Not Complete], should " + addButton + " more than 10 products...";
            }

        }
        else
        {
            label += '[Complete] - The set is a complete concept';
        }
    }
    else
        label += "Please select more products for analysis";

    $("#analysis #completeness").html(label);

// add function to addMissing button
    if($("#addMissing")){
        $("#addMissing").click(function(){
            var i;
            for (i = 0; i<missingProducts.length; i++){
                host.selector.onSelected(missingProducts[i]);
            }
        });
    }

// add function for clear button
    $("#clearAnalysis").click(function(){
        var selected = host.selector.selection;
        while (selected.length > 0){
            host.selector.onDeselected(selected[selected.length-1]);
            selected.pop();
        };
    });

//    commonData.products[0] = label;

    if (commonFeatures.length > 0)
    {
        $("#analysis #common").html(new TableVisualizer().getHTML(commonData));
    }
    else
        $("#analysis #common").html("No Data");

    if (differentFeatures.length > 0)
    {
        $("#analysis #unique").html(new TableVisualizer().getHTML(differentData));
    }
    else
        $("#analysis #unique").html("No Data");

// add buttons to remove products
    var i;
    var differentProducts = $("#unique #r0").find(".td_instance");
    for (i=0; i<$(differentProducts).length; i++){
        $(differentProducts[i]).prepend('<image id="rem' + $(differentProducts[i]).text() + '" src="images/remove.png" alt="remove">')
        var buttonId = "#rem" + $(differentProducts[i]).text()
        $(buttonId).click(function(){
            console.log($(this).attr("id").substring(3))
            host.selector.onDeselected($(this).attr("id").substring(3));
        });
        $(buttonId).css("float", "left");
        $(buttonId).css("vertical-align", "middle");
        $(differentProducts[i]).append('--')

        $(buttonId).hover(
        function () {
            $(this).attr("src", "images/removeMouseOver.png");
        },
        function () {
            $(this).attr("src", "images/remove.png");
        });
    }

//    alert(missingProducts);

});
<commit_msg>Put clear button on same line as "[complete]"<commit_after>function Analysis(host)
{
    this.id = "mdAnalysis";
    this.title = "Analysis";

    this.width = 500;
    this.height = 310;
    this.posx = 0;
    this.posy = 195;

    this.host = host;
    this.dataTable = null;
}

Analysis.method("onDataLoaded", function(data){
});

Analysis.method("onRendered", function()
{
});

Analysis.method("getContent", function()
{
    var content = '
';

    content += '

';
    content += '

';

    content += '
';

    return content;
});

Analysis.method("getInitContent", function()
{
	return '';
});

Analysis.method("onSelectionChanged", function(list){
    var originalData = this.host.findModule("mdComparisonTable").dataTable;
    data = originalData.subsetByProducts(list);

    if (data.products.length <= 1)
    {
        $("#analysis #common").html("No Data");
        $("#analysis #unique").html("No Data");
    }

    var allFeatures = data.toSetOfFeatures();

    var commonData = data.getCommon(true); // ALL COMMON DATA
    var commonFeatures = commonData.toSetOfFeatures();

    var differentFeatures = allFeatures.difference(commonFeatures);
    var differentData = data.subsetByFeatures(differentFeatures.toArray()); // ALL DIFFERENT DATA
    differentData.title = "Differences";

    // get the products that are missing to make up the complete set.
    var missingProducts = originalData.getMissingProductsInCommonData(data.getCommon(false), list);

    var clearButton = '<button id="clearAnalysis">Clear</button> ';
    var label = clearButton;

    if (commonFeatures.length > 0)
    {
        if (missingProducts.length > 0)
        {
            if (missingProducts.length <= 10) // reasonable to add products to make the set complete
            {
                var addButton = '<button id="addMissing">add</button>';
                label += "[Not Complete], " + addButton + " [" + missingProducts.toString() + "]";
            }
            else
            {
                var addButton = '<button id="addMissing">add</button>';
                label += "[Not Complete], should " + addButton + " more than 10 products...";
            }

        }
        else
        {
            label += '[Complete] - The set is a complete concept';
        }
    }
    else
        label += "Please select more products for analysis";

    $("#analysis #completeness").html(label);

// add function to addMissing button
    if($("#addMissing")){
        $("#addMissing").click(function(){
            var i;
            for (i = 0; i<missingProducts.length; i++){
                host.selector.onSelected(missingProducts[i]);
            }
        });
    }

// add function for clear button
    $("#clearAnalysis").click(function(){
        var selected = host.selector.selection;
        while (selected.length > 0){
            host.selector.onDeselected(selected[selected.length-1]);
            selected.pop();
        };
    });

//    commonData.products[0] = label;

    if (commonFeatures.length > 0)
    {
        $("#analysis #common").html(new TableVisualizer().getHTML(commonData));
    }
    else
        $("#analysis #common").html("No Data");

    if (differentFeatures.length > 0)
    {
        $("#analysis #unique").html(new TableVisualizer().getHTML(differentData));
    }
    else
        $("#analysis #unique").html("No Data");

// add buttons to remove products
    var i;
    var differentProducts = $("#unique #r0").find(".td_instance");
    for (i=0; i<$(differentProducts).length; i++){
        $(differentProducts[i]).prepend('<image id="rem' + $(differentProducts[i]).text() + '" src="images/remove.png" alt="remove">')
        var buttonId = "#rem" + $(differentProducts[i]).text()
        $(buttonId).click(function(){
            console.log($(this).attr("id").substring(3))
            host.selector.onDeselected($(this).attr("id").substring(3));
        });
        $(buttonId).css("float", "left");
        $(buttonId).css("vertical-align", "middle");
        $(differentProducts[i]).append('--')

        $(buttonId).hover(
        function () {
            $(this).attr("src", "images/removeMouseOver.png");
        },
        function () {
            $(this).attr("src", "images/remove.png");
        });
    }

//    alert(missingProducts);

});
<|endoftext|>


<commit_before>import { h, Component } from 'preact';
import { Link } from 'preact-router/match';

import { shortDateFormatter } from '../../utils/formatting';
import { getVideoUrl, getPlaylistUrl, createReferrerUrl } from '../../utils/routing';

import MediaQuery from '../media-query';
import StreamingList, { StaticList } from '../streaming-list';
import RichText from '../rich-text';

import styles from './style.css';

const getItemUrl = (playlist, video) => createReferrerUrl(getVideoUrl(video), getPlaylistUrl(playlist));
const getVideoThumbnail = (video, matches) => video.snippet.thumbnails ? video.snippet.thumbnails[matches ? 'medium' : 'high'].url : null;

export const PlaylistItem = ({ video, playlist, mobile }) => (

            <Link class={styles.title} part='title' href={getItemUrl(playlist, video)}>{video.snippet.title}</Link>

Published on {shortDateFormatter.format(video.snippet.publishedAt)}

            <RichText class={styles.description} part='description' text={video.snippet.description} />

        <Link class={styles.thumbnail}
            part='thumbnail'
            title={video.snippet.title}
            href={getItemUrl(playlist, video)}
            src={getVideoThumbnail(video, mobile)}
            style={`background-image: url(${getVideoThumbnail(video, mobile)})`}
        />

);

class Playlist extends Component {

    update({ playlist, matches }) {

        const itemTemplate = video => <PlaylistItem video={video} playlist={playlist} mobile={matches} />;

        const itemHeight = matches ? 300 : 198;

        this.setState({ itemTemplate, itemHeight });

    }

    componentWillMount() {
        this.update(this.props);
    }

    componentWillReceiveProps(nextProps) {
        if (nextProps.playlist === this.props.playlist && nextProps.matches === this.props.matches) return;
        this.update(nextProps);
    }

    shouldComponentUpdate({ position }, { itemTemplate, itemHeight }) {

        const shouldUpdate =
            this.props.position !== position ||
            this.state.itemTemplate !== itemTemplate ||
            this.state.itemHeight !== itemHeight;

        return shouldUpdate;
    }

    render({ playlist, position, onPositionChange }, { itemTemplate, itemHeight }) {

        const isSync = Array.isArray(playlist.items);

        if (isSync) {

            return (

                    <StaticList
                        part='items'
                        items={playlist.items}
                        itemTemplate={itemTemplate}
                        itemHeight={itemHeight}
                        itemGutter={20}
                    />

            );

        }

        return (

                <StreamingList
                    part='items'
                    source={playlist.items}
                    total={playlist.total}
                    position={position}
                    itemTemplate={itemTemplate}
                    itemHeight={itemHeight}
                    itemGutter={20}
                    onPositionChange={onPositionChange}
                />

        );
    }
}

export default props => (
    <MediaQuery query='(max-device-width: 480px)'>
        <Playlist {...props} />
    </MediaQuery>
);
<commit_msg>nit: remove whitespace<commit_after>import { h, Component } from 'preact';
import { Link } from 'preact-router/match';

import { shortDateFormatter } from '../../utils/formatting';
import { getVideoUrl, getPlaylistUrl, createReferrerUrl } from '../../utils/routing';

import MediaQuery from '../media-query';
import StreamingList, { StaticList } from '../streaming-list';
import RichText from '../rich-text';

import styles from './style.css';

const getItemUrl = (playlist, video) => createReferrerUrl(getVideoUrl(video), getPlaylistUrl(playlist));
const getVideoThumbnail = (video, matches) => video.snippet.thumbnails ? video.snippet.thumbnails[matches ? 'medium' : 'high'].url : null;

export const PlaylistItem = ({ video, playlist, mobile }) => (

            <Link class={styles.title} part='title' href={getItemUrl(playlist, video)}>{video.snippet.title}</Link>

Published on {shortDateFormatter.format(video.snippet.publishedAt)}

            <RichText class={styles.description} part='description' text={video.snippet.description} />

        <Link class={styles.thumbnail}
            part='thumbnail'
            title={video.snippet.title}
            href={getItemUrl(playlist, video)}
            src={getVideoThumbnail(video, mobile)}
            style={`background-image: url(${getVideoThumbnail(video, mobile)})`}
        />

);

class Playlist extends Component {

    update({ playlist, matches }) {

        const itemTemplate = video => <PlaylistItem video={video} playlist={playlist} mobile={matches} />;

        const itemHeight = matches ? 300 : 198;

        this.setState({ itemTemplate, itemHeight });

    }

    componentWillMount() {
        this.update(this.props);
    }

    componentWillReceiveProps(nextProps) {
        if (nextProps.playlist === this.props.playlist && nextProps.matches === this.props.matches) return;
        this.update(nextProps);
    }

    shouldComponentUpdate({ position }, { itemTemplate, itemHeight }) {

        const shouldUpdate =
            this.props.position !== position ||
            this.state.itemTemplate !== itemTemplate ||
            this.state.itemHeight !== itemHeight;

        return shouldUpdate;
    }

    render({ playlist, position, onPositionChange }, { itemTemplate, itemHeight }) {

        const isSync = Array.isArray(playlist.items);

        if (isSync) {

            return (

                    <StaticList
                        part='items'
                        items={playlist.items}
                        itemTemplate={itemTemplate}
                        itemHeight={itemHeight}
                        itemGutter={20}
                    />

            );

        }

        return (

                <StreamingList
                    part='items'
                    source={playlist.items}
                    total={playlist.total}
                    position={position}
                    itemTemplate={itemTemplate}
                    itemHeight={itemHeight}
                    itemGutter={20}
                    onPositionChange={onPositionChange}
                />

        );
    }
}

export default props => (
    <MediaQuery query='(max-device-width: 480px)'>
        <Playlist {...props} />
    </MediaQuery>
);
<|endoftext|>


<commit_before>
(function() {

cdb.admin.forms = {};

var polygon_stroke = {
   name: 'Polygon Stroke',
   form: {
      'line-width': { type: 'width', value: 1 },
      'line-color': { type: 'color' , value: '#FFF' },
      'line-opacity': { type: 'opacity', value: 0.8 }
   }
};

var line_stroke = {
   name: 'LineStroke',
   form: {
      'line-width': { type: 'width', value: 1 },
      'line-color': { type: 'color' , value: '#FF6600' },
      'line-opacity': { type: 'opacity', value: 0.8 }
   }
};

var polygon_fill = {
   name: 'Polygon Fill',
   form: {
      'polygon-fill': { type: 'color' , value: '#FF5C00' },
      'polygon-opacity': { type: 'opacity' , value: 0.8 }
  }
};

var label_text = {
     name: 'Label Text',
     form: {
      'text-name': { type: 'select' }  /* value is filled by wizard */
     }
};

var label_text_properties = {
    name: 'Label Font',
    form: {
      'text-face-name': {
        type: 'select',
        value: "DejaVu Sans Book",
        extra: ["DejaVu Sans Book","unifont Medium"]
      },
      'text-size': { type: 'number', value: 10, min: 1, max:50 },
      'text-fill': { type: 'color' , value: '#000' },
      'text-allow-overlap': { type: 'hidden', value: true }
    }
};

var label_text_offset =  {
    name: 'Label Offset',
    form: {
      'text-dy': { type: 'number', value: -10, min: -30, max: 30 }
    }
}

var label_halo_properties = {
  name: 'Label Halo',
  form: {
    'text-halo-fill':  { type: 'color' , value: '#FFF' },
    'text-halo-radius': { type: 'number', value: 1, min: 0, max:10}
  }
};

var marker_fill = {
       name: 'Marker Fill',
       form: {
          'marker-fill': { type: 'color' , value: '#FF5C00' },
          'marker-opacity': { type: 'opacity' , value: 0.8 },
          'marker-allow-overlap': { type: 'hidden', value: true },
          'marker-placement':{ type:'hidden', value: 'point'},
          'marker-type':{ type:'hidden', value: 'ellipse'}
      }
};

var marker_radius = {
   name: 'Marker Width',
   form: {
      'marker-width': { type: 'width', value: 7 }
   }
};

var marker_stroke = {
   name: 'Marker Stroke',
   form: {
      'marker-line-width': { type: 'width', value: 2 },
      'marker-line-color': { type: 'color' , value: '#FFF' },
      'marker-line-opacity': { type: 'opacity', value: 1 }
  }
};

cdb.admin.forms.simple_form = {
  'polygon': [
    polygon_fill,
    polygon_stroke,
    label_text,
    label_text_properties,
    label_halo_properties,
    label_text_offset
  ],
  'point': [
    marker_fill,
    marker_radius,
    marker_stroke,
    label_text,
    label_text_properties,
    label_halo_properties,
    label_text_offset
  ],
  'line': [
    line_stroke,
    label_text,
    label_text_properties,
    label_halo_properties,
    label_text_offset
  ]
};

var column = {
  name: 'Column',
  form: { 'property': { type: 'select' } } /* value is filled by wizard */
};

var method = {
  name: 'Method',
  form: {
    // enable this when there is more than one method
    'stats_method': { type: 'select', value: 'Quantiles', extra: ['Quantiles'] }
  }
};

var buckets = {
  name: 'Buckets',
  form: {
    'method': { type: 'select', value: '7 Buckets', extra: ['3 Buckets', '5 Buckets', '7 Buckets'] }
  }
};

var color_ramp_polyline = {
  name: 'Color Ramp',
  form: {
    'color_ramp': { type: 'select', value: 'red', extra:['pink',
      'red', 'black', 'green', 'blue',
      'inverted_pink', 'inverted_red', 'inverted_black',
      'inverted_green', 'inverted_blue', 'spectrum1', 'spectrum2'] },
    'line-opacity': { type: 'opacity', value: 0.8 }
  }
};

var color_ramp_polygon = {
  name: 'Color Ramp',
  form: {
    'color_ramp': { type: 'select', value: 'red', extra:['pink',
      'red', 'black', 'green', 'blue',
      'inverted_pink', 'inverted_red', 'inverted_black',
      'inverted_green', 'inverted_blue', 'spectrum1', 'spectrum2'] },
    'polygon-opacity': { type: 'opacity', value: 0.8 }
  }
};

cdb.admin.forms.bubble_form = [
  column, // Select column
  {
     name: 'Radius',
     title: 'Radius (min-max)',
     form: {
       'radius_min': { type: 'number', value: 10, min:0, max:100 },
       'radius_max': { type: 'number', value: 25, min:0, max:100 }
     },
     text: '- to -'
  },
  {
     name: 'Bubble fill',
     form: {
       'marker-fill': { type: 'color', value: '#FF5C00' },
       'marker-opacity': { type: 'opacity', value: 0.9 }
     }
  },
  {
     name: 'Bubble stroke',
     form: {
       'marker-line-width': { type: 'number', value: 2, min:0, max:100, inc: 0.5 },
       'marker-line-color': { type: 'color', value: '#FFF' },
       'marker-line-opacity': { type: 'opacity', value: 1.0 }
     }
  }
];

cdb.admin.forms.choropleth = {
  'polygon': [
    column,
    //method,
    buckets,
    color_ramp_polygon,
    polygon_stroke,
    label_text,
    label_text_properties,
    label_halo_properties,
    label_text_offset
  ],

  'line': [
    column,
    //method,
    buckets,
    color_ramp_polyline,
    line_stroke,
    label_text,
    label_text_properties,
    label_halo_properties,
    label_text_offset
  ],
  'point': [
    column,
    //method,
    buckets,
    color_ramp_polygon,
    marker_stroke,
    label_text,
    label_text_properties,
    label_halo_properties,
    label_text_offset
  ],
};

cdb.admin.forms.density = [
  {
     name: 'Method',
     form: {
       'geometry_type': { type: 'select', value: 'Hexagons', extra: ['Hexagons', 'Rectangles'] }
     }
  },
  {
     name: 'Buckets',
     form: {
       'method': { type: 'select', value: '5 Buckets', extra: ['5 Buckets', '7 Buckets'] }
     }
  },

  {
     name: 'Color ramp',
     form: {
       'color_ramp': { type: 'select', value: 'red', extra:['pink',
          'red', 'black', 'green', 'blue',
          'inverted_pink', 'inverted_red', 'inverted_black',
          'inverted_green', 'inverted_blue', 'spectrum1', 'spectrum2'] },
       'polygon-opacity': { type: 'opacity', value: 0.8 }
     }
  },

  polygon_stroke,
  {
    name: 'Polygon size',
    form: {
      'polygon-size': { type: 'number', value: 15, min: 1, max: 100 }
    }
  }
];

})();
<commit_msg>fixed choroplet line wizard<commit_after>
(function() {

cdb.admin.forms = {};

var polygon_stroke = {
   name: 'Polygon Stroke',
   form: {
      'line-width': { type: 'width', value: 1 },
      'line-color': { type: 'color' , value: '#FFF' },
      'line-opacity': { type: 'opacity', value: 0.8 }
   }
};

var line_stroke = {
   name: 'LineStroke',
   form: {
      'line-width': { type: 'width', value: 1 },
      'line-color': { type: 'color' , value: '#FF6600' },
      'line-opacity': { type: 'opacity', value: 0.8 }
   }
};

var line_stroke_chroloplet = {
   name: 'LineStroke',
   form: {
      'line-width': { type: 'width', value: 1 },
      'line-opacity': { type: 'opacity', value: 0.8 }
   }
};

var polygon_fill = {
   name: 'Polygon Fill',
   form: {
      'polygon-fill': { type: 'color' , value: '#FF5C00' },
      'polygon-opacity': { type: 'opacity' , value: 0.8 }
  }
};

var label_text = {
     name: 'Label Text',
     form: {
      'text-name': { type: 'select' }  /* value is filled by wizard */
     }
};

var label_text_properties = {
    name: 'Label Font',
    form: {
      'text-face-name': {
        type: 'select',
        value: "DejaVu Sans Book",
        extra: ["DejaVu Sans Book","unifont Medium"]
      },
      'text-size': { type: 'number', value: 10, min: 1, max:50 },
      'text-fill': { type: 'color' , value: '#000' },
      'text-allow-overlap': { type: 'hidden', value: true }
    }
};

var label_text_offset =  {
    name: 'Label Offset',
    form: {
      'text-dy': { type: 'number', value: -10, min: -30, max: 30 }
    }
}

var label_halo_properties = {
  name: 'Label Halo',
  form: {
    'text-halo-fill':  { type: 'color' , value: '#FFF' },
    'text-halo-radius': { type: 'number', value: 1, min: 0, max:10}
  }
};

var marker_fill = {
       name: 'Marker Fill',
       form: {
          'marker-fill': { type: 'color' , value: '#FF5C00' },
          'marker-opacity': { type: 'opacity' , value: 0.8 },
          'marker-allow-overlap': { type: 'hidden', value: true },
          'marker-placement':{ type:'hidden', value: 'point'},
          'marker-type':{ type:'hidden', value: 'ellipse'}
      }
};

var marker_radius = {
   name: 'Marker Width',
   form: {
      'marker-width': { type: 'width', value: 7 }
   }
};

var marker_stroke = {
   name: 'Marker Stroke',
   form: {
      'marker-line-width': { type: 'width', value: 2 },
      'marker-line-color': { type: 'color' , value: '#FFF' },
      'marker-line-opacity': { type: 'opacity', value: 1 }
  }
};

cdb.admin.forms.simple_form = {
  'polygon': [
    polygon_fill,
    polygon_stroke,
    label_text,
    label_text_properties,
    label_halo_properties,
    label_text_offset
  ],
  'point': [
    marker_fill,
    marker_radius,
    marker_stroke,
    label_text,
    label_text_properties,
    label_halo_properties,
    label_text_offset
  ],
  'line': [
    line_stroke,
    label_text,
    label_text_properties,
    label_halo_properties,
    label_text_offset
  ]
};

var column = {
  name: 'Column',
  form: { 'property': { type: 'select' } } /* value is filled by wizard */
};

var method = {
  name: 'Method',
  form: {
    // enable this when there is more than one method
    'stats_method': { type: 'select', value: 'Quantiles', extra: ['Quantiles'] }
  }
};

var buckets = {
  name: 'Buckets',
  form: {
    'method': { type: 'select', value: '7 Buckets', extra: ['3 Buckets', '5 Buckets', '7 Buckets'] }
  }
};

var color_ramp_polyline = {
  name: 'Color Ramp',
  form: {
    'color_ramp': { type: 'select', value: 'red', extra:['pink',
      'red', 'black', 'green', 'blue',
      'inverted_pink', 'inverted_red', 'inverted_black',
      'inverted_green', 'inverted_blue', 'spectrum1', 'spectrum2'] },
    'line-opacity': { type: 'opacity', value: 0.8 }
  }
};

var color_ramp_polygon = {
  name: 'Color Ramp',
  form: {
    'color_ramp': { type: 'select', value: 'red', extra:['pink',
      'red', 'black', 'green', 'blue',
      'inverted_pink', 'inverted_red', 'inverted_black',
      'inverted_green', 'inverted_blue', 'spectrum1', 'spectrum2'] },
    'polygon-opacity': { type: 'opacity', value: 0.8 }
  }
};

cdb.admin.forms.bubble_form = [
  column, // Select column
  {
     name: 'Radius',
     title: 'Radius (min-max)',
     form: {
       'radius_min': { type: 'number', value: 10, min:0, max:100 },
       'radius_max': { type: 'number', value: 25, min:0, max:100 }
     },
     text: '- to -'
  },
  {
     name: 'Bubble fill',
     form: {
       'marker-fill': { type: 'color', value: '#FF5C00' },
       'marker-opacity': { type: 'opacity', value: 0.9 }
     }
  },
  {
     name: 'Bubble stroke',
     form: {
       'marker-line-width': { type: 'number', value: 2, min:0, max:100, inc: 0.5 },
       'marker-line-color': { type: 'color', value: '#FFF' },
       'marker-line-opacity': { type: 'opacity', value: 1.0 }
     }
  }
];

cdb.admin.forms.choropleth = {
  'polygon': [
    column,
    //method,
    buckets,
    color_ramp_polygon,
    polygon_stroke,
    label_text,
    label_text_properties,
    label_halo_properties,
    label_text_offset
  ],

  'line': [
    column,
    //method,
    buckets,
    color_ramp_polyline,
    line_stroke_chroloplet,
    label_text,
    label_text_properties,
    label_halo_properties,
    label_text_offset
  ],
  'point': [
    column,
    //method,
    buckets,
    color_ramp_polygon,
    marker_stroke,
    label_text,
    label_text_properties,
    label_halo_properties,
    label_text_offset
  ],
};

cdb.admin.forms.density = [
  {
     name: 'Method',
     form: {
       'geometry_type': { type: 'select', value: 'Hexagons', extra: ['Hexagons', 'Rectangles'] }
     }
  },
  {
     name: 'Buckets',
     form: {
       'method': { type: 'select', value: '5 Buckets', extra: ['5 Buckets', '7 Buckets'] }
     }
  },

  {
     name: 'Color ramp',
     form: {
       'color_ramp': { type: 'select', value: 'red', extra:['pink',
          'red', 'black', 'green', 'blue',
          'inverted_pink', 'inverted_red', 'inverted_black',
          'inverted_green', 'inverted_blue', 'spectrum1', 'spectrum2'] },
       'polygon-opacity': { type: 'opacity', value: 0.8 }
     }
  },

  polygon_stroke,
  {
    name: 'Polygon size',
    form: {
      'polygon-size': { type: 'number', value: 15, min: 1, max: 100 }
    }
  }
];

})();
<|endoftext|>


<commit_before>const Writable = require('stream').Writable;
const Module = require('./Module');
const Instance = require('./Instance');

function isBlankNode (string) {
    return string.indexOf('_:') === 0;
}

module.exports = (scope, event, args) => {
    return new Writable({
        objectMode: true,
        write: (triple, enc, done) => {

            let subject = triple[0] || triple.subject;
            let predicate = triple[1] || triple.predicate;
            let object = triple[2] || triple.object;

            switch (predicate) {

                case 'http://schema.jillix.net/vocab/onEnd':
                    event.set('e', object);
                    break;

                case 'http://schema.jillix.net/vocab/onError':
                    event.set('r', object);
                    break;

                case 'http://schema.jillix.net/vocab/module':
                    Module(scope, args, object, (error, module) => {

                        if (error) {
                            return event.error(error);
                        }

                        Instance(scope, args, subject, 'module', module);
                    });
                    break;

                case 'http://schema.jillix.net/vocab/roles':
                    Instance(scope, args, subject, (error, instance) => {

                        if (error) {
                            return event.error(error);
                        }

                        instance.role(object);
                    });
                    break;

                case 'http://schema.jillix.net/vocab/args':

                    try {
                        object = JSON.parse(object.slice(1, -1));
                    } catch (error) {
                        event.error(error);
                        break;
                    }

                    if (isBlankNode(subject)) {
                        event.handler(subject, 'args', object);
                        break;
                    }

                    Instance(scope, args, subject, (error, instance) => {

                        if (error) {
                            return event.error(error);
                        }

                        instance.args(object);
                    });
                    break;

                case 'http://schema.jillix.net/vocab/sequence':

                    if (isBlankNode(subject)) {
                        event.handler(subject, 'next', object);
                        break;
                    }

                    event.handler(object, 'first', true);
                    break;

                case 'http://schema.jillix.net/vocab/instance':
                    ++event.load;
                    Instance(scope, args, object, (error, instance) => {

                        if (error) {
                            return event.error(error);
                        }

                        event.handler(subject, 'instance', instance);
                        event.done(event);
                    });
                    break;

                case 'http://schema.jillix.net/vocab/dataHandler':
                    event.handler(subject, 'data', object.split('#')[1]);
                    break;

                case 'http://schema.jillix.net/vocab/streamHandler':
                    event.handler(subject, 'stream', object.split('#')[1]);
                    break;

                case 'http://schema.jillix.net/vocab/emit':
                    ++event.load;
                    event.handler(subject, 'emit', object);
                    event.done(event);
                    break;

                default:
                    console.log('[Parser] Unknown triple:', predicate);
            }

            done();
        }
    });
};
<commit_msg>update parsing to changes in event, instance and module<commit_after>const Writable = require('stream').Writable;
const Module = require('./Module');
const Instance = require('./Instance');

function isBlankNode (string) {
    return string.indexOf('_:') === 0;
}

module.exports = (scope, event, args) => {
    return new Writable({
        objectMode: true,
        write: (triple, enc, done) => {

            let subject = triple[0] || triple.subject;
            let predicate = triple[1] || triple.predicate;
            let object = triple[2] || triple.object;

            switch (predicate) {

                case 'http://schema.jillix.net/vocab/onEnd':
                    event.e = object;
                    break;

                case 'http://schema.jillix.net/vocab/onError':
                    event.r = object;
                    break;

                case 'http://schema.jillix.net/vocab/module':
                    Module(scope, args, object, (error, module) => {

                        if (error) {
                            return event.done(error);
                        }

                        Instance(scope, args, subject).module(module);
                    });
                    break;

                case 'http://schema.jillix.net/vocab/roles':
                    Instance(scope, args, subject).roles[object] = true;
                    break;

                case 'http://schema.jillix.net/vocab/args':

                    try {
                        object = JSON.parse(object.slice(1, -1));
                    } catch (error) {
                        event.done(error);
                        break;
                    }

                    if (isBlankNode(subject)) {
                        event.set(subject, 'A', object);
                        break;
                    }

                    Instance(scope, args, subject).args = object;
                    break;

                case 'http://schema.jillix.net/vocab/sequence':

                    if (isBlankNode(subject)) {
                        event.set(subject, 'N', object);
                        break;
                    }

                    event.set(object, 'F', true);
                    break;

                case 'http://schema.jillix.net/vocab/instance':
                    ++event.load;
                    Instance(scope, args, object).done((error, instance) => {

                        if (error) {
                            return event.done(error);
                        }

                        event.set(subject, 'I', instance.clone);
                        event.done();
                    });
                    break;

                case 'http://schema.jillix.net/vocab/dataHandler':
                    event.set(subject, 'D', object.split('#')[1]);
                    break;

                case 'http://schema.jillix.net/vocab/streamHandler':
                    event.set(subject, 'S', object.split('#')[1]);
                    break;

                case 'http://schema.jillix.net/vocab/emit':
                    ++event.load;
                    event.set(subject, 'E', object);
                    event.done();
                    break;

                default:
                    event.done(new Error('[Parser] Unknown triple: ' + predicate));
            }

            done();
        }
    });
};
<|endoftext|>


<commit_before>var FFA = require('./FFA'); // Base gamemode
var Entity = require('../entity');
//LMS or "Last Man Standing"
//After a set time interval the Server will not allow players to spawn and will only let them specate
//Some time later, the Server will disconnect all players and restart the cycle.

function LMS () {
    FFA.apply(this, Array.prototype.slice.call(arguments));
    this.ID = 4;
    this.name = "LMS";
    this.specByLeaderboard = true;

    // Gamemode Specific Variables
    this.nodesMother = [];
    this.tickMotherSpawn = 0;
    this.tickMotherUpdate = 0;

    // Config
    this.motherSpawnInterval = 25 * 5;  // How many ticks it takes to spawn another mother cell (5 seconds)
    this.motherUpdateInterval = 2;      // How many ticks it takes to spawn mother food (1 second)
    this.motherMinAmount = 20;

    // Whether last man standing has started or not
    this.lmsStart = false;
}

module.exports = LMS;
LMS.prototype = new FFA();

// Gamemode Specific Functions

LMS.prototype.spawnMotherCell = function (gameServer) {
    // Checks if there are enough mother cells on the map
    if (this.nodesMother.length >= this.motherMinAmount) {
        return;
    }
    // Spawns a mother cell
    var pos = gameServer.randomPos();
    if (gameServer.willCollide(pos, 149)) {
        // cannot find safe position => do not spawn
        return;
    }
    // Spawn if no cells are colliding
    var mother = new Entity.MotherCell(gameServer, null, pos, null);
    gameServer.addNode(mother);
};

// Override

LMS.prototype.onServerInit = function (gameServer) {
    // Called when the server starts
    gameServer.run = true;

    // Override for special virus mechanics
    var self = this;
    Entity.Virus.prototype.onEat = function (prey) {
        // Pushes the virus
        var angle = prey.isMoving ? prey.boostDirection.angle : this.boostDirection.angle;
        this.setBoost(16 * 20, angle);
    };
    Entity.MotherCell.prototype.onAdd = function () {
        self.nodesMother.push(this);
    };
    Entity.MotherCell.prototype.onRemove = function () {
        var index = self.nodesMother.indexOf(this);
        if (index != -1)
            self.nodesMother.splice(index, 1);
    };
    var short = gameServer.config.lastManStandingShortest * 60000;
    var long = gameServer.config.lastManStandingLongest * 60000;
    var shortkick = gameServer.config.lastManStandingKickShortest * 60000;
    var longkick = gameServer.config.lastManStandingKickLongest * 60000;
    var time = Math.floor((Math.random() * (long - short)) + short);
    var kickingTime = Math.floor((Math.random() * (longkick - shortkick)) + shortkick);
    var endInt = setInterval(function() {self.lmsKick()}, kickingTime);
    var startInt = setInterval(function() {self.lmsBegin()}, time);
};

LMS.prototype.onPlayerSpawn = function (gameServer, player) {
    // Only spawn players if LMS hasnt started yet
    if (!this.lmsStart) {
        // Random color upon spawning
        player.setColor(gameServer.getRandomColor());
        gameServer.spawnPlayer(player, gameServer.randomPos());
    }
};

LMS.prototype.onPlayerDeath = function (gameServer){
};

LMS.prototype.lmsKick = function (gameServer, player) {
    this.lmsStart = false;
    console.log("You can now join");
};

LMS.prototype.lmsBegin = function () {
    this.lmsStart = true;
    console.log("LMS HAS STARTED!");
};

LMS.prototype.onTick = function (gameServer) {
    // Mother Cell Spawning
    if (this.tickMotherSpawn >= this.motherSpawnInterval) {
        this.tickMotherSpawn = 0;
        this.spawnMotherCell(gameServer);
    } else {
        this.tickMotherSpawn++;
    }
    if (this.tickMotherUpdate >= this.motherUpdateInterval) {
        this.tickMotherUpdate = 0;
        for (var i = 0; i < this.nodesMother.length; i++) {
            this.nodesMother[i].onUpdate();
        }
    } else {
        this.tickMotherUpdate++;
    }
};
<commit_msg>Delete LMS.js<commit_after><|endoftext|>


<commit_before>import $ from 'jquery';
import _ from 'underscore';
import videojs from 'video.js';
import RangeItem from './rangeItem';
import {formatTime, formatToFixedDecimals} from './utils';
import Alerts from '../../utils/alert';
import dialog from 'phraseanet-common/src/components/dialog';

const humane = require('humane-js');

/**
 * VideoJs Range Collection
 */
const Component = videojs.getComponent('Component');

class RangeCollection extends Component {
    uid = 0;
    defaultRange = {
        startPosition: -1,
        endPosition: -1,
        title: '',
        handlePositions: [],
        selected: false,
        image: {
            src: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFkAAAAyCAYAAAA3OHc2AAAAuElEQVR4Xu3UwQkAIAwEwdh/0Qr2kH2NBWRhODwzc8dbFTiQV33/ccj7xpADY8iQC4Gg4U+GHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgEiQftoTIBhrHr1wAAAABJRU5ErkJggg==',
            width: 89,
            height: 50
        },
        manualSnapShot: false
    };
    rangeCollection = [];
    rangeItemComponentCollection = [];
    currentRange = false;
    isHoverChapterSelected = false;

    constructor(player, settings) {
        super(player, settings);
        this.settings = settings;
        this.$el = this.renderElContent();

        this.player_.activeRangeStream.subscribe((params) => {
            this.currentRange = params.activeRange;
            this.refreshRangeCollection()
        });

        this.isHoverChapterSelected = settings.preferences.overlapChapters == 1 ? true : false;
    }

    initDefaultRange() {
        // init collection with a new range if nothing specified:
        let newRange = this.addRange(this.defaultRange);
        this.player_.rangeStream.onNext({
            action: 'create',
            range: newRange
        });
    }

    addRangeEvent() {
        let newRange = this.addNewRange(this.defaultRange);
        this.player_.rangeStream.onNext({
            action: 'create',
            range: newRange
        });
    }

    exportRangeEvent() {
        this.player_.rangeStream.onNext({
            action: 'export-ranges',
            ranges: this.exportRanges()
        });
    }

    exportVTTRangeEvent() {
        this.player_.rangeStream.onNext({
            action: 'export-vtt-ranges',
            data: this.exportVttRanges()
        });
    }

    setHoverChapter(isChecked) {
        this.isHoverChapterSelected = isChecked;
        this.player_.rangeStream.onNext({

            action: 'saveRangeCollectionPref',

            data: isChecked

        });
    }

    /**
     * Create the component's DOM element
     *
     * @return {Element}
     * @method createEl
     */
    createEl() {
        return super.createEl('div', {
            className: 'range-collection-container',
            innerHTML: ''
        });
    }

    renderElContent() {
        return $(this.el());
    }

    update(range) {
        let updatedRange;

        if (!this.isExist(range)) {
            updatedRange = this.addNewRange(range);
        } else {
            updatedRange = this.updateRange(range);
        }
        return updatedRange;
    }

    updatingByDragging(range) {
        if(this.isHoverChapterSelected) {

            this.syncRange(range);

        }else {

            this.updateRange(range);

        }
    }

    isExist(range) {
        if (range.id === undefined) {
            return false;
        }
        for (let i = 0; i < this.rangeCollection.length; i++) {
            if (this.rangeCollection[i].id === range.id) {
                return true;
            }
        }
        return false;
    }

    remove(range) {
        let cleanedColl = _.filter(this.rangeCollection, (rangeData, index) => {
            if (range.id === rangeData.id) {
                return false;
            }
            return true;
        });
        this.rangeCollection = cleanedColl;
        // if removed range is active one, activate another one
        if (range.id === this.currentRange.id) {
            if (this.rangeCollection.length > 0) {

                //let lastRange = this.rangeCollection.length-1;
                this.player_.rangeStream.onNext({
                    action: 'select',
                    range: this.rangeCollection[this.rangeCollection.length - 1]
                })
            }

        }
        this.refreshRangeCollection();
    }

    addRange(range) {
        let lastId = this.uid = this.uid + 1;
        let newRange = _.extend({}, this.defaultRange, range, {id: lastId});
        newRange = this.setHandlePositions(newRange);
        this.rangeCollection.push(newRange);
        this.refreshRangeCollection();
        return newRange;
    }

    addNewRange(range) {
        let lastId = this.uid = this.uid + 1;
        let newRange = _.extend({}, this.defaultRange, range, {id: lastId});
        newRange.startPosition = this.getStartingPosition();
        newRange.endPosition = this.getEndPosition(newRange.startPosition);
        newRange = this.setHandlePositions(newRange);
        this.rangeCollection.push(newRange);
        this.refreshRangeCollection();
        return newRange;
    }

    getStartingPosition() {
        //tracker is at ending of previous range
        let gap = _.first(this.settings.record.sources).framerate * 0.001;
        let lastKnownPosition = this.player_.currentTime();

        if((lastKnownPosition + gap) < this.player_.duration()) {
            lastKnownPosition += gap;
            return lastKnownPosition;
        }
        return lastKnownPosition;
        // let gap = 0.01;
        // let lastRange = this.rangeCollection.length > 0 ?
        //     this.rangeCollection[this.rangeCollection.length -1] : null;
        //
        // if(lastRange != null ||
        //     formatToFixedDecimals(this.player_.currentTime()) < formatToFixedDecimals(lastRange.endPosition)) {
        //     lastKnownPosition = lastRange.endPosition + gap <= this.player_.duration()
        //         ? lastRange.endPosition + gap
        //         : this.player_.duration();
        // }else {
        //     lastKnownPosition = this.player_.currentTime() + gap <= this.player_.duration()
        //         ? this.player_.currentTime() + gap
        //         : this.player_.duration();
        // }
        // return lastKnownPosition;
    }

    getEndPosition(startPosition) {
        let rangeDuration = this.player_.duration()/10;
        let endPosition = startPosition + rangeDuration;
        if(endPosition >= this.player_.duration()) {
            endPosition == this.player_.duration();
        }
        return endPosition;
        // let gap = 0.01;
        // let rangeDuration = this.player_.duration()/10;
        // let endPosition = null;
        // if(formatToFixedDecimals(startPosition) >= formatToFixedDecimals(this.player_.currentTime() + gap)) {
        //     endPosition = startPosition + rangeDuration <= this.player_.duration()
        //         ? startPosition + rangeDuration
        //         : this.player_.duration();
        // }else {
        //     endPosition = this.player_.currentTime() + gap;
        // }
        // return endPosition;
    }

    updateRange(range) {
        if (range.id !== undefined) {
            this.rangeCollection = _.map(this.rangeCollection, (rangeData, index) => {
                if (range.id === rangeData.id) {
                    range = this.setHandlePositions(range);
                    return range;
                }
                return rangeData;
            });
        }
        this.refreshRangeCollection();
        return range;
    }

    syncRange(range) {

        let gap = _.first(this.settings.record.sources).framerate * 0.001;
        if (range.id !== undefined) {
            let index = _.findIndex(this.rangeCollection, (rangeData) => {
                return rangeData.id == range.id;
            });

            if(index !== null) {
                if(index < this.rangeCollection.length-1) {
                    //update next range
                    let rangeToUpdate = this.rangeCollection[index+1];
                    rangeToUpdate.startPosition = range.endPosition + gap <= rangeToUpdate.endPosition
                        ? range.endPosition + gap : rangeToUpdate.endPosition;
                    let newRange = this.setHandlePositions(rangeToUpdate);
                    this.rangeCollection[index+1] = newRange;
                }
                if (index > 0) {
                    //update previous range
                    let rangeToUpdate = this.rangeCollection[index-1];
                    rangeToUpdate.endPosition = range.startPosition - gap >= rangeToUpdate.startPosition
                        ? range.startPosition - gap : rangeToUpdate.startPosition;
                    let newRange = this.setHandlePositions(rangeToUpdate);
                    this.rangeCollection[index-1] = newRange;
                }

                let newRange = this.setHandlePositions(range);
                this.rangeCollection[index] = newRange;
            }
        }
        this.refreshRangeCollection();
        return range;

}

    setHandlePositions(range) {
        let videoDuration = this.player_.duration();
        if (videoDuration > 0) {
            let left = ((range.startPosition / videoDuration) * 100);
            let right = ((range.endPosition / videoDuration) * 100);

            range.handlePositions = {left, right};
        }
        return range;
    }

    getRangeById(id) {
        let foundRange = {};
        for (let i = 0; i < this.rangeCollection.length; i++) {
            if (this.rangeCollection[i].id === id) {
                foundRange = this.rangeCollection[i];
            }
        }
        return foundRange;
    }

    exportRanges = () => {
        let exportedRanges = [];
        for (let i = 0; i < this.rangeCollection.length; i++) {
            exportedRanges.push({
                startPosition: this.rangeCollection[i].startPosition,
                endPosition: this.rangeCollection[i].endPosition
            })
        }
        return exportedRanges;
    }
    exportVttRanges = () => {
        let exportedRanges = [`WEBVTT
`];
        for (let i = 0; i < this.rangeCollection.length; i++) {
            let exportableData = {
                title: this.rangeCollection[i].title!= "" ? this.rangeCollection[i].title : document.getElementById("default-video-chapter-label").value
            };

            if (this.rangeCollection[i].image.src !== '') {
                exportableData.image = this.rangeCollection[i].image.src;
                exportableData.manualSnapShot = this.rangeCollection[i].manualSnapShot || false;
            }

            exportedRanges.push(`${i + 1}
${formatTime(this.rangeCollection[i].startPosition, 'hh:mm:ss.mmm')} --> ${formatTime(this.rangeCollection[i].endPosition, 'hh:mm:ss.mmm')}
${JSON.stringify(exportableData)}
`)
        }
        return exportedRanges.join('\n');
    }

    get = (model) => {
        if (model === undefined) {
            return this.rangeCollection;
        }
        return this.getRangeById(model.id);
    }

    splice = (...args) => {
        return Array.prototype.splice.apply(this.rangeCollection, args);
    }

    getIndex = (model) => {
        let index = {};
        for (let i = 0; i < this.rangeCollection.length; i++) {
            if (this.rangeCollection[i].id === model.id) {
                index = i;
            }
        }
        return index;
    }

    getSelection = () => {
        let selectedRanges = [];
        for (let i = 0; i < this.rangeCollection.length; i++) {
            if (this.rangeCollection[i].selected === true) {
                selectedRanges.push(this.rangeCollection[i]);
            }
        }
        return selectedRanges;
    }

    resetSelection = () => {
        for (let i = 0; i < this.rangeCollection.length; i++) {
            this.rangeCollection[i].selected = false;
        }
    }

    addToSelection = (model) => {
        for (let i = 0; i < this.rangeCollection.length; i++) {
            if (this.rangeCollection[i].id === model.id) {
                this.rangeCollection[i].selected = true;
            }
        }
    }

    removeFromSelection = (model) => {
        for (let i = 0; i < this.rangeCollection.length; i++) {
            if (this.rangeCollection[i].id === model.id) {
                this.rangeCollection[i].selected = false;
            }
        }
    }

    getFirstSelected = () => {
        let firstModel = false;
        for (let i = 0; i < this.rangeCollection.length; i++) {
            if (this.rangeCollection[i].selected === true && firstModel === false) {
                firstModel = this.rangeCollection[i];
            }
        }
        return firstModel;
    }

    getLastSelected = () => {
        let lastModel = false;
        for (let i = 0; i < this.rangeCollection.length; i++) {
            if (this.rangeCollection[i].selected === true) {
                lastModel = this.rangeCollection[i];
            }
        }
        return lastModel;
    }

    reset = (collection) => {
        this.rangeCollection = collection;
        // refresh internal indexes:
        for (let i = 0; i < this.rangeCollection.length; i++) {
            this.rangeCollection[i].index = i;
        }
        this.refreshRangeCollection();
    }

    setActiveRange = (direction) => {
        if (this.currentRange === false) {
            return;
        }
        let toIndex = this.currentRange.index - 1;

        if (direction === 'down') {
            toIndex = this.currentRange.index + 1;
        }

        if (this.rangeCollection[toIndex] !== undefined) {

            this.player_.rangeStream.onNext({
                action: 'change',
                range: this.rangeCollection[toIndex]
            });
        }
    }

    moveRange = (direction) => {
        if (this.currentRange === false) {
            return;
        }
        let collection = this.get();
        let toIndex = this.currentRange.index - 1;

        if (direction === 'down') {
            toIndex = this.currentRange.index + 1;
        }
        this.addToSelection(this.currentRange);
        let selectedModels = this.getSelection();

        for (let i = selectedModels.length; i--;) {
            let fromIndex = this.getIndex(this.get(selectedModels[i]));

            collection.splice(toIndex, 0, this.splice(fromIndex, 1)[0]);
        }

        this.reset(collection);
    }

    refreshRangeCollection = () => {
        // remove any existing items
        for (let i = 0; i < this.rangeItemComponentCollection.length; i++) {
            this.rangeItemComponentCollection[i].dispose();
            this.removeChild(this.rangeItemComponentCollection[i]);
        }
        this.rangeItemComponentCollection = [];

        let activeId = 0;
        if (this.currentRange !== false) {
            activeId = this.currentRange.id;
        }

        for (let i = 0; i < this.rangeCollection.length; i++) {
            let model = _.extend({}, this.rangeCollection[i], {index: i});
            let item = new RangeItem(this.player_, {
                model: model,
                collection: this,
                isActive: this.rangeCollection[i].id === activeId ? true : false
            }, this.settings);

            this.rangeItemComponentCollection.push(item);
            this.addChild(item);

        }
    }

    exportRangesData = (rangeData) => {
        var title = this.settings.translations.alertTitle;
        var message = this.settings.translations.updateTitle;
        var services = this.settings.services;
        $.ajax({
            type: 'POST',
            url: `${this.settings.baseUrl}prod/tools/metadata/save/`,
            data: {
                databox_id: this.settings.databoxId,
                record_id: this.settings.recordId,
                meta_struct_id: this.settings.meta_struct_id,
                value: rangeData
            },
            success: function (data) {
                if (!data.success) {
                    humane.error(data.message);
                } else {
                    humane.info(message);
                }
            }
        });
};
}

videojs.registerComponent('RangeCollection', RangeCollection);

export default RangeCollection;
<commit_msg>PHRAS-3044<commit_after>import $ from 'jquery';
import _ from 'underscore';
import videojs from 'video.js';
import RangeItem from './rangeItem';
import {formatTime, formatToFixedDecimals} from './utils';
import Alerts from '../../utils/alert';
import dialog from 'phraseanet-common/src/components/dialog';

const humane = require('humane-js');

/**
 * VideoJs Range Collection
 */
const Component = videojs.getComponent('Component');

class RangeCollection extends Component {
    uid = 0;
    defaultRange = {
        startPosition: -1,
        endPosition: -1,
        title: '',
        handlePositions: [],
        selected: false,
        image: {
            src: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFkAAAAyCAYAAAA3OHc2AAAAuElEQVR4Xu3UwQkAIAwEwdh/0Qr2kH2NBWRhODwzc8dbFTiQV33/ccj7xpADY8iQC4Gg4U+GHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgECUuGHAgEiQftoTIBhrHr1wAAAABJRU5ErkJggg==',
            width: 89,
            height: 50
        },
        manualSnapShot: false
    };
    rangeCollection = [];
    rangeItemComponentCollection = [];
    currentRange = false;
    isHoverChapterSelected = false;

    constructor(player, settings) {
        super(player, settings);
        this.settings = settings;
        this.$el = this.renderElContent();

        this.player_.activeRangeStream.subscribe((params) => {
            this.currentRange = params.activeRange;
            this.refreshRangeCollection()
        });

        this.isHoverChapterSelected = settings.preferences.overlapChapters == 1 ? true : false;
    }

    initDefaultRange() {
        // init collection with a new range if nothing specified:
        let newRange = this.addRange(this.defaultRange);
        this.player_.rangeStream.onNext({
            action: 'create',
            range: newRange
        });
    }

    addRangeEvent() {
        let newRange = this.addNewRange(this.defaultRange);
        this.player_.rangeStream.onNext({
            action: 'create',
            range: newRange
        });
    }

    exportRangeEvent() {
        this.player_.rangeStream.onNext({
            action: 'export-ranges',
            ranges: this.exportRanges()
        });
    }

    exportVTTRangeEvent() {
        this.player_.rangeStream.onNext({
            action: 'export-vtt-ranges',
            data: this.exportVttRanges()
        });
    }

    setHoverChapter(isChecked) {
        this.isHoverChapterSelected = isChecked;
        this.player_.rangeStream.onNext({

            action: 'saveRangeCollectionPref',

            data: isChecked

        });
    }

    /**
     * Create the component's DOM element
     *
     * @return {Element}
     * @method createEl
     */
    createEl() {
        return super.createEl('div', {
            className: 'range-collection-container',
            innerHTML: ''
        });
    }

    renderElContent() {
        return $(this.el());
    }

    update(range) {
        let updatedRange;

        if (!this.isExist(range)) {
            updatedRange = this.addNewRange(range);
        } else {
            updatedRange = this.updateRange(range);
        }
        return updatedRange;
    }

    updatingByDragging(range) {
        if(this.isHoverChapterSelected) {

            this.syncRange(range);

        }else {

            this.updateRange(range);

        }
    }

    isExist(range) {
        if (range.id === undefined) {
            return false;
        }
        for (let i = 0; i < this.rangeCollection.length; i++) {
            if (this.rangeCollection[i].id === range.id) {
                return true;
            }
        }
        return false;
    }

    remove(range) {
        let cleanedColl = _.filter(this.rangeCollection, (rangeData, index) => {
            if (range.id === rangeData.id) {
                return false;
            }
            return true;
        });
        this.rangeCollection = cleanedColl;
        // if removed range is active one, activate another one
        if (range.id === this.currentRange.id) {
            if (this.rangeCollection.length > 0) {

                //let lastRange = this.rangeCollection.length-1;
                this.player_.rangeStream.onNext({
                    action: 'select',
                    range: this.rangeCollection[this.rangeCollection.length - 1]
                })
            }

        }
        this.refreshRangeCollection();
    }

    addRange(range) {
        let lastId = this.uid = this.uid + 1;
        let newRange = _.extend({}, this.defaultRange, range, {id: lastId});
        newRange = this.setHandlePositions(newRange);
        this.rangeCollection.push(newRange);
        this.refreshRangeCollection();
        return newRange;
    }

    addNewRange(range) {
        let lastId = this.uid = this.uid + 1;
        let newRange = _.extend({}, this.defaultRange, range, {id: lastId});
        newRange.startPosition = this.getStartingPosition();
        newRange.endPosition = this.getEndPosition(newRange.startPosition);
        newRange = this.setHandlePositions(newRange);
        this.rangeCollection.push(newRange);
        this.refreshRangeCollection();
        return newRange;
    }

    getStartingPosition() {
        //tracker is at ending of previous range
        let gap = _.first(this.settings.record.sources).framerate * 0.001;
        let lastKnownPosition = this.player_.currentTime();

        if((lastKnownPosition + gap) < this.player_.duration()) {
            lastKnownPosition += gap;
            return lastKnownPosition;
        }
        return lastKnownPosition;
        // let gap = 0.01;
        // let lastRange = this.rangeCollection.length > 0 ?
        //     this.rangeCollection[this.rangeCollection.length -1] : null;
        //
        // if(lastRange != null ||
        //     formatToFixedDecimals(this.player_.currentTime()) < formatToFixedDecimals(lastRange.endPosition)) {
        //     lastKnownPosition = lastRange.endPosition + gap <= this.player_.duration()
        //         ? lastRange.endPosition + gap
        //         : this.player_.duration();
        // }else {
        //     lastKnownPosition = this.player_.currentTime() + gap <= this.player_.duration()
        //         ? this.player_.currentTime() + gap
        //         : this.player_.duration();
        // }
        // return lastKnownPosition;
    }

    getEndPosition(startPosition) {
        let rangeDuration = this.player_.duration()/10;
        let endPosition = startPosition + rangeDuration;
        if(endPosition >= this.player_.duration()) {
            endPosition == this.player_.duration();
        }
        return endPosition;
        // let gap = 0.01;
        // let rangeDuration = this.player_.duration()/10;
        // let endPosition = null;
        // if(formatToFixedDecimals(startPosition) >= formatToFixedDecimals(this.player_.currentTime() + gap)) {
        //     endPosition = startPosition + rangeDuration <= this.player_.duration()
        //         ? startPosition + rangeDuration
        //         : this.player_.duration();
        // }else {
        //     endPosition = this.player_.currentTime() + gap;
        // }
        // return endPosition;
    }

    updateRange(range) {
        if (range.id !== undefined) {
            this.rangeCollection = _.map(this.rangeCollection, (rangeData, index) => {
                if (range.id === rangeData.id) {
                    range = this.setHandlePositions(range);
                    return range;
                }
                return rangeData;
            });
        }
        this.refreshRangeCollection();
        return range;
    }

    syncRange(range) {

        let gap = _.first(this.settings.record.sources).framerate * 0.001;
        if (range.id !== undefined) {
            let index = _.findIndex(this.rangeCollection, (rangeData) => {
                return rangeData.id == range.id;
            });

            if(index !== null) {
                if(index < this.rangeCollection.length-1) {
                    //update next range
                    let rangeToUpdate = this.rangeCollection[index+1];
                    rangeToUpdate.startPosition = range.endPosition + gap <= rangeToUpdate.endPosition
                        ? range.endPosition + gap : rangeToUpdate.endPosition;
                    let newRange = this.setHandlePositions(rangeToUpdate);
                    this.rangeCollection[index+1] = newRange;
                }
                if (index > 0) {
                    //update previous range
                    let rangeToUpdate = this.rangeCollection[index-1];
                    rangeToUpdate.endPosition = range.startPosition - gap >= rangeToUpdate.startPosition
                        ? range.startPosition - gap : rangeToUpdate.startPosition;
                    let newRange = this.setHandlePositions(rangeToUpdate);
                    this.rangeCollection[index-1] = newRange;
                }

                let newRange = this.setHandlePositions(range);
                this.rangeCollection[index] = newRange;
            }
        }
        this.refreshRangeCollection();
        return range;

}

    setHandlePositions(range) {
        let videoDuration = this.player_.duration();
        if (videoDuration > 0) {
            let left = ((range.startPosition / videoDuration) * 100);
            let right = ((range.endPosition / videoDuration) * 100);

            range.handlePositions = {left, right};
        }
        return range;
    }

    getRangeById(id) {
        let foundRange = {};
        for (let i = 0; i < this.rangeCollection.length; i++) {
            if (this.rangeCollection[i].id === id) {
                foundRange = this.rangeCollection[i];
            }
        }
        return foundRange;
    }

    exportRanges = () => {
        let exportedRanges = [];
        for (let i = 0; i < this.rangeCollection.length; i++) {
            exportedRanges.push({
                startPosition: this.rangeCollection[i].startPosition,
                endPosition: this.rangeCollection[i].endPosition
            })
        }
        return exportedRanges;
    }
    exportVttRanges = () => {
        let exportedRanges = [`WEBVTT
`];
        let titleValue= document.getElementById("default-video-chapter-label").value;
        for (let i = 0; i < this.rangeCollection.length; i++) {
            let exportableData = {
                title: this.rangeCollection[i].title != "" ? this.rangeCollection[i].title : titleValue
            };

            if (this.rangeCollection[i].image.src !== '') {
                exportableData.image = this.rangeCollection[i].image.src;
                exportableData.manualSnapShot = this.rangeCollection[i].manualSnapShot || false;
            }

            exportedRanges.push(`${i + 1}
${formatTime(this.rangeCollection[i].startPosition, 'hh:mm:ss.mmm')} --> ${formatTime(this.rangeCollection[i].endPosition, 'hh:mm:ss.mmm')}
${JSON.stringify(exportableData)}
`)
        }
        return exportedRanges.join('\n');
    }

    get = (model) => {
        if (model === undefined) {
            return this.rangeCollection;
        }
        return this.getRangeById(model.id);
    }

    splice = (...args) => {
        return Array.prototype.splice.apply(this.rangeCollection, args);
    }

    getIndex = (model) => {
        let index = {};
        for (let i = 0; i < this.rangeCollection.length; i++) {
            if (this.rangeCollection[i].id === model.id) {
                index = i;
            }
        }
        return index;
    }

    getSelection = () => {
        let selectedRanges = [];
        for (let i = 0; i < this.rangeCollection.length; i++) {
            if (this.rangeCollection[i].selected === true) {
                selectedRanges.push(this.rangeCollection[i]);
            }
        }
        return selectedRanges;
    }

    resetSelection = () => {
        for (let i = 0; i < this.rangeCollection.length; i++) {
            this.rangeCollection[i].selected = false;
        }
    }

    addToSelection = (model) => {
        for (let i = 0; i < this.rangeCollection.length; i++) {
            if (this.rangeCollection[i].id === model.id) {
                this.rangeCollection[i].selected = true;
            }
        }
    }

    removeFromSelection = (model) => {
        for (let i = 0; i < this.rangeCollection.length; i++) {
            if (this.rangeCollection[i].id === model.id) {
                this.rangeCollection[i].selected = false;
            }
        }
    }

    getFirstSelected = () => {
        let firstModel = false;
        for (let i = 0; i < this.rangeCollection.length; i++) {
            if (this.rangeCollection[i].selected === true && firstModel === false) {
                firstModel = this.rangeCollection[i];
            }
        }
        return firstModel;
    }

    getLastSelected = () => {
        let lastModel = false;
        for (let i = 0; i < this.rangeCollection.length; i++) {
            if (this.rangeCollection[i].selected === true) {
                lastModel = this.rangeCollection[i];
            }
        }
        return lastModel;
    }

    reset = (collection) => {
        this.rangeCollection = collection;
        // refresh internal indexes:
        for (let i = 0; i < this.rangeCollection.length; i++) {
            this.rangeCollection[i].index = i;
        }
        this.refreshRangeCollection();
    }

    setActiveRange = (direction) => {
        if (this.currentRange === false) {
            return;
        }
        let toIndex = this.currentRange.index - 1;

        if (direction === 'down') {
            toIndex = this.currentRange.index + 1;
        }

        if (this.rangeCollection[toIndex] !== undefined) {

            this.player_.rangeStream.onNext({
                action: 'change',
                range: this.rangeCollection[toIndex]
            });
        }
    }

    moveRange = (direction) => {
        if (this.currentRange === false) {
            return;
        }
        let collection = this.get();
        let toIndex = this.currentRange.index - 1;

        if (direction === 'down') {
            toIndex = this.currentRange.index + 1;
        }
        this.addToSelection(this.currentRange);
        let selectedModels = this.getSelection();

        for (let i = selectedModels.length; i--;) {
            let fromIndex = this.getIndex(this.get(selectedModels[i]));

            collection.splice(toIndex, 0, this.splice(fromIndex, 1)[0]);
        }

        this.reset(collection);
    }

    refreshRangeCollection = () => {
        // remove any existing items
        for (let i = 0; i < this.rangeItemComponentCollection.length; i++) {
            this.rangeItemComponentCollection[i].dispose();
            this.removeChild(this.rangeItemComponentCollection[i]);
        }
        this.rangeItemComponentCollection = [];

        let activeId = 0;
        if (this.currentRange !== false) {
            activeId = this.currentRange.id;
        }

        for (let i = 0; i < this.rangeCollection.length; i++) {
            let model = _.extend({}, this.rangeCollection[i], {index: i});
            let item = new RangeItem(this.player_, {
                model: model,
                collection: this,
                isActive: this.rangeCollection[i].id === activeId ? true : false
            }, this.settings);

            this.rangeItemComponentCollection.push(item);
            this.addChild(item);

        }
    }

    exportRangesData = (rangeData) => {
        var title = this.settings.translations.alertTitle;
        var message = this.settings.translations.updateTitle;
        var services = this.settings.services;
        $.ajax({
            type: 'POST',
            url: `${this.settings.baseUrl}prod/tools/metadata/save/`,
            data: {
                databox_id: this.settings.databoxId,
                record_id: this.settings.recordId,
                meta_struct_id: this.settings.meta_struct_id,
                value: rangeData
            },
            success: function (data) {
                if (!data.success) {
                    humane.error(data.message);
                } else {
                    humane.info(message);
                }
            }
        });
};
}

videojs.registerComponent('RangeCollection', RangeCollection);

export default RangeCollection;
<|endoftext|>


<commit_before>const typescript = require('rollup-plugin-typescript2');
const replace = require('rollup-plugin-replace');
const resolve = require('rollup-plugin-node-resolve');

const reporters = ['progress'];
const frameworks = ['jasmine'];
const plugins = [
  'karma-jasmine',
  'karma-chrome-launcher',
  'karma-rollup-preprocessor'
];

var customLaunchers = {
  // windows
  bs_chrome: {
    base: 'BrowserStack',
    browser: 'chrome',
    browser_version: '57',
    os: 'Windows',
    os_version: '10'
  },
  bs_firefox: {
    base: 'BrowserStack',
    browser: 'firefox',
    browser_version: '53',
    os: 'Windows',
    os_version: '10'
  },
  bs_ie_11: {
    base: 'BrowserStack',
    browser: 'ie',
    browser_version: '11.0',
    os: 'Windows',
    os_version: '10'
  },
  bs_edge: {
    base: 'BrowserStack',
    browser: 'edge',
    browser_version: '13',
    os: 'Windows',
    os_version: '10'
  },
  // os x
  bs_osx_safari: {
    base: 'BrowserStack',
    browser: 'safari',
    browser_version: '10',
    os: 'OS X',
    os_version: 'Sierra'
  },
  // ios
  bs_ios_safari: {
    base: 'BrowserStack',
    browser: 'Safari',
    os: 'iOS',
    os_version: '10.3',
    device: 'iPhone 7',
    real_mobile: true
  },
  // android
  bs_android_chrome: {
    base: 'BrowserStack',
    browser: 'chrome',
    os: 'android',
    os_version: '7.0',
    device: 'Samsung Galaxy S8',
    real_mobile: true
  }
};

module.exports = function(config) {
  config.set({
    customLaunchers: customLaunchers,
    browsers: ['Chrome'],
    frameworks: frameworks,
    reporters: reporters,

    files: [
      'tests/integration/*.ts'
    ],

    preprocessors: {
     'tests/integration/*.ts': ['rollup']
    },

    mime: {
      'text/x-typescript': ['ts','tsx']
    },

    rollupPreprocessor: {
      plugins: [
        typescript({
          tsconfig: 'tests/integration/tsconfig.json'
        }),
        resolve()
      ],
      format: 'iife',
      sourcemap: 'inline'
    },

    plugins: plugins

  });

  if (process.env.TRAVIS) {
    config.set({
      browsers: Object.keys(customLaunchers),
      singleRun: true,
      reporters: reporters.concat('BrowserStack'),
      plugins: plugins.concat('karma-browserstack-launcher'),
      browserStack: {
        project: 'hickory',
        username: process.env.BROWSERSTACK_USERNAME,
        accessKey: process.env.BROWSERSTACK_ACCESS_KEY,
        build: process.env.TRAVIS_BUILD_NUMBER,
        name: process.env.TRAVIS_JOB_NUMBER,
        video: false,
        timeout: 120
      },
      browserDisconnectTimeout: 10000,
      browserDisconnectTolerance: 1
    });
  }
}
<commit_msg>Karma hash use default timeout<commit_after>const typescript = require("rollup-plugin-typescript2");
const replace = require("rollup-plugin-replace");
const resolve = require("rollup-plugin-node-resolve");

const reporters = ["progress"];
const frameworks = ["jasmine"];
const plugins = [
  "karma-jasmine",
  "karma-chrome-launcher",
  "karma-rollup-preprocessor"
];

var customLaunchers = {
  // windows
  bs_chrome: {
    base: "BrowserStack",
    browser: "chrome",
    browser_version: "57",
    os: "Windows",
    os_version: "10"
  },
  bs_firefox: {
    base: "BrowserStack",
    browser: "firefox",
    browser_version: "53",
    os: "Windows",
    os_version: "10"
  },
  bs_ie_11: {
    base: "BrowserStack",
    browser: "ie",
    browser_version: "11.0",
    os: "Windows",
    os_version: "10"
  },
  bs_edge: {
    base: "BrowserStack",
    browser: "edge",
    browser_version: "13",
    os: "Windows",
    os_version: "10"
  },
  // os x
  bs_osx_safari: {
    base: "BrowserStack",
    browser: "safari",
    browser_version: "10",
    os: "OS X",
    os_version: "Sierra"
  },
  // ios
  bs_ios_safari: {
    base: "BrowserStack",
    browser: "Safari",
    os: "iOS",
    os_version: "10.3",
    device: "iPhone 7",
    real_mobile: true
  },
  // android
  bs_android_chrome: {
    base: "BrowserStack",
    browser: "chrome",
    os: "android",
    os_version: "7.0",
    device: "Samsung Galaxy S8",
    real_mobile: true
  }
};

module.exports = function(config) {
  config.set({
    customLaunchers: customLaunchers,
    browsers: ["Chrome"],
    frameworks: frameworks,
    reporters: reporters,

    files: ["tests/integration/*.ts"],

    preprocessors: {
      "tests/integration/*.ts": ["rollup"]
    },

    mime: {
      "text/x-typescript": ["ts", "tsx"]
    },

    rollupPreprocessor: {
      plugins: [
        typescript({
          tsconfig: "tests/integration/tsconfig.json"
        }),
        resolve()
      ],
      format: "iife",
      sourcemap: "inline"
    },

    plugins: plugins
  });

  if (process.env.TRAVIS) {
    config.set({
      browsers: Object.keys(customLaunchers),
      singleRun: true,
      reporters: reporters.concat("BrowserStack"),
      plugins: plugins.concat("karma-browserstack-launcher"),
      browserStack: {
        project: "hickory",
        username: process.env.BROWSERSTACK_USERNAME,
        accessKey: process.env.BROWSERSTACK_ACCESS_KEY,
        build: process.env.TRAVIS_BUILD_NUMBER,
        name: process.env.TRAVIS_JOB_NUMBER,
        video: false
      },
      browserDisconnectTimeout: 10000,
      browserDisconnectTolerance: 1
    });
  }
};
<|endoftext|>


<commit_before>// weui
import 'weui';

// vue系列
import Vue from 'vue';
import VueTouch from 'vue-touch';
import VueRouter from 'vue-router';
import VuePseudo from './modules/vue-pseudo.js';

// 注册插件
Vue.use(VueTouch);
Vue.use(VueRouter);
Vue.use(VuePseudo);

// 组件
import app from './components/app.vue';
import test from './components/test.vue';

// 配置路由
let router = new VueRouter();

// 注册组件
router.map({
    '/chats' : {
		component : test,
	},
	'/contacts' : {
		component : test,
	},
	'/discover' : {
		component : test,
	},
	'/me' : {
		component : test,
	},
    '/error' : {
		component : test,
	},
    '/test' : {
		component : test,
	},
});

router.redirect({
  '/' : '/chats',
  '*' : '/error',
});

router.start(app, 'app');

if (process.env.NODE_ENV !== 'production') {
    window.router = router;
}
<commit_msg>update index<commit_after>// weui
import 'weui';

// vue系列
import Vue from 'vue';
import VueTouch from 'vue-touch';
import VuePseudo from 'vue-pseudo';
import VueRouter from 'vue-router';

// 注册插件
Vue.use(VueTouch);
Vue.use(VuePseudo);
Vue.use(VueRouter);

// 组件
import app from './components/app.vue';
import test from './components/test.vue';

// 配置路由
let router = new VueRouter();

// 注册组件
router.map({
    '/chats' : {
		component : test,
	},
    '/chats/*view' : {
		component : test,
	},
	'/contacts' : {
		component : test,
	},
    '/contacts/*view' : {
		component : test,
	},
	'/discover' : {
		component : test,
	},
    '/discover/*view' : {
		component : test,
	},
	'/me' : {
		component : test,
	},
    '/me/*view' : {
		component : test,
	},
    '/error' : {
		component : test,
	},
});

router.redirect({
    '/' : '/chats',
    '*' : '/error',
});

router.start(app, 'app');

if (process.env.NODE_ENV !== 'production') {
    window.router = router;
}
<|endoftext|>


<commit_before>
import getWindow from 'get-window'
import isBackward from 'selection-is-backward'
import { IS_SAFARI, IS_IOS } from '../constants/environment'

/**
 * CSS overflow values that would cause scrolling.
 *
 * @type {Array}
 */

const OVERFLOWS = [
  'auto',
  'overlay',
  'scroll',
]

/**
 * Find the nearest parent with scrolling, or window.
 *
 * @param {el} Element
 */

function findScrollContainer(el, window) {
  let parent = el.parentNode
  let scroller

  while (!scroller) {
    if (!parent.parentNode) break

    const style = window.getComputedStyle(parent)
    const { overflowY } = style

    if (OVERFLOWS.includes(overflowY)) {
      scroller = parent
      break
    }

    parent = parent.parentNode
  }

  // COMPAT: Because Chrome does not allow doucment.body.scrollTop, we're
  // assuming that window.scrollTo() should be used if the scrollable element
  // turns out to be document.body or document.documentElement. This will work
  // unless body is intentionally set to scrollable by restricting its height
  // (e.g. height: 100vh).
  if (!scroller) {
    return window.document.body
  }

  return scroller
}

/**
 * Get the current iOS version. Assumes that an IOS check was conducted
 * prior to calling.
 */

const IOS_VERSION_REGEX = /OS (\d+)_/

function getMajorIOSVersion() {
  const { userAgent } = window.navigator
  const matches = userAgent.match(IOS_VERSION_REGEX)
  return matches ? parseInt(matches[1]) : null
}

/**
 * Scroll the current selection's focus point into view if needed.
 *
 * @param {Selection} selection
 */

function scrollToSelection(selection) {
  if (IS_IOS) {
    const majorIOSVersion = getMajorIOSVersion()
    if (majorIOSVersion && majorIOSVersion == 11) return
  }

  if (!selection.anchorNode) return

  const window = getWindow(selection.anchorNode)
  const scroller = findScrollContainer(selection.anchorNode, window)
  const isWindow = scroller == window.document.body || scroller == window.document.documentElement
  const backward = isBackward(selection)

  const range = selection.getRangeAt(0).cloneRange()
  range.collapse(backward)
  let cursorRect = range.getBoundingClientRect()

  // COMPAT: range.getBoundingClientRect() returns 0s in Safari when range is
  // collapsed. Expanding the range by 1 is a relatively effective workaround
  // for vertical scroll, although horizontal may be off by 1 character.
  // https://bugs.webkit.org/show_bug.cgi?id=138949
  // https://bugs.chromium.org/p/chromium/issues/detail?id=435438
  if (IS_SAFARI) {
    if (range.collapsed && cursorRect.top == 0 && cursorRect.height == 0) {
      if (range.startOffset == 0) {
        range.setEnd(range.endContainer, 1)
      } else {
        range.setStart(range.startContainer, range.startOffset - 1)
      }

      cursorRect = range.getBoundingClientRect()

      if (cursorRect.top == 0 && cursorRect.height == 0) {
        if (range.getClientRects().length) {
          cursorRect = range.getClientRects()[0]
        }
      }
    }
  }

  let width
  let height
  let yOffset
  let xOffset
  let scrollerTop = 0
  let scrollerLeft = 0
  let scrollerBordersY = 0
  let scrollerBordersX = 0
  let scrollerPaddingTop = 0
  let scrollerPaddingBottom = 0
  let scrollerPaddingLeft = 0
  let scrollerPaddingRight = 0

  if (isWindow) {
    const { innerWidth, innerHeight, pageYOffset, pageXOffset } = window
    width = innerWidth
    height = innerHeight
    yOffset = pageYOffset
    xOffset = pageXOffset
  } else {
    const { offsetWidth, offsetHeight, scrollTop, scrollLeft } = scroller
    const {
      borderTopWidth,
      borderBottomWidth,
      borderLeftWidth,
      borderRightWidth,
      paddingTop,
      paddingBottom,
      paddingLeft,
      paddingRight,
    } = window.getComputedStyle(scroller)

    const scrollerRect = scroller.getBoundingClientRect()
    width = offsetWidth
    height = offsetHeight
    scrollerTop = scrollerRect.top + parseInt(borderTopWidth, 10)
    scrollerLeft = scrollerRect.left + parseInt(borderLeftWidth, 10)
    scrollerBordersY = parseInt(borderTopWidth, 10) + parseInt(borderBottomWidth, 10)
    scrollerBordersX = parseInt(borderLeftWidth, 10) + parseInt(borderRightWidth, 10)
    scrollerPaddingTop = parseInt(paddingTop, 10)
    scrollerPaddingBottom = parseInt(paddingBottom, 10)
    scrollerPaddingLeft = parseInt(paddingLeft, 10)
    scrollerPaddingRight = parseInt(paddingRight, 10)
    yOffset = scrollTop
    xOffset = scrollLeft
  }

  const cursorTop = cursorRect.top + yOffset - scrollerTop
  const cursorLeft = cursorRect.left + xOffset - scrollerLeft

  let x = xOffset
  let y = yOffset

  if (cursorLeft < xOffset) {
    // selection to the left of viewport
    x = cursorLeft - scrollerPaddingLeft
  } else if (cursorLeft + cursorRect.width + scrollerBordersX > xOffset + width) {
    // selection to the right of viewport
    x = cursorLeft + scrollerBordersX + scrollerPaddingRight - width
  }

  if (cursorTop < yOffset) {
    // selection above viewport
    y = cursorTop - scrollerPaddingTop
  } else if (cursorTop + cursorRect.height + scrollerBordersY > yOffset + height) {
    // selection below viewport
    y = cursorTop + scrollerBordersY + scrollerPaddingBottom + cursorRect.height - height
  }

  if (isWindow) {
    window.scrollTo(x, y)
  } else {
    scroller.scrollTop = y
    scroller.scrollLeft = x
  }
}

/**
 * Export.
 *
 * @type {Function}
 */

export default scrollToSelection
<commit_msg>Updated scroll-to-selection so it skips the scroll only on version 11 of iOS.<commit_after>
import getWindow from 'get-window'
import isBackward from 'selection-is-backward'
import { IS_SAFARI, IS_IOS } from '../constants/environment'

/**
 * CSS overflow values that would cause scrolling.
 *
 * @type {Array}
 */

const OVERFLOWS = [
  'auto',
  'overlay',
  'scroll',
]

/**
 * Detect whether we are running IOS version 11
 */

const IS_IOS_11 = IS_IOS && !!window.navigator.userAgent.match(/os 11_/i)

/**
 * Find the nearest parent with scrolling, or window.
 *
 * @param {el} Element
 */

function findScrollContainer(el, window) {
  let parent = el.parentNode
  let scroller

  while (!scroller) {
    if (!parent.parentNode) break

    const style = window.getComputedStyle(parent)
    const { overflowY } = style

    if (OVERFLOWS.includes(overflowY)) {
      scroller = parent
      break
    }

    parent = parent.parentNode
  }

  // COMPAT: Because Chrome does not allow doucment.body.scrollTop, we're
  // assuming that window.scrollTo() should be used if the scrollable element
  // turns out to be document.body or document.documentElement. This will work
  // unless body is intentionally set to scrollable by restricting its height
  // (e.g. height: 100vh).
  if (!scroller) {
    return window.document.body
  }

  return scroller
}

/**
 * Scroll the current selection's focus point into view if needed.
 *
 * @param {Selection} selection
 */

function scrollToSelection(selection) {
  if (IS_IOS_11) return
  if (!selection.anchorNode) return

  const window = getWindow(selection.anchorNode)
  const scroller = findScrollContainer(selection.anchorNode, window)
  const isWindow = scroller == window.document.body || scroller == window.document.documentElement
  const backward = isBackward(selection)

  const range = selection.getRangeAt(0).cloneRange()
  range.collapse(backward)
  let cursorRect = range.getBoundingClientRect()

  // COMPAT: range.getBoundingClientRect() returns 0s in Safari when range is
  // collapsed. Expanding the range by 1 is a relatively effective workaround
  // for vertical scroll, although horizontal may be off by 1 character.
  // https://bugs.webkit.org/show_bug.cgi?id=138949
  // https://bugs.chromium.org/p/chromium/issues/detail?id=435438
  if (IS_SAFARI) {
    if (range.collapsed && cursorRect.top == 0 && cursorRect.height == 0) {
      if (range.startOffset == 0) {
        range.setEnd(range.endContainer, 1)
      } else {
        range.setStart(range.startContainer, range.startOffset - 1)
      }

      cursorRect = range.getBoundingClientRect()

      if (cursorRect.top == 0 && cursorRect.height == 0) {
        if (range.getClientRects().length) {
          cursorRect = range.getClientRects()[0]
        }
      }
    }
  }

  let width
  let height
  let yOffset
  let xOffset
  let scrollerTop = 0
  let scrollerLeft = 0
  let scrollerBordersY = 0
  let scrollerBordersX = 0
  let scrollerPaddingTop = 0
  let scrollerPaddingBottom = 0
  let scrollerPaddingLeft = 0
  let scrollerPaddingRight = 0

  if (isWindow) {
    const { innerWidth, innerHeight, pageYOffset, pageXOffset } = window
    width = innerWidth
    height = innerHeight
    yOffset = pageYOffset
    xOffset = pageXOffset
  } else {
    const { offsetWidth, offsetHeight, scrollTop, scrollLeft } = scroller
    const {
      borderTopWidth,
      borderBottomWidth,
      borderLeftWidth,
      borderRightWidth,
      paddingTop,
      paddingBottom,
      paddingLeft,
      paddingRight,
    } = window.getComputedStyle(scroller)

    const scrollerRect = scroller.getBoundingClientRect()
    width = offsetWidth
    height = offsetHeight
    scrollerTop = scrollerRect.top + parseInt(borderTopWidth, 10)
    scrollerLeft = scrollerRect.left + parseInt(borderLeftWidth, 10)
    scrollerBordersY = parseInt(borderTopWidth, 10) + parseInt(borderBottomWidth, 10)
    scrollerBordersX = parseInt(borderLeftWidth, 10) + parseInt(borderRightWidth, 10)
    scrollerPaddingTop = parseInt(paddingTop, 10)
    scrollerPaddingBottom = parseInt(paddingBottom, 10)
    scrollerPaddingLeft = parseInt(paddingLeft, 10)
    scrollerPaddingRight = parseInt(paddingRight, 10)
    yOffset = scrollTop
    xOffset = scrollLeft
  }

  const cursorTop = cursorRect.top + yOffset - scrollerTop
  const cursorLeft = cursorRect.left + xOffset - scrollerLeft

  let x = xOffset
  let y = yOffset

  if (cursorLeft < xOffset) {
    // selection to the left of viewport
    x = cursorLeft - scrollerPaddingLeft
  } else if (cursorLeft + cursorRect.width + scrollerBordersX > xOffset + width) {
    // selection to the right of viewport
    x = cursorLeft + scrollerBordersX + scrollerPaddingRight - width
  }

  if (cursorTop < yOffset) {
    // selection above viewport
    y = cursorTop - scrollerPaddingTop
  } else if (cursorTop + cursorRect.height + scrollerBordersY > yOffset + height) {
    // selection below viewport
    y = cursorTop + scrollerBordersY + scrollerPaddingBottom + cursorRect.height - height
  }

  if (isWindow) {
    window.scrollTo(x, y)
  } else {
    scroller.scrollTop = y
    scroller.scrollLeft = x
  }
}

/**
 * Export.
 *
 * @type {Function}
 */

export default scrollToSelection
<|endoftext|>


<commit_before>/*
 * The main component for the home page.
 */

import React, {Component} from 'react';

import {routeData} from '../../data/Routes';
import {Blurb, Heading, Link, MailLink} from '../../Components';

Link.registerPreloadResources('/', () => [
    require('./me.png'),
]);

export default class HomePage extends Component {

    render() {
        const urls = {
            cmu: "https://www.cs.cmu.edu",
            resume: require("./resume.pdf"),
            github: "https://github.com/wchargin",
        };
        return

            <Heading level={1}>Hey!</Heading>
            <Blurb
                image={require("./me.png")}
                imagePosition={Blurb.IMAGE_RIGHT}
            >

                    I’m pursuing a computer science major and math minor
                    at <Link href={urls.cmu}>Carnegie Mellon</Link>.
                    I love computer science because it unites math, logic,
                    and critical thinking into a powerful toolset that
                    I can use to solve real-world problems. You’ve
                    landed on my personal website and portfolio.

                    Helpful info and links:

                        Pick up a copy of my{" "}
                        <Link href={urls.resume}>résumé!</Link>

                        Feel free to check out{" "}
                        <Link href={urls.github}>my GitHub profile!</Link>

                        If you’d like to contact me,{" "}
                        <MailLink>request my email!</MailLink>

            </Blurb>
            <Heading level={2}>What do you want to know?</Heading>

                    My surname is pronounced with a hard g: it
                    rhymes with bargain,
                    not barge in.

                    My hobbies include learning Greek and the game of Go.

                    Here are some more pages with information about me:

                        {routeData.map(route =>
                            !route.isIndex && route.navbarTitle &&

                                <Link key={route.path} to={route.path}>
                                    {route.navbarTitle}
                                </Link>

)}

;
    }

}
<commit_msg>Strengthen calls to action on the home page<commit_after>/*
 * The main component for the home page.
 */

import React, {Component} from 'react';

import {routeData} from '../../data/Routes';
import {Blurb, Heading, Link, MailLink} from '../../Components';

Link.registerPreloadResources('/', () => [
    require('./me.png'),
]);

export default class HomePage extends Component {

    render() {
        const urls = {
            cmu: "https://www.cs.cmu.edu",
            resume: require("./resume.pdf"),
            github: "https://github.com/wchargin",
        };
        return

            <Heading level={1}>Hey!</Heading>
            <Blurb
                image={require("./me.png")}
                imagePosition={Blurb.IMAGE_RIGHT}
            >

                    I’m pursuing a computer science major and math minor
                    at <Link href={urls.cmu}>Carnegie Mellon</Link>.
                    I love computer science because it unites math, logic,
                    and critical thinking into a powerful toolset that
                    I can use to solve real-world problems. You’ve
                    landed on my personal website and portfolio.

                    Helpful info and links:

                        Pick up a copy of my{" "}
                        <Link href={urls.resume}>
                            résumé!
                        </Link>

                        Feel free to check out{" "}
                        <Link href={urls.github}>
                            my GitHub profile!
                        </Link>

                        If you’d like to contact me,{" "}
                        <MailLink>
                            request my email!
                        </MailLink>

            </Blurb>
            <Heading level={2}>What do you want to know?</Heading>

                    My surname is pronounced with a hard g: it
                    rhymes with bargain,
                    not barge in.

                    My hobbies include learning Greek and the game of Go.

                    Here are some more pages with information about me:

                        {routeData.map(route =>
                            !route.isIndex && route.navbarTitle &&

                                <Link key={route.path} to={route.path}>
                                    {route.navbarTitle}
                                </Link>

)}

;
    }

}
<|endoftext|>