<commit_before>define(['underscore', 'backbone'], function(_, Backbone) {
  "use strict";

  console.log('EventBus.');

  var EventBus = _.extend({}, Backbone.Events);

  EventBus.sub = function(event, callback, context) {
    this.on(event, callback, context);
  },

  EventBus.unsub = function(event, callback, context) {
    this.off(event, callback, context);
  },

  EventBus.pub = function(events) {
    try {
      this.trigger.apply(EventBus, arguments);
    } catch(ex) {
      console.error('EventBus Publish ERROR: events: ' + events + ' exception: ', (ex.stack || ex.stacktrace || ex.message));
    }
    return EventBus;
  };

  return EventBus;
});
<commit_msg>Update eventbus.js<commit_after>define(['underscore', 'backbone'], function(_, Backbone) {
  "use strict";

  console.log('EventBus.');

  var EventBus = _.extend({}, Backbone.Events);

  var _trigger = EventBus.trigger;
  EventBus.trigger = function(events) {
    try {
      console.log('EventBus.trigger: ' + arguments);
      _trigger.apply(EventBus, arguments);
    } catch(ex) {
      console.error('EventBus.trigger ERROR: events: ' + events + ' exception: ', (ex.stack || ex.stacktrace || ex.message));
    }
    return EventBus;
  };

  return EventBus;
});
<|endoftext|>


<commit_before>iD.ui.MapInMap = function(context) {
    var key = '/';

    function map_in_map(selection) {

        var backgroundLayer = iD.TileLayer(),
            overlayLayers = {},
            dispatch = d3.dispatch('change'),
            gpxLayer = iD.GpxLayer(context, dispatch),
            projection = iD.geo.RawMercator(),
            zoom = d3.behavior.zoom()
                .scaleExtent([ztok(0.5), ztok(24)])
                .on('zoom', zoomPan),
            transformed = false,
            panning = false,
            zDiff = 6,    // by default, minimap renders at (main zoom - 6)
            tStart, tLast, tCurr, kLast, kCurr, tiles, svg, gpx, timeoutId;

        iD.ui.MapInMap.gpxLayer = gpxLayer;

        function ztok(z) { return 256 * Math.pow(2, z); }
        function ktoz(k) { return Math.log(k) / Math.LN2 - 8; }

        function startMouse() {
            context.surface().on('mouseup.map-in-map-outside', endMouse);
            context.container().on('mouseup.map-in-map-outside', endMouse);

            tStart = tLast = tCurr = projection.translate();
            panning = true;
        }

        function zoomPan() {
            var e = d3.event.sourceEvent,
                t = d3.event.translate,
                k = d3.event.scale,
                zMain = ktoz(context.projection.scale() * 2 * Math.PI),
                zMini = ktoz(k);

            // restrict minimap zoom to < (main zoom - 3)
            if (zMini > zMain - 3) {
                zMini = zMain - 3;
                zoom.scale(kCurr).translate(tCurr);  // restore last good values
                return;
            }

            tCurr = t;
            kCurr = k;
            zDiff = zMain - zMini;

            var scale = kCurr / kLast,
                tX = Math.round((tCurr[0] / scale - tLast[0]) * scale),
                tY = Math.round((tCurr[1] / scale - tLast[1]) * scale);

            iD.util.setTransform(tiles, tX, tY, scale);
            iD.util.setTransform(svg, 0, 0, scale);
            iD.util.setTransform(gpx, 0, 0, scale);
            transformed = true;

            queueRedraw();

            e.preventDefault();
            e.stopPropagation();
        }

        function endMouse() {
            context.surface().on('mouseup.map-in-map-outside', null);
            context.container().on('mouseup.map-in-map-outside', null);

            updateProjection();
            panning = false;

            if (tCurr[0] !== tStart[0] && tCurr[1] !== tStart[1]) {
                var dMini = selection.dimensions(),
                    cMini = [ dMini[0] / 2, dMini[1] / 2 ];

                context.map().center(projection.invert(cMini));
            }
        }

        function updateProjection() {
            var loc = context.map().center(),
                dMini = selection.dimensions(),
                cMini = [ dMini[0] / 2, dMini[1] / 2 ],
                tMain = context.projection.translate(),
                kMain = context.projection.scale(),
                zMain = ktoz(kMain * 2 * Math.PI),
                zMini = Math.max(zMain - zDiff, 0.5),
                kMini = ztok(zMini);

            projection
                .translate(tMain)
                .scale(kMini / (2 * Math.PI));

            var s = projection(loc),
                mouse = panning ? [ tCurr[0] - tStart[0], tCurr[1] - tStart[1] ] : [0, 0],
                tMini = [
                    cMini[0] - s[0] + tMain[0] + mouse[0],
                    cMini[1] - s[1] + tMain[1] + mouse[1]
                ];

            projection
                .translate(tMini)
                .clipExtent([[0, 0], dMini]);

            zoom
                .center(cMini)
                .translate(tMini)
                .scale(kMini);

            tLast = tCurr = tMini;
            kLast = kCurr = kMini;

            if (transformed) {
                iD.util.setTransform(tiles, 0, 0);
                iD.util.setTransform(svg, 0, 0);
                iD.util.setTransform(gpx, 0, 0);
                transformed = false;
            }
        }

        function redraw() {
            if (hidden()) return;

            updateProjection();

            var dMini = selection.dimensions(),
                zMini = ktoz(projection.scale() * 2 * Math.PI);

            // setup tile container
            tiles = selection
                .selectAll('.map-in-map-tiles')
                .data([0]);

            tiles
                .enter()
                .append('div')
                .attr('class', 'map-in-map-tiles');

            // redraw background
            backgroundLayer
                .source(context.background().baseLayerSource())
                .projection(projection)
                .dimensions(dMini);

            var background = tiles
                .selectAll('.map-in-map-background')
                .data([0]);

            background.enter()
                .append('div')
                .attr('class', 'map-in-map-background');

            background
                .call(backgroundLayer);

            // redraw overlay
            var overlaySources = context.background().overlayLayerSources();
            var activeOverlayLayers = [];
            for (var i = 0; i < overlaySources.length; i++) {
                if (overlaySources[i].validZoom(zMini)) {
                    if (!overlayLayers[i]) overlayLayers[i] = iD.TileLayer();
                    activeOverlayLayers.push(overlayLayers[i]
                        .source(overlaySources[i])
                        .projection(projection)
                        .dimensions(dMini));
                }
            }

            var overlay = tiles
                .selectAll('.map-in-map-overlay')
                .data([0]);

            overlay.enter()
                .append('div')
                .attr('class', 'map-in-map-overlay');

            var overlays = overlay
                .selectAll('div')
                .data(activeOverlayLayers, function(d) { return d.source().name(); });

            overlays.enter().append('div');
            overlays.each(function(layer) {
                d3.select(this).call(layer);
            });

            overlays.exit()
                .remove();

            // redraw gpx overlay
            gpxLayer
                .projection(projection);

            gpx = tiles
                .selectAll('.map-in-map-gpx')
                .data([0]);

            gpx.enter()
                .append('div')
                .attr('class', 'map-in-map-gpx');

            gpx.call(gpxLayer);
            gpx.dimensions(dMini);

            // redraw bounding box
            if (!panning) {
                var getPath = d3.geo.path().projection(projection),
                    bbox = { type: 'Polygon', coordinates: [context.map().extent().polygon()] };

                svg = selection.selectAll('.map-in-map-svg')
                    .data([0]);

                svg.enter()
                    .append('svg')
                    .attr('class', 'map-in-map-svg');

                var path = svg.selectAll('.map-in-map-bbox')
                    .data([bbox]);

                path.enter()
                    .append('path')
                    .attr('class', 'map-in-map-bbox');

                path
                    .attr('d', getPath)
                    .classed('thick', function(d) { return getPath.area(d) < 30; });
            }
        }

        function queueRedraw() {
            clearTimeout(timeoutId);
            timeoutId = setTimeout(function() { redraw(); }, 300);
        }

        function hidden() {
            return selection.style('display') === 'none';
        }

        function toggle() {
            if (d3.event) d3.event.preventDefault();

            var label = d3.select('.minimap-toggle');

            if (hidden()) {
                selection
                    .style('display', 'block')
                    .style('opacity', 0)
                    .transition()
                    .duration(200)
                    .style('opacity', 1);

                label.classed('active', true)
                    .select('input').property('checked', true);

                redraw();

            } else {
                selection
                    .style('display', 'block')
                    .style('opacity', 1)
                    .transition()
                    .duration(200)
                    .style('opacity', 0)
                    .each('end', function() {
                        d3.select(this).style('display', 'none');
                    });

                label.classed('active', false)
                    .select('input').property('checked', false);
            }
        }

        iD.ui.MapInMap.toggle = toggle;

        selection
            .on('mousedown.map-in-map', startMouse)
            .on('mouseup.map-in-map', endMouse);

        selection
            .call(zoom)
            .on('dblclick.zoom', null);

        context.map()
            .on('drawn.map-in-map', function(drawn) {
                if (drawn.full === true) redraw();
            });

        redraw();

        var keybinding = d3.keybinding('map-in-map')
            .on(key, toggle);

        d3.select(document)
            .call(keybinding);
    }

    return map_in_map;
};
<commit_msg>Don't transform gpx layer, as it is attached to tiles container<commit_after>iD.ui.MapInMap = function(context) {
    var key = '/';

    function map_in_map(selection) {

        var backgroundLayer = iD.TileLayer(),
            overlayLayers = {},
            dispatch = d3.dispatch('change'),
            gpxLayer = iD.GpxLayer(context, dispatch),
            projection = iD.geo.RawMercator(),
            zoom = d3.behavior.zoom()
                .scaleExtent([ztok(0.5), ztok(24)])
                .on('zoom', zoomPan),
            transformed = false,
            panning = false,
            zDiff = 6,    // by default, minimap renders at (main zoom - 6)
            tStart, tLast, tCurr, kLast, kCurr, tiles, svg, gpx, timeoutId;

        iD.ui.MapInMap.gpxLayer = gpxLayer;

        function ztok(z) { return 256 * Math.pow(2, z); }
        function ktoz(k) { return Math.log(k) / Math.LN2 - 8; }

        function startMouse() {
            context.surface().on('mouseup.map-in-map-outside', endMouse);
            context.container().on('mouseup.map-in-map-outside', endMouse);

            tStart = tLast = tCurr = projection.translate();
            panning = true;
        }

        function zoomPan() {
            var e = d3.event.sourceEvent,
                t = d3.event.translate,
                k = d3.event.scale,
                zMain = ktoz(context.projection.scale() * 2 * Math.PI),
                zMini = ktoz(k);

            // restrict minimap zoom to < (main zoom - 3)
            if (zMini > zMain - 3) {
                zMini = zMain - 3;
                zoom.scale(kCurr).translate(tCurr);  // restore last good values
                return;
            }

            tCurr = t;
            kCurr = k;
            zDiff = zMain - zMini;

            var scale = kCurr / kLast,
                tX = Math.round((tCurr[0] / scale - tLast[0]) * scale),
                tY = Math.round((tCurr[1] / scale - tLast[1]) * scale);

            iD.util.setTransform(tiles, tX, tY, scale);
            iD.util.setTransform(svg, 0, 0, scale);
            transformed = true;

            queueRedraw();

            e.preventDefault();
            e.stopPropagation();
        }

        function endMouse() {
            context.surface().on('mouseup.map-in-map-outside', null);
            context.container().on('mouseup.map-in-map-outside', null);

            updateProjection();
            panning = false;

            if (tCurr[0] !== tStart[0] && tCurr[1] !== tStart[1]) {
                var dMini = selection.dimensions(),
                    cMini = [ dMini[0] / 2, dMini[1] / 2 ];

                context.map().center(projection.invert(cMini));
            }
        }

        function updateProjection() {
            var loc = context.map().center(),
                dMini = selection.dimensions(),
                cMini = [ dMini[0] / 2, dMini[1] / 2 ],
                tMain = context.projection.translate(),
                kMain = context.projection.scale(),
                zMain = ktoz(kMain * 2 * Math.PI),
                zMini = Math.max(zMain - zDiff, 0.5),
                kMini = ztok(zMini);

            projection
                .translate(tMain)
                .scale(kMini / (2 * Math.PI));

            var s = projection(loc),
                mouse = panning ? [ tCurr[0] - tStart[0], tCurr[1] - tStart[1] ] : [0, 0],
                tMini = [
                    cMini[0] - s[0] + tMain[0] + mouse[0],
                    cMini[1] - s[1] + tMain[1] + mouse[1]
                ];

            projection
                .translate(tMini)
                .clipExtent([[0, 0], dMini]);

            zoom
                .center(cMini)
                .translate(tMini)
                .scale(kMini);

            tLast = tCurr = tMini;
            kLast = kCurr = kMini;

            if (transformed) {
                iD.util.setTransform(tiles, 0, 0);
                iD.util.setTransform(svg, 0, 0);
                transformed = false;
            }
        }

        function redraw() {
            if (hidden()) return;

            updateProjection();

            var dMini = selection.dimensions(),
                zMini = ktoz(projection.scale() * 2 * Math.PI);

            // setup tile container
            tiles = selection
                .selectAll('.map-in-map-tiles')
                .data([0]);

            tiles
                .enter()
                .append('div')
                .attr('class', 'map-in-map-tiles');

            // redraw background
            backgroundLayer
                .source(context.background().baseLayerSource())
                .projection(projection)
                .dimensions(dMini);

            var background = tiles
                .selectAll('.map-in-map-background')
                .data([0]);

            background.enter()
                .append('div')
                .attr('class', 'map-in-map-background');

            background
                .call(backgroundLayer);

            // redraw overlay
            var overlaySources = context.background().overlayLayerSources();
            var activeOverlayLayers = [];
            for (var i = 0; i < overlaySources.length; i++) {
                if (overlaySources[i].validZoom(zMini)) {
                    if (!overlayLayers[i]) overlayLayers[i] = iD.TileLayer();
                    activeOverlayLayers.push(overlayLayers[i]
                        .source(overlaySources[i])
                        .projection(projection)
                        .dimensions(dMini));
                }
            }

            var overlay = tiles
                .selectAll('.map-in-map-overlay')
                .data([0]);

            overlay.enter()
                .append('div')
                .attr('class', 'map-in-map-overlay');

            var overlays = overlay
                .selectAll('div')
                .data(activeOverlayLayers, function(d) { return d.source().name(); });

            overlays.enter().append('div');
            overlays.each(function(layer) {
                d3.select(this).call(layer);
            });

            overlays.exit()
                .remove();

            // redraw gpx overlay
            gpxLayer
                .projection(projection);

            gpx = tiles
                .selectAll('.map-in-map-gpx')
                .data([0]);

            gpx.enter()
                .append('div')
                .attr('class', 'map-in-map-gpx');

            gpx.call(gpxLayer);
            gpx.dimensions(dMini);

            // redraw bounding box
            if (!panning) {
                var getPath = d3.geo.path().projection(projection),
                    bbox = { type: 'Polygon', coordinates: [context.map().extent().polygon()] };

                svg = selection.selectAll('.map-in-map-svg')
                    .data([0]);

                svg.enter()
                    .append('svg')
                    .attr('class', 'map-in-map-svg');

                var path = svg.selectAll('.map-in-map-bbox')
                    .data([bbox]);

                path.enter()
                    .append('path')
                    .attr('class', 'map-in-map-bbox');

                path
                    .attr('d', getPath)
                    .classed('thick', function(d) { return getPath.area(d) < 30; });
            }
        }

        function queueRedraw() {
            clearTimeout(timeoutId);
            timeoutId = setTimeout(function() { redraw(); }, 300);
        }

        function hidden() {
            return selection.style('display') === 'none';
        }

        function toggle() {
            if (d3.event) d3.event.preventDefault();

            var label = d3.select('.minimap-toggle');

            if (hidden()) {
                selection
                    .style('display', 'block')
                    .style('opacity', 0)
                    .transition()
                    .duration(200)
                    .style('opacity', 1);

                label.classed('active', true)
                    .select('input').property('checked', true);

                redraw();

            } else {
                selection
                    .style('display', 'block')
                    .style('opacity', 1)
                    .transition()
                    .duration(200)
                    .style('opacity', 0)
                    .each('end', function() {
                        d3.select(this).style('display', 'none');
                    });

                label.classed('active', false)
                    .select('input').property('checked', false);
            }
        }

        iD.ui.MapInMap.toggle = toggle;

        selection
            .on('mousedown.map-in-map', startMouse)
            .on('mouseup.map-in-map', endMouse);

        selection
            .call(zoom)
            .on('dblclick.zoom', null);

        context.map()
            .on('drawn.map-in-map', function(drawn) {
                if (drawn.full === true) redraw();
            });

        redraw();

        var keybinding = d3.keybinding('map-in-map')
            .on(key, toggle);

        d3.select(document)
            .call(keybinding);
    }

    return map_in_map;
};
<|endoftext|>


