<commit_before>var fs = require('fs');
var extend = require('extend');
var util = require('../util');
var mime = require('mime');
var qs = require('querystring');
var Buffer = require('safe-buffer').Buffer;
var PassThrough = require('stream').PassThrough;
var protoMgr = require('../rules/protocols');
var CRLF_RE = /\r\n|\r|\n/g;
var RAW_FILE_RE = /rawfile/;
var HEADERS_SEP_RE = /(\r?\n(?:\r\n|\r|\n)|\r\r\n?)/;
var MAX_HEADERS_SIZE = 256 * 1024;
var TPL_RE = /(?:dust|tpl|jsonp):$/;

function isTplProtocol(protocol) {
  return TPL_RE.test(protocol);
}

function isRawFileProtocol(protocol) {
  return RAW_FILE_RE.test(protocol);
}

function readFiles(files, callback) {
  var file = files.shift();
  var execCallback = function(err, stat) {
    if(!err && stat && stat.isFile()) {
      callback(null, file, stat.size);
    } else if (files.length) {
      readFiles(files, callback);
    } else {
      callback(err || new Error('Not found file ' + file), file);
    }
  };

  !file || typeof file != 'string' ? execCallback() : fs.stat(file, execCallback);
}

function parseRes(str, rawHeaderNames) {
  if (!str) {
    return {
      statusCode: 200,
      headers: {}
    };
  }
  var headers = str.split(CRLF_RE);
  var statusLine = headers.shift().trim().split(/\s+/g);
  return {
    statusCode: statusLine[1] || 200,
    headers: util.parseHeaders(headers, rawHeaderNames)
  };
}

function getRawResByValue(body) {
  var headers;
  if (HEADERS_SEP_RE.test(body)) {
    var crlfStr = RegExp.$1;
    var index = body.indexOf(crlfStr);
    headers = body.substring(0, index);
    body = body.substring(index + crlfStr.length);
  }
  var rawHeaderNames = {};
  var reader = parseRes(headers, rawHeaderNames);
  reader.rawHeaderNames = rawHeaderNames;
  reader.body = body;
  return reader;
}

function getRawResByPath(protocol, path, req, callback) {
  var isRawFile = isRawFileProtocol(protocol);
  var range = isRawFile ? undefined : util.parseRange(req, req.localFileSize);
  var reader = fs.createReadStream(path, range);
  var rawHeaderNames = reader.rawHeaderNames = rawHeaderNames;
  if (isRawFile) {
    var buffer;
    var response = function(err, crlf) {
      reader.removeAllListeners('data');
      reader.removeAllListeners('error');
      reader.removeAllListeners('end');
      var stream = reader;
      reader = new PassThrough();
      if (err) {
        reader.statusCode = 500;
        reader.push(err.stack);
        reader.push(null);
      } else {
        if (crlf) {
          crlf = util.toBuffer(crlf);
          var index = util.indexOfList(buffer, crlf);
          if (index != -1) {
            extend(reader, parseRes(buffer.slice(0, index) + '', rawHeaderNames));
            buffer = buffer.slice(index + crlf.length);
          }
        }
        buffer && reader.push(buffer);
        stream.on('error', function(err) {
          reader.emit('error', err);
        });
        stream.pipe(reader);
      }
      callback(reader);
    };

    reader.on('data', function(data) {
      buffer = buffer ? Buffer.concat([buffer, data]) : data;
      if (HEADERS_SEP_RE.test(buffer + '')) {
        response(null, RegExp.$1);
      } else if (buffer.length > MAX_HEADERS_SIZE) {
        response();
      }
    });
    reader.on('error', response);
    reader.on('end', response);
  } else {
    callback(reader, range);
  }
}

function addRangeHeaders(res, range, size) {
  if (!range) {
    return;
  }
  var headers = res.headers;
  headers['content-range'] = 'bytes ' + (range.start + '-' + range.end) + '/' + size;
  headers['accept-ranges'] = 'bytes';
  headers['content-length'] = range.end - range.start + 1;
  res.statusCode = 206;
}

