<commit_before>//osjs main class
function Osjs(){
	this.write_key = null;
	this.anonymousId = null;
	this.userId = null;
	this.datas = [];
	var self = this;

	//options
	this.setOptions = function(options){
		if(options.write_key){
			self.write_key = options.write_key;
		}

		if(options.anonymousId){
			//if an anon id is passed, we save it
			self.anonymousId = options.anonymousId;
		}
		else if(!self.anonymousId){
			//no anon id, we generate one in case we need it.
			self.anonymousId = Math.floor(Math.random() * 0xfffffffffffff);
		}

		if(options.userId && !self.userId){
			self.userId = options.userId;
		}
	}

	//xhr func
	this.xhr = function(url, data){
		//we add timestamp to data, if there is not one already present
		if(!data.timestamp){
			var d = new Date();
			var t = d.toISOString(); //segment need timestamp at ISO format
			data.timestamp = t;
		}
		var xmlhttp;
		if (window.XMLHttpRequest){
			// code for IE7+, Firefox, Chrome, Opera, Safari
		    xmlhttp=new XMLHttpRequest();
		}
		else{
			// code for IE6, IE5
		    xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
		}
		console.log(JSON.stringify(data, null,4));
		xmlhttp.onreadystatechange = function(){
			if(xmlhttp.readyState==4){
				if(xmlhttp.status == 200){
					//success, we can send the queue if there is one
					self.sendQueue();
				}
				else{
					//error => queue
					self.queue(url, data);
				}
			}
		}
		xmlhttp.open("POST", url, true);
		xmlhttp.setRequestHeader("Authorization", "Basic " + btoa(self.write_key + ":" + null));
		xmlhttp.setRequestHeader("Content-type","application/json");
		//xmlhttp.setRequestHeader("Content-length", data.length);
		xmlhttp.send(JSON.stringify(data));
	}

	this.queue = function(url, data){
		var a = url.split("/").pop(); //we get the action name from the url
		//we merge the action into the data, so that we can use import
		data.action = a;
		self.datas.push(data);
	}

	this.sendQueue = function(){
		if(self.datas.length !== 0){
			//we have some stored data => we send it
			//we create the data with the queue
			var data = {
				"batch":self.datas
			};
			//we empty the queue
			self.datas = [];
			var xmlhttp;
			if (window.XMLHttpRequest){
				// code for IE7+, Firefox, Chrome, Opera, Safari
			    xmlhttp=new XMLHttpRequest();
			}
			else{
				// code for IE6, IE5
			    xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
			}
			xmlhttp.onreadystatechange = function(){
				if(xmlhttp.readyState==4){
					if(xmlhttp.status == 200){
						//it worked. nothing to do.
					}
					else{
						//it didnt work. higly improbable. but we repopulate the queue
						for(var i=0;i<data.batch.length;i++){
							self.datas.push(data.batch[i]);
						}
					}
				}
			}
			xmlhttp.open("POST", "https://api.segment.io/v1/import", true);
			xmlhttp.setRequestHeader("Authorization", "Basic " + btoa(self.write_key + ":" + null));
			xmlhttp.setRequestHeader("Content-type","application/json");
			//xmlhttp.setRequestHeader("Content-length", data.length);
			xmlhttp.send(JSON.stringify(data));

		}
		else{
			//queue empty. we do nothing
		}
	}

	//identify
	this.identify = function(data){
		if(!data.anonymousId){
			data.anonymousId = self.anonymousId;
		}
		if(!data.userId && self.userId){
			data.userId = self.userId;
		}
		self.xhr("https://api.segment.io/v1/identify", data);
	}

	//group
	this.group = function(data){
		if(!data.anonymousId){
			data.anonymousId = self.anonymousId;
		}
		if(!data.userId && self.userId){
			data.userId = self.userId;
		}
		self.xhr("https://api.segment.io/v1/group", data);
	}

	//track
	this.track = function(data){
		if(!data.anonymousId){
			data.anonymousId = self.anonymousId;
		}
		if(!data.userId && self.userId){
			data.userId = self.userId;
		}
		self.xhr("https://api.segment.io/v1/track", data);
	}

	//page
	this.page = function(data){
		if(!data.anonymousId){
			data.anonymousId = self.anonymousId;
		}
		if(!data.userId && self.userId){
			data.userId = self.userId;
		}
		self.xhr("https://api.segment.io/v1/page", data);
	}

	//screen
	this.screen = function(data){
		if(!data.anonymousId){
			data.anonymousId = self.anonymousId;
		}
		if(!data.userId && self.userId){
			data.userId = self.userId;
		}
		self.xhr("https://api.segment.io/v1/screen", data);
	}

	//alias
	this.alias = function(data){
		if(!data.userId && self.userId){
			data.userId = self.userId;
		}
		self.xhr("https://api.segment.io/v1/alias", data);
	}

	//import to make compatible with queue system
	/*this.import = function(data){
		self.xhr("https://api.segment.io/v1/import", data);
	}*/

}

var osjs = new Osjs();

<commit_msg>alias improvement<commit_after>//osjs main class
function Osjs(){
	this.write_key = null;
	this.anonymousId = null;
	this.userId = null;
	this.datas = [];
	var self = this;

	//options
	this.setOptions = function(options){
		if(options.write_key){
			self.write_key = options.write_key;
		}

		if(options.anonymousId){
			//if an anon id is passed, we save it
			self.anonymousId = options.anonymousId;
		}
		else if(!self.anonymousId){
			//no anon id, we generate one in case we need it.
			self.anonymousId = Math.floor(Math.random() * 0xfffffffffffff);
		}

		if(options.userId && !self.userId){
			self.userId = options.userId;
		}
	}

	//xhr func
	this.xhr = function(url, data){
		//we add timestamp to data, if there is not one already present
		if(!data.timestamp){
			var d = new Date();
			var t = d.toISOString(); //segment need timestamp at ISO format
			data.timestamp = t;
		}
		var xmlhttp;
		if (window.XMLHttpRequest){
			// code for IE7+, Firefox, Chrome, Opera, Safari
		    xmlhttp=new XMLHttpRequest();
		}
		else{
			// code for IE6, IE5
		    xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
		}
		console.log(JSON.stringify(data, null,4));
		xmlhttp.onreadystatechange = function(){
			if(xmlhttp.readyState==4){
				if(xmlhttp.status == 200){
					//success, we can send the queue if there is one
					self.sendQueue();
				}
				else{
					//error => queue
					self.queue(url, data);
				}
			}
		}
		xmlhttp.open("POST", url, true);
		xmlhttp.setRequestHeader("Authorization", "Basic " + btoa(self.write_key + ":" + null));
		xmlhttp.setRequestHeader("Content-type","application/json");
		//xmlhttp.setRequestHeader("Content-length", data.length);
		xmlhttp.send(JSON.stringify(data));
	}

	this.queue = function(url, data){
		var a = url.split("/").pop(); //we get the action name from the url
		//we merge the action into the data, so that we can use import
		data.action = a;
		self.datas.push(data);
	}

	this.sendQueue = function(){
		if(self.datas.length !== 0){
			//we have some stored data => we send it
			//we create the data with the queue
			var data = {
				"batch":self.datas
			};
			//we empty the queue
			self.datas = [];
			var xmlhttp;
			if (window.XMLHttpRequest){
				// code for IE7+, Firefox, Chrome, Opera, Safari
			    xmlhttp=new XMLHttpRequest();
			}
			else{
				// code for IE6, IE5
			    xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
			}
			xmlhttp.onreadystatechange = function(){
				if(xmlhttp.readyState==4){
					if(xmlhttp.status == 200){
						//it worked. nothing to do.
					}
					else{
						//it didnt work. higly improbable. but we repopulate the queue
						for(var i=0;i<data.batch.length;i++){
							self.datas.push(data.batch[i]);
						}
					}
				}
			}
			xmlhttp.open("POST", "https://api.segment.io/v1/import", true);
			xmlhttp.setRequestHeader("Authorization", "Basic " + btoa(self.write_key + ":" + null));
			xmlhttp.setRequestHeader("Content-type","application/json");
			//xmlhttp.setRequestHeader("Content-length", data.length);
			xmlhttp.send(JSON.stringify(data));

		}
		else{
			//queue empty. we do nothing
		}
	}

	//identify
	this.identify = function(data){
		if(!data.anonymousId){
			data.anonymousId = self.anonymousId;
		}
		if(!data.userId && self.userId){
			data.userId = self.userId;
		}
		self.xhr("https://api.segment.io/v1/identify", data);
	}

	//group
	this.group = function(data){
		if(!data.anonymousId){
			data.anonymousId = self.anonymousId;
		}
		if(!data.userId && self.userId){
			data.userId = self.userId;
		}
		self.xhr("https://api.segment.io/v1/group", data);
	}

	//track
	this.track = function(data){
		if(!data.anonymousId){
			data.anonymousId = self.anonymousId;
		}
		if(!data.userId && self.userId){
			data.userId = self.userId;
		}
		self.xhr("https://api.segment.io/v1/track", data);
	}

	//page
	this.page = function(data){
		if(!data.anonymousId){
			data.anonymousId = self.anonymousId;
		}
		if(!data.userId && self.userId){
			data.userId = self.userId;
		}
		self.xhr("https://api.segment.io/v1/page", data);
	}

	//screen
	this.screen = function(data){
		if(!data.anonymousId){
			data.anonymousId = self.anonymousId;
		}
		if(!data.userId && self.userId){
			data.userId = self.userId;
		}
		self.xhr("https://api.segment.io/v1/screen", data);
	}

	//alias
	this.alias = function(data){
		if(!data.userId && self.userId){
			data.userId = self.userId;
		}
		if(!data.previousId && self.anonymousId){
			//we link userId to anonId if no previous Id set
			data.previousId = self.anonymousId;
		}
		self.xhr("https://api.segment.io/v1/alias", data);
	}

	//import to make compatible with queue system
	/*this.import = function(data){
		self.xhr("https://api.segment.io/v1/import", data);
	}*/

}

var osjs = new Osjs();

<|endoftext|>


<commit_before>/**
 * Service to work with MDX2JSON. All request to server should be made from here
 */
