<commit_before>// RFXrec433 - USB 433.92MHz receiver: http://www.rfxcom.com/store/Receivers/12113

var rfxcom      = require('rfxcom')
  , util        = require('util')
  , devices     = require('./../../core/device')
  , steward     = require('./../../core/steward')
  , utility     = require('./../../core/utility')
  ;

var logger   = exports.logger = utility.logger('gateway');

var Gateway = exports.Device = function(deviceID, deviceUID, info) {
  var self = this;

  self.whatami = info.deviceType;
  self.deviceID = deviceID.toString();
  self.deviceUID = deviceUID;
  self.name = info.device.name;
  self.getName();

  self.status = 'ready';
  self.changed();
  self.rfx = info.rfx;
  self.info = {};

  utility.broker.subscribe('actors', function(request, taskID, actor, perform, parameter) {/* jshint unused: false */
    if (actor !== ('device/' + self.deviceID)) return;

    if (request === 'perform') return devices.perform(self, taskID, perform, parameter);
  });

  self.rfx.logger = utility.logfnx(logger, 'device/' + self.deviceID);
  self.rfx.on('response',  function(type, seqno) {
    logger.debug('device/' + self.deviceID, { event: 'response',  type:   type, seqno: seqno });
  }).on('status',  function(evt) {
    logger.info('device/' + self.deviceID,  { event: 'status',    params: evt });
  }).on('elec2',  function(evt) {
    logger.info('device/' + self.deviceID,  { event: 'elec2',     params: evt });
  }).on('security1',  function(evt) {
    logger.info('device/' + self.deviceID,  { event: 'security1', params: evt });
  }).on('temp1',  function(evt) { self.tempX(self, evt);
  }).on('temp2',  function(evt) { self.tempX(self, evt);
  }).on('temp3',  function(evt) { self.tempX(self, evt);
  }).on('temp4',  function(evt) { self.tempX(self, evt);
  }).on('temp5',  function(evt) { self.tempX(self, evt);
  }).on('th1',  function(evt) { self.thX(self, evt);
  }).on('th2',  function(evt) { self.thX(self, evt);
  }).on('th3',  function(evt) { self.thX(self, evt);
  }).on('th4',  function(evt) { self.thX(self, evt);
  }).on('th5',  function(evt) { self.thX(self, evt);
  }).on('lighting1',  function(evt) {
    logger.info('device/' + self.deviceID,  { event: 'lighting1', params: evt });
  }).on('lighting2',  function(evt) {
    logger.info('device/' + self.deviceID,  { event: 'lighting2', params: evt });
  }).on('lighting5',  function(evt) {
    logger.info('device/' + self.deviceID,  { event: 'lighting5', params: evt });
  }).on('data',  function(data) {
    logger.debug('device/' + self.deviceID, { event: 'data',      params: data.toString('hex') });
  }).initialise(function() {
    logger.info('device/' + self.deviceID,  { event: 'initialize' });
  });
};
util.inherits(Gateway, require('./../device-gateway').Device);

Gateway.prototype.thX = function(self, evt) {
  var info, name, params, sensor, udn;

  params = { lastSample  : new Date().getTime()
           , temperature : (!!evt.temperature) ? evt.temperature : null
           , humidity    : (!!evt.humidity)    ? evt.humidity    : null
           };

  udn = 'rfxcom:th:' + evt.id;
  if (!!devices.devices[udn]) {
    sensor = devices.devices[udn].device;
    return sensor.update(sensor, params);
  }

  name = (!!evt.humidity) ? 'Thermo-Hygro Sensor' : 'Temperature Sensor';

  info =  { source: self.deviceID, gateway: self, params: params };
  info.device = { url                          : null
                , name                         : name + ' #' + evt.id
                , manufacturer                 : 'Oregon Scientific'
                , model        : { name        : name
                                 , description : ''
                                 , number      : evt.subtype
                                 }
                , unit         : { serial      : evt.id
                                 , udn         : udn
                                 }
                };
  info.url = info.device.url;
  info.deviceType = '/device/climate/oregon-scientific/sensor';
  info.id = info.device.unit.udn;

  logger.info('device/' + self.deviceID, { name: info.device.name, id: info.device.unit.serial,  params: params });
  devices.discover(info);
  self.changed();
};
Gateway.prototype.tempX = Gateway.prototype.thX;

var scan = function() {
  rfxcom.devices(function(err, results) {
    var device, i, info, rfx, udn;

    if (err) return utility.logger('discovery').error('RFXrec433-usb', { diagnostic: err.message });

    for (i = 0; i < results.length; i++) {
      device = results[i];
      udn = 'rfxcom:' + device.serialNumber;
      if (!!devices.devices[udn]) continue;

      rfx = new rfxcom.RfxCom(device.comName, { debug: true, logger: utility.logger('discovery') });

      info = { source: device, rfx: rfx };
      info.device = { url          : null
                    , name         : 'RFXrec433 #' + device.serialNumber
                    , manufacturer : device.manufacturer
                    , model        : { name        : 'RFXrec 433'
                                     , description : 'USB 433.92MHz receiver'
                                     , number      : device.productId
                                     }
                    , unit         : { serial      : device.serialNumber
                                     , udn         : udn
                                     }
                    };
      info.url = info.device.url;
      info.deviceType = '/device/gateway/rfxrec433/usb';
      info.id = info.device.unit.udn;
      if (!!devices.devices[info.id]) return;

      utility.logger('discovery').info(device.comName, { manufacturer : device.manufacturer
                                                       , vendorID     : device.vendorId
                                                       , productID    : device.productId
                                                       , serialNo     : device.serialNumber
                                                       });
      devices.discover(info);
    }
  });

  setTimeout(scan, 30 * 1000);
};

exports.start = function() {
  steward.actors.device.gateway.rfxrec433 = steward.actors.device.gateway.rfxrec433 ||
      { $info     : { type: '/device/gateway/rfxrec433' } };

  steward.actors.device.gateway.rfxrec433.usb =
      { $info     : { type       : '/device/gateway/rfxrec433/usb'
                    , observe    : [ ]
                    , perform    : [ ]
                    , properties : { name   : true
                                   , status : [ 'ready' ]
                                   }
                    }
      , $validate : { perform    : devices.validate_perform
                    }
      };
  devices.makers['/device/gateway/rfxrec433/usb'] = Gateway;

  scan();
};
<commit_msg>more RFXtrx433 support<commit_after>// RFXrec433 - USB 433.92MHz receiver: http://www.rfxcom.com/store/Receivers/12113

var rfxcom      = require('rfxcom')
  , serialport  = require('serialport')
  , util        = require('util')
  , devices     = require('./../../core/device')
  , steward     = require('./../../core/steward')
  , utility     = require('./../../core/utility')
  ;

var logger  = exports.logger = utility.logger('gateway');
var logger2                  = utility.logger('discovery');

var Gateway = exports.Device = function(deviceID, deviceUID, info) {
  var self = this;

  self.whatami = info.deviceType;
  self.deviceID = deviceID.toString();
  self.deviceUID = deviceUID;
  self.name = info.device.name;
  self.getName();

  self.status = 'ready';
  self.changed();
  self.rfx = info.rfx;
  self.info = {};

  utility.broker.subscribe('actors', function(request, taskID, actor, perform, parameter) {/* jshint unused: false */
    if (actor !== ('device/' + self.deviceID)) return;

    if (request === 'perform') return devices.perform(self, taskID, perform, parameter);
  });

  self.rfx.logger = utility.logfnx(logger, 'device/' + self.deviceID);
  self.rfx.on('response',  function(type, seqno) {
    logger.debug('device/' + self.deviceID, { event: 'response',  type:   type, seqno: seqno });
  }).on('status',  function(evt) {
    logger.info('device/' + self.deviceID,  { event: 'status',    params: evt });
  }).on('elec2',  function(evt) {
    logger.info('device/' + self.deviceID,  { event: 'elec2',     params: evt });
  }).on('security1',  function(evt) {
    logger.info('device/' + self.deviceID,  { event: 'security1', params: evt });
  }).on('temp1',  function(evt) { self.tempX(self, evt);
  }).on('temp2',  function(evt) { self.tempX(self, evt);
  }).on('temp3',  function(evt) { self.tempX(self, evt);
  }).on('temp4',  function(evt) { self.tempX(self, evt);
  }).on('temp5',  function(evt) { self.tempX(self, evt);
  }).on('th1',  function(evt) { self.thX(self, evt);
  }).on('th2',  function(evt) { self.thX(self, evt);
  }).on('th3',  function(evt) { self.thX(self, evt);
  }).on('th4',  function(evt) { self.thX(self, evt);
  }).on('th5',  function(evt) { self.thX(self, evt);
  }).on('lighting1',  function(evt) {
    logger.info('device/' + self.deviceID,  { event: 'lighting1', params: evt });
  }).on('lighting2',  function(evt) {
    logger.info('device/' + self.deviceID,  { event: 'lighting2', params: evt });
  }).on('lighting5',  function(evt) {
    logger.info('device/' + self.deviceID,  { event: 'lighting5', params: evt });
  }).on('data',  function(data) {
    logger.debug('device/' + self.deviceID, { event: 'data',      params: data.toString('hex') });
  }).on('receive',  function(data) {
    logger.debug('device/' + self.deviceID, { event: 'receive',   params: data.toString('hex') });
  }).initialise(function() {
    logger.info('device/' + self.deviceID,  { event: 'initialize' });
  });
};
util.inherits(Gateway, require('./../device-gateway').Device);

