<commit_before>(function($) {

	var taggitPrefix = '/';

	var scripts = document.getElementsByTagName('SCRIPT');
	for (var i = 0,l=scripts.length; i < l; i++) {
		var src = scripts[i].getAttribute('src');
		if (typeof src == 'string' && src.length) {
			var matches = src.match(/^(.+\/)static\/js\/taggit\.js/);
			if (matches) {
				taggitPrefix = matches[1];
			}
		}
	}

	function split(val) {
		return val.split(/,\s*/);
	}

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

    function setup_autocomplete() {
        $.getJSON(taggitPrefix + 'ajax', {}, function(data) {
			var availableTags = data.map(function(i) {
                return i.fields.name;
            });
			if ($.ui && $.ui.autocomplete && $.ui.autocomplete.filter) {
				$('input.taggit-tags')
				// don't navigate away from the field on tab when selecting an item
				.bind("keydown", function(event) {
					if (event.keyCode === $.ui.keyCode.TAB &&
							$(this).data("autocomplete").menu.active) {
						event.preventDefault();
					}
				})
				.autocomplete({
					minLength: 2,
					source: function(request, response) {
						// delegate back to autocomplete, but extract the last term
						response($.ui.autocomplete.filter(
							availableTags, extractLast(request.term)));
					},
					focus: function() {
						// prevent value inserted on focus
						return false;
					},
					select: function(event, ui) {
						var terms = split(this.value);
						// remove the current input
                        terms[terms.length-1] = ui.item.value;
						// add placeholder to get the comma-and-space at the end
						terms.push("");
						this.value = terms.join(", ");
						return false;
					}
				});
			} else {
				$('input.taggit-tags').autocomplete({
					source: availableTags
				});
			}

		});
    }

    function get_contents_by_name(context, field_name) {
        var $form = $(context).parents('form').slice(0,1);
        var $field = $form.find('[name='+field_name +']');

        // Explicit check to CKEDITOR
        if($field[0].tagName === 'TEXTAREA' &&
               window.CKEDITOR !== undefined &&
               CKEDITOR.instances[$field.attr('id')] !== undefined) {
            return CKEDITOR.instances[$field.attr('id')].getData();
        }
        return $field.val();
    }

    function setup_generate_tags() {
        var selector = 'button.taggit-tag-suggest';
        $(selector).live('click', function() {
            // Get content field to use and url to query
            var $input = $(this).prev('input'),
                query_url = taggitPrefix + 'generate-tags',
                content_field = $input.attr('data-tag-content-field'),
                self = this;

            var raw_contents = content_field.split(',').map(function(cf) {
                return get_contents_by_name(self, cf);
            }).join('\n');

            $.ajax({
                url: query_url,
                type: 'POST',
                dataType: 'jsonp',
                data: {'contents': raw_contents},
                success: function(new_tags) {
                    // Make sure to dedup the provided tags against the
                    // already given tags.
                    var tags = split( $input.val() );
                    for(var set = {}, i = 0; i < tags.length; i++) {
                        set[tags[i]] = true;
                    }
                    tags.push.apply(tags, new_tags.filter(function(i){
                        return set[i]  === undefined
                    }));
                    $input.val(tags.join(','));
                }

            });

        });
    }

	$(document).ready(function() {
        //setup_autocomplete();
        setup_generate_tags();
    });

})((typeof window.django != 'undefined') ? django.jQuery : jQuery);
<commit_msg>Adds console<commit_after>(function($) {

	var taggitPrefix = '/';

	var scripts = document.getElementsByTagName('SCRIPT');
	for (var i = 0,l=scripts.length; i < l; i++) {
		var src = scripts[i].getAttribute('src');
		if (typeof src == 'string' && src.length) {
			var matches = src.match(/^(.+\/)static\/js\/taggit\.js/);
			if (matches) {
				taggitPrefix = matches[1];
			}
		}
	}

	function split(val) {
		return val.split(/,\s*/);
	}

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

    function setup_autocomplete() {
        $.getJSON(taggitPrefix + 'ajax', {}, function(data) {
			var availableTags = data.map(function(i) {
                return i.fields.name;
            });
			if ($.ui && $.ui.autocomplete && $.ui.autocomplete.filter) {
				$('input.taggit-tags')
				// don't navigate away from the field on tab when selecting an item
				.bind("keydown", function(event) {
					if (event.keyCode === $.ui.keyCode.TAB &&
							$(this).data("autocomplete").menu.active) {
						event.preventDefault();
					}
				})
				.autocomplete({
					minLength: 2,
					source: function(request, response) {
						// delegate back to autocomplete, but extract the last term
						response($.ui.autocomplete.filter(
							availableTags, extractLast(request.term)));
					},
					focus: function() {
						// prevent value inserted on focus
						return false;
					},
					select: function(event, ui) {
						var terms = split(this.value);
						// remove the current input
                        terms[terms.length-1] = ui.item.value;
						// add placeholder to get the comma-and-space at the end
						terms.push("");
						this.value = terms.join(", ");
						return false;
					}
				});
			} else {
				$('input.taggit-tags').autocomplete({
					source: availableTags
				});
			}

		});
    }

    function get_contents_by_name(context, field_name) {
        var $form = $(context).parents('form').slice(0,1);
        var $field = $form.find('[name='+field_name +']');

        // Explicit check to CKEDITOR
        if($field[0].tagName === 'TEXTAREA' &&
               window.CKEDITOR !== undefined &&
               CKEDITOR.instances[$field.attr('id')] !== undefined) {
            return CKEDITOR.instances[$field.attr('id')].getData();
        }
        return $field.val();
    }

    function setup_generate_tags() {
        var selector = 'button.taggit-tag-suggest';
        $(selector).live('click', function() {
            // Get content field to use and url to query
            var $input = $(this).prev('input'),
                query_url = taggitPrefix + 'generate-tags',
                content_field = $input.attr('data-tag-content-field'),
                self = this;

            var raw_contents = content_field.split(',').map(function(cf) {
                return get_contents_by_name(self, cf);
            }).join('\n');

            $.ajax({
                url: query_url,
                type: 'POST',
                dataType: 'jsonp',
                data: {'contents': raw_contents},
                success: function(new_tags) {
                    // Make sure to dedup the provided tags against the
                    // already given tags.
                    var tags = split( $input.val() );
                    for(var set = {}, i = 0; i < tags.length; i++) {
                        set[tags[i]] = true;
                    }
                    tags.push.apply(tags, new_tags.filter(function(i){
                        return set[i]  === undefined
                    }));
                    console.log('New tag set:' + tags.join(','));
                    $input.val(tags.join(','));
                }

            });

        });
    }

	$(document).ready(function() {
        //setup_autocomplete();
        setup_generate_tags();
    });

})((typeof window.django != 'undefined') ? django.jQuery : jQuery);
<|endoftext|>


<commit_before>var analytics = require('analytics');
var d3 = require('d3');
var convert = require('convert');
var Feedback = require('feedback-modal');
var mouseenter = require('mouseenter');
var mouseleave = require('mouseleave');
var Calculator = require('route-cost-calculator');
var RouteDirections = require('route-directions-table');
var RouteModal = require('route-modal');
var routeSummarySegments = require('route-summary-segments');
var routeResource = require('route-resource');
var session = require('session');
//var transitive = require('transitive');
var view = require('view');
var showMapView = require('map-view');
/**
 * Expose `View`
 */

var View = module.exports = view(require('./template.html'), function(view, model) {
  mouseenter(view.el, function() {

      var itineration = JSON.parse(localStorage.getItem('itineration'));
      for (var i=0; i<itineration.length;i++) {
           if (i!=model.index){
                var rec = d3.selectAll(".iteration-"+i)
                .style("z-index", "10");
                rec.attr('class', 'iteration-'+i+' legend-fadeout');
           }
      }
       var rec2 = d3.selectAll(".leaflet-div-icon1");
       rec2.attr('class', 'leaflet-marker-icon leaflet-div-icon2 leaflet-zoom-hide legend-fadeout');

  });

  mouseleave(view.el, function() {

  var itineration = JSON.parse(localStorage.getItem('itineration'));
   for (var i=0; i<itineration.length;i++) {
        if (i!=model.index){
             var rec = d3.selectAll(".iteration-"+i)
             .style("z-index", "50");
             rec.attr('class', 'iteration-'+i);
        }
   }
   var rec2 = d3.selectAll(".leaflet-div-icon2");
   rec2.attr('class', 'leaflet-marker-icon leaflet-div-icon1 leaflet-zoom-hide');

  });
});

View.prototype.calculator = function() {
  return new Calculator(this.model);
};

View.prototype.directions = function() {
  return new RouteDirections(this.model);
};

View.prototype.segments = function() {
  return routeSummarySegments(this.model);
};

View.prototype.costSavings = function() {
  return convert.roundNumberToString(this.model.costSavings());
};

View.prototype.timeSavingsAndNoCostSavings = function() {
  return this.model.timeSavings() && !this.model.costSavings();
};

/**
 * Show/hide
 */

View.prototype.showDetails = function(e) {
  e.preventDefault();
  var el = this.el;
  var expanded = document.querySelector('.option.expanded');
  if (expanded) expanded.classList.remove('expanded');

  el.classList.add('expanded');

  analytics.track('Expanded Route Details', {
    plan: session.plan().generateQuery(),
    route: {
      modes: this.model.modes(),
      summary: this.model.summary()
    }
  });

  var scrollable = document.querySelector('.scrollable');
  scrollable.scrollTop = el.offsetTop - 52;
};

View.prototype.hideDetails = function(e) {
  e.preventDefault();
  var list = this.el.classList;
  if (list.contains('expanded')) {
    list.remove('expanded');
  }
};

/**
 * Get the option number for display purposes (1-based)
 */

View.prototype.optionNumber = function() {
  return this.model.index + 1;
};

/**
 * View
 */

View.prototype.feedback = function(e) {
  e.preventDefault();
  Feedback(this.model).show();
};

/**
 * Select this option
 */

View.prototype.selectOption = function() {
  var route = this.model;
  var plan = session.plan();
  var tags = route.tags(plan);

  analytics.send_ga({
    category: 'route-card',
    action: 'select route',
    label: JSON.stringify(tags),
    value: 1
  });
  routeResource.findByTags(tags, function(err, resources) {
    var routeModal = new RouteModal(route, null, {
      context: 'route-card',
      resources: resources
    });
    routeModal.show();
    routeModal.on('next', function() {
      routeModal.hide();
    });
  });
};
<commit_msg>adding styles<commit_after>var analytics = require('analytics');
var d3 = require('d3');
var convert = require('convert');
var Feedback = require('feedback-modal');
var mouseenter = require('mouseenter');
var mouseleave = require('mouseleave');
var Calculator = require('route-cost-calculator');
var RouteDirections = require('route-directions-table');
var RouteModal = require('route-modal');
var routeSummarySegments = require('route-summary-segments');
var routeResource = require('route-resource');
var session = require('session');
//var transitive = require('transitive');
var view = require('view');
var showMapView = require('map-view');
/**
 * Expose `View`
 */

var View = module.exports = view(require('./template.html'), function(view, model) {
  mouseenter(view.el, function() {
      var d3_sort_list = [];
      var number = 1;
      var itineration = JSON.parse(localStorage.getItem('itineration'));
      for (var i=0; i<itineration.length;i++) {
          number += 1;
           d3_sort_list.push({'class_':".iteration-"+i, 'position':number});
           if (i!=model.index){
                d3_sort_list.push({'class_':".iteration-"+i, 'position':1});
                var rec = d3.selectAll(".iteration-"+i)
                .style("z-index", "10");
                rec.attr('class', 'iteration-'+i+' legend-fadeout');
           }
      }
      console.log("d3_sort_list ->", d3_sort_list);
       var rec2 = d3.selectAll(".leaflet-div-icon1");
       rec2.attr('class', 'leaflet-marker-icon leaflet-div-icon2 leaflet-zoom-hide legend-fadeout');

  });

  mouseleave(view.el, function() {

  var itineration = JSON.parse(localStorage.getItem('itineration'));
   for (var i=0; i<itineration.length;i++) {
        if (i!=model.index){
             var rec = d3.selectAll(".iteration-"+i)
             .style("z-index", "50");
             rec.attr('class', 'iteration-'+i);
        }
   }
   var rec2 = d3.selectAll(".leaflet-div-icon2");
   rec2.attr('class', 'leaflet-marker-icon leaflet-div-icon1 leaflet-zoom-hide');

  });
});

