<commit_before>/*jslint browser: true, for: true */
/*global dashjs, flowplayer, MediaPlayer, window */

/*!

   MPEG-DASH engine plugin for Flowplayer HTML5

   Copyright (c) 2015-2016, Flowplayer Oy

   Released under the MIT License:
   http://www.opensource.org/licenses/mit-license.php

   Includes hls.js
   Copyright (c) 2015 Dailymotion (http://www.dailymotion.com)
   https://github.com/dailymotion/hls.js/blob/master/LICENSE

   Includes es5.js
   https://github.com/inexorabletash/polyfill/blob/master/es5.js
   for compatibility with legacy browsers

   Requires Flowplayer HTML5 version 6.x
   revision: $GIT_ID$

*/

(function (flowplayer, dashjs) {
    "use strict";
    var engineName = "dash",
        mse = window.MediaSource,
        common = flowplayer.common,
        extend = flowplayer.extend,
        version = flowplayer.version,
        dashconf,

        dashCanPlay = function (sourceType, dashType, dashCodecs) {
            return sourceType.toLowerCase() === "application/dash+xml" &&
                    mse.isTypeSupported(dashType + ';codecs="' + dashCodecs + '"') &&
                    // Android MSE advertises he-aac, but fails
                    (dashCodecs.indexOf("mp4a.40.5") < 0 || navigator.userAgent.indexOf("Android") < 0);
        },

        engineImpl = function dashjsEngine(player, root) {
            var bean = flowplayer.bean,
                mediaPlayer,
                videoTag,
                bc,
                has_bg,

                engine = {
                    engineName: engineName,

                    pick: function (sources) {
                        var i,
                            source,
                            dashType,
                            dashCodecs;

                        for (i = 0; i < sources.length; i += 1) {
                            source = sources[i];
                            dashType = source.dashType || dashconf.type;
                            dashCodecs = source.dashCodecs || dashconf.codecs;
                            if (dashCanPlay(source.type, dashType, dashCodecs)) {
                                if (typeof source.src === 'string') {
                                    source.src = common.createAbsoluteUrl(source.src);
                                }
                                return source;
                            }
                        }
                    },

                    load: function (video) {
                        var conf = player.conf,
                            EVENTS = {
                                ended: "finish",
                                loadeddata: "ready",
                                pause: "pause",
                                play: "resume",
                                progress: "buffer",
                                ratechange: "speed",
                                seeked: "seek",
                                timeupdate: "progress",
                                volumechange: "volume"
                            },
                            DASHEVENTS = dashjs.MediaPlayer.events,
                            autoplay = !!video.autoplay || !!conf.autoplay,
                            posterClass = "is-poster",
                            livestartpos = 0;

                        if (!mediaPlayer) {
                            common.removeNode(common.findDirect("video", root)[0]
                                    || common.find(".fp-player > video", root)[0]);
                            // dash.js enforces preload="auto" and
                            // autoplay depending on initialization
                            // so setting the attributes here will have no effect
                            videoTag = common.createElement("video", {
                                "class": "fp-engine " + engineName + "-engine",
                                "x-webkit-airplay": "allow"
                            });

                            Object.keys(EVENTS).forEach(function (key) {
                                var flow = EVENTS[key],
                                    type = key + "." + engineName,
                                    arg;

                                bean.on(videoTag, type, function (e) {
                                    if (conf.debug && flow.indexOf("progress") < 0) {
                                        console.log(type, "->", flow, e.originalEvent);
                                    }
                                    if (!player.ready && flow.indexOf("ready") < 0) {
                                        return;
                                    }

                                    var ct = 0,
                                        buffer = 0,
                                        buffend = 0,
                                        buffered,
                                        i;

                                    switch (flow) {
                                    case "ready":
                                        arg = extend(player.video, {
                                            duration: videoTag.duration,
                                            seekable: videoTag.seekable.end(null),
                                            width: videoTag.videoWidth,
                                            height: videoTag.videoHeight,
                                            url: player.video.src
                                        });
                                        break;
                                    case "resume":
                                        if (player.poster) {
                                            player.poster = false;
                                            common.removeClass(root, posterClass);
                                        }
                                        break;
                                    case "seek":
                                    case "progress":
                                        ct = videoTag.currentTime;
                                        if (player.video.live && !livestartpos && ct > 0) {
                                            livestartpos = ct;
                                        }
                                        arg = !player.video.live
                                            ? ct
                                            : livestartpos
                                                ? ct - livestartpos
                                                : 0;
                                        break;
                                    case "speed":
                                        arg = videoTag.playbackRate;
                                        break;
                                    case "volume":
                                        arg = videoTag.volume;
                                        break;
                                    case "buffer":
                                        try {
                                            ct = videoTag.currentTime;
                                            // cycle through time ranges to obtain buffer
                                            // nearest current time
                                            if (ct) {
                                                buffered = videoTag.buffered;
                                                for (i = buffered.length - 1; i > -1; i -= 1) {
                                                    buffend = buffered.end(i);

                                                    if (buffend >= ct) {
                                                        buffer = buffend;
                                                    }
                                                }
                                            }
                                        } catch (ignore) {}
                                        video.buffer = buffer;
                                        arg = e;
                                        break;
                                    }

                                    player.trigger(flow, [player, arg]);
                                });
                            });

                            if (conf.poster) {
                                var posterHack = function () {
                                    setTimeout(function () {
                                        if (!player.poster) {
                                            common.addClass(root, posterClass);
                                            player.poster = true;
                                        }
                                    }, 0);
                                };

                                player.one("ready." + engineName, posterHack).on("stop." + engineName, posterHack);
                            }
                            player.on("error." + engineName, function () {
                                if (mediaPlayer) {
                                    mediaPlayer.reset();
                                    mediaPlayer = 0;
                                }
                            });

                            mediaPlayer = dashjs.MediaPlayer().create();
                            player.engine[engineName] = mediaPlayer;

                            // new ABR algo
                            mediaPlayer.enableBufferOccupancyABR(!!dashconf.bufferOccupancyABR);
                            // caching can cause failures in playlists
                            // for the moment disable entirely
                            mediaPlayer.enableLastBitrateCaching(false);
                            // for seeking in paused state
                            mediaPlayer.setScheduleWhilePaused(true);
                            mediaPlayer.getDebug().setLogToBrowserConsole(!!dashconf.debug);

                            Object.keys(DASHEVENTS).forEach(function (key) {
                                var etype = DASHEVENTS[key],
                                    fpEventType = engineName + etype.charAt(0).toUpperCase() + etype.slice(1),
                                    listeners = dashconf.listeners,
                                    expose = listeners && listeners.indexOf(etype) > -1;

                                mediaPlayer.on(etype, function (e) {
                                    var data = extend({}, e),
                                        src = player.video.src,
                                        fperr,
                                        errobj;

                                    delete data.type;
                                    switch (key) {
                                    case "ERROR":
                                        switch (data.error) {
                                        case "download":
                                            fperr = 4;
                                            break;
                                        case "manifestError":
                                            fperr = 5;
                                            break;
                                        case "mediasource":
                                            switch (e.event) {
                                            case "MEDIA_ERR_DECODE":
                                                fperr = 3;
                                                break;
                                            case "MEDIA_ERR_SRC_NOT_SUPPORTED":
                                                fperr = 5;
                                                break;
                                            case "MEDIA_ERR_NETWORK":
                                                fperr = 2;
                                                break;
                                            case "MEDIA_ERR_ABORTED":
                                                fperr = 1;
                                                break;
                                            }
                                            break;
                                        }
                                        if (fperr) {
                                            errobj = {code: fperr};
                                            if (fperr > 2) {
                                                errobj.video = extend(video, {
                                                    src: src,
                                                    url: data.event.url || src
                                                });
                                            }
                                            player.trigger('error', [player, errobj]);
                                            return;
                                        }
                                        break;
                                    }

                                    if (expose) {
                                        player.trigger(fpEventType, [player, data]);
                                    }
                                });
                            });

                            common.prepend(common.find(".fp-player", root)[0], videoTag);
                            mediaPlayer.initialize(videoTag, video.src, autoplay);

                            // at least some Android requires extra load
                            // https://github.com/flowplayer/flowplayer/issues/910
                            if (autoplay && !flowplayer.support.zeropreload) {
                                videoTag.load();
                            }

                        } else {
                            if ((player.video.src && video.src !== player.video.src) || video.index) {
                                mediaPlayer.setAutoPlay(true);
                            }
                            mediaPlayer.attachSource(video.src);

                        }

                        // update video object before ready
                        player.video = video;
                    },

                    resume: function () {
                        videoTag.play();
                    },

                    pause: function () {
                        videoTag.pause();
                    },

                    seek: function (time) {
                        videoTag.currentTime = time;
                    },

                    volume: function (level) {
                        if (videoTag) {
                            videoTag.volume = level;
                        }
                    },

                    speed: function (val) {
                        videoTag.playbackRate = val;
                        player.trigger('speed', [player, val]);
                    },

                    unload: function () {
                        if (mediaPlayer) {
                            var listeners = "." + engineName;

                            mediaPlayer.reset();
                            mediaPlayer = 0;
                            player.off(listeners);
                            bean.off(root, listeners);
                            bean.off(videoTag, listeners);
                            common.removeNode(videoTag);
                            videoTag = 0;
                        }
                    }
                };

            // pre 6.0.4: no boolean api.conf.poster and no poster with autoplay
            if (/^6\.0\.[0-3]$/.test(version) &&
                    !player.conf.splash && !player.conf.poster && !player.conf.autoplay) {
                bc = common.css(root, 'backgroundColor');
                // spaces in rgba arg mandatory for recognition
                has_bg = common.css(root, 'backgroundImage') !== "none" ||
                        (bc && bc !== "rgba(0, 0, 0, 0)" && bc !== "transparent");
                if (has_bg) {
                    player.conf.poster = true;
                }
            }

            return engine;
        };

    if (mse && typeof mse.isTypeSupported === "function" && version.indexOf("5.") !== 0) {
        // only load engine if it can be used
        engineImpl.engineName = engineName; // must be exposed
        engineImpl.canPlay = function (type, conf) {
            /*
              WARNING: MediaSource.isTypeSupported very inconsistent!
              e.g. Safari ignores codecs entirely, even bogus, like codecs="XYZ"
              example avc3 main level 3.1 + aac_he: avc3.4d401f; mp4a.40.5
              example avc1 high level 4.1 + aac_lc: avc1.640029; mp4a.40.2
              default: avc1 baseline level 3.0 + aac_lc
            */
            // inject dash conf at earliest opportunity
            dashconf = extend({
                type: "video/mp4",
                codecs: "avc1.42c01e,mp4a.40.2"
            }, flowplayer.conf[engineName], conf[engineName], conf.clip[engineName]);

            return dashCanPlay(type, dashconf.type, dashconf.codecs);
        };

        // put on top of engine stack
        // so mpegedash is tested before html5
        flowplayer.engines.unshift(engineImpl);

    }

}.apply(null, (typeof module === 'object' && module.exports)
    ? [require('flowplayer'), require('dashjs')]
    : [window.flowplayer, window.dashjs]));
