<commit_before>/*
* Colorwheel
* Copyright (c) 2010 John Weir (http://famedriver.com)
* Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
*
* requires jQuery & Raphael
*   http://jquery.com http://raphaeljs.com
*
* see http://jweir.github.com/colorwheel for Usage
*
*/

Raphael.colorwheel = function(target, color_wheel_size, no_segments){
  var canvas,
      current_color,
      size,
      segments = no_segments || 60,
      bs_square = {},
      hue_ring = {},
      tri_size,
      cursor = {},
      drag_target,
      input_target,
      center,
      parent,
      change_callback,
      drag_callbacks = [function(){}, function(){}],
      offset,
      padding = 2,
      sdim; // holds the dimensions for the saturation square

  function point(x, y){ return {x:x, y:y}}
  function radians(a){ return a * (Math.PI/180) }

  function angle(x,y){
    var q = x > 0 ? 0 : 180;
    return q+Math.atan((0 - y)/(0 - x))*180/(Math.PI)
  }

  function create(target, color_wheel_size){
    size     = color_wheel_size;
    tri_size = size/20;
    center   = size/2;
    parent   = $(target);
    canvas   = Raphael(parent[0],size, size);
    canvas.safari();

    create_bs_square();
    create_hue_ring();
    hue_ring.cursor = cursor_create(tri_size);
    bs_square.cursor = cursor_create(tri_size*0.5);
    events_setup();
    parent.css({height:size+"px", width:size+"px"});
    disable_select(parent);
    return public_methods();
  }

  function disable_select(target){
    $(target).css({"unselectable": "on","-moz-user-select": "none","-webkit-user-select": "none"});
  }

  function public_methods(){
    return {
      input: input,
      onchange: onchange,
      ondrag : ondrag,
      color : set_color
    }
  }

  // Sets a textfield for user input of hex color values
  // TODO don't clear the change callback
  // TODO allow a null target to unbind the input
  function input(target){
    change_callback = null;
    input_target = target;
    $(target).keyup(function(){
        this.value = "#"+this.value.replace(/^#/,"");
        if(this.value.match(/^#([0-9A-F]){3}$|^#([0-9A-F]){6}$/img)){
          set_color(this.value);
          update_color(true);
        }
    });
    set_color(target.value);
    update_color(true);

    return public_methods();
  }

  function onchange(callback){
    change_callback = callback;
    update_color(false);
    return public_methods();
  }

  function ondrag(start_callback, end_callback){
    drag_callbacks = [start_callback || function(){}, end_callback || function(){}];
    return public_methods();
  }

  function drag(e){
    var x = e.pageX - (parent.offset().left + center),
        y = e.pageY - (parent.offset().top + center);

    if(drag_target == hue_ring){
      set_hue_cursor(x,y);
      update_color();
      return true;
    }
    if(drag_target == bs_square){
      set_bs_cursor(x,y);
      update_color();
      return true;
    }
  }

  function start_drag(event, target){
    $(document).mouseup(stop_drag)
    $(document).mousemove(drag)
    drag_target = target;
    drag(event);
    drag_callbacks[0](current_color)
  }

  function stop_drag(){
    $(document).unbind("mouseup",stop_drag);
    $(document).unbind("mousemove",drag);
    drag_callbacks[1](current_color)
  }

  function event_drag_stop(event,o){
    o.mousemove = null
    drag_target=null;
  }

  function events_setup(){
    $([hue_ring.event.node,hue_ring.cursor[0].node]).mousedown(function(e){start_drag(e,hue_ring)});
    $([bs_square.b.node, bs_square.cursor[0].node]).mousedown(function(e){start_drag(e,bs_square)});
  }

  function cursor_create(size){
    var set = canvas.set().push(
        canvas.circle(0, 0, size).attr({"stroke-width":4, stroke:"#333"}),
        canvas.circle(0, 0, size+2).attr({"stroke-width":1, stroke:"#FFF", opacity:0.5})
    );

    set[0].node.style.cursor = "crosshair";

    return set;
  }

  function set_bs_cursor(x,y){
    x = x+center;
    y = y+center;
    if(x < sdim.x) x = sdim.x;
    if(x > sdim.x+sdim.l) x = sdim.x+sdim.l;
    if(y < sdim.y) y = sdim.y;
    if(y > sdim.y+sdim.l) y = sdim.y + sdim.l;

    bs_square.cursor.attr({cx:x, cy:y}).translate(0,0);
  }

  function set_hue(color){
    var hex = Raphael.getRGB(color).hex
    bs_square.h.attr("fill", hex);
  }

  function hue(){
    return Raphael.rgb2hsb(bs_square.h.attr("fill")).h;
  }

  function set_color(value){
    if(value === undefined){
      return current_color;
    }
    var temp = canvas.rect(1,1,1,1).attr({fill:value}),
        hsb = canvas.raphael.rgb2hsb(temp.attr("fill"));
        yy = hsb
    set_bs_cursor(
      (0-sdim.l/2) + (sdim.l*hsb.s),
      sdim.l/2 - (sdim.l*hsb.b));
    set_hue_cursor((360*(hsb.h))-90);
    temp.remove();
    return public_methods();;
  }

  // Could optimize this method
  function update_color(dont_replace_input_value){
    var x = bs_square.cursor.items[0].attr("cx"),
        y = bs_square.cursor.items[0].attr("cy"),
        hsb = {
          b: 1-(y-sdim.y)/sdim.l,
          s: (x-sdim.x)/sdim.l,
          h: hue()
        };
    current_color = Raphael.getRGB("hsb("+hsb.h+","+hsb.s+","+hsb.b+")");

    if(input_target){
      var c = Raphael.getRGB("hsb("+hsb.h+","+hsb.s+","+hsb.b+")").hex;
      if(dont_replace_input_value != true) input_target.value = c;
      if(hsb.b < 0.5){
        $(input_target).css("color", "#FFF")
      } else {
        $(input_target).css("color", "#000")
      }
      input_target.style.background = c;
    }

    if(change_callback != undefined){
      change_callback(current_color);
    }
  }

  // accepts either x,y or d (degrees)
  function set_hue_cursor(mixed_args){
    if(arguments.length == 2){
      var d = angle(arguments[0],arguments[1]);
    } else {
      var d = arguments[0]
    }

    var x = Math.cos(radians(d)) * (center-tri_size-padding);
    var y = Math.sin(radians(d)) * (center-tri_size-padding);
    hue_ring.cursor.attr({cx:x+center, cy:y+center}).translate(0,0);
    set_hue("hsb("+(d+90)/360+",1,1)")
  }

  function bs_square_dim(){
    if(sdim){ return sdim}
    var s = size - (tri_size * 4);
    return sdim = {
      x:(s/6)+tri_size*2+padding,
      y:(s/6)+tri_size*2+padding,
      l:(s * 2/3)-padding*2};
  }

  function create_bs_square(){
    bs_square_dim();
    box = [sdim.x, sdim.y, sdim.l, sdim.l];

    bs_square.h = canvas.rect.apply(canvas, box).attr({
      stroke:"#EEE", gradient: "0-#FFF-#000", opacity:1})
    bs_square.s = canvas.rect.apply(canvas, box).attr({
      stroke:null, gradient: "0-#FFF-#FFF", opacity:0})
    bs_square.b = canvas.rect.apply(canvas, box).attr({
      stroke:null, gradient: "90-#000-#FFF", opacity:0})
    bs_square.b.node.style.cursor = "crosshair";
  }

  function hue_segement_shape(){
    var path = "M -@W 0 L @W 0 L @W @H L -@W @H z";
    return path.replace(/@H/img, tri_size*2).replace(/@W/img,tri_size);
  }

  function copy_segment(r, d, k){
    var n = r.clone();
    var hue = d*(255/k);

    n.rotate((360/k)*d, (size/2), size/2);
    n.attr({"stroke-width":0, fill:"hsb("+d*(1/k)+", 1, 0.85)"})
    hue_ring.hues.push(n)
  }

  function create_hue_ring(){
    var s = hue_segement_shape(),
        tri = canvas.path(s).attr({stroke:null}).translate(size/2, padding),
        k = segments; // # of segments to use to generate the hues

    hue_ring.hues = canvas.set();

    for(n=0; n<k; n++){ copy_segment(tri, n, k); }

    // IE needs a slight opacity to assign events
    hue_ring.event = canvas.circle(
      center,
      center,
      center-tri_size-padding).attr({"stroke-width":tri_size*2, opacity:0.01});

    hue_ring.outline = canvas.circle(
      center,
      center,
      center-tri_size-padding).attr({"stroke":"#000", "stroke-width":(tri_size*2)+3, opacity:0.1})
    hue_ring.outline.toBack();
    hue_ring.event.node.style.cursor = "crosshair";
  }

  return create(target, color_wheel_size);
};
<commit_msg>jslint<commit_after>/*
* Colorwheel
* Copyright (c) 2010 John Weir (http://famedriver.com)
* Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
*
* requires jQuery & Raphael
*   http://jquery.com http://raphaeljs.com
*
* see http://jweir.github.com/colorwheel for Usage
*
*/

Raphael.colorwheel = function(target, color_wheel_size, no_segments){
  var canvas,
      current_color,
      size,
      segments = no_segments || 60,
      bs_square = {},
      hue_ring = {},
      tri_size,
      cursor = {},
      drag_target,
      input_target,
      center,
      parent,
      change_callback,
      drag_callbacks = [function(){}, function(){}],
      offset,
      padding = 2,
      sdim; // holds the dimensions for the saturation square

  function point(x, y){ return {x:x, y:y};}
  function radians(a){ return a * (Math.PI/180);}

  function angle(x,y){
    var q = x > 0 ? 0 : 180;
    return q+Math.atan((0 - y)/(0 - x))*180/(Math.PI);
  }

  function create(target, color_wheel_size){
    size     = color_wheel_size;
    tri_size = size/20;
    center   = size/2;
    parent   = $(target);
    canvas   = Raphael(parent[0],size, size);
    canvas.safari();

    create_bs_square();
    create_hue_ring();
    hue_ring.cursor = cursor_create(tri_size);
    bs_square.cursor = cursor_create(tri_size*0.5);
    events_setup();
    parent.css({height:size+"px", width:size+"px"});
    disable_select(parent);
    return public_methods();
  }

  function disable_select(target){
    $(target).css({"unselectable": "on","-moz-user-select": "none","-webkit-user-select": "none"});
  }

  function public_methods(){
    return {
      input: input,
      onchange: onchange,
      ondrag : ondrag,
      color : set_color
    };
  }

  // Sets a textfield for user input of hex color values
  // TODO don't clear the change callback
  // TODO allow a null target to unbind the input
  function input(target){
    change_callback = null;
    input_target = target;
    $(target).keyup(function(){
        this.value = "#"+this.value.replace(/^#/,"");
        if(this.value.match(/^#([0-9A-F]){3}$|^#([0-9A-F]){6}$/img)){
          set_color(this.value);
          update_color(true);
        }
    });
    set_color(target.value);
    update_color(true);

    return public_methods();
  }

  function onchange(callback){
    change_callback = callback;
    update_color(false);
    return public_methods();
  }

  function ondrag(start_callback, end_callback){
    drag_callbacks = [start_callback || function(){}, end_callback || function(){}];
    return public_methods();
  }

  function drag(e){
    var x = e.pageX - (parent.offset().left + center),
        y = e.pageY - (parent.offset().top + center);

    if(drag_target == hue_ring){
      set_hue_cursor(x,y);
      update_color();
      return true;
    }
    if(drag_target == bs_square){
      set_bs_cursor(x,y);
      update_color();
      return true;
    }
  }

  function start_drag(event, target){
    $(document).mouseup(stop_drag);
    $(document).mousemove(drag);
    drag_target = target;
    drag(event);
    drag_callbacks[0](current_color);
  }

  function stop_drag(){
    $(document).unbind("mouseup",stop_drag);
    $(document).unbind("mousemove",drag);
    drag_callbacks[1](current_color);
  }

  function event_drag_stop(event,o){
    o.mousemove = null;
    drag_target=null;
  }

  function events_setup(){
    $([hue_ring.event.node,hue_ring.cursor[0].node]).mousedown(function(e){start_drag(e,hue_ring);});
    $([bs_square.b.node, bs_square.cursor[0].node]).mousedown(function(e){start_drag(e,bs_square);});
  }

  function cursor_create(size){
    var set = canvas.set().push(
        canvas.circle(0, 0, size).attr({"stroke-width":4, stroke:"#333"}),
        canvas.circle(0, 0, size+2).attr({"stroke-width":1, stroke:"#FFF", opacity:0.5})
    );

    set[0].node.style.cursor = "crosshair";

    return set;
  }

  function set_bs_cursor(x,y){
    x = x+center;
    y = y+center;
    if(x < sdim.x) x = sdim.x;
    if(x > sdim.x+sdim.l) x = sdim.x+sdim.l;
    if(y < sdim.y) y = sdim.y;
    if(y > sdim.y+sdim.l) y = sdim.y + sdim.l;

    bs_square.cursor.attr({cx:x, cy:y}).translate(0,0);
  }

  function set_hue(color){
    var hex = Raphael.getRGB(color).hex;
    bs_square.h.attr("fill", hex);
  }

  function hue(){
    return Raphael.rgb2hsb(bs_square.h.attr("fill")).h;
  }

  function set_color(value){
    if(value === undefined){
      return current_color;
    }
    var temp = canvas.rect(1,1,1,1).attr({fill:value}),
        hsb = canvas.raphael.rgb2hsb(temp.attr("fill"));

    set_bs_cursor(
      (0-sdim.l/2) + (sdim.l*hsb.s),
      sdim.l/2 - (sdim.l*hsb.b));
    set_hue_cursor((360*(hsb.h))-90);
    temp.remove();
    return public_methods();
  }

  // Could optimize this method
  function update_color(dont_replace_input_value){
    var x = bs_square.cursor.items[0].attr("cx"),
        y = bs_square.cursor.items[0].attr("cy"),
        hsb = {
          b: 1-(y-sdim.y)/sdim.l,
          s: (x-sdim.x)/sdim.l,
          h: hue()
        };
    current_color = Raphael.getRGB("hsb("+hsb.h+","+hsb.s+","+hsb.b+")");

    if(input_target){
      var c = Raphael.getRGB("hsb("+hsb.h+","+hsb.s+","+hsb.b+")").hex;
      if(dont_replace_input_value != true) input_target.value = c;
      if(hsb.b < 0.5){
        $(input_target).css("color", "#FFF");
      } else {
        $(input_target).css("color", "#000");
      }
      input_target.style.background = c;
    }

    if(change_callback != undefined){
      change_callback(current_color);
    }
  }

  // accepts either x,y or d (degrees)
  function set_hue_cursor(mixed_args){
    var d;
    if(arguments.length == 2){
      d = angle(arguments[0],arguments[1]);
    } else {
      d = arguments[0];
    }

    var x = Math.cos(radians(d)) * (center-tri_size-padding);
    var y = Math.sin(radians(d)) * (center-tri_size-padding);
    hue_ring.cursor.attr({cx:x+center, cy:y+center}).translate(0,0);
    set_hue("hsb("+(d+90)/360+",1,1)");
  }

  function bs_square_dim(){
    if(sdim){ return sdim;}
    var s = size - (tri_size * 4);
    sdim = {
      x:(s/6)+tri_size*2+padding,
      y:(s/6)+tri_size*2+padding,
      l:(s * 2/3)-padding*2
    };
    return sdim;
  }

  function create_bs_square(){
    bs_square_dim();
    box = [sdim.x, sdim.y, sdim.l, sdim.l];

    bs_square.h = canvas.rect.apply(canvas, box).attr({
      stroke:"#EEE", gradient: "0-#FFF-#000", opacity:1});
    bs_square.s = canvas.rect.apply(canvas, box).attr({
      stroke:null, gradient: "0-#FFF-#FFF", opacity:0});
    bs_square.b = canvas.rect.apply(canvas, box).attr({
      stroke:null, gradient: "90-#000-#FFF", opacity:0});
    bs_square.b.node.style.cursor = "crosshair";
  }

  function hue_segement_shape(){
    var path = "M -@W 0 L @W 0 L @W @H L -@W @H z";
    return path.replace(/@H/img, tri_size*2).replace(/@W/img,tri_size);
  }

  function copy_segment(r, d, k){
    var n = r.clone();
    var hue = d*(255/k);

    n.rotate((360/k)*d, (size/2), size/2);
    n.attr({"stroke-width":0, fill:"hsb("+d*(1/k)+", 1, 0.85)"});
    hue_ring.hues.push(n);
  }

  function create_hue_ring(){
    var s = hue_segement_shape(),
        tri = canvas.path(s).attr({stroke:null}).translate(size/2, padding),
        k = segments; // # of segments to use to generate the hues

    hue_ring.hues = canvas.set();

    for(n=0; n<k; n++){ copy_segment(tri, n, k); }

    // IE needs a slight opacity to assign events
    hue_ring.event = canvas.circle(
      center,
      center,
      center-tri_size-padding).attr({"stroke-width":tri_size*2, opacity:0.01});

    hue_ring.outline = canvas.circle(
      center,
      center,
      center-tri_size-padding).attr({"stroke":"#000", "stroke-width":(tri_size*2)+3, opacity:0.1});
    hue_ring.outline.toBack();
    hue_ring.event.node.style.cursor = "crosshair";
  }

  return create(target, color_wheel_size);
};
<|endoftext|>


<commit_before>/**
 * Creates an instance of the Tags View
 *
 * @constructor
 * @this {Tags}
 * @param {Document} document The document to be shown in the Tags view.
 * @param {DIV} container The conatiner div for the Tags view.
 * @param {DocumentDialog} parent The parent document dialog.
 */
Tags = function(document,container,parent){
	this.type = "tags";
	this.container = container;
	this.stopped = true;
	this.document = document;
	this.container = container;
	this.parent = parent;
	this.lp = new LinkProcessor();
	this.documentScope = EditionProperties.documentScope;
	this.initialize();
}

/**
 * Initializes the tag cloud to display the tags and activates pagination and/or scope selection panels
 *
 * @this {Tags}
 */
Tags.prototype.initialize = function(){
	var context = this;
	this.buttonPanel = $('<div/>').appendTo(this.container);
	this.buttonPanel.addClass('buttonPanel');
	this.contentPanel = $('<div/>').appendTo(this.container);
	$(this.contentPanel).css('overflow','auto');
	this.parent.facetSelector.setTriggerFunc(function(facetSelection){
		$(context.contentPanel).empty();
		if( context.documentScope ){
			context.showTags();
		}
		else {
			context.show(context.parent.page);
		}
		context.parent.facetsChanged(facetSelection);
	});
	this.parent.paginator.setTriggerFunc(function(page){
		context.showPage(page);
		context.parent.pageChanged(page);
	});
	if( EditionProperties.scopeSelection ){
		var id = 'scope'+EditionGui.getIndependentId();
		var documentTags = $("<input type='radio' name='"+id+"'>"+Util.getString('documentTags')+"</input>").appendTo(this.buttonPanel);
		var tagsByPages = $("<input type='radio' name='"+id+"'>"+Util.getString('tagsByPages')+"</input>").appendTo(this.buttonPanel);
		if( this.documentScope ){
			$(documentTags).attr('checked',true);
		}
		else {
			$(tagsByPages).attr('checked',true);
		}
		var setScope = function(scope){
			if( context.documentScope != scope ){
				if( scope ){
					context.parent.hidePagination();
				}
				else {
					context.parent.showPagination();
				}
				context.documentScope = scope;
				context.display(context.parent.page);
				context.resize();
			}
		};
		$(documentTags).click(function(){
			setScope(true);
		});
		$(tagsByPages).click(function(){
			setScope(false);
		});
	}
}

/**
 * Retrieves and shows the tags for a given page by updating the tag cloud.
 *
 * @this {Tags}
 * @param {number} page The tags of the given page will be shown (p = 0 for all tags of the document).
 */
Tags.prototype.show = function(page){
	var context = this;
	var facets = this.parent.facetSelector.getFacetString();
	if( facets == '' ){
		$(Util.getAlertMessage(Util.getString('selectFacetsAlert'))).appendTo(this.contentPanel);
		return;
	}
	if( !this.stopped ){
		this.parent.stopProcessing();
	}
	this.stopped = false;
	this.parent.startProcessing();
	var failure = function(errorObject){
		if( !context.stopped ){
			$(Util.getErrorMessage(errorObject.status)).appendTo(context.contentPanel);
			context.parent.stopProcessing();
		}
	}
	var success = function(xml){
		if( !context.stopped ){
			var tagArray = Util.getTags($(xml).find('tag'));
			context.tags = tagArray;
			var trigger = function(){
				context.lp.appendTooltips(context.contentPanel);
				context.parent.stopProcessing();
			};
			$(context.contentPanel).jQCloud(tagArray,{trigger:trigger});
		}
	}
	DocumentServerConnection.getDocumentTags(context.document,page,facets,success,failure);
};

/**
 * Display all tags of the document
 *
 * @this {Tags}
 */
Tags.prototype.showTags = function(){
	$(this.contentPanel).empty();
	this.show(0);
};

/**
 * Display tags mentioned on a given page.
 *
 * @this {Tags}
 * @param {number} page The tags of the given page will be shown.
 */
Tags.prototype.showPage = function(page){
	this.actualPage = page;
	$(this.contentPanel).empty();
	this.show(page);
};

/**
 * Display the tags for the document (page = 0) or a given page (page > 0)
 *
 * @this {Tags}
 * @param {number} page The page to be shown.
 */
Tags.prototype.display = function(page){
	if( this.documentScope ){
		this.showTags();
	}
	else {
		page ? this.parent.paginator.setPage(page,false) : this.parent.paginator.setPage(1,false);
	}
};

/**
 * Resizes the tag cloud.
 *
 * @this {Tags}
 */
Tags.prototype.resize = function(){
	var context = this;
	$(this.contentPanel).css('width','100%');
	$(this.contentPanel).css('height',($(this.container).height()-$(this.buttonPanel).height())+'px');
	if( typeof this.tags != 'undefined' ){
		$(this.contentPanel).empty();
		var trigger = function(){
			context.lp.appendTooltips(context.contentPanel);
		};
		$(this.contentPanel).jQCloud(this.tags,{trigger:trigger});
		this.lp.appendTooltips(this.contentPanel);
	}
};

/**
 * Updates this Tags view if its parent document dialog is linked to other views for the same document and a 'pageChange' or 'facetsChange' event was performed in one of these other linked views
 *
 * @this {Tags}
 * @param {JSON} change The information for the view update. It contains a type (e.g. 'pageChange') and a data information (e.g. the new page number in case of a 'pageChange' event)
 */
Tags.prototype.onChange = function(change){
	if( change.type == "facetsChange" ){
		this.parent.facetSelector.setFacetSelection(change.data);
		this.context.display(this.parent.page);
	}
	if( change.type == "pageChange" ){
		if( this.actualPage != change.data ){
			this.parent.page = change.data;
			this.parent.paginator.setPage(change.data,true);
			this.showPage(change.data);
		}
	}
};
<commit_msg>removed tag view bug<commit_after>/**
 * Creates an instance of the Tags View
 *
 * @constructor
 * @this {Tags}
 * @param {Document} document The document to be shown in the Tags view.
 * @param {DIV} container The conatiner div for the Tags view.
 * @param {DocumentDialog} parent The parent document dialog.
 */
Tags = function(document,container,parent){
	this.type = "tags";
	this.container = container;
	this.stopped = true;
	this.pages = document.pages;
	this.document = document;
	this.container = container;
	this.parent = parent;
	this.lp = new LinkProcessor();
	this.documentScope = EditionProperties.documentScope;
	this.initialize();
}

/**
 * Initializes the tag cloud to display the tags and activates pagination and/or scope selection panels
 *
 * @this {Tags}
 */
Tags.prototype.initialize = function(){
	var context = this;
	this.buttonPanel = $('<div/>').appendTo(this.container);
	this.buttonPanel.addClass('buttonPanel');
	this.contentPanel = $('<div/>').appendTo(this.container);
	$(this.contentPanel).css('overflow','auto');
	this.parent.facetSelector.setTriggerFunc(function(facetSelection){
		$(context.contentPanel).empty();
		if( context.documentScope ){
			context.showTags();
		}
		else {
			context.show(context.parent.page);
		}
		context.parent.facetsChanged(facetSelection);
	});
	this.parent.paginator.setTriggerFunc(function(page){
		context.showPage(page);
		context.parent.pageChanged(page);
	});
	if( EditionProperties.scopeSelection ){
		var id = 'scope'+EditionGui.getIndependentId();
		var documentTags = $("<input type='radio' name='"+id+"'>"+Util.getString('documentTags')+"</input>").appendTo(this.buttonPanel);
		var tagsByPages = $("<input type='radio' name='"+id+"'>"+Util.getString('tagsByPages')+"</input>").appendTo(this.buttonPanel);
		if( this.documentScope ){
			$(documentTags).attr('checked',true);
		}
		else {
			$(tagsByPages).attr('checked',true);
		}
		var setScope = function(scope){
			if( context.documentScope != scope ){
				if( scope ){
					context.parent.hidePagination();
				}
				else {
					context.parent.showPagination();
				}
				context.documentScope = scope;
				context.display(context.parent.page);
				context.resize();
			}
		};
		$(documentTags).click(function(){
			setScope(true);
		});
		$(tagsByPages).click(function(){
			setScope(false);
		});
	}
}

/**
 * Retrieves and shows the tags for a given page by updating the tag cloud.
 *
 * @this {Tags}
 * @param {number} page The tags of the given page will be shown (p = 0 for all tags of the document).
 */
Tags.prototype.show = function(page){
	var context = this;
	var facets = this.parent.facetSelector.getFacetString();
	if( facets == '' ){
		$(Util.getAlertMessage(Util.getString('selectFacetsAlert'))).appendTo(this.contentPanel);
		return;
	}
	if( !this.stopped ){
		this.parent.stopProcessing();
	}
	this.stopped = false;
	this.parent.startProcessing();
	var failure = function(errorObject){
		if( !context.stopped ){
			$(Util.getErrorMessage(errorObject.status)).appendTo(context.contentPanel);
			context.parent.stopProcessing();
		}
	}
	var success = function(xml){
		if( !context.stopped ){
			var tagArray = Util.getTags($(xml).find('tag'));
			context.tags = tagArray;
			var trigger = function(){
				context.lp.appendTooltips(context.contentPanel);
				context.parent.stopProcessing();
			};
			$(context.contentPanel).jQCloud(tagArray,{trigger:trigger});
		}
	}
	DocumentServerConnection.getDocumentTags(context.document,page,facets,success,failure);
};

/**
 * Display all tags of the document
 *
 * @this {Tags}
 */
Tags.prototype.showTags = function(){
	$(this.contentPanel).empty();
	this.show(0);
};

/**
 * Display tags mentioned on a given page.
 *
 * @this {Tags}
 * @param {number} page The tags of the given page will be shown.
 */
Tags.prototype.showPage = function(page){
	this.actualPage = page;
	$(this.contentPanel).empty();
	this.show(page);
};

/**
 * Display the tags for the document (page = 0) or a given page (page > 0)
 *
 * @this {Tags}
 * @param {number} page The page to be shown.
 */
Tags.prototype.display = function(page){
	if( this.documentScope ){
		this.showTags();
	}
	else if( page ){
		this.parent.paginator.setPage(page,true);
		this.showPage(page);
	}
	else {
		this.parent.paginator.setPage(1,true);
		this.showPage(1);
	}
};

/**
 * Resizes the tag cloud.
 *
 * @this {Tags}
 */
Tags.prototype.resize = function(){
	var context = this;
	$(this.contentPanel).css('width','100%');
	$(this.contentPanel).css('height',($(this.container).height()-$(this.buttonPanel).height())+'px');
	if( typeof this.tags != 'undefined' ){
		$(this.contentPanel).empty();
		var trigger = function(){
			context.lp.appendTooltips(context.contentPanel);
		};
		$(this.contentPanel).jQCloud(this.tags,{trigger:trigger});
		this.lp.appendTooltips(this.contentPanel);
	}
};

/**
 * Updates this Tags view if its parent document dialog is linked to other views for the same document and a 'pageChange' or 'facetsChange' event was performed in one of these other linked views
 *
 * @this {Tags}
 * @param {JSON} change The information for the view update. It contains a type (e.g. 'pageChange') and a data information (e.g. the new page number in case of a 'pageChange' event)
 */
Tags.prototype.onChange = function(change){
	if( change.type == "facetsChange" ){
		this.parent.facetSelector.setFacetSelection(change.data);
		this.context.display(this.parent.page);
	}
	if( change.type == "pageChange" ){
		if( this.actualPage != change.data ){
			this.parent.page = change.data;
			this.parent.paginator.setPage(change.data,true);
			this.showPage(change.data);
		}
	}
};
<|endoftext|>


<commit_before>// this code helps us define our schema for state mangment
// schema : {position:{x:x,y:y,z:z}, algs:[algname1,algname2]}
var camic_state = new StateManager('state');

function setPosition(position){
  var pt = new OpenSeadragon.Point(position.x, position.y);
  viewer.viewport.zoomTo(position.z, pt);
  viewer.viewport.panTo(pt, true);
}

// TODO test if this method always works
function setAlgs(algList){
  SELECTED_ALGORITHM_LIST = algList;
}

// initalize after 500 mseconds
document.addEventListener("ready-for-state",function(){
  console.log("ready-for-state evt")
  camic_state.add_key('position', setPosition);
  camic_state.add_key('alg', setAlgs);
  // before touching the url, get what we already have
  try{
    camic_state.initialize(camic_state.decode(camic_state.get_url_state()));
  }
  catch(e){
    console.log(e);
  }
});

algHandler = function() {
  camic_state.vals['alg']=SELECTED_ALGORITHM_LIST;
  //camic_state.set_url();
};

moveHandler = function() {
  var pos = viewer.viewport.getCenter(true);
  var zoom = viewer.viewport.getZoom(true);
  camic_state.vals['position']={'x':pos.x, 'y':pos.y, 'z':zoom};
  //camic_state.set_url();
};

// TODO make this actually trigger usefully
// update url when requested only (this should be share)
function LinkRequest(){
  moveHandler();
  algHandler();
  console.log("{state : " + camic_state.encode(camic_state.vals)+ "}");
}
<commit_msg>change to osd event<commit_after>// this code helps us define our schema for state mangment
// schema : {position:{x:x,y:y,z:z}, algs:[algname1,algname2]}
var camic_state = new StateManager('state');

function setPosition(position){
  var pt = new OpenSeadragon.Point(position.x, position.y);
  viewer.viewport.zoomTo(position.z, pt);
  viewer.viewport.panTo(pt, true);
}

// TODO test if this method always works
function setAlgs(algList){
  SELECTED_ALGORITHM_LIST = algList;
}

// initalize after 500 mseconds
viewer.addHandler('open',function(){
  console.log("ready-for-state evt")
  camic_state.add_key('position', setPosition);
  camic_state.add_key('alg', setAlgs);
  // before touching the url, get what we already have
  try{
    camic_state.initialize(camic_state.decode(camic_state.get_url_state()));
  }
  catch(e){
    console.log(e);
  }
});

algHandler = function() {
  camic_state.vals['alg']=SELECTED_ALGORITHM_LIST;
  //camic_state.set_url();
};

moveHandler = function() {
  var pos = viewer.viewport.getCenter(true);
  var zoom = viewer.viewport.getZoom(true);
  camic_state.vals['position']={'x':pos.x, 'y':pos.y, 'z':zoom};
  //camic_state.set_url();
};

// TODO make this actually trigger usefully
// update url when requested only (this should be share)
function LinkRequest(){
  moveHandler();
  algHandler();
  console.log("{state : " + camic_state.encode(camic_state.vals)+ "}");
}
<|endoftext|>


<commit_before>'use strict';

var $ = require('jquery');

require('../libs/pikaday/plugins/pikaday.jquery'),
require('../libs/select2/dist/js/select2.min'),
require('../libs/spectrum/spectrum');

function PulsarFormComponent(html) {

    this.$html = html;

};

PulsarFormComponent.prototype.init = function () {

    var component = this;

    // Colourpickers
    component.initColourpickers();

    // Attach basic pikaday to datepicker fields
    this.$html.find('[data-datepicker=true]').pikaday({
        format: 'DD/MM/YYYY'
    });

    component.$select2 = this.$html.find('.js-select2');

    component.$select2.each(function() {

        var $this = $(this);

        if ($this.data('html')) {

            function formatOption(data) {
                return $('' + data.text + '');
            };

            $this.select2({
                templateResult: formatOption,
                templateSelection: formatOption
            });

        } else {
            $this.select2();
        }
    });

    // Block styled checkboxes and radios
    var choiceBlock = component.$html.find(".choice--block");

    // set up choice block states on load
    $.each(choiceBlock, function() {
        component.initSelectionButtons($(this));
    });

    // choice block click behaviour
    choiceBlock.on('change', '.controls input[type="checkbox"], .controls input[type="radio"]', component.selectionButtons);

};

PulsarFormComponent.prototype.initSelectionButtons = function(e) {

    e.find('input[type="checkbox"]:checked, input[type="radio"]:checked')
        .closest('.control__label')
        .addClass('is-selected');

};

PulsarFormComponent.prototype.initColourpickers = function() {

    var component = this,
        pickers = component.$html.find('.js-colorpicker');

    pickers.each(function() {
        var $this = $(this),
            $input = $this.find('.form__control'),
            $pickerInput = $($.parseHTML('<input>'));

        $pickerInput.insertAfter($input);

        // changing the picker should update the input
        $pickerInput.spectrum({
            color: '#' + $input.val(),
            showInput: false,
            preferredFormat: 'hex',
            replacerClassName: 'btn',
            change: function (color) {
                $input.val(('' + color).substring(1));
            }
        });

        // changing the input should update the picker
        $input.on('change', function () {
            $pickerInput.spectrum('set', '#' + $input.val());
        });
    });
};

PulsarFormComponent.prototype.selectionButtons = function() {

    var $target = $(this);

    var $controls = $target.closest('.controls');

    $controls.find('input[type="checkbox"]:not(:checked), input[type="radio"]:not(:checked)')
        .closest('.control__label')
        .removeClass('is-selected');

    if ($target.is(':checked')) {
        $target.closest('.control__label').addClass('is-selected');
    } else {
        $target.closest('.control__label').removeClass('is-selected');
    }

};

module.exports = PulsarFormComponent;
<commit_msg>Add change event when colourpicker is used<commit_after>'use strict';

var $ = require('jquery');

require('../libs/pikaday/plugins/pikaday.jquery'),
require('../libs/select2/dist/js/select2.min'),
require('../libs/spectrum/spectrum');

function PulsarFormComponent(html) {

    this.$html = html;

};

PulsarFormComponent.prototype.init = function () {

    var component = this;

    // Colourpickers
    component.initColourpickers();

    // Attach basic pikaday to datepicker fields
    this.$html.find('[data-datepicker=true]').pikaday({
        format: 'DD/MM/YYYY'
    });

    component.$select2 = this.$html.find('.js-select2');

    component.$select2.each(function() {

        var $this = $(this);

        if ($this.data('html')) {

            function formatOption(data) {
                return $('' + data.text + '');
            };

            $this.select2({
                templateResult: formatOption,
                templateSelection: formatOption
            });

        } else {
            $this.select2();
        }
    });

    // Block styled checkboxes and radios
    var choiceBlock = component.$html.find(".choice--block");

    // set up choice block states on load
    $.each(choiceBlock, function() {
        component.initSelectionButtons($(this));
    });

    // choice block click behaviour
    choiceBlock.on('change', '.controls input[type="checkbox"], .controls input[type="radio"]', component.selectionButtons);

};

PulsarFormComponent.prototype.initSelectionButtons = function(e) {

    e.find('input[type="checkbox"]:checked, input[type="radio"]:checked')
        .closest('.control__label')
        .addClass('is-selected');

};

PulsarFormComponent.prototype.initColourpickers = function() {

    var component = this,
        pickers = component.$html.find('.js-colorpicker');

    pickers.each(function() {
        var $this = $(this),
            $input = $this.find('.form__control'),
            $pickerInput = $($.parseHTML('<input>'));

        $pickerInput.insertAfter($input);

        // changing the picker should update the input
        $pickerInput.spectrum({
            color: '#' + $input.val(),
            showInput: false,
            preferredFormat: 'hex',
            replacerClassName: 'btn',
            change: function (color) {
                $input.val(('' + color).substring(1));
                $input.trigger('change');
            }
        });

        // changing the input should update the picker
        $input.on('change', function () {
            $pickerInput.spectrum('set', '#' + $input.val());
        });
    });
};

PulsarFormComponent.prototype.selectionButtons = function() {

    var $target = $(this);

    var $controls = $target.closest('.controls');

    $controls.find('input[type="checkbox"]:not(:checked), input[type="radio"]:not(:checked)')
        .closest('.control__label')
        .removeClass('is-selected');

    if ($target.is(':checked')) {
        $target.closest('.control__label').addClass('is-selected');
    } else {
        $target.closest('.control__label').removeClass('is-selected');
    }

};

module.exports = PulsarFormComponent;
<|endoftext|>


<commit_before>var _     = require('underscore'),
    Hours = require('cloud/models/hours'),
    CATEGORIES = require("lib/categories");

module.exports = Parse.Object.extend('Facility', {
  initialize: function() {
    this.set("services", []);
  },
  // no gender restriction or gender == self.gender
  matchesGender: function(targetGender) {
    var g = this.get('gender');

    if ( !g || !targetGender )  {
      return true;
    } else {
      return g.toUpperCase() == targetGender.toUpperCase();
    }
  },

  presentJSON: function() {
    var asJSON = this.toJSON();
    asJSON.services = this.get('services').map(function(service) {
      return service.toJSON();
    });
    asJSON.demographics = this.demographics();
    asJSON.distinctCategories = this.distinctCategories();
    return asJSON;
  },

  matchesAges: function(ages) {
    var a = this.get('age');
    if ( !ages || !a ) {
      return true;
    }

    return _.any(_.compact(ages), function(targetAge) {
      return _.include(a, targetAge);
    });
  },

  matchesFilter: function(filter) {
    var match = true;

    if ( !filter ) {
      return true;
    }

    match &= this.matchesGender(filter.gender);
    match &= this.matchesAges(filter.age);
    match &= this.hasServiceInCategories(filter.categories);
    return match;
  },

  hasKnownStatus: function() {
    return (this.status() !== 'unknown');
  },

  status: function() {
    var open;

    if ( this._status ) return this._status;

    open = this.hasOpenService(new Date());

    if ( open === true ) {
      this._status = 'open';
    } else if ( open === false ) {
      this._status = 'closed';
    } else {
      this._status = 'unknown';
    }

    return this._status;
  },

  hasOpenService: function(time) {
    var services = this.get('services');
    try {
      return _.any(services, function(service) {
        return service.hours().within(time);
      });
    } catch(e) {
      console.log(e);
      return null;
    }
  },

  hasServiceInCategories: function(categories) {
    if ( !categories )  {
      return true;
    }

    var services = this.get('services');
    return _.any(_.compact(categories), function(targetCategory) {
      return _.any(services, function(facService) {
        return facService.get("category") === targetCategory;
      });
    });
  },

  age_as_string: function(input) {
    switch ( input.toUpperCase() ) {
      case "C":
        return "children";
      case "Y":
        return "teens";
      case "A":
        return "adults";
      case "S":
        return "seniors";
    }
  },

  demographics: function() {
    var g, a, output = "";
    if ( !this.get('age') && !this.get('gender') ) {
      output = "Anyone";
    } else {
      if ( (g = this.get('gender') ) ) {
        if ( this.get('age') ) {
          output = g.toUpperCase() == "F" ? "Female " : "Male ";
        } else {
          output = "Only " + (g.toUpperCase() == "F" ? "women" : "men");
        }
      } else {
        output = "All ";
      }

      if ( (a = this.get('age') ) ) {
        // C-Y-A-S
        var translated = _(a).map(this.age_as_string);
        output += _(translated).join(", ");
      }
    }
    return output;
  },
  distinctCategories: function() {
    var s = [], h = {};
    _.each(this.get("services"), function(service) {
      var cat = service.get("category");
      if ( !h[cat] ) {
        h[cat] = 1;
        s.push(_.find(CATEGORIES, function(e) { return e.key == cat; }));
      }
    });
    return s;
  }
});
<commit_msg>requiring cloud/lib/categories<commit_after>var _     = require('underscore'),
    Hours = require('cloud/models/hours'),
    CATEGORIES = require("cloud/lib/categories");

module.exports = Parse.Object.extend('Facility', {
  initialize: function() {
    this.set("services", []);
  },
  // no gender restriction or gender == self.gender
  matchesGender: function(targetGender) {
    var g = this.get('gender');

    if ( !g || !targetGender )  {
      return true;
    } else {
      return g.toUpperCase() == targetGender.toUpperCase();
    }
  },

  presentJSON: function() {
    var asJSON = this.toJSON();
    asJSON.services = this.get('services').map(function(service) {
      return service.toJSON();
    });
    asJSON.demographics = this.demographics();
    asJSON.distinctCategories = this.distinctCategories();
    return asJSON;
  },

  matchesAges: function(ages) {
    var a = this.get('age');
    if ( !ages || !a ) {
      return true;
    }

    return _.any(_.compact(ages), function(targetAge) {
      return _.include(a, targetAge);
    });
  },

  matchesFilter: function(filter) {
    var match = true;

    if ( !filter ) {
      return true;
    }

    match &= this.matchesGender(filter.gender);
    match &= this.matchesAges(filter.age);
    match &= this.hasServiceInCategories(filter.categories);
    return match;
  },

  hasKnownStatus: function() {
    return (this.status() !== 'unknown');
  },

  status: function() {
    var open;

    if ( this._status ) return this._status;

    open = this.hasOpenService(new Date());

    if ( open === true ) {
      this._status = 'open';
    } else if ( open === false ) {
      this._status = 'closed';
    } else {
      this._status = 'unknown';
    }

    return this._status;
  },

  hasOpenService: function(time) {
    var services = this.get('services');
    try {
      return _.any(services, function(service) {
        return service.hours().within(time);
      });
    } catch(e) {
      console.log(e);
      return null;
    }
  },

  hasServiceInCategories: function(categories) {
    if ( !categories )  {
      return true;
    }

    var services = this.get('services');
    return _.any(_.compact(categories), function(targetCategory) {
      return _.any(services, function(facService) {
        return facService.get("category") === targetCategory;
      });
    });
  },

  age_as_string: function(input) {
    switch ( input.toUpperCase() ) {
      case "C":
        return "children";
      case "Y":
        return "teens";
      case "A":
        return "adults";
      case "S":
        return "seniors";
    }
  },

  demographics: function() {
    var g, a, output = "";
    if ( !this.get('age') && !this.get('gender') ) {
      output = "Anyone";
    } else {
      if ( (g = this.get('gender') ) ) {
        if ( this.get('age') ) {
          output = g.toUpperCase() == "F" ? "Female " : "Male ";
        } else {
          output = "Only " + (g.toUpperCase() == "F" ? "women" : "men");
        }
      } else {
        output = "All ";
      }

      if ( (a = this.get('age') ) ) {
        // C-Y-A-S
        var translated = _(a).map(this.age_as_string);
        output += _(translated).join(", ");
      }
    }
    return output;
  },
  distinctCategories: function() {
    var s = [], h = {};
    _.each(this.get("services"), function(service) {
      var cat = service.get("category");
      if ( !h[cat] ) {
        h[cat] = 1;
        s.push(_.find(CATEGORIES, function(e) { return e.key == cat; }));
      }
    });
    return s;
  }
});
<|endoftext|>


<commit_before>// Copyright 2014-2017, University of Colorado Boulder

/**
 * Base class for button models, which describe the behavior of buttons when users interact with them.  Property values
 * are set by an associated listener, see ButtonListener for details.
 */
define( function( require ) {
  'use strict';

  // modules
  var BooleanProperty = require( 'AXON/BooleanProperty' );
  var inherit = require( 'PHET_CORE/inherit' );
  var PressListener = require( 'SCENERY/listeners/PressListener' );
  var Property = require( 'AXON/Property' );
  var sun = require( 'SUN/sun' );
  var Tandem = require( 'TANDEM/Tandem' );

  /**
   * @param {Object} [options]
   * @constructor
   */
  function ButtonModel( options ) {

    options = _.extend( {
      // {function} called on pointer down
      startCallback: function() {},
      // {function} called on pointer up, @param {boolean} over - indicates whether the pointer was released over the button
      endCallback: function( over ) {},
      // {boolean} is the button enabled?
      enabled: true,

      tandem: Tandem.required,

      // a11y
      fireOnHoldInterval: 100 // fire continuously at this interval in ms when holding down button with keyboard
    }, options );

    var self = this;

    // model properties
    this.overProperty = new Property( false ); // @public - Is the pointer over the button?
    this.downProperty = new Property( false ); // @public - Is the pointer down?

    // @public - Is the button enabled?
    this.enabledProperty = new BooleanProperty( options.enabled, {
      tandem: options.tandem.createTandem( 'enabledProperty' ),
      phetioInstanceDocumentation: 'When disabled, the button is grayed out and cannot be pressed'
    } );

    // @private - keep track of and store all listeners this model creates
    this.listeners = [];

    // @private {number}
    this._fireOnHoldInterval = options.fireOnHoldInterval;

    // startCallback on pointer down, endCallback on pointer up. lazyLink so they aren't called immediately.
    this.downProperty.lazyLink( function( down ) {
      if ( down ) {
        options.startCallback();
      }
      else {
        options.endCallback( self.overProperty.get() );
      }
    } );

    // interrupt listeners when enabled is set to false
    this.enabledProperty.link( function( enabled ) {
      if ( !enabled ) {
        for ( var i = 0; i < self.listeners.length; i++ ) {
          var listener = self.listeners[ i ];
          listener.interrupt && listener.interrupt();
        }
      }
    } );

    // @private
    this.disposeButtonModel = function() {

      // This will unlink all listeners, causing potential issues if listeners try to unlink properties afterwards
      this.overProperty.dispose();
      this.downProperty.dispose();
      this.enabledProperty.dispose();
      this.listeners = [];
    };
  }

  sun.register( 'ButtonModel', ButtonModel );

  return inherit( Object, ButtonModel, {

    /**
     * @public
     */
    dispose: function() {
      this.disposeButtonModel();
    },

    /**
     * Click the button by pressing the button down and then releasing after a timeout. When assistive technology is
     * used, the browser does not receive 'down' or 'up' events on buttons - only a single 'click' event. For a11y we
     * need to toggle the pressed state every 'click' event.
     * @param {function} [endListener] - optional function to be called once the button has been released after
     *                                   accessibility related interaction.
     * @public
     */
    a11yClick: function( endListener ) {
      if ( !this.downProperty.get() && this.enabledProperty.get() ) {

        // ensure that button is 'over' so listener can be called while button is down
        this.overProperty.set( true );
        this.downProperty.set( true );

        var self = this;
        // Timer.setTimeout( function() {

        // no longer down, don't reset 'over' so button can be styled as long as it has focus
        self.downProperty.set( false );

        endListener && endListener();
        // }, self._fireOnHoldInterval );
      }
    },

    /**
     * Button is no longer considered over on blur, unless blur was initiated by a 'down' event.
     *
     * @public
     */
    a11yBlur: function() {
      if ( !this.downProperty.get() ) {
        this.overProperty.value = false;
      }
    },

    /**
     * Creates a standard button listener that can be added to a node and that will trigger the changes to this model.
     * @param {Tandem} tandem
     * @returns {PressListener}
     * @public
     */
    createListener: function( tandem ) {
      var self = this;

      var pressListener = new PressListener( {
        tandem: tandem,
        isPressedProperty: this.downProperty,
        isOverProperty: this.overProperty,
        canStartPress: function() {
          return self.enabledProperty.value;
        }
      } );
      this.listeners.push( pressListener );
      return pressListener;
    }
  } );
} );<commit_msg>Added documentation to various instances, see https://github.com/phetsims/phet-io/issues/1346<commit_after>// Copyright 2014-2017, University of Colorado Boulder

/**
 * Base class for button models, which describe the behavior of buttons when users interact with them.  Property values
 * are set by an associated listener, see ButtonListener for details.
 */
define( function( require ) {
  'use strict';

  // modules
  var BooleanProperty = require( 'AXON/BooleanProperty' );
  var inherit = require( 'PHET_CORE/inherit' );
  var PressListener = require( 'SCENERY/listeners/PressListener' );
  var Property = require( 'AXON/Property' );
  var sun = require( 'SUN/sun' );
  var Tandem = require( 'TANDEM/Tandem' );

  /**
   * @param {Object} [options]
   * @constructor
   */
  function ButtonModel( options ) {

    options = _.extend( {
      // {function} called on pointer down
      startCallback: function() {},
      // {function} called on pointer up, @param {boolean} over - indicates whether the pointer was released over the button
      endCallback: function( over ) {},
      // {boolean} is the button enabled?
      enabled: true,

      tandem: Tandem.required,

      // a11y
      fireOnHoldInterval: 100 // fire continuously at this interval in ms when holding down button with keyboard
    }, options );

    var self = this;

    // model properties
    this.overProperty = new Property( false ); // @public - Is the pointer over the button?
    this.downProperty = new Property( false ); // @public - Is the pointer down?

    // @public - Is the button enabled?
    this.enabledProperty = new BooleanProperty( options.enabled, {
      tandem: options.tandem.createTandem( 'enabledProperty' ),
      phetioInstanceDocumentation: 'When disabled, the button is grayed out and cannot be pressed'
    } );

    // @private - keep track of and store all listeners this model creates
    this.listeners = [];

    // @private {number}
    this._fireOnHoldInterval = options.fireOnHoldInterval;

    // startCallback on pointer down, endCallback on pointer up. lazyLink so they aren't called immediately.
    this.downProperty.lazyLink( function( down ) {
      if ( down ) {
        options.startCallback();
      }
      else {
        options.endCallback( self.overProperty.get() );
      }
    } );

    // interrupt listeners when enabled is set to false
    this.enabledProperty.link( function( enabled ) {
      if ( !enabled ) {
        for ( var i = 0; i < self.listeners.length; i++ ) {
          var listener = self.listeners[ i ];
          listener.interrupt && listener.interrupt();
        }
      }
    } );

    // @private
    this.disposeButtonModel = function() {

      // This will unlink all listeners, causing potential issues if listeners try to unlink properties afterwards
      this.overProperty.dispose();
      this.downProperty.dispose();
      this.enabledProperty.dispose();
      this.listeners = [];
    };
  }

  sun.register( 'ButtonModel', ButtonModel );

  return inherit( Object, ButtonModel, {

    /**
     * @public
     */
    dispose: function() {
      this.disposeButtonModel();
    },

    /**
     * Click the button by pressing the button down and then releasing after a timeout. When assistive technology is
     * used, the browser does not receive 'down' or 'up' events on buttons - only a single 'click' event. For a11y we
     * need to toggle the pressed state every 'click' event.
     * @param {function} [endListener] - optional function to be called once the button has been released after
     *                                   accessibility related interaction.
     * @public
     */
    a11yClick: function( endListener ) {
      if ( !this.downProperty.get() && this.enabledProperty.get() ) {

        // ensure that button is 'over' so listener can be called while button is down
        this.overProperty.set( true );
        this.downProperty.set( true );

        var self = this;
        // Timer.setTimeout( function() {

        // no longer down, don't reset 'over' so button can be styled as long as it has focus
        self.downProperty.set( false );

        endListener && endListener();
        // }, self._fireOnHoldInterval );
      }
    },

    /**
     * Button is no longer considered over on blur, unless blur was initiated by a 'down' event.
     *
     * @public
     */
    a11yBlur: function() {
      if ( !this.downProperty.get() ) {
        this.overProperty.value = false;
      }
    },

    /**
     * Creates a standard button listener that can be added to a node and that will trigger the changes to this model.
     * @param {Tandem} tandem
     * @returns {PressListener}
     * @public
     */
    createListener: function( tandem ) {
      var self = this;

      var pressListener = new PressListener( {
        tandem: tandem,
        phetioInstanceDocumentation: 'Indicates when the button has been pressed or released',
        isPressedProperty: this.downProperty,
        isOverProperty: this.overProperty,
        canStartPress: function() {
          return self.enabledProperty.value;
        }
      } );
      this.listeners.push( pressListener );
      return pressListener;
    }
  } );
} );<|endoftext|>


<commit_before>// Copyright 2002-2014, University of Colorado Boulder

/**
 * Demonstration of misc scenery-phet UI components
 *
 * @author Sam Reid
 * @author Chris Malley
 */
define( function( require ) {
  'use strict';

  // modules
  var Dimension2 = require( 'DOT/Dimension2' );
  var FaucetNode = require( 'SCENERY_PHET/FaucetNode' );
  var HSlider = require( 'SUN/HSlider' );
  var inherit = require( 'PHET_CORE/inherit' );
  var MeasuringTape = require( 'SCENERY_PHET/MeasuringTape' );
  var ModelViewTransform2 = require( 'PHETCOMMON/view/ModelViewTransform2' );
  var Node = require( 'SCENERY/nodes/Node' );
  var Property = require( 'AXON/Property' );
  var ResetAllButton = require( 'SCENERY_PHET/buttons/ResetAllButton' );
  var ScreenView = require( 'JOIST/ScreenView' );
  var StarNode = require( 'SCENERY_PHET/StarNode' );
  var ThermometerNode = require( 'SCENERY_PHET/ThermometerNode' );

  function ComponentsView() {

    ScreenView.call( this, {renderer: 'svg'} );

    // thermometer
    var temperatureProperty = new Property( 50 );
    var thermometer = new ThermometerNode( 0, 100, temperatureProperty, {
      right: this.layoutBounds.right - 100,
      bottom: this.layoutBounds.bottom - 20
    } );
    this.addChild( thermometer );
    var temperatureSlider = new HSlider( temperatureProperty, { min: 0, max: 100 }, {
      thumbSize: new Dimension2( 15, 30 ),
      thumbFillHighlighted: 'red',
      thumbFillEnabled: 'rgb(158,35,32)'
    } );
    temperatureSlider.rotation = -Math.PI / 2;
    temperatureSlider.right = thermometer.left - 10;
    temperatureSlider.centerY = thermometer.centerY;
    this.addChild( temperatureSlider );

    // measuring tape
    var measuringTapeScaleProperty = new Property( 0.5 );
    var measuringTapeUnitsProperty = new Property( { name: 'meters', multiplier: 1 } );
    var measuringTape = new MeasuringTape( new ModelViewTransform2.createIdentity(), measuringTapeUnitsProperty, new Property( true ), {
      textColor: 'black',
      unrolledTapeDistance: 100,
      dragBounds: this.layoutBounds,
      scaleProperty: measuringTapeScaleProperty
    } );
    this.addChild( measuringTape );
    var measuringTapeScaleSlider = new HSlider( measuringTapeScaleProperty, { min: 0.5, max: 2 }, {
      left: 50,
      top: measuringTape.bottom + 20
    } );
    this.addChild( measuringTapeScaleSlider );

    /*
     * Fill up a star by creating new StarNodes dynamically.
     * Shouldn't be a problem for sims since stars are relatively static.
     * Stars should be rewritten if they need to support smooth dynamic filling (may require mutable kite paths).
     */
    var starNodeContainer = new Node( {
      children: [new StarNode()],
      top: 20,
      right: this.layoutBounds.right - 20
    } );
    this.addChild( starNodeContainer );
    var starValueProperty = new Property( 1 );
    var starSlider = new HSlider( starValueProperty, { min: 0, max: 1 }, {
      thumbFillHighlighted: 'yellow',
      thumbFillEnabled: 'rgb(220,220,0)',
      thumbCenterLineStroke: 'black',
      right: starNodeContainer.right,
      top: starNodeContainer.bottom + 5
    } );
    this.addChild( starSlider );
    starValueProperty.link( function( value ) {
      starNodeContainer.children = [ new StarNode( { value: value } ) ];
    } );

    // faucet
    var fluidRateProperty = new Property( 5 );
    var faucetNode = new FaucetNode( 10, fluidRateProperty, new Property( true ), {
      left: 10,
      bottom: this.layoutBounds.bottom - 10
    } );
    this.addChild( faucetNode );

    // Reset All button
    var resetAllButton = new ResetAllButton( {
      listener: function() {
        temperatureProperty.reset();
        measuringTapeScaleProperty.reset();
        starValueProperty.reset();
        fluidRateProperty.reset();
      },
      radius: 22,
      right: this.layoutBounds.right - 10,
      bottom: this.layoutBounds.bottom - 10
    } );
    this.addChild( resetAllButton );
  }

  return inherit( ScreenView, ComponentsView );
} );<commit_msg>fix bug in MeasuringTape demo code, don't need to call new on ModelViewTransform when calling createIdentityTransform<commit_after>// Copyright 2002-2014, University of Colorado Boulder

/**
 * Demonstration of misc scenery-phet UI components
 *
 * @author Sam Reid
 * @author Chris Malley
 */
define( function( require ) {
  'use strict';

  // modules
  var Dimension2 = require( 'DOT/Dimension2' );
  var FaucetNode = require( 'SCENERY_PHET/FaucetNode' );
  var HSlider = require( 'SUN/HSlider' );
  var inherit = require( 'PHET_CORE/inherit' );
  var MeasuringTape = require( 'SCENERY_PHET/MeasuringTape' );
  var ModelViewTransform2 = require( 'PHETCOMMON/view/ModelViewTransform2' );
  var Node = require( 'SCENERY/nodes/Node' );
  var Property = require( 'AXON/Property' );
  var ResetAllButton = require( 'SCENERY_PHET/buttons/ResetAllButton' );
  var ScreenView = require( 'JOIST/ScreenView' );
  var StarNode = require( 'SCENERY_PHET/StarNode' );
  var ThermometerNode = require( 'SCENERY_PHET/ThermometerNode' );

  function ComponentsView() {

    ScreenView.call( this, {renderer: 'svg'} );

    // thermometer
    var temperatureProperty = new Property( 50 );
    var thermometer = new ThermometerNode( 0, 100, temperatureProperty, {
      right: this.layoutBounds.right - 100,
      bottom: this.layoutBounds.bottom - 20
    } );
    this.addChild( thermometer );
    var temperatureSlider = new HSlider( temperatureProperty, { min: 0, max: 100 }, {
      thumbSize: new Dimension2( 15, 30 ),
      thumbFillHighlighted: 'red',
      thumbFillEnabled: 'rgb(158,35,32)'
    } );
    temperatureSlider.rotation = -Math.PI / 2;
    temperatureSlider.right = thermometer.left - 10;
    temperatureSlider.centerY = thermometer.centerY;
    this.addChild( temperatureSlider );

    // measuring tape
    var measuringTapeScaleProperty = new Property( 0.5 );
    var measuringTapeUnitsProperty = new Property( { name: 'meters', multiplier: 1 } );
    var measuringTape = new MeasuringTape( ModelViewTransform2.createIdentity(), measuringTapeUnitsProperty, new Property( true ), {
      textColor: 'black',
      unrolledTapeDistance: 100,
      dragBounds: this.layoutBounds,
      scaleProperty: measuringTapeScaleProperty
    } );
    this.addChild( measuringTape );
    var measuringTapeScaleSlider = new HSlider( measuringTapeScaleProperty, { min: 0.5, max: 2 }, {
      left: 50,
      top: measuringTape.bottom + 20
    } );
    this.addChild( measuringTapeScaleSlider );

    /*
     * Fill up a star by creating new StarNodes dynamically.
     * Shouldn't be a problem for sims since stars are relatively static.
     * Stars should be rewritten if they need to support smooth dynamic filling (may require mutable kite paths).
     */
    var starNodeContainer = new Node( {
      children: [new StarNode()],
      top: 20,
      right: this.layoutBounds.right - 20
    } );
    this.addChild( starNodeContainer );
    var starValueProperty = new Property( 1 );
    var starSlider = new HSlider( starValueProperty, { min: 0, max: 1 }, {
      thumbFillHighlighted: 'yellow',
      thumbFillEnabled: 'rgb(220,220,0)',
      thumbCenterLineStroke: 'black',
      right: starNodeContainer.right,
      top: starNodeContainer.bottom + 5
    } );
    this.addChild( starSlider );
    starValueProperty.link( function( value ) {
      starNodeContainer.children = [ new StarNode( { value: value } ) ];
    } );

    // faucet
    var fluidRateProperty = new Property( 5 );
    var faucetNode = new FaucetNode( 10, fluidRateProperty, new Property( true ), {
      left: 10,
      bottom: this.layoutBounds.bottom - 10
    } );
    this.addChild( faucetNode );

    // Reset All button
    var resetAllButton = new ResetAllButton( {
      listener: function() {
        temperatureProperty.reset();
        measuringTapeScaleProperty.reset();
        starValueProperty.reset();
        fluidRateProperty.reset();
      },
      radius: 22,
      right: this.layoutBounds.right - 10,
      bottom: this.layoutBounds.bottom - 10
    } );
    this.addChild( resetAllButton );
  }

  return inherit( ScreenView, ComponentsView );
} );<|endoftext|>


<commit_before>(function( $ ){
  var $EL;
  var listItem = 0;
  var MY_CONSTANT = 'value';
  var accordionHeight = "12";
  var sectionWidth = 0;
  var windowSize = 0;
  var total_pages = 0;
  var listItem = 0;
  var position = 0;
  var settings = {};
  var defaults = {
    DEBUG: false,
    defaultOptionA: 'defaultValue',
    speed: 1000
  }
  var methods = {

     init : function( options ) {
       $EL = this;
       settings = $.extend({}, defaults, options);

       total_pages = $EL.find(".section").length;
       accordionHeight = parseInt($EL.children(".section").first().css("width"));
       methods._setWindowSize();

       $EL.children(".section").each(function(index) {
         sectionWidth += parseInt($(this).outerWidth(true));
       });
       $EL.css("width", "110%");
       var iW = methods._hz_innerWidth();
       $EL.find(".section .fixed").each(function( index ) {
         $(this).css("width", iW);
       });
       $EL.children(".section").first().addClass("active");
       $EL.find(".active").css("width", methods._hz_outerWidth());

       $EL.on("click", ".section", function(event) {
         event.preventDefault();
         if (!$(this).hasClass("active")) {
           $(this).parent().children(".section").each(function(index, value) {
             if ($(this).is(".active")) {
               $(this).addClass("closing");
             }
           });
           $(this).addClass("opening active");
           methods._animateMethod();
         }
       });

       $(document).keydown(function(e) {
         if (e.keyCode === 37) {
           methods._next_slide();
         } else if (e.keyCode === 38) {
           methods._slide(0);
         } else if (e.keyCode === 39) {
           methods._prev_slide();
         } else if (e.keyCode === 40) {
           methods._slide(total_pages);
         }
       });

       $(window).resize(function() {
         $EL.css("width", "110%");
         methods._setWindowSize();
         methods._simpleMethod();
       });

       return this.each(function(){
         $(window).bind('reset.horizontalAccordion', methods.reset);
       });

     },
     destroy : function( ) {

       return this.each(function(){
         $(window).unbind('.horizontalAccordion');
       })

     },
     reset : function( ) {
       // ...
     },

     /** #### PUBLIC METHODS #### */
     publicMethod : function ()
     {
         console.log('inside publicMethod!');
         return $EL;        // support jQuery chaining
     },

     hide : function( ) {
       // ...
     },
     update : function( content ) {
       // ...
     },
     next : function( ) {
       methods._next_slide();
       return $EL;        // support jQuery chaining
     },
     prev : function(){
       methods._prev_slide();
       return $EL;        // support jQuery chaining

     },
     slide : function( num ) {
       // ...
     },

     /** #### PRIVATE METHODS #### */
     _privateMethod : function ()
     {
       console.log($myEL);
     },

     _simpleMethod : function() {
       console.log($EL);
       $EL.children(".closing").removeClass("active");
       $EL.children(".section").css("width", accordionHeight);
       $EL.find(".active").css("width", methods._hz_outerWidth());
       $EL.find(".active .fixed").css("width", methods._hz_innerWidth());
       $EL.children(".section").removeClass("closing");
     },

     _animateMethod : function() {
       $EL.find(".opening .fixed").css("width", methods._hz_innerWidth());
       $EL.find(".closing").animate({
         width: accordionHeight
       }, settings.speed, "linear", function() {
         $EL.children(".section").removeClass("active").removeClass("closing");
       });
       $EL.find(".opening").animate({
         width: methods._hz_outerWidth()
       }, settings.speed, "linear", function() {
         $EL.children(".section").removeClass("active").removeClass("opening");
         $(this).addClass("active");
       });
     },

     _setWindowSize : function() {
       var oldWidth;
       oldWidth = void 0;
       oldWidth = $EL.css("width");
       $EL.css("width", "100%");
       windowSize = $EL.outerWidth(true);
       $EL.css("width", oldWidth);
     },

     _hz_innerWidth : function() {
       var iW;
       iW = void 0;
       iW = parseInt(methods._hz_outerWidth() - (2 * accordionHeight - 25));
       return iW;
     },

     _hz_outerWidth : function() {
       var oW = windowSize - sectionWidth + 5;
       return oW;
     },

     _next_slide : function() {
       listItem = $EL.find(".active");
       position = (listItem.index(".section") + 1) % total_pages;
       $EL.find(".active").addClass("closing");
       $EL.find(".section").eq(position).addClass("opening active");
       methods._animateMethod();
     },

     _prev_slide : function() {
       listItem = $EL.find(".active");
       position = (listItem.index(".section") - 1) % total_pages;
       $EL.find(".active").addClass("closing");
       $EL.find(".section").eq(position).addClass("opening active");
       methods._animateMethod();
     },

     _slide : function(num) {
       listItem = $EL.find(".active");
       if (listItem.index(".section") === num) {
         return console.log("hahahah");
       } else {
         $EL.find(".active").addClass("closing");
         $EL.find(".section").eq(num).addClass("opening active");
         methods._animateMethod();
       }
     },

  };

  $.fn.horizontalAccordion = function( method ) {

    if ( methods[method] ) {
      if ( String(method).indexOf('_') == 0 ){
        $.error( 'Method ' + method + ' is a private function of jQuery.horizontalAccordion' );
      }else{
        return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
      }
    } else if ( typeof method === 'object' || ! method ) {
      return methods.init.apply( this, arguments );
    } else {
      $.error( 'Method ' + method + ' does not exist on jQuery.horizontalAccordion' );
    }

  };

})( jQuery );

<commit_msg>update with more options<commit_after>(function( $ ){
  var $EL;
  var listItem = 0;
  var MY_CONSTANT = 'value';
  var accordionHeight = "12";
  var sectionWidth = 0;
  var windowSize = 0;
  var total_pages = 0;
  var listItem = 0;
  var position = 0;
  var settings = {};
  var defaults = {
    DEBUG: false,
    click: true,
    resize: true,
    key: true,

    defaultOptionA: 'defaultValue',
    speed: 1000
  }
  var methods = {

     init : function( options ) {
       $EL = this;
       settings = $.extend({}, defaults, options);

       total_pages = $EL.find(".section").length;
       accordionHeight = parseInt($EL.children(".section").first().css("width"));
       methods._setWindowSize();

       $EL.children(".section").each(function(index) {
         sectionWidth += parseInt($(this).outerWidth(true));
       });
       $EL.css("width", "110%");
       var iW = methods._hz_innerWidth();
       $EL.find(".section .fixed").each(function( index ) {
         $(this).css("width", iW);
       });
       $EL.children(".section").first().addClass("active");
       $EL.find(".active").css("width", methods._hz_outerWidth());

       if( settings.click ){
         console.log(settings.click);
         methods._click_init();
       };

      if( settings.key ){
        methods._key_press();
      };
      if( settings.resize ){
        methods._resize();
      };
       return this.each(function(){
         $(window).bind('reset.horizontalAccordion', methods.reset);
       });

     },

     /** #### PUBLIC METHODS #### */
     destroy : function( ) {

       return this.each(function(){
         $(window).unbind('.horizontalAccordion');
       })

     },
     reset : function( ) {
       // ...
     },
     publicMethod : function ()
     {
         console.log('inside publicMethod!');
         return $EL;        // support jQuery chaining
     },
     hide : function( ) {
       // ...
     },
     update : function( content ) {
       // ...
     },
     next : function( ) {
       methods._next_slide();
       return $EL;        // support jQuery chaining
     },
     prev : function(){
       methods._prev_slide();
       return $EL;        // support jQuery chaining

     },
     slide : function( num ) {
       // ...
     },

     /** #### PRIVATE METHODS #### */
     _privateMethod : function ()
     {
       console.log($myEL);
     },

     _key_press : function(){
       $(document).keydown(function(e) {
         if (e.keyCode === 37) {
           methods._next_slide();
         } else if (e.keyCode === 38) {
           methods._slide(0);
         } else if (e.keyCode === 39) {
           methods._prev_slide();
         } else if (e.keyCode === 40) {
           methods._slide(total_pages);
         }
       });
     },

     _resize : function(){
       $(window).resize(function() {
         $EL.css("width", "110%");
         methods._setWindowSize();
         methods._simpleMethod();
       });
     },

     _click_init : function(){
       $EL.on("click", ".section", function(event) {
         event.preventDefault();
         if (!$(this).hasClass("active")) {
           $(this).parent().children(".section").each(function(index, value) {
             if ($(this).is(".active")) {
               $(this).addClass("closing");
             }
           });
           $(this).addClass("opening active");
           methods._animateMethod();
         }
       });
     }

     _simpleMethod : function() {
       console.log($EL);
       $EL.children(".closing").removeClass("active");
       $EL.children(".section").css("width", accordionHeight);
       $EL.find(".active").css("width", methods._hz_outerWidth());
       $EL.find(".active .fixed").css("width", methods._hz_innerWidth());
       $EL.children(".section").removeClass("closing");
     },

     _animateMethod : function() {
       $EL.find(".opening .fixed").css("width", methods._hz_innerWidth());
       $EL.find(".closing").animate({
         width: accordionHeight
       }, settings.speed, "linear", function() {
         $EL.children(".section").removeClass("active").removeClass("closing");
       });
       $EL.find(".opening").animate({
         width: methods._hz_outerWidth()
       }, settings.speed, "linear", function() {
         $EL.children(".section").removeClass("active").removeClass("opening");
         $(this).addClass("active");
       });
     },

     _setWindowSize : function() {
       var oldWidth;
       oldWidth = void 0;
       oldWidth = $EL.css("width");
       $EL.css("width", "100%");
       windowSize = $EL.outerWidth(true);
       $EL.css("width", oldWidth);
     },

     _hz_innerWidth : function() {
       var iW;
       iW = void 0;
       iW = parseInt(methods._hz_outerWidth() - (2 * accordionHeight - 25));
       return iW;
     },

     _hz_outerWidth : function() {
       var oW = windowSize - sectionWidth + 5;
       return oW;
     },

     _next_slide : function() {
       listItem = $EL.find(".active");
       position = (listItem.index(".section") + 1) % total_pages;
       $EL.find(".active").addClass("closing");
       $EL.find(".section").eq(position).addClass("opening active");
       methods._animateMethod();
     },

     _prev_slide : function() {
       listItem = $EL.find(".active");
       position = (listItem.index(".section") - 1) % total_pages;
       $EL.find(".active").addClass("closing");
       $EL.find(".section").eq(position).addClass("opening active");
       methods._animateMethod();
     },

     _slide : function(num) {
       listItem = $EL.find(".active");
       if (listItem.index(".section") === num) {
         return console.log("hahahah");
       } else {
         $EL.find(".active").addClass("closing");
         $EL.find(".section").eq(num).addClass("opening active");
         methods._animateMethod();
       }
     },

  };

  $.fn.horizontalAccordion = function( method ) {

    if ( methods[method] ) {
      if ( String(method).indexOf('_') == 0 ){
        $.error( 'Method ' + method + ' is a private function of jQuery.horizontalAccordion' );
      }else{
        return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
      }
    } else if ( typeof method === 'object' || ! method ) {
      return methods.init.apply( this, arguments );
    } else {
      $.error( 'Method ' + method + ' does not exist on jQuery.horizontalAccordion' );
    }

  };

})( jQuery );

<|endoftext|>


<commit_before>//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
//>>description: Popup windows.
//>>label: Popups

define( [ "jquery",
	"jquery.mobile.widget",
	"jquery.mobile.navigation",
	"../external/requirejs/depend!./jquery.mobile.hashchange[jquery]" ], function( $ ) {
//>>excludeEnd("jqmBuildExclude");
(function( $, undefined ) {

	$.widget( "mobile.popup", $.mobile.widget, {
		options: {
			theme: null,
			overlayTheme: null,
			shadow: true,
			corners: true,
			fade: true,
			transition: $.mobile.defaultDialogTransition,
			initSelector: ":jqmData(role='popup')"
		},

		_create: function() {
			var ui = {
					screen: "#ui-popup-screen",
					container: "#ui-popup-container"
				},
				proto = $(
					"
" +
					"

" +
					"

" +
					"
"
				),
				thisPage = this.element.closest( ":jqmData(role='page')" ),
				self = this;

			if ( thisPage.length === 0 ) {
				thisPage = $( "body" );
			}

			// Assign the relevant parts of the proto
			for ( var key in ui ) {
				ui[ key ] = proto.find( ui[ key ] ).removeAttr( "id" );
			}

			// Apply the proto
			thisPage.append( ui.screen );
			ui.container.insertAfter( ui.screen );
			ui.container.append( this.element );

			// Define instance variables
			$.extend( this, {
				_ui: ui,
				_isOpen: false
			});

			$.each( this.options, function( key ) {
				// Cause initial options to be applied by their handler by temporarily setting the option to undefined
				// - the handler then sets it to the initial value
				var value = self.options[ key ];

				self.options[ key ] = undefined;
				self._setOption( key, value, true );
			});

			ui.screen.bind( "vclick", function( e ) {
				e.preventDefault();
				e.stopImmediatePropagation();
				self.close();
			});
		},

		_realSetTheme: function( dst, theme ) {
			var classes = ( dst.attr( "class" ) || "").split( " " ),
				alreadyAdded = true,
				currentTheme = null,
				matches;

			theme = String( theme );
			while ( classes.length > 0 ) {
				currentTheme = classes.pop();
				matches = currentTheme.match( /^ui-body-([a-z])$/ );
				if ( matches && matches.length > 1 ) {
					currentTheme = matches[ 1 ];
					break;
				} else {
					currentTheme = null;
				}
			}

			if ( theme !== currentTheme ) {
				dst.removeClass( "ui-body-" + currentTheme );
				if ( theme !== null ) {
					dst.addClass( "ui-body-" + theme );
				}
			}
		},

		_setTheme: function( value ) {
			this._realSetTheme( this.element, value );
			this.options.theme = value;
			this.element.attr( "data-" + ( $.mobile.ns || "" ) + "theme", value );
		},

		_setOverlayTheme: function( value ) {
			this._realSetTheme( this._ui.container, value );
			// The screen must always have some kind of background for fade to work, so, if the theme is being unset,
			// set the background to "a".
			this._realSetTheme( this._ui.screen, (value === "" ? "a" : value) );
			this.options.overlayTheme = value;
			this.element.attr( "data-" + ( $.mobile.ns || "" ) + "overlay-theme", value );
		},

		_setShadow: function( value ) {
			this._ui.container[value ? "addClass" : "removeClass"]( "ui-overlay-shadow" );
			this.options.shadow = value;
			this.element.attr( "data-" + ( $.mobile.ns || "" ) + "shadow", value );
		},

		_setCorners: function( value ) {
			this._ui.container[value ? "addClass" : "removeClass"]( "ui-corner-all" );
			this.options.corners = value;
			this.element.attr( "data-" + ( $.mobile.ns || "" ) + "corners", value );
		},

		_setFade: function( value ) {
			this.options.fade = value;
			this.element.attr( "data-" + ( $.mobile.ns || "" ) + "fade", value );
		},

		_setTransition: function( value ) {
			this._ui.container.removeClass( this.options.transition || "" );
			if ( value && value !== "none" ) {
				this._ui.container.addClass( value );
			}
			this.options.transition = value;
			this.element.attr( "data-" + ( $.mobile.ns || "" ) + "transition", value );
		},

		_setOption: function( key, value ) {
			var setter = "_set" + key.replace( /^[a-z]/, function(c) {
				return c.toUpperCase();
			});

			if ( this[setter] !== undefined ) {
				this[setter]( value );
			} else {
				$.mobile.widget.prototype._setOption.apply( this, arguments );
			}
		},

		_placementCoords: function( x, y ) {
			// Try and center the overlay over the given coordinates
			var ret,
				menuHeight = this._ui.container.outerHeight( true ),
				menuWidth = this._ui.container.outerWidth( true ),
				scrollTop = $( window ).scrollTop(),
				screenHeight = $( window ).height(),
				screenWidth = $( window ).width(),
				halfheight = menuHeight / 2,
				maxwidth = parseFloat( this._ui.container.css( "max-width" ) ),
				roomtop = y - scrollTop,
				roombot = scrollTop + screenHeight - y,
				newtop, newleft;

			if ( roomtop > menuHeight / 2 && roombot > menuHeight / 2 ) {
				newtop = y - halfheight;
			} else {
				// 30px tolerance off the edges
				newtop = roomtop > roombot ? scrollTop + screenHeight - menuHeight - 30 : scrollTop + 30;
			}

			// If the menuwidth is smaller than the screen center is
			if ( menuWidth < maxwidth ) {
				newleft = ( screenWidth - menuWidth ) / 2;
			} else {
				//otherwise insure a >= 30px offset from the left
				newleft = x - menuWidth / 2;

				// 10px tolerance off the edges
				if ( newleft < 10 ) {
					newleft = 10;
				} else if ( ( newleft + menuWidth ) > screenWidth ) {
					newleft = screenWidth - menuWidth - 10;
				}
			}

			return { x: newleft, y: newtop };
		},

		_bindHashChange: function() {
			var self = this;
			$( window ).one( "hashchange.popup", function() {
				self.close( true );
			});
		},

		_unbindHashChange: function() {
			$( window ).unbind( "hashchange.popup" );
		},

		open: function( x, y ) {
			if ( !this._isOpen ) {
				var self = this,
					onAnimationComplete = function() {
						self._ui.screen.height( $( document ).height() );
					},
					coords = this._placementCoords(
							(undefined === x ? window.innerWidth / 2 : x),
							(undefined === y ? window.innerHeight / 2 : y) );

				this._ui.screen
						.height( $( document ).height() )
						.removeClass( "ui-screen-hidden" );

				if ( this.options.fade ) {
					this._ui.screen.animate( {opacity: 0.5}, "fast" );
				}

				this._ui.container
					.removeClass( "ui-selectmenu-hidden" )
					.css( {
						left: coords.x,
						top: coords.y
					});

				if ( this.options.transition && this.options.transition !== "none" ) {
					this._ui.container
						.addClass( "in" )
						.animationComplete( onAnimationComplete );
				} else {
					onAnimationComplete();
				}

				// listen for hashchange that will occur when we set it to null dialog hash
				$( window ).one( "hashchange", function() {
					self._bindHashChange();
				});

				// set hash to non-linkable dialog url
				$.mobile.path.set( ( ( $.mobile.activePage != $.mobile.firstPage) ? $.mobile.urlHistory.getActive().url : "" ) + "&ui-state=dialog" );

				this._isOpen = true;
			}
		},

		close: function( fromHash ) {
			if ( this._isOpen ) {
				var self = this,
					onAnimationComplete = function() {
						self._ui.container
							.removeClass( "reverse out" )
							.addClass( "ui-selectmenu-hidden" )
							.removeAttr( "style" );
					},
					hideScreen = function() {
						self._ui.screen.addClass( "ui-screen-hidden" );
						self._isOpen = false;
						self.element.trigger( "closed" );
						self._ui.screen.removeAttr( "style" );
					};

				if ( this.options.transition && this.options.transition !== "none" ) {
					this._ui.container
						.removeClass( "in" )
						.addClass( "reverse out" )
						.animationComplete( onAnimationComplete );
				} else {
					onAnimationComplete();
				}

				if ( this.options.fade ) {
					this._ui.screen.animate( {opacity: 0.0}, "fast", hideScreen );
				} else {
					hideScreen();
				}

				// unbind listener that comes with opening popup
				this._unbindHashChange();

				// if the close event did not come from an internal hash listener, reset URL back
				if ( !fromHash ) {
					window.history.back();
				}
			}
		}
	});

	$.mobile.popup.bindPopupToButton = function( btn, popup ) {
		if ( btn.length === 0 || popup.length === 0 ) return;

		var btnVClickHandler = function( e ) {
			// When /this/ button causes a popup, align the popup's theme with that of the button, unless the popup has a theme pre-set
			if ( !popup.jqmData( "overlay-theme-set" ) ) {
				popup.popup( "option", "overlayTheme", btn.jqmData( "theme" ) );
			}
			popup.popup( "open",
					btn.offset().left + btn.outerWidth() / 2,
					btn.offset().top + btn.outerHeight() / 2 );

			// Swallow event, because it might end up getting picked up by the popup window's screen handler, which
			// will in turn cause the popup window to close - Thanks Sasha!
			if ( e.stopPropagation ) {
				e.stopPropagation();
			}
			if ( e.preventDefault ) {
				e.preventDefault();
			}
		};

		// If the popup has a theme set, prevent it from being clobbered by the associated button
		if ( (popup.popup( "option", "overlayTheme" ) || "").match( /[a-z]/ ) ) {
			popup.jqmData( "overlay-theme-set", true );
		}

		btn.attr( {
			"aria-haspopup": true,
			"aria-owns": btn.attr( "href" )
		})
			.removeAttr( "href" )
			.bind( "vclick", btnVClickHandler );
	};

	$( document ).bind( "pagecreate create", function( e )  {
		$( $.mobile.popup.prototype.options.initSelector, e.target )
				.not( ":jqmData(role='none'), :jqmData(role='nojs')" )
				.popup();

		$( "a[href^='#']:jqmData(rel='popup')", e.target ).each( function() {
			$.mobile.popup.bindPopupToButton( $( this ), $( $( this ).attr( "href" ) ) );
		});
	});

})( jQuery );
//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
});
//>>excludeEnd("jqmBuildExclude");
<commit_msg>Added a changebeforechange handler to handle navigation from the popup without leaving traces of the popup in the history. If a changePage happens when a popup is open, we capture it and first go back (to close the popup and clean the history) then call changePage.<commit_after>//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
//>>description: Popup windows.
//>>label: Popups

define( [ "jquery",
	"jquery.mobile.widget",
	"jquery.mobile.navigation",
	"../external/requirejs/depend!./jquery.mobile.hashchange[jquery]" ], function( $ ) {
//>>excludeEnd("jqmBuildExclude");
(function( $, undefined ) {

	$.widget( "mobile.popup", $.mobile.widget, {
		options: {
			theme: null,
			overlayTheme: null,
			shadow: true,
			corners: true,
			fade: true,
			transition: $.mobile.defaultDialogTransition,
			initSelector: ":jqmData(role='popup')"
		},

		_create: function() {
			var ui = {
					screen: "#ui-popup-screen",
					container: "#ui-popup-container"
				},
				proto = $(
					"
" +
					"

" +
					"

" +
					"
"
				),
				thisPage = this.element.closest( ":jqmData(role='page')" ),
				self = this;

			if ( thisPage.length === 0 ) {
				thisPage = $( "body" );
			}

			// Assign the relevant parts of the proto
			for ( var key in ui ) {
				ui[ key ] = proto.find( ui[ key ] ).removeAttr( "id" );
			}

			// Apply the proto
			thisPage.append( ui.screen );
			ui.container.insertAfter( ui.screen );
			ui.container.append( this.element );

			// Define instance variables
			$.extend( this, {
				_ui: ui,
				_isOpen: false
			});

			$.each( this.options, function( key ) {
				// Cause initial options to be applied by their handler by temporarily setting the option to undefined
				// - the handler then sets it to the initial value
				var value = self.options[ key ];

				self.options[ key ] = undefined;
				self._setOption( key, value, true );
			});

			ui.screen.bind( "vclick", function( e ) {
				e.preventDefault();
				e.stopImmediatePropagation();
				self.close();
			});
		},

		_realSetTheme: function( dst, theme ) {
			var classes = ( dst.attr( "class" ) || "").split( " " ),
				alreadyAdded = true,
				currentTheme = null,
				matches;

			theme = String( theme );
			while ( classes.length > 0 ) {
				currentTheme = classes.pop();
				matches = currentTheme.match( /^ui-body-([a-z])$/ );
				if ( matches && matches.length > 1 ) {
					currentTheme = matches[ 1 ];
					break;
				} else {
					currentTheme = null;
				}
			}

			if ( theme !== currentTheme ) {
				dst.removeClass( "ui-body-" + currentTheme );
				if ( theme !== null ) {
					dst.addClass( "ui-body-" + theme );
				}
			}
		},

		_setTheme: function( value ) {
			this._realSetTheme( this.element, value );
			this.options.theme = value;
			this.element.attr( "data-" + ( $.mobile.ns || "" ) + "theme", value );
		},

		_setOverlayTheme: function( value ) {
			this._realSetTheme( this._ui.container, value );
			// The screen must always have some kind of background for fade to work, so, if the theme is being unset,
			// set the background to "a".
			this._realSetTheme( this._ui.screen, (value === "" ? "a" : value) );
			this.options.overlayTheme = value;
			this.element.attr( "data-" + ( $.mobile.ns || "" ) + "overlay-theme", value );
		},

		_setShadow: function( value ) {
			this._ui.container[value ? "addClass" : "removeClass"]( "ui-overlay-shadow" );
			this.options.shadow = value;
			this.element.attr( "data-" + ( $.mobile.ns || "" ) + "shadow", value );
		},

		_setCorners: function( value ) {
			this._ui.container[value ? "addClass" : "removeClass"]( "ui-corner-all" );
			this.options.corners = value;
			this.element.attr( "data-" + ( $.mobile.ns || "" ) + "corners", value );
		},

		_setFade: function( value ) {
			this.options.fade = value;
			this.element.attr( "data-" + ( $.mobile.ns || "" ) + "fade", value );
		},

		_setTransition: function( value ) {
			this._ui.container.removeClass( this.options.transition || "" );
			if ( value && value !== "none" ) {
				this._ui.container.addClass( value );
			}
			this.options.transition = value;
			this.element.attr( "data-" + ( $.mobile.ns || "" ) + "transition", value );
		},

		_setOption: function( key, value ) {
			var setter = "_set" + key.replace( /^[a-z]/, function(c) {
				return c.toUpperCase();
			});

			if ( this[setter] !== undefined ) {
				this[setter]( value );
			} else {
				$.mobile.widget.prototype._setOption.apply( this, arguments );
			}
		},

		_placementCoords: function( x, y ) {
			// Try and center the overlay over the given coordinates
			var ret,
				menuHeight = this._ui.container.outerHeight( true ),
				menuWidth = this._ui.container.outerWidth( true ),
				scrollTop = $( window ).scrollTop(),
				screenHeight = $( window ).height(),
				screenWidth = $( window ).width(),
				halfheight = menuHeight / 2,
				maxwidth = parseFloat( this._ui.container.css( "max-width" ) ),
				roomtop = y - scrollTop,
				roombot = scrollTop + screenHeight - y,
				newtop, newleft;

			if ( roomtop > menuHeight / 2 && roombot > menuHeight / 2 ) {
				newtop = y - halfheight;
			} else {
				// 30px tolerance off the edges
				newtop = roomtop > roombot ? scrollTop + screenHeight - menuHeight - 30 : scrollTop + 30;
			}

			// If the menuwidth is smaller than the screen center is
			if ( menuWidth < maxwidth ) {
				newleft = ( screenWidth - menuWidth ) / 2;
			} else {
				//otherwise insure a >= 30px offset from the left
				newleft = x - menuWidth / 2;

				// 10px tolerance off the edges
				if ( newleft < 10 ) {
					newleft = 10;
				} else if ( ( newleft + menuWidth ) > screenWidth ) {
					newleft = screenWidth - menuWidth - 10;
				}
			}

			return { x: newleft, y: newtop };
		},

		_bindHashChange: function() {
			var self = this;
			$( window ).one( "hashchange.popup", function() {
				self.close( true );
			});
		},

		_unbindHashChange: function() {
			$( window ).unbind( "hashchange.popup" );
		},

		_onPageBeforeChange: function( e, data ) {
			if ( typeof( data.toPage ) === "object" && data.toPage.jqmData( "url" ) !== $.mobile.activePage.jqmData( "url" ) ) {
				// Prevent the changePage from happening
				e.preventDefault();
				e.stopImmediatePropagation();

				setTimeout( function() {
					// Resume the changePage
					$.mobile.changePage( data.toPage, data.options );
				}, 250);

				this.close();
			}
		},

		open: function( x, y ) {
			if ( !this._isOpen ) {
				var self = this,
					onAnimationComplete = function() {
						self._ui.screen.height( $( document ).height() );
					},
					coords = this._placementCoords(
							(undefined === x ? window.innerWidth / 2 : x),
							(undefined === y ? window.innerHeight / 2 : y) );

				this._ui.screen
						.height( $( document ).height() )
						.removeClass( "ui-screen-hidden" );

				if ( this.options.fade ) {
					this._ui.screen.animate( {opacity: 0.5}, "fast" );
				}

				this._ui.container
					.removeClass( "ui-selectmenu-hidden" )
					.css( {
						left: coords.x,
						top: coords.y
					});

				if ( this.options.transition && this.options.transition !== "none" ) {
					this._ui.container
						.addClass( "in" )
						.animationComplete( onAnimationComplete );
				} else {
					onAnimationComplete();
				}

				// listen for hashchange that will occur when we set it to null dialog hash
				$( window ).one( "hashchange", function() {
					self._bindHashChange();
				});

				$( window ).bind( "pagebeforechange.popup", $.proxy( this, "_onPageBeforeChange" ) );

				// set hash to non-linkable dialog url
				$.mobile.path.set( ( ( $.mobile.activePage != $.mobile.firstPage) ? $.mobile.urlHistory.getActive().url : "" ) + "&ui-state=dialog" );

				this._isOpen = true;
			}
		},

		close: function( fromHash ) {
			if ( this._isOpen ) {
				var self = this,
					onAnimationComplete = function() {
						self._ui.container
							.removeClass( "reverse out" )
							.addClass( "ui-selectmenu-hidden" )
							.removeAttr( "style" );
					},
					hideScreen = function() {
						self._ui.screen.addClass( "ui-screen-hidden" );
						self._isOpen = false;
						self.element.trigger( "closed" );
						self._ui.screen.removeAttr( "style" );
					};

				if ( this.options.transition && this.options.transition !== "none" ) {
					this._ui.container
						.removeClass( "in" )
						.addClass( "reverse out" )
						.animationComplete( onAnimationComplete );
				} else {
					onAnimationComplete();
				}

				if ( this.options.fade ) {
					this._ui.screen.animate( {opacity: 0.0}, "fast", hideScreen );
				} else {
					hideScreen();
				}

				// unbind listener that comes with opening popup
				this._unbindHashChange();
				$( window ).unbind( "pagebeforechange.popup" );

				// if the close event did not come from an internal hash listener, reset URL back
				if ( !fromHash ) {
					window.history.back();
				}
			}
		}
	});

	$.mobile.popup.bindPopupToButton = function( btn, popup ) {
		if ( btn.length === 0 || popup.length === 0 ) return;

		var btnVClickHandler = function( e ) {
			// When /this/ button causes a popup, align the popup's theme with that of the button, unless the popup has a theme pre-set
			if ( !popup.jqmData( "overlay-theme-set" ) ) {
				popup.popup( "option", "overlayTheme", btn.jqmData( "theme" ) );
			}
			popup.popup( "open",
					btn.offset().left + btn.outerWidth() / 2,
					btn.offset().top + btn.outerHeight() / 2 );

			// Swallow event, because it might end up getting picked up by the popup window's screen handler, which
			// will in turn cause the popup window to close - Thanks Sasha!
			if ( e.stopPropagation ) {
				e.stopPropagation();
			}
			if ( e.preventDefault ) {
				e.preventDefault();
			}
		};

		// If the popup has a theme set, prevent it from being clobbered by the associated button
		if ( (popup.popup( "option", "overlayTheme" ) || "").match( /[a-z]/ ) ) {
			popup.jqmData( "overlay-theme-set", true );
		}

		btn.attr( {
			"aria-haspopup": true,
			"aria-owns": btn.attr( "href" )
		})
			.removeAttr( "href" )
			.bind( "vclick", btnVClickHandler );
	};

	$( document ).bind( "pagecreate create", function( e )  {
		$( $.mobile.popup.prototype.options.initSelector, e.target )
				.not( ":jqmData(role='none'), :jqmData(role='nojs')" )
				.popup();

		$( "a[href^='#']:jqmData(rel='popup')", e.target ).each( function() {
			$.mobile.popup.bindPopupToButton( $( this ), $( $( this ).attr( "href" ) ) );
		});
	});

})( jQuery );
//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
});
//>>excludeEnd("jqmBuildExclude");
<|endoftext|>