View.prototype.calculator = function() {
  return new Calculator(this.model);
};

View.prototype.directions = function() {
  return new RouteDirections(this.model);
};

View.prototype.segments = function() {
  return routeSummarySegments(this.model);
};

View.prototype.costSavings = function() {
  return convert.roundNumberToString(this.model.costSavings());
};

View.prototype.timeSavingsAndNoCostSavings = function() {
  return this.model.timeSavings() && !this.model.costSavings();
};

/**
 * Show/hide
 */

View.prototype.showDetails = function(e) {
  e.preventDefault();
  var el = this.el;
  var expanded = document.querySelector('.option.expanded');
  if (expanded) expanded.classList.remove('expanded');

  el.classList.add('expanded');

  analytics.track('Expanded Route Details', {
    plan: session.plan().generateQuery(),
    route: {
      modes: this.model.modes(),
      summary: this.model.summary()
    }
  });

  var scrollable = document.querySelector('.scrollable');
  scrollable.scrollTop = el.offsetTop - 52;
};

View.prototype.hideDetails = function(e) {
  e.preventDefault();
  var list = this.el.classList;
  if (list.contains('expanded')) {
    list.remove('expanded');
  }
};

/**
 * Get the option number for display purposes (1-based)
 */

View.prototype.optionNumber = function() {
  return this.model.index + 1;
};

/**
 * View
 */

View.prototype.feedback = function(e) {
  e.preventDefault();
  Feedback(this.model).show();
};

/**
 * Select this option
 */

View.prototype.selectOption = function() {
  var route = this.model;
  var plan = session.plan();
  var tags = route.tags(plan);

  analytics.send_ga({
    category: 'route-card',
    action: 'select route',
    label: JSON.stringify(tags),
    value: 1
  });
  routeResource.findByTags(tags, function(err, resources) {
    var routeModal = new RouteModal(route, null, {
      context: 'route-card',
      resources: resources
    });
    routeModal.show();
    routeModal.on('next', function() {
      routeModal.hide();
    });
  });
};
<|endoftext|>


<commit_before>import gulp from 'gulp';
import nugetRestore from 'gulp-nuget-restore';

export default {
  /**
   * Task name
   * @type {String}
   */
  name: 'sitecore:nuget-restore',

  /**
   * Task description
   * @type {String}
   */
  description: 'Restore all nuget packages for solution.',

  /**
   * Task default configuration
   * @type {Object}
   */
  config: {
    deps: [],
  },

  /**
   * Task help options
   * @type {Object}
   */
  help: {
    'solution, -s': 'Solution file path',
  },

  /**
   * Task function
   * @param {object} config
   * @param {Function} end
   * @param {Function} error
   */
  fn(config, end, error) {
    if (!config.solution) {
      error('A solution file path was not set.');

      return;
    }

    gulp.src(config.solution)
      .pipe(nugetRestore())
      .on('end', end);
  },
};
<commit_msg>Add a noop pipe to ensure end is called<commit_after>import gulp from 'gulp';
import es from 'event-stream';
import nugetRestore from 'gulp-nuget-restore';

export default {
  /**
   * Task name
   * @type {String}
   */
  name: 'sitecore:nuget-restore',

  /**
   * Task description
   * @type {String}
   */
  description: 'Restore all nuget packages for solution.',

  /**
   * Task default configuration
   * @type {Object}
   */
  config: {
    deps: [],
  },

  /**
   * Task help options
   * @type {Object}
   */
  help: {
    'solution, -s': 'Solution file path',
  },

  /**
   * Task function
   * @param {object} config
   * @param {Function} end
   * @param {Function} error
   */
  fn(config, end, error) {
    if (!config.solution) {
      error('A solution file path was not set.');

      return;
    }

    gulp.src(config.solution)
      .pipe(nugetRestore())
      .pipe(es.through(() => {}))
        .on('end', end);
  },
};
<|endoftext|>


<commit_before>/**
 * @ngdoc page
 * @name keyboard
 * @module ionic
 * @description
 * On both Android and iOS, Ionic will attempt to prevent the keyboard from obscuring inputs and
 * focusable elements when it appears by scrolling them into view.  In order for this to work,
 * any focusable elements must be within a [Scroll View](http://ionicframework.com/docs/api/directive/ionScroll/)
 * or a directive such as [Content](http://ionicframework.com/docs/api/directive/ionContent/) that has a Scroll View.
 *
 * It will also attempt to prevent the native overflow scrolling on focus, which can cause layout issues such as
 * pushing headers up and out of view.
 *
 * The keyboard fixes work best in conjunction with the [Ionic Keyboard Plugin](https://github.com/driftyco/ionic-plugins-keyboard),
 * although it will perform reasonably well without.  However, if you are using Cordova there is no reason not to use the plugin.
 *
 * ### Hide when keyboard shows
 *
 * To hide an element when the keyboard is open, add the class `hide-on-keyboard-open`.
 *
 * ```html
 * <div class="hide-on-keyboard-open">
 *   <div id="google-map"></div>
 * </div>
 * ```
 *
 *
 * ### Android Notes
 * - If your app is running in fullscreen, i.e. you have `<preference name="Fullscreen" value="true" />` in your `config.xml` file
 * you will need to set `ionic.Platform.isFullScreen = true` manually.
 *
 * - If you are not using the keyboard plugin, it may be necessary to set `android:windowSoftInputMode="adjustResize"` to
 * your activity in `AndroidManifest.xml` to get things working properly.
 *
 * ### iOS Notes
 * - if you are not using the keyboard plugin, switching to inputs below the keyboard using the accessory bar will automatically use the native browser's
 * overflow scrolling and push headers out of view
 *
 */

/*
IONIC KEYBOARD
---------------

*/

var keyboardViewportHeight = window.innerHeight;
var keyboardIsOpen;
var keyboardActiveElement;
var keyboardFocusOutTimer;
var keyboardFocusInTimer;
var keyboardLastShow = 0;

var KEYBOARD_OPEN_CSS = 'keyboard-open';
var SCROLL_CONTAINER_CSS = 'scroll';

ionic.keyboard = {
  isOpen: false,
  height: null,
  landscape: false,
};

function keyboardInit() {
  if( keyboardHasPlugin() ) {
    window.addEventListener('native.showkeyboard', keyboardNativeShow);
    window.addEventListener('native.hidekeyboard', keyboardFocusOut);
  }
  else {
    document.body.addEventListener('focusout', keyboardFocusOut);
  }

  document.body.addEventListener('ionic.focusin', keyboardBrowserFocusIn);
  document.body.addEventListener('focusin', keyboardBrowserFocusIn);

  document.body.addEventListener('orientationchange', keyboardOrientationChange);

  document.removeEventListener('touchstart', keyboardInit);
}

function keyboardNativeShow(e) {
  clearTimeout(keyboardFocusOutTimer);
  ionic.keyboard.height = e.keyboardHeight;
}

function keyboardBrowserFocusIn(e) {
  if( !e.target || !ionic.tap.isTextInput(e.target) || !keyboardIsWithinScroll(e.target) ) return;

  document.addEventListener('keydown', keyboardOnKeyDown, false);

  document.body.scrollTop = 0;
  document.body.querySelector('.scroll-content').scrollTop = 0;

  keyboardActiveElement = e.target;

  keyboardSetShow(e);
}

function keyboardSetShow(e) {
  clearTimeout(keyboardFocusInTimer);
  clearTimeout(keyboardFocusOutTimer);

  keyboardFocusInTimer = setTimeout(function(){
    if ( keyboardLastShow + 350 > Date.now() ) return;
    keyboardLastShow = Date.now();
    var keyboardHeight;
    var elementBounds = keyboardActiveElement.getBoundingClientRect();
    var count = 0;

    var pollKeyboardHeight = setInterval(function(){

      keyboardHeight = keyboardGetHeight();
      if (count > 10){
        clearInterval(pollKeyboardHeight);
        //waited long enough, just guess
        keyboardHeight = 275;
      }
      if (keyboardHeight){
        keyboardShow(e.target, elementBounds.top, elementBounds.bottom, keyboardViewportHeight, keyboardHeight);
        clearInterval(pollKeyboardHeight);
      }
      count++;

    }, 100);
  }, 32);
}

function keyboardShow(element, elementTop, elementBottom, viewportHeight, keyboardHeight) {
  var details = {
    target: element,
    elementTop: Math.round(elementTop),
    elementBottom: Math.round(elementBottom),
    keyboardHeight: keyboardHeight,
    viewportHeight: viewportHeight
  };

  details.hasPlugin = keyboardHasPlugin();

  details.contentHeight = viewportHeight - keyboardHeight;

  console.log('keyboardShow', keyboardHeight, details.contentHeight);

  // distance from top of input to the top of the keyboard
  details.keyboardTopOffset = details.elementTop - details.contentHeight;

  console.log('keyboardTopOffset', details.elementTop, details.contentHeight, details.keyboardTopOffset);

  // figure out if the element is under the keyboard
  details.isElementUnderKeyboard = (details.elementBottom > details.contentHeight);

  ionic.keyboard.isOpen = true;

  // send event so the scroll view adjusts
  keyboardActiveElement = element;
  ionic.trigger('scrollChildIntoView', details, true);

  ionic.requestAnimationFrame(function(){
    document.body.classList.add(KEYBOARD_OPEN_CSS);
  });

  // any showing part of the document that isn't within the scroll the user
  // could touchmove and cause some ugly changes to the app, so disable
  // any touchmove events while the keyboard is open using e.preventDefault()
  document.addEventListener('touchmove', keyboardPreventDefault, false);

  return details;
}

function keyboardFocusOut(e) {
  clearTimeout(keyboardFocusOutTimer);

  keyboardFocusOutTimer = setTimeout(keyboardHide, 350);
}

function keyboardHide() {
  console.log('keyboardHide');
  ionic.keyboard.isOpen = false;

  ionic.trigger('resetScrollView', {
    target: keyboardActiveElement
  }, true);

  ionic.requestAnimationFrame(function(){
    document.body.classList.remove(KEYBOARD_OPEN_CSS);
  });

  // the keyboard is gone now, remove the touchmove that disables native scroll
  document.removeEventListener('touchmove', keyboardPreventDefault);
  document.removeEventListener('keydown', keyboardOnKeyDown);
}

function keyboardUpdateViewportHeight() {
  if( window.innerHeight > keyboardViewportHeight ) {
    keyboardViewportHeight = window.innerHeight;
  }
}

function keyboardOnKeyDown(e) {
  if( ionic.scroll.isScrolling ) {
    keyboardPreventDefault(e);
  }
}

function keyboardPreventDefault(e) {
  if( e.target.tagName !== 'TEXTAREA' ) {
    e.preventDefault();
  }
}

function keyboardOrientationChange() {
  var updatedViewportHeight = window.innerHeight;

  //too slow, have to wait for updated height
  if (updatedViewportHeight === keyboardViewportHeight){
    var count = 0;
    var pollViewportHeight = setInterval(function(){
      //give up
      if (count > 10){
        clearInterval(pollViewportHeight);
      }

      updatedViewportHeight = window.innerHeight;

      if (updatedViewportHeight !== keyboardViewportHeight){
        if (updatedViewportHeight < keyboardViewportHeight){
          ionic.keyboard.landscape = true;
        }
        else {
          ionic.keyboard.landscape = false;
        }
        keyboardViewportHeight = updatedViewportHeight;
        clearInterval(pollViewportHeight);
      }
      count++;

    }, 50);
  }
  else {
    keyboardViewportHeight = updatedViewportHeight;
  }
}

function keyboardGetHeight() {
  // check if we are already have a keyboard height from the plugin
  if ( ionic.keyboard.height ) {
    return ionic.keyboard.height;
  }

  if ( ionic.Platform.isAndroid() ){
    //should be using the plugin, no way to know how big the keyboard is, so guess
    if ( ionic.Platform.isFullScreen ){
      return 275;
    }
    //otherwise, wait for the screen to resize
    if ( window.innerHeight < keyboardViewportHeight ){
      return keyboardViewportHeight - window.innerHeight;
    }
    else {
      return 0;
    }
  }

  // fallback for when its the webview without the plugin
  // or for just the standard web browser
  if( ionic.Platform.isIOS() ) {
    if ( ionic.keyboard.landscape ){
      return 206;
    }

    if (!ionic.Platform.isWebView()){
      return 216;
    }

    return 260;
  }

  // safe guess
  return 275;
}