<commit_before>/**
 * Created by aldiraraharja on 1/15/17.
 */
'use strict';

const Promise = require('bluebird');
const axios = require('axios');

const OK = 'ok';
const ERROR = 'error';

class YtsClient {
  constructor(BASE_URL) {
    this.BASE_URL = BASE_URL;
  }

  listMovie(searchParams) {
    const defaultSearchTerms = {
      limit: 10,
    };
    return this._get(
      'list_movies',
      Object.assign(defaultSearchTerms, searchParams)
    );
  }

  searchMovie(term) {
    return this.listMovie({
      query_term: term,
    });
  }

  movieDetails(params) {
    const defaultParams = {
      with_images: true,
      with_cast: true,
    };
    return this._get('movie_details', Object.assign(defaultParams, params));
  }

  getMovie(movieId) {
    return this.movieDetails({ movie_id: movieId });
  }

  listUpcoming() {
    return this._get('list_upcoming');
  }

  _get(endpoint, query) {
    console.log(`requesting to ${endpoint}`);
    console.log(query);
    return axios
      .get(`${this.BASE_URL}${endpoint}.json`, {
        params: query,
      })
      .then(response => {
        console.log(response);
        return response.data;
      })
      .catch(err => {
        console.log(err);
      });
  }

  _post(endpoint, payload) {
    return axios
      .post(`${this.BASE_URL}${endpoint}.json`, payload)
      .then(response => response.data)
      .catch(err => console.log(err));
  }
}

module.exports = YtsClient;
<commit_msg>correct way to get data<commit_after>/**
 * Created by aldiraraharja on 1/15/17.
 */
'use strict';

const Promise = require('bluebird');
const axios = require('axios');

const OK = 'ok';
const ERROR = 'error';

class YtsClient {
  constructor(BASE_URL) {
    this.BASE_URL = BASE_URL;
  }

  listMovie(searchParams) {
    const defaultSearchTerms = {
      limit: 10,
    };
    return this._get(
      'list_movies',
      Object.assign(defaultSearchTerms, searchParams)
    );
  }

  searchMovie(term) {
    return this.listMovie({
      query_term: term,
    });
  }

  movieDetails(params) {
    const defaultParams = {
      with_images: true,
      with_cast: true,
    };
    return this._get('movie_details', Object.assign(defaultParams, params));
  }

  getMovie(movieId) {
    return this.movieDetails({ movie_id: movieId });
  }

  listUpcoming() {
    return this._get('list_upcoming');
  }

  _get(endpoint, query) {
    console.log(`requesting to ${endpoint}`);
    console.log(query);
    return axios
      .get(`${this.BASE_URL}${endpoint}.json`, {
        params: query,
      })
      .then(response => {
        console.log(response);
        return response.data.data;
      })
      .catch(err => {
        console.log(err);
      });
  }

  _post(endpoint, payload) {
    return axios
      .post(`${this.BASE_URL}${endpoint}.json`, payload)
      .then(response => response.data.data)
      .catch(err => console.log(err));
  }
}

module.exports = YtsClient;
<|endoftext|>


