<commit_before>Ext.namespace('Gemma');
Ext.BLANK_IMAGE_URL = '/Gemma/images/default/s.gif';
/**
 *
 * Used as one tab of the EE page
 *
 * pass in the ee details obj as experimentDetails
 *
 * @class Gemma.ExpressionExperimentDetails
 * @extends Ext.Panel
 *
 */
Gemma.ExpressionExperimentTools = Ext.extend(Ext.Panel, {
    experimentDetails: null,
    border: false,
    tbar: new Ext.Toolbar(),
	defaultType:'box',
    defaults:{
		border:false
	},
	padding:10,
    initComponent: function(){
        Gemma.ExpressionExperimentTools.superclass.initComponent.call(this);
        var manager = new Gemma.EEManager({
            editable: this.editable
        });
        manager.on('reportUpdated', function(){
        	this.fireEvent('reloadNeeded');
        },this);
        var refreshButton = new Ext.Button({
            text: 'Refresh',
            icon: '/Gemma/images/icons/arrow_refresh_small.png',
            tootltip: 'Refresh statistics',
            handler: function(){
                manager.updateEEReport(this.experimentDetails.id);
            },
            scope: this

        });

        this.getTopToolbar().addButton(refreshButton);
        this.add({
            html: '
Analyses:

'
        });

		var missingValueInfo = this.missingValueAnalysisPanelRenderer(this.experimentDetails, manager);
		this.add(missingValueInfo);
		var processedVectorInfo = this.processedVectorCreatePanelRenderer(this.experimentDetails, manager);
		this.add(processedVectorInfo);
		var differentialAnalysisInfo = this.differentialAnalysisPanelRenderer(this.experimentDetails, manager);
		this.add(differentialAnalysisInfo);
		var linkAnalysisInfo = this.linkAnalysisPanelRenderer(this.experimentDetails, manager);
		this.add(linkAnalysisInfo);

    },

    linkAnalysisPanelRenderer: function(ee, manager){
		var panel = new Ext.Panel({
			layout: 'hbox',
			defaults: {
				border: false,
				padding:2
			},
			items: [{
				html: 'Link Analysis: '
			}]
		});
        var id = ee.id;
		var runBtn = new Ext.Button({
			icon:'/Gemma/images/icons/control_play_blue.png',
			tooltip:'missing value computation',
			handler: manager.doLinks.createDelegate(this,[id]),
			scope:this,
			cls:'transparent-btn'
		});
        if (ee.dateLinkAnalysis) {
            var type = ee.linkAnalysisEventType;
            var color = "#000";
            var suggestRun = true;
            var qtip = 'ext:qtip="Analysis was OK"';
            if (type == 'FailedLinkAnalysisEventImpl') {
                color = 'red';
                qtip = 'ext:qtip="Analysis failed"';
            }
            else
                if (type == 'TooSmallDatasetLinkAnalysisEventImpl') {
                    color = '#CCC';
                    qtip = 'ext:qtip="Analysis was too small"';
                    suggestRun = false;
                }
            panel.add({
				html: '' +
				Ext.util.Format.date(ee.dateLinkAnalysis, 'y/M/d')
			});
			if(suggestRun){
				panel.add(runBtn);
			}
			return panel;
        }
        else {
			panel.add({html:'Needed '});
			panel.add(runBtn);
            return panel;
        }

    },
    missingValueAnalysisPanelRenderer: function(ee, manager){
		var panel = new Ext.Panel({
			layout: 'hbox',
			defaults: {
				border: false,
				padding:2
			},
			items: [{
				html: 'Missing values: '
			}]
		});
        var id = ee.id;
		var runBtn = new Ext.Button({
			icon:'/Gemma/images/icons/control_play_blue.png',
			tooltip:'missing value computation',
			handler: manager.doMissingValues.createDelegate(this,[id]),
			scope:this,
			cls:'transparent-btn'
		});
        /*
         * Offer missing value analysis if it's possible (this might need
         * tweaking).
         */
        if (ee.technologyType != 'ONECOLOR' && ee.hasEitherIntensity) {

            if (ee.dateMissingValueAnalysis) {
                var type = ee.missingValueAnalysisEventType;
                var color = "#000";
                var suggestRun = true;
                var qtip = 'ext:qtip="OK"';
                if (type == 'FailedMissingValueAnalysisEventImpl') {
                    color = 'red';
                    qtip = 'ext:qtip="Failed"';
                }

                //return '' +
                //Ext.util.Format.date(ee.dateMissingValueAnalysis, 'y/M/d') +
                //' ' +
                //(suggestRun ? runurl : '');
				panel.add({ html: '' +
					Ext.util.Format.date(ee.dateMissingValueAnalysis, 'y/M/d') +
					' '});
					if(suggestRun){
						panel.add(runBtn);
					}
				return panel;
            }
            else {
				panel.add({
					html: 'Needed '
				});
				panel.add(runBtn);
                return panel;
            }

        }
        else {

				panel.add({
					html: 'NA'
				});
                return panel;
        }
    },

    processedVectorCreatePanelRenderer: function(ee, manager){
        var panel = new Ext.Panel({
			layout: 'hbox',
			defaults: {
				border: false,
				padding:2
			},
			items: [{
				html: 'Proccessed Vector Computation: '
			}]
		});
        var id = ee.id;
		var runBtn = new Ext.Button({
			icon:'/Gemma/images/icons/control_play_blue.png',
			tooltip:'processed vector computation',
			handler: manager.doProcessedVectors.createDelegate(this,[id]),
			scope:this,
			cls:'transparent-btn'
		});
        if (ee.dateProcessedDataVectorComputation) {
            var type = ee.processedDataVectorComputationEventType;
            var color = "#000";

            var suggestRun = true;
            var qtip = 'ext:qtip="OK"';
            if (type == 'FailedProcessedVectorComputationEventImpl') { // note:
                // no
                // such
                // thing.
                color = 'red';
                qtip = 'ext:qtip="Failed"';
            }
            panel.add({html:'' +
            Ext.util.Format.date(ee.dateProcessedDataVectorComputation, 'y/M/d') +
            ' '});
			if(suggestRun){
				panel.add(runBtn);
			}
            return panel;
        }
        else {
			panel.add({html:'Needed '});
			panel.add(runBtn);
            return panel;
        }
    },

    differentialAnalysisPanelRenderer: function(ee, manager){
        var panel = new Ext.Panel({
			layout: 'hbox',
			defaults: {
				border: false,
				padding:2
			},
			items: [{
				html: 'Differential Expression Analysis: '
			}]
		});
        var id = ee.id;
		var runBtn = new Ext.Button({
			icon:'/Gemma/images/icons/control_play_blue.png',
			tooltip:'differential expression analysis',
			handler: manager.doDifferential.createDelegate(this,[id]),
			scope:this,
			cls:'transparent-btn'
		});
        if (ee.numPopulatedFactors > 0) {
            if (ee.dateDifferentialAnalysis) {
                var type = ee.differentialAnalysisEventType;

                var color = "#000";
                var suggestRun = true;
                var qtip = 'ext:qtip="OK"';
                if (type == 'FailedDifferentialExpressionAnalysisEventImpl') { // note:
                    // no
                    // such
                    // thing.
                    color = 'red';
                    qtip = 'ext:qtip="Failed"';
                }
                panel.add({html:'' +
                Ext.util.Format.date(ee.dateDifferentialAnalysis, 'y/M/d') +
                ' '});
				if(suggestRun){
					panel.add(runBtn);
				}
                return panel;
            }
            else {

                panel.add({html:'Needed '});
				panel.add(runBtn);
                return panel;
            }
        }
        else {

            panel.add({html:'NA'});
            return panel;
        }
    },
    renderProcessedExpressionVectorCount: function(e){
        return e.processedExpressionVectorCount ? e.processedExpressionVectorCount : ' [count not available] ';
    }
});

<commit_msg>minor change - fix tooltip<commit_after>Ext.namespace('Gemma');
Ext.BLANK_IMAGE_URL = '/Gemma/images/default/s.gif';
/**
 *
 * Used as one tab of the EE page - the "Admin" tab.
 *
 * pass in the ee details obj as experimentDetails
 *
 * @class Gemma.ExpressionExperimentDetails
 * @extends Ext.Panel
 * version $Id$
 *
 */