function keyboardIsWithinScroll(ele) {
  while(ele) {
    if(ele.classList.contains(SCROLL_CONTAINER_CSS)) {
      return true;
    }
    ele = ele.parentElement;
  }
  return false;
}

function keyboardHasPlugin() {
  return !!(window.cordova && cordova.plugins && cordova.plugins.Keyboard);
}

ionic.Platform.ready(function() {
  keyboardUpdateViewportHeight();

  // Android sometimes reports bad innerHeight on window.load
  // try it again in a lil bit to play it safe
  setTimeout(keyboardUpdateViewportHeight, 999);

  // only initialize the adjustments for the virtual keyboard
  // if a touchstart event happens
  document.addEventListener('touchstart', keyboardInit, false);
});

<commit_msg>update keyboard docs with windowSoftInputMode info<commit_after>/**
 * @ngdoc page
 * @name keyboard
 * @module ionic
 * @description
 * On both Android and iOS, Ionic will attempt to prevent the keyboard from obscuring inputs and
 * focusable elements when it appears by scrolling them into view.  In order for this to work,
 * any focusable elements must be within a [Scroll View](http://ionicframework.com/docs/api/directive/ionScroll/)
 * or a directive such as [Content](http://ionicframework.com/docs/api/directive/ionContent/) that has a Scroll View.
 *
 * It will also attempt to prevent the native overflow scrolling on focus, which can cause layout issues such as
 * pushing headers up and out of view.
 *
 * The keyboard fixes work best in conjunction with the [Ionic Keyboard Plugin](https://github.com/driftyco/ionic-plugins-keyboard),
 * although it will perform reasonably well without.  However, if you are using Cordova there is no reason not to use the plugin.
 *
 * ### Hide when keyboard shows
 *
 * To hide an element when the keyboard is open, add the class `hide-on-keyboard-open`.
 *
 * ```html
 * <div class="hide-on-keyboard-open">
 *   <div id="google-map"></div>
 * </div>
 * ```
 *
 *
 * ### Android Notes
 * - If your app is running in fullscreen, i.e. you have `<preference name="Fullscreen" value="true" />` in your `config.xml` file
 * you will need to set `ionic.Platform.isFullScreen = true` manually.
 *
 * - You can configure the behavior of the web view when the keyboard shows by setting
 *   [android:windowSoftInputMode](http://developer.android.com/reference/android/R.attr.html#windowSoftInputMode) to either `adjustPan`, `adjustResize` or `adjustNothing` in your app's activity in `AndroidManifest.xml`. `adjustResize` is the recommended setting for Ionic, but if for some reason you do use `adjustPan` you will need to set `ionic.Platform.isFullScreen = true`.
 *
 *   ```xml
 *   <activity android:windowSoftInputMode="adjustResize">
 *
 *   ```
 *
 * ### iOS Notes
 * - if you are not using the keyboard plugin, switching to inputs below the keyboard using the accessory bar will automatically use the native browser's
 * overflow scrolling and push headers out of view
 *
 */

/*
IONIC KEYBOARD
---------------

*/

var keyboardViewportHeight = window.innerHeight;
var keyboardIsOpen;
var keyboardActiveElement;
var keyboardFocusOutTimer;
var keyboardFocusInTimer;
var keyboardLastShow = 0;

var KEYBOARD_OPEN_CSS = 'keyboard-open';
var SCROLL_CONTAINER_CSS = 'scroll';

ionic.keyboard = {
  isOpen: false,
  height: null,
  landscape: false,
};

function keyboardInit() {
  if( keyboardHasPlugin() ) {
    window.addEventListener('native.showkeyboard', keyboardNativeShow);
    window.addEventListener('native.hidekeyboard', keyboardFocusOut);
  }
  else {
    document.body.addEventListener('focusout', keyboardFocusOut);
  }

  document.body.addEventListener('ionic.focusin', keyboardBrowserFocusIn);
  document.body.addEventListener('focusin', keyboardBrowserFocusIn);

  document.body.addEventListener('orientationchange', keyboardOrientationChange);

  document.removeEventListener('touchstart', keyboardInit);
}

function keyboardNativeShow(e) {
  clearTimeout(keyboardFocusOutTimer);
  ionic.keyboard.height = e.keyboardHeight;
}

function keyboardBrowserFocusIn(e) {
  if( !e.target || !ionic.tap.isTextInput(e.target) || !keyboardIsWithinScroll(e.target) ) return;

  document.addEventListener('keydown', keyboardOnKeyDown, false);

  document.body.scrollTop = 0;
  document.body.querySelector('.scroll-content').scrollTop = 0;

  keyboardActiveElement = e.target;

  keyboardSetShow(e);
}

function keyboardSetShow(e) {
  clearTimeout(keyboardFocusInTimer);
  clearTimeout(keyboardFocusOutTimer);

  keyboardFocusInTimer = setTimeout(function(){
    if ( keyboardLastShow + 350 > Date.now() ) return;
    keyboardLastShow = Date.now();
    var keyboardHeight;
    var elementBounds = keyboardActiveElement.getBoundingClientRect();
    var count = 0;

    var pollKeyboardHeight = setInterval(function(){

      keyboardHeight = keyboardGetHeight();
      if (count > 10){
        clearInterval(pollKeyboardHeight);
        //waited long enough, just guess
        keyboardHeight = 275;
      }
      if (keyboardHeight){
        keyboardShow(e.target, elementBounds.top, elementBounds.bottom, keyboardViewportHeight, keyboardHeight);
        clearInterval(pollKeyboardHeight);
      }
      count++;

    }, 100);
  }, 32);
}

function keyboardShow(element, elementTop, elementBottom, viewportHeight, keyboardHeight) {
  var details = {
    target: element,
    elementTop: Math.round(elementTop),
    elementBottom: Math.round(elementBottom),
    keyboardHeight: keyboardHeight,
    viewportHeight: viewportHeight
  };

  details.hasPlugin = keyboardHasPlugin();

  details.contentHeight = viewportHeight - keyboardHeight;

  console.log('keyboardShow', keyboardHeight, details.contentHeight);

  // distance from top of input to the top of the keyboard
  details.keyboardTopOffset = details.elementTop - details.contentHeight;

  console.log('keyboardTopOffset', details.elementTop, details.contentHeight, details.keyboardTopOffset);

  // figure out if the element is under the keyboard
  details.isElementUnderKeyboard = (details.elementBottom > details.contentHeight);

  ionic.keyboard.isOpen = true;

  // send event so the scroll view adjusts
  keyboardActiveElement = element;
  ionic.trigger('scrollChildIntoView', details, true);

  ionic.requestAnimationFrame(function(){
    document.body.classList.add(KEYBOARD_OPEN_CSS);
  });

  // any showing part of the document that isn't within the scroll the user
  // could touchmove and cause some ugly changes to the app, so disable
  // any touchmove events while the keyboard is open using e.preventDefault()
  document.addEventListener('touchmove', keyboardPreventDefault, false);

  return details;
}

function keyboardFocusOut(e) {
  clearTimeout(keyboardFocusOutTimer);

  keyboardFocusOutTimer = setTimeout(keyboardHide, 350);
}

function keyboardHide() {
  console.log('keyboardHide');
  ionic.keyboard.isOpen = false;

  ionic.trigger('resetScrollView', {
    target: keyboardActiveElement
  }, true);

  ionic.requestAnimationFrame(function(){
    document.body.classList.remove(KEYBOARD_OPEN_CSS);
  });

  // the keyboard is gone now, remove the touchmove that disables native scroll
  document.removeEventListener('touchmove', keyboardPreventDefault);
  document.removeEventListener('keydown', keyboardOnKeyDown);
}

function keyboardUpdateViewportHeight() {
  if( window.innerHeight > keyboardViewportHeight ) {
    keyboardViewportHeight = window.innerHeight;
  }
}

function keyboardOnKeyDown(e) {
  if( ionic.scroll.isScrolling ) {
    keyboardPreventDefault(e);
  }
}

function keyboardPreventDefault(e) {
  if( e.target.tagName !== 'TEXTAREA' ) {
    e.preventDefault();
  }
}

function keyboardOrientationChange() {
  var updatedViewportHeight = window.innerHeight;

  //too slow, have to wait for updated height
  if (updatedViewportHeight === keyboardViewportHeight){
    var count = 0;
    var pollViewportHeight = setInterval(function(){
      //give up
      if (count > 10){
        clearInterval(pollViewportHeight);
      }

      updatedViewportHeight = window.innerHeight;

      if (updatedViewportHeight !== keyboardViewportHeight){
        if (updatedViewportHeight < keyboardViewportHeight){
          ionic.keyboard.landscape = true;
        }
        else {
          ionic.keyboard.landscape = false;
        }
        keyboardViewportHeight = updatedViewportHeight;
        clearInterval(pollViewportHeight);
      }
      count++;

    }, 50);
  }
  else {
    keyboardViewportHeight = updatedViewportHeight;
  }
}

function keyboardGetHeight() {
  // check if we are already have a keyboard height from the plugin
  if ( ionic.keyboard.height ) {
    return ionic.keyboard.height;
  }

  if ( ionic.Platform.isAndroid() ){
    //should be using the plugin, no way to know how big the keyboard is, so guess
    if ( ionic.Platform.isFullScreen ){
      return 275;
    }
    //otherwise, wait for the screen to resize
    if ( window.innerHeight < keyboardViewportHeight ){
      return keyboardViewportHeight - window.innerHeight;
    }
    else {
      return 0;
    }
  }

  // fallback for when its the webview without the plugin
  // or for just the standard web browser
  if( ionic.Platform.isIOS() ) {
    if ( ionic.keyboard.landscape ){
      return 206;
    }

    if (!ionic.Platform.isWebView()){
      return 216;
    }

    return 260;
  }

  // safe guess
  return 275;
}

function keyboardIsWithinScroll(ele) {
  while(ele) {
    if(ele.classList.contains(SCROLL_CONTAINER_CSS)) {
      return true;
    }
    ele = ele.parentElement;
  }
  return false;
}

function keyboardHasPlugin() {
  return !!(window.cordova && cordova.plugins && cordova.plugins.Keyboard);
}

ionic.Platform.ready(function() {
  keyboardUpdateViewportHeight();

  // Android sometimes reports bad innerHeight on window.load
  // try it again in a lil bit to play it safe
  setTimeout(keyboardUpdateViewportHeight, 999);

  // only initialize the adjustments for the virtual keyboard
  // if a touchstart event happens
  document.addEventListener('touchstart', keyboardInit, false);
});

<|endoftext|>