<commit_before>openerp.web_process = function (openerp) {
    var QWeb = openerp.web.qweb;
    QWeb.add_template('/web_process/static/src/xml/web_process.xml');
    openerp.web.ViewManager.include({
        start: function() {
            this._super();
            var self = this;
            this.process_check();
            this.process_help = this.action.help || 'Help: Not Defined';
        },
        process_check: function() {
            var self = this,
            grandparent = this.widget_parent && this.widget_parent.widget_parent,
            view = this.views[this.views_src[0].view_type],
            $process_view = this.$element.find('.oe-process-view');

            this.process_model = this.model;
            if (!(grandparent instanceof openerp.web.WebClient) ||
                !(view.view_type === this.views_src[0].view_type
                    && view.view_id === this.views_src[0].view_id)) {
                        $process_view.hide();
                        return;
            }
            $process_view.click(function() {
                $.when(self.load_process()).then(self.get_process_id());
            });
        },

        process_subflow : function() {
            var self = this;
            new openerp.web.DataSetSearch(this,
                "ir.actions.act_window",this.session.context,[])
            .read_slice(['help'],
                { domain:
                    [
                        ['res_model','=',this.process_action_model],
                        ['name','ilike', this.process_action_name]
                    ]
                },
                function(res) {
                    if (res.length) {
                        self.process_help = res[0]['help'] || 'Help: Not Defined';
                    }
                    $.when(self.load_process()).then(self.render_process_view());

            });
        },

        load_process: function() {
            this.$element.html(QWeb.render("ProcessView", this));
        },

        get_process_id: function() {
            var self = this;
            this.process_dataset = new openerp.web.DataSetStatic(this, "process.process", this.session.context);
            this.process_dataset.call("search_by_model",
                    [self.process_model,self.session.context],
                    function(res) {self.process_renderer(res)});
        },
        process_renderer: function(res) {
            var self = this;
            if(!res.length) {
                this.process_model = false;
                this.get_process_id();
            } else {
                if(res.length > 1) {
                    this.selection = res;
                    $.when(this.load_process()).then(function() {
                        var $parent = self.widget_parent.$element;
                        $parent.find('#change_process').click(function() {
                            self.selection = false;
                            self.p_id = $parent.find('#select_process').val();
                            $.when(self.load_process()).then(self.render_process_view());
                        });
                    });
                } else {
                    this.p_id = res[0][0];
                    $.when(this.load_process()).then(this.render_process_view());
                }
            }
        },

        render_process_view: function() {
            var self = this;
            this.p_id = parseInt(this.p_id, 10);
            this.process_dataset.call("graph_get",
                    [self.p_id, self.model, false, [80,80,150,100]],
                    function(res) {
                        res['title'] = res.resource ? res.resource : res.name;
                        self.process_dataset.call("search_by_model",
                            [self.model,self.session.context],
                            function(r) {
                                res['related'] = r;
                            });
                        self.draw_process_graph(res);
                    }
            );
        },

        draw_process_graph: function(res) {
            var self = this;
            var process_graph = new Graph();

            var process_renderer = function(r, n) {
                var process_node,
                    process_node_text,
                    process_node_desc,
                    process_set;

                var node_button,
                    node_menu,
                    img_src;

                var bg = "node",
                    clip_rect = "".concat(n.node.x,",",n.node.y,",150,100"),
//                    text_position_x  = n.node.x + (n.node.y/2)

                //Image part
                bg = n.node.kind == "subflow" ? "node-subflow" : "node";
                bg = n.node.gray ? bg + "-gray" : bg;
                img_src = '/web_process/static/src/img/'+ bg + '.png';

                r['image'](img_src, n.node.x, n.node.y,150, 100)
                    .attr({"clip-rect": clip_rect})
                    .mousedown(function(){
                        return false;
                });

                //Node
                process_node = r['rect'](n.node.x, n.node.y, 150, 100).attr({stroke: "none"});
                // Node text
                process_node_text =  r.text(n.node.x, n.node.y, (n.node.name))
                    .attr({"fill": "#fff", "font-weight": "bold", "cursor": "pointer"});
                process_node_text.translate(n.node.x / 2, 10)
                if(n.node.subflow) {
                    process_node_text.click(function() {
                        self.p_id = n.node.subflow[0];
                        self.process_action_model =  n.node.model;
                        self.process_action_name = n.node.name;
                        self.process_subflow();
                    });
                }

                //Node Description
                process_node_desc = r.text(n.node.x+75, n.node.y+50, (n.node.notes));

                r['image']('/web/static/src/img/icons/gtk-info.png', n.node.x+20, n.node.y+70, 16, 16)
                    .attr({"cursor": "pointer", "title": "Help"})
                    .click(function() {
                        window.open(n.node.url || "http://doc.openerp.com/v6.0/index.php?model=" + n.node.model);
                    });

                if(n.node.menu) {
                    r['image']('/web/static/src/img/icons/gtk-jump-to.png', n.node.x+115, n.node.y+70, 16, 16)
                    .attr({"cursor": "pointer", "title": n.node.menu.name})
                    .click(function() {
                        self.jump_to_view(n.node.res_model, n.node.menu.id);
                    });
                }

                process_set = r.set().push(process_node);
	            process_set.mousedown(function() {
                    return false;
                });
                return process_set;
            };

            _.each(res['nodes'],function(node, node_id) {
                node['res_model'] = self.model,
                node['res_id'] = false,
                node['id'] = node_id;
                process_graph.addNode(node['name'], {node: node,render: process_renderer});
            });

            _.each(res['transitions'], function(transitions) {
                var src = res['nodes'][transitions['source']];
                var dst = res['nodes'][transitions['target']];
                // make active
                transitions['active'] = src.active && !dst.gray;
                process_graph.addEdge(src['name'], dst['name'], {directed : true});
            });

            var layouter = new Graph.Layout.Ordered(process_graph);
            var render_process_graph = new Graph.Renderer.Raphael('process_canvas', process_graph, $('#process_canvas').width(), $('#process_canvas').height());
        },

        jump_to_view: function(model, id) {
            var self = this;
            var dataset = new openerp.web.DataSetStatic(this, 'ir.values', this.session.context);
            dataset.call('get',
                ['action', 'tree_but_open',[['ir.ui.menu', id]], dataset.context],
                function(res) {
                    self.$element.empty();
                    var action = res[0][res[0].length - 1];
                    self.rpc("/web/action/load", {
                        action_id: action.id,
                        context: dataset.context
                        }, function(result) {
                            var action_manager = new openerp.web.ActionManager(self);
                            action_manager.appendTo(self.widget_parent.$element);
                            action_manager.do_action(result.result);
                        });
                });
        }
    });
};

// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
<commit_msg>[IMP] process :- string display in node.<commit_after>openerp.web_process = function (openerp) {
    var QWeb = openerp.web.qweb;
    QWeb.add_template('/web_process/static/src/xml/web_process.xml');
    openerp.web.ViewManager.include({
        start: function() {
            this._super();
            var self = this;
            this.process_check();
            this.process_help = this.action.help || 'Help: Not Defined';
        },
        process_check: function() {
            var self = this,
            grandparent = this.widget_parent && this.widget_parent.widget_parent,
            view = this.views[this.views_src[0].view_type],
            $process_view = this.$element.find('.oe-process-view');

            this.process_model = this.model;
            if (!(grandparent instanceof openerp.web.WebClient) ||
                !(view.view_type === this.views_src[0].view_type
                    && view.view_id === this.views_src[0].view_id)) {
                        $process_view.hide();
                        return;
            }
            $process_view.click(function() {
                $.when(self.load_process()).then(self.get_process_id());
            });
        },

        process_subflow : function() {
            var self = this;
            new openerp.web.DataSetSearch(this,
                "ir.actions.act_window",this.session.context,[])
            .read_slice(['help'],
                { domain:
                    [
                        ['res_model','=',this.process_action_model],
                        ['name','ilike', this.process_action_name]
                    ]
                },
                function(res) {
                    if (res.length) {
                        self.process_help = res[0]['help'] || 'Help: Not Defined';
                    }
                    $.when(self.load_process()).then(self.render_process_view());

            });
        },

        load_process: function() {
            this.$element.html(QWeb.render("ProcessView", this));
        },

        get_process_id: function() {
            var self = this;
            this.process_dataset = new openerp.web.DataSetStatic(this, "process.process", this.session.context);
            this.process_dataset.call("search_by_model",
                    [self.process_model,self.session.context],
                    function(res) {self.process_renderer(res)});
        },
        process_renderer: function(res) {
            var self = this;
            if(!res.length) {
                this.process_model = false;
                this.get_process_id();
            } else {
                if(res.length > 1) {
                    this.selection = res;
                    $.when(this.load_process()).then(function() {
                        var $parent = self.widget_parent.$element;
                        $parent.find('#change_process').click(function() {
                            self.selection = false;
                            self.p_id = $parent.find('#select_process').val();
                            $.when(self.load_process()).then(self.render_process_view());
                        });
                    });
                } else {
                    this.p_id = res[0][0];
                    $.when(this.load_process()).then(this.render_process_view());
                }
            }
        },

        render_process_view: function() {
            var self = this;
            this.p_id = parseInt(this.p_id, 10);
            this.process_dataset.call("graph_get",
                    [self.p_id, self.model, false, [80,80,150,100]],
                    function(res) {
                        res['title'] = res.resource ? res.resource : res.name;
                        self.process_dataset.call("search_by_model",
                            [self.model,self.session.context],
                            function(r) {
                                res['related'] = r;
                            });
                        self.draw_process_graph(res);
                    }
            );
        },
        draw_process_graph: function(res) {
            var self = this;
            var process_graph = new Graph();

            var process_renderer = function(r, n) {
                var process_node,
                    process_node_text,
                    process_node_desc,
                    process_set;

                var node_button,
                    node_menu,
                    img_src;

                var bg = "node",
                    clip_rect = "".concat(n.node.x,",",n.node.y,",150,100"),
//                    text_position_x  = n.node.x + (n.node.y/2)

                //Image part
                bg = n.node.kind == "subflow" ? "node-subflow" : "node";
                bg = n.node.gray ? bg + "-gray" : bg;
                img_src = '/web_process/static/src/img/'+ bg + '.png';

                r['image'](img_src, n.node.x, n.node.y,150, 100)
                    .attr({"clip-rect": clip_rect})
                    .mousedown(function(){
                        return false;
                });

                //Node
                process_node = r['rect'](n.node.x, n.node.y, 150, 100).attr({stroke: "none"});
                // Node text
                process_node_text =  r.text(n.node.x, n.node.y, (n.node.name))
                    .attr({"fill": "#fff", "font-weight": "bold", "cursor": "pointer"});
                process_node_text.translate(n.node.x / 2, 10)
                if(n.node.subflow) {
                    process_node_text.click(function() {
                        self.p_id = n.node.subflow[0];
                        self.process_action_model =  n.node.model;
                        self.process_action_name = n.node.name;
                        self.process_subflow();
                    });
                }

                //Node Description
                new_notes = n.node.notes;
                if(n.node.notes.length > 25) {
                    var new_notes= temp_str = '';
                    var from = to = 0;
                    while (1){
                        from = 25;
                        temp_str = n.node.notes.substr(to ,25);
                        if (temp_str.lastIndexOf(" ") < 25 && temp_str.length >= 25) {
                            from  =  temp_str.lastIndexOf(" ");
                        }
                        new_notes += "\n" + n.node.notes.substr(to , from);
                        if(new_notes.length > n.node.notes.length) break;
                        to += from;
                    }
                }
                process_node_desc = r.text(n.node.x+85, n.node.y+50, (new_notes));
                r['image']('/web/static/src/img/icons/gtk-info.png', n.node.x+20, n.node.y+70, 16, 16)
                    .attr({"cursor": "pointer", "title": "Help"})
                    .click(function() {
                        window.open(n.node.url || "http://doc.openerp.com/v6.0/index.php?model=" + n.node.model);
                    });

                if(n.node.menu) {
                    r['image']('/web/static/src/img/icons/gtk-jump-to.png', n.node.x+115, n.node.y+70, 16, 16)
                    .attr({"cursor": "pointer", "title": n.node.menu.name})
                    .click(function() {
                        self.jump_to_view(n.node.res_model, n.node.menu.id);
                    });
                }

                process_set = r.set().push(process_node);
	            process_set.mousedown(function() {
                    return false;
                });
                return process_set;
            };

            _.each(res['nodes'],function(node, node_id) {
                node['res_model'] = self.model,
                node['res_id'] = false,
                node['id'] = node_id;
                process_graph.addNode(node['name'], {node: node,render: process_renderer});
            });

            _.each(res['transitions'], function(transitions) {
                var src = res['nodes'][transitions['source']];
                var dst = res['nodes'][transitions['target']];
                // make active
                transitions['active'] = src.active && !dst.gray;
                process_graph.addEdge(src['name'], dst['name'], {directed : true});
            });

            var layouter = new Graph.Layout.Ordered(process_graph);
            var render_process_graph = new Graph.Renderer.Raphael('process_canvas', process_graph, $('#process_canvas').width(), $('#process_canvas').height());
        },

        jump_to_view: function(model, id) {
            var self = this;
            var dataset = new openerp.web.DataSetStatic(this, 'ir.values', this.session.context);
            dataset.call('get',
                ['action', 'tree_but_open',[['ir.ui.menu', id]], dataset.context],
                function(res) {
                    self.$element.empty();
                    var action = res[0][res[0].length - 1];
                    self.rpc("/web/action/load", {
                        action_id: action.id,
                        context: dataset.context
                        }, function(result) {
                            var action_manager = new openerp.web.ActionManager(self);
                            action_manager.appendTo(self.widget_parent.$element);
                            action_manager.do_action(result.result);
                        });
                });
        }
    });
};

// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
<|endoftext|>


<commit_before>const _ = require('lodash')
const cheerio = require('cheerio')
const uslug = require('uslug')
const pageHelper = require('../../../helpers/page')
const URL = require('url').URL

/* global WIKI */

module.exports = {
  async render() {
    const $ = cheerio.load(this.input)

    if ($.root().children().length < 1) {
      return ''
    }

    // --------------------------------
    // STEP: PRE
    // --------------------------------

    for (let child of _.reject(this.children, ['step', 'post'])) {
      const renderer = require(`../${_.kebabCase(child.key)}/renderer.js`)
      renderer.init($, child.config)
    }

    // --------------------------------
    // Detect internal / external links
    // --------------------------------

    let internalRefs = []
    const reservedPrefixes = /^\/[a-z]\//gi
    const exactReservedPaths = /^\/[a-z]$/gi

    const isHostSet = WIKI.config.host.length > 7 && WIKI.config.host !== 'http://'
    if (!isHostSet) {
      WIKI.logger.warn('Host is not set. You must set the Site Host under General in the Administration Area!')
    }

    $('a').each((i, elm) => {
      let href = $(elm).attr('href')

      // -> Ignore empty / anchor links, e-mail addresses, and telephone numbers
      if (!href || href.length < 1 || href.indexOf('#') === 0 ||
        href.indexOf('mailto:') === 0 || href.indexOf('tel:') === 0) {
        return
      }

      // -> Strip host from local links
      if (isHostSet && href.indexOf(WIKI.config.host) === 0) {
        href = href.replace(WIKI.config.host, '')
      }

      // -> Assign local / external tag
      if (href.indexOf('://') < 0) {
        // -> Remove trailing slash
        if (_.endsWith('/')) {
          href = href.slice(0, -1)
        }

        // -> Check for system prefix
        if (reservedPrefixes.test(href) || exactReservedPaths.test(href)) {
          $(elm).addClass(`is-system-link`)
        } else if (href.indexOf('.') >= 0) {
          $(elm).addClass(`is-asset-link`)
        } else {
          let pagePath = null

          // -> Add locale prefix if using namespacing
          if (WIKI.config.lang.namespacing) {
            // -> Reformat paths
            if (href.indexOf('/') !== 0) {
              href = (this.page.path === 'home') ? `/${this.page.localeCode}/${href}` : `/${this.page.localeCode}/${this.page.path}/${href}`
            } else if (href.charAt(3) !== '/') {
              href = `/${this.page.localeCode}${href}`
            }

            try {
              const parsedUrl = new URL(`http://x${href}`)
              pagePath = pageHelper.parsePath(parsedUrl.pathname)
            } catch (err) {
              return
            }
          } else {
            // -> Reformat paths
            if (href.indexOf('/') !== 0) {
              href = (this.page.path === 'home') ? `/${href}` : `/${this.page.path}/${href}`
            }

            try {
              const parsedUrl = new URL(`http://x${href}`)
              pagePath = pageHelper.parsePath(parsedUrl.pathname)
            } catch (err) {
              return
            }
          }
          // -> Save internal references
          internalRefs.push({
            localeCode: pagePath.locale,
            path: pagePath.path
          })

          $(elm).addClass(`is-internal-link`)
        }
      } else {
        $(elm).addClass(`is-external-link`)
      }

      // -> Update element
      $(elm).attr('href', href)
    })

    // --------------------------------
    // Detect internal link states
    // --------------------------------

    const pastLinks = await this.page.$relatedQuery('links')

    if (internalRefs.length > 0) {
      // -> Find matching pages
      const results = await WIKI.models.pages.query().column('id', 'path', 'localeCode').where(builder => {
        internalRefs.forEach((ref, idx) => {
          if (idx < 1) {
            builder.where(ref)
          } else {
            builder.orWhere(ref)
          }
        })
      })

      // -> Apply tag to internal links for found pages
      $('a.is-internal-link').each((i, elm) => {
        const href = $(elm).attr('href')
        let hrefObj = {}
        try {
          const parsedUrl = new URL(`http://x${href}`)
          hrefObj = pageHelper.parsePath(parsedUrl.pathname)
        } catch (err) {
          return
        }
        if (_.some(results, r => {
          return r.localeCode === hrefObj.locale && r.path === hrefObj.path
        })) {
          $(elm).addClass(`is-valid-page`)
        } else {
          $(elm).addClass(`is-invalid-page`)
        }
      })

      // -> Add missing links
      const missingLinks = _.differenceWith(internalRefs, pastLinks, (nLink, pLink) => {
        return nLink.localeCode === pLink.localeCode && nLink.path === pLink.path
      })
      if (missingLinks.length > 0) {
        if (WIKI.config.db.type === 'postgres') {
          await WIKI.models.pageLinks.query().insert(missingLinks.map(lnk => ({
            pageId: this.page.id,
            path: lnk.path,
            localeCode: lnk.localeCode
          })))
        } else {
          for (const lnk of missingLinks) {
            await WIKI.models.pageLinks.query().insert({
              pageId: this.page.id,
              path: lnk.path,
              localeCode: lnk.localeCode
            })
          }
        }
      }
    }

    // -> Remove outdated links
    if (pastLinks) {
      const outdatedLinks = _.differenceWith(pastLinks, internalRefs, (nLink, pLink) => {
        return nLink.localeCode === pLink.localeCode && nLink.path === pLink.path
      })
      if (outdatedLinks.length > 0) {
        await WIKI.models.pageLinks.query().delete().whereIn('id', _.map(outdatedLinks, 'id'))
      }
    }

    // --------------------------------
    // Add header handles
    // --------------------------------

    let headers = []
    $('h1,h2,h3,h4,h5,h6').each((i, elm) => {
      if ($(elm).attr('id')) {
        return
      }
      let headerSlug = uslug($(elm).text())

      // -> Cannot start with a number (CSS selector limitation)
      if (headerSlug.match(/^\d/)) {
        headerSlug = `h-${headerSlug}`
      }

      // -> Make sure header is unique
      if (headers.indexOf(headerSlug) >= 0) {
        let isUnique = false
        let hIdx = 1
        while (!isUnique) {
          const headerSlugTry = `${headerSlug}-${hIdx}`
          if (headers.indexOf(headerSlugTry) < 0) {
            isUnique = true
            headerSlug = headerSlugTry
          }
          hIdx++
        }
      }

      // -> Add anchor
      $(elm).attr('id', headerSlug).addClass('toc-header')
      $(elm).prepend(`<a class="toc-anchor" href="#${headerSlug}">¶</a> `)

      headers.push(headerSlug)
    })

    let output = $.html('body').replace('', '').replace('', '')

    // --------------------------------
    // STEP: POST
    // --------------------------------

    for (let child of _.filter(this.children, ['step', 'post'])) {
      const renderer = require(`../${_.kebabCase(child.key)}/renderer.js`)
      output = renderer.init(output, child.config)
    }

    return output
  }
}
<commit_msg>fix: render system link detection resets on each find<commit_after>const _ = require('lodash')
const cheerio = require('cheerio')
const uslug = require('uslug')
const pageHelper = require('../../../helpers/page')
const URL = require('url').URL

/* global WIKI */