Gateway.prototype.thX = function(self, evt) {
  var info, name, params, sensor, udn;

  params = { lastSample  : new Date().getTime()
           , temperature : (!!evt.temperature) ? evt.temperature : null
           , humidity    : (!!evt.humidity)    ? evt.humidity    : null
           };

  udn = 'rfxcom:th:' + evt.id;
  if (!!devices.devices[udn]) {
    sensor = devices.devices[udn].device;
    return sensor.update(sensor, params);
  }

  name = (!!evt.humidity) ? 'Thermo-Hygro Sensor' : 'Temperature Sensor';

  info =  { source: self.deviceID, gateway: self, params: params };
  info.device = { url                          : null
                , name                         : name + ' #' + evt.id
                , manufacturer                 : 'Oregon Scientific'
                , model        : { name        : name
                                 , description : ''
                                 , number      : evt.subtype
                                 }
                , unit         : { serial      : evt.id
                                 , udn         : udn
                                 }
                };
  info.url = info.device.url;
  info.deviceType = '/device/climate/oregon-scientific/sensor';
  info.id = info.device.unit.udn;

  logger.info('device/' + self.deviceID, { name: info.device.name, id: info.device.unit.serial,  params: params });
  devices.discover(info);
  self.changed();
};
Gateway.prototype.tempX = Gateway.prototype.thX;

var scanning      = {};

var fingerprints  =
  [
    { vendor         : 'RFXCOM'
    , modelName      : 'RFXtrx433'
    , description    : 'USB 433.92MHz transceiver'
    , manufacturer   : 'RFXCOM'
    , vendorId       : 0x0403
    , productId      : 0x6001
    , deviceType     : '/device/gateway/rfxtrx433/usb'
    }
  , { vendor         : 'RFXCOM'
    , modelName      : 'RFXrec433'
    , description    : 'USB 433.92MHz receiver'
    , manufacturer   : 'RFXCOM'
    , vendorId       : 0x0403
    , productId      : 0x6001
    , pnpId          : 'usb-RFXCOM_RFXrec433_'
    , deviceType     : '/device/gateway/rfxrec433/usb'
    }
  ];

var scan = function() {
  serialport.list(function(err, info) {
    var i, j;

    if (!!err) return logger2.error('RFXrec433-usb', { diagnostic: err.message });

    for (i = 0; i < info.length; i++) {
      for (j = fingerprints.length - 1; j !== -1; j--) {
        if ((info[i].pnpId.indexOf(fingerprints[j].pnpId) === 0)
              || ((     fingerprints[j].manufacturer === info[i].manufacturer)
                    && (fingerprints[j].vendorId     === parseInt(info[i].vendorId, 16))
                    && (fingerprints[j].productId    === parseInt(info[i].productId, 16)))) {
          info[i].vendor = fingerprints[j].vendor;
          info[i].modelName = fingerprints[j].modelName;
          info[i].description = fingerprints[j].description;
          info[i].deviceType = fingerprints[j].deviceType;
          scan1(info[i]);
        }
      }
    }
  });

  setTimeout(scan, 30 * 1000);
};

var scan1 = function(driver) {
  var comName, info, rfx, udn;

  comName = driver.comName;
  if (!!scanning[comName]) return;
  scanning[comName] = true;

  udn = 'rfxcom:' + driver.serialNumber;
  if (!!devices.devices[udn]) return;

  rfx = new rfxcom.RfxCom(comName, { debug: true, logger: logger2 });

  info = { source: driver, rfx: rfx };
  info.device = { url          : null
                , name         : driver.modelName + ' #' + driver.serialNumber
                , manufacturer : driver.manufacturer
                , model        : { name        : driver.modelName
                                 , description : driver.description
                                 , number      : driver.productId
                                 }
                , unit         : { serial      : driver.serialNumber
                                 , udn         : udn
                                 }
                };
  info.url = info.device.url;
  info.deviceType = driver.deviceType;
  info.id = info.device.unit.udn;
  if (!!devices.devices[info.id]) return;

  logger2.info(comName, { manufacturer : driver.manufacturer
                        , vendorID     : driver.vendorId
                        , productID    : driver.productId
                        , serialNo     : driver.serialNumber
                        });
  devices.discover(info);
};

exports.start = function() {
  steward.actors.device.gateway.rfxrec433 = steward.actors.device.gateway.rfxrec433 ||
      { $info     : { type: '/device/gateway/rfxrec433' } };

  steward.actors.device.gateway.rfxrec433.usb =
      { $info     : { type       : '/device/gateway/rfxrec433/usb'
                    , observe    : [ ]
                    , perform    : [ ]
                    , properties : { name   : true
                                   , status : [ 'ready' ]
                                   }
                    }
      , $validate : { perform    : devices.validate_perform
                    }
      };
  devices.makers['/device/gateway/rfxrec433/usb'] = Gateway;

  steward.actors.device.gateway.rfxtrx433 = utility.clone(steward.actors.device.gateway.rfxrec433);
  steward.actors.device.gateway.rfxtrx433.$info.type = '/device/gateway/rfxtrx433';
  steward.actors.device.gateway.rfxtrx433.usb.$info.type = '/device/gateway/rfxtrx433/usb';
  devices.makers['/device/gateway/rfxtrx433/usb'] = Gateway;

  scan();
};
<|endoftext|>


<commit_before>/**
 * Miscellaneous js functions for WebHelp
 * Kasun Gajasinghe, http://kasunbg.blogspot.com
 * David Cramer, http://www.thingbag.net
 *
 */

//Turn ON and OFF the animations for Show/Hide Sidebar. Extend this to other anime as well if any.
var noAnimations=false;

$(document).ready(function() {
	// When you click on a link to an anchor, scroll down
	// 105 px to cope with the fact that the banner
	// hides the top 95px or so of the page.
	// This code deals with the problem when
	// you click on a link within a page.
	$('a[href*=#]').click(function() {
		if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'')
		    && location.hostname == this.hostname) {
		    var $target = $(this.hash);
		    $target = $target.length && $target
			|| $('[name=' + this.hash.slice(1) +']');
		if (!(this.hash == "#searchDiv" || this.hash == "#treeDiv"  || this.hash == "") && $target.length) {
			var targetOffset = $target.offset().top - 120;
			$('html,body')
			    .animate({scrollTop: targetOffset}, 200);
			return false;
		    }
		}
	    });

    //  $("#showHideHighlight").button(); //add jquery button styling to 'Go' button
    //Generate tabs in nav-pane with JQuery
    $(function() {
        $("#tabs").tabs({
            cookie: {
                expires: 2 // store cookie for 2 days.
            }
        });
    });

    //Generate the tree
    $("#ulTreeDiv").attr("style", "");
    $("#tree").treeview({
        collapsed: true,
        animated: "medium",
        control: "#sidetreecontrol",
        persist: "location"
    });

    //after toc fully styled, display it. Until loading, a 'loading' image will be displayed
    $("#tocLoading").attr("style", "display:none;");
    //    $("#ulTreeDiv").attr("style","display:block;");

    //.searchButton is the css class applied to 'Go' button
    $(function() {
        $("button", ".searchButton").button();

        $("button", ".searchButton").click(function() {
            return false;
        });
    });

    //'ui-tabs-1' is the cookie name which is used for the persistence of the tabs.(Content/Search tab)
    if ($.cookie('ui-tabs-1') === '1') {    //search tab is active
        if ($.cookie('textToSearch') != undefined && $.cookie('textToSearch').length > 0) {
            document.getElementById('textToSearch').value = $.cookie('textToSearch');
            Verifie('searchForm');
            searchHighlight($.cookie('textToSearch'));
            $("#showHideHighlight").css("display", "block");
        }
    }

    syncToc(); //Synchronize the toc tree with the content pane, when loading the page.
    //$("#doSearch").button(); //add jquery button styling to 'Go' button

    // When you click on a link to an anchor, scroll down
    // 120 px to cope with the fact that the banner
    // hides the top 95px or so of the page.
    // This code deals with the problem when
    // you click on a link from another page.
    var hash = window.location.hash;
    if(hash){
	var targetOffset = $(hash).offset().top - 120;
	$('html,body').animate({scrollTop: targetOffset}, 200);
	return false;
    }
});

/**
 * If an user moved to another page by clicking on a toc link, and then clicked on #searchDiv,
 * search should be performed if the cookie textToSearch is not empty.
 */
function doSearch() {
//'ui-tabs-1' is the cookie name which is used for the persistence of the tabs.(Content/Search tab)
    if ($.cookie('textToSearch') != undefined && $.cookie('textToSearch').length > 0) {
        document.getElementById('textToSearch').value = $.cookie('textToSearch');
        Verifie('searchForm');
    }
}

/**
 * Synchronize with the tableOfContents
 */