<commit_before>var Events = {
  debug: 1,
  api: 'https://online.ntnu.no/events/events.ics',

  get: function(callback) {
    if (callback == undefined) {
      if (this.debug) console.log('ERROR: Callback is required. In the callback you should insert the results into the DOM.');
      return;
    }

    // Get ICS from server
    try {
      var cal = $.parseIcs(this.api);
      for (var i = 0; i < 3; i++) {
        if (this.debug) console.log(this.prettifyDate(cal.event[i].dtend[0].value) + ' ' + this.treatTextField(cal.event[i].summary[0].value));
      }
    }
    catch (err) {
      if (this.debug) console.log('ERROR: Fetching events failed', err);
    }
  },

  treatTextField: function(field) {
    field = field.replace(/(\d\.*[\s-]+)*\d\.*\s+klasse/gi, '');
    field = field.replace(/\-/, '');
    // Remove multiple whitespace
    field = field.replace(/\s\s+/g,'');
    // "..stedHvor.." -> "..sted. Hvor.."
    field = field.replace(/([a-z])([A-Z])/g, '$1. '+'$2'.capitalize());
    // Remove meta information from title or description, within curly brackets {}
    field = field.replace(/\{.*\}/gi,'');
    // Shorten 'bedriftspresentasjon' to 'bedpres'
    field = field.replace(/edrift(s)?presentasjon/gi, 'edpres');
    field = field.replace(/\./gi, '');
    field = field.replace(/consulting/gi, '');
    // Trimming
    field = field.trim();
    return field;
  },

  prettifyDate: function(meetings) {
    meetings = meetings.trim();
    var submeetings = ((meetings.substring(6,8) - 0) + '.' + (meetings.substring(4,6) - 0));
    return submeetings;
  },

}
<commit_msg>events: turned off debug<commit_after>var Events = {
  debug: 0,
  api: 'https://online.ntnu.no/events/events.ics',

  get: function(callback) {
    if (callback == undefined) {
      if (this.debug) console.log('ERROR: Callback is required. In the callback you should insert the results into the DOM.');
      return;
    }

    // Get ICS from server
    try {
      var cal = $.parseIcs(this.api);
      for (var i = 0; i < 3; i++) {
        if (this.debug) console.log(this.prettifyDate(cal.event[i].dtend[0].value) + ' ' + this.treatTextField(cal.event[i].summary[0].value));
      }
    }
    catch (err) {
      if (this.debug) console.log('ERROR: Fetching events failed', err);
    }
  },

  treatTextField: function(field) {
    field = field.replace(/(\d\.*[\s-]+)*\d\.*\s+klasse/gi, '');
    field = field.replace(/\-/, '');
    // Remove multiple whitespace
    field = field.replace(/\s\s+/g,'');
    // "..stedHvor.." -> "..sted. Hvor.."
    field = field.replace(/([a-z])([A-Z])/g, '$1. '+'$2'.capitalize());
    // Remove meta information from title or description, within curly brackets {}
    field = field.replace(/\{.*\}/gi,'');
    // Shorten 'bedriftspresentasjon' to 'bedpres'
    field = field.replace(/edrift(s)?presentasjon/gi, 'edpres');
    field = field.replace(/\./gi, '');
    field = field.replace(/consulting/gi, '');
    // Trimming
    field = field.trim();
    return field;
  },

  prettifyDate: function(meetings) {
    meetings = meetings.trim();
    var submeetings = ((meetings.substring(6,8) - 0) + '.' + (meetings.substring(4,6) - 0));
    return submeetings;
  },

}
<|endoftext|>


<commit_before>/**
 * Visual Blocks Editor
 *
 * Copyright 2012 Google Inc.
 * http://code.google.com/p/google-blockly/
 *
 * 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
 *
 *   http://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.
 */

/**
 * @fileoverview XML reader and writer.
 * @author fraser@google.com (Neil Fraser)
 */

Blockly.Xml = {};

/**
 * Encode a block tree as XML.
 * @param {!Object} blockGroup The SVG workspace.
 * @return {!Element} XML document.
 */
Blockly.Xml.workspaceToDom = function(blockGroup) {
  var xml = document.createElement('xml');
  var blocks = blockGroup.getTopBlocks();
  for (var i = 0, block; block = blocks[i]; i++) {
    var element = Blockly.Xml.blockToDom_(block);
    var xy = block.getRelativeToSurfaceXY();
    element.setAttribute('x', Blockly.RTL ? -xy.x : xy.x);
    element.setAttribute('y', xy.y);
    xml.appendChild(element);
  }
  return xml;
};

/**
 * Encode a block subtree as XML.
 * @param {!Blockly.Block} block The root block to encode.
 * @return {!Element} Tree of XML elements.
 * @private
 */
Blockly.Xml.blockToDom_ = function(block) {
  var element = document.createElement('block');
  element.setAttribute('type', block.type);
  if (block.mutationToDom) {
    // Custom data for an advanced block.
    element.appendChild(block.mutationToDom());
  }
  for (var i = 0, title; title = block.titleRow[i]; i++) {
    var container = document.createElement('title');
    var titleText = document.createTextNode(title.getText());
    container.appendChild(titleText);
    element.appendChild(container);
  }

  if (block.comment) {
    var commentElement = document.createElement('comment');
    var commentText = document.createTextNode(block.comment.getText());
    commentElement.appendChild(commentText);
    commentElement.setAttribute('pinned', block.comment.isPinned());
    var xy = block.comment.getBubbleLocation();
    commentElement.setAttribute('x', xy.x);
    commentElement.setAttribute('y', xy.y);
    var hw = block.comment.getBubbleSize();
    commentElement.setAttribute('h', hw.height);
    commentElement.setAttribute('w', hw.width);
    element.appendChild(commentElement);
  }

  var valueInputs = false;
  for (var i = 0, input; input = block.inputList[i]; i++) {
    var container;
    if (input.type == Blockly.LOCAL_VARIABLE) {
      container = document.createElement('variable');
      container.setAttribute('data', input.getText());
    } else {
      if (input.type == Blockly.INPUT_VALUE) {
        valueInputs = true;
        container = document.createElement('value');
      } else if (input.type == Blockly.NEXT_STATEMENT) {
        container = document.createElement('statement');
      }
      var childBlock = input.targetBlock();
      if (childBlock) {
        container.appendChild(Blockly.Xml.blockToDom_(childBlock));
      }
    }
    if (input.label && input.label.getText) {
      container.setAttribute('label', input.label.getText());
    }
    element.appendChild(container);
  }
  if (valueInputs) {
    element.setAttribute('inline', block.inputsInline);
  }
  if (block.collapsed) {
    element.setAttribute('collapsed', true);
  }

  if (block.nextConnection) {
    var container = document.createElement('next');
    var nextBlock = block.nextConnection.targetBlock();
    if (nextBlock) {
      container.appendChild(Blockly.Xml.blockToDom_(nextBlock));
    }
    element.appendChild(container);
  }

  return element;
};

/**
 * Converts a DOM structure into plain text.
 * Currently the text format is fairly ugly: all one line with no whitespace.
 * @param {!Element} dom A tree of XML elements.
 * @return {string} Text representation.
 */
Blockly.Xml.domToText = function(dom) {
  var oSerializer = new XMLSerializer();
  return oSerializer.serializeToString(dom);
};

/**
 * Converts a DOM structure into properly indented text.
 * @param {!Element} dom A tree of XML elements.
 * @return {string} Text representation.
 */
Blockly.Xml.domToPrettyText = function(dom) {
  // This function is not guaranteed to be correct for all XML.
  // But it handles the XML that Blockly generates.
  var line = Blockly.Xml.domToText(dom);
  // Add place every open and close tag on its own line.
  var lines = line.split('<');
  // Indent every line.
  var indent = '';
  for (var x = 1; x < lines.length; x++) {
    var nextChar = lines[x][0];
    if (nextChar == '/') {
      indent = indent.substring(2);
    }
    lines[x] = indent + '<' + lines[x];
    if (nextChar != '/') {
      indent += '  ';
    }
  }
  // Pull simple tags back together.
  // E.g. <foo></foo>
  var text = lines.join('\n');
  text = text.replace(/(<(\w+)[^>]*>[^\n]*)\n *<\/\2>/g, '$1</$2>');
  // Trim leading blank line.
  return text.replace(/^\n/, '');
};

/**
 * Converts plain text into a DOM structure.
 * Throws an error if XML doesn't parse.
 * @param {string} text Text representation.
 * @return {!Element} A tree of XML elements.
 */
Blockly.Xml.textToDom = function(text) {
  var oParser = new DOMParser();
  var dom = oParser.parseFromString(text, 'text/xml');
  // The DOM should have one and only one top-level node, an XML tag.
  if (!dom || !dom.firstChild || dom.firstChild.tagName != 'xml' ||
      dom.firstChild !== dom.lastChild) {
    // Whatever we got back from the parser is not XML.
    throw 'Blockly.Xml.textToDom did not obtain a valid XML tree.';
  }
  return dom.firstChild;
};

/**
 * Decode an XML DOM and create blocks on the workspace.
 * @param {!Object} blockGroup The SVG workspace.
 * @param {!Element} xml XML DOM.
 */
Blockly.Xml.domToWorkspace = function(blockGroup, xml) {
  for (var x = 0, xmlChild; xmlChild = xml.childNodes[x]; x++) {
    if (xmlChild.nodeName == 'block') {
      var block = Blockly.Xml.domToBlock_(blockGroup, xmlChild);
      var blockX = parseInt(xmlChild.getAttribute('x'), 10);
      var blockY = parseInt(xmlChild.getAttribute('y'), 10);
      if (!isNaN(blockX) && !isNaN(blockY)) {
        block.moveBy(Blockly.RTL ? -blockX : blockX, blockY);
      }
    }
  }
};

/**
 * Decode an XML block tag and create a block (and possibly sub blocks) on the
 * workspace.
 * @param {!Object} blockGroup The SVG workspace.
 * @param {!Element} xmlBlock XML block element.
 * @return {!Blockly.Block} The root block created.
 * @private
 */
Blockly.Xml.domToBlock_ = function(blockGroup, xmlBlock) {
  var prototypeName = xmlBlock.getAttribute('type');
  var block = new Blockly.Block(blockGroup, prototypeName);

  var inline = xmlBlock.getAttribute('inline');
  if (inline) {
    block.setInputsInline(inline == 'true');
  }

  var collapsed = xmlBlock.getAttribute('collapsed');
  if (collapsed) {
    block.setCollapsed(collapsed == 'true');
  }

  var titleIndex = -1;
  var inputIndicies = {};
  inputIndicies[Blockly.LOCAL_VARIABLE] = -1;
  inputIndicies[Blockly.INPUT_VALUE] = -1;
  inputIndicies[Blockly.NEXT_STATEMENT] = -1;
  /**
   * Returns the next input of a given type.
   * Closure: uses inputIndicies and block from external scope.
   * @param {number} type The type of input to search for.
   * @return {Object} The next input or null if none.
   */
  function nextInput(type) {
    var startIndex = inputIndicies[type];
    for (var i = startIndex + 1; i < block.inputList.length; i++) {
      if (block.inputList[i].type == type) {
        inputIndicies[type] = i;
        return block.inputList[i];
      }
    }
    return null;
  }

  for (var x = 0, xmlChild; xmlChild = xmlBlock.childNodes[x]; x++) {
    if (xmlChild.nodeType == 3 && xmlChild.data.match(/^\s*$/)) {
      // Extra whitespace between tags does not concern us.
      continue;
    }
    var blockChild = null;
    var input;
    switch (xmlChild.tagName.toLowerCase()) {
      case 'mutation':
        // Custom data for an advanced block.
        if (block.domToMutation) {
          block.domToMutation(xmlChild);
        }
        break;
      case 'comment':
        block.setCommentText(xmlChild.textContent);
        var pinned = xmlChild.getAttribute('pinned');
        if (pinned) {
          block.comment.setPinned(pinned == 'true');
        }
        var bubbleX = parseInt(xmlChild.getAttribute('x'), 10);
        var bubbleY = parseInt(xmlChild.getAttribute('y'), 10);
        if (!isNaN(bubbleX) && !isNaN(bubbleY)) {
          block.comment.setBubbleLocation(bubbleX, bubbleY, false);
        }
        var bubbleW = parseInt(xmlChild.getAttribute('w'), 10);
        var bubbleH = parseInt(xmlChild.getAttribute('h'), 10);
        if (!isNaN(bubbleW) && !isNaN(bubbleH)) {
          block.comment.setBubbleSize(bubbleW, bubbleH);
        }
        break;
      case 'title':
        block.setTitleText(xmlChild.textContent, ++titleIndex);
        break;
      case 'variable':
        var data = xmlChild.getAttribute('data');
        if (data !== null) {
          input = nextInput(Blockly.LOCAL_VARIABLE);
          if (!input) {
            throw 'Variable input does not exist.';
          }
          input.setText(data);
        }
        break;
      case 'value':
        input = nextInput(Blockly.INPUT_VALUE);
        if (!input) {
          throw 'Value input does not exist.';
        }
        if (xmlChild.firstChild && xmlChild.firstChild.tagName == 'block') {
          blockChild = Blockly.Xml.domToBlock_(blockGroup, xmlChild.firstChild);
          if (!blockChild.outputConnection) {
            throw 'Child block does not have output value.';
          }
          input.connect(blockChild.outputConnection);
        }
        break;
      case 'statement':
        input = nextInput(Blockly.NEXT_STATEMENT);
        if (!input) {
          throw 'Statement input does not exist.';
        }
        if (xmlChild.firstChild && xmlChild.firstChild.tagName == 'block') {
          blockChild = Blockly.Xml.domToBlock_(blockGroup, xmlChild.firstChild);
          if (!blockChild.previousConnection) {
            throw 'Child block does not have previous statement.';
          }
          input.connect(blockChild.previousConnection);
        }
        break;
      case 'next':
        if (xmlChild.firstChild && xmlChild.firstChild.tagName == 'block') {
          if (!block.nextConnection) {
            throw 'Next statement does not exist.';
          } else if (block.nextConnection.targetConnection) {
            // This could happen if there is more than one XML 'next' tag.
            throw 'Next statement is already connected.';
          }
          blockChild = Blockly.Xml.domToBlock_(blockGroup, xmlChild.firstChild);
          if (!blockChild.previousConnection) {
            throw 'Next block does not have previous statement.';
          }
          block.nextConnection.connect(blockChild.previousConnection);
        }
        break;
      default:
        // Unknown tag; ignore.  Same principle as HTML parsers.
    }
    var labelText = xmlChild.getAttribute('label');
    if (labelText !== null && input && input.label && input.label.setText) {
      input.label.setText(labelText);
    }
  }
  block.render();
  return block;
};
<commit_msg>Improved XML parser.<commit_after>/**
 * Visual Blocks Editor
 *
 * Copyright 2012 Google Inc.
 * http://code.google.com/p/google-blockly/
 *
 * 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
 *
 *   http://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.
 */