Gemma.ExpressionExperimentTools = Ext.extend(Ext.Panel, {
    experimentDetails: null,
    border: false,
    tbar: new Ext.Toolbar(),
	defaultType:'box',
    defaults:{
		border:false
	},
	padding:10,
    initComponent: function(){
        Gemma.ExpressionExperimentTools.superclass.initComponent.call(this);
        var manager = new Gemma.EEManager({
            editable: this.editable
        });
        manager.on('reportUpdated', function(){
        	this.fireEvent('reloadNeeded');
        },this);
        var refreshButton = new Ext.Button({
            text: 'Refresh',
            icon: '/Gemma/images/icons/arrow_refresh_small.png',
            tooltip: 'Refresh statistics (not including the differential expression ones)',
            handler: function(){
                manager.updateEEReport(this.experimentDetails.id);
            },
            scope: this

        });

        this.getTopToolbar().addButton(refreshButton);
        this.add({
            html: '
Analyses:

'
        });

		var missingValueInfo = this.missingValueAnalysisPanelRenderer(this.experimentDetails, manager);
		this.add(missingValueInfo);
		var processedVectorInfo = this.processedVectorCreatePanelRenderer(this.experimentDetails, manager);
		this.add(processedVectorInfo);
		var differentialAnalysisInfo = this.differentialAnalysisPanelRenderer(this.experimentDetails, manager);
		this.add(differentialAnalysisInfo);
		var linkAnalysisInfo = this.linkAnalysisPanelRenderer(this.experimentDetails, manager);
		this.add(linkAnalysisInfo);

    },

    linkAnalysisPanelRenderer: function(ee, manager){
		var panel = new Ext.Panel({
			layout: 'hbox',
			defaults: {
				border: false,
				padding:2
			},
			items: [{
				html: 'Link Analysis: '
			}]
		});
        var id = ee.id;
		var runBtn = new Ext.Button({
			icon:'/Gemma/images/icons/control_play_blue.png',
			tooltip:'missing value computation',
			handler: manager.doLinks.createDelegate(this,[id]),
			scope:this,
			cls:'transparent-btn'
		});
        if (ee.dateLinkAnalysis) {
            var type = ee.linkAnalysisEventType;
            var color = "#000";
            var suggestRun = true;
            var qtip = 'ext:qtip="Analysis was OK"';
            if (type == 'FailedLinkAnalysisEventImpl') {
                color = 'red';
                qtip = 'ext:qtip="Analysis failed"';
            }
            else
                if (type == 'TooSmallDatasetLinkAnalysisEventImpl') {
                    color = '#CCC';
                    qtip = 'ext:qtip="Analysis was too small"';
                    suggestRun = false;
                }
            panel.add({
				html: '' +
				Ext.util.Format.date(ee.dateLinkAnalysis, 'y/M/d')
			});
			if(suggestRun){
				panel.add(runBtn);
			}
			return panel;
        }
        else {
			panel.add({html:'Needed '});
			panel.add(runBtn);
            return panel;
        }

    },
    missingValueAnalysisPanelRenderer: function(ee, manager){
		var panel = new Ext.Panel({
			layout: 'hbox',
			defaults: {
				border: false,
				padding:2
			},
			items: [{
				html: 'Missing values: '
			}]
		});
        var id = ee.id;
		var runBtn = new Ext.Button({
			icon:'/Gemma/images/icons/control_play_blue.png',
			tooltip:'missing value computation',
			handler: manager.doMissingValues.createDelegate(this,[id]),
			scope:this,
			cls:'transparent-btn'
		});
        /*
         * Offer missing value analysis if it's possible (this might need
         * tweaking).
         */
        if (ee.technologyType != 'ONECOLOR' && ee.hasEitherIntensity) {

            if (ee.dateMissingValueAnalysis) {
                var type = ee.missingValueAnalysisEventType;
                var color = "#000";
                var suggestRun = true;
                var qtip = 'ext:qtip="OK"';
                if (type == 'FailedMissingValueAnalysisEventImpl') {
                    color = 'red';
                    qtip = 'ext:qtip="Failed"';
                }

                //return '' +
                //Ext.util.Format.date(ee.dateMissingValueAnalysis, 'y/M/d') +
                //' ' +
                //(suggestRun ? runurl : '');
				panel.add({ html: '' +
					Ext.util.Format.date(ee.dateMissingValueAnalysis, 'y/M/d') +
					' '});
					if(suggestRun){
						panel.add(runBtn);
					}
				return panel;
            }
            else {
				panel.add({
					html: 'Needed '
				});
				panel.add(runBtn);
                return panel;
            }

        }
        else {

				panel.add({
					html: 'NA'
				});
                return panel;
        }
    },

    processedVectorCreatePanelRenderer: function(ee, manager){
        var panel = new Ext.Panel({
			layout: 'hbox',
			defaults: {
				border: false,
				padding:2
			},
			items: [{
				html: 'Proccessed Vector Computation: '
			}]
		});
        var id = ee.id;
		var runBtn = new Ext.Button({
			icon:'/Gemma/images/icons/control_play_blue.png',
			tooltip:'processed vector computation',
			handler: manager.doProcessedVectors.createDelegate(this,[id]),
			scope:this,
			cls:'transparent-btn'
		});
        if (ee.dateProcessedDataVectorComputation) {
            var type = ee.processedDataVectorComputationEventType;
            var color = "#000";

            var suggestRun = true;
            var qtip = 'ext:qtip="OK"';
            if (type == 'FailedProcessedVectorComputationEventImpl') { // note:
                // no
                // such
                // thing.
                color = 'red';
                qtip = 'ext:qtip="Failed"';
            }
            panel.add({html:'' +
            Ext.util.Format.date(ee.dateProcessedDataVectorComputation, 'y/M/d') +
            ' '});
			if(suggestRun){
				panel.add(runBtn);
			}
            return panel;
        }
        else {
			panel.add({html:'Needed '});
			panel.add(runBtn);
            return panel;
        }
    },

    differentialAnalysisPanelRenderer: function(ee, manager){
        var panel = new Ext.Panel({
			layout: 'hbox',
			defaults: {
				border: false,
				padding:2
			},
			items: [{
				html: 'Differential Expression Analysis: '
			}]
		});
        var id = ee.id;
		var runBtn = new Ext.Button({
			icon:'/Gemma/images/icons/control_play_blue.png',
			tooltip:'differential expression analysis',
			handler: manager.doDifferential.createDelegate(this,[id]),
			scope:this,
			cls:'transparent-btn'
		});
        if (ee.numPopulatedFactors > 0) {
            if (ee.dateDifferentialAnalysis) {
                var type = ee.differentialAnalysisEventType;

                var color = "#000";
                var suggestRun = true;
                var qtip = 'ext:qtip="OK"';
                if (type == 'FailedDifferentialExpressionAnalysisEventImpl') { // note:
                    // no
                    // such
                    // thing.
                    color = 'red';
                    qtip = 'ext:qtip="Failed"';
                }
                panel.add({html:'' +
                Ext.util.Format.date(ee.dateDifferentialAnalysis, 'y/M/d') +
                ' '});
				if(suggestRun){
					panel.add(runBtn);
				}
                return panel;
            }
            else {

                panel.add({html:'Needed '});
				panel.add(runBtn);
                return panel;
            }
        }
        else {

            panel.add({html:'NA'});
            return panel;
        }
    },
    renderProcessedExpressionVectorCount: function(e){
        return e.processedExpressionVectorCount ? e.processedExpressionVectorCount : ' [count not available] ';
    }
});

<|endoftext|>


<commit_before>/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */

'use strict';

if (!window['Gaia'])
  var Gaia = {};

(function() {

  var lastDragPosition = -1;
  var isKeyDown = false;

  Gaia.TaskManager = {

    _isActive: false,

    get isActive() {
      return this._isActive;
    },

    set isActive(value) {
      this._isActive = value;

      var runningApps = Gaia.AppManager.runningApps;

      if (value) {
        this.element.classList.add('active');
        for (var i = 0; i < runningApps.length; i++) {
          var classList = runningApps[i].window.classList;
          classList.add('active');
          classList.add('noTransition');
        }
      } else {
        this.element.classList.remove('active');
        for (var i = 0; i < runningApps.length; i++) {
          var classList = runningApps[i].window.classList;
          classList.remove('active');
          classList.remove('noTransition');
        }
      }
    },

    get element() {
      delete this.element;

      return this.element = document.getElementById('taskManager');
    },

    get listElement() {
      delete this.listElement;

      return this.listElement = this.element.getElementsByTagName('ul')[0];
    },

    init: function() {
      window.addEventListener('keydown', this);
      window.addEventListener('keyup', this);

      var listElement = this.listElement;
      listElement.addEventListener('touchstart', this);
      listElement.addEventListener('touchmove', this);
      listElement.addEventListener('touchend', this);
    },

    handleEvent: function(evt) {
      switch (evt.type) {
        case 'keydown':
          if (evt.keyCode !== evt.DOM_VK_ESCAPE || isKeyDown)
            return;

          isKeyDown = true;

          if (this.isActive)
            this.isActive = false;
          else {
            setTimeout(function(self) {
              if (isKeyDown)
                self.isActive = true;
            }, 1000, this);
          }
          break;
        case 'keyup':
          if (evt.keyCode !== evt.DOM_VK_ESCAPE)
            return;

          isKeyDown = false;
          break;
        case 'touchstart':
          var touches = evt.changedTouches;

          if (touches.length !== 1)
            return;

          var touch = touches[0];
          lastDragPosition = touch.pageX;
          break;
        case 'touchmove':
          if (lastDragPosition === -1)
            return;

          var touches = evt.changedTouches;

          if (touches.length !== 1)
            return;

          var touch = touches[0];
          this.listElement.scrollLeft -= touch.pageX - lastDragPosition;
          lastDragPosition = touch.pageX;
          break;
        case 'touchend':
          lastDragPosition = -1;
          break;
        default:
          throw new Error('Unhandled event in TaskManager');
          break;
      }
    },

    add: function(id) {
      var item = document.createElement('li');
      item.id = 'task_' + id;
      item.setAttribute('style', 'background: -moz-element(#app_' + id + ') no-repeat');
      this.listElement.appendChild(item);
      return item;
    },

    remove: function(id) {
      var listElement = this.listElement;
      var item = listElement.getElementById('task_' + id);
      listElement.removeChild(item);
    }

  };

  window.addEventListener('load', function(evt) {
    Gaia.TaskManager.init();
  });

})();<commit_msg>Added animation frames to the 'snap' when swiping between tasks in the Task Manager.<commit_after>/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */

'use strict';

if (!window['Gaia'])
  var Gaia = {};

(function() {

  var lastDragPosition = -1;
  var isKeyDown = false;
  var checkKeyPressTimeout = null;
  var animateScrollInterval = null;

  var animationLoop = function(renderCallback) {
    var isRunning = true;
    var lastFrame = +new Date();
    var requestAnimationFrame = function(animFrameCallback) {
      if (window.mozRequestAnimationFrame)
        window.mozRequestAnimationFrame(animFrameCallback);
      else if (window.webkitRequestAnimationFrame)
        window.webkitRequestAnimationFrame(animFrameCallback);
      else if (window.requestAnimationFrame)
        window.requestAnimationFrame(animFrameCallback);
    };

    (function loop(currentFrame) {
      if (isRunning !== false) {
        requestAnimationFrame(loop);
        isRunning = renderCallback(currentFrame - lastFrame);
        lastFrame = currentFrame;
      }
    })(lastFrame);
  };

  Gaia.TaskManager = {

    _isActive: false,

    get isActive() {
      return this._isActive;
    },

    set isActive(value) {
      this._isActive = value;

      var runningApps = Gaia.AppManager.runningApps;

      if (value) {
        this.element.classList.add('active');
        for (var i = 0; i < runningApps.length; i++) {
          var classList = runningApps[i].window.classList;
          classList.add('active');
          classList.add('noTransition');
        }
      } else {
        this.element.classList.remove('active');
        for (var i = 0; i < runningApps.length; i++) {
          var classList = runningApps[i].window.classList;
          classList.remove('active');
          classList.remove('noTransition');
        }
      }
    },

    get element() {
      delete this.element;

      return this.element = document.getElementById('taskManager');
    },

    get listElement() {
      delete this.listElement;

      return this.listElement = this.element.getElementsByTagName('ul')[0];
    },

    init: function() {
      window.addEventListener('keydown', this);
      window.addEventListener('keyup', this);

      var listElement = this.listElement;
      listElement.addEventListener('touchstart', this);
      listElement.addEventListener('touchmove', this);
      listElement.addEventListener('touchend', this);
    },

    handleEvent: function(evt) {
      switch (evt.type) {
        case 'keydown':
          if (evt.keyCode !== evt.DOM_VK_ESCAPE || isKeyDown)
            return;

          if (checkKeyPressTimeout) {
            clearTimeout(checkKeyPressTimeout);
            checkKeyPressTimeout = null;
          }

          isKeyDown = true;

          if (this.isActive)
            this.isActive = false;
          else {
            checkKeyPressTimeout = setTimeout(function checkKeyPress(self) {
              checkKeyPressTimeout = null;

              if (isKeyDown)
                self.isActive = true;
            }, 1000, this);
          }
          break;
        case 'keyup':
          if (evt.keyCode !== evt.DOM_VK_ESCAPE)
            return;

          if (checkKeyPressTimeout) {
            clearTimeout(checkKeyPressTimeout);
            checkKeyPressTimeout = null;
          }

          isKeyDown = false;
          break;
        case 'touchstart':
          var touches = evt.changedTouches;

          if (touches.length !== 1)
            return;

          var touch = touches[0];
          lastDragPosition = touch.pageX;
          break;
        case 'touchmove':
          if (lastDragPosition === -1)
            return;

          var touches = evt.changedTouches;

          if (touches.length !== 1)
            return;

          var touch = touches[0];
          this.listElement.scrollLeft -= touch.pageX - lastDragPosition;
          lastDragPosition = touch.pageX;
          break;
        case 'touchend':
          var listElement = this.listElement;
          var listItemWidth = window.innerWidth * 0.6;
          var listIndex = Math.round(this.listElement.scrollLeft / listItemWidth);
          var currentScrollLeft = listElement.scrollLeft;
          var targetScrollLeft = listIndex * listItemWidth;
          var willAnimateToTheLeft = (currentScrollLeft < targetScrollLeft);

         if (currentScrollLeft !== targetScrollLeft) {
            animationLoop(function(deltaTime) {
              if (willAnimateToTheLeft) {
                listElement.scrollLeft = currentScrollLeft += 10 * deltaTime / 16;

                if (currentScrollLeft >= targetScrollLeft) {
                  listElement.scrollLeft = currentScrollLeft = targetScrollLeft;
                  return false;
                }
              } else {
                listElement.scrollLeft = currentScrollLeft -= 10 * deltaTime / 16;

                if (currentScrollLeft <= targetScrollLeft) {
                  listElement.scrollLeft = currentScrollLeft = targetScrollLeft;
                  return false;
                }
              }
            });
          }

          lastDragPosition = -1;
          break;
        default:
          throw new Error('Unhandled event in TaskManager');
          break;
      }
    },

    add: function(id) {
      var item = document.createElement('li');
      item.id = 'task_' + id;
      item.setAttribute('style', 'background: -moz-element(#app_' + id + ') no-repeat');
      this.listElement.appendChild(item);
      return item;
    },

    remove: function(id) {
      var listElement = this.listElement;
      var item = listElement.getElementById('task_' + id);
      listElement.removeChild(item);
    }

  };

  window.addEventListener('load', function(evt) {
    Gaia.TaskManager.init();
  });

})();<|endoftext|>