module.exports = {
  async render() {
    const $ = cheerio.load(this.input)

    if ($.root().children().length < 1) {
      return ''
    }

    // --------------------------------
    // STEP: PRE
    // --------------------------------

    for (let child of _.reject(this.children, ['step', 'post'])) {
      const renderer = require(`../${_.kebabCase(child.key)}/renderer.js`)
      renderer.init($, child.config)
    }

    // --------------------------------
    // Detect internal / external links
    // --------------------------------

    let internalRefs = []
    const reservedPrefixes = /^\/[a-z]\//i
    const exactReservedPaths = /^\/[a-z]$/i

    const isHostSet = WIKI.config.host.length > 7 && WIKI.config.host !== 'http://'
    if (!isHostSet) {
      WIKI.logger.warn('Host is not set. You must set the Site Host under General in the Administration Area!')
    }

    $('a').each((i, elm) => {
      let href = $(elm).attr('href')

      // -> Ignore empty / anchor links, e-mail addresses, and telephone numbers
      if (!href || href.length < 1 || href.indexOf('#') === 0 ||
        href.indexOf('mailto:') === 0 || href.indexOf('tel:') === 0) {
        return
      }

      // -> Strip host from local links
      if (isHostSet && href.indexOf(WIKI.config.host) === 0) {
        href = href.replace(WIKI.config.host, '')
      }

      // -> Assign local / external tag
      if (href.indexOf('://') < 0) {
        // -> Remove trailing slash
        if (_.endsWith('/')) {
          href = href.slice(0, -1)
        }

        // -> Check for system prefix
        if (reservedPrefixes.test(href) || exactReservedPaths.test(href)) {
          $(elm).addClass(`is-system-link`)
        } else if (href.indexOf('.') >= 0) {
          $(elm).addClass(`is-asset-link`)
        } else {
          let pagePath = null

          // -> Add locale prefix if using namespacing
          if (WIKI.config.lang.namespacing) {
            // -> Reformat paths
            if (href.indexOf('/') !== 0) {
              href = (this.page.path === 'home') ? `/${this.page.localeCode}/${href}` : `/${this.page.localeCode}/${this.page.path}/${href}`
            } else if (href.charAt(3) !== '/') {
              href = `/${this.page.localeCode}${href}`
            }

            try {
              const parsedUrl = new URL(`http://x${href}`)
              pagePath = pageHelper.parsePath(parsedUrl.pathname)
            } catch (err) {
              return
            }
          } else {
            // -> Reformat paths
            if (href.indexOf('/') !== 0) {
              href = (this.page.path === 'home') ? `/${href}` : `/${this.page.path}/${href}`
            }

            try {
              const parsedUrl = new URL(`http://x${href}`)
              pagePath = pageHelper.parsePath(parsedUrl.pathname)
            } catch (err) {
              return
            }
          }
          // -> Save internal references
          internalRefs.push({
            localeCode: pagePath.locale,
            path: pagePath.path
          })

          $(elm).addClass(`is-internal-link`)
        }
      } else {
        $(elm).addClass(`is-external-link`)
      }

      // -> Update element
      $(elm).attr('href', href)
    })

    // --------------------------------
    // Detect internal link states
    // --------------------------------

    const pastLinks = await this.page.$relatedQuery('links')

    if (internalRefs.length > 0) {
      // -> Find matching pages
      const results = await WIKI.models.pages.query().column('id', 'path', 'localeCode').where(builder => {
        internalRefs.forEach((ref, idx) => {
          if (idx < 1) {
            builder.where(ref)
          } else {
            builder.orWhere(ref)
          }
        })
      })

      // -> Apply tag to internal links for found pages
      $('a.is-internal-link').each((i, elm) => {
        const href = $(elm).attr('href')
        let hrefObj = {}
        try {
          const parsedUrl = new URL(`http://x${href}`)
          hrefObj = pageHelper.parsePath(parsedUrl.pathname)
        } catch (err) {
          return
        }
        if (_.some(results, r => {
          return r.localeCode === hrefObj.locale && r.path === hrefObj.path
        })) {
          $(elm).addClass(`is-valid-page`)
        } else {
          $(elm).addClass(`is-invalid-page`)
        }
      })

      // -> Add missing links
      const missingLinks = _.differenceWith(internalRefs, pastLinks, (nLink, pLink) => {
        return nLink.localeCode === pLink.localeCode && nLink.path === pLink.path
      })
      if (missingLinks.length > 0) {
        if (WIKI.config.db.type === 'postgres') {
          await WIKI.models.pageLinks.query().insert(missingLinks.map(lnk => ({
            pageId: this.page.id,
            path: lnk.path,
            localeCode: lnk.localeCode
          })))
        } else {
          for (const lnk of missingLinks) {
            await WIKI.models.pageLinks.query().insert({
              pageId: this.page.id,
              path: lnk.path,
              localeCode: lnk.localeCode
            })
          }
        }
      }
    }

    // -> Remove outdated links
    if (pastLinks) {
      const outdatedLinks = _.differenceWith(pastLinks, internalRefs, (nLink, pLink) => {
        return nLink.localeCode === pLink.localeCode && nLink.path === pLink.path
      })
      if (outdatedLinks.length > 0) {
        await WIKI.models.pageLinks.query().delete().whereIn('id', _.map(outdatedLinks, 'id'))
      }
    }

    // --------------------------------
    // Add header handles
    // --------------------------------

    let headers = []
    $('h1,h2,h3,h4,h5,h6').each((i, elm) => {
      if ($(elm).attr('id')) {
        return
      }
      let headerSlug = uslug($(elm).text())

      // -> Cannot start with a number (CSS selector limitation)
      if (headerSlug.match(/^\d/)) {
        headerSlug = `h-${headerSlug}`
      }

      // -> Make sure header is unique
      if (headers.indexOf(headerSlug) >= 0) {
        let isUnique = false
        let hIdx = 1
        while (!isUnique) {
          const headerSlugTry = `${headerSlug}-${hIdx}`
          if (headers.indexOf(headerSlugTry) < 0) {
            isUnique = true
            headerSlug = headerSlugTry
          }
          hIdx++
        }
      }

      // -> Add anchor
      $(elm).attr('id', headerSlug).addClass('toc-header')
      $(elm).prepend(`<a class="toc-anchor" href="#${headerSlug}">¶</a> `)

      headers.push(headerSlug)
    })

    let output = $.html('body').replace('', '').replace('', '')

    // --------------------------------
    // STEP: POST
    // --------------------------------

    for (let child of _.filter(this.children, ['step', 'post'])) {
      const renderer = require(`../${_.kebabCase(child.key)}/renderer.js`)
      output = renderer.init(output, child.config)
    }

    return output
  }
}
<|endoftext|>


<commit_before>import React from "react";
import {
  StyleSheet,
  Text,
  View,
  Image,
  ScrollView,
  Animated,
  TouchableOpacity,
  Platform,
  StatusBar
} from "react-native";
import { NavigationActions } from "react-navigation";
import { lightpurple, darkpurple, pink } from "./colors.js";
import * as Animatable from "react-native-animatable";
import { Feather } from '@expo/vector-icons';

// var infoButtons = [
//   require("./assets/images/info.png"),
//   require("./assets/images/xbutton.png")
// ];

export default class MuralInfoPage extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      descriptionVisible: false,

      // should be set true after the first time the user clicks to show description
      // this prevents fadeIn/fadeOut animations on intial render
      pastInitialClick: false
    };
  }

  static navigationOptions = ({ navigation }) => {
    return Platform.OS === "ios"
      ? {
          headerLeft: (
            <TouchableOpacity
              style={{ top: 30, left: -25, padding: 40 }}
              onPress={() => navigation.dispatch(NavigationActions.back())}
            >
              <View
                style={{
                  position: "relative",
                  flexDirection: "row",
                  backgroundColor: 'white',
                  zIndex: 100,
                  marginTop: -15,
                  width: 120,
                  height: 40,
                  borderRadius: 100,
                  alignItems: 'center',
                  justifyContent: 'center',
                  paddingRight: 6,
                  shadowOffset: { width: 1, height: 1 },
                  shadowRadius: 2,
                  shadowOpacity: 0.6,
                }}
              >
                <Feather name="chevron-left" size={25} color={pink} style={{marginBottom: 1}} />
                <Text style={{fontWeight: 'bold', fontSize: 17, color: pink}}>  Back </Text>
              </View>
            </TouchableOpacity>
          ),
          headerStyle: {
            position: "absolute",
            backgroundColor: "transparent",
            zIndex: 100,
            top: 0,
            left: 0,
            right: 0,
            borderBottomColor: "transparent"
          }
        }
      : {
          title: "Punto Urban Art",
          headerTintColor: "white",
          headerStyle: { backgroundColor: pink }
        };
  }

  toggleShowDescription() {
    this.setState({
      descriptionVisible: !this.state.descriptionVisible,
      pastInitialClick: true
    });
  }

  render() {
    const mural = this.props.navigation.state.params.mural;
    const artist = this.props.navigation.state.params.artist;

    closeButton = (
      <Feather name="x" size={50} color="white" style={{fontWeight: 'bold'}} />
    );
    readMoreButton = (
      <TouchableOpacity
        style={{
          paddingTop: 15,
          paddingBottom: 50,
          paddingRight: 70
        }}
        onPress={this.toggleShowDescription.bind(this)}
      >
        <View style={infoStyles.moreInfoButtonContainer}>
          <Text style={infoStyles.moreInfoButton}>Read More</Text>
        </View>
      </TouchableOpacity>
    );

    var description = "";
    if (artist["city"]) {
      description += artist["city"];
    }

    if (mural["Month"] && mural["Year"]) {
      description += "\n\n" + mural["Month"] + ", " + mural["Year"];
    }

    if (mural["Medium"]) {
      description += "\n" + mural["Medium"];
    }

    if (mural["Description"] && mural["Description"].trim().length > 0) {
      description += "\n\n" + mural["Description"];
    }

    if (artist["bio"] && artist["bio"].trim().length > 0) {
      description += "\n\n" + artist["bio"];
    }

    descriptionVisible = this.state.descriptionVisible;
    pastInitialClick = this.state.pastInitialClick;

    return (
      <View style={infoStyles.container}>
        <StatusBar
          barStyle={Platform.OS === "ios" ? "light-content" : "light-content"}
        />
        <Image
          style={{
            flex: 1,
            position: "absolute",
            resizeMode: "cover",
            height: "100%",
            width: "100%"
          }}
          source={{ uri: mural.Photo }}
        />
        <Animatable.View
          animation={descriptionVisible ? "fadeIn" : "fadeOut"}
          duration={500}
          style={infoStyles.darkerOverlay}
        />
        <View style={infoStyles.darkOverlay} />
        <View style={infoStyles.textContainer}>
          <View style={infoStyles.top}>
            <View style={infoStyles.info}>
              <View>
                <Text style={infoStyles.name}>{mural.Title}</Text>
              </View>
              <View>
                <Text style={infoStyles.artist}>{artist.name}</Text>
              </View>
            </View>
            <Animatable.View
              animation={descriptionVisible ? "fadeIn" : "fadeOut"}
              duration={200}
              style={infoStyles.button}
            >
              <TouchableOpacity
                style={{
                  padding: 15,
                  paddingTop: 20,
                  paddingLeft: 15,
                  paddingBottom: 20
                }}
                onPress={this.toggleShowDescription.bind(this)}
              >
                {closeButton}
              </TouchableOpacity>
            </Animatable.View>
          </View>
          <View>
            {
              <Animatable.View
                animation={descriptionVisible ? "fadeOut" : "fadeIn"}
                duration={descriptionVisible ? 200 : 1000}
                style={infoStyles.description}
              >
                {readMoreButton}
              </Animatable.View>
            }
            {pastInitialClick && (
              <Animatable.View
                animation={descriptionVisible ? "fadeInUp" : "fadeOutDown"}
                duration={500}
                style={infoStyles.description}
              >
                <ScrollView style={{ marginTop: 10, height: "80%", marginBottom: 50 }}>
                  <Text style={{ color: "white", marginTop: 10 }}>{description}</Text>
                </ScrollView>
              </Animatable.View>
            )}
          </View>
        </View>
      </View>
    );
  }
}