/**
 * @fileoverview XML reader and writer.
 * @author fraser@google.com (Neil Fraser)
 */

Blockly.Xml = {};

/**
 * Encode a block tree as XML.
 * @param {!Object} blockGroup The SVG workspace.
 * @return {!Element} XML document.
 */
Blockly.Xml.workspaceToDom = function(blockGroup) {
  var xml = document.createElement('xml');
  var blocks = blockGroup.getTopBlocks();
  for (var i = 0, block; block = blocks[i]; i++) {
    var element = Blockly.Xml.blockToDom_(block);
    var xy = block.getRelativeToSurfaceXY();
    element.setAttribute('x', Blockly.RTL ? -xy.x : xy.x);
    element.setAttribute('y', xy.y);
    xml.appendChild(element);
  }
  return xml;
};

/**
 * Encode a block subtree as XML.
 * @param {!Blockly.Block} block The root block to encode.
 * @return {!Element} Tree of XML elements.
 * @private
 */
Blockly.Xml.blockToDom_ = function(block) {
  var element = document.createElement('block');
  element.setAttribute('type', block.type);
  if (block.mutationToDom) {
    // Custom data for an advanced block.
    element.appendChild(block.mutationToDom());
  }
  for (var i = 0, title; title = block.titleRow[i]; i++) {
    var container = document.createElement('title');
    var titleText = document.createTextNode(title.getText());
    container.appendChild(titleText);
    element.appendChild(container);
  }

  if (block.comment) {
    var commentElement = document.createElement('comment');
    var commentText = document.createTextNode(block.comment.getText());
    commentElement.appendChild(commentText);
    commentElement.setAttribute('pinned', block.comment.isPinned());
    var xy = block.comment.getBubbleLocation();
    commentElement.setAttribute('x', xy.x);
    commentElement.setAttribute('y', xy.y);
    var hw = block.comment.getBubbleSize();
    commentElement.setAttribute('h', hw.height);
    commentElement.setAttribute('w', hw.width);
    element.appendChild(commentElement);
  }

  var valueInputs = false;
  for (var i = 0, input; input = block.inputList[i]; i++) {
    var container;
    if (input.type == Blockly.LOCAL_VARIABLE) {
      container = document.createElement('variable');
      container.setAttribute('data', input.getText());
    } else {
      if (input.type == Blockly.INPUT_VALUE) {
        valueInputs = true;
        container = document.createElement('value');
      } else if (input.type == Blockly.NEXT_STATEMENT) {
        container = document.createElement('statement');
      }
      var childBlock = input.targetBlock();
      if (childBlock) {
        container.appendChild(Blockly.Xml.blockToDom_(childBlock));
      }
    }
    if (input.label && input.label.getText) {
      container.setAttribute('label', input.label.getText());
    }
    element.appendChild(container);
  }
  if (valueInputs) {
    element.setAttribute('inline', block.inputsInline);
  }
  if (block.collapsed) {
    element.setAttribute('collapsed', true);
  }

  if (block.nextConnection) {
    var container = document.createElement('next');
    var nextBlock = block.nextConnection.targetBlock();
    if (nextBlock) {
      container.appendChild(Blockly.Xml.blockToDom_(nextBlock));
    }
    element.appendChild(container);
  }

  return element;
};

/**
 * Converts a DOM structure into plain text.
 * Currently the text format is fairly ugly: all one line with no whitespace.
 * @param {!Element} dom A tree of XML elements.
 * @return {string} Text representation.
 */
Blockly.Xml.domToText = function(dom) {
  var oSerializer = new XMLSerializer();
  return oSerializer.serializeToString(dom);
};

/**
 * Converts a DOM structure into properly indented text.
 * @param {!Element} dom A tree of XML elements.
 * @return {string} Text representation.
 */
Blockly.Xml.domToPrettyText = function(dom) {
  // This function is not guaranteed to be correct for all XML.
  // But it handles the XML that Blockly generates.
  var line = Blockly.Xml.domToText(dom);
  // Add place every open and close tag on its own line.
  var lines = line.split('<');
  // Indent every line.
  var indent = '';
  for (var x = 1; x < lines.length; x++) {
    var nextChar = lines[x][0];
    if (nextChar == '/') {
      indent = indent.substring(2);
    }
    lines[x] = indent + '<' + lines[x];
    if (nextChar != '/') {
      indent += '  ';
    }
  }
  // Pull simple tags back together.
  // E.g. <foo></foo>
  var text = lines.join('\n');
  text = text.replace(/(<(\w+)[^>]*>[^\n]*)\n *<\/\2>/g, '$1</$2>');
  // Trim leading blank line.
  return text.replace(/^\n/, '');
};

/**
 * Converts plain text into a DOM structure.
 * Throws an error if XML doesn't parse.
 * @param {string} text Text representation.
 * @return {!Element} A tree of XML elements.
 */
Blockly.Xml.textToDom = function(text) {
  var oParser = new DOMParser();
  var dom = oParser.parseFromString(text, 'text/xml');
  // The DOM should have one and only one top-level node, an XML tag.
  if (!dom || !dom.firstChild || dom.firstChild.tagName != 'xml' ||
      dom.firstChild !== dom.lastChild) {
    // Whatever we got back from the parser is not XML.
    throw 'Blockly.Xml.textToDom did not obtain a valid XML tree.';
  }
  return dom.firstChild;
};

/**
 * Decode an XML DOM and create blocks on the workspace.
 * @param {!Object} blockGroup The SVG workspace.
 * @param {!Element} xml XML DOM.
 */
Blockly.Xml.domToWorkspace = function(blockGroup, xml) {
  for (var x = 0, xmlChild; xmlChild = xml.childNodes[x]; x++) {
    if (xmlChild.nodeName && xmlChild.nodeName.toLowerCase() == 'block') {
      var block = Blockly.Xml.domToBlock_(blockGroup, xmlChild);
      var blockX = parseInt(xmlChild.getAttribute('x'), 10);
      var blockY = parseInt(xmlChild.getAttribute('y'), 10);
      if (!isNaN(blockX) && !isNaN(blockY)) {
        block.moveBy(Blockly.RTL ? -blockX : blockX, blockY);
      }
    }
  }
};

/**
 * Decode an XML block tag and create a block (and possibly sub blocks) on the
 * workspace.
 * @param {!Object} blockGroup The SVG workspace.
 * @param {!Element} xmlBlock XML block element.
 * @return {!Blockly.Block} The root block created.
 * @private
 */
Blockly.Xml.domToBlock_ = function(blockGroup, xmlBlock) {
  var prototypeName = xmlBlock.getAttribute('type');
  var block = new Blockly.Block(blockGroup, prototypeName);

  var inline = xmlBlock.getAttribute('inline');
  if (inline) {
    block.setInputsInline(inline == 'true');
  }

  var collapsed = xmlBlock.getAttribute('collapsed');
  if (collapsed) {
    block.setCollapsed(collapsed == 'true');
  }

  var titleIndex = -1;
  var inputIndicies = {};
  inputIndicies[Blockly.LOCAL_VARIABLE] = -1;
  inputIndicies[Blockly.INPUT_VALUE] = -1;
  inputIndicies[Blockly.NEXT_STATEMENT] = -1;
  /**
   * Returns the next input of a given type.
   * Closure: uses inputIndicies and block from external scope.
   * @param {number} type The type of input to search for.
   * @return {Object} The next input or null if none.
   */
  function nextInput(type) {
    var startIndex = inputIndicies[type];
    for (var i = startIndex + 1; i < block.inputList.length; i++) {
      if (block.inputList[i].type == type) {
        inputIndicies[type] = i;
        return block.inputList[i];
      }
    }
    return null;
  }

  for (var x = 0, xmlChild; xmlChild = xmlBlock.childNodes[x]; x++) {
    if (xmlChild.nodeType == 3 && xmlChild.data.match(/^\s*$/)) {
      // Extra whitespace between tags does not concern us.
      continue;
    }
    var blockChild = null;
    var input;

    // Find the first 'real' grandchild node (that isn't whitespace).
    var firstRealGrandchild = null;
    for (var y = 0, grandchildNode; grandchildNode = xmlChild.childNodes[y]; y++) {
      if (grandchildNode.nodeType != 3 || !grandchildNode.data.match(/^\s*$/)) {
        firstRealGrandchild = grandchildNode;
      }
    }

    switch (xmlChild.tagName.toLowerCase()) {
      case 'mutation':
        // Custom data for an advanced block.
        if (block.domToMutation) {
          block.domToMutation(xmlChild);
        }
        break;
      case 'comment':
        block.setCommentText(xmlChild.textContent);
        var pinned = xmlChild.getAttribute('pinned');
        if (pinned) {
          block.comment.setPinned(pinned == 'true');
        }
        var bubbleX = parseInt(xmlChild.getAttribute('x'), 10);
        var bubbleY = parseInt(xmlChild.getAttribute('y'), 10);
        if (!isNaN(bubbleX) && !isNaN(bubbleY)) {
          block.comment.setBubbleLocation(bubbleX, bubbleY, false);
        }
        var bubbleW = parseInt(xmlChild.getAttribute('w'), 10);
        var bubbleH = parseInt(xmlChild.getAttribute('h'), 10);
        if (!isNaN(bubbleW) && !isNaN(bubbleH)) {
          block.comment.setBubbleSize(bubbleW, bubbleH);
        }
        break;
      case 'title':
        block.setTitleText(xmlChild.textContent, ++titleIndex);
        break;
      case 'variable':
        var data = xmlChild.getAttribute('data');
        if (data !== null) {
          input = nextInput(Blockly.LOCAL_VARIABLE);
          if (!input) {
            throw 'Variable input does not exist.';
          }
          input.setText(data);
        }
        break;
      case 'value':
        input = nextInput(Blockly.INPUT_VALUE);
        if (!input) {
          throw 'Value input does not exist.';
        }
        if (firstRealGrandchild && firstRealGrandchild.tagName &&
            firstRealGrandchild.tagName.toLowerCase() == 'block') {
          blockChild = Blockly.Xml.domToBlock_(blockGroup, firstRealGrandchild);
          if (!blockChild.outputConnection) {
            throw 'Child block does not have output value.';
          }
          input.connect(blockChild.outputConnection);
        }
        break;
      case 'statement':
        input = nextInput(Blockly.NEXT_STATEMENT);
        if (!input) {
          throw 'Statement input does not exist.';
        }
        if (firstRealGrandchild && firstRealGrandchild.tagName &&
            firstRealGrandchild.tagName.toLowerCase() == 'block') {
          blockChild = Blockly.Xml.domToBlock_(blockGroup, firstRealGrandchild);
          if (!blockChild.previousConnection) {
            throw 'Child block does not have previous statement.';
          }
          input.connect(blockChild.previousConnection);
        }
        break;
      case 'next':
        if (firstRealGrandchild && firstRealGrandchild.tagName &&
            firstRealGrandchild.tagName.toLowerCase() == 'block') {
          if (!block.nextConnection) {
            throw 'Next statement does not exist.';
          } else if (block.nextConnection.targetConnection) {
            // This could happen if there is more than one XML 'next' tag.
            throw 'Next statement is already connected.';
          }
          blockChild = Blockly.Xml.domToBlock_(blockGroup, firstRealGrandchild);
          if (!blockChild.previousConnection) {
            throw 'Next block does not have previous statement.';
          }
          block.nextConnection.connect(blockChild.previousConnection);
        }
        break;
      default:
        // Unknown tag; ignore.  Same principle as HTML parsers.
    }
    var labelText = xmlChild.getAttribute('label');
    if (labelText !== null && input && input.label && input.label.setText) {
      input.label.setText(labelText);
    }
  }
  block.render();
  return block;
};