(function() {
    'use strict';

    function ConnectorSvc($http, CONST, $cookieStore, $location, $routeParams) {
        var _this = this;
        this.firstRun = true;
        this.username = localStorage.userName || "";
        this.url = "";
        this.getDashboards = getDashboards;
        this.getPivotData = getPivotData;
        this.execMDX = execMDX;
        this.getWidgets = getWidgets;
        this.signIn = signIn;
        this.signOut = signOut;
        this.getNamespace = getNamespace;
        this.getFavorites = getFavorites;
        this.addFavorite = addFavorite;
        this.deleteFavorite = deleteFavorite;
        this.searchFilters = searchFilters;
        this.saveConfig = saveConfig;
        this.loadConfig = loadConfig;

        // for local testing
        /*
         "http://146.185.143.59/MDX2JSON/"
         "http://82.196.12.237:57772/MDX2JSON/"  vportal
         "http://classroom.intersystems.ru/MDX2JSON/"
         "http://146.185.183.169:57772/MDX2JSON/"
         "http://37.139.6.156/MDX2JSON/"
         "http://192.168.1.20:57772/MDX2JSON/"
         "http://37.139.17.101/MDX2JSON/"
         */
        if (localStorage.connectorRedirect) this.url = localStorage.connectorRedirect; else {
            this.url = $location.$$protocol + "://" + $location.$$host;
            if ($location.$$port) this.url += ":" + $location.$$port;
            this.url += "/MDX2JSON/";
        }

        /**
         * Returns current namespace
         * @returns {string} Namespace
         */
        function getNamespace() {
            return $routeParams.ns || "samples";
        }

        /**
         * Requests dashboard list
         * @returns {object} $http promise
         */
        function getDashboards() {
            _this.firstRun = false;
            return $http({
                method: 'POST',
                data: {Folder: ""},
                url: _this.url + 'Dashboards?Namespace=' + getNamespace(),
                withCredentials: true
            });
        }

        function getPivotData(dataSourceName) {
            return $http({
                method: 'POST',
                url: _this.url + 'DataSource?Namespace=' + getNamespace(),
                data: {DataSource: dataSourceName},
                timeout: CONST.timeout,
                withCredentials: true
            });
        }

        /**
         * Requests MDX query result
         * @param {string} mdx MDX query
         * @returns {object} $http promise
         */
        function execMDX(mdx) {
            var parts = mdx.split(" ");
            if (parts) if (parts.length !== 0) if (parts[0].toUpperCase() === "DRILLTHROUGH") return execMDXDrillthrough(mdx);

            return $http({
                method: 'POST',
                url: _this.url + 'MDX?Namespace=' + getNamespace(),
                data: {MDX: mdx},
                timeout: CONST.timeout,
                withCredentials: true
            });
        }

        /**
         * Requests MDX drillthrough query result
         * @param {string} mdx MDX query
         * @returns {object} $http promise
         */
        function execMDXDrillthrough(mdx) {
            return $http({
                method: 'POST',
                url: _this.url + 'MDXDrillthrough?Namespace=' + getNamespace(),
                data: {MDX: mdx},
                timeout: CONST.timeout,
                withCredentials: true
            });
        }

        /**
         * Requests widgets list
         * @param {string} dashboard Dashboard
         * @returns {object} $http promise
         */
        function getWidgets(dashboard) {
            return $http({
                method: 'POST',
                url: _this.url + 'Dashboard?Namespace=' + getNamespace(),// + "&Debug",
                data: JSON.stringify({Dashboard: dashboard}),
                timeout: CONST.timeout,
                withCredentials: true,
                headers: {'Content-Type': 'application/json'}
            });
        }

        /**
         * Requests filter values
         * @param {string} searchStr Search string
         * @param {string} dataSource Filter data source
         * @returns {object} $http promise
         */
        function searchFilters(searchStr, dataSource) {
            return $http({
                method: 'POST',
                data: {
                    DataSource: dataSource,
                    Values: 1,
                    Search: searchStr
                },
                url: _this.url + 'Filters?Namespace=' + getNamespace(),
                withCredentials: true
            });
        }

        /**
         * Requests favorites
         * @returns {object} $http promise
         */
        function getFavorites() {
            return $http({
                method: 'GET',
                data: {},
                url: _this.url + 'Favorites?Namespace=' + getNamespace(),
                withCredentials: true
            });
        }

        /**
         * Adds favorite
         * @param {string} path Favorite path
         * @returns {object} $http promise
         */
        function addFavorite(path) {
            return $http({
                method: 'POST',
                data: {},
                url: _this.url + 'Favorites/'+ encodeURIComponent(path) + '?Namespace=' + getNamespace(),
                withCredentials: true
            });
        }

        /**
         * Deletes favorite
         * @param {string} path Favorite path
         * @returns {object} $http promise
         */
        function deleteFavorite(path) {
            return $http({
                method: 'DELETE',
                data: {},
                url: _this.url + 'Favorites/'+ encodeURIComponent(path) + '?Namespace=' + getNamespace(),
                withCredentials: true
            });
        }

        /**
         * Loads configuration from server
         * @returns {object} $http promise
         */
        function loadConfig(cutomNamespace) {
            return $http({
                method: 'Get',
                data: {},
                url: _this.url + 'Config/DeepSeeWeb?Namespace=' + (cutomNamespace || getNamespace()),
                withCredentials: true
            });
        }

        /**
         * Saves configuration to server
         * @param {object} config Configuration to save
         * @returns {object} $http promise
         */
        function saveConfig(config) {
            return $http({
                method: 'POST',
                data: { Application: "DeepSeeWeb", Config: JSON.stringify(config) },
                url: _this.url + 'Config?Namespace=' + getNamespace(),
                withCredentials: true
            });
        }

        /**
         * Sings in
         * @param {string} login User login
         * @param {string} password User password
         * @param {string} namespace Namespace
         * @returns {object} $http promise
         */
        function signIn(login, password, namespace) {
            _this.username = login;
            return $http({
                method: 'GET',
                url: _this.url + 'Test?Namespace=' + namespace,
                timeout: CONST.timeout,
                headers: {
                    'Authorization': 'Basic ' + btoa(login + ":" + password)
                }
            });
        }

        /**
         * Signs out
         */
        function signOut() {
            _this.firstRun = true;
            //delete sessionStorage.dashboarList;
            $cookieStore.remove("CSPWSERVERID");
            $cookieStore.remove("CacheLoginToken");
            $cookieStore.remove("CSPSESSIONID-SP-80-UP-");

            _this.username = "";
            localStorage.userName = "";

            $location.path("/login").search({});
        }
    }

    angular.module('app')
        .service('Connector', ['$http', 'CONST', '$cookieStore', '$location', '$routeParams', ConnectorSvc]);

})();
<commit_msg>file loading added<commit_after>/**
 * Service to work with MDX2JSON. All request to server should be made from here
 */
(function() {
    'use strict';

    function ConnectorSvc($http, CONST, $cookieStore, $location, $routeParams) {
        var _this = this;
        this.firstRun = true;
        this.username = localStorage.userName || "";
        this.url = "";
        this.getDashboards = getDashboards;
        this.getPivotData = getPivotData;
        this.execMDX = execMDX;
        this.getWidgets = getWidgets;
        this.signIn = signIn;
        this.signOut = signOut;
        this.getFile = getFile;
        this.getNamespace = getNamespace;
        this.getFavorites = getFavorites;
        this.addFavorite = addFavorite;
        this.deleteFavorite = deleteFavorite;
        this.searchFilters = searchFilters;
        this.saveConfig = saveConfig;
        this.loadConfig = loadConfig;

        // for local testing
        /*
         "http://146.185.143.59/MDX2JSON/"
         "http://82.196.12.237:57772/MDX2JSON/"  vportal
         "http://classroom.intersystems.ru/MDX2JSON/"
         "http://146.185.183.169:57772/MDX2JSON/"
         "http://37.139.6.156/MDX2JSON/"
         "http://192.168.1.20:57772/MDX2JSON/"
         "http://37.139.17.101/MDX2JSON/"
         */
        if (localStorage.connectorRedirect) this.url = localStorage.connectorRedirect; else {
            this.url = $location.$$protocol + "://" + $location.$$host;
            if ($location.$$port) this.url += ":" + $location.$$port;
            this.url += "/MDX2JSON/";
        }

        /**
         * Returns current namespace
         * @returns {string} Namespace
         */
        function getNamespace() {
            return $routeParams.ns || "samples";
        }

        /**
         * Requests dashboard list
         * @returns {object} $http promise
         */
        function getDashboards() {
            _this.firstRun = false;
            return $http({
                method: 'POST',
                data: {Folder: ""},
                url: _this.url + 'Dashboards?Namespace=' + getNamespace(),
                withCredentials: true
            });
        }

        function getPivotData(dataSourceName) {
            return $http({
                method: 'POST',
                url: _this.url + 'DataSource?Namespace=' + getNamespace(),
                data: {DataSource: dataSourceName},
                timeout: CONST.timeout,
                withCredentials: true
            });
        }

        /**
         * Requests MDX query result
         * @param {string} mdx MDX query
         * @returns {object} $http promise
         */
        function execMDX(mdx) {
            var parts = mdx.split(" ");
            if (parts) if (parts.length !== 0) if (parts[0].toUpperCase() === "DRILLTHROUGH") return execMDXDrillthrough(mdx);

            return $http({
                method: 'POST',
                url: _this.url + 'MDX?Namespace=' + getNamespace(),
                data: {MDX: mdx},
                timeout: CONST.timeout,
                withCredentials: true
            });
        }

        /**
         * Requests MDX drillthrough query result
         * @param {string} mdx MDX query
         * @returns {object} $http promise
         */
        function execMDXDrillthrough(mdx) {
            return $http({
                method: 'POST',
                url: _this.url + 'MDXDrillthrough?Namespace=' + getNamespace(),
                data: {MDX: mdx},
                timeout: CONST.timeout,
                withCredentials: true
            });
        }

        /**
         * Requests widgets list
         * @param {string} dashboard Dashboard
         * @returns {object} $http promise
         */
        function getWidgets(dashboard) {
            return $http({
                method: 'POST',
                url: _this.url + 'Dashboard?Namespace=' + getNamespace(),// + "&Debug",
                data: JSON.stringify({Dashboard: dashboard}),
                timeout: CONST.timeout,
                withCredentials: true,
                headers: {'Content-Type': 'application/json'}
            });
        }

        /**
         * Requests filter values
         * @param {string} searchStr Search string
         * @param {string} dataSource Filter data source
         * @returns {object} $http promise
         */
        function searchFilters(searchStr, dataSource) {
            return $http({
                method: 'POST',
                data: {
                    DataSource: dataSource,
                    Values: 1,
                    Search: searchStr
                },
                url: _this.url + 'Filters?Namespace=' + getNamespace(),
                withCredentials: true
            });
        }

        /**
         * Loads file
         * @returns {object} $http promise
         */
        function getFile(url) {
            return $http({
                method: 'GET',
                data: {},
                url: url,
                withCredentials: true
            });
        }

        /**
         * Requests favorites
         * @returns {object} $http promise
         */
        function getFavorites() {
            return $http({
                method: 'GET',
                data: {},
                url: _this.url + 'Favorites?Namespace=' + getNamespace(),
                withCredentials: true
            });
        }

        /**
         * Adds favorite
         * @param {string} path Favorite path
         * @returns {object} $http promise
         */
        function addFavorite(path) {
            return $http({
                method: 'POST',
                data: {},
                url: _this.url + 'Favorites/'+ encodeURIComponent(path) + '?Namespace=' + getNamespace(),
                withCredentials: true
            });
        }

        /**
         * Deletes favorite
         * @param {string} path Favorite path
         * @returns {object} $http promise
         */
        function deleteFavorite(path) {
            return $http({
                method: 'DELETE',
                data: {},
                url: _this.url + 'Favorites/'+ encodeURIComponent(path) + '?Namespace=' + getNamespace(),
                withCredentials: true
            });
        }

        /**
         * Loads configuration from server
         * @returns {object} $http promise
         */
        function loadConfig(cutomNamespace) {
            return $http({
                method: 'Get',
                data: {},
                url: _this.url + 'Config/DeepSeeWeb?Namespace=' + (cutomNamespace || getNamespace()),
                withCredentials: true
            });
        }

        /**
         * Saves configuration to server
         * @param {object} config Configuration to save
         * @returns {object} $http promise
         */
        function saveConfig(config) {
            return $http({
                method: 'POST',
                data: { Application: "DeepSeeWeb", Config: JSON.stringify(config) },
                url: _this.url + 'Config?Namespace=' + getNamespace(),
                withCredentials: true
            });
        }

        /**
         * Sings in
         * @param {string} login User login
         * @param {string} password User password
         * @param {string} namespace Namespace
         * @returns {object} $http promise
         */
        function signIn(login, password, namespace) {
            _this.username = login;
            return $http({
                method: 'GET',
                url: _this.url + 'Test?Namespace=' + namespace,
                timeout: CONST.timeout,
                headers: {
                    'Authorization': 'Basic ' + btoa(login + ":" + password)
                }
            });
        }

        /**
         * Signs out
         */
        function signOut() {
            _this.firstRun = true;
            //delete sessionStorage.dashboarList;
            $cookieStore.remove("CSPWSERVERID");
            $cookieStore.remove("CacheLoginToken");
            $cookieStore.remove("CSPSESSIONID-SP-80-UP-");

            _this.username = "";
            localStorage.userName = "";

            $location.path("/login").search({});
        }
    }

    angular.module('app')
        .service('Connector', ['$http', 'CONST', '$cookieStore', '$location', '$routeParams', ConnectorSvc]);

})();
<|endoftext|>