<commit_msg>Internal dash config must be updated on engine load<commit_after>/*jslint browser: true, for: true */
/*global dashjs, flowplayer, MediaPlayer, window */

/*!

   MPEG-DASH engine plugin for Flowplayer HTML5

   Copyright (c) 2015-2016, Flowplayer Oy

   Released under the MIT License:
   http://www.opensource.org/licenses/mit-license.php

   Includes hls.js
   Copyright (c) 2015 Dailymotion (http://www.dailymotion.com)
   https://github.com/dailymotion/hls.js/blob/master/LICENSE

   Includes es5.js
   https://github.com/inexorabletash/polyfill/blob/master/es5.js
   for compatibility with legacy browsers

   Requires Flowplayer HTML5 version 6.x
   revision: $GIT_ID$

*/

(function (flowplayer, dashjs) {
    "use strict";
    var engineName = "dash",
        mse = window.MediaSource,
        common = flowplayer.common,
        extend = flowplayer.extend,
        version = flowplayer.version,
        dashconf,

        dashCanPlay = function (sourceType, dashType, dashCodecs) {
            return sourceType.toLowerCase() === "application/dash+xml" &&
                    mse.isTypeSupported(dashType + ';codecs="' + dashCodecs + '"') &&
                    // Android MSE advertises he-aac, but fails
                    (dashCodecs.indexOf("mp4a.40.5") < 0 || navigator.userAgent.indexOf("Android") < 0);
        },

        engineImpl = function dashjsEngine(player, root) {
            var bean = flowplayer.bean,
                mediaPlayer,
                videoTag,
                bc,
                has_bg,

                engine = {
                    engineName: engineName,

                    pick: function (sources) {
                        var i,
                            source,
                            dashType,
                            dashCodecs;

                        for (i = 0; i < sources.length; i += 1) {
                            source = sources[i];
                            dashType = source.dashType || dashconf.type;
                            dashCodecs = source.dashCodecs || dashconf.codecs;
                            if (dashCanPlay(source.type, dashType, dashCodecs)) {
                                if (typeof source.src === 'string') {
                                    source.src = common.createAbsoluteUrl(source.src);
                                }
                                return source;
                            }
                        }
                    },

                    load: function (video) {
                        var conf = player.conf,
                            dashUpdatedConf = extend(dashconf, conf.dash, conf.clip.dash),
                            EVENTS = {
                                ended: "finish",
                                loadeddata: "ready",
                                pause: "pause",
                                play: "resume",
                                progress: "buffer",
                                ratechange: "speed",
                                seeked: "seek",
                                timeupdate: "progress",
                                volumechange: "volume"
                            },
                            DASHEVENTS = dashjs.MediaPlayer.events,
                            autoplay = !!video.autoplay || !!conf.autoplay,
                            posterClass = "is-poster",
                            livestartpos = 0;

                        if (!mediaPlayer) {
                            common.removeNode(common.findDirect("video", root)[0]
                                    || common.find(".fp-player > video", root)[0]);
                            // dash.js enforces preload="auto" and
                            // autoplay depending on initialization
                            // so setting the attributes here will have no effect
                            videoTag = common.createElement("video", {
                                "class": "fp-engine " + engineName + "-engine",
                                "x-webkit-airplay": "allow"
                            });

                            Object.keys(EVENTS).forEach(function (key) {
                                var flow = EVENTS[key],
                                    type = key + "." + engineName,
                                    arg;

                                bean.on(videoTag, type, function (e) {
                                    if (conf.debug && flow.indexOf("progress") < 0) {
                                        console.log(type, "->", flow, e.originalEvent);
                                    }
                                    if (!player.ready && flow.indexOf("ready") < 0) {
                                        return;
                                    }

                                    var ct = 0,
                                        buffer = 0,
                                        buffend = 0,
                                        buffered,
                                        i;

                                    switch (flow) {
                                    case "ready":
                                        arg = extend(player.video, {
                                            duration: videoTag.duration,
                                            seekable: videoTag.seekable.end(null),
                                            width: videoTag.videoWidth,
                                            height: videoTag.videoHeight,
                                            url: player.video.src
                                        });
                                        break;
                                    case "resume":
                                        if (player.poster) {
                                            player.poster = false;
                                            common.removeClass(root, posterClass);
                                        }
                                        break;
                                    case "seek":
                                    case "progress":
                                        ct = videoTag.currentTime;
                                        if (player.video.live && !livestartpos && ct > 0) {
                                            livestartpos = ct;
                                        }
                                        arg = !player.video.live
                                            ? ct
                                            : livestartpos
                                                ? ct - livestartpos
                                                : 0;
                                        break;
                                    case "speed":
                                        arg = videoTag.playbackRate;
                                        break;
                                    case "volume":
                                        arg = videoTag.volume;
                                        break;
                                    case "buffer":
                                        try {
                                            ct = videoTag.currentTime;
                                            // cycle through time ranges to obtain buffer
                                            // nearest current time
                                            if (ct) {
                                                buffered = videoTag.buffered;
                                                for (i = buffered.length - 1; i > -1; i -= 1) {
                                                    buffend = buffered.end(i);

                                                    if (buffend >= ct) {
                                                        buffer = buffend;
                                                    }
                                                }
                                            }
                                        } catch (ignore) {}
                                        video.buffer = buffer;
                                        arg = e;
                                        break;
                                    }

                                    player.trigger(flow, [player, arg]);
                                });
                            });

                            if (conf.poster) {
                                var posterHack = function () {
                                    setTimeout(function () {
                                        if (!player.poster) {
                                            common.addClass(root, posterClass);
                                            player.poster = true;
                                        }
                                    }, 0);
                                };

                                player.one("ready." + engineName, posterHack).on("stop." + engineName, posterHack);
                            }
                            player.on("error." + engineName, function () {
                                if (mediaPlayer) {
                                    mediaPlayer.reset();
                                    mediaPlayer = 0;
                                }
                            });

                            mediaPlayer = dashjs.MediaPlayer().create();
                            player.engine[engineName] = mediaPlayer;

                            // new ABR algo
                            mediaPlayer.enableBufferOccupancyABR(!!dashUpdatedConf.bufferOccupancyABR);
                            // caching can cause failures in playlists
                            // for the moment disable entirely
                            mediaPlayer.enableLastBitrateCaching(false);
                            // for seeking in paused state
                            mediaPlayer.setScheduleWhilePaused(true);
                            mediaPlayer.getDebug().setLogToBrowserConsole(!!dashUpdatedConf.debug);

                            Object.keys(DASHEVENTS).forEach(function (key) {
                                var etype = DASHEVENTS[key],
                                    fpEventType = engineName + etype.charAt(0).toUpperCase() + etype.slice(1),
                                    listeners = dashUpdatedConf.listeners,
                                    expose = listeners && listeners.indexOf(etype) > -1;

                                mediaPlayer.on(etype, function (e) {
                                    var data = extend({}, e),
                                        src = player.video.src,
                                        fperr,
                                        errobj;

                                    delete data.type;
                                    switch (key) {
                                    case "ERROR":
                                        switch (data.error) {
                                        case "download":
                                            fperr = 4;
                                            break;
                                        case "manifestError":
                                            fperr = 5;
                                            break;
                                        case "mediasource":
                                            switch (e.event) {
                                            case "MEDIA_ERR_DECODE":
                                                fperr = 3;
                                                break;
                                            case "MEDIA_ERR_SRC_NOT_SUPPORTED":
                                                fperr = 5;
                                                break;
                                            case "MEDIA_ERR_NETWORK":
                                                fperr = 2;
                                                break;
                                            case "MEDIA_ERR_ABORTED":
                                                fperr = 1;
                                                break;
                                            }
                                            break;
                                        }
                                        if (fperr) {
                                            errobj = {code: fperr};
                                            if (fperr > 2) {
                                                errobj.video = extend(video, {
                                                    src: src,
                                                    url: data.event.url || src
                                                });
                                            }
                                            player.trigger('error', [player, errobj]);
                                            return;
                                        }
                                        break;
                                    }

                                    if (expose) {
                                        player.trigger(fpEventType, [player, data]);
                                    }
                                });
                            });

                            common.prepend(common.find(".fp-player", root)[0], videoTag);
                            mediaPlayer.initialize(videoTag, video.src, autoplay);

                            // at least some Android requires extra load
                            // https://github.com/flowplayer/flowplayer/issues/910
                            if (autoplay && !flowplayer.support.zeropreload) {
                                videoTag.load();
                            }

                        } else {
                            if ((player.video.src && video.src !== player.video.src) || video.index) {
                                mediaPlayer.setAutoPlay(true);
                            }
                            mediaPlayer.attachSource(video.src);

                        }

                        // update video object before ready
                        player.video = video;
                    },

                    resume: function () {
                        videoTag.play();
                    },

                    pause: function () {
                        videoTag.pause();
                    },

                    seek: function (time) {
                        videoTag.currentTime = time;
                    },

                    volume: function (level) {
                        if (videoTag) {
                            videoTag.volume = level;
                        }
                    },

                    speed: function (val) {
                        videoTag.playbackRate = val;
                        player.trigger('speed', [player, val]);
                    },

                    unload: function () {
                        if (mediaPlayer) {
                            var listeners = "." + engineName;

                            mediaPlayer.reset();
                            mediaPlayer = 0;
                            player.off(listeners);
                            bean.off(root, listeners);
                            bean.off(videoTag, listeners);
                            common.removeNode(videoTag);
                            videoTag = 0;
                        }
                    }
                };

            // pre 6.0.4: no boolean api.conf.poster and no poster with autoplay
            if (/^6\.0\.[0-3]$/.test(version) &&
                    !player.conf.splash && !player.conf.poster && !player.conf.autoplay) {
                bc = common.css(root, 'backgroundColor');
                // spaces in rgba arg mandatory for recognition
                has_bg = common.css(root, 'backgroundImage') !== "none" ||
                        (bc && bc !== "rgba(0, 0, 0, 0)" && bc !== "transparent");
                if (has_bg) {
                    player.conf.poster = true;
                }
            }

            return engine;
        };

    if (mse && typeof mse.isTypeSupported === "function" && version.indexOf("5.") !== 0) {
        // only load engine if it can be used
        engineImpl.engineName = engineName; // must be exposed
        engineImpl.canPlay = function (type, conf) {
            /*
              WARNING: MediaSource.isTypeSupported very inconsistent!
              e.g. Safari ignores codecs entirely, even bogus, like codecs="XYZ"
              example avc3 main level 3.1 + aac_he: avc3.4d401f; mp4a.40.5
              example avc1 high level 4.1 + aac_lc: avc1.640029; mp4a.40.2
              default: avc1 baseline level 3.0 + aac_lc
            */
            // inject dash conf at earliest opportunity
            dashconf = extend({
                type: "video/mp4",
                codecs: "avc1.42c01e,mp4a.40.2"
            }, flowplayer.conf[engineName], conf[engineName], conf.clip[engineName]);

            return dashCanPlay(type, dashconf.type, dashconf.codecs);
        };

        // put on top of engine stack
        // so mpegedash is tested before html5
        flowplayer.engines.unshift(engineImpl);

    }

}.apply(null, (typeof module === 'object' && module.exports)
    ? [require('flowplayer'), require('dashjs')]
    : [window.flowplayer, window.dashjs]));
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { View, Image, TouchableHighlight } from 'react-native';
import Injector from 'react-native-injectable-component';