/**
 * Find the first 'real' child of a node, skipping whitespace text nodes.
 * Return true if that child is of the the specified type (case insensitive).
 * @param {!Node} parentNode The parent node.
 * @param {string} tagName The node type to check for.
 * @return {boolean} True if the first real child is the specified type.
 * @private
 */
Blockly.Xml.isFirstRealChild_ = function(parentNode, tagName) {
  for (var x = 0, childNode; childNode = parentNode.childNodes[x]; x++) {
    if (childNode.nodeType != 3 || !childNode.data.match(/^\s*$/)) {
      return childNode.tagName && childNode.tagName.toLowerCase() == tagName;
    }
  }
  return false;
};
<|endoftext|>


<commit_before>"use strict";

var Promise         = require('bluebird')
  , winston         = require('winston')
  , _               = require('lodash')
  , os              = require('os')
  , uuid            = require('node-uuid')
  , config          = require('config-url')
  , rp              = require('request-promise')
  , request         = require('request')
  , urljoin         = require('url-join')
  , retry           = require('bluebird-retry')
  // , net             = require('net')
  , ip              = require('ip')
  , Request         = require('./Request')
  ;

class Agent {
  constructor(pool) {
    this.pool = pool;

    if (!this.pool) {
      throw new Error('"type" param not defined or recognized');
    }

    this.group = config.get('agent.group-id');
    this.id = uuid.v4();

    if (!this.group) {
      throw new Error('config error: "agent.group-id" is required for the agent to connect to the relay. make sure that your group id is unique uuid.');
    }
  }

  initialize(cb) {
    return this.pool.initialize().asCallback(cb);
  }

  listen() {
    winston.info('agent connecting to', config.getUrl('relay'));

    let url = config.getUrl('relay');

    this.socket = require('socket.io-client')(url);

    this.socket.on('connect', () => {
      winston.info('connected');
      this.start_heartbeat();
    });

    this.socket.on('disconnect', () =>{
      this.end_heartbeat();
      winston.info('disconnected');
    });

    const http = require('http');

    let proxy = http.createServer((req, res) => {
      // todo [akamel] we only parse this to get the request id out... seems we should be able to bypass it
      let r = new Request(JSON.parse(req.headers['__metadata']));
      this.pool
            .run(r)
            .then((worker) => {
              return Promise.fromCallback((cb) => {
                worker.on('ready', (err, data, container) => {
                  let port = data.NetworkSettings.Ports['80/tcp'][0].HostPort;

                  // todo [akamel] rename doc to metadata
                  let headers = {
                      '__metadata' : JSON.stringify(r.doc)
                  };

                  res.setHeader('RunOn-Agent', `${os.hostname()} (${ip.address()})`);

                  // todo [akamel] consider moving these headers to worker?
                  let pragma = _.get(r.doc, 'manual.pragma');
                  if (pragma) {
                    res.setHeader('Manual-Pragma', JSON.stringify(pragma));
                  }

                  let time = process.hrtime();
                  let count = 0;
                  let url = `http://localhost:${port}`;
                  retry(() => {
                      count++;
                      return rp.get(url);
                    }, { interval : 10, timeout : 5000, max_tries : -1, backoff : 2, max_interval : 60 })
                    .then(() =>
                      Promise
                        .fromCallback((cb) => {
                          console.log('going to:', urljoin(url, req.url))
                          req
                            .pipe(request({ url : urljoin(url, req.url), headers : headers }))
                            .on('response', (res) => {
                              let content_type = _.get(r.doc, 'manual.output["content-type"]');
                              if (content_type) {
                                res.headers['content-type'] = content_type;
                              }
                            })
                            .on('error', (err) => {
                              cb(new Error('request failed: ' + url));
                            })
                            .pipe(res)
                            .on('error', (err) => {
                              cb(new Error('response failed'));
                            });

                          res.on('finish', cb);
                        })
                    )
                    .then(() => {
                      let diff = process.hrtime(time);
                      winston.info(`needed ${count} retries to connect to container, in ${(diff[0] * 1e9 + diff[1]) / 1e6} seconds`);
                    })
                    .asCallback(cb);
                });
              });
            })
            .catch((err) => {
              res.statusCode = 500;
              res.write(err.toString());
              res.end();
            });
      // todo [akamel] handle other worker events here
    }).listen(config.getUrlObject('agent').port);
    // server.on('clientError', (err, socket) => {
    //   socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
    // });
  }

  start_heartbeat() {
    this.end_heartbeat();

    var ping = () => {
      var data = {
          name                : os.hostname()
          // todo [akamel] use machine name or url in production [agent specific]
        , run_url             : config.getUrl('agent')
        , id                  : this.id
        , group               : this.group
        , uptime              : process.uptime()
        , totalmem            : os.totalmem()
        , freemem             : os.freemem()
        , loadavg             : os.loadavg()
        , cpus                : os.cpus()
        // , workers             : this.pool.info()
      };

      this.socket.emit('/ping', data);
    };

    this.heartbeat_timer_token = setInterval(ping, 10 * 1000);
    ping();
  }

  end_heartbeat() {
    if (this.heartbeat_timer_token) {
      clearInterval(this.heartbeat_timer_token);
    }
  }
}

module.exports = Agent;<commit_msg>move setting of headers to same place<commit_after>"use strict";

var Promise         = require('bluebird')
  , winston         = require('winston')
  , _               = require('lodash')
  , os              = require('os')
  , uuid            = require('node-uuid')
  , config          = require('config-url')
  , rp              = require('request-promise')
  , request         = require('request')
  , urljoin         = require('url-join')
  , retry           = require('bluebird-retry')
  // , net             = require('net')
  , ip              = require('ip')
  , Request         = require('./Request')
  ;

class Agent {
  constructor(pool) {
    this.pool = pool;

    if (!this.pool) {
      throw new Error('"type" param not defined or recognized');
    }

    this.group = config.get('agent.group-id');
    this.id = uuid.v4();

    if (!this.group) {
      throw new Error('config error: "agent.group-id" is required for the agent to connect to the relay. make sure that your group id is unique uuid.');
    }
  }

  initialize(cb) {
    return this.pool.initialize().asCallback(cb);
  }

  listen() {
    winston.info('agent connecting to', config.getUrl('relay'));

    let url = config.getUrl('relay');

    this.socket = require('socket.io-client')(url);

    this.socket.on('connect', () => {
      winston.info('connected');
      this.start_heartbeat();
    });

    this.socket.on('disconnect', () =>{
      this.end_heartbeat();
      winston.info('disconnected');
    });

    const http = require('http');

    let proxy = http.createServer((req, res) => {
      // todo [akamel] we only parse this to get the request id out... seems we should be able to bypass it
      let r = new Request(JSON.parse(req.headers['__metadata']));
      this.pool
            .run(r)
            .then((worker) => {
              return Promise.fromCallback((cb) => {
                worker.on('ready', (err, data, container) => {
                  let port = data.NetworkSettings.Ports['80/tcp'][0].HostPort;

                  // todo [akamel] rename doc to metadata
                  let headers = {
                      '__metadata' : JSON.stringify(r.doc)
                  };

                  let time = process.hrtime();
                  let count = 0;
                  let url = `http://localhost:${port}`;
                  retry(() => {
                      count++;
                      return rp.get(url);
                    }, { interval : 10, timeout : 5000, max_tries : -1, backoff : 2, max_interval : 60 })
                    .then(() =>
                      Promise
                        .fromCallback((cb) => {
                          req
                            .pipe(request({ url : urljoin(url, req.url), headers : headers }))
                            .on('response', (res) => {
                              let content_type = _.get(r.doc, 'manual.output["content-type"]');
                              if (content_type) {
                                res.headers['content-type'] = content_type;
                              }

                              res.headers['RunOn-Agent'] = `${os.hostname()} (${ip.address()})`;

                              // todo [akamel] consider moving these headers to worker?
                              let pragma = _.get(r.doc, 'manual.pragma');
                              if (pragma) {
                                res.headers['Manual-Pragma'] = JSON.stringify(pragma);
                              }
                            })
                            .on('error', (err) => {
                              cb(new Error('request failed: ' + url));
                            })
                            .pipe(res)
                            .on('error', (err) => {
                              cb(new Error('response failed'));
                            });

                          res.on('finish', cb);
                        })
                    )
                    .then(() => {
                      let diff = process.hrtime(time);
                      winston.info(`needed ${count} retries to connect to container, in ${(diff[0] * 1e9 + diff[1]) / 1e6} seconds`);
                    })
                    .asCallback(cb);
                });
              });
            })
            .catch((err) => {
              res.statusCode = 500;
              res.write(err.toString());
              res.end();
            });
      // todo [akamel] handle other worker events here
    }).listen(config.getUrlObject('agent').port);
    // server.on('clientError', (err, socket) => {
    //   socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
    // });
  }

  start_heartbeat() {
    this.end_heartbeat();

    var ping = () => {
      var data = {
          name                : os.hostname()
          // todo [akamel] use machine name or url in production [agent specific]
        , run_url             : config.getUrl('agent')
        , id                  : this.id
        , group               : this.group
        , uptime              : process.uptime()
        , totalmem            : os.totalmem()
        , freemem             : os.freemem()
        , loadavg             : os.loadavg()
        , cpus                : os.cpus()
        // , workers             : this.pool.info()
      };

      this.socket.emit('/ping', data);
    };

    this.heartbeat_timer_token = setInterval(ping, 10 * 1000);
    ping();
  }

  end_heartbeat() {
    if (this.heartbeat_timer_token) {
      clearInterval(this.heartbeat_timer_token);
    }
  }
}

module.exports = Agent;<|endoftext|>


<commit_before><commit_msg>small refactoring<commit_after><|endoftext|>