infoStyles = {};
if (Platform.OS === "ios") {
  infoStyles = StyleSheet.create({
    container: {
      flex: 1,
      backgroundColor: "#fff"
    },
    textContainer: {
      flex: 1,
      marginTop: "20%",
      paddingTop: 60,
      padding: 20,
      paddingRight: 0,
      backgroundColor: "transparent"
    },
    top: {
      display: "flex",
      flexDirection: "row"
    },
    info: {
      flex: 4,
      justifyContent: "center",
      alignItems: "flex-start"
    },
    button: {
      flex: 2,
      justifyContent: "center",
      alignItems: "flex-end"
    },
    name: {
      color: "white",
      fontWeight: "bold",
      textShadowColor: "black",
      textShadowOffset: { width: 1, height: 1 },
      textShadowRadius: 2,
      paddingLeft: 3,
      paddingTop: 3,
      lineHeight: 35,
      marginBottom: 5,
      fontSize: 36
    },
    artist: {
      color: "white",
      textShadowColor: "black",
      textShadowOffset: { width: 1, height: 1 },
      textShadowRadius: 2,
      paddingLeft: 3,
      fontSize: 24,
    },
    description: {
      paddingRight: 20,
      paddingLeft: 3,
      position: "absolute"
    },
    darkOverlay: {
      position: "absolute",
      height: "100%",
      width: "100%",
      backgroundColor: "rgba(0, 0, 0, 0.45)"
    },
    darkerOverlay: {
      position: "absolute",
      height: "100%",
      width: "100%",
      backgroundColor: "rgba(0, 0, 0, 0.7)"
    },
    moreInfoButton: {
      color: "white",
      textShadowColor: "black",
      textShadowOffset: { width: -1, height: 1 },
      textShadowRadius: 2,
      fontWeight: 'bold',
      fontSize: 16
    },
    moreInfoButtonContainer: {
      backgroundColor: "rgba(128, 128, 128, 0.3)",
      width: 135,
      height: 40,
      borderColor: 'white',
      marginLeft: -5,
      borderWidth: 2,
      borderRadius: 100,
      alignItems: 'center',
      justifyContent: 'center',
      shadowColor: "black",
      shadowOffset: { width: 1, height: 1 },
      shadowRadius: 2,
      shadowOpacity: 0.6,
    }
  });
} else {
  infoStyles = StyleSheet.create({
    container: {
      flex: 1,
      backgroundColor: "#fff"
    },
    textContainer: {
      flex: 1,
      paddingTop: 60,
      paddingRight: 0,
      padding: 20,
      backgroundColor: "transparent"
    },
    top: {
      display: "flex",
      flexDirection: "row"
    },
    info: {
      flex: 4,
      justifyContent: "center",
      alignItems: "flex-start"
    },
    button: {
      flex: 2,
      justifyContent: "center",
      alignItems: "flex-end"
    },
    name: {
      color: "white",
      textShadowColor: "black",
      fontWeight: "bold",
      textShadowOffset: { width: -1, height: 0 },
      textShadowRadius: 5,
      paddingLeft: 2,
      lineHeight: 35,
      marginBottom: 5,
      fontSize: 36
    },
    artist: {
      color: "white",
      textShadowColor: "black",
      textShadowOffset: { width: -1, height: 0 },
      textShadowRadius: 5,
      paddingLeft: 2,
      fontSize: 24,
    },
    description: {
      paddingRight: 20,
      paddingLeft: 2,
      position: "absolute"
    },
    darkOverlay: {
      position: "absolute",
      height: "100%",
      width: "100%",
      backgroundColor: "rgba(0, 0, 0, 0.4)"
    },
    darkerOverlay: {
      position: "absolute",
      height: "100%",
      width: "100%",
      backgroundColor: "rgba(0, 0, 0, 0.6)"
    },
    moreInfoButton: {
      color: "white",
      fontSize: 15,
      elevation: 4,
    },
    moreInfoButtonContainer: {
      backgroundColor: "rgba(56, 56, 56, 0.3)",
      width: 135,
      height: 40,
      borderColor: 'white',
      borderWidth: 2,
      borderRadius: 20,
      alignItems: 'center',
      justifyContent: 'center',
      elevation: 2,
    }
  });
}
<commit_msg>hacky scrollview height<commit_after>import React from "react";
import {
  StyleSheet,
  Text,
  View,
  Image,
  ScrollView,
  Animated,
  Dimensions,
  TouchableOpacity,
  Platform,
  StatusBar
} from "react-native";
import { NavigationActions } from "react-navigation";
import { lightpurple, darkpurple, pink } from "./colors.js";
import * as Animatable from "react-native-animatable";
import { Feather } from '@expo/vector-icons';

// var infoButtons = [
//   require("./assets/images/info.png"),
//   require("./assets/images/xbutton.png")
// ];

function isIphoneX() {
  const dimen = Dimensions.get("window");
  return (
    Platform.OS === "ios" &&
    !Platform.isPad &&
    !Platform.isTVOS &&
    (dimen.height === 812 || dimen.width === 812)
  );
}

export default class MuralInfoPage extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      descriptionVisible: false,

      // should be set true after the first time the user clicks to show description
      // this prevents fadeIn/fadeOut animations on intial render
      pastInitialClick: false
    };
  }

  static navigationOptions = ({ navigation }) => {
    return Platform.OS === "ios"
      ? {
          headerLeft: (
            <TouchableOpacity
              style={{ top: 30, left: -25, padding: 40 }}
              onPress={() => navigation.dispatch(NavigationActions.back())}
            >
              <View
                style={{
                  position: "relative",
                  flexDirection: "row",
                  backgroundColor: 'white',
                  zIndex: 100,
                  marginTop: -15,
                  width: 120,
                  height: 40,
                  borderRadius: 100,
                  alignItems: 'center',
                  justifyContent: 'center',
                  paddingRight: 6,
                  shadowOffset: { width: 1, height: 1 },
                  shadowRadius: 2,
                  shadowOpacity: 0.6,
                }}
              >
                <Feather name="chevron-left" size={25} color={pink} style={{marginBottom: 1}} />
                <Text style={{fontWeight: 'bold', fontSize: 17, color: pink}}>  Back </Text>
              </View>
            </TouchableOpacity>
          ),
          headerStyle: {
            position: "absolute",
            backgroundColor: "transparent",
            zIndex: 100,
            top: 0,
            left: 0,
            right: 0,
            borderBottomColor: "transparent"
          }
        }
      : {
          title: "Punto Urban Art",
          headerTintColor: "white",
          headerStyle: { backgroundColor: pink }
        };
  }

  toggleShowDescription() {
    this.setState({
      descriptionVisible: !this.state.descriptionVisible,
      pastInitialClick: true
    });
  }

  render() {
    const mural = this.props.navigation.state.params.mural;
    const artist = this.props.navigation.state.params.artist;

    closeButton = (
      <Feather name="x" size={50} color="white" style={{fontWeight: 'bold'}} />
    );
    readMoreButton = (
      <TouchableOpacity
        style={{
          paddingTop: 15,
          paddingBottom: 50,
          paddingRight: 70
        }}
        onPress={this.toggleShowDescription.bind(this)}
      >
        <View style={infoStyles.moreInfoButtonContainer}>
          <Text style={infoStyles.moreInfoButton}>Read More</Text>
        </View>
      </TouchableOpacity>
    );

    var description = "";
    if (artist["city"]) {
      description += artist["city"];
    }

    if (mural["Month"] && mural["Year"]) {
      description += "\n\n" + mural["Month"] + ", " + mural["Year"];
    }

    if (mural["Medium"]) {
      description += "\n" + mural["Medium"];
    }

    if (mural["Description"] && mural["Description"].trim().length > 0) {
      description += "\n\n" + mural["Description"];
    }

    if (artist["bio"] && artist["bio"].trim().length > 0) {
      description += "\n\n" + artist["bio"];
    }

    descriptionVisible = this.state.descriptionVisible;
    pastInitialClick = this.state.pastInitialClick;

    return (
      <View style={infoStyles.container}>
        <StatusBar
          barStyle={Platform.OS === "ios" ? "light-content" : "light-content"}
        />
        <Image
          style={{
            flex: 1,
            position: "absolute",
            resizeMode: "cover",
            height: "100%",
            width: "100%"
          }}
          source={{ uri: mural.Photo }}
        />
        <Animatable.View
          animation={descriptionVisible ? "fadeIn" : "fadeOut"}
          duration={500}
          style={infoStyles.darkerOverlay}
        />
        <View style={infoStyles.darkOverlay} />
        <View style={infoStyles.textContainer}>
          <View style={infoStyles.top}>
            <View style={infoStyles.info}>
              <View>
                <Text style={infoStyles.name}>{mural.Title}</Text>
              </View>
              <View>
                <Text style={infoStyles.artist}>{artist.name}</Text>
              </View>
            </View>
            <Animatable.View
              animation={descriptionVisible ? "fadeIn" : "fadeOut"}
              duration={200}
              style={infoStyles.button}
            >
              <TouchableOpacity
                style={{
                  padding: 15,
                  paddingTop: 20,
                  paddingLeft: 15,
                  paddingBottom: 20
                }}
                onPress={this.toggleShowDescription.bind(this)}
              >
                {closeButton}
              </TouchableOpacity>
            </Animatable.View>
          </View>
          <View style={{flex: 1}}>
            {
              <Animatable.View
                animation={descriptionVisible ? "fadeOut" : "fadeIn"}
                duration={descriptionVisible ? 200 : 1000}
                style={infoStyles.description}
              >
                {readMoreButton}
              </Animatable.View>
            }
            {pastInitialClick && (
              <Animatable.View
                animation={descriptionVisible ? "fadeInUp" : "fadeOutDown"}
                duration={500}
                style={infoStyles.description}
              >
                <ScrollView style={{marginTop: 10, height: Dimensions.get("window").height / 2}}>
                  <Text style={{ color: "white", marginTop: 10 }}>{description}</Text>
                </ScrollView>
              </Animatable.View>
            )}
          </View>
        </View>
      </View>
    );
  }
}