<commit_before>import _ from "lodash";
import api from "./api";

const PROP = Symbol("Prop");
const FIELD_KEYS = [
  "title",
  "subtitle",
];

/**
 * The [this] context that is passed into the [describe/it]
 * BDD methods.
 */
export default class UIHarnessContext {
  constructor(type) {
    // Determine whether this is the currently loaded suite.
    const isCurrent = () => {
          const currentSuite = api.current.get("suite");
          return (currentSuite && currentSuite.id === this.suite.id);
        };

    // Read|Write helper for data-property methods.
    const propState = {};
    this[PROP] = (key, value, options = {}) => {
          // WRITE.
          if (!_.isUndefined(value)) {
            propState[key] = value;
            if (isCurrent()) { api.setCurrent({ [key]: value }); }
            return this; // When writing the [this] context is returned.
                         // This allows for chaining of write operations.
          }
          // READ.
          let result = propState[key];
          if (_.isUndefined(result)) { result = options.default; }
          return result
        };
  }

  /**
   * Converts to an object of all current values.
   */
  toValues() {
    const result = {};
    FIELD_KEYS.forEach(key => { result[key] = this[key](); });
    return result;
  }

  /**
   * Gets or sets the display title.
   */
  title(value) { return this[PROP]("title", value, { default: this.suite.name }); }

  /**
   * Gets or sets the sub-title.
   */
  subtitle(value) { return this[PROP]("subtitle", value); }
}
<commit_msg>Rename this context class.<commit_after>import _ from "lodash";
import api from "./api";

const PROP = Symbol("Prop");
const FIELD_KEYS = [
  "title",
  "subtitle",
];

/**
 * The [this] context that is passed into the [describe/it]
 * BDD methods.
 */
export default class UIHarness {
  constructor(type) {
    // Determine whether this is the currently loaded suite.
    const isCurrent = () => {
          const currentSuite = api.current.get("suite");
          return (currentSuite && currentSuite.id === this.suite.id);
        };

    // Read|Write helper for data-property methods.
    const propState = {};
    this[PROP] = (key, value, options = {}) => {
          // WRITE.
          if (!_.isUndefined(value)) {
            propState[key] = value;
            if (isCurrent()) { api.setCurrent({ [key]: value }); }
            return this; // When writing the [this] context is returned.
                         // This allows for chaining of write operations.
          }
          // READ.
          let result = propState[key];
          if (_.isUndefined(result)) { result = options.default; }
          return result
        };
  }

  /**
   * Converts to an object of all current values.
   */
  toValues() {
    const result = {};
    FIELD_KEYS.forEach(key => { result[key] = this[key](); });
    return result;
  }

  /**
   * Gets or sets the display title.
   */
  title(value) { return this[PROP]("title", value, { default: this.suite.name }); }

  /**
   * Gets or sets the sub-title.
   */
  subtitle(value) { return this[PROP]("subtitle", value); }
}
<|endoftext|>


<commit_before>var isNode = typeof module !== 'undefined' && module.exports;

if (isNode) {
	process.once('message', function (code) {
		eval(JSON.parse(code).data);
	});
} else {
	self.onmessage = function (code) {
		eval(code.data);
	};
}<commit_msg>Removed unused eval.js file<commit_after><|endoftext|>


<commit_before>
// This file sets up boxing of javascript native objects into squeak objects
// All relevant classes are enhanced by that functionality and there are
// Several global functions to box or unbox objects.

// Some objects are boxing primitive js-values. Unboxing these values is polymorphic.
// The real version of this method is below. This could alternatively throw an error,
// but we try to be tolerant.
_Object._addInstanceMethods({
	__giveError: function(methodname) {
		var msg = "We have an obsolete " + methodname + "()-call! Fix it.";
		alert(msg);
		throw msg;
	},
	// TODO if we're sure everything is fixed, remove these warnings.
	js: function() {
		this.__giveError("js");
	},
	jsNew_: function() {
		this.__giveError("jsNew:");
	},
	js_: function() {
		this.__giveError("js:");
	},
	slot_be_: function() {
		this.__giveError("slot:be:");
	},
	slot_: function() {
		this.__giveError("slot:");
	},
	slot_apply_: function() {
		this.__giveError("slot:apply:");
	},

	_unbox: function() {
		return this;
	},
	// This never gets called, we just need a true-ish slot in each box-instance
	_isBoxedObject: function() { throw "just access this slot without calling."; }
});

// Class, that will wrap native javascript-objects to implement the Object-interface.
// Additionally, it adds accessor-methods for all fields to provide a squeak-API to
// set slots on javascript-objects.
Class("_Box", { superclass: _DoesNotUnderstandClass_ });

// Functions to bootstrap primitive values and wrap them into 'squeak'-objects
// Most functions are used in translated code directly, to avoid switch-statement in _boxObject()
// (Instead of bool(), compiled code uses _true/_false directly. bool() is used in kernel_primitives.js etc.)
var bool = function(aBool) { if (aBool) { return _true; } else { return _false; } }
var character = function(aString) { return Character._wrapping(aString); }
var string = function(aString) { return ByteString._wrapping(aString); }
var number = function(aNumber) { return Float._wrapping(aNumber); }
var array = function(anArray) { return _Array._wrapping(anArray); }
var object = function(anObject) { return _Box._wrapping(anObject); }
// if we box a javascript function into a smalltalk block we must bind it on creation
// Non-local-return handling is not required here
var boundBlock = function(func, that) {
	var b = BlockClosure._newInstance();
	// This block is unboxed to func, but additional things happen on evaluation
	b.original$ = func;
	b.evaluated$ = function() {
		return _boxObject(func.apply(that, _unboxIterable(arguments)));
	}
	b.constructorArguments$ = function(argumentCollection) {
		// When using a library-function as constructor, unpack the arguments
		return _unboxIterable(argumentCollection);
	}
	return b;
}

// There are multiple js-'classes', that will be wrapped into a Squeak-Array
var arrayConstructors = [Array, NodeList];
var isArrayObject = function(anObject) {
	var constructor = anObject.constructor;
	for (index in arrayConstructors) {
		if (arrayConstructors[index] == constructor) {
			return true;
		}
	}
	return false;
};

// This static unboxing-function is added to avoid adding an _unbox method to native js-objects
var _unboxObject = function(anyObject) {
	if (anyObject._isBoxedObject) {
		return anyObject._unbox();
	}
	return anyObject;
};
var _unboxIterable = function(iterable) {
	var unboxed = [];
	for (index in iterable) {
		unboxed.push(_unboxObject(iterable[index]));
	}
	return unboxed;
}
// The 'that' parameter is optional and will be undefined otherwise
// It is relevant for functions, to bind them to their containing object when invoking them.
var _boxObject = function(nativeObject, that) {
	if (nativeObject === null || nativeObject === undefined) {
		return nil;
	}
	if (!nativeObject._isBoxedObject) {
		switch( typeof(nativeObject) ) {
			case "number": return number(nativeObject); break;
			case "string": return string(nativeObject); break;
			case "boolean": return bool(nativeObject); break;
			case "function": return boundBlock(nativeObject, that); break;
			case "object":
				if (isArrayObject(nativeObject)) {
					return array(nativeObject);
				} else {
					return object(nativeObject);
				}
				break;
			default:
				alert("Could not box creepy object: " + nativeObject);
		}
    }
	// nativeObject is already boxed!
	return nativeObject;
};
var _boxIterable = function(iterable) {
	var boxed = [];
	for (index in iterable) {
		boxed.push(_boxObject(iterable[index]));
	}
	return boxed;
}

// These boxing classes box fixed, immutable values
False._addInstanceMethods( { _unbox: function() { return false; } } );
True._addInstanceMethods( { _unbox: function() { return true; } } );
UndefinedObject._addInstanceMethods( { _unbox: function() { return null; } } );

// These boxing classes box variable values and are all added the same functionality.
var boxingClasses = [_Box, ByteString, _Number, Character, BlockClosure, _Array];
for (index in boxingClasses) {
	var aClass = boxingClasses[index];
	aClass._addClassMethods({
		_wrapping: function(originalObject) {
			var result = this._newInstance(); // Polymorphic for different kinds of boxes
			result.original$ = originalObject;
			return result;
		}
	});
	aClass._addInstanceMethods({
		_hiddenGetter_: function(slotName) {
			return this.original$[slotName];
		},
		doesNotUnderstand_: function(aMessage) {
			var methodName = _unboxObject(aMessage.selector());
			if (methodName[methodName.length - 1] == ':') {
				// setter. Set the unboxed, native-js, value.
				var value = aMessage._arguments();
				if (value.length >= 1) // If more then one argument, ignore the rest!
					value = value[0];
				else // No arguments given when invoking setter!? Don't set an empty array.
					value = undefined;

				this.original$[methodName.substring(0, methodName.length - 1)] = _unboxObject(value);
				return value;
			} else {
				// getter. Second parameter relevant, if slot contains a function.
				// For most boxing classes, the javascript-native is hidden totally (this implementation).
				// _Box refines this method (_hiddenGetter_) to also check the underlying original$ for the slot
				// An example is the slot 'value', which is important on a DOM-TextArea and also implemented in Object
				return _boxObject(this._hiddenGetter_(methodName), this.original$);
			}
		},
		_unbox: function() {
			return this.original$;
		}
	});
}
_Box._addClassMethods({
	_wrapping: function(originalObject) {
		// In addition to the default original$-slot, also create a dummy-Object-instance.
		// This is a hack to implement the Object-protocol in a _Box. _Box inherits from _DoesNotUnderstandClass_,
		// so it does not implement any of Object's methods (to be able to fully access the underlying native object).
		// If the underlying object does not contain a certain slot, the method is invoked on the dummy-instance instead.
		// This way we have methods like #hash and #ifNil:ifNotNil: on boxed native objects.
		var result = _super("_wrapping")(originalObject);
		result.proxiedObject$ = _Object._newInstance();
		return result;
	}
});
_Box._addInstanceMethods({
	_hiddenGetter_: function(slotName) {
		var result = this.original$[slotName];
		// First check, if the underlying object has this slot.
		if (result != undefined) {
			if (typeof(result) == "function") {
				result = result();
			}
		} else {
			// If not, invoke it on our 'proxiedObject' to implement the Object-protocol of Squeak.
			// As this covers onle 'getters', invoke without arguments
			result = this.proxiedObject$[slotName]();
		}
		return result;
	}
});