<commit_before>var windowElements = document.getElementsByTagName("*");
var DEFAULT = true, CUSTOM = false;
var defaultDirectives = {
  'abbr' : 'abbr',
  'accept': 'accept',
  'accesskey': 'accesskey',
  'action': 'action',
  'align': 'align',
  'alt':'alt',
  'background':'background',
  'bgcolor': 'bgcolor',
  'border': 'border',
  'cellpadding': 'cellpadding',
  'char': 'char',
  'charoff': 'charoff',
  'charset': 'charset',
  'checked': 'checked',
  'cite': 'cite',
  'class': 'class',
  'classid': 'classid',
  'code': 'code',
  'codebase': 'codebase',
  'color': 'color',
  'cols': 'cols',
  'colspan': 'colspan',
  'content': 'content',
  'data': 'data',
  'defer': 'defer',
  'dir': 'dir',
  'face': 'face',
  'for': 'for',
  'frame': 'frame',
  'frameborder': 'frameborder',
  'headers': 'headers',
  'height': 'height',
  'href': 'href',
  'id': 'id',
  'label': 'label',
  'lang': 'lang',
  'language': 'language',
  'link': 'link',
  'marginheight': 'marginheight',
  'marginwidth': 'marginwidth',
  'maxlength':'maxlength',
  'media': 'media',
  'multiple': 'multiple',
  'name': 'name',
  'object': 'object',
  'onblur': 'onblur',
  'onchange': 'onchange',
  'onclick': 'onclick',
  'onfocus': 'onfocus',
  'onkeydown':'onkeydown',
  'onkeypress': 'onkeypress',
  'onkeyup': 'onkeyup',
  'onload': 'onload',
  'onmousedown': 'onmousedown',
  'onmousemove': 'onmousemove',
  'onmouseout': 'onmouseout',
  'onmouseover': 'onmouseover',
  'onmouseup': 'onmouseup',
  'onreset': 'onreset',
  'onselect': 'onselect',
  'onsubmit': 'onsubmit',
  'readonly': 'readonly',
  'rel': 'rel',
  'rev': 'rev',
  'rows': 'rows',
  'rowspan': 'rowspan',
  'size': 'size',
  'span': 'span',
  'src': 'src',
  'start': 'start',
  'style': 'style',
  'text': 'text',
  'target': 'target',
  'title': 'title',
  'type': 'type',
  'value': 'value',
  'width': 'width',
  'ng-app': 'ng-app',
  'ng-bind': 'ng-bind',
  'ng-bindhtml': 'ng-bindhtml',
  'ng-bindtemplate': 'ng-bindtemplate',
  'ng-blur': 'ng-blur',
  'ng-change': 'ng-change',
  'ng-checked': 'ng-checked',
  'ng-class': 'ng-class',
  'ng-classeven': 'ng-classeven',
  'ng-classodd': 'ng-classodd',
  'ng-click': 'ng-click',
  'ng-cloak': 'ng-cloak',
  'ng-controller': 'ng-controller',
  'ng-copy': 'ng-copy',
  'ng-csp': 'ng-csp',
  'ng-cut': 'ng-cut',
  'ng-dblclick': 'ng-dblclick',
  'ng-disabled': 'ng-disabled',
  'ng-focus': 'ng-focus',
  'ng-form': 'ng-form',
  'ng-hide': 'ng-hide',
  'ng-href': 'ng-href',
  'ng-if': 'ng-if',
  'ng-include': 'ng-include',
  'ng-init': 'ng-init',
  'ng-keydown': 'ng-keydown',
  'ng-keypress': 'ng-keypress',
  'ng-keyup': 'ng-keyup',
  'ng-list': 'ng-list',
  'ng-model': 'ng-model',
  'ng-modeloptions': 'ng-modeloptions',
  'ng-mousedown': 'ng-mousedown',
  'ng-mouseenter': 'ng-mouseenter',
  'ng-mouseleave': 'ng-mouseleave',
  'ng-mousemove': 'ng-mousemove',
  'ng-mouseover': 'ng-mouseover',
  'ng-mouseup': 'ng-mouseup',
  'ng-nonbindable': 'ng-nonbindable',
  'ng-open': 'ng-open',
  'ng-paste': 'ng-paste',
  'ng-pluralize': 'ng-pluralize',
  'ng-readonly': 'ng-readonly',
  'ng-repeat': 'ng-repeat',
  'ng-selected': 'ng-selected',
  'ng-show': 'ng-show',
  'ng-src': 'ng-src',
  'ng-srcset': 'ng-srcset',
  'ng-style': 'ng-style',
  'ng-submit': 'ng-submit',
  'ng-switch': 'ng-switch',
  'ng-transclude': 'ng-transclude',
  'ng-value': 'ng-value'};
var customDirectives = {'ha-breadcrumbs':'ha-breadcrumbs'}
var failedElements = [];
var correctionsFound = [];

var checkDefaultDirs = function() {
  for(var elesIndex = 0; elesIndex < windowElements.length; elesIndex++) {
    var attrsOfEle = windowElements[elesIndex].attributes;
    if(attrsOfEle.length){
      failedAttributes = getFailedAttributes(attrsOfEle);
      if(failedAttributes.length){
        failedEle = {
          htmlComponent:windowElements[elesIndex],
          failedAttributes: failedAttributes
        };
        failedElements.push(failedEle);
      }
    }
  }
}
var getFailedAttributes = function(attributes) {
  var failedAttributes = [];
  for(var attrIndex = 0; attrIndex < attributes.length; attrIndex++) {
    var attrName = attributes[attrIndex].nodeName;
    var inDefault = attrOfEleExsistIn(DEFAULT, attrName);
    var inCustom = attrOfEleExsistIn(CUSTOM, attrName);
    if(!inDefault && !inCustom) {
      var failedAttr = {
        failedAttr: attrName,
        correction: ''
      }
      failedAttributes.push(failedAttr);
    }
  }
  return failedAttributes;
}
var getSuggestions = function() {
  for(var failedEleIndex = 0; failedEleIndex < failedElements.length; failedEleIndex++) {
    var cDirMatch = findClosestMatchIn(CUSTOM, failedEleIndex);
    var dDirMatch = findClosestMatchIn(DEFAULT, failedEleIndex);
    var match;
    for(var index = 0; index < cDirMatch.length; index++) {
      var minLevDist = Math.min(cDirMatch[index].levDist, dDirMatch[index].levDist);
      var match = (minLevDist == cDirMatch[index].levDist)? cDirMatch : dDirMatch;
    }
    var toPush = {htmlComponent: failedElements[failedEleIndex], results: match};
    correctionsFound.push(toPush);
  }
}
var findClosestMatchIn = function(isDefault, currentEle) {
  var toSearch = (isDefault)? defaultDirectives : customDirectives;
  var failedEleAttrs = failedElements[currentEle].failedAttributes;
  var correctionsToSend = [];
  for(var failedAttrIndex = 0; failedAttrIndex < failedEleAttrs.length; failedAttrIndex++) {
    var dirFail = failedEleAttrs[failedAttrIndex].failedAttr;
    var min_levDist = Number.MAX_SAFE_INTEGER;
    for(var attr in toSearch) {
      var dirCust = toSearch[attr];
      if(Math.abs(dirFail.length-dirCust.length) < 3) {
        var currentlevDist = levenshteinDistance(dirFail,dirCust);
        var closestMatch = (min_levDist > currentlevDist)? dirCust : closestMatch;
        var min_levDist = (min_levDist > currentlevDist)? currentlevDist : min_levDist;
        console.log("New LD: "+min_levDist+"  New Match: "+closestMatch);
      }
    }
    correctionsToSend.push({
      error: dirFail,
      match:closestMatch,
      levDist:min_levDist
    });
  }
  return correctionsToSend;
}
var attrOfEleExsistIn = function(isDefault,attribute){
  //for(var attrIndex = 0; attrIndex < attribute.length; attrIndex++) {
    //attrName = attribute[attrIndex].nodeName;
    var currentAttr = (isDefault)? defaultDirectives[attribute]:
      customDirectives[attribute];
    if(currentAttr) {
      return true;
    }
  //}
  return false;
}
var levenshteinDistance = function(s, t) {
    var d = [];
    var n = s.length;
    var m = t.length;

    if (n == 0) return m;
    if (m == 0) return n;

    for (var i = n; i >= 0; i--) d[i] = [];
    for (var i = n; i >= 0; i--) d[i][0] = i;
    for (var j = m; j >= 0; j--) d[0][j] = j;
    for (var i = 1; i <= n; i++) {
        var s_i = s.charAt(i - 1);

        for (var j = 1; j <= m; j++) {
            if (i == j && d[i][j] > 4) return n;
            var t_j = t.charAt(j - 1);
            var cost = (s_i == t_j) ? 0 : 1;
            var mi = d[i - 1][j] + 1;
            var b = d[i][j - 1] + 1;
            var c = d[i - 1][j - 1] + cost;
            if (b < mi) mi = b;
            if (c < mi) mi = c;
            d[i][j] = mi;
            if (i > 1 && j > 1 && s_i == t.charAt(j - 2) && s.charAt(i - 2) == t_j) {
                d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + cost);
            }
        }
    }
    return d[n][m];
}

checkDefaultDirs();
getSuggestions();
console.log("windowElements")
console.log(windowElements);
console.log("failedElements")
console.log(failedElements);
console.log("correctionsFound")
console.log(correctionsFound);

<commit_msg>feat(dd-app): display suggestion results appropriately<commit_after>var windowElements = document.getElementsByTagName("*");
var DEFAULT = true, CUSTOM = false;
var defaultDirectives = {
  'abbr' : 'abbr',
  'accept': 'accept',
  'accesskey': 'accesskey',
  'action': 'action',
  'align': 'align',
  'alt':'alt',
  'background':'background',
  'bgcolor': 'bgcolor',
  'border': 'border',
  'cellpadding': 'cellpadding',
  'char': 'char',
  'charoff': 'charoff',
  'charset': 'charset',
  'checked': 'checked',
  'cite': 'cite',
  'class': 'class',
  'classid': 'classid',
  'code': 'code',
  'codebase': 'codebase',
  'color': 'color',
  'cols': 'cols',
  'colspan': 'colspan',
  'content': 'content',
  'data': 'data',
  'defer': 'defer',
  'dir': 'dir',
  'face': 'face',
  'for': 'for',
  'frame': 'frame',
  'frameborder': 'frameborder',
  'headers': 'headers',
  'height': 'height',
  'href': 'href',
  'id': 'id',
  'label': 'label',
  'lang': 'lang',
  'language': 'language',
  'link': 'link',
  'marginheight': 'marginheight',
  'marginwidth': 'marginwidth',
  'maxlength':'maxlength',
  'media': 'media',
  'multiple': 'multiple',
  'name': 'name',
  'object': 'object',
  'onblur': 'onblur',
  'onchange': 'onchange',
  'onclick': 'onclick',
  'onfocus': 'onfocus',
  'onkeydown':'onkeydown',
  'onkeypress': 'onkeypress',
  'onkeyup': 'onkeyup',
  'onload': 'onload',
  'onmousedown': 'onmousedown',
  'onmousemove': 'onmousemove',
  'onmouseout': 'onmouseout',
  'onmouseover': 'onmouseover',
  'onmouseup': 'onmouseup',
  'onreset': 'onreset',
  'onselect': 'onselect',
  'onsubmit': 'onsubmit',
  'readonly': 'readonly',
  'rel': 'rel',
  'rev': 'rev',
  'rows': 'rows',
  'rowspan': 'rowspan',
  'size': 'size',
  'span': 'span',
  'src': 'src',
  'start': 'start',
  'style': 'style',
  'text': 'text',
  'target': 'target',
  'title': 'title',
  'type': 'type',
  'value': 'value',
  'width': 'width',
  'ng-app': 'ng-app',
  'ng-bind': 'ng-bind',
  'ng-bindhtml': 'ng-bindhtml',
  'ng-bindtemplate': 'ng-bindtemplate',
  'ng-blur': 'ng-blur',
  'ng-change': 'ng-change',
  'ng-checked': 'ng-checked',
  'ng-class': 'ng-class',
  'ng-classeven': 'ng-classeven',
  'ng-classodd': 'ng-classodd',
  'ng-click': 'ng-click',
  'ng-cloak': 'ng-cloak',
  'ng-controller': 'ng-controller',
  'ng-copy': 'ng-copy',
  'ng-csp': 'ng-csp',
  'ng-cut': 'ng-cut',
  'ng-dblclick': 'ng-dblclick',
  'ng-disabled': 'ng-disabled',
  'ng-focus': 'ng-focus',
  'ng-form': 'ng-form',
  'ng-hide': 'ng-hide',
  'ng-href': 'ng-href',
  'ng-if': 'ng-if',
  'ng-include': 'ng-include',
  'ng-init': 'ng-init',
  'ng-keydown': 'ng-keydown',
  'ng-keypress': 'ng-keypress',
  'ng-keyup': 'ng-keyup',
  'ng-list': 'ng-list',
  'ng-model': 'ng-model',
  'ng-modeloptions': 'ng-modeloptions',
  'ng-mousedown': 'ng-mousedown',
  'ng-mouseenter': 'ng-mouseenter',
  'ng-mouseleave': 'ng-mouseleave',
  'ng-mousemove': 'ng-mousemove',
  'ng-mouseover': 'ng-mouseover',
  'ng-mouseup': 'ng-mouseup',
  'ng-nonbindable': 'ng-nonbindable',
  'ng-open': 'ng-open',
  'ng-paste': 'ng-paste',
  'ng-pluralize': 'ng-pluralize',
  'ng-readonly': 'ng-readonly',
  'ng-repeat': 'ng-repeat',
  'ng-selected': 'ng-selected',
  'ng-show': 'ng-show',
  'ng-src': 'ng-src',
  'ng-srcset': 'ng-srcset',
  'ng-style': 'ng-style',
  'ng-submit': 'ng-submit',
  'ng-switch': 'ng-switch',
  'ng-transclude': 'ng-transclude',
  'ng-value': 'ng-value'};