module.exports = function(req, res, next) {
  var options = req.options;
  var config = this.config;
  var protocol = options && options.protocol;
  if (!protoMgr.isFileProxy(protocol)) {
    return next();
  }
  var defaultType = mime.lookup(req.fullUrl.replace(/[?#].*$/, ''), 'text/html');
  var rule = req.rules.rule;
  if (rule.value) {
    var body = util.removeProtocol(rule.value, true);
    var isRawFile = isRawFileProtocol(protocol);
    var reader = isRawFile ? getRawResByValue(body) : {
      statusCode: 200,
      body: body,
      headers: {
        'content-type': (rule.key ? mime.lookup(rule.key, defaultType) : defaultType) + '; charset=utf-8'
      }
    };

    if (isTplProtocol(protocol)){
      reader.realUrl = rule.matcher;
      render(reader);
    } else {
      if (!isRawFile) {
        var size = Buffer.byteLength(body);
        var range = util.parseRange(req, size);
        if (range) {
          body = Buffer.from(body);
          reader.body = body.slice(range.start, range.end + 1);
        }
        addRangeHeaders(reader, range, size);
      }
      reader = util.wrapResponse(reader);
      reader.realUrl = rule.matcher;
      res.response(reader);
    }
    return;
  }

  readFiles(util.getRuleFiles(rule), function(err, path, size) {
    if (err) {
      if (/^x/.test(protocol)) {
        var fullUrl = /^xs/.test(protocol) ? req.fullUrl.replace(/^http:/, 'https:') : req.fullUrl;
        extend(options, util.parseUrl(fullUrl));
        next();
      } else {
        var notFound = util.wrapResponse({
          statusCode: 404,
          body: 'Not found file ' + path + '',
          headers: {
            'content-type': 'text/html; charset=utf-8'
          }
        });
        notFound.realUrl = path;
        res.response(notFound);
      }
      return;
    }

    var headers = {
      'server': config.name,
      'content-type': mime.lookup(path, defaultType) + '; charset=utf-8'
    };

    if (isTplProtocol(protocol)) {
      var reader = {
        statusCode: 200,
        realUrl: path,
        headers: headers
      };
      fs.readFile(path, {encoding: 'utf8'}, function(err, data) {
        if (err) {
          return util.emitError(req, err);
        }
        reader.body = data;
        render(reader);
      });
    } else {
      req.localFileSize = size;
      getRawResByPath(protocol, path, req, function(reader, range) {
        reader.realUrl = path;
        reader.statusCode = reader.statusCode || 200;
        reader.headers = reader.headers || headers;
        addRangeHeaders(reader, range, size);
        res.response(reader);
      });
    }
  });

  function render(reader) {
    if (reader.body) {
      var data = qs.parse(util.getQueryString(req.fullUrl));
      if (Object.keys(data).length) {
        reader.body = reader.body.replace(/\$?\{([\w\-$]+)\}/g, function(all, matched) {
          var value = data[matched];
          if (value === undefined) {
            return all;
          }
          return util.getQueryValue(value);
        });
      }
    }
    var realUrl = reader.realUrl;
    reader = util.wrapResponse(reader);
    reader.realUrl = realUrl;
    res.response(reader);
  }
};
<commit_msg>feat: supports response `206 Partial Content` in Map Local<commit_after>var fs = require('fs');
var extend = require('extend');
var util = require('../util');
var mime = require('mime');
var qs = require('querystring');
var Buffer = require('safe-buffer').Buffer;
var PassThrough = require('stream').PassThrough;
var protoMgr = require('../rules/protocols');
var CRLF_RE = /\r\n|\r|\n/g;
var RAW_FILE_RE = /rawfile/;
var HEADERS_SEP_RE = /(\r?\n(?:\r\n|\r|\n)|\r\r\n?)/;
var MAX_HEADERS_SIZE = 256 * 1024;
var TPL_RE = /(?:dust|tpl|jsonp):$/;

function isTplProtocol(protocol) {
  return TPL_RE.test(protocol);
}

function isRawFileProtocol(protocol) {
  return RAW_FILE_RE.test(protocol);
}

function readFiles(files, callback) {
  var file = files.shift();
  var execCallback = function(err, stat) {
    if(!err && stat && stat.isFile()) {
      callback(null, file, stat.size);
    } else if (files.length) {
      readFiles(files, callback);
    } else {
      callback(err || new Error('Not found file ' + file), file);
    }
  };

  !file || typeof file != 'string' ? execCallback() : fs.stat(file, execCallback);
}

function parseRes(str, rawHeaderNames) {
  if (!str) {
    return {
      statusCode: 200,
      headers: {}
    };
  }
  var headers = str.split(CRLF_RE);
  var statusLine = headers.shift().trim().split(/\s+/g);
  return {
    statusCode: statusLine[1] || 200,
    headers: util.parseHeaders(headers, rawHeaderNames)
  };
}

function getRawResByValue(body) {
  var headers;
  if (HEADERS_SEP_RE.test(body)) {
    var crlfStr = RegExp.$1;
    var index = body.indexOf(crlfStr);
    headers = body.substring(0, index);
    body = body.substring(index + crlfStr.length);
  }
  var rawHeaderNames = {};
  var reader = parseRes(headers, rawHeaderNames);
  reader.rawHeaderNames = rawHeaderNames;
  reader.body = body;
  return reader;
}

function getRawResByPath(protocol, path, req, callback) {
  var isRawFile = isRawFileProtocol(protocol);
  var range = isRawFile ? undefined : util.parseRange(req, req.localFileSize);
  var reader = fs.createReadStream(path, range);
  var rawHeaderNames = reader.rawHeaderNames = rawHeaderNames;
  if (isRawFile) {
    var buffer;
    var response = function(err, crlf) {
      reader.removeAllListeners('data');
      reader.removeAllListeners('error');
      reader.removeAllListeners('end');
      var stream = reader;
      reader = new PassThrough();
      if (err) {
        reader.statusCode = 500;
        reader.push(err.stack);
        reader.push(null);
      } else {
        if (crlf) {
          crlf = util.toBuffer(crlf);
          var index = util.indexOfList(buffer, crlf);
          if (index != -1) {
            extend(reader, parseRes(buffer.slice(0, index) + '', rawHeaderNames));
            buffer = buffer.slice(index + crlf.length);
          }
        }
        buffer && reader.push(buffer);
        stream.on('error', function(err) {
          reader.emit('error', err);
        });
        stream.pipe(reader);
      }
      callback(reader);
    };

    reader.on('data', function(data) {
      buffer = buffer ? Buffer.concat([buffer, data]) : data;
      if (HEADERS_SEP_RE.test(buffer + '')) {
        response(null, RegExp.$1);
      } else if (buffer.length > MAX_HEADERS_SIZE) {
        response();
      }
    });
    reader.on('error', response);
    reader.on('end', response);
  } else {
    callback(reader, range);
  }
}

function addRangeHeaders(res, range, size) {
  if (!range) {
    return;
  }
  var headers = res.headers;
  headers['content-range'] = 'bytes ' + (range.start + '-' + range.end) + '/' + size;
  headers['accept-ranges'] = 'bytes';
  headers['content-length'] = range.end - range.start + 1;
  res.statusCode = 206;
}

module.exports = function(req, res, next) {
  var options = req.options;
  var config = this.config;
  var protocol = options && options.protocol;
  if (!protoMgr.isFileProxy(protocol)) {
    return next();
  }
  var defaultType = mime.lookup(req.fullUrl.replace(/[?#].*$/, ''), 'text/html');
  var rule = req.rules.rule;
  if (rule.value) {
    var body = util.removeProtocol(rule.value, true);
    var isRawFile = isRawFileProtocol(protocol);
    var reader = isRawFile ? getRawResByValue(body) : {
      statusCode: 200,
      body: body,
      headers: {
        'content-type': (rule.key ? mime.lookup(rule.key, defaultType) : defaultType) + '; charset=utf-8'
      }
    };

    if (isTplProtocol(protocol)){
      reader.realUrl = rule.matcher;
      render(reader);
    } else {
      if (!isRawFile) {
        var size = Buffer.byteLength(body);
        var range = util.parseRange(req, size);
        if (range) {
          body = Buffer.from(body);
          reader.body = body.slice(range.start, range.end + 1);
          addRangeHeaders(reader, range, size);
        }
      }
      reader = util.wrapResponse(reader);
      reader.realUrl = rule.matcher;
      res.response(reader);
    }
    return;
  }

  readFiles(util.getRuleFiles(rule), function(err, path, size) {
    if (err) {
      if (/^x/.test(protocol)) {
        var fullUrl = /^xs/.test(protocol) ? req.fullUrl.replace(/^http:/, 'https:') : req.fullUrl;
        extend(options, util.parseUrl(fullUrl));
        next();
      } else {
        var notFound = util.wrapResponse({
          statusCode: 404,
          body: 'Not found file ' + path + '',
          headers: {
            'content-type': 'text/html; charset=utf-8'
          }
        });
        notFound.realUrl = path;
        res.response(notFound);
      }
      return;
    }

    var headers = {
      'server': config.name,
      'content-type': mime.lookup(path, defaultType) + '; charset=utf-8'
    };

    if (isTplProtocol(protocol)) {
      var reader = {
        statusCode: 200,
        realUrl: path,
        headers: headers
      };
      fs.readFile(path, {encoding: 'utf8'}, function(err, data) {
        if (err) {
          return util.emitError(req, err);
        }
        reader.body = data;
        render(reader);
      });
    } else {
      req.localFileSize = size;
      getRawResByPath(protocol, path, req, function(reader, range) {
        reader.realUrl = path;
        reader.statusCode = reader.statusCode || 200;
        reader.headers = reader.headers || headers;
        addRangeHeaders(reader, range, size);
        res.response(reader);
      });
    }
  });

  function render(reader) {
    if (reader.body) {
      var data = qs.parse(util.getQueryString(req.fullUrl));
      if (Object.keys(data).length) {
        reader.body = reader.body.replace(/\$?\{([\w\-$]+)\}/g, function(all, matched) {
          var value = data[matched];
          if (value === undefined) {
            return all;
          }
          return util.getQueryValue(value);
        });
      }
    }
    var realUrl = reader.realUrl;
    reader = util.wrapResponse(reader);
    reader.realUrl = realUrl;
    res.response(reader);
  }
};
<|endoftext|>


<commit_before><commit_msg>remove express and socket.io<commit_after><|endoftext|>


<commit_before>var fs = require('fs');
var extend = require('util')._extend;
var util = require('../../util');
var url = require('url');
var mime = require('mime');
var rules = require('../rules');
var querystring = require('querystring');

function decodePath(path) {
	try {
		return decodeURIComponent(path);
	 } catch (e) {}

	return QueryString.unescape(path);
}

function readFiles(files, callback) {
	var file = files.shift();
	var execCallback = function(err, stat) {
		 if(!err && stat && stat.isFile()) {
			 callback(null, file);
		 } else if (files.length) {
			 readFiles(files, callback);
		 }  else {
			 callback(err || new Error('Not found file ' + file), file);
		 }
	};

	!file ||typeof file != 'string' ? execCallback() : fs.stat(file, execCallback);
}

module.exports = function(req, res, next) {
	var options = req.options;
	var config = this.config;
	var protocol = options && options.protocol;
	if (!/^(?:|x|xs)(?:file|dust|tpl|jsonp):$/.test(protocol)) {
		next();
		return;
	}
	var rule = req.rules.rule;
	if (rule.value) {
		util.drain(req, function() {
			var key = rule.key;
			var reader = {
					statusCode: 200,
					body: util.removeProtocol(rule.value, true),
					headers: {
					    	'content-type': (key ? mime.lookup(key) : 'text/html') + '; charset=utf-8'
					    }
			};

		    if (/(?:dust|tpl|jsonp):$/.test(protocol)){
		    	render(reader);
		    } else {
		    	res.response(util.wrapResponse(reader));
		    }
		});
		return;
	}

	var files = rule.files || [util.getPath(util.rule.getUrl(rule))];
	files = files.map(function(file) {
		return decodePath(file);
	});

	readFiles(files, function(err, path) {
		if (err) {
	    	if (/^x/.test(protocol)) {
				  extend(options, url.parse(/^xs/.test(protocol) ? req.fullUrl.replace(/^http:/, 'https:') : req.fullUrl));
				  next();
			  } else {
				  res.response(util.wrapResponse({
						statusCode: 404,
						body: 'Not found file ' + path + '',
						headers: {
						    	'content-type': 'text/html; charset=utf-8'
						    }
				}));
			  }
	    	return;
	    }

	    util.drain(req, function() {
	    	var reader = fs.createReadStream(path);
		    reader.statusCode = 200;
		    reader.realUrl = path;
		    reader.headers = {
		    		'server': config.name,
			    	'content-type': mime.lookup(path) + '; charset=utf-8'
			    };

		    if (/(?:dust|tpl|jsonp):$/.test(protocol)) {
		    	var content = '';
		    	reader.setEncoding('utf8');
		    	reader.on('data', function(data) {
		    		content += data;
		    	});
		    	reader.on('end', function() {
		    		reader.body = content;
		    		render(reader);
		    	});

		    	reader.on('error', function(err) {
		    		util.emitError(req, err);
		    	});
		    } else {
		    	res.response(reader);
		    }
	    });

	});

	function render(reader) {
		if (reader.body) {
			var index = req.url.indexOf('?') + 1;
			index = index > 0 && req.url.substring(index).replace(/#.*$/, '');
			var data = index && querystring.parse(index);
			if (data) {
				reader.body = reader.body.replace(/\{([\w\-$]+)\}/g, function(all, matched) {
					return matched in data ? data[matched] : all;
				});
			}
		}
		var realUrl = reader.realUrl;
		reader = util.wrapResponse(reader);
		reader.realUrl = realUrl;
		res.response(reader);
	}
};<commit_msg>file path<commit_after>var fs = require('fs');
var extend = require('util')._extend;
var util = require('../../util');
var url = require('url');
var mime = require('mime');
var rules = require('../rules');
var querystring = require('querystring');

function decodePath(path) {
	path = path.replace(/[?#].*$/, '');
	try {
		return decodeURIComponent(path);
	 } catch (e) {}

	return QueryString.unescape(path);
}

function readFiles(files, callback) {
	var file = files.shift();
	var execCallback = function(err, stat) {
		 if(!err && stat && stat.isFile()) {
			 callback(null, file);
		 } else if (files.length) {
			 readFiles(files, callback);
		 }  else {
			 callback(err || new Error('Not found file ' + file), file);
		 }
	};

	!file ||typeof file != 'string' ? execCallback() : fs.stat(file, execCallback);
}

module.exports = function(req, res, next) {
	var options = req.options;
	var config = this.config;
	var protocol = options && options.protocol;
	if (!/^(?:|x|xs)(?:file|dust|tpl|jsonp):$/.test(protocol)) {
		next();
		return;
	}
	var rule = req.rules.rule;
	if (rule.value) {
		util.drain(req, function() {
			var key = rule.key;
			var reader = {
					statusCode: 200,
					body: util.removeProtocol(rule.value, true),
					headers: {
					    	'content-type': (key ? mime.lookup(key) : 'text/html') + '; charset=utf-8'
					    }
			};

		    if (/(?:dust|tpl|jsonp):$/.test(protocol)){
		    	render(reader);
		    } else {
		    	res.response(util.wrapResponse(reader));
		    }
		});
		return;
	}

	var files = rule.files || [util.getPath(util.rule.getUrl(rule))];
	files = files.map(function(file) {
		return decodePath(file);
	});

	readFiles(files, function(err, path) {
		if (err) {
	    	if (/^x/.test(protocol)) {
				  extend(options, url.parse(/^xs/.test(protocol) ? req.fullUrl.replace(/^http:/, 'https:') : req.fullUrl));
				  next();
			  } else {
				  res.response(util.wrapResponse({
						statusCode: 404,
						body: 'Not found file ' + path + '',
						headers: {
						    	'content-type': 'text/html; charset=utf-8'
						    }
				}));
			  }
	    	return;
	    }

	    util.drain(req, function() {
	    	var reader = fs.createReadStream(path);
		    reader.statusCode = 200;
		    reader.realUrl = path;
		    reader.headers = {
		    		'server': config.name,
			    	'content-type': mime.lookup(path) + '; charset=utf-8'
			    };

		    if (/(?:dust|tpl|jsonp):$/.test(protocol)) {
		    	var content = '';
		    	reader.setEncoding('utf8');
		    	reader.on('data', function(data) {
		    		content += data;
		    	});
		    	reader.on('end', function() {
		    		reader.body = content;
		    		render(reader);
		    	});

		    	reader.on('error', function(err) {
		    		util.emitError(req, err);
		    	});
		    } else {
		    	res.response(reader);
		    }
	    });

	});

	function render(reader) {
		if (reader.body) {
			var index = req.url.indexOf('?') + 1;
			index = index > 0 && req.url.substring(index).replace(/#.*$/, '');
			var data = index && querystring.parse(index);
			if (data) {
				reader.body = reader.body.replace(/\{([\w\-$]+)\}/g, function(all, matched) {
					return matched in data ? data[matched] : all;
				});
			}
		}
		var realUrl = reader.realUrl;
		reader = util.wrapResponse(reader);
		reader.realUrl = realUrl;
		res.response(reader);
	}
};<|endoftext|>


<commit_before>/*
 * Jquery Ajax Paginator Plugin
 * @requires jQuery 1.3 or later
 * @requires jQuery Address Plugin v1.4 http://www.asual.com/jquery/address/
 *
 */
(function($){
/*
 * Example of usage:

    $('.ajax-pagination').ajaxPaginator({
        container: $('.watch-page-content'),
        onPageChange: function(page, callback){
            VideosApi.load_watch_page(page, function(data){
                this.options.container.html(data.content || '');
                callback.call(this, data);
            }, this);
        },
    });

 *  For more information see options.
 */

 $.widget("unisub.ajaxPaginator", {
     prevLink: null,
     nextLink: null,
     fromValueNode: null,
     toValueNode: null,
     totalValueNode: null,
     pageInfoNode: null,
     loadingIndicator: null,
     container: null,

     page: 1, //current page
     pages: null,  //total number of pages. Can be empty on page load, when we don't know have many pages have
     timeoutId: null, //callback timer ID

     options: {
         pages: null,
         prevLink: '.pag_prev',
         nextLink: '.pag_next',
         pageInfoNode: '.page-info',
         loadingIndicator: '.loading-indicator',
         fromValueNode: '.from-value',
         toValueNode: '.to-value',
         totalValueNode: '.total-value',
         container: null,

         //null - for scrolling to container, false - not scroll,
         //'top' - to page top, or some other jQuery node
         scrollTo: null,
         scrollSpeed: 500,
         scrollOffset: -10,

         onPageChange: function(page, callback){
             /*
              * This method get page number and should load/change page content.
              * Callback should be executed with changed metadata in format:
              * {
              *     total: <int>,
              *     pages: <int>,
              *     from: <int>,
              *     to: <int>
              * }
              */
         }
     },

     _create: function() {
         var elements = ['prevLink', 'nextLink', 'fromValueNode', 'toValueNode',
            'pageInfoNode', 'totalValueNode', 'loadingIndicator'];

         for (var i=elements.length; i--;){
             var name = elements[i];
             if (typeof this.options[name] == 'string'){
                 this[name] = $(this.options[name], this.element);
             }else{
                 this[name] = this.options[name];
             }
         };
         //I just hate this.options, so like add them to this
         this.pages = this.options.pages;
         this.onPageChange = this.options.onPageChange;
         this.container = this.options.container;
     },
     _init: function(){
         var page = $.address.parameter('page')-0;
         page = page || this.page;
         this.setPage(page);

         var that = this;

         this.prevLink.click(function(){
             that._onPrevClick.apply(that, arguments);
             return false;
         });

         this.nextLink.click(function(){
             that._onNextClick.apply(that, arguments);
             return false;
         });

         $.address.change(function(){
             that._onAdressChange.apply(that, arguments);
         });
     },
     _onAdressChange: function(event){
         var page = event.parameters.page-0;
         if (page && page !== this.page){
             this.setPage(page);
         }
     },
     _onNextClick: function(){
         if (this.pages && this.page < this.pages){
             this.setPage(this.page + 1);
         }
     },
     _onPrevClick: function(){
         if (this.page > 1){
            this.setPage(this.page - 1);
         }
     },
     updateContent: function(data){
        var $c = this.container;

        //fix Chrome page jumping
        $.browser.webkit && $c.css('height', $c.height()+'px');

        $c.html(data.content || '');

        //fix Chrome page jumping
        if ($.browser.webkit) {
            setTimeout(function(){
                $c.css('height', $c.children().height()+'px');
            }, 1);
        };
     },
     scrollAfterUpdate: function(data){
         var speed = $.address.parameter('speed')-0 || this.options.scrollSpeed;

         if ($.address.parameter('top') || this.options.scrollTo === 'top'){
             if (speed==1){
                 $('html, body').scrollTop(0);
                 $.jGrowl('Instance scroll to the TOP');
             }else{
                 $('html, body').animate({scrollTop: 0}, speed);
                 $.jGrowl('Scrool to TOP with for '+speed+'ms');
             }
         }else if(this.options.scrollTo !== false){
             if (this.options.scrollTo){
                 var offset = this.options.scrollTo.offset().top + this.options.scrollOffset;
             }else{
                 var offset = this.container.offset().top + this.options.scrollOffset;
             }
             if (speed==1){
                 $('html, body').scrollTop(offset);
                 $.jGrowl('Instance scroll to the CONTAINER TOP');
             }else{
                 $('html, body').animate({scrollTop: offset}, speed);
                 $.jGrowl('Scrool to CONTAINER TOP with for '+speed+'ms');
             }
         }
     },
     _pageLoadCallback: function(data){
         /*
          * This function is executed after page loading and update
          * metadata
          */
         data.total && this.totalValueNode.html(data.total);
         data.from && this.fromValueNode.html(data.from);
         data.to && this.toValueNode.html(data.to);
         data.pages && this.setPages(data.pages);

         this.updateContent(data);
         this.hideLoading();
         this.scrollAfterUpdate(data);
     },
     _checkNavigationLinks: function(){
         if (this.page == 1){
             this.prevLink.hide();
         }else{
             this.prevLink.show();
         };

         if ( ! this.pages || this.page == this.pages){
             this.nextLink.hide();
         }else{
             this.nextLink.show();
         };
     },
     showLoading: function(){
         this.pageInfoNode.hide();
         this.loadingIndicator.show();
         this.container.css('opacity', '0.4');
     },
     hideLoading: function(){
         this.loadingIndicator.hide();
         this.pageInfoNode.show();
         this.container.css('opacity', '');
     },
     setPages: function(pages){
         /*
          * This is set from server after page loading.
          * So number of pages can change and we should check if current
          * page number is still valid.
          * We may not reload data, because server will return last
          * page if we send to large page number.
          */
         this.pages = pages;

         if (this.pages && this.page > this.pages){
             this.page = this.pages;
         };
         this._checkNavigationLinks();
     },
     setPage: function(page){
         //check if page number is valid
         if (page <= 0){
             page = 1;
         };

         if (this.pages && page > this.pages){
             page = this.pages;
         }

         this.page = page;

         //hide/show navigation links
         this._checkNavigationLinks();

         //change URL
         if (page != 1 || $.address.parameter('page')){
             $.address.parameter('page', page);
         }

         //init timedout callback for page loading
         //this is for more quickly navigation, so we can quickly change
         //few pages without waiting for loading
         if (this.timeoutId){
             clearTimeout(this.timeoutId);
             this.timeoutId = null;
         };
         var that = this;
         this.timeoutId = setTimeout(function(){
             that.showLoading();
             that.onPageChange(that.page, that._pageLoadCallback);
         }, 300);
     }
 });

})(jQuery);
<commit_msg>fix page scrolling for AJAX-pagintion<commit_after>/*
 * Jquery Ajax Paginator Plugin
 * @requires jQuery 1.3 or later
 * @requires jQuery Address Plugin v1.4 http://www.asual.com/jquery/address/
 *
 */
(function($){
/*
 * Example of usage:

    $('.ajax-pagination').ajaxPaginator({
        container: $('.watch-page-content'),
        onPageChange: function(page, callback){
            VideosApi.load_watch_page(page, function(data){
                this.options.container.html(data.content || '');
                callback.call(this, data);
            }, this);
        },
    });

 *  For more information see options.
 */

 $.widget("unisub.ajaxPaginator", {
     prevLink: null,
     nextLink: null,
     fromValueNode: null,
     toValueNode: null,
     totalValueNode: null,
     pageInfoNode: null,
     loadingIndicator: null,
     container: null,

     page: 1, //current page
     pages: null,  //total number of pages. Can be empty on page load, when we don't know have many pages have
     timeoutId: null, //callback timer ID

     options: {
         pages: null,
         prevLink: '.pag_prev',
         nextLink: '.pag_next',
         pageInfoNode: '.page-info',
         loadingIndicator: '.loading-indicator',
         fromValueNode: '.from-value',
         toValueNode: '.to-value',
         totalValueNode: '.total-value',
         container: null,

         //null - for scrolling to container, false - not scroll,
         //'top' - to page top, or some other jQuery node
         scrollTo: null,
         scrollSpeed: 500,
         scrollOffset: -10,

         onPageChange: function(page, callback){
             /*
              * This method get page number and should load/change page content.
              * Callback should be executed with changed metadata in format:
              * {
              *     total: <int>,
              *     pages: <int>,
              *     from: <int>,
              *     to: <int>
              * }
              */
         }
     },

     _create: function() {
         var elements = ['prevLink', 'nextLink', 'fromValueNode', 'toValueNode',
            'pageInfoNode', 'totalValueNode', 'loadingIndicator'];

         for (var i=elements.length; i--;){
             var name = elements[i];
             if (typeof this.options[name] == 'string'){
                 this[name] = $(this.options[name], this.element);
             }else{
                 this[name] = this.options[name];
             }
         };
         //I just hate this.options, so like add them to this
         this.pages = this.options.pages;
         this.onPageChange = this.options.onPageChange;
         this.container = this.options.container;
     },
     _init: function(){
         var page = $.address.parameter('page')-0;
         page = page || this.page;
         this.setPage(page, true);

         var that = this;

         this.prevLink.click(function(){
             that._onPrevClick.apply(that, arguments);
             return false;
         });

         this.nextLink.click(function(){
             that._onNextClick.apply(that, arguments);
             return false;
         });

         $.address.change(function(){
             that._onAdressChange.apply(that, arguments);
         });
     },
     _onAdressChange: function(event){
         var page = event.parameters.page-0;
         if (page && page !== this.page){
             this.setPage(page, true);
         }
     },
     _onNextClick: function(){
         if (this.pages && this.page < this.pages){
             this.setPage(this.page + 1);
         }
     },
     _onPrevClick: function(){
         if (this.page > 1){
            this.setPage(this.page - 1);
         }
     },
     _createDelegate: function(func, args, scope){
         return function(){
             callArgs = Array.prototype.slice.call(arguments, 0);
             callArgs = callArgs.concat(args);
             return func.apply(scope || window, callArgs);
         }
     },
     updateContent: function(data){
        var $c = this.container;

        //fix Chrome page jumping
        $.browser.webkit && $c.css('height', $c.height()+'px');

        $c.html(data.content || '');

        //fix Chrome page jumping
        if ($.browser.webkit) {
            setTimeout(function(){
                $c.css('height', $c.children().height()+'px');
            }, 1);
        };
     },
     scrollAfterUpdate: function(data, likeReload){
         var speed = $.address.parameter('speed')-0 || this.options.scrollSpeed;

         if ($.address.parameter('top') || this.options.scrollTo === 'top' || likeReload){
             if (speed == 1 || likeReload){
                 $('html, body').scrollTop(0);
                 $.jGrowl('Instance scroll to the TOP');
             }else{
                 $('html, body').animate({scrollTop: 0}, speed);
                 $.jGrowl('Scrool to TOP with for '+speed+'ms');
             }
         }else if(this.options.scrollTo !== false){
             if (this.options.scrollTo){
                 var offset = this.options.scrollTo.offset().top + this.options.scrollOffset;
             }else{
                 var offset = this.container.offset().top + this.options.scrollOffset;
             }
             if (speed==1){
                 $('html, body').scrollTop(offset);
                 $.jGrowl('Instance scroll to the CONTAINER TOP');
             }else{
                 $('html, body').animate({scrollTop: offset}, speed);
                 $.jGrowl('Scrool to CONTAINER TOP with for '+speed+'ms');
             }
         }
     },
     _pageLoadCallback: function(data, likeReload){
         /*
          * This function is executed after page loading and update
          * metadata
          */
         data.total && this.totalValueNode.html(data.total);
         data.from && this.fromValueNode.html(data.from);
         data.to && this.toValueNode.html(data.to);
         data.pages && this.setPages(data.pages);

         this.updateContent(data, likeReload);
         this.hideLoading(data, likeReload);
         this.scrollAfterUpdate(data, likeReload);
     },
     _checkNavigationLinks: function(){
         if (this.page == 1){
             this.prevLink.hide();
         }else{
             this.prevLink.show();
         };

         if ( ! this.pages || this.page == this.pages){
             this.nextLink.hide();
         }else{
             this.nextLink.show();
         };
     },
     showLoading: function(){
         this.pageInfoNode.hide();
         this.loadingIndicator.show();
         this.container.css('opacity', '0.4');
     },
     hideLoading: function(){
         this.loadingIndicator.hide();
         this.pageInfoNode.show();
         this.container.css('opacity', '');
     },
     setPages: function(pages){
         /*
          * This is set from server after page loading.
          * So number of pages can change and we should check if current
          * page number is still valid.
          * We may not reload data, because server will return last
          * page if we send to large page number.
          */
         this.pages = pages;

         if (this.pages && this.page > this.pages){
             this.page = this.pages;
         };
         this._checkNavigationLinks();
     },
     setPage: function(page, likeReload){
         //this for changing page on document ready and with changing URL
         //so this looks like user reload page
         likeReload = likeReload || false;
         //check if page number is valid
         if (page <= 0){
             page = 1;
         };

         if (this.pages && page > this.pages){
             page = this.pages;
         }

         this.page = page;

         //hide/show navigation links
         this._checkNavigationLinks();

         //change URL
         if (page != 1 || $.address.parameter('page')){
             $.address.parameter('page', page);
         }

         //init timedout callback for page loading
         //this is for more quickly navigation, so we can quickly change
         //few pages without waiting for loading
         if (this.timeoutId){
             clearTimeout(this.timeoutId);
             this.timeoutId = null;
         };
         var that = this;
         this.timeoutId = setTimeout(function(){
             that.showLoading();
             that.onPageChange(that.page, that._createDelegate(that._pageLoadCallback, [likeReload], that));
         }, 300);
     }
 });

})(jQuery);
<|endoftext|>


<commit_before>
///////////////////////////////
//////////////////////////// //
// THE THREE RULES OF TDD // //
//////////////////////////// //
///////////////////////////////

/**
 * 1. You are not allowed to write any production code unless it is to
 * make a failing unit test pass.
 *
 * 2. You are not allowed to write any more of a unit test than is
 * sufficient to fail; and compilation failures ARE failures.
 *
 * 3. You are not allowed to write any more production code than is
 * sufficient to pass the one failing unit test.
 *
 * Yep, this is damm hard :P
 */

var $ = require('jQuery');
var sinon = require('sinon');
var InstagramApi = require('../src/api');
var assert = require('assert');

// remember that the order of the params of methods that checks for
// equalitty is (ACTUAL, EXPECTED). Don't mess up (◕‿◕)

describe('sanity', function () {
    it('should go well', function () {
        assert.equal(!!typeof(InstagramApi), true);
    });
});

describe('InstagramApi,', function () {

    var clientId = 'clientId';
    var redirUri = 'redirUri';

    it('should initialize with args', function () {
        assert.throws(function () {
            var api = new InstagramApi();
        }, Error);
    });

    describe('regarding its methods,', function () {

        var USERID = 'USERID';
        var ACCESSTOKEN = 'ACCESSTOKEN';
        var api;

        beforeEach(function () {
            api = new InstagramApi(clientId, redirUri);
        });

        it('should get auth Url', function () {

            var expectedUrl = "https://instagram.com/oauth/authorize/" +
                "?client_id=" + clientId +
                "&redirect_uri=" + redirUri +
                "&response_type=token";

            assert.strictEqual(api.getAuthUrl(), expectedUrl);
        });

        describe('when building path,', function () {
            it('should build user info', function () {
                var expected = 'https://api.instagram.com/v1/' +
                    'users/USERID/' +
                    '?access_token=ACCESSTOKEN';
                var actual = api._buildPath('user.info');

                assert.strictEqual(actual, expected);
            });

            it('should build user feed', function () {
                var expected = 'https://api.instagram.com/v1/' +
                    'users/self/feed' +
                    '?access_token=ACCESSTOKEN';
                var actual = api._buildPath('user.feed');

                assert.strictEqual(actual, expected);
            });

            it('should build user media', function () {
                var expected = 'https://api.instagram.com/v1/' +
                    'users/USERID/media/recent/' +
                    '?access_token=ACCESSTOKEN';
                var actual = api._buildPath('user.media');

                assert.strictEqual(actual, expected);
            });
        });

        describe('when emitting requests,', function () {

            beforeEach(function () {
               sinon.spy($, 'ajax');
            });

            afterEach(function () {
                $.ajax.restore();
            });

            describe('for getting users stuff,', function () {
                it('should use the right params in the request', function () {
                    api._getUserInfo('userid', 'accesstoken');

                    assert.equal(!!$.ajax.called, true);
                    assert.equal($.ajax.getCall(0).args[0].url,
                                 'https://api.instagram.com/v1/users/userid/?access_token=accesstoken');
                });
            });
        });

        describe('when using the `user` wrapper', function () {
            var mock;

            beforeEach(function () {
                mock = sinon.mock(api);
            });

            afterEach(function () {
                mock.restore();
            });
        });
    });
});<commit_msg>adds missing tests for the /media ep<commit_after>
///////////////////////////////
//////////////////////////// //
// THE THREE RULES OF TDD // //
//////////////////////////// //
///////////////////////////////

/**
 * 1. You are not allowed to write any production code unless it is to
 * make a failing unit test pass.
 *
 * 2. You are not allowed to write any more of a unit test than is
 * sufficient to fail; and compilation failures ARE failures.
 *
 * 3. You are not allowed to write any more production code than is
 * sufficient to pass the one failing unit test.
 *
 * Yep, this is damm hard :P
 */

var $ = require('jQuery');
var sinon = require('sinon');
var InstagramApi = require('../src/api');
var assert = require('assert');

// remember that the order of the params of methods that checks for
// equalitty is (ACTUAL, EXPECTED). Don't mess up (◕‿◕)

describe('sanity', function () {
    it('should go well', function () {
        assert.equal(!!typeof(InstagramApi), true);
    });
});

describe('InstagramApi,', function () {

    var clientId = 'clientId';
    var redirUri = 'redirUri';

    it('should initialize with args', function () {
        assert.throws(function () {
            var api = new InstagramApi();
        }, Error);
    });

    describe('regarding its methods,', function () {

        var USERID = 'USERID';
        var ACCESSTOKEN = 'ACCESSTOKEN';
        var api;

        beforeEach(function () {
            api = new InstagramApi(clientId, redirUri);
        });

        it('should get auth Url', function () {

            var expectedUrl = "https://instagram.com/oauth/authorize/" +
                "?client_id=" + clientId +
                "&redirect_uri=" + redirUri +
                "&response_type=token";

            assert.strictEqual(api.getAuthUrl(), expectedUrl);
        });

        describe('when building path,', function () {
            it('should build user info', function () {
                var expected = 'https://api.instagram.com/v1/' +
                    'users/USERID/' +
                    '?access_token=ACCESSTOKEN';
                var actual = api._buildPath('user.info');

                assert.strictEqual(actual, expected);
            });

            it('should build user feed', function () {
                var expected = 'https://api.instagram.com/v1/' +
                    'users/self/feed' +
                    '?access_token=ACCESSTOKEN';
                var actual = api._buildPath('user.feed');

                assert.strictEqual(actual, expected);
            });

            it('should build user media', function () {
                var expected = 'https://api.instagram.com/v1/' +
                    'users/USERID/media/recent/' +
                    '?access_token=ACCESSTOKEN';
                var actual = api._buildPath('user.media');

                assert.strictEqual(actual, expected);
            });
        });

        describe('when emitting requests,', function () {

            beforeEach(function () {
               sinon.spy($, 'ajax');
            });

            afterEach(function () {
                $.ajax.restore();
            });

            describe('for getting users info,', function () {
                it('should use the right params in the request', function () {
                    api._getUserInfo('userid', 'accesstoken');

                    assert.equal(!!$.ajax.called, true);
                    assert.equal($.ajax.getCall(0).args[0].url,
                                 'https://api.instagram.com/v1/users/userid/?access_token=accesstoken');
                });
            });

            describe('for getting users media,', function () {
                it('should use the righ params in the request', function () {
                    api._getUserMedia('userid', 'accesstoken');

                    assert.equal(!!$.ajax.called, true);
                    assert.equal($.ajax.getCall(0).args[0].url,
                                 'https://api.instagram.com/v1/users/userid/media/recent/?access_token=accesstoken');
                });
            });
        });

    });
});<|endoftext|>


<commit_before>/*
 * logs.js: Commands related to user resources
 *
 * (C) 2010, Nodejitsu Inc.
 *
 */

var winston = require('winston'),
    jitsu = require('../../jitsu');

var logs = exports;

logs.usage = [
  'The `jitsu logs` commands allow you to read the logs related to your app.',
  'The default number of lines to show is 10.',
  '',
  'Example usages:',
  'jitsu logs all',
  'jitsu logs all <number of lines to show>',
  'jitsu logs app <app name>',
  'jitsu logs app <app name> <number of lines to show>'
];

//
// ### function all (callback)
// #### @callback {function} Continuation to pass control to when complete.
// Queries the log API and retrieves the logs for all of the user's apps
//
logs.all = function (amount, callback) {
  if (!callback) {
    callback = amount;
    amount = 10;
  }

  jitsu.logs.byUser(amount, function (err, apps) {
    if (err) {
      return callback(err);
    }

    if (apps.length === 0) {
      winston.warn('No logs for ' + jitsu.config.get('username').magenta + ' from timespan');
      return callback();
    }

    function sortLength (lname, rname) {
      var llength = apps[lname].data.length,
          rlength = apps[rname].data.length;

      if (llength === rlength) {
        return 0;
      }

      return llength > rlength ? 1 : -1;
    }

    Object.keys(apps).sort(sortLength).forEach(function (app) {
      putLogs(apps[app], app, amount, true);
    });

    callback();
  });
};

logs.all.usage = [
  'Print the logs from all applications. The default number of',
  'lines to show is 10.',
  'jits logs all <number of lines to show>',
  '',
  'Example usage:',
  'jitsu logs all',
  'jitsu logs all 5'
];

//
// ### function app (appName, callback)
// #### @appName {string} the application to get the logs for
// #### @callback {function} Continuation to pass control to when complete.
// Queries the log API and retrieves the logs for the specified application
//
logs.app = function (appName, amount, callback) {
  if (callback === undefined) {
    callback = amount;
    amount = 10;
  }

  jitsu.logs.byApp(appName, amount, function (err, results) {
    if (err) {
      return callback(err);
    }

    putLogs(results, appName, amount);
    callback();
  });
}

logs.app.usage = [
  'Print the logs from specified application. The default number of',
  'lines to show is 10.',
  'jits logs app <app name> <number of lines to show>',
  '',
  'Example usage:',
  'jitsu logs app test',
  'jitsu logs app test 40'
];

//
// ### function putLogs (results, appName, amount, showApp)
// #### @results {Object} Logs object to output.
// #### @appName {string} App name associated with the log text.
// #### @showApp {boolean} Value indicating if the app name should be output.
// Parses, formats, and outputs the specified `results` to the user.
//
function putLogs (results, appName, amount, showApp) {
  if (results.data.length === 0) {
    return winston.warn('No logs for ' + appName.magenta + ' in specified timespan');
  }

  var logged = 0,
      loglength = jitsu.config.get('loglength');

  results.data.forEach(function (datum) {
    if (datum.json) {
      datum.json.desc.split('\n').forEach(function (line) {
        var prefix = showApp
          ? datum.timestamp.grey + ' ' + datum.json.app.magenta + ': '
          : datum.timestamp.grey + ': '

        if (line.length > 0 && logged < amount) {
          if (line.length > loglength) {
            line = line.substr(0, loglength - 3) + '...';
          }

          winston.data(prefix + line);
          logged += 1;
        }
      });
    }
  });
}<commit_msg>[commands/logs] 'jitsu logs app' should not throw any error, fixes #92<commit_after>/*
 * logs.js: Commands related to user resources
 *
 * (C) 2010, Nodejitsu Inc.
 *
 */

var winston = require('winston'),
    jitsu = require('../../jitsu');

var logs = exports;

logs.usage = [
  'The `jitsu logs` commands allow you to read the logs related to your app.',
  'The default number of lines to show is 10.',
  '',
  'Example usages:',
  'jitsu logs all',
  'jitsu logs all <number of lines to show>',
  'jitsu logs app <app name>',
  'jitsu logs app <app name> <number of lines to show>'
];

//
// ### function all (callback)
// #### @callback {function} Continuation to pass control to when complete.
// Queries the log API and retrieves the logs for all of the user's apps
//
logs.all = function (amount, callback) {
  if (!callback) {
    callback = amount;
    amount = 10;
  }

  jitsu.logs.byUser(amount, function (err, apps) {
    if (err) {
      return callback(err);
    }

    if (apps.length === 0) {
      winston.warn('No logs for ' + jitsu.config.get('username').magenta + ' from timespan');
      return callback();
    }

    function sortLength (lname, rname) {
      var llength = apps[lname].data.length,
          rlength = apps[rname].data.length;

      if (llength === rlength) {
        return 0;
      }

      return llength > rlength ? 1 : -1;
    }

    Object.keys(apps).sort(sortLength).forEach(function (app) {
      putLogs(apps[app], app, amount, true);
    });

    callback();
  });
};

logs.all.usage = [
  'Print the logs from all applications. The default number of',
  'lines to show is 10.',
  'jits logs all <number of lines to show>',
  '',
  'Example usage:',
  'jitsu logs all',
  'jitsu logs all 5'
];

//
// ### function app (appName, callback)
// #### @appName {string} the application to get the logs for
// #### @callback {function} Continuation to pass control to when complete.
// Queries the log API and retrieves the logs for the specified application
//
logs.app = function (appName, amount, callback) {
  if (typeof appName === 'function') {
    callback = appName;
    callback(new Error('Application name is required for getting logs'), true);
    return;
  }

  if (callback === undefined) {
    callback = amount;
    amount = 10;
  }

  jitsu.logs.byApp(appName, amount, function (err, results) {
    if (err) {
      return callback(err);
    }

    putLogs(results, appName, amount);
    callback();
  });
}

logs.app.usage = [
  'Print the logs from specified application. The default number of',
  'lines to show is 10.',
  'jits logs app <app name> <number of lines to show>',
  '',
  'Example usage:',
  'jitsu logs app test',
  'jitsu logs app test 40'
];

//
// ### function putLogs (results, appName, amount, showApp)
// #### @results {Object} Logs object to output.
// #### @appName {string} App name associated with the log text.
// #### @showApp {boolean} Value indicating if the app name should be output.
// Parses, formats, and outputs the specified `results` to the user.
//
function putLogs (results, appName, amount, showApp) {
  if (results.data.length === 0) {
    return winston.warn('No logs for ' + appName.magenta + ' in specified timespan');
  }

  var logged = 0,
      loglength = jitsu.config.get('loglength');

  results.data.forEach(function (datum) {
    if (datum.json) {
      datum.json.desc.split('\n').forEach(function (line) {
        var prefix = showApp
          ? datum.timestamp.grey + ' ' + datum.json.app.magenta + ': '
          : datum.timestamp.grey + ': '

        if (line.length > 0 && logged < amount) {
          if (line.length > loglength) {
            line = line.substr(0, loglength - 3) + '...';
          }

          winston.data(prefix + line);
          logged += 1;
        }
      });
    }
  });
}
<|endoftext|>


<commit_before>var _ = require('underscore'),
    Cheerio = require('cheerio');

var $make = Cheerio.prototype.make;

Cheerio.prototype.make = function(dom, context) {
  var ret = $make.call(this, dom, context);

  ret.__defineGetter__('innerHTML', function() {
    return this.html();
  });
  ret.__defineSetter__('innerHTML', function(html) {
    this.html(html || '');
  });

  return ret;
};

Cheerio.prototype.bind = Cheerio.prototype.unbind =
Cheerio.prototype.on = Cheerio.prototype.off =
Cheerio.prototype.delegate =
Cheerio.prototype.one = function() {
  return this;
};

Cheerio.prototype.prop = function() {
  return this;
};

Cheerio.prototype.get = Cheerio.prototype.eq;
Cheerio.prototype.forEach = function(callback, scope) {
  var elements = this;
  elements.each(function(index) {
    callback.call(scope || elements, this, index);
  });
};

Cheerio.prototype.getAttribute = function(name) {
  return this.attr(name);
};

Cheerio.prototype.val = function(value) {
  // TODO : Special case for non-text inputs
  return this.attr('value', value);
};

Cheerio.prototype.css = function(name, value) {
  /*jshint eqnull: true */
  var styles = {};
  (this.attr('style') || '').split(/\s*;\s*/g).forEach(function(style) {
    var components = style.split(':');
    if (!components[0]) {
      return;
    }

    styles[components[0]] = (components[1] || '').replace(/;\s*$/, '');
  });

  if (value != null) {
    styles[name] = value;

    this.attr('style', _.map(styles, function(value, key) { return value ? (key + ':' + value + ';') : ''; }).join(''));
  } else {
    return styles[name];
  }
};
Cheerio.prototype.toggle = function(toggle) {
  if (toggle === undefined) {
    toggle = this.css('display') !== 'none';
  }

  this[toggle ? 'show' : 'hide']();
  return this;
};
Cheerio.prototype.show = function() {
  this.css('display', '');
  return this;
};
Cheerio.prototype.hide = function() {
  this.css('display', 'none');
  return this;
};
Cheerio.prototype.toggleClass = function(className, toggle) {
  if (toggle === undefined) {
    toggle = !this.hasClass(className);
  }
  if (toggle) {
    this.addClass(className);
  } else {
    this.removeClass(className);
  }
  return this;
};

Cheerio.prototype.focus = function() {
  this.attr('autofocus', 'autofocus');
};
<commit_msg>Remove methods now implemented by Cheerio<commit_after>var _ = require('underscore'),
    Cheerio = require('cheerio');

var $make = Cheerio.prototype.make;

Cheerio.prototype.make = function(dom, context) {
  var ret = $make.call(this, dom, context);

  ret.__defineGetter__('innerHTML', function() {
    return this.html();
  });
  ret.__defineSetter__('innerHTML', function(html) {
    this.html(html || '');
  });

  return ret;
};

Cheerio.prototype.bind = Cheerio.prototype.unbind =
Cheerio.prototype.on = Cheerio.prototype.off =
Cheerio.prototype.delegate =
Cheerio.prototype.one = function() {
  return this;
};

Cheerio.prototype.prop = function() {
  return this;
};

Cheerio.prototype.get = Cheerio.prototype.eq;
Cheerio.prototype.forEach = function(callback, scope) {
  var elements = this;
  elements.each(function(index) {
    callback.call(scope || elements, this, index);
  });
};

Cheerio.prototype.getAttribute = function(name) {
  return this.attr(name);
};
Cheerio.prototype.toggle = function(toggle) {
  if (toggle === undefined) {
    toggle = this.css('display') !== 'none';
  }

  this[toggle ? 'show' : 'hide']();
  return this;
};
Cheerio.prototype.show = function() {
  this.css('display', '');
  return this;
};
Cheerio.prototype.hide = function() {
  this.css('display', 'none');
  return this;
};
Cheerio.prototype.focus = function() {
  this.attr('autofocus', 'autofocus');
};
<|endoftext|>


<commit_before>import 'vtk.js/Sources/favicon';

// Load the rendering pieces we want to use (for both WebGL and WebGPU)
import 'vtk.js/Sources/Rendering/Profiles/Geometry';

import HttpDataAccessHelper from 'vtk.js/Sources/IO/Core/DataAccessHelper/HttpDataAccessHelper';
import macro from 'vtk.js/Sources/macros';
import vtkDeviceOrientationToCamera from 'vtk.js/Sources/Interaction/Misc/DeviceOrientationToCamera';
import vtkForwardPass from 'vtk.js/Sources/Rendering/OpenGL/ForwardPass';
import vtkFullScreenRenderWindow from 'vtk.js/Sources/Rendering/Misc/FullScreenRenderWindow';
import vtkRadialDistortionPass from 'vtk.js/Sources/Rendering/OpenGL/RadialDistortionPass';
import vtkRenderer from 'vtk.js/Sources/Rendering/Core/Renderer';
import vtkSkybox from 'vtk.js/Sources/Rendering/Core/Skybox';
import vtkSkyboxReader from 'vtk.js/Sources/IO/Misc/SkyboxReader';
import vtkURLExtract from 'vtk.js/Sources/Common/Core/URLExtract';
// import vtkMobileVR from 'vtk.js/Sources/Common/System/MobileVR';

// Force DataAccessHelper to have access to various data source
import 'vtk.js/Sources/IO/Core/DataAccessHelper/HtmlDataAccessHelper';
import 'vtk.js/Sources/IO/Core/DataAccessHelper/JSZipDataAccessHelper';

import style from './SkyboxViewer.module.css';

// ----------------------------------------------
// Possible URL parameters to look for:
//   - fileURL
//   - position
//   - direction
//   - up
//   - vr
//   - eye
//   - viewAngle
//   - debug
//   - autoIncrement
//   - k1
//   - k2
//   - centerY
// ----------------------------------------------
const userParams = vtkURLExtract.extractURLParameters();
let autoInit = true;
const cameraFocalPoint = userParams.direction || [0, 0, -1];
const cameraViewUp = userParams.up || [0, 1, 0];
const cameraViewAngle = userParams.viewAngle || 100;
const enableXR = !!userParams.xr;
const eyeSpacing = userParams.eye || 0.0;
const grid = userParams.debug || false;
const autoIncrementTimer = userParams.timer || 0;
const disableTouchNext = userParams.disableTouch || false;
const distk1 = userParams.k1 || 0.2;
const distk2 = userParams.k2 || 0.0;
const cameraCenterY = userParams.centerY || 0.0;

const body = document.querySelector('body');
let fullScreenMetod = null;

['requestFullscreen', 'msRequestFullscreen', 'webkitRequestFullscreen'].forEach(
  (m) => {
    if (body[m] && !fullScreenMetod) {
      fullScreenMetod = m;
    }
  }
);

function preventDefaults(e) {
  e.preventDefault();
  e.stopPropagation();
}

function createController(options) {
  if (options.length === 1) {
    return null;
  }
  const buffer = ['<select class="position">'];
  buffer.push(options.join(''));
  buffer.push('</select>');

  return buffer.join('');
}

function drawLine(ctx, x, y, text, delta = 10) {
  ctx.beginPath();
  ctx.moveTo(x, y - delta);
  ctx.lineTo(x, y + delta);
  ctx.stroke();
  ctx.fillText(text, x, y + delta + 10);
}

function createGrid(width, height) {
  const canvas = document.createElement('canvas');
  canvas.width = width;
  canvas.height = height;
  canvas.style.width = '100%';
  const ctx = canvas.getContext('2d');
  ctx.strokeStyle = '#FFFFFF';
  ctx.fillStyle = '#FFFFFF';
  ctx.textAlign = 'center';

  const totalWidth = width;
  const eyeCenter = width / 4;
  const y = window.screen.height / 2;
  ctx.clearRect(0, 0, width, height);

  const nbTicks = 20;
  for (let i = 0; i <= nbTicks; i++) {
    const value = (i - nbTicks / 2) / (nbTicks / 2);
    drawLine(
      ctx,
      eyeCenter + eyeCenter * (eyeSpacing + value),
      y,
      `${value}`,
      value ? 20 : 100
    );
    drawLine(
      ctx,
      totalWidth - (eyeCenter + eyeCenter * (eyeSpacing + value)),
      y,
      `${value}`,
      value ? 20 : 100
    );
  }

  ctx.fillText(
    `Current Offset ${eyeSpacing}`,
    eyeCenter + eyeCenter * eyeSpacing,
    y - 120
  );
  ctx.fillText(
    `Current Offset ${eyeSpacing}`,
    totalWidth - (eyeCenter + eyeCenter * eyeSpacing),
    y - 120
  );

  canvas.style.zIndex = 1000;
  canvas.style.position = 'fixed';
  canvas.style.top = 0;
  canvas.style.left = 0;
  body.appendChild(canvas);
}

function createVisualization(container, mapReader) {
  // Empty container
  while (container.firstChild) {
    container.removeChild(container.firstChild);
  }

  const fullScreenRenderer = vtkFullScreenRenderWindow.newInstance({
    rootContainer: container,
    containerStyle: { height: '100%', width: '100%', position: 'absolute' },
  });
  const renderWindow = fullScreenRenderer.getRenderWindow();
  const mainRenderer = fullScreenRenderer.getRenderer();
  const interactor = fullScreenRenderer.getInteractor();
  const actor = vtkSkybox.newInstance();
  let camera = mainRenderer.getActiveCamera();
  let leftRenderer = null;
  let rightRenderer = null;
  let updateCameraCallBack = mainRenderer.resetCameraClippingRange;

  // Connect viz pipeline
  actor.addTexture(mapReader.getOutputData());

  // Update Camera configuration
  const cameraConfiguration = {
    focalPoint: cameraFocalPoint,
    position: [0, 0, 0],
    viewAngle: cameraViewAngle,
    physicalViewNorth: cameraFocalPoint,
    viewUp: cameraViewUp,
    physicalViewUp: cameraViewUp,
  };

  function updateSkybox(position) {
    const selector = document.querySelector('.position');
    if (selector && selector.value !== position) {
      selector.value = position;
    }
    actor.removeAllTextures();
    mapReader.setPosition(`${position}`);
    mapReader.update();
    actor.addTexture(mapReader.getOutputData());
    renderWindow.render();
  }

  function nextPosition() {
    const currentPosition = mapReader.getPosition();
    const allPositions = mapReader.getPositions();
    const nextIdx =
      (allPositions.indexOf(currentPosition) + 1) % allPositions.length;
    updateSkybox(allPositions[nextIdx]);
  }

  if (enableXR && navigator.xr.isSessionSupported('immersive-vr')) {
    leftRenderer = vtkRenderer.newInstance();
    rightRenderer = vtkRenderer.newInstance();

    // Configure left/right renderers
    leftRenderer.setViewport(0, 0, 0.5, 1);
    leftRenderer.addActor(actor);
    const leftCamera = leftRenderer.getActiveCamera();
    leftCamera.set(cameraConfiguration);
    leftCamera.setWindowCenter(-eyeSpacing, -cameraCenterY);

    rightRenderer.setViewport(0.5, 0, 1, 1);
    rightRenderer.addActor(actor);
    const rightCamera = rightRenderer.getActiveCamera();
    rightCamera.set(cameraConfiguration);
    rightCamera.setWindowCenter(eyeSpacing, -cameraCenterY);

    // Provide custom update callback + fake camera
    updateCameraCallBack = () => {
      leftRenderer.resetCameraClippingRange();
      rightRenderer.resetCameraClippingRange();
    };
    camera = {
      setDeviceAngles(alpha, beta, gamma, screen) {
        leftCamera.setDeviceAngles(alpha, beta, gamma, screen);
        rightCamera.setDeviceAngles(alpha, beta, gamma, screen);
      },
    };

    // Reconfigure render window
    renderWindow.addRenderer(leftRenderer);
    renderWindow.addRenderer(rightRenderer);
    renderWindow.removeRenderer(mainRenderer);

    const distPass = vtkRadialDistortionPass.newInstance();
    distPass.setK1(distk1);
    distPass.setK2(distk2);
    distPass.setCameraCenterY(cameraCenterY);
    distPass.setCameraCenterX1(-eyeSpacing);
    distPass.setCameraCenterX2(eyeSpacing);
    distPass.setDelegates([vtkForwardPass.newInstance()]);
    fullScreenRenderer.getApiSpecificRenderWindow().setRenderPasses([distPass]);

    // Hide any controller
    fullScreenRenderer.setControllerVisibility(false);

    // Remove window interactions
    interactor.unbindEvents();

    // Attach touch control
    if (!disableTouchNext) {
      fullScreenRenderer
        .getRootContainer()
        .addEventListener('touchstart', nextPosition, true);
      if (fullScreenMetod) {
        fullScreenRenderer.getRootContainer().addEventListener(
          'touchend',
          (e) => {
            body[fullScreenMetod]();
          },
          true
        );
      }
    }

    // Warning if browser does not support fullscreen
    /* eslint-disable */
    if (navigator.userAgent.match('CriOS')) {
      alert(
        'Chrome on iOS does not support fullscreen. Please use Safari instead.'
      );
    }
    if (navigator.userAgent.match('FxiOS')) {
      alert(
        'Firefox on iOS does not support fullscreen. Please use Safari instead.'
      );
    }
    /* eslint-enable */
  } else {
    camera.set(cameraConfiguration);
    mainRenderer.addActor(actor);

    // add vr option button if supported
    if (
      navigator.xr !== undefined &&
      navigator.xr.isSessionSupported('immersive-vr')
    ) {
      const button = document.createElement('button');
      button.style.position = 'absolute';
      button.style.left = '10px';
      button.style.bottom = '10px';
      button.style.zIndex = 10000;
      button.textContent = 'Send To VR';
      document.querySelector('body').appendChild(button);
      button.addEventListener('click', () => {
        if (button.textContent === 'Send To VR') {
          fullScreenRenderer.getApiSpecificRenderWindow().startXR();
          button.textContent = 'Return From VR';
        } else {
          fullScreenRenderer.getApiSpecificRenderWindow().stopXR();
          button.textContent = 'Send To VR';
        }
      });
    }
  }

  renderWindow.render();

  // handle auto incrementing position
  if (autoIncrementTimer !== 0) {
    setInterval(nextPosition, autoIncrementTimer * 1000);
  }

  // Update camera control
  if (vtkDeviceOrientationToCamera.isDeviceOrientationSupported()) {
    vtkDeviceOrientationToCamera.addWindowListeners();
    const cameraListenerId =
      vtkDeviceOrientationToCamera.addCameraToSynchronize(
        interactor,
        camera,
        updateCameraCallBack
      );
    interactor.requestAnimation('deviceOrientation');
    // Test again after 100ms
    setTimeout(() => {
      if (!vtkDeviceOrientationToCamera.isDeviceOrientationSupported()) {
        vtkDeviceOrientationToCamera.removeCameraToSynchronize(
          cameraListenerId
        );
        vtkDeviceOrientationToCamera.removeWindowListeners();
        interactor.cancelAnimation('deviceOrientation');
      }
    }, 100);
  }

  // Add Control UI
  const controller = createController(
    mapReader.getPositions().map((t) => `<option value="${t}">${t}</option>`)
  );
  if (controller) {
    fullScreenRenderer.addController(controller);
    document.querySelector('.position').addEventListener('change', (e) => {
      updateSkybox(e.target.value);
    });
  }

  // Apply url args to viz
  if (userParams.position) {
    updateSkybox(userParams.position);
  }

  if (grid) {
    console.log(fullScreenRenderer.getOpenGLRenderWindow().getSize());
    createGrid(...fullScreenRenderer.getOpenGLRenderWindow().getSize());
  }
}

/* eslint-disable import/prefer-default-export */
/* eslint-disable import/no-extraneous-dependencies */

export function initLocalFileLoader(container) {
  autoInit = false;
  const exampleContainer = document.querySelector('.content');
  const rootBody = document.querySelector('body');
  const myContainer = container || exampleContainer || rootBody;

  if (myContainer !== container) {
    myContainer.classList.add(style.fullScreen);
    rootBody.style.margin = '0';
    rootBody.style.padding = '0';
  } else {
    rootBody.style.margin = '0';
    rootBody.style.padding = '0';
  }

  const fileContainer = document.createElement('div');
  fileContainer.innerHTML = `<div class="${style.bigFileDrop}"/><input type="file" accept=".skybox,.zip" style="display: none;"/>`;
  myContainer.appendChild(fileContainer);

  const fileInput = fileContainer.querySelector('input');

  function handleFile(e) {
    preventDefaults(e);
    const dataTransfer = e.dataTransfer;
    const files = e.target.files || dataTransfer.files;
    if (files.length === 1) {
      myContainer.removeChild(fileContainer);
      const reader = vtkSkyboxReader.newInstance();
      reader.parseAsArrayBuffer(files[0]);
      reader.getReadyPromise().then(() => {
        createVisualization(myContainer, reader);
      });
    }
  }

  fileInput.addEventListener('change', handleFile);
  fileContainer.addEventListener('drop', handleFile);
  fileContainer.addEventListener('click', (e) => fileInput.click());
  fileContainer.addEventListener('dragover', preventDefaults);
}

// Look for data to download
if (userParams.fileURL) {
  autoInit = false;
  const exampleContainer = document.querySelector('.content');
  const rootBody = document.querySelector('body');
  const myContainer = exampleContainer || rootBody;
  if (myContainer) {
    myContainer.classList.add(style.fullScreen);
    rootBody.style.margin = '0';
    rootBody.style.padding = '0';
  }

  const progressContainer = document.createElement('div');
  progressContainer.setAttribute('class', style.progress);
  myContainer.appendChild(progressContainer);

  const progressCallback = (progressEvent) => {
    if (progressEvent.lengthComputable) {
      const percent = Math.floor(
        (100 * progressEvent.loaded) / progressEvent.total
      );
      progressContainer.innerHTML = `Loading ${percent}%`;
    } else {
      progressContainer.innerHTML = macro.formatBytesToProperUnit(
        progressEvent.loaded
      );
    }
  };

  HttpDataAccessHelper.fetchBinary(userParams.fileURL, {
    progressCallback,
  }).then((arrayBuffer) => {
    const reader = vtkSkyboxReader.newInstance();
    reader.parseAsArrayBuffer(arrayBuffer);
    reader.getReadyPromise().then(() => {
      createVisualization(myContainer, reader);
    });
  });
}

// Auto setup if no method get called within 100ms
setTimeout(() => {
  if (autoInit) {
    initLocalFileLoader();
  }
}, 100);
<commit_msg>feat(XR): Remove force-entry XR option from SkyboxViewer<commit_after>import 'vtk.js/Sources/favicon';

// Load the rendering pieces we want to use (for both WebGL and WebGPU)
import 'vtk.js/Sources/Rendering/Profiles/Geometry';

import HttpDataAccessHelper from 'vtk.js/Sources/IO/Core/DataAccessHelper/HttpDataAccessHelper';
import macro from 'vtk.js/Sources/macros';
import vtkDeviceOrientationToCamera from 'vtk.js/Sources/Interaction/Misc/DeviceOrientationToCamera';
import vtkFullScreenRenderWindow from 'vtk.js/Sources/Rendering/Misc/FullScreenRenderWindow';
import vtkSkybox from 'vtk.js/Sources/Rendering/Core/Skybox';
import vtkSkyboxReader from 'vtk.js/Sources/IO/Misc/SkyboxReader';
import vtkURLExtract from 'vtk.js/Sources/Common/Core/URLExtract';
// import vtkMobileVR from 'vtk.js/Sources/Common/System/MobileVR';

// Force DataAccessHelper to have access to various data source
import 'vtk.js/Sources/IO/Core/DataAccessHelper/HtmlDataAccessHelper';
import 'vtk.js/Sources/IO/Core/DataAccessHelper/JSZipDataAccessHelper';

import style from './SkyboxViewer.module.css';

// ----------------------------------------------
// Possible URL parameters to look for:
//   - fileURL
//   - position
//   - direction
//   - up
//   - vr
//   - eye
//   - viewAngle
//   - debug
//   - autoIncrement
//   - k1
//   - k2
//   - centerY
// ----------------------------------------------
const userParams = vtkURLExtract.extractURLParameters();
let autoInit = true;
const cameraFocalPoint = userParams.direction || [0, 0, -1];
const cameraViewUp = userParams.up || [0, 1, 0];
const cameraViewAngle = userParams.viewAngle || 100;
const eyeSpacing = userParams.eye || 0.0;
const grid = userParams.debug || false;
const autoIncrementTimer = userParams.timer || 0;

const body = document.querySelector('body');
let fullScreenMetod = null;

['requestFullscreen', 'msRequestFullscreen', 'webkitRequestFullscreen'].forEach(
  (m) => {
    if (body[m] && !fullScreenMetod) {
      fullScreenMetod = m;
    }
  }
);

function preventDefaults(e) {
  e.preventDefault();
  e.stopPropagation();
}

function createController(options) {
  if (options.length === 1) {
    return null;
  }
  const buffer = ['<select class="position">'];
  buffer.push(options.join(''));
  buffer.push('</select>');

  return buffer.join('');
}

function drawLine(ctx, x, y, text, delta = 10) {
  ctx.beginPath();
  ctx.moveTo(x, y - delta);
  ctx.lineTo(x, y + delta);
  ctx.stroke();
  ctx.fillText(text, x, y + delta + 10);
}

function createGrid(width, height) {
  const canvas = document.createElement('canvas');
  canvas.width = width;
  canvas.height = height;
  canvas.style.width = '100%';
  const ctx = canvas.getContext('2d');
  ctx.strokeStyle = '#FFFFFF';
  ctx.fillStyle = '#FFFFFF';
  ctx.textAlign = 'center';

  const totalWidth = width;
  const eyeCenter = width / 4;
  const y = window.screen.height / 2;
  ctx.clearRect(0, 0, width, height);

  const nbTicks = 20;
  for (let i = 0; i <= nbTicks; i++) {
    const value = (i - nbTicks / 2) / (nbTicks / 2);
    drawLine(
      ctx,
      eyeCenter + eyeCenter * (eyeSpacing + value),
      y,
      `${value}`,
      value ? 20 : 100
    );
    drawLine(
      ctx,
      totalWidth - (eyeCenter + eyeCenter * (eyeSpacing + value)),
      y,
      `${value}`,
      value ? 20 : 100
    );
  }

  ctx.fillText(
    `Current Offset ${eyeSpacing}`,
    eyeCenter + eyeCenter * eyeSpacing,
    y - 120
  );
  ctx.fillText(
    `Current Offset ${eyeSpacing}`,
    totalWidth - (eyeCenter + eyeCenter * eyeSpacing),
    y - 120
  );

  canvas.style.zIndex = 1000;
  canvas.style.position = 'fixed';
  canvas.style.top = 0;
  canvas.style.left = 0;
  body.appendChild(canvas);
}

function createVisualization(container, mapReader) {
  // Empty container
  while (container.firstChild) {
    container.removeChild(container.firstChild);
  }

  const fullScreenRenderer = vtkFullScreenRenderWindow.newInstance({
    rootContainer: container,
    containerStyle: { height: '100%', width: '100%', position: 'absolute' },
  });
  const renderWindow = fullScreenRenderer.getRenderWindow();
  const mainRenderer = fullScreenRenderer.getRenderer();
  const interactor = fullScreenRenderer.getInteractor();
  const actor = vtkSkybox.newInstance();
  const camera = mainRenderer.getActiveCamera();
  const updateCameraCallBack = mainRenderer.resetCameraClippingRange;

  // Connect viz pipeline
  actor.addTexture(mapReader.getOutputData());

  // Update Camera configuration
  const cameraConfiguration = {
    focalPoint: cameraFocalPoint,
    position: [0, 0, 0],
    viewAngle: cameraViewAngle,
    physicalViewNorth: cameraFocalPoint,
    viewUp: cameraViewUp,
    physicalViewUp: cameraViewUp,
  };

  function updateSkybox(position) {
    const selector = document.querySelector('.position');
    if (selector && selector.value !== position) {
      selector.value = position;
    }
    actor.removeAllTextures();
    mapReader.setPosition(`${position}`);
    mapReader.update();
    actor.addTexture(mapReader.getOutputData());
    renderWindow.render();
  }

  function nextPosition() {
    const currentPosition = mapReader.getPosition();
    const allPositions = mapReader.getPositions();
    const nextIdx =
      (allPositions.indexOf(currentPosition) + 1) % allPositions.length;
    updateSkybox(allPositions[nextIdx]);
  }

  camera.set(cameraConfiguration);
  mainRenderer.addActor(actor);

  // add vr option button if supported
  if (
    navigator.xr !== undefined &&
    navigator.xr.isSessionSupported('immersive-vr')
  ) {
    const button = document.createElement('button');
    button.style.position = 'absolute';
    button.style.left = '10px';
    button.style.bottom = '10px';
    button.style.zIndex = 10000;
    button.textContent = 'Send To VR';
    document.querySelector('body').appendChild(button);
    button.addEventListener('click', () => {
      if (button.textContent === 'Send To VR') {
        fullScreenRenderer.getApiSpecificRenderWindow().startXR();
        button.textContent = 'Return From VR';
      } else {
        fullScreenRenderer.getApiSpecificRenderWindow().stopXR();
        button.textContent = 'Send To VR';
      }
    });
  }

  renderWindow.render();

  // handle auto incrementing position
  if (autoIncrementTimer !== 0) {
    setInterval(nextPosition, autoIncrementTimer * 1000);
  }

  // Update camera control
  if (vtkDeviceOrientationToCamera.isDeviceOrientationSupported()) {
    vtkDeviceOrientationToCamera.addWindowListeners();
    const cameraListenerId =
      vtkDeviceOrientationToCamera.addCameraToSynchronize(
        interactor,
        camera,
        updateCameraCallBack
      );
    interactor.requestAnimation('deviceOrientation');
    // Test again after 100ms
    setTimeout(() => {
      if (!vtkDeviceOrientationToCamera.isDeviceOrientationSupported()) {
        vtkDeviceOrientationToCamera.removeCameraToSynchronize(
          cameraListenerId
        );
        vtkDeviceOrientationToCamera.removeWindowListeners();
        interactor.cancelAnimation('deviceOrientation');
      }
    }, 100);
  }

  // Add Control UI
  const controller = createController(
    mapReader.getPositions().map((t) => `<option value="${t}">${t}</option>`)
  );
  if (controller) {
    fullScreenRenderer.addController(controller);
    document.querySelector('.position').addEventListener('change', (e) => {
      updateSkybox(e.target.value);
    });
  }

  // Apply url args to viz
  if (userParams.position) {
    updateSkybox(userParams.position);
  }

  if (grid) {
    console.log(fullScreenRenderer.getOpenGLRenderWindow().getSize());
    createGrid(...fullScreenRenderer.getOpenGLRenderWindow().getSize());
  }
}

/* eslint-disable import/prefer-default-export */
/* eslint-disable import/no-extraneous-dependencies */

export function initLocalFileLoader(container) {
  autoInit = false;
  const exampleContainer = document.querySelector('.content');
  const rootBody = document.querySelector('body');
  const myContainer = container || exampleContainer || rootBody;

  if (myContainer !== container) {
    myContainer.classList.add(style.fullScreen);
    rootBody.style.margin = '0';
    rootBody.style.padding = '0';
  } else {
    rootBody.style.margin = '0';
    rootBody.style.padding = '0';
  }

  const fileContainer = document.createElement('div');
  fileContainer.innerHTML = `<div class="${style.bigFileDrop}"/><input type="file" accept=".skybox,.zip" style="display: none;"/>`;
  myContainer.appendChild(fileContainer);

  const fileInput = fileContainer.querySelector('input');

  function handleFile(e) {
    preventDefaults(e);
    const dataTransfer = e.dataTransfer;
    const files = e.target.files || dataTransfer.files;
    if (files.length === 1) {
      myContainer.removeChild(fileContainer);
      const reader = vtkSkyboxReader.newInstance();
      reader.parseAsArrayBuffer(files[0]);
      reader.getReadyPromise().then(() => {
        createVisualization(myContainer, reader);
      });
    }
  }

  fileInput.addEventListener('change', handleFile);
  fileContainer.addEventListener('drop', handleFile);
  fileContainer.addEventListener('click', (e) => fileInput.click());
  fileContainer.addEventListener('dragover', preventDefaults);
}

// Look for data to download
if (userParams.fileURL) {
  autoInit = false;
  const exampleContainer = document.querySelector('.content');
  const rootBody = document.querySelector('body');
  const myContainer = exampleContainer || rootBody;
  if (myContainer) {
    myContainer.classList.add(style.fullScreen);
    rootBody.style.margin = '0';
    rootBody.style.padding = '0';
  }

  const progressContainer = document.createElement('div');
  progressContainer.setAttribute('class', style.progress);
  myContainer.appendChild(progressContainer);

  const progressCallback = (progressEvent) => {
    if (progressEvent.lengthComputable) {
      const percent = Math.floor(
        (100 * progressEvent.loaded) / progressEvent.total
      );
      progressContainer.innerHTML = `Loading ${percent}%`;
    } else {
      progressContainer.innerHTML = macro.formatBytesToProperUnit(
        progressEvent.loaded
      );
    }
  };

  HttpDataAccessHelper.fetchBinary(userParams.fileURL, {
    progressCallback,
  }).then((arrayBuffer) => {
    const reader = vtkSkyboxReader.newInstance();
    reader.parseAsArrayBuffer(arrayBuffer);
    reader.getReadyPromise().then(() => {
      createVisualization(myContainer, reader);
    });
  });
}

// Auto setup if no method get called within 100ms
setTimeout(() => {
  if (autoInit) {
    initLocalFileLoader();
  }
}, 100);
<|endoftext|>