<commit_before>$(document).ready(function() {

    if ($("div.pollItemsValue").length == maxPollItems) {
        $("a#add").hide();
    }

    $( "#sortable" ).sortable({update: function(event, ui) {reIndex()}});

    var name = $("#sortable").attr("rel");

    $("a#add").click(function(e){
        e.preventDefault();
        length = $("div.pollItemsValue").length;
        if(length < maxPollItems) {
            newItem = $(".pollItemsValue:last").clone();
            $(newItem).insertAfter(".pollItemsValue:last");
            $("input[type=text]", newItem).val("");
            reIndex();
            if ($("div.pollItemsValue").length == maxPollItems) {
                $("a#add").hide();
            }
        }
    });

    $(".pollItemsValue .remove").live("click", function(e){
        e.preventDefault();
        if($("div.pollItemsValue").length > minPollItems) {
            $(this).closest('div.pollItemsValue').remove();
            reIndex();
            if ($("div.pollItemsValue").length < maxPollItems) {
                $("a#add").show();
            }
        }
    });

    function reIndex(){
        $(".pollItemsValue input[type=text]").each(function(index) {
            $(this).attr("name", name.replace("__index__", index));
        });
    }
});<commit_msg>#JC-1373 Add dynamic poll item functionality * Do refactoring accroding to CR<commit_after>$(document).ready(function() {

    if ($("div.pollItemsValue").length == maxPollItems) {
        $("a#add").hide();
    }

    $("#sortable").sortable({update: function(event, ui) {reIndex()}});

    var name = $("#sortable").attr("rel");

    $("a#add").click(function(e){
        e.preventDefault();
        length = $("div.pollItemsValue").length;
        if(length < maxPollItems) {
            newItem = $(".pollItemsValue:last").clone();
            $(newItem).insertAfter(".pollItemsValue:last");
            $("input[type=text]", newItem).val("");
            reIndex();
            if ($("div.pollItemsValue").length == maxPollItems) {
                $("a#add").hide();
            }
        }
    });

    $(".pollItemsValue .remove").live("click", function(e){
        e.preventDefault();
        if($("div.pollItemsValue").length > minPollItems) {
            $(this).closest('div.pollItemsValue').remove();
            reIndex();
            $("a#add").show();
        }
    });

    function reIndex(){
        $(".pollItemsValue input[type=text]").each(function(index) {
            $(this).attr("name", name.replace("__index__", index));
        });
    }
});<|endoftext|>