function syncToc() {
    var a = document.getElementById("webhelp-currentid");
    if (a != undefined) {
        //Expanding the child sections of the selected node.
        var nodeClass = a.getAttribute("class");
        if (nodeClass != null && !nodeClass.match(/collapsable/)) {
            a.setAttribute("class", "collapsable");
            //remove display:none; css style from <ul> block in the selected node.
            var ulNode = a.getElementsByTagName("ul")[0];
            if (ulNode != undefined) {
                if (ulNode.hasAttribute("style")) {
                    ulNode.setAttribute("style", "display: block; background-color: #D8D8D8 !important;");
                } else {
                    var ulStyle = document.createAttribute("style");
                    ulStyle.nodeValue = "display: block; background-color: #D8D8D8 !important;";
                    ulNode.setAttributeNode(ulStyle);
            }   }
            //adjust tree's + sign to -
            var divNode = a.getElementsByTagName("div")[0];
            if (divNode != undefined) {
                if (divNode.hasAttribute("class")) {
                    divNode.setAttribute("class", "hitarea collapsable-hitarea");
                } else {
                    var divClass = document.createAttribute("class");
                    divClass.nodeValue = "hitarea collapsable-hitarea";
                    divNode.setAttributeNode(divClass);
            }   }
            //set persistence cookie when a node is auto expanded
            //     setCookieForExpandedNode("webhelp-currentid");
        }
        var b = a.getElementsByTagName("a")[0];

        if (b != undefined) {
            //Setting the background for selected node.
            var style = a.getAttribute("style", 2);
            if (style != null && !style.match(/background-color: Background;/)) {
                a.setAttribute("style", "background-color: #D8D8D8;  " + style);
                b.setAttribute("style", "color: black;");
            } else if (style != null) {
                a.setAttribute("style", "background-color: #D8D8D8;  " + style);
                b.setAttribute("style", "color: black;");
            } else {
                a.setAttribute("style", "background-color: #D8D8D8;  ");
                b.setAttribute("style", "color: black;");
            }
        }

        //shows the node related to current content.
        //goes a recursive call from current node to ancestor nodes, displaying all of them.
        while (a.parentNode && a.parentNode.nodeName) {
            var parentNode = a.parentNode;
            var nodeName = parentNode.nodeName;

            if (nodeName.toLowerCase() == "ul") {
                parentNode.setAttribute("style", "display: block;");
            } else if (nodeName.toLocaleLowerCase() == "li") {
                parentNode.setAttribute("class", "collapsable");
                parentNode.firstChild.setAttribute("class", "hitarea collapsable-hitarea ");
            }
            a = parentNode;
}   }  }
/*
 function setCookieForExpandedNode(nodeName) {
 var tocDiv = document.getElementById("tree"); //get table of contents Div
 var divs = tocDiv.getElementsByTagName("div");
 var matchedDivNumber;
 var i;
 for (i = 0; i < divs.length; i++) {        //1101001
 var div = divs[i];
 var liNode = div.parentNode;
 }
//create a new cookie if a treeview does not exist
 if ($.cookie(treeCookieId) == null || $.cookie(treeCookieId) == "") {
 var branches = $("#tree").find("li");//.prepareBranches(treesettings);
 var data = [];
 branches.each(function(i, e) {
 data[i] = $(e).is(":has(>ul:visible)") ? 1 : 0;
 });
 $.cookie(treeCookieId, data.join(""));

 }

 if (i < divs.length) {
 var treeviewCookie = $.cookie(treeCookieId);
 var tvCookie1 = treeviewCookie.substring(0, i);
 var tvCookie2 = treeviewCookie.substring(i + 1);
 var newTVCookie = tvCookie1 + "1" + tvCookie2;
 $.cookie(treeCookieId, newTVCookie);
 }
 }       */

/**
 * Code for Show/Hide TOC
 *
 */
function showHideToc() {
    var showHideButton = $("#showHideButton");
    var leftNavigation = $("#sidebar"); //hide the parent div of leftnavigation, ie sidebar
    var content = $("#content");
    var animeTime=75

    if (showHideButton != undefined && showHideButton.hasClass("pointLeft")) {
        //Hide TOC
        showHideButton.removeClass('pointLeft').addClass('pointRight');

        if(noAnimations) {
            leftNavigation.css("display", "none");
            content.css("margin", "125px 0 0 0");
        } else {
            leftNavigation.hide(animeTime);
            content.animate( { "margin-left": 0 }, animeTime);
        }
        showHideButton.attr("title", "Show Sidebar");
    } else {
        //Show the TOC
        showHideButton.removeClass('pointRight').addClass('pointLeft');
        if(noAnimations) {
            content.css("margin", "125px 0 0 280px");
            leftNavigation.css("display", "block");
        } else {
            content.animate( { "margin-left": '280px' }, animeTime);
            leftNavigation.show(animeTime);
        }
        showHideButton.attr("title", "Hide Sidebar");
    }
}

/**
 * Code for search highlighting
 */
var highlightOn = true;
function searchHighlight(searchText) {
    highlightOn = true;
    if (searchText != undefined) {
        var wList;
        var sList = new Array();    //stem list
        //Highlight the search terms
        searchText = searchText.toLowerCase().replace(/<\//g, "_st_").replace(/\$_/g, "_di_").replace(/\.|%2C|%3B|%21|%3A|@|\/|\*/g, " ").replace(/(%20)+/g, " ").replace(/_st_/g, "</").replace(/_di_/g, "%24_")
        searchText = searchText.replace(/  +/g, " ");
        searchText = searchText.replace(/ $/, "").replace(/^ /, "");

        wList = searchText.split(" ");
        $("#content").highlight(wList); //Highlight the search input

        if (typeof stemmer != "undefined") {
            //Highlight the stems
            for (var i = 0; i < wList.length; i++) {
                var stemW = stemmer(wList[i]);
                sList.push(stemW);
            }
        } else {
            sList = wList;
        }
        $("#content").highlight(sList); //Highlight the search input's all stems
    }
}

function searchUnhighlight() {
    highlightOn = false;
    //unhighlight the search input's all stems
    $("#content").unhighlight();
    $("#content").unhighlight();
}

function toggleHighlight() {
    if (highlightOn) {
        searchUnhighlight();
    } else {
        searchHighlight($.cookie('textToSearch'));
    }
}<commit_msg>WebHelp: additional checks and escaping for identifiers from url anchor hashes. #PL-2618 fixed<commit_after>/**
 * Miscellaneous js functions for WebHelp
 * Kasun Gajasinghe, http://kasunbg.blogspot.com
 * David Cramer, http://www.thingbag.net
 *
 */

//Turn ON and OFF the animations for Show/Hide Sidebar. Extend this to other anime as well if any.
var noAnimations=false;

$(document).ready(function() {
	// When you click on a link to an anchor, scroll down
	// 105 px to cope with the fact that the banner
	// hides the top 95px or so of the page.
	// This code deals with the problem when
	// you click on a link within a page.
	$('a[href*=#]').click(function() {
		if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'')
		    && location.hostname == this.hostname) {
		    var $target = $(this.hash);
		    $target = $target.length && $target
			|| $('[name=' + this.hash.slice(1) +']');
		if (!(this.hash == "#searchDiv" || this.hash == "#treeDiv"  || this.hash == "") && $target.length) {
			var targetOffset = $target.offset().top - 120;
			$('html,body')
			    .animate({scrollTop: targetOffset}, 200);
			return false;
		    }
		}
	    });

    //  $("#showHideHighlight").button(); //add jquery button styling to 'Go' button
    //Generate tabs in nav-pane with JQuery
    $(function() {
        $("#tabs").tabs({
            cookie: {
                expires: 2 // store cookie for 2 days.
            }
        });
    });

    //Generate the tree
    $("#ulTreeDiv").attr("style", "");
    $("#tree").treeview({
        collapsed: true,
        animated: "medium",
        control: "#sidetreecontrol",
        persist: "location"
    });

    //after toc fully styled, display it. Until loading, a 'loading' image will be displayed
    $("#tocLoading").attr("style", "display:none;");
    //    $("#ulTreeDiv").attr("style","display:block;");

    //.searchButton is the css class applied to 'Go' button
    $(function() {
        $("button", ".searchButton").button();

        $("button", ".searchButton").click(function() {
            return false;
        });
    });

    //'ui-tabs-1' is the cookie name which is used for the persistence of the tabs.(Content/Search tab)
    if ($.cookie('ui-tabs-1') === '1') {    //search tab is active
        if ($.cookie('textToSearch') != undefined && $.cookie('textToSearch').length > 0) {
            document.getElementById('textToSearch').value = $.cookie('textToSearch');
            Verifie('searchForm');
            searchHighlight($.cookie('textToSearch'));
            $("#showHideHighlight").css("display", "block");
        }
    }

    syncToc(); //Synchronize the toc tree with the content pane, when loading the page.
    //$("#doSearch").button(); //add jquery button styling to 'Go' button

    // When you click on a link to an anchor, scroll down
    // 120 px to cope with the fact that the banner
    // hides the top 95px or so of the page.
    // This code deals with the problem when
    // you click on a link from another page.
    var hash = window.location.hash;
    if(hash){
        // Also escape dot symbols.
        hash = hash.split('.').join('\\.');
        $hash = $(hash);
        if ($hash.length) {
            var offset = $hash.offset().top - 120;
            $('html,body').animate({scrollTop: offset}, 200);
        }
    }
    return false;
});

/**
 * If an user moved to another page by clicking on a toc link, and then clicked on #searchDiv,
 * search should be performed if the cookie textToSearch is not empty.
 */
function doSearch() {
//'ui-tabs-1' is the cookie name which is used for the persistence of the tabs.(Content/Search tab)
    if ($.cookie('textToSearch') != undefined && $.cookie('textToSearch').length > 0) {
        document.getElementById('textToSearch').value = $.cookie('textToSearch');
        Verifie('searchForm');
    }
}

/**
 * Synchronize with the tableOfContents
 */