export default function Brick (props) {
	// Avoid margins for first element
	const image = (props.onPress) ? _getTouchableUnit(props, props.gutter) : _getImageTag(props, props.gutter);
	const footer = (props.renderFooter) ? props.renderFooter(props.data) : null;
	const header = (props.renderHeader) ? props.renderHeader(props.data) : null;

	return (
		<View key={props.brickKey}>
		  {header}
		  {image}
		  {footer}
		</View>
	);
}

// _getImageTag :: Image, Gutter -> ImageTag
export function _getImageTag (props, gutter = 0) {
	const imageProps = {
		key: props.uri,
		source: {
			uri: props.uri
		},
		resizeMethod: 'auto',
		style: {
			width: props.width,
			height: props.height,
			marginTop: gutter,
			...props.imageContainerStyle,
		}
	};

	return (
		<Injector
		  defaultComponent={Image}
		  defaultProps={imageProps}
		  injectant={props.customImageComponent}
		  injectantProps={props.customImageProps} />
	)
}

// _getTouchableUnit :: Image, Number -> TouchableTag
export function _getTouchableUnit (image, gutter = 0) {
	return (
		<TouchableHighlight
          key={image.uri}
          onPress={() => image.onPress(image.data)}>
          <View>
            { _getImageTag(image, gutter) }
          </View>
		</TouchableHighlight>
	);
}
<commit_msg>passed data to customImageComponent (#94)<commit_after>import React, { Component } from 'react';
import { View, Image, TouchableHighlight } from 'react-native';
import Injector from 'react-native-injectable-component';

export default function Brick (props) {
	// Avoid margins for first element
	const image = (props.onPress) ? _getTouchableUnit(props, props.gutter) : _getImageTag(props, props.gutter);
	const footer = (props.renderFooter) ? props.renderFooter(props.data) : null;
	const header = (props.renderHeader) ? props.renderHeader(props.data) : null;

	return (
		<View key={props.brickKey}>
		  {header}
		  {image}
		  {footer}
		</View>
	);
}

// _getImageTag :: Image, Gutter -> ImageTag
export function _getImageTag (props, gutter = 0) {
	const imageProps = {
		key: props.uri,
		source: {
			uri: props.uri
		},
		data: {
			...props.data
		},
		resizeMethod: 'auto',
		style: {
			width: props.width,
			height: props.height,
			marginTop: gutter,
			...props.imageContainerStyle,
		}
	};

	return (
		<Injector
		  defaultComponent={Image}
		  defaultProps={imageProps}
		  injectant={props.customImageComponent}
		  injectantProps={props.customImageProps} />
	)
}

// _getTouchableUnit :: Image, Number -> TouchableTag
export function _getTouchableUnit (image, gutter = 0) {
	return (
		<TouchableHighlight
          key={image.uri}
          onPress={() => image.onPress(image.data)}>
          <View>
            { _getImageTag(image, gutter) }
          </View>
		</TouchableHighlight>
	);
}
<|endoftext|>


<commit_before>// wmts preview module
ckan.module('wmtspreview', function (jQuery, _) {
  return {
    initialize: function () {
      var self = this;

      self.el.empty();
      self.el.append($('

').attr('id', 'map'));
      self.map = ckan.commonLeafletMap('map', this.options.map_config, {center: [0, 0], zoom: 3});

      $.ajaxSetup({
        beforeSend: function (xhr) {
          xhr.overrideMimeType('application/xml; charset=UTF-8');
        }
      });

      jQuery.get(preload_resource['url']).done(
        function(data){
          self.showPreview(preload_resource['original_url'], data);
        })
      .fail(
        function(jqXHR, textStatus, errorThrown) {
          self.showError(jqXHR, textStatus, errorThrown);
        }
      );
    },

    showError: function (jqXHR, textStatus, errorThrown) {
      if (textStatus == 'error' && jqXHR.responseText.length) {
        this.el.html(jqXHR.responseText);
      } else {
        this.el.html(this.i18n('error', {text: textStatus, error: errorThrown}));
      }
    },

    showPreview: function (url, data) {
      var self = this;
      var EPSG4326 = proj4('EPSG:4326');
      var xmlPathPrefix = 'Contents Layer';
      var nameSpace = ($(data).find('ows\\:Identifier').length != 0) ? 'ows\\:' : '';
      var tileUrlPrefix = $(data).find(nameSpace + 'Operation[name="GetTile"]').find(nameSpace + 'Get:contains("KVP")').attr('xlink:href');
      var bboxName;
      var mapInfos = [];
      var tileVariables = {TileMatrixSet: '{tileMatrixSet}', TileMatrix: '{z}', Style: '{style}', TileRow: '{y}', TileCol: '{x}'};
      var maps = {};
      var mapLatLngBounds = {};
      var overlay;

      // Ensure that URLs have http://.
      function httpify(s) {
        if (s != undefined) {
          if (!s.match(/^[a-zA-Z]+:\/\//)) s = 'http://' + s;
	}
	return s;
      }

      // Get the layer when changing to a new layer.
      function layerChange(e) {
	overlay = e.layer;
      }

      // Load crs from epsg.io.
      function loadEPSG(url, callback) {
        var script = document.createElement('script');
        script.src = url;
        script.onreadystatechange = callback;
        script.onload = callback;
        document.getElementsByTagName('head')[0].appendChild(script);
      }

      // Transform point coordinates from user coordinate system to EPSG:4326.
      function transCoord(x, y, userCrs) {
        if (proj4) {
          var p = proj4(userCrs, EPSG4326, [parseFloat(x), parseFloat(y)]);
        }
        return [p[1], p[0]];
      }

      // Try to obtain the WGS84BoundingBox or BoundingBox.
      if ($(data).find(nameSpace + 'WGS84BoundingBox').length != 0) {
        bboxName = 'WGS84BoundingBox';
      } else if ($(data).find(nameSpace + 'BoundingBox').length != 0) {
	bboxName = 'BoundingBox';
      } else {
        bboxName = '';
      }

      // Collect information for each map.
      $(data).find(xmlPathPrefix).each(function(i, selectedElement) {
        mapInfos.push({
          'id': $(selectedElement).find(nameSpace + 'Identifier').first().text(),
          'title': $(selectedElement).find(nameSpace + 'Title').first().text(),
          'tileMatrixSet': $(selectedElement).find('TileMatrixSet').first().text(),
          'style': $(selectedElement).find('Style').find(nameSpace + 'Identifier').first().text(),
          'format': $(selectedElement).find('Format').text(),
          'resourceUrl': httpify($(selectedElement).find('ResourceURL').attr('template')),
          'lowerCorner': $(selectedElement).find(nameSpace + bboxName).find(nameSpace + 'LowerCorner').text().split(' ').reverse(),
          'upperCorner': $(selectedElement).find(nameSpace + bboxName).find(nameSpace + 'UpperCorner').text().split(' ').reverse(),
        });
      });

      // Get tiles via RESTful if the service has resourceUrls, otherwise get them via KVP.
      jQuery.each(mapInfos, function(i, mapInfo) {
        maps[mapInfo.title] = (mapInfo.resourceUrl != undefined) ?
        // Discard any unsupported tile variables.
        L.tileLayer(mapInfo.resourceUrl.replace(/{([^}]+)}/g, function(g0, g1) { return (tileVariables[g1] != undefined) ? tileVariables[g1] : ''; }), mapInfo) :
        L.tileLayer(httpify(tileUrlPrefix) + 'SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER={id}&STYLE={style}&FORMAT={format}&TILEMATRIXSET={tileMatrixSet}&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}', mapInfo);
        mapLatLngBounds[mapInfo.id] = [mapInfo.lowerCorner, mapInfo.upperCorner];
      });

      // If we only have BoundingBox info, load crs from epsg.io.
      if (bboxName == 'BoundingBox') {
        xmlMapCrs = $(data).find(xmlPathPrefix).find(nameSpace + bboxName).first().attr("crs");
        EPSG = xmlMapCrs.substring(xmlMapCrs.indexOf("EPSG::") + 6, xmlMapCrs.length);
        loadEPSG('http://epsg.io/' + EPSG + '.js', function() {
	  // Except for EPSG:3821 (which is incomplete)
          if (EPSG == 3821) {
            proj4.defs([
              ['EPSG:3821', '+proj=tmerc +ellps=GRS67 +towgs84=-752,-358,-179,-.0000011698,.0000018398,.0000009822,.00002329 +lat_0=0 +lon_0=121 +x_0=250000 +y_0=0 +k=0.9999 +units=m +no_defs']
            ]);
          }
          EPSGUser = proj4('EPSG:' + EPSG);
          jQuery.each(mapInfos, function(i, mapInfo) {
            lowercorner = mapLatLngBounds[mapInfo.id][0];
            uppercorner = mapLatLngBounds[mapInfo.id][1];
            mapLatLngBounds[mapInfo.id] = [transCoord(lowercorner[1], lowercorner[0], EPSGUser), transCoord(uppercorner[1], uppercorner[0], EPSGUser)];
          });
          self.map.fitBounds(mapLatLngBounds[mapInfos[0].id]);
        });
      }

      overlay = maps[mapInfos[0].title];
      self.map.addLayer(maps[mapInfos[0].title]);
      L.control.layers(maps, null).addTo(self.map);
      if (mapLatLngBounds[mapInfos[0].id][0] != '') self.map.fitBounds(mapLatLngBounds[mapInfos[0].id]);
      self.map.on({baselayerchange: layerChange});

      // Layer control for mobile
      var container = document.getElementsByClassName('leaflet-control-layers')[0];
      L.DomEvent.disableClickPropagation(container);

      // Opacity control for desktop
      if (!L.Browser.touch) {
	var outer = $('
');
	var inner = $('
');
	var start = false;
	var startTop;
	$(outer).append(inner);
	$(outer).appendTo('body');
	var handle = document.getElementById('handle');
        document.onmousemove = function(e) {
          if (!start) return;
          handle.style.top = Math.max(-5, Math.min(195, startTop + parseInt(e.clientY, 10) - start)) + 'px';
          overlay.setOpacity(1 - (handle.offsetTop / 200));
        };
        handle.onmousedown = function(e) {
          start = parseInt(e.clientY, 10);
          startTop = handle.offsetTop - 5;
	  return false;
        };
        document.onmouseup = function(e) {
          start = null;
        };
      }
    }
  };
});
<commit_msg>Remove the unnecessary url parameter in wmts_view<commit_after>// wmts preview module
ckan.module('wmtspreview', function (jQuery, _) {
  return {
    initialize: function () {
      var self = this;

      self.el.empty();
      self.el.append($('

').attr('id', 'map'));
      self.map = ckan.commonLeafletMap('map', this.options.map_config, {center: [0, 0], zoom: 3});

      $.ajaxSetup({
        beforeSend: function (xhr) {
          xhr.overrideMimeType('application/xml; charset=UTF-8');
        }
      });

      jQuery.get(preload_resource['url']).done(
        function(data){
          self.showPreview(data);
        })
      .fail(
        function(jqXHR, textStatus, errorThrown) {
          self.showError(jqXHR, textStatus, errorThrown);
        }
      );
    },

    showError: function (jqXHR, textStatus, errorThrown) {
      if (textStatus == 'error' && jqXHR.responseText.length) {
        this.el.html(jqXHR.responseText);
      } else {
        this.el.html(this.i18n('error', {text: textStatus, error: errorThrown}));
      }
    },

    showPreview: function (wmtsInfo) {
      var self = this;
      var EPSG4326 = proj4('EPSG:4326');
      var xmlPathPrefix = 'Contents Layer';
      var nameSpace = ($(wmtsInfo).find('ows\\:Identifier').length != 0) ? 'ows\\:' : '';
      var tileUrlPrefix = $(wmtsInfo).find(nameSpace + 'Operation[name="GetTile"]').find(nameSpace + 'Get:contains("KVP")').attr('xlink:href');
      var bboxName;
      var mapInfos = [];
      var tileVariables = {TileMatrixSet: '{tileMatrixSet}', TileMatrix: '{z}', Style: '{style}', TileRow: '{y}', TileCol: '{x}'};
      var maps = {};
      var mapLatLngBounds = {};
      var overlay;

      // Ensure that URLs have http://.
      function httpify(s) {
        if (s != undefined) {
          if (!s.match(/^[a-zA-Z]+:\/\//)) s = 'http://' + s;
	}
	return s;
      }

      // Get the layer when changing to a new layer.
      function layerChange(e) {
	overlay = e.layer;
      }

      // Load crs from epsg.io.
      function loadEPSG(url, callback) {
        var script = document.createElement('script');
        script.src = url;
        script.onreadystatechange = callback;
        script.onload = callback;
        document.getElementsByTagName('head')[0].appendChild(script);
      }

      // Transform point coordinates from user coordinate system to EPSG:4326.
      function transCoord(x, y, userCrs) {
        if (proj4) {
          var p = proj4(userCrs, EPSG4326, [parseFloat(x), parseFloat(y)]);
        }
        return [p[1], p[0]];
      }

      // Try to obtain the WGS84BoundingBox or BoundingBox.
      if ($(wmtsInfo).find(nameSpace + 'WGS84BoundingBox').length != 0) {
        bboxName = 'WGS84BoundingBox';
      } else if ($(wmtsInfo).find(nameSpace + 'BoundingBox').length != 0) {
	bboxName = 'BoundingBox';
      } else {
        bboxName = '';
      }

      // Collect information for each map.
      $(wmtsInfo).find(xmlPathPrefix).each(function(i, selectedElement) {
        mapInfos.push({
          'id': $(selectedElement).find(nameSpace + 'Identifier').first().text(),
          'title': $(selectedElement).find(nameSpace + 'Title').first().text(),
          'tileMatrixSet': $(selectedElement).find('TileMatrixSet').first().text(),
          'style': $(selectedElement).find('Style').find(nameSpace + 'Identifier').first().text(),
          'format': $(selectedElement).find('Format').text(),
          'resourceUrl': httpify($(selectedElement).find('ResourceURL').attr('template')),
          'lowerCorner': $(selectedElement).find(nameSpace + bboxName).find(nameSpace + 'LowerCorner').text().split(' ').reverse(),
          'upperCorner': $(selectedElement).find(nameSpace + bboxName).find(nameSpace + 'UpperCorner').text().split(' ').reverse(),
        });
      });

      // Get tiles via RESTful if the service has resourceUrls, otherwise get them via KVP.
      jQuery.each(mapInfos, function(i, mapInfo) {
        maps[mapInfo.title] = (mapInfo.resourceUrl != undefined) ?
        // Discard any unsupported tile variables.
        L.tileLayer(mapInfo.resourceUrl.replace(/{([^}]+)}/g, function(g0, g1) { return (tileVariables[g1] != undefined) ? tileVariables[g1] : ''; }), mapInfo) :
        L.tileLayer(httpify(tileUrlPrefix) + 'SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER={id}&STYLE={style}&FORMAT={format}&TILEMATRIXSET={tileMatrixSet}&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}', mapInfo);
        mapLatLngBounds[mapInfo.id] = [mapInfo.lowerCorner, mapInfo.upperCorner];
      });

      // If we only have BoundingBox info, load crs from epsg.io.
      if (bboxName == 'BoundingBox') {
        xmlMapCrs = $(wmtsInfo).find(xmlPathPrefix).find(nameSpace + bboxName).first().attr("crs");
        EPSG = xmlMapCrs.substring(xmlMapCrs.indexOf("EPSG::") + 6, xmlMapCrs.length);
        loadEPSG('http://epsg.io/' + EPSG + '.js', function() {
	  // Except for EPSG:3821 (which is incomplete)
          if (EPSG == 3821) {
            proj4.defs([
              ['EPSG:3821', '+proj=tmerc +ellps=GRS67 +towgs84=-752,-358,-179,-.0000011698,.0000018398,.0000009822,.00002329 +lat_0=0 +lon_0=121 +x_0=250000 +y_0=0 +k=0.9999 +units=m +no_defs']
            ]);
          }
          EPSGUser = proj4('EPSG:' + EPSG);
          jQuery.each(mapInfos, function(i, mapInfo) {
            lowercorner = mapLatLngBounds[mapInfo.id][0];
            uppercorner = mapLatLngBounds[mapInfo.id][1];
            mapLatLngBounds[mapInfo.id] = [transCoord(lowercorner[1], lowercorner[0], EPSGUser), transCoord(uppercorner[1], uppercorner[0], EPSGUser)];
          });
          self.map.fitBounds(mapLatLngBounds[mapInfos[0].id]);
        });
      }

      overlay = maps[mapInfos[0].title];
      self.map.addLayer(maps[mapInfos[0].title]);
      L.control.layers(maps, null).addTo(self.map);
      if (mapLatLngBounds[mapInfos[0].id][0] != '') self.map.fitBounds(mapLatLngBounds[mapInfos[0].id]);
      self.map.on({baselayerchange: layerChange});

      // Layer control for mobile
      var container = document.getElementsByClassName('leaflet-control-layers')[0];
      L.DomEvent.disableClickPropagation(container);

      // Opacity control for desktop
      if (!L.Browser.touch) {
	var outer = $('
');
	var inner = $('
');
	var start = false;
	var startTop;
	$(outer).append(inner);
	$(outer).appendTo('body');
	var handle = document.getElementById('handle');
        document.onmousemove = function(e) {
          if (!start) return;
          handle.style.top = Math.max(-5, Math.min(195, startTop + parseInt(e.clientY, 10) - start)) + 'px';
          overlay.setOpacity(1 - (handle.offsetTop / 200));
        };
        handle.onmousedown = function(e) {
          start = parseInt(e.clientY, 10);
          startTop = handle.offsetTop - 5;
	  return false;
        };
        document.onmouseup = function(e) {
          start = null;
        };
      }
    }
  };
});
<|endoftext|>


<commit_before>(function(tiy, $) {
    'use strict';

    // Public API methods
    tiy.loadModule = loadModule;
    tiy.showMessage = showMessage;

    // locals & constants
    let tiyoData = null;
    let navUI = null;
    let mainUI = null;
    let notifyUI = null;
    let modulesLoaded = [];
    let moduleDisplayed = null;
    let dataLoaded = false;
    let uiLoaded = false;

    const MAIN_TEMPLATE = 'templates/main.html';
    const NAV_TEMPLATE = 'templates/nav.html';
    const NOTIFICATIONS_TEMPLATE = 'templates/notifications.html';
    const PANEL_ANIMATION_TIME = 200;

    function main() {
        console.info('Initializing TIYO assistant');

        addFontAwesomeStyleSheet();
        setupNotificationsUI();

        collectData()
        .then(function getNavUI(data) {
            tiyoData = data;
            dataLoaded = true;
            console.log('Data gathered', data);
            return $.get(chrome.extension.getURL(NAV_TEMPLATE));
        })
        .then(function getMainUI(html) {
            navUI = $(html);
            $('.main .header:first').append(navUI);

            modulesLoaded.forEach(addNavIcon);
            navUI.on('click', 'li', toggleModuleUI);

            return $.get(chrome.extension.getURL(MAIN_TEMPLATE));
        })
        .then(function callModuleRenders(html) {
            mainUI = $(html);
            $('.main .content').prepend(mainUI);
            uiLoaded = true;

            setupContentClose();

            console.log('UI base loaded, calling render methods', mainUI);
            modulesLoaded.forEach(function(mod) {
                doRender(mod);
            });
        });
    }

    /**
    * Chrome extensions have issues with access files from css like fonts, so
    * we need to embed the styelsheet using the chromse extension URL, which
    * is dynamically generated. The remainder of the FA styles are in a static
    * stylesheet in /vendor
    */
    function addFontAwesomeStyleSheet() {
        $('head').append(
            $('<style>')
            .attr('type', 'text/css')
            .text(
                `@font-face {
                    font-family: FontAwesome;
                    src: url('${chrome.extension.getURL('vendor/fontawesome-webfont.woff')}');
                }`
            )
        );
    }

    function getUser() {
        try {
            return  JSON.parse(
                $( "#IntercomSettingsScriptTag" )
                .text()
                .replace("window.intercomSettings =", "")
                .replace(";", "")
            );
        } catch (e) {
            return;
        }
    }

    function collectData() {
        let pathname = window.location.pathname.split(/\//),
            data = {
                user: null,
                path: null,
                content: null,
                group: null,
                students: []
            },
            group = $('.card-block dt:contains("Group")').next().find('a');

        data.user = getUser();

        // Admin view of path
        if (/\/admin\/paths\/[0-9]+/.test(window.location.pathname)) {
            data.path = {
                id: Number(pathname[3]),
                title: $('.content .breadcrumb li:eq(1)').text()
            };
        }

        // Admin view of content piece
        if (/\/admin\/(lessons|assignmnents)\/[0-9]+/.test(window.location.pathname)) {
            data.content = {
                id: Number(pathname[3]),
                title: $('.content .breadcrumb li:eq(3)').text(),
                type: pathname[2],
                isAdmin: true
            };
        }

        // Student view of content piece
        if (/\/paths\/[0-9]+\/units\/[0-9]+\/[^\/]+\/[0-9]+/.test(window.location.pathname)) {
            data.path = {
                id: Number(pathname[2]),
                title: $('.m-pathheader-info-title').text()
            };
            data.content = {
                id: Number(pathname[6]),
                title: $('.m-lessonheader-title').text(),
                type: pathname[5],
                isAdmin: false
            };
        }

        let p;
        if (group.length) {
            data.group = {
                title: group.text(),
                id: Number(group.attr('href').match(/\/([0-9]+)/)[1])
            };

            p = $.get(group.attr('href')).then(function(html) {
                let students = $(html).find('#students tr td:first-child a');
                students.each(function() {
                    let studentElem = $(this).find('.profile-placeholder-medium, img').remove().end();
                    data.students.push({
                        id: Number(studentElem.attr('href').match(/\/([0-9]+)/)[1]),
                        name: studentElem.text()
                    });
                });
                return data;
            });
        } else {
            p = Promise.resolve(data);
        }

        return p;
    }

    function addNavIcon(mod) {
        if (!navUI) { return; }

        navUI.find('ul').append(
            `<li data-module='${mod.name}' title='${mod.name}' aria-title='${mod.name}'><i class='fa ${mod.navIcon} fa-lg' aria-hidden='true'></i></li>`
        );
    }

    function toggleModuleUI(e) {
        e.preventDefault();
        var name = $(this).data('module');
        var mod = modulesLoaded.filter(function(m) { return m.name === name;});
        if (!mod.length) { return; }

        if (moduleDisplayed === mod[0].name) {
            console.log('hiding ', mod[0]);
            closeContent(e);
        } else {
            console.log('showing ', mod[0]);
            moduleDisplayed = mod[0].name;
            $('.tiyo-assistant-module').hide();
            $(`[data-module="${mod[0].name}"]`).show().trigger('showing');
            mainUI.slideDown(PANEL_ANIMATION_TIME);
        }
    }

    function closeContent(e) {
        e.preventDefault();
        $(`[data-module="${moduleDisplayed}"]`).show().trigger('hiding');
        moduleDisplayed = null;
        mainUI.slideUp(PANEL_ANIMATION_TIME);
    }

    function setupContentClose() {
        $('.tiyo-assistant-close').click(closeContent);
    }

    function loadModule(api) {
        if (!api) { return; }
        if (!api.name) { api.name = Date.getTime(); }

        console.info('loading module', api);

        modulesLoaded.push(api);

        addNavIcon(api);
        doRender(api);
    }

    function doRender(mod) {
        if (uiLoaded && typeof(mod.render) === 'function') {
            var elem = createModuleWrapper(mod);
            mod.render(tiyoData, elem);
        }
    }

    function createModuleWrapper(mod) {
        var elem = $(`<article data-module='${mod.name}'>`).addClass('tiyo-assistant-module');
        $(mainUI).find('.tiyo-assistant-content').append(elem);
        return elem;
    }

    function setupNotificationsUI() {
        $.get(chrome.extension.getURL(NOTIFICATIONS_TEMPLATE)).then(function(html) {
            notifyUI = $(html).appendTo('body');
            notifyUI.on('click', '.close', function() {
                $(this).parent().fadeOut(function() { $(this).remove(); });
            });
        });
    }

    function showMessage(msg, options = {}) {
        options.type = options.type || 'danger';
        options.duration = (Number(options.duration) || options.duration === 0) ? options.duration : 4;

        let dismissable = (options.canDismiss === false) ? '' : 'alert-dismissible';

        let msgNode = $(`<p class='alert alert-${options.type} ${dismissable}'>`).text(msg);

        if (dismissable.length) {
            msgNode.append(`<button class='close'>×</button>`);
        }

        notifyUI.append(msgNode);

        if (options.duration && options.duration > 0) {
            setTimeout(function() {
                msgNode.fadeOut(function() { $(this).remove(); });
            }, (options.duration * 1000));
        }
    }

    // Kick things off...
    main();
    // Then export our module API
    window.tiy = tiy;

})(window.tiy || {}, window.jQuery);
<commit_msg>Added switch to indicate if user is on path page<commit_after>(function(tiy, $) {
    'use strict';

    // Public API methods
    tiy.loadModule = loadModule;
    tiy.showMessage = showMessage;

    // locals & constants
    let tiyoData = null;
    let navUI = null;
    let mainUI = null;
    let notifyUI = null;
    let modulesLoaded = [];
    let moduleDisplayed = null;
    let dataLoaded = false;
    let uiLoaded = false;

    const MAIN_TEMPLATE = 'templates/main.html';
    const NAV_TEMPLATE = 'templates/nav.html';
    const NOTIFICATIONS_TEMPLATE = 'templates/notifications.html';
    const PANEL_ANIMATION_TIME = 200;

    function main() {
        console.info('Initializing TIYO assistant');

        addFontAwesomeStyleSheet();
        setupNotificationsUI();

        collectData()
        .then(function getNavUI(data) {
            tiyoData = data;
            dataLoaded = true;
            console.log('Data gathered', data);
            return $.get(chrome.extension.getURL(NAV_TEMPLATE));
        })
        .then(function getMainUI(html) {
            navUI = $(html);
            $('.main .header:first').append(navUI);

            modulesLoaded.forEach(addNavIcon);
            navUI.on('click', 'li', toggleModuleUI);

            return $.get(chrome.extension.getURL(MAIN_TEMPLATE));
        })
        .then(function callModuleRenders(html) {
            mainUI = $(html);
            $('.main .content').prepend(mainUI);
            uiLoaded = true;

            setupContentClose();

            console.log('UI base loaded, calling render methods', mainUI);
            modulesLoaded.forEach(function(mod) {
                doRender(mod);
            });
        });
    }

    /**
    * Chrome extensions have issues with access files from css like fonts, so
    * we need to embed the styelsheet using the chromse extension URL, which
    * is dynamically generated. The remainder of the FA styles are in a static
    * stylesheet in /vendor
    */
    function addFontAwesomeStyleSheet() {
        $('head').append(
            $('<style>')
            .attr('type', 'text/css')
            .text(
                `@font-face {
                    font-family: FontAwesome;
                    src: url('${chrome.extension.getURL('vendor/fontawesome-webfont.woff')}');
                }`
            )
        );
    }

    function getUser() {
        try {
            return  JSON.parse(
                $( "#IntercomSettingsScriptTag" )
                .text()
                .replace("window.intercomSettings =", "")
                .replace(";", "")
            );
        } catch (e) {
            return;
        }
    }

    function collectData() {
        let pathname = window.location.pathname.split(/\//),
            data = {
                user: null,
                path: null,
                content: null,
                group: null,
                students: []
            },
            group = $('.card-block dt:contains("Group")').next().find('a');

        data.user = getUser();

        // Admin view of path
        if (/\/admin\/paths\/[0-9]+/.test(window.location.pathname)) {
            data.path = {
                id: Number(pathname[3]),
                title: $('.content .breadcrumb li:eq(1)').text(),
                onPage: true
            };
        }

        // Admin view of content piece
        if (/\/admin\/(lessons|assignmnents)\/[0-9]+/.test(window.location.pathname)) {
            data.content = {
                id: Number(pathname[3]),
                title: $('.content .breadcrumb li:eq(3)').text(),
                type: pathname[2],
                isAdmin: true
            };
        }

        // Student view of content piece
        if (/\/paths\/[0-9]+\/units\/[0-9]+\/[^\/]+\/[0-9]+/.test(window.location.pathname)) {
            data.path = {
                id: Number(pathname[2]),
                title: $('.m-pathheader-info-title').text(),
                onPage: false
            };
            data.content = {
                id: Number(pathname[6]),
                title: $('.m-lessonheader-title').text(),
                type: pathname[5],
                isAdmin: false
            };
        }

        let p;
        if (group.length) {
            data.group = {
                title: group.text(),
                id: Number(group.attr('href').match(/\/([0-9]+)/)[1])
            };

            p = $.get(group.attr('href')).then(function(html) {
                let students = $(html).find('#students tr td:first-child a');
                students.each(function() {
                    let studentElem = $(this).find('.profile-placeholder-medium, img').remove().end();
                    data.students.push({
                        id: Number(studentElem.attr('href').match(/\/([0-9]+)/)[1]),
                        name: studentElem.text()
                    });
                });
                return data;
            });
        } else {
            p = Promise.resolve(data);
        }

        return p;
    }

    function addNavIcon(mod) {
        if (!navUI) { return; }

        navUI.find('ul').append(
            `<li data-module='${mod.name}' title='${mod.name}' aria-title='${mod.name}'><i class='fa ${mod.navIcon} fa-lg' aria-hidden='true'></i></li>`
        );
    }

    function toggleModuleUI(e) {
        e.preventDefault();
        var name = $(this).data('module');
        var mod = modulesLoaded.filter(function(m) { return m.name === name;});
        if (!mod.length) { return; }

        if (moduleDisplayed === mod[0].name) {
            console.log('hiding ', mod[0]);
            closeContent(e);
        } else {
            console.log('showing ', mod[0]);
            moduleDisplayed = mod[0].name;
            $('.tiyo-assistant-module').hide();
            $(`[data-module="${mod[0].name}"]`).show().trigger('showing');
            mainUI.slideDown(PANEL_ANIMATION_TIME);
        }
    }

    function closeContent(e) {
        e.preventDefault();
        $(`[data-module="${moduleDisplayed}"]`).show().trigger('hiding');
        moduleDisplayed = null;
        mainUI.slideUp(PANEL_ANIMATION_TIME);
    }

    function setupContentClose() {
        $('.tiyo-assistant-close').click(closeContent);
    }

    function loadModule(api) {
        if (!api) { return; }
        if (!api.name) { api.name = Date.getTime(); }

        console.info('loading module', api);

        modulesLoaded.push(api);

        addNavIcon(api);
        doRender(api);
    }

    function doRender(mod) {
        if (uiLoaded && typeof(mod.render) === 'function') {
            var elem = createModuleWrapper(mod);
            mod.render(tiyoData, elem);
        }
    }

    function createModuleWrapper(mod) {
        var elem = $(`<article data-module='${mod.name}'>`).addClass('tiyo-assistant-module');
        $(mainUI).find('.tiyo-assistant-content').append(elem);
        return elem;
    }

    function setupNotificationsUI() {
        $.get(chrome.extension.getURL(NOTIFICATIONS_TEMPLATE)).then(function(html) {
            notifyUI = $(html).appendTo('body');
            notifyUI.on('click', '.close', function() {
                $(this).parent().fadeOut(function() { $(this).remove(); });
            });
        });
    }

    function showMessage(msg, options = {}) {
        options.type = options.type || 'danger';
        options.duration = (Number(options.duration) || options.duration === 0) ? options.duration : 4;

        let dismissable = (options.canDismiss === false) ? '' : 'alert-dismissible';

        let msgNode = $(`<p class='alert alert-${options.type} ${dismissable}'>`).text(msg);

        if (dismissable.length) {
            msgNode.append(`<button class='close'>×</button>`);
        }

        notifyUI.append(msgNode);

        if (options.duration && options.duration > 0) {
            setTimeout(function() {
                msgNode.fadeOut(function() { $(this).remove(); });
            }, (options.duration * 1000));
        }
    }

    // Kick things off...
    main();
    // Then export our module API
    window.tiy = tiy;

})(window.tiy || {}, window.jQuery);
<|endoftext|>


<commit_before>var markers = {}

$(document).ready(function () {

    // Initialize world map and center it to the user position
    var map = L.map('map');

    L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}', {
        attribution: 'Map data © OpenStreetMap contributors, CC-BY-SA, Imagery © Mapbox',
        maxZoom: 18,
        id: MAPBOX_ID,
        accessToken: MAPBOX_TOKEN
    }).addTo(map);

    map.locate({setView: true, maxZoom: 5});

    map.on('locationfound', onLocationFound);

    // Assign a fingerprint to the user
    var fp = $.cookie('fp');

    if (!fp) {
        fp = createFingerprint();
        $.cookie('fp', fp);
    }

    // Create socketIO connection
    var socket = io.connect('http://' + document.domain + ':' + location.port);

    // Send user location to the server once he accepts geo location
    function onLocationFound(e) {
        socket.emit('send_pos', e.latlng.lat, e.latlng.lng, e.timestamp, fp);
        // Display user location
        L.marker([e.latlng.lat, e.latlng.lng]).addTo(map).bindPopup("This is you.").openPopup();
    }

    // Handle positions init
    socket.on('init_pos', function (data) {
        refreshPositions(map, data.pos, fp);
    });

    // Handle positions update
    socket.on('update_pos', function (data) {
        refreshPositions(map, data.pos, fp);
    });

});

function createFingerprint() {

    var fingerprint = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
        var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
        return v.toString(16);
    });

    return fingerprint;

}

function refreshPositions(map, positions, userFp) {

    for (var i = 0; i < positions.length; i++) {

        position = positions[i];

        if (position.fp in markers) {
            // Refresh the position if it's already on the map
            markers[position.fp].setLatLng(new L.LatLng(position.lat, position.long)).bindPopup('Last seen ' + moment(position.timestamp).fromNow());
        } else if (position.fp != userFp) {
            // Create a marker for the position if it's not the current user position
            markers[position.fp] = L.marker([position.lat, position.long]).addTo(map).bindPopup('Last seen ' + moment(position.timestamp).fromNow());
        }

    }
}<commit_msg>Use the same protocol used to load the current page in the socketio url<commit_after>var markers = {}

$(document).ready(function () {

    // Initialize world map and center it to the user position
    var map = L.map('map');

    L.tileLayer('//api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}', {
        attribution: 'Map data © OpenStreetMap contributors, CC-BY-SA, Imagery © Mapbox',
        maxZoom: 18,
        id: MAPBOX_ID,
        accessToken: MAPBOX_TOKEN
    }).addTo(map);

    map.locate({setView: true, maxZoom: 5});

    map.on('locationfound', onLocationFound);

    // Assign a fingerprint to the user
    var fp = $.cookie('fp');

    if (!fp) {
        fp = createFingerprint();
        $.cookie('fp', fp);
    }

    // Create socketIO connection
    var socket = io.connect('//' + document.domain + ':' + location.port);

    // Send user location to the server once he accepts geo location
    function onLocationFound(e) {
        socket.emit('send_pos', e.latlng.lat, e.latlng.lng, e.timestamp, fp);
        // Display user location
        L.marker([e.latlng.lat, e.latlng.lng]).addTo(map).bindPopup("This is you.").openPopup();
    }

    // Handle positions init
    socket.on('init_pos', function (data) {
        refreshPositions(map, data.pos, fp);
    });

    // Handle positions update
    socket.on('update_pos', function (data) {
        refreshPositions(map, data.pos, fp);
    });

});

function createFingerprint() {

    var fingerprint = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
        var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
        return v.toString(16);
    });

    return fingerprint;

}

function refreshPositions(map, positions, userFp) {

    for (var i = 0; i < positions.length; i++) {

        position = positions[i];

        if (position.fp in markers) {
            // Refresh the position if it's already on the map
            markers[position.fp].setLatLng(new L.LatLng(position.lat, position.long)).bindPopup('Last seen ' + moment(position.timestamp).fromNow());
        } else if (position.fp != userFp) {
            // Create a marker for the position if it's not the current user position
            markers[position.fp] = L.marker([position.lat, position.long]).addTo(map).bindPopup('Last seen ' + moment(position.timestamp).fromNow());
        }

    }
}<|endoftext|>


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

var resolveModule = function(names, mod, root) {
  if (names.length == 0) {
    if (typeof mod.current != "string") {
      throw ["error","invalid_require_path",
        'Must require a JavaScript string, not: '+(typeof mod.current)];
    }
    return {
      current : mod.current,
      parent : mod.parent,
      id : mod.id,
      exports : {}
    }
  }
  // we need to traverse the path
  var n = names.shift();
  if (n == '..') {
    if (!(mod.parent && mod.parent.parent)) {
      throw ["error", "invalid_require_path", 'Object has no parent '+JSON.stringify(mod.current)];
    }
    return resolveModule(names, {
      id : mod.id.slice(0, mod.id.lastIndexOf('/')),
      parent : mod.parent.parent,
      current : mod.parent.current
    });
  } else if (n == '.') {
    if (!mod.parent) {
      throw ["error", "invalid_require_path", 'Object has no parent '+JSON.stringify(mod.current)];
    }
    return resolveModule(names, {
      parent : mod.parent,
      current : mod.current,
      id : mod.id
    });
  } else if (root) {
    mod = {current : root};
  }
  if (!mod.current[n]) {
    throw ["error", "invalid_require_path", 'Object has no property "'+n+'". '+JSON.stringify(mod.current)];
  }
  return resolveModule(names, {
    current : mod.current[n],
    parent : mod,
    id : mod.id ? mod.id + '/' + n : n
  });
};

var Couch = {
  // moving this away from global so we can move to json2.js later
  toJSON : function (val) {
    return JSON.stringify(val);
  },
  compileFunction : function(source, ddoc) {
    if (!source) throw(["error","not_found","missing function"]);
    // Some newer SpiderMonkey's appear to not like evaluating
    // an anonymous function at global scope. Simple fix just
    // wraps the source with parens so the function object is
    // returned correctly.
    source = "(" + source + ")";
    try {
      if (sandbox) {
        if (ddoc) {
          if (!ddoc._module_cache) {
            ddoc._module_cache = {};
          }
          var require = function(name, module) {
            module = module || {};
            var newModule = resolveModule(name.split('/'), module.parent, ddoc);
            if (!ddoc._module_cache.hasOwnProperty(newModule.id)) {
              // create empty exports object before executing the module,
              // stops circular requires from filling the stack
              ddoc._module_cache[newModule.id] = {};
              var s = "function (module, exports, require) { " + newModule.current + " }";
              try {
                var func = sandbox ? evalcx(s, sandbox) : eval(s);
                func.apply(sandbox, [newModule, newModule.exports, function(name) {
                  return require(name, newModule);
                }]);
              } catch(e) {
                throw ["error","compilation_error","Module require('"+name+"') raised error "+e.toSource()];
              }
              ddoc._module_cache[newModule.id] = newModule.exports;
            }
            return ddoc._module_cache[newModule.id];
          }
          sandbox.require = require;
        }
        var functionObject = evalcx(source, sandbox);
      } else {
        var functionObject = eval(source);
      }
    } catch (err) {
      throw(["error", "compilation_error", err.toSource() + " (" + source + ")"]);
    };
    if (typeof(functionObject) == "function") {
      return functionObject;
    } else {
      throw(["error","compilation_error",
        "Expression does not eval to a function. (" + source.toSource() + ")"]);
    };
  },
  recursivelySeal : function(obj) {
    // seal() is broken in current Spidermonkey
    try {
      seal(obj);
    } catch (x) {
      // Sealing of arrays broken in some SpiderMonkey versions.
      // https://bugzilla.mozilla.org/show_bug.cgi?id=449657
    }
    for (var propname in obj) {
      if (typeof obj[propname] == "object") {
        arguments.callee(obj[propname]);
      }
    }
  }
}

// prints the object as JSON, and rescues and logs any toJSON() related errors
function respond(obj) {
  try {
    print(Couch.toJSON(obj));
  } catch(e) {
    log("Error converting object to JSON: " + e.toString());
    log("error on obj: "+ obj.toSource());
  }
};

function log(message) {
  // idea: query_server_config option for log level
  if (typeof message == "xml") {
    message = message.toXMLString();
  } else if (typeof message != "string") {
    message = Couch.toJSON(message);
  }
  respond(["log", String(message)]);
};

function isArray(obj) {
  return toString.call(obj) === "[object Array]";
}
<commit_msg>Allow CommonJS modules to be an empty string.<commit_after>// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.

var resolveModule = function(names, mod, root) {
  if (names.length == 0) {
    if (typeof mod.current != "string") {
      throw ["error","invalid_require_path",
        'Must require a JavaScript string, not: '+(typeof mod.current)];
    }
    return {
      current : mod.current,
      parent : mod.parent,
      id : mod.id,
      exports : {}
    }
  }
  // we need to traverse the path
  var n = names.shift();
  if (n == '..') {
    if (!(mod.parent && mod.parent.parent)) {
      throw ["error", "invalid_require_path", 'Object has no parent '+JSON.stringify(mod.current)];
    }
    return resolveModule(names, {
      id : mod.id.slice(0, mod.id.lastIndexOf('/')),
      parent : mod.parent.parent,
      current : mod.parent.current
    });
  } else if (n == '.') {
    if (!mod.parent) {
      throw ["error", "invalid_require_path", 'Object has no parent '+JSON.stringify(mod.current)];
    }
    return resolveModule(names, {
      parent : mod.parent,
      current : mod.current,
      id : mod.id
    });
  } else if (root) {
    mod = {current : root};
  }
  if (mod.current[n] === undefined) {
    throw ["error", "invalid_require_path", 'Object has no property "'+n+'". '+JSON.stringify(mod.current)];
  }
  return resolveModule(names, {
    current : mod.current[n],
    parent : mod,
    id : mod.id ? mod.id + '/' + n : n
  });
};

var Couch = {
  // moving this away from global so we can move to json2.js later
  toJSON : function (val) {
    return JSON.stringify(val);
  },
  compileFunction : function(source, ddoc) {
    if (!source) throw(["error","not_found","missing function"]);
    // Some newer SpiderMonkey's appear to not like evaluating
    // an anonymous function at global scope. Simple fix just
    // wraps the source with parens so the function object is
    // returned correctly.
    source = "(" + source + ")";
    try {
      if (sandbox) {
        if (ddoc) {
          if (!ddoc._module_cache) {
            ddoc._module_cache = {};
          }
          var require = function(name, module) {
            module = module || {};
            var newModule = resolveModule(name.split('/'), module.parent, ddoc);
            if (!ddoc._module_cache.hasOwnProperty(newModule.id)) {
              // create empty exports object before executing the module,
              // stops circular requires from filling the stack
              ddoc._module_cache[newModule.id] = {};
              var s = "function (module, exports, require) { " + newModule.current + " }";
              try {
                var func = sandbox ? evalcx(s, sandbox) : eval(s);
                func.apply(sandbox, [newModule, newModule.exports, function(name) {
                  return require(name, newModule);
                }]);
              } catch(e) {
                throw ["error","compilation_error","Module require('"+name+"') raised error "+e.toSource()];
              }
              ddoc._module_cache[newModule.id] = newModule.exports;
            }
            return ddoc._module_cache[newModule.id];
          }
          sandbox.require = require;
        }
        var functionObject = evalcx(source, sandbox);
      } else {
        var functionObject = eval(source);
      }
    } catch (err) {
      throw(["error", "compilation_error", err.toSource() + " (" + source + ")"]);
    };
    if (typeof(functionObject) == "function") {
      return functionObject;
    } else {
      throw(["error","compilation_error",
        "Expression does not eval to a function. (" + source.toSource() + ")"]);
    };
  },
  recursivelySeal : function(obj) {
    // seal() is broken in current Spidermonkey
    try {
      seal(obj);
    } catch (x) {
      // Sealing of arrays broken in some SpiderMonkey versions.
      // https://bugzilla.mozilla.org/show_bug.cgi?id=449657
    }
    for (var propname in obj) {
      if (typeof obj[propname] == "object") {
        arguments.callee(obj[propname]);
      }
    }
  }
}

// prints the object as JSON, and rescues and logs any toJSON() related errors
function respond(obj) {
  try {
    print(Couch.toJSON(obj));
  } catch(e) {
    log("Error converting object to JSON: " + e.toString());
    log("error on obj: "+ obj.toSource());
  }
};

function log(message) {
  // idea: query_server_config option for log level
  if (typeof message == "xml") {
    message = message.toXMLString();
  } else if (typeof message != "string") {
    message = Couch.toJSON(message);
  }
  respond(["log", String(message)]);
};

function isArray(obj) {
  return toString.call(obj) === "[object Array]";
}
<|endoftext|>


<commit_before>import { Unit } from 'Unit';
import { GameState } from 'GameState';
import { GameMap } from 'GameMap';

export default function start() {
  var Phaser = window.Phaser;

  var game = new Phaser.Game(800, 600, Phaser.AUTO, '', {
    preload,
    create,
    update,
    render
  });

  var unit;
  var state;
  var map;

  var setPosOnce = false;

  function preload() {
    game.load.tilemap('map', 'assets/map.json', null, Phaser.Tilemap.TILED_JSON);
    game.load.image('character', 'assets/images/character.png');
    game.load.image('tileset', 'assets/images/tile_sheet.png');
  }

  function create() {
    game.physics.startSystem(Phaser.Physics.ARCADE);

    state = new GameState(game);
    map = new GameMap({
      game,
      mapName: 'map',
      dimensions: { width: 80, height: 60 },
      tileDimensions: { width: 10, height: 10 },
      walkableTiles: [5,6,8]
    });

    // render the map
    map.render({
      tileset: 'main',
      tilesetImageKey: 'tileset',
      layer: 'Tile Layer 1'
    });

    // player

    // render the player on screen
    var { x, y } = map.tileCoordsToWorldCoords({x: 36, y: 30});
    unit = new Unit({x, y, game, spriteKey: 'character', speed: 100});

    game.physics.arcade.enable(unit.sprite);
  }

  // move the unit's tile position
  function updateUnitPosition(worldPos) {
    unit.moveTo(worldPos);

    setPosOnce = true;
  }

  function update() {
    // if the mouse is pressed, find a path to the mouse's position
    if(game.input.activePointer.isDown) {
      unit.findPath(map, game.input.activePointer);
    }

    unit.update();
  }

  function render() {
    game.debug.inputInfo(32, 32);
  }
}
<commit_msg>finally prototyped two units<commit_after>import { Unit } from 'Unit';
import { GameState } from 'GameState';
import { GameMap } from 'GameMap';

export default function start() {
  var Phaser = window.Phaser;

  var game = new Phaser.Game(800, 600, Phaser.AUTO, '', {
    preload,
    create,
    update,
    render
  });

  var unit;
  var unit2;
  var state;
  var map;

  var setPosOnce = false;

  function preload() {
    game.load.tilemap('map', 'assets/map.json', null, Phaser.Tilemap.TILED_JSON);
    game.load.image('character', 'assets/images/character.png');
    game.load.image('tileset', 'assets/images/tile_sheet.png');
  }

  function create() {
    game.physics.startSystem(Phaser.Physics.ARCADE);

    state = new GameState(game);
    map = new GameMap({
      game,
      mapName: 'map',
      dimensions: { width: 80, height: 60 },
      tileDimensions: { width: 10, height: 10 },
      walkableTiles: [5,6,8]
    });

    // render the map
    map.render({
      tileset: 'main',
      tilesetImageKey: 'tileset',
      layer: 'Tile Layer 1'
    });

    // player

    // render the player on screen
    var { x, y } = map.tileCoordsToWorldCoords({x: 36, y: 30});
    unit = new Unit({x, y, game, spriteKey: 'character', speed: 100});

    var pos = map.tileCoordsToWorldCoords({x: 30, y: 30});
    unit2 = new Unit({x: pos.x, y: pos.y, game, spriteKey: 'character', speed: 100});
  }

  // move the unit's tile position
  function updateUnitPosition(worldPos) {
    unit.moveTo(worldPos);

    setPosOnce = true;
  }

  function update() {
    // if the mouse is pressed, find a path to the mouse's position
    if(game.input.activePointer.isDown) {
      unit.findPath(map, game.input.activePointer);
      unit2.findPath(map, game.input.activePointer);
    }

    unit.update();
    unit2.update();
  }

  function render() {
    game.debug.inputInfo(32, 32);
  }
}
<|endoftext|>