BlockClosure._addInstanceMethods ( {
	_unbox: function() {
		var originalBlock = this.original$;
		return function () {
			var boxedArguments = new Array(arguments.length);
			for (var i=0; i <arguments.length ; i++) {
				boxedArguments[i] = _boxObject(arguments[i]);
			}
			return originalBlock.apply(this, boxedArguments )  }
	}
});
<commit_msg>fixes in boxing<commit_after>
// This file sets up boxing of javascript native objects into squeak objects
// All relevant classes are enhanced by that functionality and there are
// Several global functions to box or unbox objects.

// Some objects are boxing primitive js-values. Unboxing these values is polymorphic.
// The real version of this method is below. This could alternatively throw an error,
// but we try to be tolerant.
_Object._addInstanceMethods({
	__giveError: function(methodname) {
		var msg = "We have an obsolete " + methodname + "()-call! Fix it.";
		alert(msg);
		throw msg;
	},
	// TODO if we're sure everything is fixed, remove these warnings.
	js: function() {
		this.__giveError("js");
	},
	jsNew_: function() {
		this.__giveError("jsNew:");
	},
	js_: function() {
		this.__giveError("js:");
	},
	slot_be_: function() {
		this.__giveError("slot:be:");
	},
	slot_: function() {
		this.__giveError("slot:");
	},
	slot_apply_: function() {
		this.__giveError("slot:apply:");
	},

	_unbox: function() {
		return this;
	},
	// This never gets called, we just need a true-ish slot in each box-instance
	_isBoxedObject: function() { throw "just access this slot without calling."; }
});

// Class, that will wrap native javascript-objects to implement the Object-interface.
// Additionally, it adds accessor-methods for all fields to provide a squeak-API to
// set slots on javascript-objects.
Class("_Box", { superclass: _DoesNotUnderstandClass_ });

// Functions to bootstrap primitive values and wrap them into 'squeak'-objects
// Most functions are used in translated code directly, to avoid switch-statement in _boxObject()
// (Instead of bool(), compiled code uses _true/_false directly. bool() is used in kernel_primitives.js etc.)
var bool = function(aBool) { if (aBool) { return _true; } else { return _false; } }
var character = function(aString) { return Character._wrapping(aString); }
var string = function(aString) { return ByteString._wrapping(aString); }
var number = function(aNumber) { return Float._wrapping(aNumber); }
var array = function(anArray) { return _Array._wrapping(anArray); }
var object = function(anObject) { return _Box._wrapping(anObject); }
// if we box a javascript function into a smalltalk block we must bind it on creation
// Non-local-return handling is not required here
var boundBlock = function(func, that) {
	var b = BlockClosure._newInstance();
	// This block is unboxed to func, but additional things happen on evaluation
	b.original$ = func;
	b.evaluated$ = function() {
		return _boxObject(func.apply(that, _unboxIterable(arguments)));
	}
	b.constructorArguments$ = function(argumentCollection) {
		// When using a library-function as constructor, unpack the arguments
		return _unboxIterable(argumentCollection);
	}
	return b;
}

// There are multiple js-'classes', that will be wrapped into a Squeak-Array
var arrayConstructors = [Array, NodeList];
var isArrayObject = function(anObject) {
	var constructor = anObject.constructor;
	for (index in arrayConstructors) {
		if (arrayConstructors[index] == constructor) {
			return true;
		}
	}
	return false;
};

// This static unboxing-function is added to avoid adding an _unbox method to native js-objects
var _unboxObject = function(anyObject) {
	if (anyObject._isBoxedObject) {
		return anyObject._unbox();
	}
	return anyObject;
};
var _unboxIterable = function(iterable) {
	var unboxed = [];
	for (index in iterable) {
		unboxed.push(_unboxObject(iterable[index]));
	}
	return unboxed;
}
// The 'that' parameter is optional and will be undefined otherwise
// It is relevant for functions, to bind them to their containing object when invoking them.
var _boxObject = function(nativeObject, that) {
	if (nativeObject === null || nativeObject === undefined) {
		return nil;
	}
	if (!nativeObject._isBoxedObject) {
		switch( typeof(nativeObject) ) {
			case "number": return number(nativeObject); break;
			case "string": return string(nativeObject); break;
			case "boolean": return bool(nativeObject); break;
			case "function": return boundBlock(nativeObject, that); break;
			case "object":
				if (isArrayObject(nativeObject)) {
					return array(nativeObject);
				} else {
					return object(nativeObject);
				}
				break;
			default:
				alert("Could not box creepy object: " + nativeObject);
		}
    }
	// nativeObject is already boxed!
	return nativeObject;
};
var _boxIterable = function(iterable) {
	var boxed = [];
	for (index in iterable) {
		boxed.push(_boxObject(iterable[index]));
	}
	return boxed;
}

// These boxing classes box fixed, immutable values
False._addInstanceMethods( { _unbox: function() { return false; } } );
True._addInstanceMethods( { _unbox: function() { return true; } } );
UndefinedObject._addInstanceMethods( { _unbox: function() { return null; } } );

// This DummyClass implements doesNotUnderstand: returning nil. This enables correct behaviour
// Of the _Box-class. An instance of _Box needs an instance of such a Dummy to implement the Object-interface.
// This Dummy-instance is invoked, if the original$-object does not have the queried slot.
Class("_DummyClass", {superclass: _Object, instanceMethods: { doesNotUnderstand_: function() { return nil; }}});
var _wrappingImpl = function(originalObject) {
	var result = this._newInstance(); // Polymorphic for different kinds of boxes
	result.original$ = originalObject;
	return result;
};
// These boxing classes box variable values and are all added the same functionality.
var boxingClasses = [_Box, ByteString, _Number, Character, BlockClosure, _Array];
for (index in boxingClasses) {
	var aClass = boxingClasses[index];
	aClass._addClassMethods({
		_wrapping: _wrappingImpl
	});
	aClass._addInstanceMethods({
		_hiddenGetter_: function(slotName) {
			return this.original$[slotName];
		},
		doesNotUnderstand_: function(aMessage) {
			var methodName = _unboxObject(aMessage.selector());
			if (methodName[methodName.length - 1] == ':') {
				// setter. Set the unboxed, native-js, value.
				var value = aMessage._arguments();
				if (value.length >= 1) // If more then one argument, ignore the rest!
					value = value[0];
				else // No arguments given when invoking setter!? Don't set an empty array.
					value = undefined;

				this.original$[methodName.substring(0, methodName.length - 1)] = _unboxObject(value);
				return value;
			} else {
				// getter. Second parameter relevant, if slot contains a function.
				// For most boxing classes, the javascript-native is hidden totally (this implementation).
				// _Box refines this method (_hiddenGetter_) to also check the underlying original$ for the slot
				// An example is the slot 'value', which is important on a DOM-TextArea and also implemented in Object
				return _boxObject(this._hiddenGetter_(methodName), this.original$);
			}
		},
		_unbox: function() {
			return this.original$;
		}
	});
}
_Box._addClassMethods({
	_wrapping: function(originalObject) {
		// In addition to the default original$-slot, also create a dummy-Object-instance.
		// This is a hack to implement the Object-protocol in a _Box. _Box inherits from _DoesNotUnderstandClass_,
		// so it does not implement any of Object's methods (to be able to fully access the underlying native object).
		// If the underlying object does not contain a certain slot, the method is invoked on the dummy-instance instead.
		// This way we have methods like #hash and #ifNil:ifNotNil: on boxed native objects.
		var result = _wrappingImpl.apply(this, arguments);
		result.dummyObject$ = _DummyClass._newInstance();
		return result;
	}
});
_Box._addInstanceMethods({
	_hiddenGetter_: function(slotName) {
		var result = this.original$[slotName];
		// First check, if the underlying object has this slot.
		// If not, try to invoke the corresponding Method implemented on Object (e.g. ifNil:ifNotNil:)
		// If this is not present, return nil.
		if (result === undefined) {
			// If not, invoke it on our 'dummyObject' to implement the Object-protocol of Squeak.
			// As this covers only 'getters', invoke without arguments.
			// This returns nil, if there is no such method. This corresponds to the javascript-behaviour,
			// when querying a slot, that is not present.
			result = this.dummyObject$[slotName]();
		}
		return result;
	}
});
<|endoftext|>


<commit_before>updateHeight = function () {
  highlightChannel();
  var body_height = $('body').height();
  var final_height = body_height - 90;
  $('#chat, #chat-channel-users, #chat-main, #chat-servers').height(final_height);
  $('#chat-logs-container').height(final_height - $('#chat-main .topic').height() - 24);
}

Template.chat_connections.servers = function () {
  return UserServers.find();
}

Template.server_channels.channels = function (server_id) {
  return UserChannels.find({user_server_id: server_id, active: true});
}

Template.chat.rendered = function () {
  $('.content-main').addClass('no-padding');
}

function  highlightChannel () {
  var room_id = Session.get('room_id');
  var server_id = Session.get('server_id');
  $('#server-' + server_id).find('.dropdown.active').removeClass('active');
  $('.server-room').parent().removeClass('active');
  if (Session.get('roomtype') == 'channel')
    $('.server-room#channel-id-' + room_id).parent().addClass('active');
  else if (Session.get('roomtype') == 'pm')
    $('.server-room#' + room_id).parent().addClass('active');
  else if (Session.get('roomtype') == 'server')
    $('#server-' + server_id + ' ul.server-link-ul li:first').addClass('active');
  $('#chat-input').focus();
  refreshAutocompleteNicksSource();
}

Template.chat_main.chat_logs = function () {
  var room_id = Session.get('room_id');
  if (Session.get('roomtype') == 'channel') {
    return UserChannelLogs.find({channel_id: room_id});
  } else if (Session.get('roomtype') == 'pm') {
    var nick = room_id.substr(room_id.indexOf('-') + 1);
    return PMLogs.find({
      $or: [
        {from: nick, to_user_id: Meteor.user()._id},
        {from_user_id: Meteor.user()._id, to: nick}
      ]
    });
  } else if (Session.get('roomtype') == 'server') {
    var server_id = Session.get('room_id');
    return UserServerLogs.find({server_id: server_id});
  }

}