var customDirectives = {'ha-breadcrumbs':'ha-breadcrumbs'}
var failedElements = [];
var correctionsFound = [];

var checkDefaultDirs = function() {
  for(var elesIndex = 0; elesIndex < windowElements.length; elesIndex++) {
    var attrsOfEle = windowElements[elesIndex].attributes;
    if(attrsOfEle.length){
      failedAttributes = getFailedAttributes(attrsOfEle);
      if(failedAttributes.length){
        failedEle = {
          ele: windowElements[elesIndex],
          failedAttributes: failedAttributes
        };
        failedElements.push(failedEle);
      }
    }
  }
}
var getSuggestions = function() {
  for(var failedEleIndex = 0; failedEleIndex < failedElements.length; failedEleIndex++) {
    var cDirMatch = findClosestMatchIn(CUSTOM, failedEleIndex);
    var dDirMatch = findClosestMatchIn(DEFAULT, failedEleIndex);
    var match;
    for(var index = 0; index < cDirMatch.length; index++) {
      var minLevDist = Math.min(cDirMatch[index].levDist, dDirMatch[index].levDist);
      var match = (minLevDist == cDirMatch[index].levDist)? cDirMatch : dDirMatch;
    }
    var toPush = {domElement: failedElements[failedEleIndex], results: match};
    correctionsFound.push(toPush);
  }
}
var displayResults = function() {
  correctionsFound.forEach(function(obj) {ß
    obj.results.forEach(function(attr) {
      id = (obj.domElement.ele.id) ? 'with id: #'+obj.domElement.ele.id : '';
      type = obj.domElement.ele.nodeName;
      var message = 'There was an error in '+type+' element '+id+
      '. Found incorrect attribute "'+attr.error+'" try "'+attr.match+'".';
      console.log(message);
    })
  })
}
var getFailedAttributes = function(attributes) {
  var failedAttributes = [];
  for(var attrIndex = 0; attrIndex < attributes.length; attrIndex++) {
    var attrName = attributes[attrIndex].nodeName;
    var inDefault = attrOfEleExsistIn(DEFAULT, attrName);
    var inCustom = attrOfEleExsistIn(CUSTOM, attrName);
    if(!inDefault && !inCustom) {
      var failedAttr = {
        failedAttr: attrName,
        correction: ''
      }
      failedAttributes.push(failedAttr);
    }
  }
  return failedAttributes;
}
var findClosestMatchIn = function(isDefault, currentEle) {
  var toSearch = (isDefault)? defaultDirectives : customDirectives;
  var failedEleAttrs = failedElements[currentEle].failedAttributes;
  var correctionsToSend = [];
  for(var failedAttrIndex = 0; failedAttrIndex < failedEleAttrs.length; failedAttrIndex++) {
    var dirFail = failedEleAttrs[failedAttrIndex].failedAttr;
    var min_levDist = Number.MAX_SAFE_INTEGER;
    for(var attr in toSearch) {
      var dirCust = toSearch[attr];
      if(Math.abs(dirFail.length-dirCust.length) < 3) {
        var currentlevDist = levenshteinDistance(dirFail,dirCust);
        var closestMatch = (min_levDist > currentlevDist)? dirCust : closestMatch;
        var min_levDist = (min_levDist > currentlevDist)? currentlevDist : min_levDist;
      }
    }
    correctionsToSend.push({
      error: dirFail,
      match:closestMatch,
      levDist:min_levDist
    });
  }
  return correctionsToSend;
}
var attrOfEleExsistIn = function(isDefault,attribute){
  var currentAttr = (isDefault)? defaultDirectives[attribute]:
    customDirectives[attribute];
  if(currentAttr) {
    return true;
  }
  return false;
}
var levenshteinDistance = function(s, t) {
    var d = [];
    var n = s.length;
    var m = t.length;

    if (n == 0) return m;
    if (m == 0) return n;

    for (var i = n; i >= 0; i--) d[i] = [];
    for (var i = n; i >= 0; i--) d[i][0] = i;
    for (var j = m; j >= 0; j--) d[0][j] = j;
    for (var i = 1; i <= n; i++) {
        var s_i = s.charAt(i - 1);

        for (var j = 1; j <= m; j++) {
            if (i == j && d[i][j] > 4) return n;
            var t_j = t.charAt(j - 1);
            var cost = (s_i == t_j) ? 0 : 1;
            var mi = d[i - 1][j] + 1;
            var b = d[i][j - 1] + 1;
            var c = d[i - 1][j - 1] + cost;
            if (b < mi) mi = b;
            if (c < mi) mi = c;
            d[i][j] = mi;
            if (i > 1 && j > 1 && s_i == t.charAt(j - 2) && s.charAt(i - 2) == t_j) {
                d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + cost);
            }
        }
    }
    return d[n][m];
}

checkDefaultDirs();
getSuggestions();
displayResults();
<|endoftext|>


<commit_before>'use strict';

// Load requirements
const assign = require('deep-assign');

// Load libraries
const logger = require('../log');

// Variables
let queueCache = [];

// Send back the function
module.exports = function(task) {
  return new Promise((resolve, reject) => {

    // Variables
    let added = [],
        promises = [],
        options = {};

    // Exit without a task
    if ( ! task || typeof task !== 'object' ) {
      return reject('Missing or invalid task argument');
    }

    // Loop through and assign the available jobs to the queue
    task.jobs.forEach((job) => {

      // Skip if already in queue
      if ( queueCache.includes(job.file) ) {
        return false;
      }

      // Add to cache to stop additional runs
      queueCache.push(job.file);
      this.total = queueCache.length;

      // Track files being added with this task
      added.push(job.basename);

      // Merge options for this task
      job.options = assign(options, job.options);

      // Add to the queue
      promises.push(this.items.add(() => {

        // Update queue length
        this.length = ( this.items.getQueueLength() + this.items.getPendingLength() );

        // Update current task position
        this.current++;

        // Update overall counter
        task.overall = {total: this.total, current: this.current};

        // DEBUG
        logger.info('Starting task {cyan:%s} of {green:%s}', this.current, this.total);

        // Queue data test
        if ( this.items.queue[0] ) {
          let next = this.items.queue[0].job;
          logger.info('Next task {green:' + next.basename + '}');
        }

        // Send to conversion for processing
        return require('../conversion').run(job);
      }));

      // Add data to queue for lookup later
      this.items.queue[( this.items.queue.length - 1)].job = job;
    });

    // DEBUG
    logger.info('Added:\n  {green:' + added.join('\n  ').trim() + '}');

    // Unpause the queue
    this.items.maxPendingPromises = 1;
    this.items._dequeue();

    // Wait for this task to complete to resolve
    Promise.all(promises).then((result) => {
      return resolve(result);
    }).catch((err) => {
      return reject(err);
    });
  });
};
<commit_msg>Drop next task output from queue<commit_after>'use strict';

// Load requirements
const assign = require('deep-assign');

// Load libraries
const logger = require('../log');

// Variables
let queueCache = [];

// Send back the function
module.exports = function(task) {
  return new Promise((resolve, reject) => {

    // Variables
    let added = [],
        promises = [],
        options = {};

    // Exit without a task
    if ( ! task || typeof task !== 'object' ) {
      return reject('Missing or invalid task argument');
    }

    // Loop through and assign the available jobs to the queue
    task.jobs.forEach((job) => {

      // Skip if already in queue
      if ( queueCache.includes(job.file) ) {
        return false;
      }

      // Add to cache to stop additional runs
      queueCache.push(job.file);
      this.total = queueCache.length;

      // Track files being added with this task
      added.push(job.basename);

      // Merge options for this task
      job.options = assign(options, job.options);

      // Add to the queue
      promises.push(this.items.add(() => {

        // Update queue length
        this.length = ( this.items.getQueueLength() + this.items.getPendingLength() );

        // Update current task position
        this.current++;

        // Update overall counter
        task.overall = {total: this.total, current: this.current};

        // DEBUG
        logger.info('Starting task {cyan:%s} of {green:%s}', this.current, this.total);

        // Queue data test
        // Not needed, just keeping it for reference later
        /*if ( this.items.queue[0] ) {
          let next = this.items.queue[0].job;
          logger.info('Next task {green:' + next.basename + '}');
        }*/

        // Send to conversion for processing
        return require('../conversion').run(job);
      }));

      // Add data to queue for lookup later
      this.items.queue[( this.items.queue.length - 1)].job = job;
    });

    // DEBUG
    logger.info('Added:\n  {green:' + added.join('\n  ').trim() + '}');

    // Unpause the queue
    this.items.maxPendingPromises = 1;
    this.items._dequeue();

    // Wait for this task to complete to resolve
    Promise.all(promises).then((result) => {
      return resolve(result);
    }).catch((err) => {
      return reject(err);
    });
  });
};
<|endoftext|>


<commit_before>"use strict";

var environmentsApp = soajsApp.components;
environmentsApp.controller('analyticsCtrl', ['$scope', '$cookies', '$timeout', 'hacloudSrv', 'deploySrv', 'injectFiles', function ($scope, $cookies, $timeout, hacloudSrv, deploySrv, injectFiles) {
	$scope.$parent.isUserLoggedIn();

	$scope.access = {};
	constructModulePermissions($scope, $scope.access, environmentsConfig.permissions);

    $scope.analytics = {
        activated: false
    };

    $scope.checkAnalytics = function () {
        getSendDataFromServer($scope, ngDataApi, {
            method: 'get',
            routeName: '/dashboard/analytics/check',
            params: {
                'env': $scope.envCode
            }
        }, function (error, response) {
            if (error) {
                $scope.displayAlert('danger', error.message);
            }
            else {
                $scope.analytics.activated = response.data;
            }
        });
    };

    $scope.activateAnalytics = function () {
        getSendDataFromServer($scope, ngDataApi, {
            method: 'send',
            routeName: '/dashboard/analytics/activate',
            data: {
                'env': $scope.envCode
            }
        }, function (error, response) {
            if (error) {
                $scope.displayAlert('danger', error.message);
            }
            else {
                $scope.analytics.activated = true;
                $scope.displayAlert('success', 'Analytics for ' + $scope.envCode + ' has been activated');
            }
        });
    };

	// if ($scope.access.listNodes) {
		injectFiles.injectCss('modules/dashboard/environments/environments.css');
		$scope.envCode = $cookies.getObject("myEnv").code;

		$scope.checkAnalytics();
	// }
}]);
<commit_msg>SOAJ-364: UI bug fix<commit_after>"use strict";

var environmentsApp = soajsApp.components;
environmentsApp.controller('analyticsCtrl', ['$scope', '$cookies', '$timeout', 'ngDataApi', 'injectFiles', function ($scope, $cookies, $timeout, ngDataApi, injectFiles) {
	$scope.$parent.isUserLoggedIn();

	$scope.access = {};
	constructModulePermissions($scope, $scope.access, environmentsConfig.permissions);

    $scope.analytics = {
        activated: false
    };

    $scope.checkAnalytics = function () {
        getSendDataFromServer($scope, ngDataApi, {
            method: 'get',
            routeName: '/dashboard/analytics/check',
            params: {
                'env': $scope.envCode
            }
        }, function (error, response) {
            if (error) {
                $scope.displayAlert('danger', error.message);
            }
            else {
                $scope.analytics.activated = response.data;
            }
        });
    };

    $scope.activateAnalytics = function () {
        getSendDataFromServer($scope, ngDataApi, {
            method: 'send',
            routeName: '/dashboard/analytics/activate',
            data: {
                'env': $scope.envCode
            }
        }, function (error, response) {
            if (error) {
                $scope.displayAlert('danger', error.message);
            }
            else {
                $scope.analytics.activated = true;
                $scope.displayAlert('success', 'Analytics for ' + $scope.envCode + ' has been activated');
            }
        });
    };

	// if ($scope.access.listNodes) {
		injectFiles.injectCss('modules/dashboard/environments/environments.css');
		$scope.envCode = $cookies.getObject("myEnv").code;

		$scope.checkAnalytics();
	// }
}]);
<|endoftext|>


<commit_before><commit_msg>CI: Work around some problems comparing generated HTML as Firefox and Chome insert attributes in a different order<commit_after><|endoftext|>