function syncToc() {
    var a = document.getElementById("webhelp-currentid");
    if (a != undefined) {
        //Expanding the child sections of the selected node.
        var nodeClass = a.getAttribute("class");
        if (nodeClass != null && !nodeClass.match(/collapsable/)) {
            a.setAttribute("class", "collapsable");
            //remove display:none; css style from <ul> block in the selected node.
            var ulNode = a.getElementsByTagName("ul")[0];
            if (ulNode != undefined) {
                if (ulNode.hasAttribute("style")) {
                    ulNode.setAttribute("style", "display: block; background-color: #D8D8D8 !important;");
                } else {
                    var ulStyle = document.createAttribute("style");
                    ulStyle.nodeValue = "display: block; background-color: #D8D8D8 !important;";
                    ulNode.setAttributeNode(ulStyle);
            }   }
            //adjust tree's + sign to -
            var divNode = a.getElementsByTagName("div")[0];
            if (divNode != undefined) {
                if (divNode.hasAttribute("class")) {
                    divNode.setAttribute("class", "hitarea collapsable-hitarea");
                } else {
                    var divClass = document.createAttribute("class");
                    divClass.nodeValue = "hitarea collapsable-hitarea";
                    divNode.setAttributeNode(divClass);
            }   }
            //set persistence cookie when a node is auto expanded
            //     setCookieForExpandedNode("webhelp-currentid");
        }
        var b = a.getElementsByTagName("a")[0];

        if (b != undefined) {
            //Setting the background for selected node.
            var style = a.getAttribute("style", 2);
            if (style != null && !style.match(/background-color: Background;/)) {
                a.setAttribute("style", "background-color: #D8D8D8;  " + style);
                b.setAttribute("style", "color: black;");
            } else if (style != null) {
                a.setAttribute("style", "background-color: #D8D8D8;  " + style);
                b.setAttribute("style", "color: black;");
            } else {
                a.setAttribute("style", "background-color: #D8D8D8;  ");
                b.setAttribute("style", "color: black;");
            }
        }

        //shows the node related to current content.
        //goes a recursive call from current node to ancestor nodes, displaying all of them.
        while (a.parentNode && a.parentNode.nodeName) {
            var parentNode = a.parentNode;
            var nodeName = parentNode.nodeName;

            if (nodeName.toLowerCase() == "ul") {
                parentNode.setAttribute("style", "display: block;");
            } else if (nodeName.toLocaleLowerCase() == "li") {
                parentNode.setAttribute("class", "collapsable");
                parentNode.firstChild.setAttribute("class", "hitarea collapsable-hitarea ");
            }
            a = parentNode;
}   }  }
/*
 function setCookieForExpandedNode(nodeName) {
 var tocDiv = document.getElementById("tree"); //get table of contents Div
 var divs = tocDiv.getElementsByTagName("div");
 var matchedDivNumber;
 var i;
 for (i = 0; i < divs.length; i++) {        //1101001
 var div = divs[i];
 var liNode = div.parentNode;
 }
//create a new cookie if a treeview does not exist
 if ($.cookie(treeCookieId) == null || $.cookie(treeCookieId) == "") {
 var branches = $("#tree").find("li");//.prepareBranches(treesettings);
 var data = [];
 branches.each(function(i, e) {
 data[i] = $(e).is(":has(>ul:visible)") ? 1 : 0;
 });
 $.cookie(treeCookieId, data.join(""));

 }

 if (i < divs.length) {
 var treeviewCookie = $.cookie(treeCookieId);
 var tvCookie1 = treeviewCookie.substring(0, i);
 var tvCookie2 = treeviewCookie.substring(i + 1);
 var newTVCookie = tvCookie1 + "1" + tvCookie2;
 $.cookie(treeCookieId, newTVCookie);
 }
 }       */

/**
 * Code for Show/Hide TOC
 *
 */
function showHideToc() {
    var showHideButton = $("#showHideButton");
    var leftNavigation = $("#sidebar"); //hide the parent div of leftnavigation, ie sidebar
    var content = $("#content");
    var animeTime=75

    if (showHideButton != undefined && showHideButton.hasClass("pointLeft")) {
        //Hide TOC
        showHideButton.removeClass('pointLeft').addClass('pointRight');

        if(noAnimations) {
            leftNavigation.css("display", "none");
            content.css("margin", "125px 0 0 0");
        } else {
            leftNavigation.hide(animeTime);
            content.animate( { "margin-left": 0 }, animeTime);
        }
        showHideButton.attr("title", "Show Sidebar");
    } else {
        //Show the TOC
        showHideButton.removeClass('pointRight').addClass('pointLeft');
        if(noAnimations) {
            content.css("margin", "125px 0 0 280px");
            leftNavigation.css("display", "block");
        } else {
            content.animate( { "margin-left": '280px' }, animeTime);
            leftNavigation.show(animeTime);
        }
        showHideButton.attr("title", "Hide Sidebar");
    }
}

/**
 * Code for search highlighting
 */