Template.chat_main.topic = function () {
  try {
    var channel = UserChannels.findOne({_id: Session.get('room_id')});
    if (channel) {
      return channel.topic || "";
    }
  } catch (err) {
    return "";
  }
};

Template.chat_main.rendered = updateHeight;

Template.chat_main.events = {
  'scroll #chat-logs-container': function (event) {
    var scroll_top = $(event.target).scrollTop();
    var room_id = Session.get('room_id');
    if ((event.target.scrollHeight - scroll_top) <= $(this).outerHeight())
      scroll_top = null;
    if (Session.get('roomtype') == 'channel')
      Session.set('scroll_height_channel-' + room_id,
        scroll_top);
    else if (Session.get('roomtype') == 'pm')
      Session.set('scroll_height_' + room_id,
        scroll_top);
    else if (Session.get('roomtype') == 'server')
      Session.set('scroll_height_server-' + Session.get('server_id'),
        scroll_top);

  }
};

function autocompleteNicksInitiate () {
  function split (val) {
    return val.split(/(^|[\ ]+)@/ );
  }

  function extractLast ( term ) {
    return split(term).pop();
  }

  $('#chat-input')
    .bind('keydown', function (event) {
      if ( event.keyCode === $.ui.keyCode.TAB &&
            $( this ).data( "ui-autocomplete" ).menu.active ) {
          event.preventDefault();
      }
    })
    .autocomplete({
      autoFocus: true,
      minLength: 1,
      source: function( request, response ) {
        // delegate back to autocomplete, but extract the last term
        response( $.ui.autocomplete.filter(
          getChannelNicks(), extractLast( request.term ) ) );
      },
      search: function (event, ui) {
        var $input = $('#chat-input');
        var val = $input.val() || "";
        if (val.split(' ').length == 1 && val.length >= 1 && val[0] != '@')
          return false;
      },
      focus: function() {
        // prevent value inserted on focus
        return false;
      },
      select: function( event, ui ) {
        var terms = split( this.value );
        // remove the current input
        terms.pop();
        // add the selected item
        terms.push( ui.item.value );
        this.value = terms.join( "" );
        if (this.value.length >= 1 && this.value[0] == "")
          this.value = this.value.substr(1);
        return false;
      },
      open: function($event, ui) {
          var $widget = $("ul.ui-autocomplete");
          var $input = $("#chat-input");
          var position = $input.position();

          var top_offset = $widget.find('li').length * 24;
          if (top_offset > 200)
            top_offset = 200;
          $("#chat-input-form").append($widget);
          $widget.width('auto')
            .css('max-height', 200)
            .css('overflow', 'auto')
            .css("left", position.left + $input.val().length * 6)
            .css("bottom", 36)
            .css("top", - top_offset - 2);
      }
    });
}

function refreshAutocompleteNicksSource () {
  $('chat-input').autocomplete('option', 'source', getChannelNicks());
}

function getChannelNicks () {
  var channel_nicks = [];
  var channel = UserChannels.findOne({_id: Session.get('room_id')}) || {};
  for (var nick in channel.nicks || {})
    channel_nicks.push(nick);
  return channel_nicks;
}

function serverRoomSelectHandler (event) {
    var $target = $(event.target);
    if ($target.hasClass('caret') || $target.hasClass('dropdown-caret'))
      return;
    event.stopPropagation();
    $('.dropdown.open').removeClass('open');
    var prev_room_id = Session.get('room_id');
    var prefix = '';
    var prev_roomtype = Session.get('roomtype');
    if (prev_roomtype == 'server' || prev_roomtype == 'channel')
      prefix = prev_roomtype + '-';
    Session.set('scroll_height_' + prefix + prev_room_id, $('#chat-logs-container').scrollTop() || null);
    if ($target.data('roomtype') == 'channel') {
      var server_id = $target.parents('.server').data('server-id');
      Session.set('server_id', server_id);
      Session.set('roomtype', 'channel');
      Session.set('room_id', $(event.target).data('id'));
      channel_nicks = getChannelNicks();
    } else if ($target.data('roomtype') == 'pm') {
      var server_id = $target.parents('.server').data('server-id');
      Session.set('server_id', server_id);
      Session.set('roomtype', 'pm');
      Session.set('room_id', $target.attr('id'));
    } else if ($target.data('roomtype') == 'server' || $target.parent().data('roomtype') == 'server') {
      Session.set('room_id', $target.parent().data('server-id') || $target.data('server-id'));
      Session.set('server_id', Session.get('room_id'));
      Session.set('roomtype', 'server');
    }
    highlightChannel();
}

Template.chat_connections.events({
  'click .server-room': serverRoomSelectHandler,
  'click .server-link': serverRoomSelectHandler
});

Template.server_pms.pms = function (id) {
  var server = UserServers.findOne({_id: id});
  var user = Meteor.user();
  var pms = user.profile.connections[id].pms;
  var return_pms = [];
  for (nick in pms)
    return_pms.push({name: nick, server_id: server._id});
  return return_pms;
}

function chatUserClickHandler (event) {
    if ($(event.target).hasClass('caret'))
      return;
    event.stopPropagation();
    $('.channel-user').parent().removeClass('active');
    $('.dropdown.open').removeClass('open');
    $(event.target).parent().addClass('active');
}

Template.server_channels.rendered = updateHeight;

Template.chat_users.channel_users = function () {
  if (Session.get('roomtype') == 'channel') {
    var channel_id = Session.get('room_id');
    var channel = UserChannels.findOne({_id: channel_id});
    var nicks = {};
    if (channel)
      nicks = channel.nicks || {};
    var nicks_list = [];
    for (var key in nicks)
      nicks_list.push({name: key, status: nicks.key})
    return nicks_list;
  } else
    return [];
};

Template.chat_users.rendered = updateHeight;

Template.chat_main.rendered = function () {
  setTimeout(function () {
    updateHeight();
    var roomtype = Session.get('roomtype');
    var key = '';
    var room_id = Session.get('room_id');
    if (roomtype == 'channel')
      key = 'scroll_height_channel-' + room_id;
    else if (roomtype == 'pm')
      key = 'scroll_height_' + room_id;
    else if (roomtype == 'server')
      key = 'scroll_height_server-' + room_id;
    var chat_height = Session.get(key);
    $('#chat-logs-container').scrollTop(chat_height || $('#chat-logs').height());
  }, 0);
};

Template.chat_main.destroyed = function () {
  var roomtype = Session.get('roomtype');
  if (roomtype == 'server' || roomtype == 'channel') {
    prefix = roomtype + '-';
    Session.set('scroll_height_' + prefix + Session.get('room_id'), $('#chat-logs-container').scrollTop());
  }
};

Client = {};

Meteor.subscribe("client", Meteor.user() && Meteor.user().username);

Template.chat_input.events({
  'keydown #chat-input': function (e) {
    var keyCode = e.keyCode || e.which;
    if (keyCode == 9)
      e.preventDefault();
  },
  'submit #chat-input-form': function (event) {
    event.preventDefault();
    var $form = $(event.target);
    var $chat_input = $form.find('#chat-input');
    var message = $chat_input.val();
    try {
      var myNick = (Meteor.user().profile.connections[Session.get(
        'server_id')]['client_data'] || {})['nick'] || Meteor.user().username;
    } catch (err) {
      console.log(err);
      var myNick = null;
    }
    if (!message)
      return;
    $chat_input.val('');
    var prefix = '';
    if (Session.get('roomtype') == 'channel') {
      var room_id = Session.get('room_id');
      var channel = UserChannels.findOne({_id: room_id});
      prefix = 'channel-';
      UserChannelLogs.insert({
        from: myNick || Meteor.user().username,
        user_id: Meteor.user()._id,
        channel: channel.name,
        channel_id: room_id,
        message: message,
        time: new Date(),
      });
      Meteor.call('send_channel_message', channel._id, message);
    } else if (Session.get('roomtype') == 'pm') {
      var room_id = Session.get('room_id');
      var nick = room_id.substr(room_id.indexOf('-') + 1);
      PMLogs.insert({
        from: myNick || Meteor.user().username,
        from_user_id: Meteor.user()._id,
        to: nick,
        message: message,
        time: new Date(),
      });
      Meteor.call('send_pm', message, room_id)
    } else if (Session.get('roomtype') == 'server') {
      var room_id = 'server-' + Session.get('server_id');
      prefix = 'server-';
    }
    Session.set('scroll_height_' + prefix + room_id, null);
  }
});

Template.user_menu.events = {
  'click .pm-user': function (event) {
    var $target = $(event.target);
    var nick = $target.data('user-nick');
    var user = Meteor.user();
    var server_id = Session.get('server_id');
    var profile = user.profile;
    if (!profile) {
      profile = {connections: {}};
      profile.connections[server_id] = {pms: {}};
    }
    if (!profile.connections[server_id].pms)
      profile.connections[server_id].pms = {};
    profile.connections[server_id].pms[nick] = '';
    Meteor.users.update({_id: user._id}, {$set: {profile: profile}});
    Session.set('roomtype', 'pm');
    Session.set('room_id', Session.get('server_id') + '-' + nick);
  },
  'click .channel-user': chatUserClickHandler,
};

Template.chat_input.rendered = function () {
  autocompleteNicksInitiate();
}

Template.channel_menu.events = {
  'click .channel-remove': function (e) {
    var channel_id = $(e.target).data("channel-id");
    var channel = UserChannels.findOne({_id: channel_id});
    Meteor.call("part_user_channel", channel.user_server_name, channel.name);
  }
}

Template.server_pm_menu.events = {
  'click .pm-remove': function (e) {
    var user = Meteor.user();
    var pm_id = $(e.target).parents('li').find(
      '.pm.server-room').attr('id');
    var user_server_id = pm_id.split('-')[0];
    var nick = pm_id.split('-')[1];
    var profile = user.profile;
    var pms = user.profile.connections[user_server_id].pms;
    delete pms[nick];
    Meteor.users.update({_id: user._id}, {$set: {profile: profile}});
  }
}
<commit_msg>Bugfix in user selection from nick list.<commit_after>updateHeight = function () {
  highlightChannel();
  var body_height = $('body').height();
  var final_height = body_height - 90;
  $('#chat, #chat-channel-users, #chat-main, #chat-servers').height(final_height);
  $('#chat-logs-container').height(final_height - $('#chat-main .topic').height() - 24);
}

Template.chat_connections.servers = function () {
  return UserServers.find();
}

Template.server_channels.channels = function (server_id) {
  return UserChannels.find({user_server_id: server_id, active: true});
}

Template.chat.rendered = function () {
  $('.content-main').addClass('no-padding');
}