infoStyles = {};
if (Platform.OS === "ios") {
  infoStyles = StyleSheet.create({
    container: {
      flex: 1,
      backgroundColor: "#fff"
    },
    textContainer: {
      flex: 1,
      marginTop: "20%",
      paddingTop: 60,
      padding: 20,
      paddingRight: 0,
      backgroundColor: "transparent"
    },
    top: {
      display: "flex",
      flexDirection: "row"
    },
    info: {
      flex: 4,
      justifyContent: "center",
      alignItems: "flex-start"
    },
    button: {
      flex: 2,
      justifyContent: "center",
      alignItems: "flex-end"
    },
    name: {
      color: "white",
      fontWeight: "bold",
      textShadowColor: "black",
      textShadowOffset: { width: 1, height: 1 },
      textShadowRadius: 2,
      paddingLeft: 3,
      paddingTop: 3,
      lineHeight: 35,
      marginBottom: 5,
      fontSize: 36
    },
    artist: {
      color: "white",
      textShadowColor: "black",
      textShadowOffset: { width: 1, height: 1 },
      textShadowRadius: 2,
      paddingLeft: 3,
      fontSize: 24,
    },
    description: {
      paddingRight: 20,
      paddingLeft: 3,
      position: "absolute",
      flex: 1
    },
    darkOverlay: {
      position: "absolute",
      height: "100%",
      width: "100%",
      backgroundColor: "rgba(0, 0, 0, 0.45)"
    },
    darkerOverlay: {
      position: "absolute",
      height: "100%",
      width: "100%",
      backgroundColor: "rgba(0, 0, 0, 0.7)"
    },
    moreInfoButton: {
      color: "white",
      textShadowColor: "black",
      textShadowOffset: { width: -1, height: 1 },
      textShadowRadius: 2,
      fontWeight: 'bold',
      fontSize: 16
    },
    moreInfoButtonContainer: {
      backgroundColor: "rgba(128, 128, 128, 0.3)",
      width: 135,
      height: 40,
      borderColor: 'white',
      marginLeft: -5,
      borderWidth: 2,
      borderRadius: 100,
      alignItems: 'center',
      justifyContent: 'center',
      shadowColor: "black",
      shadowOffset: { width: 1, height: 1 },
      shadowRadius: 2,
      shadowOpacity: 0.6,
    }
  });
} else {
  infoStyles = StyleSheet.create({
    container: {
      flex: 1,
      backgroundColor: "#fff"
    },
    textContainer: {
      flex: 1,
      paddingTop: 60,
      paddingRight: 0,
      padding: 20,
      backgroundColor: "transparent"
    },
    top: {
      display: "flex",
      flexDirection: "row"
    },
    info: {
      flex: 4,
      justifyContent: "center",
      alignItems: "flex-start"
    },
    button: {
      flex: 2,
      justifyContent: "center",
      alignItems: "flex-end"
    },
    name: {
      color: "white",
      textShadowColor: "black",
      fontWeight: "bold",
      textShadowOffset: { width: -1, height: 0 },
      textShadowRadius: 5,
      paddingLeft: 2,
      lineHeight: 35,
      marginBottom: 5,
      fontSize: 36
    },
    artist: {
      color: "white",
      textShadowColor: "black",
      textShadowOffset: { width: -1, height: 0 },
      textShadowRadius: 5,
      paddingLeft: 2,
      fontSize: 24,
    },
    description: {
      paddingRight: 20,
      paddingLeft: 2,
      position: "absolute"
    },
    darkOverlay: {
      position: "absolute",
      height: "100%",
      width: "100%",
      backgroundColor: "rgba(0, 0, 0, 0.4)"
    },
    darkerOverlay: {
      position: "absolute",
      height: "100%",
      width: "100%",
      backgroundColor: "rgba(0, 0, 0, 0.6)"
    },
    moreInfoButton: {
      color: "white",
      fontSize: 15,
      elevation: 4,
    },
    moreInfoButtonContainer: {
      backgroundColor: "rgba(56, 56, 56, 0.3)",
      width: 135,
      height: 40,
      borderColor: 'white',
      borderWidth: 2,
      borderRadius: 20,
      alignItems: 'center',
      justifyContent: 'center',
      elevation: 2,
    }
  });
}
<|endoftext|>


<commit_before>
/**
 * Module dependencies.
 */

var express = require('./../../lib/express'),
    connect = require('connect'),
    form = require('connect-form'),
    sys = require('sys');

var app = express.createServer(
    // connect-form (http://github.com/visionmedia/connect-form)
    // middleware uses the formidable middleware to parse urlencoded
    // and multipart form data
    form(),

    // Used for res.redirect()
    connect.redirect()
);

app.get('/', function(req, res){
    res.send('<form method="post" enctype="form-data/multipart">'
        + '
Name: <input type="text" name="name" />
'
        + '
Image: <input type="file" name="image" />
'
        + '
<input type="submit" value="Upload" />
'
        + '</form>');
});

app.post('/', function(req, res){
    // connect-form adds the req.form object
    // we can (optionally) define onComplete, passing
    // the exception (if any) fields parsed, and files parsed
    req.form.onComplete = function(err, fields, files){
        sys.puts(fields.name + ' uploaded ' + files.image.filename);
    };
});

app.listen(3000);<commit_msg>Added progress to multipart example<commit_after>
/**
 * Module dependencies.
 */

var express = require('./../../lib/express'),
    connect = require('connect'),
    form = require('connect-form'),
    sys = require('sys');

var app = express.createServer(
    // connect-form (http://github.com/visionmedia/connect-form)
    // middleware uses the formidable middleware to parse urlencoded
    // and multipart form data
    form(),

    // Used for res.redirect()
    connect.redirect()
);

app.get('/', function(req, res){
    res.send('<form method="post" enctype="form-data/multipart">'
        + '
Image: <input type="file" name="image" />
'
        + '
<input type="submit" value="Upload" />
'
        + '</form>');
});

app.post('/', function(req, res){
    // We can add listeners for several form
    // events such as "progress"
    req.form.addListener('progress', function(bytesReceived, bytesExpected){
        var percent = (bytesReceived / bytesExpected * 100) | 0;
        sys.print('Uploading: %' + percent + '\r');
    });

    // connect-form adds the req.form object
    // we can (optionally) define onComplete, passing
    // the exception (if any) fields parsed, and files parsed
    req.form.onComplete = function(err, fields, files){
        sys.puts('\nuploaded ' + files.image.filename);
    };
});

app.listen(3000);<|endoftext|>


<commit_before>/**
 *
 * @fileoverview Singleton object to handle global Google API operations.
 *
 * This class handles authorization, and loading client libraries.  It provides
 * a global singleton object.
 *
 */

goog.provide('colab.drive.ApiWrapper');

goog.require('colab.app');
goog.require('colab.client_id');
goog.require('colab.error.GapiError');
goog.require('colab.params');
goog.require('colab.scope');
goog.require('goog.Promise');
goog.require('goog.events');
goog.require('goog.ui.Dialog');

/**
 * Handles Google API initialization and authorization.
 * @final @constructor
 */
colab.drive.ApiWrapper = function() {
  var that = this;

  /**
   * Use this until we implement saving into binary format, or else, we will
   * lose all existing content. After saving is implemented, switch to use
   * NEW_CLIENT_ID.
   *
   * @type {string}
   * @const
   */
  this.CLIENT_ID = colab.params.getHashParams().legacyClient ?
      colab.client_id.INSTALL_CLIENT_ID : colab.client_id.DRIVE_CLIENT_ID;

  /** @type {goog.promise.Resolver} */
  this.gapiLoad1 = goog.Promise.withResolver();

  /** @type {goog.Promise} */
  this.clientLoaded = new goog.Promise(function(resolve, reject) {
    that.gapiLoad1.promise.then(function() {
      gapi.load('auth:client,drive-realtime,drive-share', resolve);
    }, reject);
  });

  /**
   * Promise that is fullfilled when the google Drive API is loaded
   * @const {!goog.Promise}
   */
  this.apiLoaded = new goog.Promise(function(resolve, reject) {
    that.clientLoaded.then(function() {
      gapi.client.load('drive', 'v2', resolve);
    }, reject);
  });

  /**
   * A promise that is resolved when the Google Drive auth is done
   * @type {goog.Promise}
   */
  this.authorized = new goog.Promise(function(resolve, reject) {
    if (colab.app.appMode) {
      // In app mode, set auth token that is passed in by postMessage
      var receivedToken = false;
      colab.app.addMessageListener('access_token', function(msgType, content) {
        if (content) {
          gapi.auth.setToken(content);
          if (!receivedToken) {
            // TODO(kestert): Should this be reject?
            resolve(null);
            receivedToken = true;
          }
        }
      });
    } else {
      that.clientLoaded.then(function() {
        // In web mode, use standard OAuth flow.
        that.authorize(/**@type {function()} */ (resolve), reject);
        // Refresh OAuth token every 40 minutes.
        window.setInterval(function() {
          that.authorize(function() {}, function(reason) {
            console.log('failed to refresh OAuth token');
          });
        }, 40 * 60 * 1000);
      });
    }
  });

  /**
   * A promise that is resolved when both authorization and drive API loading
   * is complete.
   * @type {goog.Promise}
   */
  this.driveApiReady = goog.Promise.all([this.apiLoaded, this.authorized]);

  /**
   * @type {gapi.client.plus.PeopleGetResponse}
   */
  this.myInfo = null;

  this.clientLoaded.then(function() {
    gapi.client.load('plus', 'v1', function() {
      that.authorized.then(function() {
        var request = gapi.client.plus.people.get({
          'userId' : 'me'
        });
        request.execute(function(response) {
          that.myInfo =
              /** @type {gapi.client.plus.PeopleGetResponse} */ (response);
        });
      });
    });
  });
};
goog.addSingletonGetter(colab.drive.ApiWrapper);

/**
 * Callback for loading of the google client API script loaded as
 * a script tag in index.html.
 */
colab.drive.ApiWrapper.onClientLoad = function() {
  colab.drive.ApiWrapper.getInstance().gapiLoad1.resolve();
};

goog.exportSymbol('onClientLoad', colab.drive.ApiWrapper.onClientLoad);

/**
 * Authorize using Google OAuth API.
 *
 * @param {function()} onSuccess Callback for success
 * @param {function(colab.error.GapiError!)} onFailure Callback for success
 * @param {boolean=} opt_withPopup If true, display popup without first trying
 *     to authorize without a popup.
 */
colab.drive.ApiWrapper.prototype.authorize = function(onSuccess, onFailure,
    opt_withPopup) {
  var that = this;
  var doAuthorize = function() {
    gapi.auth.authorize({
      'client_id': that.CLIENT_ID,
      'scope': ['email', colab.scope.FILE_SCOPE],
      'immediate': !opt_withPopup
    }, function(response) {
      var error = colab.error.GapiError.fromResponse(response);
      if (error) {
        if (opt_withPopup) {
          onFailure(error);
        } else {
          that.authorize(onSuccess, onFailure, true);
        }
      }

      onSuccess();
    });
  };

  // if no popup, calls the authorization function immediately
  if (!opt_withPopup) {
    doAuthorize();
    return;
  }

  // Gets user to initiate the authorization with a dialog,
  // to prevent popup blockers.
  var dialog = new goog.ui.Dialog();
  dialog.setDisposeOnHide(true);
  dialog.setContent('Click OK to launch the authorization popup window.');
  dialog.setTitle('Authorization Needed');
  dialog.setButtonSet(goog.ui.Dialog.ButtonSet.createOk());

  goog.events.listen(dialog, goog.ui.Dialog.EventType.SELECT, function(e) {
    doAuthorize();
  });
  dialog.setVisible(true);
};
<commit_msg>Adds error dialog if cookies are disabled<commit_after>/**
 *
 * @fileoverview Singleton object to handle global Google API operations.
 *
 * This class handles authorization, and loading client libraries.  It provides
 * a global singleton object.
 *
 */

goog.provide('colab.drive.ApiWrapper');

goog.require('colab.app');
goog.require('colab.client_id');
goog.require('colab.error.GapiError');
goog.require('colab.params');
goog.require('colab.scope');
goog.require('goog.Promise');
goog.require('goog.events');
goog.require('goog.ui.Dialog');

/**
 * Handles Google API initialization and authorization.
 * @final @constructor
 */