var highlightOn = true;
function searchHighlight(searchText) {
    highlightOn = true;
    if (searchText != undefined) {
        var wList;
        var sList = new Array();    //stem list
        //Highlight the search terms
        searchText = searchText.toLowerCase().replace(/<\//g, "_st_").replace(/\$_/g, "_di_").replace(/\.|%2C|%3B|%21|%3A|@|\/|\*/g, " ").replace(/(%20)+/g, " ").replace(/_st_/g, "</").replace(/_di_/g, "%24_")
        searchText = searchText.replace(/  +/g, " ");
        searchText = searchText.replace(/ $/, "").replace(/^ /, "");

        wList = searchText.split(" ");
        $("#content").highlight(wList); //Highlight the search input

        if (typeof stemmer != "undefined") {
            //Highlight the stems
            for (var i = 0; i < wList.length; i++) {
                var stemW = stemmer(wList[i]);
                sList.push(stemW);
            }
        } else {
            sList = wList;
        }
        $("#content").highlight(sList); //Highlight the search input's all stems
    }
}

function searchUnhighlight() {
    highlightOn = false;
    //unhighlight the search input's all stems
    $("#content").unhighlight();
    $("#content").unhighlight();
}

function toggleHighlight() {
    if (highlightOn) {
        searchUnhighlight();
    } else {
        searchHighlight($.cookie('textToSearch'));
    }
}<|endoftext|>


<commit_before>//How to use this: https://github.com/monkeyraptor/math_operation

//Change this "math" keyword if it collided with your own JavaScript thingy.
//For example, "goat".
//Then to call the *factorial* function: goat.factorial(2).
var math = {
    //checking above 21 digit length or infinity
    check: function (a) {
        "use strict";
        var result = 0;

        if (a.toString().length > 21 || !isFinite(a)) {
            result = 1;
        }
        return result;
    },

    //rounding down
    rd: function (a) {
        "use strict";
        return Math.floor(a);
    },

    //absolute
    ab: function (a) {
        "use strict";
        return Math.abs(a);
    },

    //square root
    sqr: function (a) {
        "use strict";
        return Math.sqrt(a);
    },
    //*****************************************
    //[1] Factorial
    factorial: function (n) {
        "use strict";
        var i = 1,
            result = 1;

        if (Number(n) >= 0) {
            n = this.rd(n);

            if (n > 1) {
                for (i; i <= n; i++) {
                    result *= i;
                }
            } else {
                result = 1;
            }
        } else {
            result = "INPUT ERROR: n >= 0";
        }
        if (!!this.check(result)) {
            result = "Result is too LARGE: " + result;
        }
        return result;
    },

    //*****************************************
    //[2] Combination
    combination: function (n, k) {
        "use strict";
        var start,
            numerator = 1,
            denumerator = 1,
            i = 1,
            result;

        if (n >= k && Number(n) >= 0 && Number(k) >= 0) {
            n = this.rd(n);
            k = this.rd(k);

            if (n === k || k === 0) {
                result = 1;
            } else if (k === 1) {
                result = n;
            } else {
                start = n - k + 1;

                for (i; i <= k; i++) {
                    denumerator *= i;
                }
                for (start; start <= n; start++) {
                    numerator *= start;
                }
                result = numerator / denumerator;
            }
        } else {
            result = "INPUT ERROR: n >= k, n >= 0, k >= 0";
        }
        if (!!this.check(result)) {
            result = "Result is too LARGE: " + result;
        }
        return result;
    },

    //*****************************************
    //[3] Permutation
    permutation: function (n, k) {
        "use strict";
        var start,
            numerator = 1,
            result;

        if (n >= k && Number(n) >= 0 && Number(k) >= 0) {
            n = this.rd(n);
            k = this.rd(k);

            if (n === k || k === 0) {
                result = 1;
            } else if (k === 1) {
                result = n;
            } else {
                start = n - k + 1;
                for (start; start <= n; start++) {
                    numerator *= start;
                }
                result = numerator;
            }
        } else {
            result = "INPUT ERROR: n >= k, n >= 0, k >= 0";
        }
        if (!!this.check(result)) {
            result = "Result is too LARGE: " + result;
        }
        return result;
    },

    //*****************************************
    //[4] Adding comma to large integer
    addcomma: function (your_number) {
        "use strict";
        var f = [],
            p,
            r,
            i = 1;

        if (!isNaN(your_number)) {
            if (your_number < 0) { p = "-"; } else { p = ""; }

            r = this.rd(this.ab(your_number)).toString();
            f = r.split("").reverse();

            for (i; i <= this.rd(f.length / 4); i++) {
                f.splice((4 * i - 1), 0, ",");
            }
            your_number = p + f.reverse().join("");
        } else {
            your_number = "INPUT ERROR: must be number";
        }
        return your_number;
    },

    //*****************************************
    //[5] Generating Fibonacci sequence
    fibonacci: function (first, second, how_many) {
        "use strict";
        var i = 2,
            result,
            array; //starting numbers

        if (Number(first) !== 0 && Number(second) !== 0 && Number(how_many) !== 0) {
            first = this.rd(first);
            second = this.rd(second);
            how_many = this.rd(how_many);
            array = [first, second];

            for (i = 2; i <= how_many + 1; i++) {
                array.push(array[i - 1] + array[i - 2]);
            }
            result = array.join(", ");
        } else {
            result = "INPUT ERROR: only accepts number and non-zero";
        }
        return result;
    },

    //*****************************************
    //[6] Get the factor of a positive integer
    factorof: function (a, b) {
        "use strict";
        var result,
            i = 1,
            j = 0,
            k = 0,
            array = [],
            left = [],
            right = [],
            a_l,
            divider;

        if (!isNaN(a) && a !== 0) { //check if number and non-zero
            if (a < 0) { //convert it to positive integer and round down
                a = this.ab(this.rd(a));
            }

            for (i; i <= a; i++) {
                if (a % i === 0) {
                    array.push(i);
                }
            }

            if (!!b) { //flag for displaying multiplication of the factors
                a_l = array.length;

                if (a_l % 2 === 0) { //if the array length is even
                    divider = a_l / 2;

                    for (j; j < divider; j++) {
                        left.push(array[j]);
                        right.push(array[j + divider]);
                    }

                    right.reverse();
                    array = [];

                    for (k; k < left.length; k++) {
                        array.push(left[k] + " * " + right[k]);
                    }
                } else { //for odd array length
                    divider = this.rd(a_l / 2);

                    for (j; j < divider; j++) {
                        left.push(array[j]);
                        right.push(array[j + divider + 1]);
                    }

                    left.push(array[divider]);
                    right.reverse().push(left[left.length - 1]);
                    array = [];

                    for (k; k < left.length; k++) {
                        array.push(left[k] + " * " + right[k]);
                    }
                }
            }

            result = array.join(", ");
        } else {
            result = "INPUT ERROR: only accepts non-zero integer";
        }
        return result;
    },

    //*****************************************
    //[7] Checking prime number
    prime_check: function (a) {
        "use strict";
        var result,
            i = 2,
            limit;

        //maximum digit length = 21 (999,999,999,999,999,999,999)
        if (a.toString().length < 21) {
            if (!isNaN(a) && a > 1) {
                a = this.rd(a);
                limit = this.rd(this.sqr(a));
                result = "PRIME number";

                for (i; i <= limit; i++) {
                    if (a % i === 0) {
                        result = "Not a prime number";
                        break;
                    }
                }

            } else {
                result = "INPUT ERROR: only positive integer > 1";
            }

        } else {
            result = "INPUT ERROR: digit length <= 21";
        }

        return result;
    },

    //*****************************************
    //[8] Generate prime numbers
    generate_prime: function (start, how_many) {
        "use strict";
        var result,
            primes = [];

        if (Number(start) > 1 && Number(how_many) > 0) {
            start = this.rd(start);
            how_many = this.rd(how_many);

            for (start;  how_many > 0;  start++) {
                if (!this.prime_check(start).match(/not/gi)) {
                    primes.push(start);
                    --how_many;
                }
            }

            result = primes.join(", ");
        } else {
            result = "INPUT ERROR: only positive integer, how_many > 0, start > 1";
        }

        return result;
    }
};
<commit_msg>Updated 3 things<commit_after>//How to use this: https://github.com/monkeyraptor/math_operation

//Change this "math" keyword if it collided with your own JavaScript thingy.
//For example, "goat".
//Then to call the *factorial* function: goat.factorial(2).
var math = {
    //checking above 21 digit length or infinity
    check: function (a) {
        "use strict";
        var result = 0;

        //updated this (2015-04-21)
        if (!!a.toString().match(/error/gi)) {
            result = -1;
        } else if (a.toString().length > 21 || !isFinite(a)) {
            result = 1;
        }

        return result;
    },

    //rounding down
    rd: function (a) {
        "use strict";
        return Math.floor(a);
    },

    //absolute
    ab: function (a) {
        "use strict";
        return Math.abs(a);
    },

    //square root
    sqr: function (a) {
        "use strict";
        return Math.sqrt(a);
    },
    //*****************************************
    //[1] Factorial
    factorial: function (n) {
        "use strict";
        var i = 1,
            result = 1;

        if (Number(n) >= 0) {
            n = this.rd(n);

            if (n > 1) {
                for (i; i <= n; i++) {
                    result *= i;
                }
            } else {
                result = 1;
            }
        } else {
            result = "INPUT ERROR: n >= 0";
        }
        if (this.check(result) > 0) { //updated this (2015-04-21)
            result = "Result is too LARGE: " + result;
        }
        return result;
    },

    //*****************************************
    //[2] Combination
    combination: function (n, k) {
        "use strict";
        var start,
            numerator = 1,
            denumerator = 1,
            i = 1,
            result;

        if (n >= k && Number(n) >= 0 && Number(k) >= 0) {
            n = this.rd(n);
            k = this.rd(k);

            if (n === k) { //updated this (2015-04-21)
                result = 1;
            } else if (k === 1) {
                result = n;
            } else {
                start = n - k + 1;

                for (i; i <= k; i++) {
                    denumerator *= i;
                }
                for (start; start <= n; start++) {
                    numerator *= start;
                }
                result = numerator / denumerator;
            }
        } else {
            result = "INPUT ERROR: n >= k, n >= 0, k >= 0";
        }
        if (this.check(result) > 0) { //updated this (2015-04-21)
            result = "Result is too LARGE: " + result;
        }
        return result;
    },

    //*****************************************
    //[3] Permutation
    permutation: function (n, k) {
        "use strict";
        var start,
            numerator = 1,
            result;

        if (n >= k && Number(n) >= 0 && Number(k) >= 0) {
            n = this.rd(n);
            k = this.rd(k);

            if (n === 0 || k === 0) { //updated this part (2015-04-21)
                result = 1;
            } else if (n === k) { //added this part
                result = this.factorial(n);
            } else if (k === 1) {
                result = n;
            } else {
                start = n - k + 1;
                for (start; start <= n; start++) {
                    numerator *= start;
                }
                result = numerator;
            }
        } else {
            result = "INPUT ERROR: n >= k, n >= 0, k >= 0";
        }
        if (this.check(result) > 0) { //updated this (2015-04-21)
            result = "Result is too LARGE: " + result;
        }
        return result;
    },

    //*****************************************
    //[4] Adding comma to large integer
    addcomma: function (your_number) {
        "use strict";
        var f = [],
            p,
            r,
            i = 1;

        if (!isNaN(your_number)) {
            if (your_number < 0) { p = "-"; } else { p = ""; }

            r = this.rd(this.ab(your_number)).toString();
            f = r.split("").reverse();

            for (i; i <= this.rd(f.length / 4); i++) {
                f.splice((4 * i - 1), 0, ",");
            }
            your_number = p + f.reverse().join("");
        } else {
            your_number = "INPUT ERROR: must be number";
        }
        return your_number;
    },

    //*****************************************
    //[5] Generating Fibonacci sequence
    fibonacci: function (first, second, how_many) {
        "use strict";
        var i = 2,
            result,
            array; //starting numbers

        if (Number(first) !== 0 && Number(second) !== 0 && Number(how_many) !== 0) {
            first = this.rd(first);
            second = this.rd(second);
            how_many = this.rd(how_many);
            array = [first, second];

            for (i = 2; i <= how_many + 1; i++) {
                array.push(array[i - 1] + array[i - 2]);
            }
            result = array.join(", ");
        } else {
            result = "INPUT ERROR: only accepts number and non-zero";
        }
        return result;
    },

    //*****************************************
    //[6] Get the factor of a positive integer
    factorof: function (a, b) {
        "use strict";
        var result,
            i = 1,
            j = 0,
            k = 0,
            array = [],
            left = [],
            right = [],
            a_l,
            divider;

        if (!isNaN(a) && a !== 0) { //check if number and non-zero
            if (a < 0) { //convert it to positive integer and round down
                a = this.ab(this.rd(a));
            }

            for (i; i <= a; i++) {
                if (a % i === 0) {
                    array.push(i);
                }
            }

            if (!!b) { //flag for displaying multiplication of the factors
                a_l = array.length;

                if (a_l % 2 === 0) { //if the array length is even
                    divider = a_l / 2;

                    for (j; j < divider; j++) {
                        left.push(array[j]);
                        right.push(array[j + divider]);
                    }

                    right.reverse();
                    array = [];

                    for (k; k < left.length; k++) {
                        array.push(left[k] + " * " + right[k]);
                    }
                } else { //for odd array length
                    divider = this.rd(a_l / 2);

                    for (j; j < divider; j++) {
                        left.push(array[j]);
                        right.push(array[j + divider + 1]);
                    }

                    left.push(array[divider]);
                    right.reverse().push(left[left.length - 1]);
                    array = [];

                    for (k; k < left.length; k++) {
                        array.push(left[k] + " * " + right[k]);
                    }
                }
            }

            result = array.join(", ");
        } else {
            result = "INPUT ERROR: only accepts non-zero integer";
        }
        return result;
    },

    //*****************************************
    //[7] Checking prime number
    prime_check: function (a) {
        "use strict";
        var result,
            i = 2,
            limit;

        //maximum digit length = 21 (999,999,999,999,999,999,999)
        if (a.toString().length < 21) {
            if (!isNaN(a) && a > 1) {
                a = this.rd(a);
                limit = this.rd(this.sqr(a));
                result = "PRIME number";

                for (i; i <= limit; i++) {
                    if (a % i === 0) {
                        result = "Not a prime number";
                        break;
                    }
                }

            } else {
                result = "INPUT ERROR: only positive integer > 1";
            }

        } else {
            result = "INPUT ERROR: digit length <= 21";
        }

        return result;
    },

    //*****************************************
    //[8] Generate prime numbers
    generate_prime: function (start, how_many) {
        "use strict";
        var result,
            primes = [];

        if (Number(start) > 1 && Number(how_many) > 0) {
            start = this.rd(start);
            how_many = this.rd(how_many);

            for (start;  how_many > 0;  start++) {
                if (!this.prime_check(start).match(/not/gi)) {
                    primes.push(start);
                    --how_many;
                }
            }

            result = primes.join(", ");
        } else {
            result = "INPUT ERROR: only positive integer, how_many > 0, start > 1";
        }

        return result;
    }
};
<|endoftext|>


<commit_before>var timeout;

jQuery(function() {
        reloadWidget();
    });

function reloadWidget() {
    jQuery.ajax("./index.php", {
            success : function(htmlData) {
                jQuery("#infoAjax").html("");
                jQuery("#infoAjax").html(htmlData);
                var h = document.getElementById("tactical-overview").scrollHeight + 10;
                if(h){
                    parent.iResize(window.name, h);
                }else{
                    parent.iResize(window.name, 200);
                }
            }
        });
    if (autoRefresh) {
        if (timeout) {
            clearTimeout(timeout);
        }
        timeout = setTimeout(reloadWidget, (autoRefresh * 1000));
    }
}
<commit_msg>fix: scrollHeight<commit_after>var timeout;

jQuery(function() {
        reloadWidget();
    });

function reloadWidget() {
    jQuery.ajax("./index.php", {
            success : function(htmlData) {
                jQuery("#infoAjax").html("");
                jQuery("#infoAjax").html(htmlData);
                var h = jQuery("#tactical-overview").prop("scrollHeight") + 10;
                if(h){
                    parent.iResize(window.name, h);
                }else{
                    parent.iResize(window.name, 200);
                }
            }
        });
    if (autoRefresh) {
        if (timeout) {
            clearTimeout(timeout);
        }
        timeout = setTimeout(reloadWidget, (autoRefresh * 1000));
    }
}
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import PTT from '../PTT';
import TimerFetch from './TimerFetch';
import Cookies from 'js-cookie';
import LoadingIcon from '../LoadingIcon';
import $ from 'jquery'; // Import jQuery.

/**
 * New Timer form
 */
class TimerNewForm extends Component {
  constructor(props) {
    super(props);

    this.state = {
      view: 'show',
      loading: '',
      post: null, // The current post we are working with.
      projects: null,
      clients: null,
      form: {
        action: PTT.get('endpoint'),
        status: 'publish',
        id: props.post  || '',
        time: props.total || '',
        title: '',
        content: '',
        client: '',
        project: ''
      }
    }

    // Bind this.
    this._handleSubmit = this._handleSubmit.bind(this);
    this._loadClients = this._loadClients.bind(this);
    this._loadProjects = this._loadProjects.bind(this);
    this._updateFieldValue = this._updateFieldValue.bind(this);
  }

  render() {
    const state = this.state;

    return (

        {state.loading}
        <form className={state.view}
            action={state.form.action}
            method="post"
            onSubmit={this._handleSubmit}>

          <input type="hidden"
              name="status"
              value={state.form.status} />

          <input type="hidden"
              name="id"
              value={state.form.id} />

            Title
              <input type="text" name="title" id="title"
                value={state.form.title}
                onChange={this._updateFieldValue} />

            Time
              <input type="text" name="pwptt_hours" id="pwptt_hours"  defaultValue={state.form.time} />

            Description
              <textarea name="content" id="content"
                value={state.form.content}
                onChange={this._updateFieldValue}  />

            Clients
              <input type="text" name="client"
                list="clients" className="new-tag-input"
                ref={(input) => this._client = input}
                onFocus={this._loadClients.bind(this)} />
              {state.clients}

            Projects
              <input type="text" name="project"
                list="projects" className="new-tag-input"
                ref={(input) => this._project = input}
                onFocus={this._loadProjects.bind(this)} />
              {state.projects}

          <button type="submit">Submit</button>
        </form>

    );
  }

  componentDidMount() {
    const state = this.state;

    // if we have a form id, the lets get the post before loading the form
    if ( state.form.id ) {
      // get the post and save it
      state.post = TimerFetch.getPost( state.form.id );
      state.post.then( _p => {
        // Build form before showing it.
        const buildForm = Object.assign( state.form, {
          title:       _p.title.rendered,
          content: _p.content.rendered,
          client: ( _p.premise_time_tracker_client.length )
              ? _p.premise_time_tracker_client.split(',')
              : '',
          project: ( _p.premise_time_tracker_project.length )
               ? _p.premise_time_tracker_project.split(',')
               : '',
        } )
        this.setState( {
          form: buildForm,
        });
        console.log('form should be built');
      } );
    }
  }

  _updateFieldValue(e) {
    var newState = {};
    newState[e.target.name] = e.target.value;
    this.setState({
      form: Object.assign( this.state.form, newState ),
    });
  }

  _handleSubmit(e) {
    e.preventDefault();

    $('body').animate({scrollTop: 0}, 400);

    // Reference 'this' and show the loading icon.
    let _this = this;
    _this.setState( {
      loading: <LoadingIcon />,
      view: 'hide',
    });

    var fields = $(e.target).serializeArray(),
    query      = e.target.action,
    parser     = '',
    id;
    // parse fields
    for (var i = fields.length - 1; i >= 0; i--) {
      // exclude id or empty values
      if ( 'id' !== fields[i].name
         && fields[i].value.length ) {
        parser += '&' + fields[i].name + '=' + fields[i].value;
      }
      // save the id separately
      else {
        id = fields[i].value;
      }
    }
    // build the query
    query += '/' + id + '?' + parser.substr(1, parser.length);

    // save our timer
    $.ajax( {
      url: query,
      method: 'POST',
      beforeSend: PTT.get('auth').ajaxBeforeSend,
    }).done( function( response ) {
      // we were successful!
      console.log(response);
      // delete post cookie
      Cookies.remove( 'ptt_current_timer' );
      // reload because we cannot update the view.
      // TODO fix this!
      location.reload();
    }).fail( function( err ) {
      console.error( err );
      _this.setState( {
        message: There was an error
        // TODO test err.responseText();
      });
    });
  }

  _listTax( terms, taxonomyName ) {

    if (!terms.length) {
      return ;
    }

    let list = [];
    for (var i = terms.length - 1; i >= 0; i--) {
      list.push(
        <option value={terms[i].name} data-id={terms[i].id} />
      );
    }

    const ul = <datalist id={taxonomyName}>
      {list}
    </datalist>;
    return ul;
  }

  _theForm( _form ) {
    // this.state.form = Object.assign( this.state.form, _form );
    // return(

    // );
  }

  _loadClients() {
    console.log('loading clients');
    TimerFetch.getTaxonomy( 'client' ).then( clients => {
      // Do not mutate state directly. Use setState().
      // this.state.clients = this._listTax( clients );
      this.setState({
        clients: this._listTax( clients, 'clients' ),
        view: this._theForm(),
      });
    });
  }

  _loadProjects() {
    console.log('loading projects');
    TimerFetch.getTaxonomy( 'project' ).then( projects => {
      this.setState({
        projects: this._listTax( projects, 'projects' ),
      });
    });
  }
}

export default TimerNewForm;
<commit_msg>Get project / client term ID when submitting form.<commit_after>import React, { Component } from 'react';
import PTT from '../PTT';
import TimerFetch from './TimerFetch';
import Cookies from 'js-cookie';
import LoadingIcon from '../LoadingIcon';
import $ from 'jquery'; // Import jQuery.

/**
 * New Timer form
 */
class TimerNewForm extends Component {
  constructor(props) {
    super(props);

    this.state = {
      view: 'show',
      loading: '',
      post: null, // The current post we are working with.
      premise_time_tracker_project: null,
      premise_time_tracker_client: null,
      form: {
        action: PTT.get('endpoint'),
        status: 'publish',
        id: props.post  || '',
        time: props.total || '',
        title: '',
        content: '',
        client: '',
        project: ''
      }
    }

    // Bind this.
    this._handleSubmit = this._handleSubmit.bind(this);
    this._loadClients = this._loadClients.bind(this);
    this._loadProjects = this._loadProjects.bind(this);
    this._updateFieldValue = this._updateFieldValue.bind(this);
  }

  render() {
    const state = this.state;

    let clientsList, projectsList;

    if ( state.premise_time_tracker_client ) {
      clientsList = this._listTax( state.premise_time_tracker_client, 'clients' );
    }

    if ( state.premise_time_tracker_project ) {
      projectsList = this._listTax( state.premise_time_tracker_project, 'projects' );
    }

    return (

        {state.loading}
        <form className={state.view}
            action={state.form.action}
            method="post"
            onSubmit={this._handleSubmit}>

          <input type="hidden"
              name="status"
              value={state.form.status} />

          <input type="hidden"
              name="id"
              value={state.form.id} />

            Title
              <input type="text" name="title" id="title"
                value={state.form.title}
                onChange={this._updateFieldValue} />

            Time
              <input type="text" name="pwptt_hours" id="pwptt_hours"  defaultValue={state.form.time} />

            Description
              <textarea name="content" id="content"
                value={state.form.content}
                onChange={this._updateFieldValue}  />

            Clients
              <input type="text" name="premise_time_tracker_client"
                list="clients" className="new-tag-input"
                ref={(input) => this._client = input}
                onFocus={this._loadClients.bind(this)} />
              {clientsList}

            Projects
              <input type="text" name="premise_time_tracker_project"
                list="projects" className="new-tag-input"
                ref={(input) => this._project = input}
                onFocus={this._loadProjects.bind(this)} />
              {projectsList}

          <button type="submit">Submit</button>
        </form>

    );
  }

  componentDidMount() {
    const state = this.state;

    // if we have a form id, the lets get the post before loading the form
    if ( state.form.id ) {
      // get the post and save it
      state.post = TimerFetch.getPost( state.form.id );
      state.post.then( _p => {
        // Build form before showing it.
        const buildForm = Object.assign( state.form, {
          title:       _p.title.rendered,
          content: _p.content.rendered,
          client: ( _p.premise_time_tracker_client.length )
              ? _p.premise_time_tracker_client.split(',')
              : '',
          project: ( _p.premise_time_tracker_project.length )
               ? _p.premise_time_tracker_project.split(',')
               : '',
        } )
        this.setState( {
          form: buildForm,
        });
        console.log('form should be built');
      } );
    }
  }

  _updateFieldValue(e) {
    var newState = {};
    newState[e.target.name] = e.target.value;
    this.setState({
      form: Object.assign( this.state.form, newState ),
    });
  }

  _handleSubmit(e) {
    e.preventDefault();

    $('body').animate({scrollTop: 0}, 400);

    // Reference 'this' and show the loading icon.
    let _this = this;
    _this.setState( {
      loading: <LoadingIcon />,
      view: 'hide',
    });

    var fields = $(e.target).serializeArray(),
    query      = e.target.action,
    parser     = '',
    id;
    // parse fields
    for (var i = fields.length - 1; i >= 0; i--) {
      // exclude id or empty values
      if ( 'id' !== fields[i].name
         && fields[i].value.length ) {

        if ( fields[i].name === 'premise_time_tracker_client' ||
          fields[i].name === 'premise_time_tracker_project' ) {
          // Get term ID from list, or create new term if needed.
          fields[i].value = this._getTermId( fields[i].name, fields[i].value );
        }

        parser += '&' + fields[i].name + '=' + fields[i].value;
      }
      // save the id separately
      else {
        id = fields[i].value;
      }
    }
    // build the query
    query += '/' + id + '?' + parser.substr(1, parser.length);

    console.log(query); return;

    // save our timer
    $.ajax( {
      url: query,
      method: 'POST',
      beforeSend: PTT.get('auth').ajaxBeforeSend,
    }).done( function( response ) {
      // we were successful!
      console.log(response);
      // delete post cookie
      Cookies.remove( 'ptt_current_timer' );
      // reload because we cannot update the view.
      // TODO fix this!
      location.reload();
    }).fail( function( err ) {
      console.error( err );
      _this.setState( {
        message: There was an error
        // TODO test err.responseText();
      });
    });
  }

  _listTax( terms, taxonomyName ) {

    if (!terms.length) {
      return ;
    }

    let list = [];
    for (var i = terms.length - 1; i >= 0; i--) {
      list.push(
        <option value={terms[i].name}
          data-id={terms[i].id}
          key={terms[i].name + terms[i].id} />
      );
    }

    const ul = <datalist id={taxonomyName}>
      {list}
    </datalist>;
    return ul;
  }

  _theForm( _form ) {
    // this.state.form = Object.assign( this.state.form, _form );
    // return(

    // );
  }

  _loadClients() {
    console.log('loading clients');
    TimerFetch.getTaxonomy( 'client' ).then( premise_time_tracker_client => {
      // Do not mutate state directly. Use setState().
      // this.state.clients = this._listTax( clients );
      this.setState({
        premise_time_tracker_client
      });
    });
  }

  _loadProjects() {
    console.log('loading projects');
    TimerFetch.getTaxonomy( 'project' ).then( premise_time_tracker_project => {
      this.setState({
        premise_time_tracker_project,
      });
    });
  }

  _getTermId( taxonomyName, termName ) {
    // Check if term already in list.
    let term = this.state[taxonomyName].find(function(term){
      return term.name === termName;
    });

    if ( typeof term !== 'undefined' ) {
      return term.id;
    }

    // TODO Else create term first and get ID.
  }
}

export default TimerNewForm;
<|endoftext|>


<commit_before>/*

  ## Table

  A paginated table of events matching a query

  ### Parameters
  * query ::  A string representing then current query
  * size :: Number of events per page to show
  * pages :: Number of pages to show. size * pages = number of cached events.
             Bigger = more memory usage byh the browser
  * offset :: Position from which to start in the array of hits
  * sort :: An array with 2 elements. sort[0]: field, sort[1]: direction ('asc' or 'desc')
  * style :: hash of css properties
  * fields :: columns to show in table
  * overflow :: 'height' or 'min-height' controls wether the row will expand (min-height) to
                to fit the table, or if the table will scroll to fit the row (height)
  * sortable :: Allow sorting?
  * spyable :: Show the 'eye' icon that reveals the last ES query for this panel
  ### Group Events
  #### Sends
  * table_documents :: An array containing all of the documents in the table.
                       Only used by the fields panel so far.
  #### Receives
  * time :: An object containing the time range to use and the index(es) to query
  * query :: An Array of queries, even if its only one
  * sort :: An array with 2 elements. sort[0]: field, sort[1]: direction ('asc' or 'desc')
  * selected_fields :: An array of fields to show
*/

angular.module('kibana.table', [])
.controller('table', function($rootScope, $scope, eventBus, fields, query, dashboard, filterSrv) {

  // Set and populate defaults
  var _d = {
    status  : "Stable",
    query   : "*",
    size    : 100, // Per page
    pages   : 5,   // Pages available
    offset  : 0,
    sort    : ['@timestamp','desc'],
    group   : "default",
    style   : {'font-size': '9pt'},
    overflow: 'height',
    fields  : [],
    highlight : [],
    sortable: true,
    header  : true,
    paging  : true,
    spyable: true
  }
  _.defaults($scope.panel,_d)

  $scope.init = function () {

    $scope.set_listeners($scope.panel.group)

    $scope.get_data();
  }

  $scope.set_listeners = function(group) {
    $scope.$on('refresh',function(){$scope.get_data()})
    eventBus.register($scope,'sort', function(event,sort){
      $scope.panel.sort = _.clone(sort);
      $scope.get_data();
    });
    eventBus.register($scope,'selected_fields', function(event, fields) {
      $scope.panel.fields = _.clone(fields)
    });
    eventBus.register($scope,'table_documents', function(event, docs) {
        query.list[query.ids[0]].query = docs.query;
        $scope.data = docs.docs;
    });
  }

  $scope.set_sort = function(field) {
    if($scope.panel.sort[0] === field)
      $scope.panel.sort[1] = $scope.panel.sort[1] == 'asc' ? 'desc' : 'asc';
    else
      $scope.panel.sort[0] = field;
    $scope.get_data();
  }

  $scope.toggle_field = function(field) {
    if (_.indexOf($scope.panel.fields,field) > -1)
      $scope.panel.fields = _.without($scope.panel.fields,field)
    else
      $scope.panel.fields.push(field)
    broadcast_results();
  }

  $scope.toggle_highlight = function(field) {
    if (_.indexOf($scope.panel.highlight,field) > -1)
      $scope.panel.highlight = _.without($scope.panel.highlight,field)
    else
      $scope.panel.highlight.push(field)
  }

  $scope.toggle_details = function(row) {
    row.kibana = row.kibana || {};
    row.kibana.details = !row.kibana.details ? $scope.without_kibana(row) : false;
  }

  $scope.page = function(page) {
    $scope.panel.offset = page*$scope.panel.size
    $scope.get_data();
  }

  $scope.build_search = function(field,value,negate) {
    var query;
    // This needs to be abstracted somewhere
    if(_.isArray(value)) {
      query = field+":(" + _.map(value,function(v){return angular.toJson(v)}).join(",") + ")";
    } else {
      query = field+":"+angular.toJson(value);
    }
    filterSrv.set({type:'querystring',query:query,mandate:(negate ? 'mustNot':'must')})
    $scope.panel.offset = 0;
    dashboard.refresh();
  }

  $scope.get_data = function(segment,query_id) {
    $scope.panel.error =  false;

    // Make sure we have everything for the request to complete
    if(dashboard.indices.length == 0) {
      return
    }

    $scope.panel.loading = true;

    var _segment = _.isUndefined(segment) ? 0 : segment
    $scope.segment = _segment;

    var request = $scope.ejs.Request().indices(dashboard.indices[_segment])

    var boolQuery = ejs.BoolQuery();
    _.each(query.list,function(q) {
      boolQuery = boolQuery.should(ejs.QueryStringQuery(q.query || '*'))
    })

    request = request.query(
      ejs.FilteredQuery(
        boolQuery,
        filterSrv.getBoolFilter(filterSrv.ids)
      ))
      .highlight(
        ejs.Highlight($scope.panel.highlight)
        .fragmentSize(2147483647) // Max size of a 32bit unsigned int
        .preTags('@start-highlight@')
        .postTags('@end-highlight@')
      )
      .size($scope.panel.size*$scope.panel.pages)
      .sort($scope.panel.sort[0],$scope.panel.sort[1]);

    $scope.populate_modal(request)

    var results = request.doSearch()

    // Populate scope when we have results
    results.then(function(results) {
      $scope.panel.loading = false;

      if(_segment === 0) {
        $scope.hits = 0;
        $scope.data = [];
        query_id = $scope.query_id = new Date().getTime()
      }

      // Check for error and abort if found
      if(!(_.isUndefined(results.error))) {
        $scope.panel.error = $scope.parse_error(results.error);
        return;
      }

      // Check that we're still on the same query, if not stop
      if($scope.query_id === query_id) {
        $scope.data= $scope.data.concat(_.map(results.hits.hits, function(hit) {
          return {
            _source   : flatten_json(hit['_source']),
            highlight : flatten_json(hit['highlight']||{})
          }
        }));

        $scope.hits += results.hits.total;

        // Sort the data
        $scope.data = _.sortBy($scope.data, function(v){
          return v._source[$scope.panel.sort[0]]
        });

        // Reverse if needed
        if($scope.panel.sort[1] == 'desc')
          $scope.data.reverse();

        // Keep only what we need for the set
        $scope.data = $scope.data.slice(0,$scope.panel.size * $scope.panel.pages)

      } else {
        return;
      }

      // This breaks, use $scope.data for this
      $scope.all_fields = get_all_fields(_.pluck($scope.data,'_source'));
      broadcast_results();

      // If we're not sorting in reverse chrono order, query every index for
      // size*pages results
      // Otherwise, only get size*pages results then stop querying
      if($scope.data.length < $scope.panel.size*$scope.panel.pages
        //($scope.data.length < $scope.panel.size*$scope.panel.pages
         // || !(($scope.panel.sort[0] === $scope.time.field) && $scope.panel.sort[1] === 'desc'))
        && _segment+1 < dashboard.indices.length
      ) {
        $scope.get_data(_segment+1,$scope.query_id)
      }

    });
  }

  $scope.populate_modal = function(request) {
    $scope.modal = {
      title: "Table Inspector",
      body : "
Last Elasticsearch Query

"+
          'curl -XGET '+config.elasticsearch+'/'+dashboard.indices+"/_search?pretty -d'\n"+
          angular.toJson(JSON.parse(request.toString()),true)+
        "'
",
    }
  }

  $scope.without_kibana = function (row) {
    return {
      _source   : row._source,
      highlight : row.highlight
    }
  }

  // Broadcast a list of all fields. Note that receivers of field array
  // events should be able to receive from multiple sources, merge, dedupe
  // and sort on the fly if needed.
  function broadcast_results() {
    eventBus.broadcast($scope.$id,$scope.panel.group,"fields", {
      all   : $scope.all_fields,
      sort  : $scope.panel.sort,
      active: $scope.panel.fields
    });
    eventBus.broadcast($scope.$id,$scope.panel.group,"table_documents",
      {
        query: query.list[query.ids[0]].query,
        docs : _.pluck($scope.data,'_source'),
        index: $scope.index
      });
  }

  $scope.set_refresh = function (state) {
    $scope.refresh = state;
  }

  $scope.close_edit = function() {
    if($scope.refresh)
      $scope.get_data();
    $scope.refresh =  false;
  }

})
.filter('highlight', function() {
  return function(text) {
    if (!_.isUndefined(text) && !_.isNull(text) && text.toString().length > 0) {
      return text.toString().
        replace(/&/g, '&').
        replace(/</g, '<').
        replace(/>/g, '>').
        replace(/\r?\n/g, '
').
        replace(/@start-highlight@/g, '').
        replace(/@end-highlight@/g, '')
    }
    return '';
  }
});
<commit_msg>Yet another fix for #228<commit_after>/*

  ## Table

  A paginated table of events matching a query

  ### Parameters
  * query ::  A string representing then current query
  * size :: Number of events per page to show
  * pages :: Number of pages to show. size * pages = number of cached events.
             Bigger = more memory usage byh the browser
  * offset :: Position from which to start in the array of hits
  * sort :: An array with 2 elements. sort[0]: field, sort[1]: direction ('asc' or 'desc')
  * style :: hash of css properties
  * fields :: columns to show in table
  * overflow :: 'height' or 'min-height' controls wether the row will expand (min-height) to
                to fit the table, or if the table will scroll to fit the row (height)
  * sortable :: Allow sorting?
  * spyable :: Show the 'eye' icon that reveals the last ES query for this panel
  ### Group Events
  #### Sends
  * table_documents :: An array containing all of the documents in the table.
                       Only used by the fields panel so far.
  #### Receives
  * time :: An object containing the time range to use and the index(es) to query
  * query :: An Array of queries, even if its only one
  * sort :: An array with 2 elements. sort[0]: field, sort[1]: direction ('asc' or 'desc')
  * selected_fields :: An array of fields to show
*/

angular.module('kibana.table', [])
.controller('table', function($rootScope, $scope, eventBus, fields, query, dashboard, filterSrv) {

  // Set and populate defaults
  var _d = {
    status  : "Stable",
    query   : "*",
    size    : 100, // Per page
    pages   : 5,   // Pages available
    offset  : 0,
    sort    : ['@timestamp','desc'],
    group   : "default",
    style   : {'font-size': '9pt'},
    overflow: 'height',
    fields  : [],
    highlight : [],
    sortable: true,
    header  : true,
    paging  : true,
    spyable: true
  }
  _.defaults($scope.panel,_d)

  $scope.init = function () {

    $scope.set_listeners($scope.panel.group)

    $scope.get_data();
  }

  $scope.set_listeners = function(group) {
    $scope.$on('refresh',function(){$scope.get_data()})
    eventBus.register($scope,'sort', function(event,sort){
      $scope.panel.sort = _.clone(sort);
      $scope.get_data();
    });
    eventBus.register($scope,'selected_fields', function(event, fields) {
      $scope.panel.fields = _.clone(fields)
    });
    eventBus.register($scope,'table_documents', function(event, docs) {
        query.list[query.ids[0]].query = docs.query;
        $scope.data = docs.docs;
    });
  }

  $scope.set_sort = function(field) {
    if($scope.panel.sort[0] === field)
      $scope.panel.sort[1] = $scope.panel.sort[1] == 'asc' ? 'desc' : 'asc';
    else
      $scope.panel.sort[0] = field;
    $scope.get_data();
  }

  $scope.toggle_field = function(field) {
    if (_.indexOf($scope.panel.fields,field) > -1)
      $scope.panel.fields = _.without($scope.panel.fields,field)
    else
      $scope.panel.fields.push(field)
    broadcast_results();
  }

  $scope.toggle_highlight = function(field) {
    if (_.indexOf($scope.panel.highlight,field) > -1)
      $scope.panel.highlight = _.without($scope.panel.highlight,field)
    else
      $scope.panel.highlight.push(field)
  }

  $scope.toggle_details = function(row) {
    row.kibana = row.kibana || {};
    row.kibana.details = !row.kibana.details ? $scope.without_kibana(row) : false;
  }

  $scope.page = function(page) {
    $scope.panel.offset = page*$scope.panel.size
    $scope.get_data();
  }

  $scope.build_search = function(field,value,negate) {
    var query;
    // This needs to be abstracted somewhere
    if(_.isArray(value)) {
      query = field+":(" + _.map(value,function(v){return angular.toJson(v)}).join(" AND ") + ")";
    } else {
      query = field+":"+angular.toJson(value);
    }
    filterSrv.set({type:'querystring',query:query,mandate:(negate ? 'mustNot':'must')})
    $scope.panel.offset = 0;
    dashboard.refresh();
  }

  $scope.get_data = function(segment,query_id) {
    $scope.panel.error =  false;

    // Make sure we have everything for the request to complete
    if(dashboard.indices.length == 0) {
      return
    }

    $scope.panel.loading = true;

    var _segment = _.isUndefined(segment) ? 0 : segment
    $scope.segment = _segment;

    var request = $scope.ejs.Request().indices(dashboard.indices[_segment])

    var boolQuery = ejs.BoolQuery();
    _.each(query.list,function(q) {
      boolQuery = boolQuery.should(ejs.QueryStringQuery(q.query || '*'))
    })

    request = request.query(
      ejs.FilteredQuery(
        boolQuery,
        filterSrv.getBoolFilter(filterSrv.ids)
      ))
      .highlight(
        ejs.Highlight($scope.panel.highlight)
        .fragmentSize(2147483647) // Max size of a 32bit unsigned int
        .preTags('@start-highlight@')
        .postTags('@end-highlight@')
      )
      .size($scope.panel.size*$scope.panel.pages)
      .sort($scope.panel.sort[0],$scope.panel.sort[1]);

    $scope.populate_modal(request)

    var results = request.doSearch()

    // Populate scope when we have results
    results.then(function(results) {
      $scope.panel.loading = false;

      if(_segment === 0) {
        $scope.hits = 0;
        $scope.data = [];
        query_id = $scope.query_id = new Date().getTime()
      }

      // Check for error and abort if found
      if(!(_.isUndefined(results.error))) {
        $scope.panel.error = $scope.parse_error(results.error);
        return;
      }

      // Check that we're still on the same query, if not stop
      if($scope.query_id === query_id) {
        $scope.data= $scope.data.concat(_.map(results.hits.hits, function(hit) {
          return {
            _source   : flatten_json(hit['_source']),
            highlight : flatten_json(hit['highlight']||{})
          }
        }));

        $scope.hits += results.hits.total;

        // Sort the data
        $scope.data = _.sortBy($scope.data, function(v){
          return v._source[$scope.panel.sort[0]]
        });

        // Reverse if needed
        if($scope.panel.sort[1] == 'desc')
          $scope.data.reverse();

        // Keep only what we need for the set
        $scope.data = $scope.data.slice(0,$scope.panel.size * $scope.panel.pages)

      } else {
        return;
      }

      // This breaks, use $scope.data for this
      $scope.all_fields = get_all_fields(_.pluck($scope.data,'_source'));
      broadcast_results();

      // If we're not sorting in reverse chrono order, query every index for
      // size*pages results
      // Otherwise, only get size*pages results then stop querying
      if($scope.data.length < $scope.panel.size*$scope.panel.pages
        //($scope.data.length < $scope.panel.size*$scope.panel.pages
         // || !(($scope.panel.sort[0] === $scope.time.field) && $scope.panel.sort[1] === 'desc'))
        && _segment+1 < dashboard.indices.length
      ) {
        $scope.get_data(_segment+1,$scope.query_id)
      }

    });
  }

  $scope.populate_modal = function(request) {
    $scope.modal = {
      title: "Table Inspector",
      body : "
Last Elasticsearch Query

"+
          'curl -XGET '+config.elasticsearch+'/'+dashboard.indices+"/_search?pretty -d'\n"+
          angular.toJson(JSON.parse(request.toString()),true)+
        "'
",
    }
  }

  $scope.without_kibana = function (row) {
    return {
      _source   : row._source,
      highlight : row.highlight
    }
  }

  // Broadcast a list of all fields. Note that receivers of field array
  // events should be able to receive from multiple sources, merge, dedupe
  // and sort on the fly if needed.
  function broadcast_results() {
    eventBus.broadcast($scope.$id,$scope.panel.group,"fields", {
      all   : $scope.all_fields,
      sort  : $scope.panel.sort,
      active: $scope.panel.fields
    });
    eventBus.broadcast($scope.$id,$scope.panel.group,"table_documents",
      {
        query: query.list[query.ids[0]].query,
        docs : _.pluck($scope.data,'_source'),
        index: $scope.index
      });
  }

  $scope.set_refresh = function (state) {
    $scope.refresh = state;
  }

  $scope.close_edit = function() {
    if($scope.refresh)
      $scope.get_data();
    $scope.refresh =  false;
  }

})
.filter('highlight', function() {
  return function(text) {
    if (!_.isUndefined(text) && !_.isNull(text) && text.toString().length > 0) {
      return text.toString().
        replace(/&/g, '&').
        replace(/</g, '<').
        replace(/>/g, '>').
        replace(/\r?\n/g, '
').
        replace(/@start-highlight@/g, '').
        replace(/@end-highlight@/g, '')
    }
    return '';
  }
});
<|endoftext|>