function  highlightChannel () {
  var room_id = Session.get('room_id');
  var server_id = Session.get('server_id');
  $('#server-' + server_id).find('.dropdown.active').removeClass('active');
  $('.server-room').parent().removeClass('active');
  if (Session.get('roomtype') == 'channel')
    $('.server-room#channel-id-' + room_id).parent().addClass('active');
  else if (Session.get('roomtype') == 'pm')
    $('.server-room#' + room_id).parent().addClass('active');
  else if (Session.get('roomtype') == 'server')
    $('#server-' + server_id + ' ul.server-link-ul li:first').addClass('active');
  $('#chat-input').focus();
  refreshAutocompleteNicksSource();
}

Template.chat_main.chat_logs = function () {
  var room_id = Session.get('room_id');
  if (Session.get('roomtype') == 'channel') {
    return UserChannelLogs.find({channel_id: room_id});
  } else if (Session.get('roomtype') == 'pm') {
    var nick = room_id.substr(room_id.indexOf('-') + 1);
    return PMLogs.find({
      $or: [
        {from: nick, to_user_id: Meteor.user()._id},
        {from_user_id: Meteor.user()._id, to: nick}
      ]
    });
  } else if (Session.get('roomtype') == 'server') {
    var server_id = Session.get('room_id');
    return UserServerLogs.find({server_id: server_id});
  }

}

Template.chat_main.topic = function () {
  try {
    var channel = UserChannels.findOne({_id: Session.get('room_id')});
    if (channel) {
      return channel.topic || "";
    }
  } catch (err) {
    return "";
  }
};

Template.chat_main.rendered = updateHeight;

Template.chat_main.events = {
  'scroll #chat-logs-container': function (event) {
    var scroll_top = $(event.target).scrollTop();
    var room_id = Session.get('room_id');
    if ((event.target.scrollHeight - scroll_top) <= $(this).outerHeight())
      scroll_top = null;
    if (Session.get('roomtype') == 'channel')
      Session.set('scroll_height_channel-' + room_id,
        scroll_top);
    else if (Session.get('roomtype') == 'pm')
      Session.set('scroll_height_' + room_id,
        scroll_top);
    else if (Session.get('roomtype') == 'server')
      Session.set('scroll_height_server-' + Session.get('server_id'),
        scroll_top);

  }
};

function autocompleteNicksInitiate () {
  function split (val) {
    return val.split(/(^|[\ ]+)@/ );
  }

  function extractLast ( term ) {
    return split(term).pop();
  }

  $('#chat-input')
    .bind('keydown', function (event) {
      if ( event.keyCode === $.ui.keyCode.TAB &&
            $( this ).data( "ui-autocomplete" ).menu.active ) {
          event.preventDefault();
      }
    })
    .autocomplete({
      autoFocus: true,
      minLength: 1,
      source: function( request, response ) {
        // delegate back to autocomplete, but extract the last term
        response( $.ui.autocomplete.filter(
          getChannelNicks(), extractLast( request.term ) ) );
      },
      search: function (event, ui) {
        var $input = $('#chat-input');
        var val = $input.val() || "";
        if (val.split(' ').length == 1 && val.length >= 1 && val[0] != '@')
          return false;
      },
      focus: function() {
        // prevent value inserted on focus
        return false;
      },
      select: function( event, ui ) {
        var terms = split( this.value );
        // remove the current input
        terms.pop();
        // add the selected item
        terms.push( ui.item.value );
        this.value = terms.join( "" );
        if (this.value.length >= 1 && this.value[0] == "")
          this.value = this.value.substr(1);
        return false;
      },
      open: function($event, ui) {
          var $widget = $("ul.ui-autocomplete");
          var $input = $("#chat-input");
          var position = $input.position();

          var top_offset = $widget.find('li').length * 24;
          if (top_offset > 200)
            top_offset = 200;
          $("#chat-input-form").append($widget);
          $widget.width('auto')
            .css('max-height', 200)
            .css('overflow', 'auto')
            .css("left", position.left + $input.val().length * 6)
            .css("bottom", 36)
            .css("top", - top_offset - 2);
      }
    });
}

function refreshAutocompleteNicksSource () {
  $('chat-input').autocomplete('option', 'source', getChannelNicks());
}

function getChannelNicks () {
  var channel_nicks = [];
  var channel = UserChannels.findOne({_id: Session.get('room_id')}) || {};
  for (var nick in channel.nicks || {})
    channel_nicks.push(nick);
  return channel_nicks;
}

function serverRoomSelectHandler (event) {
    var $target = $(event.target);
    if ($target.hasClass('caret') || $target.hasClass('dropdown-caret'))
      return;
    event.stopPropagation();
    $('.dropdown.open').removeClass('open');
    var prev_room_id = Session.get('room_id');
    var prefix = '';
    var prev_roomtype = Session.get('roomtype');
    if (prev_roomtype == 'server' || prev_roomtype == 'channel')
      prefix = prev_roomtype + '-';
    Session.set('scroll_height_' + prefix + prev_room_id, $('#chat-logs-container').scrollTop() || null);
    if ($target.data('roomtype') == 'channel') {
      var server_id = $target.parents('.server').data('server-id');
      Session.set('server_id', server_id);
      Session.set('roomtype', 'channel');
      Session.set('room_id', $(event.target).data('id'));
      channel_nicks = getChannelNicks();
    } else if ($target.data('roomtype') == 'pm') {
      var server_id = $target.parents('.server').data('server-id');
      Session.set('server_id', server_id);
      Session.set('roomtype', 'pm');
      Session.set('room_id', $target.attr('id'));
    } else if ($target.data('roomtype') == 'server' || $target.parent().data('roomtype') == 'server') {
      Session.set('room_id', $target.parent().data('server-id') || $target.data('server-id'));
      Session.set('server_id', Session.get('room_id'));
      Session.set('roomtype', 'server');
    }
    highlightChannel();
}

Template.chat_connections.events({
  'click .server-room': serverRoomSelectHandler,
  'click .server-link': serverRoomSelectHandler
});

Template.server_pms.pms = function (id) {
  var server = UserServers.findOne({_id: id});
  var user = Meteor.user();
  var pms = user.profile.connections[id].pms;
  var return_pms = [];
  for (nick in pms)
    return_pms.push({name: nick, server_id: server._id});
  return return_pms;
}

function chatUserClickHandler (event) {
    if ($(event.target).hasClass('caret'))
      return;
    event.stopPropagation();
    $('.channel-user').parent().removeClass('active');
    $('.dropdown.open').removeClass('open');
    $(event.target).parent().addClass('active');
}

Template.server_channels.rendered = updateHeight;

Template.chat_users.channel_users = function () {
  if (Session.get('roomtype') == 'channel') {
    var channel_id = Session.get('room_id');
    var channel = UserChannels.findOne({_id: channel_id});
    var nicks = {};
    if (channel)
      nicks = channel.nicks || {};
    var nicks_list = [];
    for (var key in nicks)
      nicks_list.push({name: key, status: nicks.key})
    return nicks_list;
  } else
    return [];
};

Template.chat_users.rendered = updateHeight;

Template.chat_main.rendered = function () {
  setTimeout(function () {
    updateHeight();
    var roomtype = Session.get('roomtype');
    var key = '';
    var room_id = Session.get('room_id');
    if (roomtype == 'channel')
      key = 'scroll_height_channel-' + room_id;
    else if (roomtype == 'pm')
      key = 'scroll_height_' + room_id;
    else if (roomtype == 'server')
      key = 'scroll_height_server-' + room_id;
    var chat_height = Session.get(key);
    $('#chat-logs-container').scrollTop(chat_height || $('#chat-logs').height());
  }, 0);
};

Template.chat_main.destroyed = function () {
  var roomtype = Session.get('roomtype');
  if (roomtype == 'server' || roomtype == 'channel') {
    prefix = roomtype + '-';
    Session.set('scroll_height_' + prefix + Session.get('room_id'), $('#chat-logs-container').scrollTop());
  }
};

Client = {};

Meteor.subscribe("client", Meteor.user() && Meteor.user().username);

Template.chat_input.events({
  'keydown #chat-input': function (e) {
    var keyCode = e.keyCode || e.which;
    if (keyCode == 9)
      e.preventDefault();
  },
  'submit #chat-input-form': function (event) {
    event.preventDefault();
    var $form = $(event.target);
    var $chat_input = $form.find('#chat-input');
    var message = $chat_input.val();
    try {
      var myNick = (Meteor.user().profile.connections[Session.get(
        'server_id')]['client_data'] || {})['nick'] || Meteor.user().username;
    } catch (err) {
      console.log(err);
      var myNick = null;
    }
    if (!message)
      return;
    $chat_input.val('');
    var prefix = '';
    if (Session.get('roomtype') == 'channel') {
      var room_id = Session.get('room_id');
      var channel = UserChannels.findOne({_id: room_id});
      prefix = 'channel-';
      UserChannelLogs.insert({
        from: myNick || Meteor.user().username,
        user_id: Meteor.user()._id,
        channel: channel.name,
        channel_id: room_id,
        message: message,
        time: new Date(),
      });
      Meteor.call('send_channel_message', channel._id, message);
    } else if (Session.get('roomtype') == 'pm') {
      var room_id = Session.get('room_id');
      var nick = room_id.substr(room_id.indexOf('-') + 1);
      PMLogs.insert({
        from: myNick || Meteor.user().username,
        from_user_id: Meteor.user()._id,
        to: nick,
        message: message,
        time: new Date(),
      });
      Meteor.call('send_pm', message, room_id)
    } else if (Session.get('roomtype') == 'server') {
      var room_id = 'server-' + Session.get('server_id');
      prefix = 'server-';
    }
    Session.set('scroll_height_' + prefix + room_id, null);
  }
});

Template.chat_users.events = {
  'click .channel-user': chatUserClickHandler,
};

Template.user_menu.events = {
  'click .pm-user': function (event) {
    var $target = $(event.target);
    var nick = $target.data('user-nick');
    var user = Meteor.user();
    var server_id = Session.get('server_id');
    var profile = user.profile;
    if (!profile) {
      profile = {connections: {}};
      profile.connections[server_id] = {pms: {}};
    }
    if (!profile.connections[server_id].pms)
      profile.connections[server_id].pms = {};
    profile.connections[server_id].pms[nick] = '';
    Meteor.users.update({_id: user._id}, {$set: {profile: profile}});
    Session.set('roomtype', 'pm');
    Session.set('room_id', Session.get('server_id') + '-' + nick);
  },
};

Template.chat_input.rendered = function () {
  autocompleteNicksInitiate();
}

Template.channel_menu.events = {
  'click .channel-remove': function (e) {
    var channel_id = $(e.target).data("channel-id");
    var channel = UserChannels.findOne({_id: channel_id});
    Meteor.call("part_user_channel", channel.user_server_name, channel.name);
  }
}

Template.server_pm_menu.events = {
  'click .pm-remove': function (e) {
    var user = Meteor.user();
    var pm_id = $(e.target).parents('li').find(
      '.pm.server-room').attr('id');
    var user_server_id = pm_id.split('-')[0];
    var nick = pm_id.split('-')[1];
    var profile = user.profile;
    var pms = user.profile.connections[user_server_id].pms;
    delete pms[nick];
    Meteor.users.update({_id: user._id}, {$set: {profile: profile}});
  }
}
<|endoftext|>