colab.drive.ApiWrapper = function() {
  var that = this;

  /**
   * Use this until we implement saving into binary format, or else, we will
   * lose all existing content. After saving is implemented, switch to use
   * NEW_CLIENT_ID.
   *
   * @type {string}
   * @const
   */
  this.CLIENT_ID = colab.params.getHashParams().legacyClient ?
      colab.client_id.INSTALL_CLIENT_ID : colab.client_id.DRIVE_CLIENT_ID;

  /** @type {goog.promise.Resolver} */
  this.gapiLoad1 = goog.Promise.withResolver();

  /** @type {goog.Promise} */
  this.clientLoaded = new goog.Promise(function(resolve, reject) {
    // Don't fullfill promise (or reject) if Cookies are not enabled.
    // instead, show error dialog.
    if (!goog.net.cookies.isEnabled()) {
      var dialog = new goog.ui.Dialog();
      dialog.setTitle('Could not load notebook');
      dialog.setContent('You must have cookies enabled to run coLaboratory');
      dialog.setVisible(true);
      return;
    }
    that.gapiLoad1.promise.then(function() {
      gapi.load('auth:client,drive-realtime,drive-share', resolve);
    }, reject);
  });

  /**
   * Promise that is fullfilled when the google Drive API is loaded
   * @const {!goog.Promise}
   */
  this.apiLoaded = new goog.Promise(function(resolve, reject) {
    that.clientLoaded.then(function() {
      gapi.client.load('drive', 'v2', resolve);
    }, reject);
  });

  /**
   * A promise that is resolved when the Google Drive auth is done
   * @type {goog.Promise}
   */
  this.authorized = new goog.Promise(function(resolve, reject) {
    if (colab.app.appMode) {
      // In app mode, set auth token that is passed in by postMessage
      var receivedToken = false;
      colab.app.addMessageListener('access_token', function(msgType, content) {
        if (content) {
          gapi.auth.setToken(content);
          if (!receivedToken) {
            // TODO(kestert): Should this be reject?
            resolve(null);
            receivedToken = true;
          }
        }
      });
    } else {
      that.clientLoaded.then(function() {
        // In web mode, use standard OAuth flow.
        that.authorize(/**@type {function()} */ (resolve), reject);
        // Refresh OAuth token every 40 minutes.
        window.setInterval(function() {
          that.authorize(function() {}, function(reason) {
            console.log('failed to refresh OAuth token');
          });
        }, 40 * 60 * 1000);
      });
    }
  });

  /**
   * A promise that is resolved when both authorization and drive API loading
   * is complete.
   * @type {goog.Promise}
   */
  this.driveApiReady = goog.Promise.all([this.apiLoaded, this.authorized]);

  /**
   * @type {gapi.client.plus.PeopleGetResponse}
   */
  this.myInfo = null;

  this.clientLoaded.then(function() {
    gapi.client.load('plus', 'v1', function() {
      that.authorized.then(function() {
        var request = gapi.client.plus.people.get({
          'userId' : 'me'
        });
        request.execute(function(response) {
          that.myInfo =
              /** @type {gapi.client.plus.PeopleGetResponse} */ (response);
        });
      });
    });
  });
};
goog.addSingletonGetter(colab.drive.ApiWrapper);

/**
 * Callback for loading of the google client API script loaded as
 * a script tag in index.html.
 */
colab.drive.ApiWrapper.onClientLoad = function() {
  colab.drive.ApiWrapper.getInstance().gapiLoad1.resolve();
};

goog.exportSymbol('onClientLoad', colab.drive.ApiWrapper.onClientLoad);

/**
 * Authorize using Google OAuth API.
 *
 * @param {function()} onSuccess Callback for success
 * @param {function(colab.error.GapiError!)} onFailure Callback for success
 * @param {boolean=} opt_withPopup If true, display popup without first trying
 *     to authorize without a popup.
 */
colab.drive.ApiWrapper.prototype.authorize = function(onSuccess, onFailure,
    opt_withPopup) {
  var that = this;
  var doAuthorize = function() {
    gapi.auth.authorize({
      'client_id': that.CLIENT_ID,
      'scope': ['email', colab.scope.FILE_SCOPE],
      'immediate': !opt_withPopup
    }, function(response) {
      var error = colab.error.GapiError.fromResponse(response);
      if (error) {
        if (opt_withPopup) {
          onFailure(error);
        } else {
          that.authorize(onSuccess, onFailure, true);
        }
      }

      onSuccess();
    });
  };

  // if no popup, calls the authorization function immediately
  if (!opt_withPopup) {
    doAuthorize();
    return;
  }

  // Gets user to initiate the authorization with a dialog,
  // to prevent popup blockers.
  var dialog = new goog.ui.Dialog();
  dialog.setDisposeOnHide(true);
  dialog.setContent('Click OK to launch the authorization popup window.');
  dialog.setTitle('Authorization Needed');
  dialog.setButtonSet(goog.ui.Dialog.ButtonSet.createOk());

  goog.events.listen(dialog, goog.ui.Dialog.EventType.SELECT, function(e) {
    doAuthorize();
  });
  dialog.setVisible(true);
};
<|endoftext|>


<commit_before>
define(["jquery", "util", "session", "elementFinder"],
    function($, util, session, elementFinder){

    var returnMe = util.Module("videos"),
    listeners = {},
    TIME_UPDATE = 'timeupdate',
    MIRRORED_EVENTS = ['play', 'pause'],
    SYNC_CHECK = 4000,
    TOO_FAR_APART = 3000;

    function getEventSender (eventName) {
        return function (event) {
            var element = event.target;
            session.send({
                type: ('video-'+eventName),
                //'this' should refer to the video element grabbed by
                //jquery, but watch out for this
                location: elementFinder.elementLocation(element),
                position: element.currentTime
            });
        }
    };

    function setupMirroredEvents (videos) {
        var currentListener;
        MIRRORED_EVENTS.forEach(function (eventName) {
            currentListener = getEventSender(eventName);
            videos.on(eventName, currentListener);
            listeners[eventName] = currentListener;
        });
    };

    //all clo
    function getTimeUpdater () {
        var last = 0;
        return function (){
            var currentTime = event.target.currentTime;
            if(areTooFarApart(currentTime, last)){
                getEventSender(TIME_UPDATE)(event);
            }
            last = currentTime;
        };
    };

    function setupTimeSync (videos) {
        var onTimeUpdate = getTimeUpdater();
        videos.on(TIME_UPDATE, onTimeUpdate);
        listeners[TIME_UPDATE] = onTimeUpdate;
    };

    function setInit () {
        var videos = $('video');
        setupMirroredEvents(videos);
        setupTimeSync(videos);
    };

    function destroyTrackers () {
        var videos = $('video');
        Object.keys(listeners).forEach(function (eventName) {
            videos.off(eventName, listeners[eventName])
        });
        listeners = {};
    };

    function setTime (video, time) {
        video.prop('currentTime', time);
    }

    function areTooFarApart (currentTime, lastTime) {
        var secDiff = Math.abs(currentTime - lastTime),
        milliDiff = secDiff * 1000;
        return milliDiff > TOO_FAR_APART;
    }

    session.on("reinitialize", setInit);

    session.on("ui-ready", setInit);

    session.on("close", destroyTrackers);

    session.hub.on('video-timeupdate', function (msg) {
        var element = elementFinder.findElement(msg.position),
        onTimeUpdate = listeners[TIME_UPDATE];

        element.off(TIME_UPDATE, onTimeUpdate);
        element.prop('currentTime', msg.position);
        element.on(TIME_UPDATE, onTimeUpdate);
    })

    MIRRORED_EVENTS.forEach( function (eventName) {
        session.hub.on("video-"+eventName, function (msg) {
            var element = elementFinder.findElement(msg.location);
            setTime(element, msg.position);
            //this will cause an infinite loop, need to
            //use event maker to dispatch a custom event
            element.trigger(eventName);
        });
    })

    return returnMe;

})
<commit_msg>probably resolved potential event loop issues<commit_after>
define(["jquery", "util", "session", "elementFinder"],
    function($, util, session, elementFinder){

    var returnMe = util.Module("videos"),
    listeners = {},
    TIME_UPDATE = 'timeupdate',
    MIRRORED_EVENTS = ['play', 'pause'],
    SYNC_CHECK = 4000,
    TOO_FAR_APART = 3000;

    function getEventSender (eventName) {
        return function (event) {
            var element = event.target;
            session.send({
                type: ('video-'+eventName),
                //'this' should refer to the video element grabbed by
                //jquery, but watch out for this
                location: elementFinder.elementLocation(element),
                position: element.currentTime
            });
        }
    };

    function setupMirroredEvents (videos) {
        var currentListener;
        MIRRORED_EVENTS.forEach(function (eventName) {
            currentListener = getEventSender(eventName);
            videos.on(eventName, currentListener);
            listeners[eventName] = currentListener;
        });
    };

    //all clo
    function getTimeUpdater () {
        var last = 0;
        return function (){
            var currentTime = event.target.currentTime;
            if(areTooFarApart(currentTime, last)){
                getEventSender(TIME_UPDATE)(event);
            }
            last = currentTime;
        };
    };

    function setupTimeSync (videos) {
        var onTimeUpdate = getTimeUpdater();
        videos.on(TIME_UPDATE, onTimeUpdate);
        listeners[TIME_UPDATE] = onTimeUpdate;
    };

    function setInit () {
        var videos = $('video');
        setupMirroredEvents(videos);
        setupTimeSync(videos);
    };

    function destroyTrackers () {
        var videos = $('video');
        Object.keys(listeners).forEach(function (eventName) {
            videos.off(eventName, listeners[eventName])
        });
        listeners = {};
    };

    function setTime (video, time) {
        video.prop('currentTime', time);
    }

    function areTooFarApart (currentTime, lastTime) {
        var secDiff = Math.abs(currentTime - lastTime),
        milliDiff = secDiff * 1000;
        return milliDiff > TOO_FAR_APART;
    }

    session.on("reinitialize", setInit);

    session.on("ui-ready", setInit);

    session.on("close", destroyTrackers);

    session.hub.on('video-timeupdate', function (msg) {
        var element = elementFinder.findElement(msg.position),
        onTimeUpdate = listeners[TIME_UPDATE],
        oldTime = element.prop('currentTime'),
        newTime = msg.position;

        //to help throttle uneccesary position changes
        if areTooFarApart(oldTime, newTime){
            element.prop('currentTime', msg.position);
        };
    })

    MIRRORED_EVENTS.forEach( function (eventName) {
        session.hub.on("video-"+eventName, function (msg) {
            var element = elementFinder.findElement(msg.location),
            state = lookupState(msg);
            setTime(element, msg.position);
            //UI tested in chromium:
            //this won't trigger an infinite event loop
            element.trigger(eventName);
        });
    })

    return returnMe;

})
<|endoftext|>