<commit_before>define ([
    'kbwidget',
    'bootstrap',
    'jquery',
    'kbase-client-api',
    'widgets/dynamicTable',
    'kbaseAuthenticatedWidget',
    'kbaseTabs',
    'kbase-generic-client-api',
    'narrativeConfig',
    'bluebird'
], function(
	KBWidget,
	bootstrap,
	$,
    kbase_client_api,
    DynamicTable,
	kbaseAuthenticatedWidget,
    kbaseTabs,
    GenericClient,
    Config,
    Promise
) {
    'use strict';

    return KBWidget({
        name: 'kbaseGenomeAnnotationAssembly',
        parent: kbaseAuthenticatedWidget,
        version: '1.0.0',
        options: {
            pageLimit: 10

        },

        init: function init(options) {
            this._super(options);

            var self = this;
            self.obj_ref = self.options.wsNameOrId + '/' + self.options.objNameOrId;
            self.link_ref = self.obj_ref;

            if(options._obj_info) {
                self.assembly_info = options._obj_info;
                self.obj_ref = self.assembly_info['ws_id'] + '/' + self.assembly_info['id'] + '/' + self.assembly_info['version'];
                self.link_ref = self.assembly_info['ws_id'] + '/' + self.assembly_info['name'] + '/' + self.assembly_info['version'];
            }

            self.client = new GenericClient(Config.url('service_wizard'), {token: self.authToken()});
            self.ws = new Workspace(Config.url('workspace'),{'token':self.authToken()});

            self.$elem.append($('
').attr('align', 'center').append($('')));

            // 1) get stats, and show the panel
            var basicInfoCalls = [];
            basicInfoCalls.push(
                Promise.resolve(self.client.sync_call('AssemblyAPI.get_stats', [this.obj_ref], null, null, 'dev'))
                    .then(function(stats) {
                        self.assembly_stats = stats[0];
                    }));
            basicInfoCalls.push(
                Promise.resolve(self.ws.get_object_info_new({objects: [{'ref':this.obj_ref}], includeMetadata:1}))
                    .then(function(info) {
                        self.assembly_obj_info = info[0];
                        self.link_ref = info[0][6] + '/' + info[0][1] + '/' + info[0][4];
                    }));
            Promise.all(basicInfoCalls)
                .then(function() {
                    self.renderBasicTable();
                })
                .catch(function(err) {
                    console.error('an error occurred! ' + err);
                    self.$elem.empty();
                    self.$elem.append('Error' + JSON.stringify(err));
                });

            return this;
        },

        processContigData: function() {
            var self = this;

            var contig_table = [];
            for (var id in self.contig_lengths) {
                if (self.contig_lengths.hasOwnProperty(id)) {
                    var gc='unknown';
                    if(self.contig_lengths.hasOwnProperty(id)) {
                        gc = String((self.contig_gc[id]*100).toFixed(2)) + '%';
                    }
                    var contig = {
                        id: id,
                        len: '' + String(self.numberWithCommas(self.contig_lengths[id]))+' bp',
                        gc:  gc
                    };
                    contig_table.push(contig);
                }
            }
            self.contig_table = contig_table;
            //console.log(contig_table);
        },

        renderBasicTable: function() {
            var self = this;
            var $container = this.$elem;
            $container.empty();

            var $tabPane = $('
');
            $container.append($tabPane);

            // Build the overview table
            var $overviewTable = $('
');

            function get_table_row(key, value) {
                return $('
').append($('').append(key)).append($('').append(value));
            }

            $overviewTable.append(get_table_row('KBase Object Name',
                '' + self.assembly_obj_info[1] +'' ));
                // leave out version for now, because that is not passed into data widgets
                //'' + self.assembly_obj_info[1] + ' (v'+self.assembly_obj_info[4]+')'+'' ));
            $overviewTable.append(get_table_row('Number of Contigs', self.assembly_stats['num_contigs'] ));
            $overviewTable.append(get_table_row('Total GC Content',  String((self.assembly_stats['gc_content']*100).toFixed(2)) + '%' ));
            $overviewTable.append(get_table_row('Total Length',      String(self.numberWithCommas(self.assembly_stats['dna_size']))+' bp'  )  );

            // Build the tabs
            var $tabs = new kbaseTabs($tabPane, {
                tabPosition : 'top',
                canDelete : true, //whether or not the tab can be removed.
                tabs : [
                    {
                        tab : 'Assembly Summary',   //name of the tab
                        content : $('
').css('margin-top','15px').append($overviewTable),  //jquery object to stuff into the content
                        canDelete : false, //override the canDelete param on a per tab basis
                        show : true,
                    }, {
                        tab : 'Contigs',
                        canDelete : false,
                        showContentCallback: function() {
                            return self.addContigList();
                        }
                    },
                ],
            });
        },

        addContigList: function() {
            var self = this;
            var $content = $('
');
            new DynamicTable($content, {
                headers: [{
                    id: 'contig_id',
                    text: 'Contig Id',
                    isSortable: true
                }, {
                    id: 'length',
                    text: 'Length (bp)',
                    isSortable: true
                }, {
                    id: 'gc',
                    text: 'GC Content (%)',
                    isSortable: true
                }],
                searchPlaceholder: 'Search contigs',
                updateFunction: function(pageNum, query, sortColId, sortColDir) {
                    var sortBy = [];
                    if (sortColId && sortColDir !== 0) {
                        sortBy.push([sortColId, sortColDir < 0 ? 0 : 1]);
                    }
                    return Promise.resolve(self.client.sync_call('AssemblyAPI.search_contigs', [{
                        ref: self.obj_ref,
                        query: query,
                        sort_by: sortBy,
                        start: pageNum * self.options.pageLimit
                    }], null, null, 'dev'))
                    .then(function(results) {
                        results = results[0];
                        var rows = [];
                        results.contigs.forEach(function(contig) {
                            rows.push([contig.contig_id, contig.length, contig.gc]);
                        });
                        return {
                            rows: rows,
                            start: results.start,
                            query: results.query,
                            total: results.num_found,
                        };
                    });
                },
                style: {'margin-top': '5px'}
            });
            return $content;
        },

        numberWithCommas: function(x) {
            return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
        }
    });

});
<commit_msg>Removed dependency on 'dev' version of AssemblyAPI for assembly viewer<commit_after>define ([
    'kbwidget',
    'bootstrap',
    'jquery',
    'kbase-client-api',
    'widgets/dynamicTable',
    'kbaseAuthenticatedWidget',
    'kbaseTabs',
    'kbase-generic-client-api',
    'narrativeConfig',
    'bluebird'
], function(
	KBWidget,
	bootstrap,
	$,
    kbase_client_api,
    DynamicTable,
	kbaseAuthenticatedWidget,
    kbaseTabs,
    GenericClient,
    Config,
    Promise
) {
    'use strict';

    return KBWidget({
        name: 'kbaseGenomeAnnotationAssembly',
        parent: kbaseAuthenticatedWidget,
        version: '1.0.0',
        options: {
            pageLimit: 10

        },

        init: function init(options) {
            this._super(options);

            var self = this;
            self.obj_ref = self.options.wsNameOrId + '/' + self.options.objNameOrId;
            self.link_ref = self.obj_ref;

            if(options._obj_info) {
                self.assembly_info = options._obj_info;
                self.obj_ref = self.assembly_info['ws_id'] + '/' + self.assembly_info['id'] + '/' + self.assembly_info['version'];
                self.link_ref = self.assembly_info['ws_id'] + '/' + self.assembly_info['name'] + '/' + self.assembly_info['version'];
            }

            self.client = new GenericClient(Config.url('service_wizard'), {token: self.authToken()});
            self.ws = new Workspace(Config.url('workspace'),{'token':self.authToken()});

            self.$elem.append($('
').attr('align', 'center').append($('')));

            // 1) get stats, and show the panel
            var basicInfoCalls = [];
            basicInfoCalls.push(
                Promise.resolve(self.client.sync_call('AssemblyAPI.get_stats', [this.obj_ref]))
                    .then(function(stats) {
                        self.assembly_stats = stats[0];
                    }));
            basicInfoCalls.push(
                Promise.resolve(self.ws.get_object_info_new({objects: [{'ref':this.obj_ref}], includeMetadata:1}))
                    .then(function(info) {
                        self.assembly_obj_info = info[0];
                        self.link_ref = info[0][6] + '/' + info[0][1] + '/' + info[0][4];
                    }));
            Promise.all(basicInfoCalls)
                .then(function() {
                    self.renderBasicTable();
                })
                .catch(function(err) {
                    console.error('an error occurred! ' + err);
                    self.$elem.empty();
                    self.$elem.append('Error' + JSON.stringify(err));
                });

            return this;
        },

        processContigData: function() {
            var self = this;

            var contig_table = [];
            for (var id in self.contig_lengths) {
                if (self.contig_lengths.hasOwnProperty(id)) {
                    var gc='unknown';
                    if(self.contig_lengths.hasOwnProperty(id)) {
                        gc = String((self.contig_gc[id]*100).toFixed(2)) + '%';
                    }
                    var contig = {
                        id: id,
                        len: '' + String(self.numberWithCommas(self.contig_lengths[id]))+' bp',
                        gc:  gc
                    };
                    contig_table.push(contig);
                }
            }
            self.contig_table = contig_table;
            //console.log(contig_table);
        },

        renderBasicTable: function() {
            var self = this;
            var $container = this.$elem;
            $container.empty();

            var $tabPane = $('
');
            $container.append($tabPane);

            // Build the overview table
            var $overviewTable = $('
');

            function get_table_row(key, value) {
                return $('
').append($('').append(key)).append($('').append(value));
            }

            $overviewTable.append(get_table_row('KBase Object Name',
                '' + self.assembly_obj_info[1] +'' ));
                // leave out version for now, because that is not passed into data widgets
                //'' + self.assembly_obj_info[1] + ' (v'+self.assembly_obj_info[4]+')'+'' ));
            $overviewTable.append(get_table_row('Number of Contigs', self.assembly_stats['num_contigs'] ));
            $overviewTable.append(get_table_row('Total GC Content',  String((self.assembly_stats['gc_content']*100).toFixed(2)) + '%' ));
            $overviewTable.append(get_table_row('Total Length',      String(self.numberWithCommas(self.assembly_stats['dna_size']))+' bp'  )  );

            // Build the tabs
            var $tabs = new kbaseTabs($tabPane, {
                tabPosition : 'top',
                canDelete : true, //whether or not the tab can be removed.
                tabs : [
                    {
                        tab : 'Assembly Summary',   //name of the tab
                        content : $('
').css('margin-top','15px').append($overviewTable),  //jquery object to stuff into the content
                        canDelete : false, //override the canDelete param on a per tab basis
                        show : true,
                    }, {
                        tab : 'Contigs',
                        canDelete : false,
                        showContentCallback: function() {
                            return self.addContigList();
                        }
                    },
                ],
            });
        },

        addContigList: function() {
            var self = this;
            var $content = $('
');
            new DynamicTable($content, {
                headers: [{
                    id: 'contig_id',
                    text: 'Contig Id',
                    isSortable: true
                }, {
                    id: 'length',
                    text: 'Length (bp)',
                    isSortable: true
                }, {
                    id: 'gc',
                    text: 'GC Content (%)',
                    isSortable: true
                }],
                searchPlaceholder: 'Search contigs',
                updateFunction: function(pageNum, query, sortColId, sortColDir) {
                    var sortBy = [];
                    if (sortColId && sortColDir !== 0) {
                        sortBy.push([sortColId, sortColDir < 0 ? 0 : 1]);
                    }
                    return Promise.resolve(self.client.sync_call('AssemblyAPI.search_contigs', [{
                        ref: self.obj_ref,
                        query: query,
                        sort_by: sortBy,
                        start: pageNum * self.options.pageLimit
                    }], null, null, 'dev'))
                    .then(function(results) {
                        results = results[0];
                        var rows = [];
                        results.contigs.forEach(function(contig) {
                            rows.push([contig.contig_id, contig.length, contig.gc]);
                        });
                        return {
                            rows: rows,
                            start: results.start,
                            query: results.query,
                            total: results.num_found,
                        };
                    });
                },
                style: {'margin-top': '5px'}
            });
            return $content;
        },

        numberWithCommas: function(x) {
            return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
        }
    });

});
<|endoftext|>


<commit_before>var userInterface = {};

userInterface.elements = {};

userInterface.initialise = function() {
    userInterface.elements.canvas = document.getElementById("canvas");
    userInterface.elements.canvas.context = canvas.getContext("2d");
    window.onresize();
};

window.onresize = function() {
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
};<commit_msg>Added basic scrolling functionality<commit_after>var userInterface = {};
userInterface.elements = {};
userInterface.variables = {
    scrollSpeed : 1,
    scrollX : 0,
    scrollY : 0
};

userInterface.initialise = function() {
    userInterface.elements.canvas = document.getElementById("canvas");
    userInterface.elements.canvas.context = canvas.getContext("2d");

    userInterface.elements.canvas.addEventListener('mousemove',userInterface.canvasMoveMouseListener);

    window.onresize();
};

window.onresize = function() {
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
};

userInterface.canvasMoveMouseListener = function(event) {
    screenX = event.x;
    screenY = event.y;

    if(screenX < 100) {
        this.variables.scrollX = 1;
    } else if (screenX > canvas.width - 100) {
        this.variables.scrollX = -1;
    } else {
        this.variables.scrollX = 0;
    }

    if (screenY < 100) {
        this.variables.scrollY = 1;
    } else if (screenY > canvas.height - 100) {
        this.variables.scrollY = -1;
    } else {
        this.variables.scrollY = 0;
    }
};

userInterface.scrollLoop = function() {
    requestAnimationFrame(this);

    if (!scrollX && !scrollY) {
        return;
    }

    canvas.xOffset += (scrollSpeed * scrollX);
    canvas.yOffset += (scrollSpeed * scrollY);
};<|endoftext|>


<commit_before>var autocomplete =(function ($) {

    var searchField = $('.form-dropdown .form-dropdown-input'),
        results = $('.form-dropdown-results'),
        tags = $('.form-dropdown-tags');

    searchField.keyup(catchEvent);
    searchField.keypress(function (event) {
        // User press enter
        if (event.which === 13 && $('.form-dropdown-option').length > 0) {
            event.preventDefault();
            selectedEnter();
        }
    });

    $('html').click(function (event) {
        if(!$(event.target).hasClass('form-dropdown-input')) {
            closeDropdown();
        }
    });

    function selectedEnter() {
        var option = ($('.form-dropdown-results li.active a').length === 0) ? $('.form-dropdown-option').first() : $('.form-dropdown-results li.active a');
        addTag.call(option);
    }

    function catchEvent(event) {

        var nextElement = $(event.target).next();

        switch(event.which) {
            case 40:
                selectOption('down', nextElement);
                break;
            case 38:
                selectOption('up', nextElement);
                break;
            case 13:
                event.preventDefault();
                break;
            case 27:
                closeDropdown();
                break;
            default:
                getResults(this);
        }

    }

    function getResults(element) {

        var categories = $.ajax({
            url: $(element).data('url'),
            type: 'GET',
            dataType: 'json',
            data: {q: $(element).val()}
        });

        var test = element;

        $.when(categories)
            .done(function (categories) {
                createDropDown(categories, test);
            })
            .fail(function () {
            })
            .always(function () {
            });
    }

    function createDropDown(request, element) {
        closeDropdown();

        var data = request.countries ? request.countries : request.categories;

        if(data) {
            for (var i = 0; i < data.length; i++) {
                var content = (typeof(data[i]) === 'string') ? data[i] : data[i][0] + ' - '+data[i][1]+'',
                    option = (typeof(data[i]) === 'string') ? data[i] : data[i][0];

                $(element).next().append('
' + content + '

');
            }
            $('.form-dropdown-option').on('click', addTag);
        }
    }

    function addTag(event) {

        var input  = event ? $(event.target) : $(this);

        if (event) {
            event.preventDefault();
        }

        var caterogyId = $(this).data('option-id'),
            checkboxOption = $(this).parent().parent().prev().data('field');

        $(this).parent().parent().next().append('
'+$(this).text()+'<button href="" data-option-id="'+caterogyId+'" class="form-dropdown-tags--close">x</button>
');
        $('.form-dropdown-tags--close').on('click', deleteTag);
        addCheckbox(checkboxOption, caterogyId);
        resultCount.update_count();

        clearInput(input.parent().parent().prev());
        closeDropdown();
    }

    function clearInput(input) {
        input.val("");
    }

    function deleteTag(event) {
        event.preventDefault();
        $(this).parent().remove();
        deleteCheckbox($(this).data('option-id'));
        resultCount.update_count();
    }

    function closeDropdown() {
        results.empty();
    }

    function addCheckbox(field, value) {
        var input = $('<input>', {
            type:"checkbox",
            name: field,
            value: value,
            checked: true,
            'data-checkbox-id': value
        });

        $('.form-dropdown-checkbox').append(input);
    }

    function deleteCheckbox(checkboxId) {
        $('input[data-checkbox-id="'+checkboxId+'"]').remove();
    }

    function selectOption(action, element){

        var list = (element.children().length - 1),
            active = $('.form-dropdown-results li.active').index();

        if(!$('.form-dropdown-results li').hasClass('active')) {
            $($('.form-dropdown-results li')[0]).addClass('active');
        } else {
            $($('.form-dropdown-results li')[active]).removeClass('active');
            if(action === 'up') {
                $($('.form-dropdown-results li')[active-1]).addClass('active');
            } else {
                var option = (active === list) ? 0 : active+1;
                $($('.form-dropdown-results li')[option]).addClass('active');
            }

        }
    }

})(jQuery);<commit_msg>Clear down the autocomplete input if the user escapes, blurs the input, or adds a tag<commit_after>var autocomplete =(function ($) {

    var searchField = $('.form-dropdown .form-dropdown-input'),
        results = $('.form-dropdown-results'),
        tags = $('.form-dropdown-tags');

    searchField.keyup(catchEvent);
    searchField.keypress(function (event) {
        // User press enter
        if (event.which === 13 && $('.form-dropdown-option').length > 0) {
            event.preventDefault();
            selectedEnter();
        }
    });

    $('html').click(function (event) {
        var input = $(event.target)
        if(!input.hasClass('form-dropdown-input')) {
            closeDropdown();
            clearInput(input);
        }
    });

    $('input.form-dropdown-input').blur(function (event) {
        var input = $(event.target)
        clearInput(input);
    });

    function selectedEnter() {
        var option = ($('.form-dropdown-results li.active a').length === 0) ? $('.form-dropdown-option').first() : $('.form-dropdown-results li.active a');
        addTag.call(option);
    }

    function catchEvent(event) {

        var nextElement = $(event.target).next();

        switch(event.which) {
            case 40:
                selectOption('down', nextElement);
                break;
            case 38:
                selectOption('up', nextElement);
                break;
            case 13:
                event.preventDefault();
                break;
            case 27:
                var input = $(event.target);
                closeDropdown();
                clearInput(input);
                break;
            default:
                getResults(this);
        }

    }

    function getResults(element) {

        var categories = $.ajax({
            url: $(element).data('url'),
            type: 'GET',
            dataType: 'json',
            data: {q: $(element).val()}
        });

        var test = element;

        $.when(categories)
            .done(function (categories) {
                createDropDown(categories, test);
            })
            .fail(function () {
            })
            .always(function () {
            });
    }

    function createDropDown(request, element) {
        closeDropdown();

        var data = request.countries ? request.countries : request.categories;

        if(data) {
            for (var i = 0; i < data.length; i++) {
                var content = (typeof(data[i]) === 'string') ? data[i] : data[i][0] + ' - '+data[i][1]+'',
                    option = (typeof(data[i]) === 'string') ? data[i] : data[i][0];

                $(element).next().append('
' + content + '

');
            }
            $('.form-dropdown-option').on('click', addTag);
        }
    }

    function addTag(event) {

        var link  = event ? $(event.target) : $(this);
        var input = link.parent().parent().prev();

        if (event) {
            event.preventDefault();
        }

        var caterogyId = $(this).data('option-id'),
            checkboxOption = $(this).parent().parent().prev().data('field');

        $(this).parent().parent().next().append('
'+$(this).text()+'<button href="" data-option-id="'+caterogyId+'" class="form-dropdown-tags--close">x</button>
');
        $('.form-dropdown-tags--close').on('click', deleteTag);
        addCheckbox(checkboxOption, caterogyId);
        resultCount.update_count();

        clearInput(input);
        closeDropdown();
    }

    function clearInput(input) {
        input.val("");
    }

    function deleteTag(event) {
        event.preventDefault();
        $(this).parent().remove();
        deleteCheckbox($(this).data('option-id'));
        resultCount.update_count();
    }

    function closeDropdown() {
        results.empty();
    }

    function addCheckbox(field, value) {
        var input = $('<input>', {
            type:"checkbox",
            name: field,
            value: value,
            checked: true,
            'data-checkbox-id': value
        });

        $('.form-dropdown-checkbox').append(input);
    }

    function deleteCheckbox(checkboxId) {
        $('input[data-checkbox-id="'+checkboxId+'"]').remove();
    }

    function selectOption(action, element){

        var list = (element.children().length - 1),
            active = $('.form-dropdown-results li.active').index();

        if(!$('.form-dropdown-results li').hasClass('active')) {
            $($('.form-dropdown-results li')[0]).addClass('active');
        } else {
            $($('.form-dropdown-results li')[active]).removeClass('active');
            if(action === 'up') {
                $($('.form-dropdown-results li')[active-1]).addClass('active');
            } else {
                var option = (active === list) ? 0 : active+1;
                $($('.form-dropdown-results li')[option]).addClass('active');
            }

        }
    }

})(jQuery);<|endoftext|>


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

/**
 * External dependencies
 */
import PropTypes from 'prop-types';
import classnames from 'classnames';
import {
	each,
	debounce,
} from 'lodash';

/**
 * WordPress dependencies
 */
import { Component, createRef } from '@wordpress/element';

/**
 * Internal dependencies
 */
import SourceLink from './source-link';
import Link from './link';
import { getSiteKitAdminURL } from '../util';

// Construct a table component from a data object.
export const getDataTableFromData = ( data, headers, options ) => {
	const dataRows = [];

	const { links, source, showURLs, useAdminURLs = false } = options;

	if ( options.cap ) {
		data = data.slice( 0, options.cap );
	}

	each( data, ( row, j ) => {
		const cells = [];
		const link = links && links[ j ];

		each( row, ( cell, i ) => {
			// Replace (none) by direct.
			if ( 'string' === typeof cell ) {
				cell = cell.replace( /\(none\)/gi, 'direct' );
			}

			const hiddenOnMobile = options && options.hideColumns && options.hideColumns.mobile.includes( i );
			const permaLink = link && link[ 0 ] === '/' ? global._googlesitekitLegacyData.admin.siteURL + link : link;

			cells.push(

					{ row[ 0 ] === cell && link
						?

							<Link
								className="googlesitekit-table__body-item-link"
								href={ useAdminURLs ? getSiteKitAdminURL( 'googlesitekit-dashboard', { permaLink } ) : link }
								external={ ! useAdminURLs }
								inherit
							>
								{ cell }
							</Link>

							{ showURLs &&
								<Link
									className="googlesitekit-table__body-item-url"
									href={ link }
									inherit
									external
								>
									{ link }
								</Link>
							}

						:
{ cell }

					}

			);
		} );

		dataRows.push(

				{ cells }

		);
	} );

	const columns = data && data[ 0 ] && data[ 0 ].length ? data[ 0 ].length : 1;
	const mobileColumns = ( options.hideColumns && options.hideColumns.mobile && options.hideColumns.mobile.length > 0 )
		? columns - options.hideColumns.mobile.length
		: columns;

	return (

			<table className={ classnames(
				'googlesitekit-table__wrapper',
				`googlesitekit-table__wrapper--${ columns }-col`,
				{ [ `googlesitekit-table__wrapper--mobile-${ mobileColumns }-col` ]: ( mobileColumns !== columns ) }
			) }>

						{ headers.map( ( header, i ) => {
							const hiddenOnMobile = options && options.hideColumns && options.hideColumns.mobile.includes( i );
							return (
								<th
									key={ `gksc_data_row_header-${ i }` }
									className={ classnames(
										'googlesitekit-table__head-item',
										{ 'googlesitekit-table__head-item--primary': header.primary },
										{ 'hidden-on-mobile': hiddenOnMobile },
									) }
									data-tooltip={ header.tooltip }
								>
									{ header.title }

							);
						} ) }

					{ dataRows }

			{ source && (
				<SourceLink
					className="googlesitekit-table__source"
					name={ source.name }
					href={ source.link }
				/>
			) }

	);
};

export class TableOverflowContainer extends Component {
	constructor() {
		super();

		this.state = {
			isScrolling: false,
		};

		this.scrollRef = createRef();

		this.updateFadeOnScroll = this.updateFadeOnScroll.bind( this );
	}

	componentDidMount() {
		const self = this;

		// Check for scrolling on load and resize.
		self.updateFadeOnScroll();

		this.resize = debounce( function() {
			self.updateFadeOnScroll();
		}, 100 );

		global.addEventListener( 'resize', this.resize );
	}

	componentWillUnmount() {
		global.removeEventListener( 'resize', this.resize );
	}

	updateFadeOnScroll() {
		const { scrollLeft, scrollWidth, offsetWidth } = this.scrollRef.current;
		const maxScroll = scrollWidth - offsetWidth;
		const scrolling = scrollLeft < ( maxScroll - 16 ) && 0 < ( maxScroll - 16 ); // 16 = $grid-gap-phone

		this.setState( {
			isScrolling: scrolling,
		} );
	}

	render() {
		const { children } = this.props;
		const { isScrolling } = this.state;

		return (

					{ children }

		);
	}
}

TableOverflowContainer.propTypes = {
	children: PropTypes.element,
};
<commit_msg>Do not compute permaLink in every data table cell.<commit_after>/**
 * DataTable component.
 *
 * Site Kit by Google, Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import PropTypes from 'prop-types';
import classnames from 'classnames';
import {
	each,
	debounce,
} from 'lodash';

/**
 * WordPress dependencies
 */
import { Component, createRef } from '@wordpress/element';

/**
 * Internal dependencies
 */
import SourceLink from './source-link';
import Link from './link';
import { getSiteKitAdminURL } from '../util';

// Construct a table component from a data object.
export const getDataTableFromData = ( data, headers, options ) => {
	const dataRows = [];

	const { links, source, showURLs, useAdminURLs = false } = options;

	if ( options.cap ) {
		data = data.slice( 0, options.cap );
	}

	each( data, ( row, j ) => {
		const cells = [];
		const link = links && links[ j ];
		const permaLink = link && link[ 0 ] === '/' ? global._googlesitekitLegacyData.admin.siteURL + link : link;

		each( row, ( cell, i ) => {
			// Replace (none) by direct.
			if ( 'string' === typeof cell ) {
				cell = cell.replace( /\(none\)/gi, 'direct' );
			}

			const hiddenOnMobile = options && options.hideColumns && options.hideColumns.mobile.includes( i );

			cells.push(

					{ row[ 0 ] === cell && link
						?

							<Link
								className="googlesitekit-table__body-item-link"
								href={ useAdminURLs ? getSiteKitAdminURL( 'googlesitekit-dashboard', { permaLink } ) : link }
								external={ ! useAdminURLs }
								inherit
							>
								{ cell }
							</Link>

							{ showURLs &&
								<Link
									className="googlesitekit-table__body-item-url"
									href={ link }
									inherit
									external
								>
									{ link }
								</Link>
							}

						:
{ cell }

					}

			);
		} );

		dataRows.push(

				{ cells }

		);
	} );

	const columns = data && data[ 0 ] && data[ 0 ].length ? data[ 0 ].length : 1;
	const mobileColumns = ( options.hideColumns && options.hideColumns.mobile && options.hideColumns.mobile.length > 0 )
		? columns - options.hideColumns.mobile.length
		: columns;

	return (

			<table className={ classnames(
				'googlesitekit-table__wrapper',
				`googlesitekit-table__wrapper--${ columns }-col`,
				{ [ `googlesitekit-table__wrapper--mobile-${ mobileColumns }-col` ]: ( mobileColumns !== columns ) }
			) }>

						{ headers.map( ( header, i ) => {
							const hiddenOnMobile = options && options.hideColumns && options.hideColumns.mobile.includes( i );
							return (
								<th
									key={ `gksc_data_row_header-${ i }` }
									className={ classnames(
										'googlesitekit-table__head-item',
										{ 'googlesitekit-table__head-item--primary': header.primary },
										{ 'hidden-on-mobile': hiddenOnMobile },
									) }
									data-tooltip={ header.tooltip }
								>
									{ header.title }

							);
						} ) }

					{ dataRows }

			{ source && (
				<SourceLink
					className="googlesitekit-table__source"
					name={ source.name }
					href={ source.link }
				/>
			) }

	);
};

export class TableOverflowContainer extends Component {
	constructor() {
		super();

		this.state = {
			isScrolling: false,
		};

		this.scrollRef = createRef();

		this.updateFadeOnScroll = this.updateFadeOnScroll.bind( this );
	}

	componentDidMount() {
		const self = this;

		// Check for scrolling on load and resize.
		self.updateFadeOnScroll();

		this.resize = debounce( function() {
			self.updateFadeOnScroll();
		}, 100 );

		global.addEventListener( 'resize', this.resize );
	}

	componentWillUnmount() {
		global.removeEventListener( 'resize', this.resize );
	}

	updateFadeOnScroll() {
		const { scrollLeft, scrollWidth, offsetWidth } = this.scrollRef.current;
		const maxScroll = scrollWidth - offsetWidth;
		const scrolling = scrollLeft < ( maxScroll - 16 ) && 0 < ( maxScroll - 16 ); // 16 = $grid-gap-phone

		this.setState( {
			isScrolling: scrolling,
		} );
	}

	render() {
		const { children } = this.props;
		const { isScrolling } = this.state;

		return (

					{ children }

		);
	}
}

TableOverflowContainer.propTypes = {
	children: PropTypes.element,
};
<|endoftext|>


<commit_before>window.getPercentiles = function() {
  $('.percentile-task').each(function(elem) {
    var $self = $(this);
    var url = $self.data('url');
    $.get(url, function(data){
      if(data.percentile != null){
      $self.find(".percentile").text(''+ data.percentile + 'th');
      $('.percentile-task').css({'visibility': 'visible'});
    } else{
      $('.percentile-task').css({'display': 'none'});
    }
    });
  });
};

$(document).ready(function() {

  window.getPercentiles();
  $('.js-rating-download').each(function(elem) {
    var $self = $(this);
    var url = $self.data('url');
    $.get(url, function(data){
      var rounded = Math.round(data.rating*2)/2,
          leftOver = rounded % 1,
          index;

      for (index = 0; index < rounded; index++) {
        $self.find('.fa-star-o:nth-child(' + index + ')').removeClass('fa-star-o').addClass('fa-star');
      }
      if(leftOver == 0.5) {
        $self.find('.fa-star-o:nth-child(' + index + ')').removeClass('fa-star-o').addClass('fa-star-half-o');
      }
      $self.text();
    });
  });

});
<commit_msg>fix percentile disapearing<commit_after>window.getPercentiles = function() {
  $('.percentile-task').each(function(elem) {
    var $self = $(this);
    var url = $self.data('url');
    $.get(url, function(data){
      if(data.percentile != null){
      $self.find(".percentile").text(''+ data.percentile + 'th');
      $self.css({'visibility': 'visible'});
    } else{
      $self.css({'display': 'none'});
    }
    });
  });
};

$(document).ready(function() {

  window.getPercentiles();
  $('.js-rating-download').each(function(elem) {
    var $self = $(this);
    var url = $self.data('url');
    $.get(url, function(data){
      var rounded = Math.round(data.rating*2)/2,
          leftOver = rounded % 1,
          index;

      for (index = 0; index < rounded; index++) {
        $self.find('.fa-star-o:nth-child(' + index + ')').removeClass('fa-star-o').addClass('fa-star');
      }
      if(leftOver == 0.5) {
        $self.find('.fa-star-o:nth-child(' + index + ')').removeClass('fa-star-o').addClass('fa-star-half-o');
      }
      $self.text();
    });
  });

});
<|endoftext|>


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

/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';

/**
 * Internal dependencies
 */
import {
	AREA_DASHBOARD_EARNINGS,
	AREA_MAIN_DASHBOARD_MONETIZATION_PRIMARY,
} from '../../googlesitekit/widgets/default-areas';
import { SetupMain } from './components/setup';
import {
	SettingsEdit,
	SettingsSetupIncomplete,
	SettingsView,
} from './components/settings';
import {
	DashboardSummaryWidget,
	DashboardTopEarningPagesWidget,
	AdBlockerWarningWidget,
} from './components/dashboard';
import ModuleTopEarningPagesWidget from './components/module/ModuleTopEarningPagesWidget';
import { ModuleOverviewWidget } from './components/module';
import AdSenseIcon from '../../../svg/adsense.svg';
import { MODULES_ADSENSE } from './datastore/constants';
import {
	AREA_MODULE_ADSENSE_MAIN,
	CONTEXT_MODULE_ADSENSE,
	ERROR_CODE_ADBLOCKER_ACTIVE,
} from './constants';
import { WIDGET_AREA_STYLES } from '../../googlesitekit/widgets/datastore/constants';
import { isFeatureEnabled } from '../../features';
export { registerStore } from './datastore';

export const registerModule = ( modules ) => {
	modules.registerModule( 'adsense', {
		storeName: MODULES_ADSENSE,
		SettingsEditComponent: SettingsEdit,
		SettingsViewComponent: SettingsView,
		SettingsSetupIncompleteComponent: SettingsSetupIncomplete,
		SetupComponent: SetupMain,
		Icon: AdSenseIcon,
		features: [
			__( 'Intelligent, automatic ad placement', 'google-site-kit' ),
			__( 'Revenue from ads placed on your site', 'google-site-kit' ),
			__( 'AdSense insights through Site Kit', 'google-site-kit' ),
		],
		checkRequirements: async ( registry ) => {
			const adBlockerActive = await registry
				.__experimentalResolveSelect( MODULES_ADSENSE )
				.isAdBlockerActive();

			if ( ! adBlockerActive ) {
				return;
			}

			const message = registry
				.select( MODULES_ADSENSE )
				.getAdBlockerWarningMessage();

			throw {
				code: ERROR_CODE_ADBLOCKER_ACTIVE,
				message,
				data: null,
			};
		},
		screenWidgetContext: CONTEXT_MODULE_ADSENSE,
	} );
};

export const registerWidgets = ( widgets ) => {
	widgets.registerWidget(
		'adBlockerWarning',
		{
			Component: AdBlockerWarningWidget,
			width: widgets.WIDGET_WIDTHS.FULL,
			priority: 1,
			wrapWidget: false,
		},
		[ AREA_MAIN_DASHBOARD_MONETIZATION_PRIMARY, AREA_MODULE_ADSENSE_MAIN ]
	);

	if ( isFeatureEnabled( 'unifiedDashboard' ) ) {
		widgets.registerWidget(
			'adsenseModuleOverview',
			{
				Component: ModuleOverviewWidget,
				width: widgets.WIDGET_WIDTHS.FULL,
				priority: 2,
				wrapWidget: false,
			},
			[ AREA_MAIN_DASHBOARD_MONETIZATION_PRIMARY ]
		);
		widgets.registerWidget(
			'adsenseTopEarningPages',
			{
				Component: DashboardTopEarningPagesWidget,
				width: [
					widgets.WIDGET_WIDTHS.HALF,
					widgets.WIDGET_WIDTHS.FULL,
				],
				priority: 2,
				wrapWidget: false,
			},
			[ AREA_MAIN_DASHBOARD_MONETIZATION_PRIMARY ]
		);
	}

	if ( ! isFeatureEnabled( 'unifiedDashboard' ) ) {
		widgets.registerWidgetArea(
			AREA_MODULE_ADSENSE_MAIN,
			{
				priority: 1,
				style: WIDGET_AREA_STYLES.BOXES,
				title: __( 'Overview', 'google-site-kit' ),
			},
			CONTEXT_MODULE_ADSENSE
		);

		widgets.registerWidget(
			'adsenseSummary',
			{
				Component: DashboardSummaryWidget,
				width: widgets.WIDGET_WIDTHS.HALF,
				priority: 1,
				wrapWidget: false,
			},
			[ AREA_DASHBOARD_EARNINGS ]
		);
		widgets.registerWidget(
			'adsenseTopEarningPages',
			{
				Component: DashboardTopEarningPagesWidget,
				width: [
					widgets.WIDGET_WIDTHS.HALF,
					widgets.WIDGET_WIDTHS.FULL,
				],
				priority: 2,
				wrapWidget: false,
			},
			[ AREA_DASHBOARD_EARNINGS ]
		);
		widgets.registerWidget(
			'adsenseModuleOverview',
			{
				Component: ModuleOverviewWidget,
				width: widgets.WIDGET_WIDTHS.FULL,
				priority: 2,
				wrapWidget: false,
			},
			[ AREA_MODULE_ADSENSE_MAIN ]
		);
		widgets.registerWidget(
			'adsenseModuleTopEarningPages',
			{
				Component: ModuleTopEarningPagesWidget,
				width: widgets.WIDGET_WIDTHS.FULL,
				priority: 2,
				wrapWidget: false,
			},
			[ AREA_MODULE_ADSENSE_MAIN ]
		);
	}
};
<commit_msg>Increase adsenseTopEarningPages widget priority to make order more explicit.<commit_after>/**
 * AdSense module initialization.
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';

/**
 * Internal dependencies
 */
import {
	AREA_DASHBOARD_EARNINGS,
	AREA_MAIN_DASHBOARD_MONETIZATION_PRIMARY,
} from '../../googlesitekit/widgets/default-areas';
import { SetupMain } from './components/setup';
import {
	SettingsEdit,
	SettingsSetupIncomplete,
	SettingsView,
} from './components/settings';
import {
	DashboardSummaryWidget,
	DashboardTopEarningPagesWidget,
	AdBlockerWarningWidget,
} from './components/dashboard';
import ModuleTopEarningPagesWidget from './components/module/ModuleTopEarningPagesWidget';
import { ModuleOverviewWidget } from './components/module';
import AdSenseIcon from '../../../svg/adsense.svg';
import { MODULES_ADSENSE } from './datastore/constants';
import {
	AREA_MODULE_ADSENSE_MAIN,
	CONTEXT_MODULE_ADSENSE,
	ERROR_CODE_ADBLOCKER_ACTIVE,
} from './constants';
import { WIDGET_AREA_STYLES } from '../../googlesitekit/widgets/datastore/constants';
import { isFeatureEnabled } from '../../features';
export { registerStore } from './datastore';

export const registerModule = ( modules ) => {
	modules.registerModule( 'adsense', {
		storeName: MODULES_ADSENSE,
		SettingsEditComponent: SettingsEdit,
		SettingsViewComponent: SettingsView,
		SettingsSetupIncompleteComponent: SettingsSetupIncomplete,
		SetupComponent: SetupMain,
		Icon: AdSenseIcon,
		features: [
			__( 'Intelligent, automatic ad placement', 'google-site-kit' ),
			__( 'Revenue from ads placed on your site', 'google-site-kit' ),
			__( 'AdSense insights through Site Kit', 'google-site-kit' ),
		],
		checkRequirements: async ( registry ) => {
			const adBlockerActive = await registry
				.__experimentalResolveSelect( MODULES_ADSENSE )
				.isAdBlockerActive();

			if ( ! adBlockerActive ) {
				return;
			}

			const message = registry
				.select( MODULES_ADSENSE )
				.getAdBlockerWarningMessage();

			throw {
				code: ERROR_CODE_ADBLOCKER_ACTIVE,
				message,
				data: null,
			};
		},
		screenWidgetContext: CONTEXT_MODULE_ADSENSE,
	} );
};

export const registerWidgets = ( widgets ) => {
	widgets.registerWidget(
		'adBlockerWarning',
		{
			Component: AdBlockerWarningWidget,
			width: widgets.WIDGET_WIDTHS.FULL,
			priority: 1,
			wrapWidget: false,
		},
		[ AREA_MAIN_DASHBOARD_MONETIZATION_PRIMARY, AREA_MODULE_ADSENSE_MAIN ]
	);

	if ( isFeatureEnabled( 'unifiedDashboard' ) ) {
		widgets.registerWidget(
			'adsenseModuleOverview',
			{
				Component: ModuleOverviewWidget,
				width: widgets.WIDGET_WIDTHS.FULL,
				priority: 2,
				wrapWidget: false,
			},
			[ AREA_MAIN_DASHBOARD_MONETIZATION_PRIMARY ]
		);
		widgets.registerWidget(
			'adsenseTopEarningPages',
			{
				Component: DashboardTopEarningPagesWidget,
				width: [
					widgets.WIDGET_WIDTHS.HALF,
					widgets.WIDGET_WIDTHS.FULL,
				],
				priority: 3,
				wrapWidget: false,
			},
			[ AREA_MAIN_DASHBOARD_MONETIZATION_PRIMARY ]
		);
	}

	if ( ! isFeatureEnabled( 'unifiedDashboard' ) ) {
		widgets.registerWidgetArea(
			AREA_MODULE_ADSENSE_MAIN,
			{
				priority: 1,
				style: WIDGET_AREA_STYLES.BOXES,
				title: __( 'Overview', 'google-site-kit' ),
			},
			CONTEXT_MODULE_ADSENSE
		);

		widgets.registerWidget(
			'adsenseSummary',
			{
				Component: DashboardSummaryWidget,
				width: widgets.WIDGET_WIDTHS.HALF,
				priority: 1,
				wrapWidget: false,
			},
			[ AREA_DASHBOARD_EARNINGS ]
		);
		widgets.registerWidget(
			'adsenseTopEarningPages',
			{
				Component: DashboardTopEarningPagesWidget,
				width: [
					widgets.WIDGET_WIDTHS.HALF,
					widgets.WIDGET_WIDTHS.FULL,
				],
				priority: 2,
				wrapWidget: false,
			},
			[ AREA_DASHBOARD_EARNINGS ]
		);
		widgets.registerWidget(
			'adsenseModuleOverview',
			{
				Component: ModuleOverviewWidget,
				width: widgets.WIDGET_WIDTHS.FULL,
				priority: 2,
				wrapWidget: false,
			},
			[ AREA_MODULE_ADSENSE_MAIN ]
		);
		widgets.registerWidget(
			'adsenseModuleTopEarningPages',
			{
				Component: ModuleTopEarningPagesWidget,
				width: widgets.WIDGET_WIDTHS.FULL,
				priority: 2,
				wrapWidget: false,
			},
			[ AREA_MODULE_ADSENSE_MAIN ]
		);
	}
};
<|endoftext|>


<commit_before>/* global $ */

$(document).ready(function () {
    function createDropdownElement($selector) {
        var i, len,
            $categorySelect = $('#category'),
            $selectChildren = $categorySelect.children(),
            $categoryDropdownDiv = $('<div/>'),
            $toggleButton = $('<button/>'),
            $caret = $('<span/>'),
            $dropdownUl = $('<ul/>');

        $categorySelect.addClass('hidden');
        $categoryDropdownDiv.addClass('dropdown')
            .css('display', 'inline-block')
            .css('margin-bottom', '20px');

        $toggleButton.addClass('btn')
            .addClass('btn-default')
            .addClass('dropdown-toggle')
            .addClass('category-button')
            .attr('type', 'button')
            .attr('id', 'category-select-dropdown')
            .attr('data-toggle', 'dropdown')
            .attr('aria-haspopup', 'true')
            .attr('aria-expanded', 'true');

        if ($categorySelect.attr('value')) {
            $toggleButton.html($categorySelect.attr('value') + ' ')
                .attr('data-value', $categorySelect.attr('value'));
        }
        else {
            $toggleButton.html('Select a category ');
        }

        $caret.addClass('caret');
        $caret.appendTo($toggleButton);

        $dropdownUl.addClass('dropdown-menu')
            .addClass('category-dropdown-menu')
            .attr('aria-labelledby', 'category-select-dropdown');

        for (i = 0, len = $selectChildren.length; i < len; i += 1) {
            var $currentOption = $($selectChildren[i]),
                $newListItem = $('<li/>'),
                $newAnchorTag = $('<a/>');

            $newAnchorTag.attr('href', '#')
                .attr('data-value', $currentOption.val())
                .html($currentOption.html())
                .css('text-align', 'center');

            $newAnchorTag.appendTo($newListItem);
            $newListItem.appendTo($dropdownUl);
        }

        $toggleButton.appendTo($categoryDropdownDiv);
        $dropdownUl.appendTo($categoryDropdownDiv);
        $categoryDropdownDiv.appendTo($selector);

        $('.dropdown-menu a').on('click', function () {
            var $this = $(this),
                $dataValue = $this.attr('data-value');
            $categorySelect.val($dataValue);
            $toggleButton.html($this.html() + ' ');
            $caret.appendTo($toggleButton);
        });
    }

    createDropdownElement($('.category'));
});<commit_msg>Fixed the dropdown category select for not having the needed html when set value for the select.<commit_after>/* global $ */

$(document).ready(function () {
    function createDropdownElement($selector) {
        var i, len,
            $categorySelect = $('#category'),
            $selectChildren = $categorySelect.children(),
            $categoryDropdownDiv = $('<div/>'),
            $toggleButton = $('<button/>'),
            $caret = $('<span/>'),
            $dropdownUl = $('<ul/>');

        $categorySelect.addClass('hidden');
        $categoryDropdownDiv.addClass('dropdown')
            .css('display', 'inline-block')
            .css('margin-bottom', '20px');

        $toggleButton.addClass('btn')
            .addClass('btn-default')
            .addClass('dropdown-toggle')
            .addClass('category-button')
            .attr('type', 'button')
            .attr('id', 'category-select-dropdown')
            .attr('data-toggle', 'dropdown')
            .attr('aria-haspopup', 'true')
            .attr('aria-expanded', 'true');

        if ($categorySelect.attr('value')) {
            var $optionWithInitialValue = $('option[value="' + $categorySelect.attr('value') + '"]');
            $toggleButton.html($optionWithInitialValue.html()    + ' ')
                .attr('data-value', $categorySelect.attr('value'));
        }
        else {
            $toggleButton.html('Select a category ');
        }

        $caret.addClass('caret');
        $caret.appendTo($toggleButton);

        $dropdownUl.addClass('dropdown-menu')
            .addClass('category-dropdown-menu')
            .attr('aria-labelledby', 'category-select-dropdown');

        for (i = 0, len = $selectChildren.length; i < len; i += 1) {
            var $currentOption = $($selectChildren[i]),
                $newListItem = $('<li/>'),
                $newAnchorTag = $('<a/>');

            $newAnchorTag.attr('href', '#')
                .attr('data-value', $currentOption.val())
                .html($currentOption.html())
                .css('text-align', 'center');

            $newAnchorTag.appendTo($newListItem);
            $newListItem.appendTo($dropdownUl);
        }

        $toggleButton.appendTo($categoryDropdownDiv);
        $dropdownUl.appendTo($categoryDropdownDiv);
        $categoryDropdownDiv.appendTo($selector);

        $('.dropdown-menu a').on('click', function () {
            var $this = $(this),
                $dataValue = $this.attr('data-value');
            $categorySelect.val($dataValue);
            $toggleButton.html($this.html() + ' ');
            $caret.appendTo($toggleButton);
        });
    }

    createDropdownElement($('.category'));
});<|endoftext|>


<commit_before>import { alignment, alignDir, generateAnimation } from './utils.js'

const re = {
  delimiter: /((\{|\}))/g,
  newline: /\\N/g,
  bold: {
    start: {
      from: /\\b1/g,
      to: ''
    },
    end: {
      from: /\\b0/g,
      to: ''
    }
  },
  italic: {
    start: {
      from: /\\i1/g,
      to: ''
    },
    end: {
      from: /\\i0/g,
      to: ''
    }
  },
  underline: {
    start: {
      from: /\\u1/g,
      to: ''
    },
    end: {
      from: /\\u0/g,
      to: ''
    }
  },
  font: {
    name: /(\\fn.+(?=\\)|\\fn.+(?=}))/g,
    size: /\\fs[0-9]{1,3}/g
  },
  color: /\\\d?c&H[0-9A-Za-z]{2,6}&/,
  alignment: /\\an?\d{1,2}/g,
  fade: /\\fad\(\d*,\d*\)/,
  pos: /\\pos\(\d*,\d*\)/,
  rot: /\\fr(x|y|z)?\d{1,3}/,
  karaoke: /\\k(f|o)?\d{1,5}/ig
}

// Need to clean up {}s after
const clean = (string) => {
  return string.replace(re.delimiter, '')
}

const handleCommon = (type, string) => {
  // Handles bold, italic and underline
  const re_ = re[type]

  if (re_.start.from.test(string)) {
    string = string.replace(re_.start.from, re_.start.to)

    re_.end.from.test(string)
      ? string = string.replace(re_.end.from, re_.end.to)
      : string += re_.end.to
  }

  return string.replace(re_.start.from, '').replace(re_.end.from, '')
}

const handleFont = (type, string, style) => {
  const fontType = re.font[type].test(string) && string.match(re.font[type])[0]

  if (fontType) {
    const font = fontType.slice(3)
    const fontClass = 'font_' + font.replace(/\s/g, '_')

    const value = font + (type === 'size' ? 'px' : '')

    // Check if class is in style. If not, includes it.
    let current = style.innerHTML
    if (!current.includes(`.${fontClass}`)) {
      style.innerHTML += `.video-player .${fontClass} {
        font-${type === 'name' ? 'family' : 'size'}:${value};
      }`
    }

    string = string.replace(re.font[type], `<p class="${fontClass}" style="display: inline;">`) + '</c>'
  }

  return string.replace(re.font[type], '')
}

const setColorStyle = (type, colorTag, string, style) => {
  const color = colorTag.replace(/\\\d?c/g, '').slice(2, 8)
  const r = color.slice(4, 6)
  const g = color.slice(2, 4)
  const b = color.slice(0, 2)
  const hexColor = `#${r}${g}${b}`

  const colorClass = `${type}${color}`

  const typeToProperty = {
    'c': {
      property: 'color',
      rule: hexColor
    },
    'b': {
      property: '-webkit-text-stroke',
      rule: `1.5px ${hexColor},`
    }
  }

  // Check if class is in style. If not, includes it.
  let current = style.innerHTML
  if (!current.includes(`.${colorClass}`)) {
    style.innerHTML += `.video-player p.${colorClass} {${typeToProperty[type].property}:${typeToProperty[type].rule};}`
  }

  return string.replace(re.color, `<p class="${colorClass}" style="display: inline;">`)
}

const handleColor = (string, style) => {
  if (re.color.test(string)) {
    const globalRe = new RegExp(re.color, ['g'])

    for (let i = 0, l = string.match(globalRe).length; i < l; ++i) {
      const colorTag = string.match(re.color)[0]
      const isPrimary = colorTag[1] === 'c' || colorTag[1] === '1'

      if (isPrimary) {
        string = setColorStyle('c', colorTag, string, style)

        if (re.color.test(string)) {
          // Meaning there is another color tag in the string so the closing tag should be
          // before the next color tag
          const match = string.match(re.color)[0]
          const index = string.indexOf(match)
          string = string.slice(0, index) + '
' + string.slice(index)
        } else {
          string += '
'
        }
      } else {
        // Hopefully temporary
        // Support only for border color
        if (colorTag[1] === '3') {
          string = setColorStyle('b', colorTag, string, style)
        }
      }
    }
  }

  return string
}

const handleFade = (cue, style) => {
  let string = cue.text

  if (re.fade.test(string)) {
    const fadeTag = string.match(re.fade)[0]

    // We can handle only appearing fade animation atm.
    // The time is in ms, we need it in seconds.
    const inDuration = +fadeTag.split(',')[0].replace('\\fad(', '') / 1000

    // There is a need for a css class.
    const fadeInClass = `fade_in_${inDuration}`.replace('.', '')

    cue.style.push(fadeInClass)
    cue.text = string.replace(fadeTag, '')

    // Check if class is in style. If not, includes it.
    let current = style.innerHTML
    if (!current.includes(`.${fadeInClass}`)) {
      const animationName = `fade${inDuration}`.replace('.', '')
      const types = [
        { type: 'in', duration: inDuration, cls: fadeInClass, name: `fade_in_${inDuration}`.replace('.', '') }
      ]

      types.forEach(({type, duration, cls}) => {
        style.innerHTML += `.video-player .${cls} ${generateAnimation(type, animationName, duration)}`
      })
    }
  }

  return cue
}

const handlePos = (cue, info) => {
  const string = cue.text
  const { PlayResX: resX, PlayResY: resY } = info

  if (re.pos.test(string)) {
    const posTag = string.match(re.pos)[0]

    const xy = posTag.replace('\\pos(', '').replace(')', '').split(',')
    const x = Math.round((xy[0] / resX) * 100)
    const y = Math.round((xy[1] / resY) * 100)

    cue.position = x
    cue.line = y

    cue.text = string.replace(posTag, '')
  }

  return cue
}

const handleRotation = (cue) => {
  const string = cue.text

  if (re.rot.test(string)) {
    const rotateTag = string.match(re.rot)
    let axis = rotateTag.replace('\\fr', '').slice(0, 1)

    if (!isNaN(+axis)) {
      // According to the specs, if no axis is specified,
      // the fallback axis should be z.
      axis = 'z'
    }

    const degrees = rotateTag.replace(`\\fr${axis}`, '')

    cue.rotate = ` rotate${axis.toUpperCase}(${degrees}deg)`

    cue.text = string.replace(rotateTag, '')
  }

  return cue
}

const handleAlignment = (string, cue, style) => {
  const alignmentTag = re.alignment.test(string) && string.match(re.alignment)[0] // Only he first tag matters

  if (alignmentTag) {
    const isNumpad = alignmentTag[2] === 'n'

    const align = isNumpad
      ? +alignmentTag[3] // tag === '\an<number>, 1 <= number <= 9
      : +alignmentTag.slice(2, 4) // tag === '\a<number>, 1 <= number <= 11

    cue.position = isNumpad ? alignment.numpad[align][1] : alignment.ssa[align][1]
    cue.line = isNumpad ? alignment.numpad[align][0] : alignment.ssa[align][0]

    if (isNumpad) {
      cue.align = alignDir.left.includes(alignment)
        ? -0
        : alignDir.right.includes(alignment)
          ? -100
          : -50

      cue.textAlign = alignDir.left.includes(alignment)
        ? 'left'
        : alignDir.right.includes(alignment)
          ? 'right'
          : 'center'
    }

    cue.text = string.replace(re.alignment, '')
  }

  return cue
}

export default function (cues, info) {
  const cssStyle = document.head.children[document.head.childElementCount - 1]

  cues.forEach((cue) => {
    let string = cue.text

    if (/\{/g.test(string)) {
      string = handleCommon('bold', string)
      string = handleCommon('italic', string)
      string = handleCommon('underline', string)

      string = handleFont('name', string, cssStyle)
      string = handleFont('size', string, cssStyle)

      string = handleColor(string, cssStyle)

      cue.text = clean(string)

      cue = handlePos(cue, info)
      cue = handleRotation(cue)
      cue = handleAlignment(string, cue, cssStyle)
      cue = handleFade(cue, cssStyle)
    }
  })

  return cues
}
<commit_msg>Fix delimiter regex<commit_after>import { alignment, alignDir, generateAnimation } from './utils.js'

const re = {
  delimiter: /[{}]/g,
  newline: /\\N/g,
  bold: {
    start: {
      from: /\\b1/g,
      to: ''
    },
    end: {
      from: /\\b0/g,
      to: ''
    }
  },
  italic: {
    start: {
      from: /\\i1/g,
      to: ''
    },
    end: {
      from: /\\i0/g,
      to: ''
    }
  },
  underline: {
    start: {
      from: /\\u1/g,
      to: ''
    },
    end: {
      from: /\\u0/g,
      to: ''
    }
  },
  font: {
    name: /(\\fn.+(?=\\)|\\fn.+(?=}))/g,
    size: /\\fs[0-9]{1,3}/g
  },
  color: /\\\d?c&H[0-9A-Za-z]{2,6}&/,
  alignment: /\\an?\d{1,2}/g,
  fade: /\\fad\(\d*,\d*\)/,
  pos: /\\pos\(\d*,\d*\)/,
  rot: /\\fr(x|y|z)?\d{1,3}/,
  karaoke: /\\k(f|o)?\d{1,5}/ig
}

// Need to clean up {}s after
const clean = (string) => {
  return string.replace(re.delimiter, '')
}

const handleCommon = (type, string) => {
  // Handles bold, italic and underline
  const re_ = re[type]

  if (re_.start.from.test(string)) {
    string = string.replace(re_.start.from, re_.start.to)

    re_.end.from.test(string)
      ? string = string.replace(re_.end.from, re_.end.to)
      : string += re_.end.to
  }

  return string.replace(re_.start.from, '').replace(re_.end.from, '')
}

const handleFont = (type, string, style) => {
  const fontType = re.font[type].test(string) && string.match(re.font[type])[0]

  if (fontType) {
    const font = fontType.slice(3)
    const fontClass = 'font_' + font.replace(/\s/g, '_')

    const value = font + (type === 'size' ? 'px' : '')

    // Check if class is in style. If not, includes it.
    let current = style.innerHTML
    if (!current.includes(`.${fontClass}`)) {
      style.innerHTML += `.video-player .${fontClass} {
        font-${type === 'name' ? 'family' : 'size'}:${value};
      }`
    }

    string = string.replace(re.font[type], `<p class="${fontClass}" style="display: inline;">`) + '</c>'
  }

  return string.replace(re.font[type], '')
}

const setColorStyle = (type, colorTag, string, style) => {
  const color = colorTag.replace(/\\\d?c/g, '').slice(2, 8)
  const r = color.slice(4, 6)
  const g = color.slice(2, 4)
  const b = color.slice(0, 2)
  const hexColor = `#${r}${g}${b}`

  const colorClass = `${type}${color}`

  const typeToProperty = {
    'c': {
      property: 'color',
      rule: hexColor
    },
    'b': {
      property: '-webkit-text-stroke',
      rule: `1.5px ${hexColor},`
    }
  }

  // Check if class is in style. If not, includes it.
  let current = style.innerHTML
  if (!current.includes(`.${colorClass}`)) {
    style.innerHTML += `.video-player p.${colorClass} {${typeToProperty[type].property}:${typeToProperty[type].rule};}`
  }

  return string.replace(re.color, `<p class="${colorClass}" style="display: inline;">`)
}

const handleColor = (string, style) => {
  if (re.color.test(string)) {
    const globalRe = new RegExp(re.color, ['g'])

    for (let i = 0, l = string.match(globalRe).length; i < l; ++i) {
      const colorTag = string.match(re.color)[0]
      const isPrimary = colorTag[1] === 'c' || colorTag[1] === '1'

      if (isPrimary) {
        string = setColorStyle('c', colorTag, string, style)

        if (re.color.test(string)) {
          // Meaning there is another color tag in the string so the closing tag should be
          // before the next color tag
          const match = string.match(re.color)[0]
          const index = string.indexOf(match)
          string = string.slice(0, index) + '
' + string.slice(index)
        } else {
          string += '
'
        }
      } else {
        // Hopefully temporary
        // Support only for border color
        if (colorTag[1] === '3') {
          string = setColorStyle('b', colorTag, string, style)
        }
      }
    }
  }

  return string
}

const handleFade = (cue, style) => {
  let string = cue.text

  if (re.fade.test(string)) {
    const fadeTag = string.match(re.fade)[0]

    // We can handle only appearing fade animation atm.
    // The time is in ms, we need it in seconds.
    const inDuration = +fadeTag.split(',')[0].replace('\\fad(', '') / 1000

    // There is a need for a css class.
    const fadeInClass = `fade_in_${inDuration}`.replace('.', '')

    cue.style.push(fadeInClass)
    cue.text = string.replace(fadeTag, '')

    // Check if class is in style. If not, includes it.
    let current = style.innerHTML
    if (!current.includes(`.${fadeInClass}`)) {
      const animationName = `fade${inDuration}`.replace('.', '')
      const types = [
        { type: 'in', duration: inDuration, cls: fadeInClass, name: `fade_in_${inDuration}`.replace('.', '') }
      ]

      types.forEach(({type, duration, cls}) => {
        style.innerHTML += `.video-player .${cls} ${generateAnimation(type, animationName, duration)}`
      })
    }
  }

  return cue
}

const handlePos = (cue, info) => {
  const string = cue.text
  const { PlayResX: resX, PlayResY: resY } = info

  if (re.pos.test(string)) {
    const posTag = string.match(re.pos)[0]

    const xy = posTag.replace('\\pos(', '').replace(')', '').split(',')
    const x = Math.round((xy[0] / resX) * 100)
    const y = Math.round((xy[1] / resY) * 100)

    cue.position = x
    cue.line = y

    cue.text = string.replace(posTag, '')
  }

  return cue
}

const handleRotation = (cue) => {
  const string = cue.text

  if (re.rot.test(string)) {
    const rotateTag = string.match(re.rot)
    let axis = rotateTag.replace('\\fr', '').slice(0, 1)

    if (!isNaN(+axis)) {
      // According to the specs, if no axis is specified,
      // the fallback axis should be z.
      axis = 'z'
    }

    const degrees = rotateTag.replace(`\\fr${axis}`, '')

    cue.rotate = ` rotate${axis.toUpperCase}(${degrees}deg)`

    cue.text = string.replace(rotateTag, '')
  }

  return cue
}

const handleAlignment = (string, cue, style) => {
  const alignmentTag = re.alignment.test(string) && string.match(re.alignment)[0] // Only he first tag matters

  if (alignmentTag) {
    const isNumpad = alignmentTag[2] === 'n'

    const align = isNumpad
      ? +alignmentTag[3] // tag === '\an<number>, 1 <= number <= 9
      : +alignmentTag.slice(2, 4) // tag === '\a<number>, 1 <= number <= 11

    cue.position = isNumpad ? alignment.numpad[align][1] : alignment.ssa[align][1]
    cue.line = isNumpad ? alignment.numpad[align][0] : alignment.ssa[align][0]

    if (isNumpad) {
      cue.align = alignDir.left.includes(alignment)
        ? -0
        : alignDir.right.includes(alignment)
          ? -100
          : -50

      cue.textAlign = alignDir.left.includes(alignment)
        ? 'left'
        : alignDir.right.includes(alignment)
          ? 'right'
          : 'center'
    }

    cue.text = string.replace(re.alignment, '')
  }

  return cue
}

export default function (cues, info) {
  const cssStyle = document.head.children[document.head.childElementCount - 1]

  cues.forEach((cue) => {
    let string = cue.text

    if (/\{/g.test(string)) {
      string = handleCommon('bold', string)
      string = handleCommon('italic', string)
      string = handleCommon('underline', string)

      string = handleFont('name', string, cssStyle)
      string = handleFont('size', string, cssStyle)

      string = handleColor(string, cssStyle)

      cue.text = clean(string)

      cue = handlePos(cue, info)
      cue = handleRotation(cue)
      cue = handleAlignment(string, cue, cssStyle)
      cue = handleFade(cue, cssStyle)
    }
  })

  return cues
}
<|endoftext|>


<commit_before>/*
 * (C) 2015 TekMonks. All rights reserved.
 * License: MIT - see enclosed LICENSE file.
 */

const https = require("https");
const fs = require("fs");

const sslConf = require(`${CONSTANTS.SSLCONF}`);
const options = {
    key: fs.readFileSync(sslConf.keyPath),
    cert: fs.readFileSync(sslConf.certPath)
};

exports.init = init;

function init(port, host = "::") {
    /* create HTTPS server */
    LOG.info(`Attaching socket listener on ${host}:${port}`);
    exports.connection = https.createServer(options, (_req, res) => {
        res.setHeader("Access-Control-Allow-Origin", "*");
    }).listen(port, host);
};<commit_msg>Marking init function as Sync.<commit_after>/*
 * (C) 2015 TekMonks. All rights reserved.
 * License: MIT - see enclosed LICENSE file.
 */

const https = require("https");
const fs = require("fs");

const sslConf = require(`${CONSTANTS.SSLCONF}`);
const options = {
    key: fs.readFileSync(sslConf.keyPath),
    cert: fs.readFileSync(sslConf.certPath)
};

exports.initSync = initSync;

function initSync(port, host = "::") {
    /* create HTTPS server */
    LOG.info(`Attaching socket listener on ${host}:${port}`);
    exports.connection = https.createServer(options, (_req, res) => {
        res.setHeader("Access-Control-Allow-Origin", "*");
    }).listen(port, host);
};<|endoftext|>