<commit_before>$(document).ready(function() {
	function putTaskNextChild(task, target) {
		task.insertAfter(target.closest(".task-list > *"))
			.show();
	}

	function createTaskId() {
		var id;
		if (localStorage.getItem("task-id") == null)
			id = 1;
		else
			id = 1 + parseInt(localStorage.getItem("task-id"));
		localStorage.setItem("task-id", id);
		return "task-" + id;
	}

	function getParent(task) {
		return task.parents(".task").first();
	}

	function createTask(id) {
		id = (typeof(id) != "undefined") ? id : createTaskId();

		var task = $("#prototype > .task")
			.clone(deepWithDataAndEvents=true)
			.attr("id", id)
			.draggable({
				handle: "> .task-title",
				revert: "invalid",
				revertDuration: 100,
			});
		task.find(".task-add-child,.task-add-next")
			.droppable({
				hoverClass: "ui-state-highlight",
				drop: function(e, ui) {
					// TODO: There should be a better way to do this
					$(ui.draggable).css({top:0,left:0});

					var oldParentTask = getParent($(ui.draggable));
					putTaskNextChild($(ui.draggable), $(this));
					saveTask(oldParentTask);
					saveTask(getParent($(ui.draggable)));
				}
			});
		return task;
	}

	function saveTask(task) {
		localStorage.setItem(task.attr("id"), JSON.stringify({
			title: task.children(".task-title").text(),
			children: _.map(task.find("> .task-list > .task"), function(x){return $(x).attr("id")})
		}));
	}

	function removeTask(task) {
		_.each(task.find("> .task-list > .task"), function(child) { removeTask($(child))});
		localStorage.removeItem(task.attr("id"));
	}

	$("#task-add").keypress(function(e) {
		if (e.keyCode == 13 && $("#task-add").val().trim() != "") {
			var task = createTask().appendTo("#task-root-list");
			task.find(".task-title")
					.text($("#task-add").val())
			task.show();
			saveTask(task);
			saveTask($("#task-root"));
			$("#task-add").val("");
		}
	});

	$(".task-close").click(function(e) {
		var task = $(e.currentTarget).closest(".task");
		var parentTask = getParent(task);
		removeTask(task);
		task.remove();
		saveTask(parentTask);
	});

	$(".task-add-child,.task-add-next").click(function(e) {
		var task = createTask();
		putTaskNextChild(task, $(e.currentTarget));
		saveTask(getParent(task));
		saveTask(task);
	});

	// TODO: make this work with drag/drop
	// we want this to be either on mouseup or as a drag/drop callback?
	// only have a single instance that moves around?
	// drag/drop needs just a little bit of snap
	$(".task-title").click(function(e) {
		var title = $(e.currentTarget);
		title.hide();
		title.siblings(".task-title-edit")
			.val(title.text())
			.show()
			.focus();
	});

	$(".task-title-edit").focusout(function(e) {
		var title = $(e.currentTarget);
		title.hide();
		title.siblings(".task-title")
			.text(title.val())
			.show();
		saveTask(title.closest(".task"));
	});

	function loadTask(id) {
		var task = JSON.parse(localStorage.getItem(id));
		var element = createTask(id);
		element.find(".task-title").text(task.title);
		_.each(task.children, function(child) {
			loadTask(child).appendTo(element.find("> .task-list"));
		});
		return element;
	}

	var root = JSON.parse(localStorage.getItem("task-root"));
	if (root != null) {
		_.each(root.children, function(child) {
			loadTask(child).appendTo($("#task-root-list"));
		});
	}
});

<commit_msg>Added tabbing to change the indent on tasks.<commit_after>$(document).ready(function() {
	function putTaskNextChild(task, target) {
		task.insertAfter(target.closest(".task-list > *"))
			.show();
	}

	function createTaskId() {
		var id;
		if (localStorage.getItem("task-id") == null)
			id = 1;
		else
			id = 1 + parseInt(localStorage.getItem("task-id"));
		localStorage.setItem("task-id", id);
		return "task-" + id;
	}

	function getParent(task) {
		return task.parents(".task").first();
	}

	function createTask(id) {
		id = (typeof(id) != "undefined") ? id : createTaskId();

		var task = $("#prototype > .task")
			.clone(deepWithDataAndEvents=true)
			.attr("id", id)
			.draggable({
				handle: "> .task-title",
				revert: "invalid",
				revertDuration: 100,
			});
		task.find(".task-add-child,.task-add-next")
			.droppable({
				hoverClass: "ui-state-highlight",
				drop: function(e, ui) {
					// TODO: There should be a better way to do this
					$(ui.draggable).css({top:0,left:0});

					var oldParentTask = getParent($(ui.draggable));
					putTaskNextChild($(ui.draggable), $(this));
					saveTask(oldParentTask);
					saveTask(getParent($(ui.draggable)));
				}
			});
		return task;
	}

	function saveTask(task) {
		localStorage.setItem(task.attr("id"), JSON.stringify({
			title: task.children(".task-title").text(),
			children: _.map(task.find("> .task-list > .task"), function(x){return $(x).attr("id")})
		}));
	}

	function removeTask(task) {
		_.each(task.find("> .task-list > .task"), function(child) { removeTask($(child))});
		localStorage.removeItem(task.attr("id"));
	}

	$("#task-add").keypress(function(e) {
		if (e.keyCode == 13 && $("#task-add").val().trim() != "") {
			var task = createTask().appendTo("#task-root-list");
			task.find(".task-title")
					.text($("#task-add").val())
			task.show();
			saveTask(task);
			saveTask($("#task-root"));
			$("#task-add").val("");
		}
	});

	$(".task-close").click(function(e) {
		var task = $(e.currentTarget).closest(".task");
		var parentTask = getParent(task);
		removeTask(task);
		task.remove();
		saveTask(parentTask);
	});

	$(".task-add-child,.task-add-next").click(function(e) {
		var task = createTask();
		putTaskNextChild(task, $(e.currentTarget));
		saveTask(getParent(task));
		saveTask(task);
	});

	// TODO: make this work with drag/drop
	// we want this to be either on mouseup or as a drag/drop callback?
	// only have a single instance that moves around?
	// drag/drop needs just a little bit of snap
	$(".task-title").click(function(e) {
		var title = $(e.currentTarget);
		title.hide();
		title.siblings(".task-title-edit")
			.val(title.text())
			.show()
			.focus()
			.select();
	});

	$(".task-title-edit").focusout(function(e) {
		var editing = $(e.currentTarget);
		if (editing.hasClass(".task-title-moving"))
			return;
		var title = editing.siblings(".task-title");
		if (editing.val().trim() != "") {
				title.text(editing.val());
				saveTask(title.closest(".task"));
		}
		editing.hide();
		title.show();
	});

	var shiftDown = false;

	$(".task-title-edit").keydown(function(e) {
		switch (e.keyCode) {
		case 9:
			var title = $(e.currentTarget);
			var task = title.closest(".task");

			if (shiftDown) {
				var parentTask = getParent(task);

				if (!getParent(parentTask).size())
					break;

				title.addClass(".task-title-moving");

				task.insertAfter(parentTask);
				saveTask(parentTask);
				saveTask(getParent(task));

				title.removeClass(".task-title-moving");
				title.focus().select();
			} else {
				var prev = task.prev(".task");

				if (!prev.size())
					break;

				title.addClass(".task-title-moving");

				task.appendTo(prev.children(".task-list"));
				saveTask(prev);
				saveTask(getParent(prev));

				title.removeClass(".task-title-moving");
				title.focus().select();
			}
			break;
		case 16:
			shiftDown = true;
			break;
		}

		return false;
	});

	$(".task-title-edit").keyup(function(e) {
		switch (e.keyCode) {
		case 13:
			$(e.currentTarget).focusout();
			break;
		case 16:
			shiftDown = false;
			break;
		}

		return false;
	});

	function loadTask(id) {
		var task = JSON.parse(localStorage.getItem(id));
		var element = createTask(id);
		element.find(".task-title").text(task.title);
		_.each(task.children, function(child) {
			loadTask(child).appendTo(element.find("> .task-list"));
		});
		return element;
	}

	var root = JSON.parse(localStorage.getItem("task-root"));
	if (root != null) {
		_.each(root.children, function(child) {
			loadTask(child).appendTo($("#task-root-list"));
		});
	}
});

<|endoftext|>


<commit_before>(function(window) {

    function Moon(opts) {
        var el = document.querySelector(opts.el),
            model = opts.model,
            children = el.childNodes

        // one way data binding
        for (m in model) {

        }
    }

})(window);<commit_msg>one way<commit_after>(function(window) {

    function Moon(opts) {
        var el = document.querySelector(opts.el),
            model = opts.model,
            children = el.childNodes

        // one way data binding
        for (var key in model) {
            if (model.hasOwnProperty(key)) {
                el.innerHTML = el.innerHTML.replace("{{" + key + "}}", model[key]);
            }
        }
    }

})(window);<|endoftext|>


<commit_before>/*****************************************************************************
 * msub.js
 * Copyright 2016 Jim Pravetz. MIT License (MIT)
 *****************************************************************************/

// var open = "\\\$\\\{";       // for ${0} pattern
var open = "\\\{";              // for {0} pattern
var close = "\\\}";
var moment = require('moment');

/**
 * Replace all instances of a {PROP} in this string with a value.
 * Note that any instances of {PROP} in your string will be replaced, if it is found in the args
 * list. This limits your use of "{some-text}" to 'some-text' that does not match the args list.
 * @param args {object|array|arguments}
 *              If an object: Key, value pair where all instances of {KEY} are replaced with value.
 *              The keys are converted to uppercase and camelcase is separated with underscore, so
 *              the key isExtNow becomes {IS_EXT_NOW} in s.
 *              If a list of arguments: converted to array
 *              If an array: replaces {1}, {2}, {3}, etc. with first, second, third, etc arguments.
 * @returns {string} Returns s with all instances of args replaced
 */
String.prototype.msub = function (args) {

    var s = this;

    if (args !== undefined && args !== null) {
        var replaceRegEx = {};
        var fnEx = {};
        if (args.constructor === Object) {
            for (var prop in args) {
                if (typeof args[prop] === 'string' || typeof args[prop] === 'number' || typeof args[prop] === 'boolean') {
                    var p = prop.replace(/([A-Z])/g, "_$1").toUpperCase();
                    replaceRegEx[prop] = new RegExp(open + p + close, 'g');
                } else if (args[prop] instanceof Date) {
                    var p = prop.replace(/([A-Z])/g, "_$1").toUpperCase();
                    var v = open + p + ":([^" + close + "]+)" + close;
                    replaceRegEx[prop] = new RegExp(v, 'g');
                    fnEx[prop] = true;
                }
            }
        } else {
            if (args.constructor !== Array) {
                args = Array.prototype.slice.call(arguments);
            }
            for (var idx = 0; idx < args.length; ++idx) {
                if (typeof args[idx] === 'string' || typeof args[idx] === 'number' || typeof args[idx] === 'boolean') {
                    replaceRegEx[idx] = new RegExp(open + String(idx) + close, 'g');
                } else if (args[idx] instanceof Date) {
                    var v = open + String(idx) + ":([^" + close + "]+)" + close;
                    replaceRegEx[idx] = new RegExp(v, 'g');
                    var d = args[idx];
                    fnEx[idx] = true;
                }
            }
        }
        for (var prop in replaceRegEx) {
            if (fnEx[prop]) {
                //s = s.replace(replaceRegEx[prop], fnEx[prop]);
                s = s.replace(replaceRegEx[prop], function (m0, m1) {
                    return moment(args[prop]).format(m1);
                });
            } else {
                s = s.replace(replaceRegEx[prop], args[prop]);
            }
        }
    }
    return s.toString();
};
<commit_msg>Removed unused code again<commit_after>/*****************************************************************************
 * msub.js
 * Copyright 2016 Jim Pravetz. MIT License (MIT)
 *****************************************************************************/

var open = "\\\{";              // for {0} pattern
var close = "\\\}";
var moment = require('moment');

/**
 * Replace all instances of a {PROP} in this string with a value.
 * Note that any instances of {PROP} in your string will be replaced, if it is found in the args
 * list. This limits your use of "{some-text}" to 'some-text' that does not match the args list.
 * @param args {object|array|arguments}
 *              If an object: Key, value pair where all instances of {KEY} are replaced with value.
 *              The keys are converted to uppercase and camelcase is separated with underscore, so
 *              the key isExtNow becomes {IS_EXT_NOW} in s.
 *              If a list of arguments: converted to array
 *              If an array: replaces {1}, {2}, {3}, etc. with first, second, third, etc arguments.
 * @returns {string} Returns s with all instances of args replaced
 */
String.prototype.msub = function (args) {

    var s = this;

    if (args !== undefined && args !== null) {
        var replaceRegEx = {};
        var fnEx = {};
        if (args.constructor === Object) {
            for (var prop in args) {
                if (typeof args[prop] === 'string' || typeof args[prop] === 'number' || typeof args[prop] === 'boolean') {
                    var p = prop.replace(/([A-Z])/g, "_$1").toUpperCase();
                    replaceRegEx[prop] = new RegExp(open + p + close, 'g');
                } else if (args[prop] instanceof Date) {
                    var p = prop.replace(/([A-Z])/g, "_$1").toUpperCase();
                    var v = open + p + ":([^" + close + "]+)" + close;
                    replaceRegEx[prop] = new RegExp(v, 'g');
                    fnEx[prop] = true;
                }
            }
        } else {
            if (args.constructor !== Array) {
                args = Array.prototype.slice.call(arguments);
            }
            for (var idx = 0; idx < args.length; ++idx) {
                if (typeof args[idx] === 'string' || typeof args[idx] === 'number' || typeof args[idx] === 'boolean') {
                    replaceRegEx[idx] = new RegExp(open + String(idx) + close, 'g');
                } else if (args[idx] instanceof Date) {
                    var v = open + String(idx) + ":([^" + close + "]+)" + close;
                    replaceRegEx[idx] = new RegExp(v, 'g');
                    var d = args[idx];
                    fnEx[idx] = true;
                }
            }
        }
        for (var prop in replaceRegEx) {
            if (fnEx[prop]) {
                //s = s.replace(replaceRegEx[prop], fnEx[prop]);
                s = s.replace(replaceRegEx[prop], function (m0, m1) {
                    return moment(args[prop]).format(m1);
                });
            } else {
                s = s.replace(replaceRegEx[prop], args[prop]);
            }
        }
    }
    return s.toString();
};
<|endoftext|>


<commit_before>/**
# tabs

A simple tab component. It shows one of its children at a time and
makes one tab based on the `name` attribute of each child.

The value of the tab component is the index of the currently visible
body.

## TODO

Implement <tab-body> and <tab-button> to allow fine-grained styling
and rich content in tabs, and assignment of specific values to tabs
(versus indices).

```
    <b8r-tab-selector>
      <div name="first" style="padding: 20px">first tab content</div>
      <div name="second" style="padding: 20px">second tab content</div>
    </b8r-tab-selector>
    <script>
      await import('../web-components/tabs.js');
    </script>
```
*/
/* global requestAnimationFrame */

import {
  fragment,
  div,
  span,
  slot,
  makeWebComponent
} from '../lib/web-components.js'

const TabSelector = makeWebComponent('b8r-tab-selector', {
  attributes: {
    value: 0
  },
  style: {
    ':host': {
      display: 'block'
    },
    slot: {
      position: 'relative',
      display: 'block',
      background: 'white',
      border: '1px solid #ccc',
      borderRadius: '2px'
    },
    '.tabs': {
      borderColor: '#ccc',
      padding: '5px 5px 0 5px',
      display: 'flex'
    },
    '.tabs > span': {
      flex: '1 1 auto',
      whitespace: 'nowrap',
      overflow: 'hidden',
      textOverflow: 'ellipsis',
      background: '#ddd',
      padding: '5px 10px',
      borderRadius: '5px 5px 0 0',
      border: '1px solid #ccc',
      borderBottom: '1px solid transparent',
      cursor: 'default',
      margin: '-1px'
    },
    '.tabs > .selected': {
      background: 'white',
      zIndex: '2',
      border: '1px solid #ccc',
      borderBottom: '1px solid white',
      transform: 'translateY(1px)'
    }
  },
  eventHandlers: {
    childListChange () {
      this.buildTabs()
    }
  },
  methods: {
    onMount () {
      this.buildTabs()
    },
    pickTab (idx) {
      this.value = idx
      const tab = this.shadowRoot.querySelector('.tabs').children[idx]
      requestAnimationFrame(() => tab.focus())
    },
    buildTabs () {
      const tabs = this.shadowRoot.querySelector('.tabs')
      // note that this is explicitly supporting b8r list bindings,
      // but should cause no problems for vanilla js.
      const bodies = [...this.children].filter(body => !body.dataset.list)
      tabs.innerHTML = ''
      bodies.forEach((body, idx) => {
        const tab = span({
          attributes: { tabIndex: 0 },
          content: body.getAttribute('name') || 'untitled'
        })
        body._tab = tab
        tab.addEventListener('keydown', (evt) => {
          switch (evt.code) {
            case 'Space':
              this.pickTab(idx)
              break
            case 'ArrowRight':
              this.pickTab(idx < bodies.length - 1 ? idx + 1 : 0)
              break
            case 'ArrowLeft':
              this.pickTab(idx ? idx - 1 : bodies.length - 1)
              break
          }
        })
        tab.addEventListener('click', () => this.pickTab(idx))
        tabs.appendChild(tab)
      })
      this._bodies = bodies
    },
    render () {
      const value = this.value && this.value <= this._bodies.length
        ? this.value
        : 0
      this._bodies.forEach((body, idx) => {
        const selected = parseInt(idx, 10) === parseInt(value, 10)
        body.style.display = selected ? '' : 'none'
        body._tab.classList.toggle('selected', selected)
      })
    }
  },
  content: fragment(
    div({ classes: ['tabs'] }),
    slot()
  ),
  ariaRole: 'rich text'
})

export {
  TabSelector
}
<commit_msg>tab layout tweak<commit_after>/**
# tabs

A simple tab component. It shows one of its children at a time and
makes one tab based on the `name` attribute of each child.

The value of the tab component is the index of the currently visible
body.

## TODO

Implement <tab-body> and <tab-button> to allow fine-grained styling
and rich content in tabs, and assignment of specific values to tabs
(versus indices).

```
    <b8r-tab-selector>
      <div name="first" style="padding: 20px">first tab content</div>
      <div name="second" style="padding: 20px">second tab content</div>
    </b8r-tab-selector>
    <script>
      await import('../web-components/tabs.js');
    </script>
```
*/
/* global requestAnimationFrame */

import {
  fragment,
  div,
  span,
  slot,
  makeWebComponent
} from '../lib/web-components.js'

const TabSelector = makeWebComponent('b8r-tab-selector', {
  attributes: {
    value: 0
  },
  style: {
    ':host': {
      display: 'flex',
      flexDirection: 'column'
    },
    slot: {
      position: 'relative',
      display: 'block',
      background: 'white',
      border: '1px solid #ccc',
      borderRadius: '2px',
      flexGrow: 1
    },
    '.tabs': {
      borderColor: '#ccc',
      padding: '5px 5px 0 5px',
      display: 'flex',
      flexShrink: 0
    },
    '.tabs > span': {
      flex: '1 1 auto',
      whitespace: 'nowrap',
      overflow: 'hidden',
      textOverflow: 'ellipsis',
      background: '#ddd',
      padding: '5px 10px',
      borderRadius: '5px 5px 0 0',
      border: '1px solid #ccc',
      borderBottom: '1px solid transparent',
      cursor: 'default',
      margin: '-1px'
    },
    '.tabs > .selected': {
      background: 'white',
      zIndex: '2',
      border: '1px solid #ccc',
      borderBottom: '1px solid white',
      transform: 'translateY(1px)'
    }
  },
  eventHandlers: {
    childListChange () {
      this.buildTabs()
    }
  },
  methods: {
    onMount () {
      this.buildTabs()
    },
    pickTab (idx) {
      this.value = idx
      const tab = this.shadowRoot.querySelector('.tabs').children[idx]
      requestAnimationFrame(() => tab.focus())
    },
    buildTabs () {
      const tabs = this.shadowRoot.querySelector('.tabs')
      // note that this is explicitly supporting b8r list bindings,
      // but should cause no problems for vanilla js.
      const bodies = [...this.children].filter(body => !body.dataset.list)
      tabs.innerHTML = ''
      bodies.forEach((body, idx) => {
        const tab = span({
          attributes: { tabIndex: 0 },
          content: body.getAttribute('name') || 'untitled'
        })
        body._tab = tab
        tab.addEventListener('keydown', (evt) => {
          switch (evt.code) {
            case 'Space':
              this.pickTab(idx)
              break
            case 'ArrowRight':
              this.pickTab(idx < bodies.length - 1 ? idx + 1 : 0)
              break
            case 'ArrowLeft':
              this.pickTab(idx ? idx - 1 : bodies.length - 1)
              break
          }
        })
        tab.addEventListener('click', () => this.pickTab(idx))
        tabs.appendChild(tab)
      })
      this._bodies = bodies
    },
    render () {
      const value = this.value && this.value <= this._bodies.length
        ? this.value
        : 0
      this._bodies.forEach((body, idx) => {
        const selected = parseInt(idx, 10) === parseInt(value, 10)
        body.style.display = selected ? '' : 'none'
        body._tab.classList.toggle('selected', selected)
      })
    }
  },
  content: fragment(
    div({ classes: ['tabs'] }),
    slot()
  ),
  ariaRole: 'rich text'
})

export {
  TabSelector
}
<|endoftext|>