<commit_before>/*
  @author: Seven Lju
  @date: 2015-02-18

  a template reader for web application.
 */
var $petal;
if($petal == null) $petal = {};

(function($petal, $win, $doc) {

var ajax = {
  _nop: function () {},
  resource: function (name, path, async) {
    if (async !== true) async = false;
    return $.ajax({
      url: path,
      method: 'GET',
      async: async
    });
  }
};

var component = {
  designView: false,
  cache: {},
  load: function (name, path, async) {
    if (component.cache[name]) return null;
    return ajax.resource(name, path, async).done(function (html) {
      component.cache[name] = html;
    });
  },
  _appendDom: function (dom, elements, templates) {
    var id = $(dom).attr('tag');
    if (!id) {
      component._searchDom(dom, elements, templates);
      return;
    }
    switch (id.charCodeAt(0)) {
    case 93: // ']', array element
      id = id.substring(1);
      if (!$.isArray(elements[id])) elements[id] = [];
      elements[id].push(dom);
      component._searchDom(dom, elements, templates);
      break;
    case 64: // '@', nest
      var subelements = {}, subtemplates = {};
      id = id.substring(1);
      elements[id] = {
        self: dom,
        dom: subelements,
        template: subtemplates
      }
      component._searchDom(dom, subelements, subtemplates);
      break;
    case 43: // '+', template
      id = id.substring(1);
      if (!component.designView) {
        $(dom).removeAttr('tag');
        templates[id] = $(dom).prop('outerHTML');
        $(dom).remove();
        break;
      }
      // if in design view, we can see the template as a dom
      // in browser; thus here should not have a break
    default:
      if (elements[id]) {
        if (!elements[id].length) {
          elements[id] = [elements[id], dom];
        } else {
          elements[id].push(dom);
        }
      } else {
        elements[id] = dom;
      }
      component._searchDom(dom, elements, templates);
    }
  },
  _searchDom: function (dom, elements, templates) {
    var ch = $(dom).children();
    var n = ch.length;
    if (n <= 0) return;
    var i;
    for (i=0; i<n; i++) {
      component._appendDom(ch[i], elements, templates);
    }
  },
  /* e.g.
    partial.html

        Name: <input tag="txt_name" type="text" />

A	B

              loading...
              loading...

        XYZ

    index.js
      $petal.ui.load('partial', 'partial.html', false);
      var control = $petal.ui.create('partial');
      $(control.dom.txt_name).val("hello world");
      $(control.dom.link[0]).click(function () { alert("0"); });
      $(control.dom.link[1]).click(function () { alert("1"); });
      $(control.dom.link[2]).click(function () { alert("2"); });
      var item = $petal.ui.createT(control.template.item);
      $(item.dom.txt_a).text("hello");
      $(item.dom.txt_b).text("world");
      $(control.dom.items).append(item.self);
      $(control.dom.nest.dom.test).text('seprate world!');
      $(document.body).append(control.self);
  */
  createT: function (template, control) {
    if (!template) return null;
    if (!control) control = {};
    var elements = {}, templates = {};
    var dom = $(template);
    if (dom.length === 1) {
      component._searchDom(dom, elements, templates);
    } else {
      for (var i = 0, n = dom.length; i < n; i++) {
        component._searchDom($(dom[i]), elements, templates);
      }
    }
    control.self = dom;
    control.dom = elements;
    control.template = templates;
    return control;
  },
  create: function (name, control) {
    return component.createT(component.cache[name], control);
  },
  empty: function (id) {
    var i, n, ch;
    ch = component.dom(id).children();
    n = ch.length;
    for (i=0; i<n; i++) {
      $(ch[i]).remove();
    }
  },
  view: function (control, id) {
    if (id) {
      component.empty(id);
      component.dom(id).append(control.self);
    } else {
      $(document.body).empty();
      $(document.body).append(control.self);
    }
  },
  dom: function (id) {
    return $('#' + id);
  }
};

$petal.ui = component;

})($petal, window, document); // Module $odphouse.router

<commit_msg>[ui-template] template support multiple elem<commit_after>/*
  @author: Seven Lju
  @date: 2015-02-18

  a template reader for web application.
 */
var $petal;
if($petal == null) $petal = {};

(function($petal, $win, $doc) {

var ajax = {
  _nop: function () {},
  resource: function (name, path, async) {
    if (async !== true) async = false;
    return $.ajax({
      url: path,
      method: 'GET',
      async: async
    });
  }
};

var component = {
  designView: false,
  cache: {},
  load: function (name, path, async) {
    if (component.cache[name]) return null;
    return ajax.resource(name, path, async).done(function (html) {
      component.cache[name] = html;
    });
  },
  _appendDom: function (dom, elements, templates) {
    var id = $(dom).attr('tag');
    if (!id) {
      component._searchDom(dom, elements, templates);
      return;
    }
    switch (id.charCodeAt(0)) {
    case 93: // ']', array element
      id = id.substring(1);
      if (!$.isArray(elements[id])) elements[id] = [];
      elements[id].push(dom);
      component._searchDom(dom, elements, templates);
      break;
    case 64: // '@', nest
      var subelements = {}, subtemplates = {};
      id = id.substring(1);
      elements[id] = {
        self: dom,
        dom: subelements,
        template: subtemplates
      }
      component._searchDom(dom, subelements, subtemplates);
      break;
    case 43: // '+', template
      id = id.substring(1);
      if (!component.designView) {
        $(dom).removeAttr('tag');
        if (templates[id]) {
          templates[id] += $(dom).prop('outerHTML');
        } else {
          templates[id] = $(dom).prop('outerHTML');
        }
        $(dom).remove();
        break;
      }
      // if in design view, we can see the template as a dom
      // in browser; thus here should not have a break
    default:
      if (elements[id]) {
        if (!elements[id].length) {
          elements[id] = [elements[id], dom];
        } else {
          elements[id].push(dom);
        }
      } else {
        elements[id] = dom;
      }
      component._searchDom(dom, elements, templates);
    }
  },
  _searchDom: function (dom, elements, templates) {
    var ch = $(dom).children();
    var n = ch.length;
    if (n <= 0) return;
    var i;
    for (i=0; i<n; i++) {
      component._appendDom(ch[i], elements, templates);
    }
  },
  /* e.g.
    partial.html

        Name: <input tag="txt_name" type="text" />

A	B

              loading...
              loading...

        XYZ

    index.js
      $petal.ui.load('partial', 'partial.html', false);
      var control = $petal.ui.create('partial');
      $(control.dom.txt_name).val("hello world");
      $(control.dom.link[0]).click(function () { alert("0"); });
      $(control.dom.link[1]).click(function () { alert("1"); });
      $(control.dom.link[2]).click(function () { alert("2"); });
      var item = $petal.ui.createT(control.template.item);
      $(item.dom.txt_a).text("hello");
      $(item.dom.txt_b).text("world");
      $(control.dom.items).append(item.self);
      $(control.dom.nest.dom.test).text('seprate world!');
      $(document.body).append(control.self);
  */
  createT: function (template, control) {
    if (!template) return null;
    if (!control) control = {};
    var elements = {}, templates = {};
    var dom = $(template);
    if (dom.length === 1) {
      component._searchDom(dom, elements, templates);
    } else {
      for (var i = 0, n = dom.length; i < n; i++) {
        component._searchDom($(dom[i]), elements, templates);
      }
    }
    control.self = dom;
    control.dom = elements;
    control.template = templates;
    return control;
  },
  create: function (name, control) {
    return component.createT(component.cache[name], control);
  },
  empty: function (id) {
    var i, n, ch;
    ch = component.dom(id).children();
    n = ch.length;
    for (i=0; i<n; i++) {
      $(ch[i]).remove();
    }
  },
  view: function (control, id) {
    if (id) {
      component.empty(id);
      component.dom(id).append(control.self);
    } else {
      $(document.body).empty();
      $(document.body).append(control.self);
    }
  },
  dom: function (id) {
    return $('#' + id);
  }
};

$petal.ui = component;

})($petal, window, document); // Module $odphouse.router

<|endoftext|>


<commit_before>// Copyright 2015-2020, University of Colorado Boulder

//TODO sun#197 ideally, only 2 corners of the button should be rounded (the corners in the direction of the arrow)
/**
 * Next/previous button in a Carousel.
 *
 * @author Chris Malley (PixelZoom, Inc.)
 */

import Dimension2 from '../../../dot/js/Dimension2.js';
import Matrix3 from '../../../dot/js/Matrix3.js';
import Shape from '../../../kite/js/Shape.js';
import merge from '../../../phet-core/js/merge.js';
import Path from '../../../scenery/js/nodes/Path.js';
import sun from '../sun.js';
import ButtonNode from './ButtonNode.js';
import RectangularPushButton from './RectangularPushButton.js';

// maps options.arrowDirection to rotation angles, in radians
const ANGLES = {
  up: 0, // arrow shape is created in 'up' direction
  down: Math.PI,
  left: -Math.PI / 2,
  right: Math.PI / 2
};

class CarouselButton extends RectangularPushButton {

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

    // see supertype for additional options
    options = merge( {

      // button
      baseColor: 'rgba( 200, 200, 200, 0.5 )', // {Color|string} button fill color
      stroke: 'black', // {Color|string|null} button stroke
      buttonAppearanceStrategy: ButtonNode.FlatAppearanceStrategy,
      cornerRadius: 4, // {number} radius for the two potentially rounded corners

      // arrow
      arrowDirection: 'up', // {string} direction that the arrow points, 'up'|'down'|'left'|'right'
      arrowSize: new Dimension2( 20, 7 ), // {Dimension2} size of the arrow, in 'up' directions
      arrowStroke: 'black', // {Color|string} color used for the arrow icons
      arrowLineWidth: 3, // {number} line width used to stroke the arrow icons
      arrowLineCap: 'round', // {string} 'butt'|'round'|'square'

      // Convenience options for dilating pointer areas such that they do not overlap with Carousel content.
      // See computePointerArea.
      touchAreaXDilation: 0,
      touchAreaYDilation: 0,
      mouseAreaXDilation: 0,
      mouseAreaYDilation: 0

    }, options );

    // validate options
    assert && assert( ANGLES.hasOwnProperty( options.arrowDirection ), 'invalid direction: ' + options.direction );

    // Generic arrow shape, points 'up'
    let arrowShape = new Shape()
      .moveTo( 0, 0 )
      .lineTo( options.arrowSize.width / 2, -options.arrowSize.height )
      .lineTo( options.arrowSize.width, 0 );

    // Transform arrow shape to match direction
    arrowShape = arrowShape.transformed( Matrix3.rotation2( ANGLES[ options.arrowDirection ] ) );

    // Arrow node
    options.content = new Path( arrowShape, {
      stroke: options.arrowStroke,
      lineWidth: options.arrowLineWidth,
      lineCap: options.arrowLineCap
    } );

    // set up the options such that the inner corners are square and outer ones are rounded
    const arrowDirection = options.arrowDirection; // convenience var
    const cornerRadius = options.cornerRadius; // convenience var
    options.leftTopCornerRadius = arrowDirection === 'up' || arrowDirection === 'left' ? cornerRadius : 0;
    options.rightTopCornerRadius = arrowDirection === 'up' || arrowDirection === 'right' ? cornerRadius : 0;
    options.leftBottomCornerRadius = arrowDirection === 'down' || arrowDirection === 'left' ? cornerRadius : 0;
    options.rightBottomCornerRadius = arrowDirection === 'down' || arrowDirection === 'right' ? cornerRadius : 0;

    super( options );

    // pointer areas
    this.touchArea = computePointerArea( this, arrowDirection, options.touchAreaXDilation, options.touchAreaYDilation );
    this.mouseArea = computePointerArea( this, arrowDirection, options.mouseAreaXDilation, options.mouseAreaYDilation );
  }
}

/**
 * Computes a pointer area based on dilation of a CarouselButton's local bounds.
 * The button is not dilated in the direction that is opposite to the arrow's direction.
 * This ensures that the pointer area will not overlap with the contents of a Carousel.
 *
 * @param {CarouselButton} button
 * @param {string} arrowDirection - direction that the arrow points, 'up'|'down'|'left'|'right'
 * @param {number} x - horizontal dilation
 * @param {number} y - vertical dilation
 * @returns {Bounds2} - null if no dilation is necessary, i.e. x === 0 && y === 0
 */
function computePointerArea( button, arrowDirection, x, y ) {
  let pointerArea = null;
  if ( x || y ) {
    switch( arrowDirection ) {
      case 'up':
        pointerArea = button.localBounds.dilatedXY( x, y / 2 ).shiftedY( -y / 2 );
        break;
      case 'down':
        pointerArea = button.localBounds.dilatedXY( x, y / 2 ).shiftedY( y / 2 );
        break;
      case 'left':
        pointerArea = button.localBounds.dilatedXY( x / 2, y ).shiftedX( -x / 2 );
        break;
      case 'right' :
        pointerArea = button.localBounds.dilatedXY( x / 2, y ).shiftedX( x / 2 );
        break;
      default:
        throw new Error( 'unsupported arrowDirection: ' + arrowDirection );
    }
  }
  return pointerArea;
}

sun.register( 'CarouselButton', CarouselButton );
export default CarouselButton;<commit_msg>Improve formatting, see https://github.com/phetsims/phet-info/issues/150<commit_after>// Copyright 2015-2020, University of Colorado Boulder

//TODO sun#197 ideally, only 2 corners of the button should be rounded (the corners in the direction of the arrow)
/**
 * Next/previous button in a Carousel.
 *
 * @author Chris Malley (PixelZoom, Inc.)
 */

import Dimension2 from '../../../dot/js/Dimension2.js';
import Matrix3 from '../../../dot/js/Matrix3.js';
import Shape from '../../../kite/js/Shape.js';
import merge from '../../../phet-core/js/merge.js';
import Path from '../../../scenery/js/nodes/Path.js';
import sun from '../sun.js';
import ButtonNode from './ButtonNode.js';
import RectangularPushButton from './RectangularPushButton.js';

// maps options.arrowDirection to rotation angles, in radians
const ANGLES = {
  up: 0, // arrow shape is created in 'up' direction
  down: Math.PI,
  left: -Math.PI / 2,
  right: Math.PI / 2
};

class CarouselButton extends RectangularPushButton {

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

    // see supertype for additional options
    options = merge( {

      // button
      baseColor: 'rgba( 200, 200, 200, 0.5 )', // {Color|string} button fill color
      stroke: 'black', // {Color|string|null} button stroke
      buttonAppearanceStrategy: ButtonNode.FlatAppearanceStrategy,
      cornerRadius: 4, // {number} radius for the two potentially rounded corners

      // arrow
      arrowDirection: 'up', // {string} direction that the arrow points, 'up'|'down'|'left'|'right'
      arrowSize: new Dimension2( 20, 7 ), // {Dimension2} size of the arrow, in 'up' directions
      arrowStroke: 'black', // {Color|string} color used for the arrow icons
      arrowLineWidth: 3, // {number} line width used to stroke the arrow icons
      arrowLineCap: 'round', // {string} 'butt'|'round'|'square'

      // Convenience options for dilating pointer areas such that they do not overlap with Carousel content.
      // See computePointerArea.
      touchAreaXDilation: 0,
      touchAreaYDilation: 0,
      mouseAreaXDilation: 0,
      mouseAreaYDilation: 0

    }, options );

    // validate options
    assert && assert( ANGLES.hasOwnProperty( options.arrowDirection ), 'invalid direction: ' + options.direction );

    // Generic arrow shape, points 'up'
    let arrowShape = new Shape()
      .moveTo( 0, 0 )
      .lineTo( options.arrowSize.width / 2, -options.arrowSize.height )
      .lineTo( options.arrowSize.width, 0 );

    // Transform arrow shape to match direction
    arrowShape = arrowShape.transformed( Matrix3.rotation2( ANGLES[ options.arrowDirection ] ) );

    // Arrow node
    options.content = new Path( arrowShape, {
      stroke: options.arrowStroke,
      lineWidth: options.arrowLineWidth,
      lineCap: options.arrowLineCap
    } );

    // set up the options such that the inner corners are square and outer ones are rounded
    const arrowDirection = options.arrowDirection; // convenience var
    const cornerRadius = options.cornerRadius; // convenience var
    options.leftTopCornerRadius = arrowDirection === 'up' || arrowDirection === 'left' ? cornerRadius : 0;
    options.rightTopCornerRadius = arrowDirection === 'up' || arrowDirection === 'right' ? cornerRadius : 0;
    options.leftBottomCornerRadius = arrowDirection === 'down' || arrowDirection === 'left' ? cornerRadius : 0;
    options.rightBottomCornerRadius = arrowDirection === 'down' || arrowDirection === 'right' ? cornerRadius : 0;

    super( options );

    // pointer areas
    this.touchArea = computePointerArea( this, arrowDirection, options.touchAreaXDilation, options.touchAreaYDilation );
    this.mouseArea = computePointerArea( this, arrowDirection, options.mouseAreaXDilation, options.mouseAreaYDilation );
  }
}

/**
 * Computes a pointer area based on dilation of a CarouselButton's local bounds.
 * The button is not dilated in the direction that is opposite to the arrow's direction.
 * This ensures that the pointer area will not overlap with the contents of a Carousel.
 *
 * @param {CarouselButton} button
 * @param {string} arrowDirection - direction that the arrow points, 'up'|'down'|'left'|'right'
 * @param {number} x - horizontal dilation
 * @param {number} y - vertical dilation
 * @returns {Bounds2} - null if no dilation is necessary, i.e. x === 0 && y === 0
 */
function computePointerArea( button, arrowDirection, x, y ) {
  let pointerArea = null;
  if ( x || y ) {
    switch( arrowDirection ) {
      case 'up':
        pointerArea = button.localBounds.dilatedXY( x, y / 2 ).shiftedY( -y / 2 );
        break;
      case 'down':
        pointerArea = button.localBounds.dilatedXY( x, y / 2 ).shiftedY( y / 2 );
        break;
      case 'left':
        pointerArea = button.localBounds.dilatedXY( x / 2, y ).shiftedX( -x / 2 );
        break;
      case 'right':
        pointerArea = button.localBounds.dilatedXY( x / 2, y ).shiftedX( x / 2 );
        break;
      default:
        throw new Error( 'unsupported arrowDirection: ' + arrowDirection );
    }
  }
  return pointerArea;
}

sun.register( 'CarouselButton', CarouselButton );
export default CarouselButton;<|endoftext|>


<commit_before>// A function that builds the __new__ method for the factory function
__BRYTHON__.$__new__ = function(factory){
    return function(cls){
        /*
        if(cls===undefined){
            throw __BRYTHON__.builtins.TypeError(factory.$dict.__name__+'.__new__(): not enough arguments')
        }
        */
        var res = factory.apply(null,[])
        res.__class__ = cls.$dict
        var init_func = null
        try{init_func = __BRYTHON__.builtins.getattr(res,'__init__')}
        catch(err){}
        if(init_func!==null){
            var args = [], pos=0
            for(var i=1, _len_i = arguments.length; i < _len_i;i++){args[pos++]=arguments[i]}
            init_func.apply(null,args)
            res.__initialized__ = true
        }
        return res
    }
}

__BRYTHON__.builtins.object = (function($B){

var _b_=$B.builtins

// class object for the built-in class 'object'
var $ObjectDict = {
    //__class__:$type, : not here, added in py_type.js after $type is defined
    // __bases__ : set to an empty tuple in py_list.js after tuple is defined
    __name__:'object',
    $native:true
}

// Function for comparison operators
// In a<b, if b defines __gt__, use b.__gt__(a)
var reverse_func = {'__lt__':'__gt__',
    '__gt__':'__lt__',
    '__le__': '__ge__',
    '__ge__': '__le__'
}
var $ObjectNI = function(name,op){
    return function(self, other){
        var klass = $B.get_class(other),
            other_comp = _b_.getattr(klass, reverse_func[name])
        if(other_comp.__func__===$ObjectDict[reverse_func[name]]){
            throw _b_.TypeError('unorderable types: object() '+op+
                ' '+ _b_.str($B.get_class(other).__name__)+'()')
        }else{
            return other_comp(other, self)
        }
    }
}

// Name of special methods : if they are not found as attributes, try
// the "reflected" attribute on the argument
// For instance, for "getattr(x,'__mul__')", if object x has no attribute
// "__mul__", try a function using the attribute "__rmul__" of its
// first argument

var opnames = ['add','sub','mul','truediv','floordiv','mod','pow',
    'lshift','rshift','and','xor','or']
var opsigns = ['+','-','*','/','//','%','**','<<','>>','&','^', '|']

$ObjectDict.__delattr__ = function(self,attr){
    _b_.getattr(self, attr) // raises AttributeError if necessary
    delete self[attr];
    return _b_.None
}

$ObjectDict.__dir__ = function(self) {
    var objects = [self],
        pos=1,
        klass = self.__class__ || $B.get_class(self)
    objects[pos++] = klass
    var mro = klass.__mro__
    for (var i=0, _len_i = mro.length; i < _len_i; i++) {
        objects[pos++]=mro[i]
    }

    var res = [], pos=0
    for (var i=0, _len_i = objects.length; i < _len_i; i++) {
        for(var attr in objects[i]){
            //if(attr.charAt(0)=='$' && attr.substr(0,2)!=='$$'){
            if(attr.charAt(0)=='$' && attr.charAt(1) != '$') {
                // exclude internal attributes set by Brython
                continue
            }
            if(!isNaN(parseInt(attr.charAt(0)))){
                // Exclude numerical attributes
                // '0', '1' are in attributes of string 'ab'
                continue
            }
            if(attr=='__mro__'){continue}
            res[pos++]=attr
        }
    }
    res = _b_.list(_b_.set(res))
    _b_.list.$dict.sort(res)
    return res
}

$ObjectDict.__eq__ = function(self,other){
    // equality test defaults to identity of objects
    //test_issue_1393
    var _class=$B.get_class(self)
    if (_class.$native || _class.__name__ == 'function') {
       var _class1=$B.get_class(other)
       if (!_class1.$native && _class1.__name__ != 'function') {
          return _b_.getattr(other, '__eq__')(self)
       }
    }
    return self===other
}

$ObjectDict.__format__ = function(){
    var $ = $B.args('__format__', 2, {self:null, spec:null},
        ['self', 'spec'], arguments, {}, null, null)
    if($.spec!==''){throw _b_.TypeError("non-empty format string passed to object.__format__")}
    return _b_.getattr($.self, '__repr__')()
}

$ObjectDict.__ge__ = $ObjectNI('__ge__','>=')

$ObjectDict.__getattribute__ = function(obj,attr){

    var klass = obj.__class__ || $B.get_class(obj)
    if(attr==='__class__'){
        return klass.$factory
    }
    var res = obj[attr]

    if(res===undefined){
        // search in classes hierarchy, following method resolution order
        function check(obj, kl, attr){
            if(kl.$methods){
                var method = kl.$methods[attr]
                if(method!==undefined){
                    return method(obj)
                }
            }
            var v=kl[attr]
            if(v!==undefined){
                return v
            }else if(attr=='__str__' && kl['__repr__']!==undefined){
                // If the class doesn't define __str__ but defines __repr__,
                // use __repr__
                return kl['__repr__']
            }
        }
        res = check(obj, klass, attr)
        if(res===undefined){
            var mro = klass.__mro__
            for(var i=0, _len_i = mro.length; i < _len_i;i++){
                res = check(obj, mro[i], attr)
                if(res!==undefined){break}
            }
        }
    }else{
        if(res.__set__===undefined){
            // For non-data descriptors, the attribute found in object
            // dictionary takes precedence
            return res
        }
    }

    if(res!==undefined){

        if(res.__class__===_b_.property.$dict){
            return res.__get__(res, obj, klass)
        }

        var get = res.__get__
        if(get===undefined && res.__class__){
            var get = res.__class__.__get__
            for(var i=0;i<res.__class__.__mro__.length && get===undefined; i++){
                get = res.__class__.__mro__[i].__get__
            }
        }
        var __get__ = get === undefined ? null : _b_.getattr(res,'__get__',null)

        // For descriptors, attribute resolution is done by applying __get__
        if(__get__!==null){
            try{return __get__.apply(null, [obj, klass])}
            catch(err){
                console.log('error in get.apply', err)
                console.log(__get__+'')
                throw err
            }
        }

        if(typeof res=='object'){
            if(__get__ && (typeof __get__=='function')){
                get_func = function(x,y){return __get__.apply(x,[y,klass])}
            }
        }

        if(__get__===null && (typeof res=='function')){
            __get__ = function(x){return x}
        }
        if(__get__!==null){ // descriptor
            res.__name__ = attr
            // __new__ is a static method
            if(attr == '__new__'){res.$type = 'staticmethod'}
            var res1 = __get__.apply(null, [res, obj, klass])
            if(typeof res1 == 'function'){
                // If attribute is a class then return it unchanged
                //
                // Example :
                // ===============
                // class A:
                //    def __init__(self,x):
                //        self.x = x
                //
                // class B:
                //    foo = A
                //    def __init__(self):
                //        self.info = self.foo(18)
                //
                // B()
                // ===============
                // In class B, when we call self.foo(18), self.foo is the
                // class A, its method __init__ must be called without B's
                // self as first argument

                if(res1.__class__ === $B.$factory) return res

                // Same thing if the attribute is a method of an instance
                // =================
                // class myRepr:
                //     def repr(self, a):
                //         return a
                //
                // class myclass:
                //     _repr=myRepr()
                //     repr= _repr.repr
                //
                //     def myfunc(self):
                //         return self.repr('test')
                // =================
                // In function myfunc, self.repr is an instance of MyRepr,
                // it must be used as is, not transformed into a method

                else if(res1.__class__===$B.$MethodDict){
                    return res
                }

                // instance method object
                return $B.make_method(attr, klass, res)(obj)

            }else{
                // result of __get__ is not a function
                return res1
            }
        }
        // attribute is not a descriptor : return it unchanged
        return res
    }else{
        // search __getattr__
        var _ga = obj['__getattr__']
        if(_ga===undefined){
            _ga = klass['__getattr__']
            if(_ga===undefined){
                var mro = klass.__mro__
                for(var i=0, len=mro.length; i < len;i++){
                    _ga = mro[i]['__getattr__']
                    if(_ga!==undefined){
                        break
                    }
                }
            }
        }
        if(_ga!==undefined){
            try{return _ga(obj,attr)}
            catch(err){}
        }
        // for special methods such as __mul__, look for __rmul__ on operand
        if(attr.substr(0,2)=='__' && attr.substr(attr.length-2)=='__'){
            var attr1 = attr.substr(2,attr.length-4) // stripped of __
            var rank = opnames.indexOf(attr1)
            if(rank > -1){
                var rop = '__r'+opnames[rank]+'__' // name of reflected operator
                var func = function(){
                    try{
                        // Operands must be of different types
                        if($B.get_class(arguments[0])===klass){throw Error('')}
                        return _b_.getattr(arguments[0],rop)(obj)
                    }catch(err){
                        var msg = "unsupported operand types for "+
                            opsigns[rank]+": '"+ klass.__name__+"' and '"+
                            $B.get_class(arguments[0]).__name__+"'"
                        throw _b_.TypeError(msg)
                    }
                }
                func.$infos = {__name__ : klass.__name__+'.'+attr}
                return func
            }
        }
        //throw AttributeError('object '+obj.__class__.__name__+" has no attribute '"+attr+"'")
    }
}

$ObjectDict.__gt__ = $ObjectNI('__gt__','>')

$ObjectDict.__hash__ = function (self) {
    var hash = self.__hashvalue__
    if(hash!==undefined){return hash}
    return self.__hashvalue__=$B.$py_next_hash--;
}

$ObjectDict.__init__ = function(){
    if(arguments.length <= 2) {  // at most "self" and kwargs
        kw = arguments[1]
        // kwargs is well formed
        if(kw.$nat !== undefined && kw.kw !== undefined) {
            if(Object.keys(kw.kw).length == 0) {  // no items in kwargs
                return _b_.None  // all is good ... return None
            }
        }
    }
    // *args expansion has elements or **kwargs is not empty
    throw _b_.TypeError("object() takes no parameters")
}

$ObjectDict.__le__ = $ObjectNI('__le__','<=')

$ObjectDict.__lt__ = $ObjectNI('__lt__','<')

$ObjectDict.__mro__ = []

$ObjectDict.__new__ = function(cls){
    if(cls===undefined){throw _b_.TypeError('object.__new__(): not enough arguments')}
    return {__class__ : cls.$dict}
}

$ObjectDict.__ne__ = function(self,other){
    return !_b_.getattr(self, '__eq__')(other)
}

$ObjectDict.__repr__ = function(self){
    if(self===object) return "<class 'object'>"
    if(self.__class__===$B.$factory) return "<class '"+self.$dict.__name__+"'>"
    if(self.__class__===$B.$type && self.__name__=='classXXX') return "<class '"+self.__name__+"'>"
    if(self.__class__.__module__!==undefined){
        return "<"+self.__class__.__module__+"."+self.__class__.__name__+" object>"
    }else{
        return "<"+self.__class__.__name__+" object>"
    }
}

$ObjectDict.__setattr__ = function(self,attr,val){
    if(val===undefined){ // setting an attribute to 'object' type is not allowed
        throw _b_.TypeError("can't set attributes of built-in/extension type 'object'")
    }else if(self.__class__===$ObjectDict){
        // setting an attribute to object() is not allowed
        if($ObjectDict[attr]===undefined){
            throw _b_.AttributeError("'object' object has no attribute '"+attr+"'")
        }else{
            throw _b_.AttributeError("'object' object attribute '"+attr+"' is read-only")
        }
    }
    self[attr] = val
    return _b_.None
}
$ObjectDict.__setattr__.__str__ = function(){return 'method object.setattr'}

$ObjectDict.__str__ = $ObjectDict.__repr__

$ObjectDict.__subclasshook__ = function(){return _b_.NotImplemented}

// constructor of the built-in class 'object'
function object(){return {__class__:$ObjectDict}}

object.$dict = $ObjectDict
// object.__class__ = $factory : this is done in py_types
$ObjectDict.$factory = object
object.__repr__ = object.__str__ = function(){return "<class 'object'>"}

$B.make_class = function(class_obj){
    // class_obj has at least an attribute "name", and possibly an attribute
    // init

    function A(){
        var res = {__class__:A.$dict}
        if(class_obj.init){
            class_obj.init.apply(null,
                [res].concat(Array.prototype.slice.call(arguments)))
        }
        return res
    }

    A.__class__ = $B.$factory

    A.$dict = {
        __class__: $B.type,
        __name__: class_obj.name
    }
    A.$dict.__mro__ = [object.$dict]

    return A
}

return object

})(__BRYTHON__)
<commit_msg>Separate 1 and 2 arguments cases<commit_after>// A function that builds the __new__ method for the factory function
__BRYTHON__.$__new__ = function(factory){
    return function(cls){
        /*
        if(cls===undefined){
            throw __BRYTHON__.builtins.TypeError(factory.$dict.__name__+'.__new__(): not enough arguments')
        }
        */
        var res = factory.apply(null,[])
        res.__class__ = cls.$dict
        var init_func = null
        try{init_func = __BRYTHON__.builtins.getattr(res,'__init__')}
        catch(err){}
        if(init_func!==null){
            var args = [], pos=0
            for(var i=1, _len_i = arguments.length; i < _len_i;i++){args[pos++]=arguments[i]}
            init_func.apply(null,args)
            res.__initialized__ = true
        }
        return res
    }
}

__BRYTHON__.builtins.object = (function($B){

var _b_=$B.builtins

// class object for the built-in class 'object'
var $ObjectDict = {
    //__class__:$type, : not here, added in py_type.js after $type is defined
    // __bases__ : set to an empty tuple in py_list.js after tuple is defined
    __name__:'object',
    $native:true
}

// Function for comparison operators
// In a<b, if b defines __gt__, use b.__gt__(a)
var reverse_func = {'__lt__':'__gt__',
    '__gt__':'__lt__',
    '__le__': '__ge__',
    '__ge__': '__le__'
}
var $ObjectNI = function(name,op){
    return function(self, other){
        var klass = $B.get_class(other),
            other_comp = _b_.getattr(klass, reverse_func[name])
        if(other_comp.__func__===$ObjectDict[reverse_func[name]]){
            throw _b_.TypeError('unorderable types: object() '+op+
                ' '+ _b_.str($B.get_class(other).__name__)+'()')
        }else{
            return other_comp(other, self)
        }
    }
}

// Name of special methods : if they are not found as attributes, try
// the "reflected" attribute on the argument
// For instance, for "getattr(x,'__mul__')", if object x has no attribute
// "__mul__", try a function using the attribute "__rmul__" of its
// first argument

var opnames = ['add','sub','mul','truediv','floordiv','mod','pow',
    'lshift','rshift','and','xor','or']
var opsigns = ['+','-','*','/','//','%','**','<<','>>','&','^', '|']

$ObjectDict.__delattr__ = function(self,attr){
    _b_.getattr(self, attr) // raises AttributeError if necessary
    delete self[attr];
    return _b_.None
}

$ObjectDict.__dir__ = function(self) {
    var objects = [self],
        pos=1,
        klass = self.__class__ || $B.get_class(self)
    objects[pos++] = klass
    var mro = klass.__mro__
    for (var i=0, _len_i = mro.length; i < _len_i; i++) {
        objects[pos++]=mro[i]
    }

    var res = [], pos=0
    for (var i=0, _len_i = objects.length; i < _len_i; i++) {
        for(var attr in objects[i]){
            //if(attr.charAt(0)=='$' && attr.substr(0,2)!=='$$'){
            if(attr.charAt(0)=='$' && attr.charAt(1) != '$') {
                // exclude internal attributes set by Brython
                continue
            }
            if(!isNaN(parseInt(attr.charAt(0)))){
                // Exclude numerical attributes
                // '0', '1' are in attributes of string 'ab'
                continue
            }
            if(attr=='__mro__'){continue}
            res[pos++]=attr
        }
    }
    res = _b_.list(_b_.set(res))
    _b_.list.$dict.sort(res)
    return res
}

$ObjectDict.__eq__ = function(self,other){
    // equality test defaults to identity of objects
    //test_issue_1393
    var _class=$B.get_class(self)
    if (_class.$native || _class.__name__ == 'function') {
       var _class1=$B.get_class(other)
       if (!_class1.$native && _class1.__name__ != 'function') {
          return _b_.getattr(other, '__eq__')(self)
       }
    }
    return self===other
}

$ObjectDict.__format__ = function(){
    var $ = $B.args('__format__', 2, {self:null, spec:null},
        ['self', 'spec'], arguments, {}, null, null)
    if($.spec!==''){throw _b_.TypeError("non-empty format string passed to object.__format__")}
    return _b_.getattr($.self, '__repr__')()
}

$ObjectDict.__ge__ = $ObjectNI('__ge__','>=')

$ObjectDict.__getattribute__ = function(obj,attr){

    var klass = obj.__class__ || $B.get_class(obj)
    if(attr==='__class__'){
        return klass.$factory
    }
    var res = obj[attr]

    if(res===undefined){
        // search in classes hierarchy, following method resolution order
        function check(obj, kl, attr){
            if(kl.$methods){
                var method = kl.$methods[attr]
                if(method!==undefined){
                    return method(obj)
                }
            }
            var v=kl[attr]
            if(v!==undefined){
                return v
            }else if(attr=='__str__' && kl['__repr__']!==undefined){
                // If the class doesn't define __str__ but defines __repr__,
                // use __repr__
                return kl['__repr__']
            }
        }
        res = check(obj, klass, attr)
        if(res===undefined){
            var mro = klass.__mro__
            for(var i=0, _len_i = mro.length; i < _len_i;i++){
                res = check(obj, mro[i], attr)
                if(res!==undefined){break}
            }
        }
    }else{
        if(res.__set__===undefined){
            // For non-data descriptors, the attribute found in object
            // dictionary takes precedence
            return res
        }
    }

    if(res!==undefined){

        if(res.__class__===_b_.property.$dict){
            return res.__get__(res, obj, klass)
        }

        var get = res.__get__
        if(get===undefined && res.__class__){
            var get = res.__class__.__get__
            for(var i=0;i<res.__class__.__mro__.length && get===undefined; i++){
                get = res.__class__.__mro__[i].__get__
            }
        }
        var __get__ = get === undefined ? null : _b_.getattr(res,'__get__',null)

        // For descriptors, attribute resolution is done by applying __get__
        if(__get__!==null){
            try{return __get__.apply(null, [obj, klass])}
            catch(err){
                console.log('error in get.apply', err)
                console.log(__get__+'')
                throw err
            }
        }

        if(typeof res=='object'){
            if(__get__ && (typeof __get__=='function')){
                get_func = function(x,y){return __get__.apply(x,[y,klass])}
            }
        }

        if(__get__===null && (typeof res=='function')){
            __get__ = function(x){return x}
        }
        if(__get__!==null){ // descriptor
            res.__name__ = attr
            // __new__ is a static method
            if(attr == '__new__'){res.$type = 'staticmethod'}
            var res1 = __get__.apply(null, [res, obj, klass])
            if(typeof res1 == 'function'){
                // If attribute is a class then return it unchanged
                //
                // Example :
                // ===============
                // class A:
                //    def __init__(self,x):
                //        self.x = x
                //
                // class B:
                //    foo = A
                //    def __init__(self):
                //        self.info = self.foo(18)
                //
                // B()
                // ===============
                // In class B, when we call self.foo(18), self.foo is the
                // class A, its method __init__ must be called without B's
                // self as first argument

                if(res1.__class__ === $B.$factory) return res

                // Same thing if the attribute is a method of an instance
                // =================
                // class myRepr:
                //     def repr(self, a):
                //         return a
                //
                // class myclass:
                //     _repr=myRepr()
                //     repr= _repr.repr
                //
                //     def myfunc(self):
                //         return self.repr('test')
                // =================
                // In function myfunc, self.repr is an instance of MyRepr,
                // it must be used as is, not transformed into a method

                else if(res1.__class__===$B.$MethodDict){
                    return res
                }

                // instance method object
                return $B.make_method(attr, klass, res)(obj)

            }else{
                // result of __get__ is not a function
                return res1
            }
        }
        // attribute is not a descriptor : return it unchanged
        return res
    }else{
        // search __getattr__
        var _ga = obj['__getattr__']
        if(_ga===undefined){
            _ga = klass['__getattr__']
            if(_ga===undefined){
                var mro = klass.__mro__
                for(var i=0, len=mro.length; i < len;i++){
                    _ga = mro[i]['__getattr__']
                    if(_ga!==undefined){
                        break
                    }
                }
            }
        }
        if(_ga!==undefined){
            try{return _ga(obj,attr)}
            catch(err){}
        }
        // for special methods such as __mul__, look for __rmul__ on operand
        if(attr.substr(0,2)=='__' && attr.substr(attr.length-2)=='__'){
            var attr1 = attr.substr(2,attr.length-4) // stripped of __
            var rank = opnames.indexOf(attr1)
            if(rank > -1){
                var rop = '__r'+opnames[rank]+'__' // name of reflected operator
                var func = function(){
                    try{
                        // Operands must be of different types
                        if($B.get_class(arguments[0])===klass){throw Error('')}
                        return _b_.getattr(arguments[0],rop)(obj)
                    }catch(err){
                        var msg = "unsupported operand types for "+
                            opsigns[rank]+": '"+ klass.__name__+"' and '"+
                            $B.get_class(arguments[0]).__name__+"'"
                        throw _b_.TypeError(msg)
                    }
                }
                func.$infos = {__name__ : klass.__name__+'.'+attr}
                return func
            }
        }
        //throw AttributeError('object '+obj.__class__.__name__+" has no attribute '"+attr+"'")
    }
}

$ObjectDict.__gt__ = $ObjectNI('__gt__','>')

$ObjectDict.__hash__ = function (self) {
    var hash = self.__hashvalue__
    if(hash!==undefined){return hash}
    return self.__hashvalue__=$B.$py_next_hash--;
}

$ObjectDict.__init__ = function(){
    if(arguments.length == 1) {  // only self
        return _b_.None  // all is good ... return None
    } else if(arguments.length == 2) {  // at most "self" and kwargs
        kw = arguments[1]
        if(kw.$nat !== undefined && kw.kw !== undefined) { // kwargs is well formed
            if(Object.keys(kw.kw).length == 0) {  // no items in kwargs
                return _b_.None  // all is good ... return None
            }
        }
    }
    // *args expansion has elements or **kwargs is not empty
    throw _b_.TypeError("object() takes no parameters")
}

$ObjectDict.__le__ = $ObjectNI('__le__','<=')

$ObjectDict.__lt__ = $ObjectNI('__lt__','<')

$ObjectDict.__mro__ = []

$ObjectDict.__new__ = function(cls){
    if(cls===undefined){throw _b_.TypeError('object.__new__(): not enough arguments')}
    return {__class__ : cls.$dict}
}

$ObjectDict.__ne__ = function(self,other){
    return !_b_.getattr(self, '__eq__')(other)
}

$ObjectDict.__repr__ = function(self){
    if(self===object) return "<class 'object'>"
    if(self.__class__===$B.$factory) return "<class '"+self.$dict.__name__+"'>"
    if(self.__class__===$B.$type && self.__name__=='classXXX') return "<class '"+self.__name__+"'>"
    if(self.__class__.__module__!==undefined){
        return "<"+self.__class__.__module__+"."+self.__class__.__name__+" object>"
    }else{
        return "<"+self.__class__.__name__+" object>"
    }
}

$ObjectDict.__setattr__ = function(self,attr,val){
    if(val===undefined){ // setting an attribute to 'object' type is not allowed
        throw _b_.TypeError("can't set attributes of built-in/extension type 'object'")
    }else if(self.__class__===$ObjectDict){
        // setting an attribute to object() is not allowed
        if($ObjectDict[attr]===undefined){
            throw _b_.AttributeError("'object' object has no attribute '"+attr+"'")
        }else{
            throw _b_.AttributeError("'object' object attribute '"+attr+"' is read-only")
        }
    }
    self[attr] = val
    return _b_.None
}
$ObjectDict.__setattr__.__str__ = function(){return 'method object.setattr'}

$ObjectDict.__str__ = $ObjectDict.__repr__

$ObjectDict.__subclasshook__ = function(){return _b_.NotImplemented}

// constructor of the built-in class 'object'
function object(){return {__class__:$ObjectDict}}

object.$dict = $ObjectDict
// object.__class__ = $factory : this is done in py_types
$ObjectDict.$factory = object
object.__repr__ = object.__str__ = function(){return "<class 'object'>"}

$B.make_class = function(class_obj){
    // class_obj has at least an attribute "name", and possibly an attribute
    // init

    function A(){
        var res = {__class__:A.$dict}
        if(class_obj.init){
            class_obj.init.apply(null,
                [res].concat(Array.prototype.slice.call(arguments)))
        }
        return res
    }

    A.__class__ = $B.$factory

    A.$dict = {
        __class__: $B.type,
        __name__: class_obj.name
    }
    A.$dict.__mro__ = [object.$dict]

    return A
}

return object

})(__BRYTHON__)
<|endoftext|>


<commit_before>// Copyright 2018-2021, University of Colorado Boulder

/**
 * a button for controlling whether sound is enabled or disabled for the sim and that is designed to work on the PhET
 * navigation bar
 *
 * @author John Blanco
 * @author Chris Klusendorf
 */

import Vector2 from '../../dot/js/Vector2.js';
import Shape from '../../kite/js/Shape.js';
import merge from '../../phet-core/js/merge.js';
import Node from '../../scenery/js/nodes/Node.js';
import Path from '../../scenery/js/nodes/Path.js';
import Rectangle from '../../scenery/js/nodes/Rectangle.js';
import ToggleNode from '../../sun/js/ToggleNode.js';
import ActivationUtterance from '../../utterance-queue/js/ActivationUtterance.js';
import joist from './joist.js';
import JoistButton from './JoistButton.js';
import joistStrings from './joistStrings.js';

// constants for node background
const NODE_HEIGHT = 22.0;
const NODE_WIDTH = NODE_HEIGHT * 1.13;

// constants for drawing speaker
const SPEAKER_HEIGHT = NODE_HEIGHT * 0.77;
const SPEAKER_WIDTH = SPEAKER_HEIGHT * 0.58;
const SPEAKER_BACK_WIDTH = SPEAKER_WIDTH * 0.46;
const SPEAKER_BACK_HEIGHT = SPEAKER_HEIGHT * 0.35;
const SPEAKER_BACK_Y_SPACE = ( SPEAKER_HEIGHT - SPEAKER_BACK_HEIGHT ) / 2.0; // space between top of speaker back and top of cone
const CORNER_RADIUS = 1.0;

// constant for drawing sound off X
const X_WIDTH = SPEAKER_HEIGHT * 0.52;

// constants for drawing sound on curves
const MAX_CURVE_RADIUS = SPEAKER_HEIGHT * 0.63;
const RADIUS_STEPPER = SPEAKER_HEIGHT * 0.23;
const MED_CURVE_RADIUS = MAX_CURVE_RADIUS - RADIUS_STEPPER;
const MIN_CURVE_RADIUS = MED_CURVE_RADIUS - RADIUS_STEPPER;
const CURVE_ANGLE = Math.PI / 2.7;
const NEG_CURVE_ANGLE = CURVE_ANGLE * -1.0;

class NavigationBarSoundToggleButton extends JoistButton {

  /**
   * @param {BooleanProperty} soundEnabledProperty
   * @param {Property.<Color|string>} backgroundColorProperty
   * @param {Tandem} tandem
   * @param {Object} [options]
   */
  constructor( soundEnabledProperty, backgroundColorProperty, tandem, options ) {

    options = merge( {

      // JoistButton options
      highlightExtensionWidth: 5,
      highlightExtensionHeight: 10,
      highlightCenterOffsetY: 0,

      visiblePropertyOptions: { phetioFeatured: true },

      // pdom
      innerContent: joistStrings.a11y.soundToggle.label,

      // voicing
      voicingNameResponse: joistStrings.a11y.soundToggle.label
    }, options );

    assert && assert( options.listener === undefined, 'NavigationBarSoundToggleButton sets listener' );
    options.listener = () => soundEnabledProperty.set( !soundEnabledProperty.get() );

    const soundOnNode = new Node();
    const soundOffNode = new Node();
    const backgroundNode = new Rectangle( 0, 0, NODE_WIDTH, NODE_HEIGHT, { fill: 'transparent' } );
    soundOnNode.addChild( backgroundNode );
    soundOffNode.addChild( backgroundNode );

    // create speaker for both sound on and sound off
    const speakerNode = new Path(
      new Shape()
        .moveTo( SPEAKER_WIDTH, 0 )
        .lineTo( SPEAKER_BACK_WIDTH, SPEAKER_BACK_Y_SPACE )
        .lineTo( CORNER_RADIUS, SPEAKER_BACK_Y_SPACE )
        .arc( CORNER_RADIUS, SPEAKER_BACK_Y_SPACE + CORNER_RADIUS, CORNER_RADIUS, Math.PI * 1.5, Math.PI, true )
        .lineToRelative( 0, SPEAKER_BACK_HEIGHT - ( 2 * CORNER_RADIUS ) )
        .arc( CORNER_RADIUS, SPEAKER_BACK_Y_SPACE + SPEAKER_BACK_HEIGHT - CORNER_RADIUS, CORNER_RADIUS, Math.PI, Math.PI * 0.5, true )
        .lineToRelative( SPEAKER_BACK_WIDTH - CORNER_RADIUS, 0 )
        .lineTo( SPEAKER_WIDTH, SPEAKER_HEIGHT )
        .lineTo( SPEAKER_WIDTH, 0 )
        .close(),
      {
        stroke: 'black',
        lineWidth: 1.5,
        lineJoin: 'round',
        centerY: soundOffNode.centerY,
        left: 0
      }
    );

    soundOnNode.addChild( speakerNode );
    soundOffNode.addChild( speakerNode );

    // create X for sound off
    const soundOffX = new Path(
      new Shape().moveTo( 0, 0 ).lineTo( X_WIDTH, X_WIDTH ).moveTo( 0, X_WIDTH )
        .lineTo( X_WIDTH, 0 ),
      {
        stroke: 'black',
        lineWidth: 1.7,
        lineCap: 'round',
        right: soundOffNode.width,
        centerY: soundOffNode.centerY
      }
    );
    soundOffNode.addChild( soundOffX );

    // create curved lines for sound on
    const soundOnCurves = new Path(
      new Shape()
        .arc( 0, 0, MAX_CURVE_RADIUS, CURVE_ANGLE, NEG_CURVE_ANGLE, true )
        .moveToPoint( new Vector2( MED_CURVE_RADIUS, 0 ).rotated( CURVE_ANGLE ) )
        .arc( 0, 0, MED_CURVE_RADIUS, CURVE_ANGLE, NEG_CURVE_ANGLE, true )
        .moveToPoint( new Vector2( MIN_CURVE_RADIUS, 0 ).rotated( CURVE_ANGLE ) )
        .arc( 0, 0, MIN_CURVE_RADIUS, CURVE_ANGLE, NEG_CURVE_ANGLE, true ),
      {
        stroke: 'black',
        lineWidth: 1.7,
        lineCap: 'round',
        right: soundOnNode.width,
        centerY: soundOnNode.centerY
      }
    );
    soundOnNode.addChild( soundOnCurves );

    const toggleNode = new ToggleNode( soundEnabledProperty,
      [
        { value: true, node: soundOnNode },
        { value: false, node: soundOffNode }
      ],
      { maxHeight: NODE_HEIGHT }
    );

    super( toggleNode, backgroundColorProperty, tandem, options );

    // must be after the button is instrumented
    this.addLinkedElement( soundEnabledProperty, {
      tandem: tandem.createTandem( 'property' )
    } );

    // pdom attribute lets user know when the toggle is pressed, linked lazily so that an alert isn't triggered
    // on construction and must be unlinked in dispose
    const soundUtterance = new ActivationUtterance();
    const pressedListener = value => {
      this.setPDOMAttribute( 'aria-pressed', !value );

      soundUtterance.alert = value ? joistStrings.a11y.soundToggle.alert.simSoundOn
                                   : joistStrings.a11y.soundToggle.alert.simSoundOff;
      phet.joist.sim.utteranceQueue.addToBack( soundUtterance );
    };
    soundEnabledProperty.lazyLink( pressedListener );
    this.setPDOMAttribute( 'aria-pressed', !soundEnabledProperty.get() );

    // change the icon so that it is visible when the background changes from dark to light
    backgroundColorProperty.link( backgroundColor => {
      const baseColor = backgroundColor === 'black' ? 'white' : 'black';
      speakerNode.stroke = baseColor;
      soundOffX.stroke = baseColor;
      soundOnCurves.stroke = baseColor;
    } );
  }
}

joist.register( 'NavigationBarSoundToggleButton', NavigationBarSoundToggleButton );
export default NavigationBarSoundToggleButton;<commit_msg>added comment about font awesome, see https://github.com/phetsims/joist/issues/730<commit_after>// Copyright 2018-2021, University of Colorado Boulder

/**
 * NavigationBarSoundToggleButton is a button for controlling whether sound is enabled or disabled that is designed to
 * work on the PhET navigation bar.
 *
 * If you're wondering why this is drawn in code rather than using a Font Awesome node, please see
 * https://github.com/phetsims/tambo/issues/19.
 *
 * @author John Blanco
 * @author Chris Klusendorf
 */

import Vector2 from '../../dot/js/Vector2.js';
import Shape from '../../kite/js/Shape.js';
import merge from '../../phet-core/js/merge.js';
import Node from '../../scenery/js/nodes/Node.js';
import Path from '../../scenery/js/nodes/Path.js';
import Rectangle from '../../scenery/js/nodes/Rectangle.js';
import ToggleNode from '../../sun/js/ToggleNode.js';
import ActivationUtterance from '../../utterance-queue/js/ActivationUtterance.js';
import joist from './joist.js';
import JoistButton from './JoistButton.js';
import joistStrings from './joistStrings.js';

// constants for node background
const NODE_HEIGHT = 22.0;
const NODE_WIDTH = NODE_HEIGHT * 1.13;

// constants for drawing speaker
const SPEAKER_HEIGHT = NODE_HEIGHT * 0.77;
const SPEAKER_WIDTH = SPEAKER_HEIGHT * 0.58;
const SPEAKER_BACK_WIDTH = SPEAKER_WIDTH * 0.46;
const SPEAKER_BACK_HEIGHT = SPEAKER_HEIGHT * 0.35;
const SPEAKER_BACK_Y_SPACE = ( SPEAKER_HEIGHT - SPEAKER_BACK_HEIGHT ) / 2.0; // space between top of speaker back and top of cone
const CORNER_RADIUS = 1.0;

// constant for drawing sound off X
const X_WIDTH = SPEAKER_HEIGHT * 0.52;

// constants for drawing sound on curves
const MAX_CURVE_RADIUS = SPEAKER_HEIGHT * 0.63;
const RADIUS_STEPPER = SPEAKER_HEIGHT * 0.23;
const MED_CURVE_RADIUS = MAX_CURVE_RADIUS - RADIUS_STEPPER;
const MIN_CURVE_RADIUS = MED_CURVE_RADIUS - RADIUS_STEPPER;
const CURVE_ANGLE = Math.PI / 2.7;
const NEG_CURVE_ANGLE = CURVE_ANGLE * -1.0;

class NavigationBarSoundToggleButton extends JoistButton {

  /**
   * @param {BooleanProperty} soundEnabledProperty
   * @param {Property.<Color|string>} backgroundColorProperty
   * @param {Tandem} tandem
   * @param {Object} [options]
   */
  constructor( soundEnabledProperty, backgroundColorProperty, tandem, options ) {

    options = merge( {

      // JoistButton options
      highlightExtensionWidth: 5,
      highlightExtensionHeight: 10,
      highlightCenterOffsetY: 0,

      visiblePropertyOptions: { phetioFeatured: true },

      // pdom
      innerContent: joistStrings.a11y.soundToggle.label,

      // voicing
      voicingNameResponse: joistStrings.a11y.soundToggle.label
    }, options );

    assert && assert( options.listener === undefined, 'NavigationBarSoundToggleButton sets listener' );
    options.listener = () => soundEnabledProperty.set( !soundEnabledProperty.get() );

    const soundOnNode = new Node();
    const soundOffNode = new Node();
    const backgroundNode = new Rectangle( 0, 0, NODE_WIDTH, NODE_HEIGHT, { fill: 'transparent' } );
    soundOnNode.addChild( backgroundNode );
    soundOffNode.addChild( backgroundNode );

    // create speaker for both sound on and sound off
    const speakerNode = new Path(
      new Shape()
        .moveTo( SPEAKER_WIDTH, 0 )
        .lineTo( SPEAKER_BACK_WIDTH, SPEAKER_BACK_Y_SPACE )
        .lineTo( CORNER_RADIUS, SPEAKER_BACK_Y_SPACE )
        .arc( CORNER_RADIUS, SPEAKER_BACK_Y_SPACE + CORNER_RADIUS, CORNER_RADIUS, Math.PI * 1.5, Math.PI, true )
        .lineToRelative( 0, SPEAKER_BACK_HEIGHT - ( 2 * CORNER_RADIUS ) )
        .arc( CORNER_RADIUS, SPEAKER_BACK_Y_SPACE + SPEAKER_BACK_HEIGHT - CORNER_RADIUS, CORNER_RADIUS, Math.PI, Math.PI * 0.5, true )
        .lineToRelative( SPEAKER_BACK_WIDTH - CORNER_RADIUS, 0 )
        .lineTo( SPEAKER_WIDTH, SPEAKER_HEIGHT )
        .lineTo( SPEAKER_WIDTH, 0 )
        .close(),
      {
        stroke: 'black',
        lineWidth: 1.5,
        lineJoin: 'round',
        centerY: soundOffNode.centerY,
        left: 0
      }
    );

    soundOnNode.addChild( speakerNode );
    soundOffNode.addChild( speakerNode );

    // create X for sound off
    const soundOffX = new Path(
      new Shape().moveTo( 0, 0 ).lineTo( X_WIDTH, X_WIDTH ).moveTo( 0, X_WIDTH )
        .lineTo( X_WIDTH, 0 ),
      {
        stroke: 'black',
        lineWidth: 1.7,
        lineCap: 'round',
        right: soundOffNode.width,
        centerY: soundOffNode.centerY
      }
    );
    soundOffNode.addChild( soundOffX );

    // create curved lines for sound on
    const soundOnCurves = new Path(
      new Shape()
        .arc( 0, 0, MAX_CURVE_RADIUS, CURVE_ANGLE, NEG_CURVE_ANGLE, true )
        .moveToPoint( new Vector2( MED_CURVE_RADIUS, 0 ).rotated( CURVE_ANGLE ) )
        .arc( 0, 0, MED_CURVE_RADIUS, CURVE_ANGLE, NEG_CURVE_ANGLE, true )
        .moveToPoint( new Vector2( MIN_CURVE_RADIUS, 0 ).rotated( CURVE_ANGLE ) )
        .arc( 0, 0, MIN_CURVE_RADIUS, CURVE_ANGLE, NEG_CURVE_ANGLE, true ),
      {
        stroke: 'black',
        lineWidth: 1.7,
        lineCap: 'round',
        right: soundOnNode.width,
        centerY: soundOnNode.centerY
      }
    );
    soundOnNode.addChild( soundOnCurves );

    const toggleNode = new ToggleNode( soundEnabledProperty,
      [
        { value: true, node: soundOnNode },
        { value: false, node: soundOffNode }
      ],
      { maxHeight: NODE_HEIGHT }
    );

    super( toggleNode, backgroundColorProperty, tandem, options );

    // must be after the button is instrumented
    this.addLinkedElement( soundEnabledProperty, {
      tandem: tandem.createTandem( 'property' )
    } );

    // pdom attribute lets user know when the toggle is pressed, linked lazily so that an alert isn't triggered
    // on construction and must be unlinked in dispose
    const soundUtterance = new ActivationUtterance();
    const pressedListener = value => {
      this.setPDOMAttribute( 'aria-pressed', !value );

      soundUtterance.alert = value ? joistStrings.a11y.soundToggle.alert.simSoundOn
                                   : joistStrings.a11y.soundToggle.alert.simSoundOff;
      phet.joist.sim.utteranceQueue.addToBack( soundUtterance );
    };
    soundEnabledProperty.lazyLink( pressedListener );
    this.setPDOMAttribute( 'aria-pressed', !soundEnabledProperty.get() );

    // change the icon so that it is visible when the background changes from dark to light
    backgroundColorProperty.link( backgroundColor => {
      const baseColor = backgroundColor === 'black' ? 'white' : 'black';
      speakerNode.stroke = baseColor;
      soundOffX.stroke = baseColor;
      soundOnCurves.stroke = baseColor;
    } );
  }
}

joist.register( 'NavigationBarSoundToggleButton', NavigationBarSoundToggleButton );
export default NavigationBarSoundToggleButton;<|endoftext|>


<commit_before>// A function that builds the __new__ method for the factory function
__BRYTHON__.$__new__ = function(factory){
    return function(cls){
        /*
        if(cls===undefined){
            throw __BRYTHON__.builtins.TypeError(factory.$dict.__name__+'.__new__(): not enough arguments')
        }
        */
        var res = factory.apply(null,[])
        res.__class__ = cls.$dict
        var init_func = null
        try{init_func = __BRYTHON__.builtins.getattr(res,'__init__')}
        catch(err){__BRYTHON__.$pop_exc()}
        if(init_func!==null){
            var args = [], pos=0
            for(var i=1, _len_i = arguments.length; i < _len_i;i++){args[pos++]=arguments[i]}
            init_func.apply(null,args)
            res.__initialized__ = true
        }
        return res
    }
}

__BRYTHON__.builtins.object = (function($B){

var _b_=$B.builtins

// class object for the built-in class 'object'
var $ObjectDict = {
    //__class__:$type, : not here, added in py_type.js after $type is defined
    // __bases__ : set to an empty tuple in py_list.js after tuple is defined
    __name__:'object',
    $native:true
}

// function used to generate the methods that return 'unorderable types'
var $ObjectNI = function(name,op){
    return function(other){
        throw _b_.TypeError('unorderable types: object() '+op+
            ' '+ _b_.str($B.get_class(other).__name__)+'()')
    }
}

// Name of special methods : if they are not found as attributes, try
// the "reflected" attribute on the argument
// For instance, for "getattr(x,'__mul__')", if object x has no attribute
// "__mul__", try a function using the attribute "__rmul__" of its
// first argument

var opnames = ['add','sub','mul','truediv','floordiv','mod','pow',
    'lshift','rshift','and','xor','or']
var opsigns = ['+','-','*','/','//','%','**','<<','>>','&','^', '|']

$ObjectDict.__delattr__ = function(self,attr){delete self[attr]}

$ObjectDict.__dir__ = function(self) {
    var objects = [self], pos=1
    var mro = $B.get_class(self).__mro__
    for (var i=0, _len_i = mro.length; i < _len_i; i++) {
        objects[pos++]=mro[i]
    }

    var res = [], pos=0
    for (var i=0, _len_i = objects.length; i < _len_i; i++) {
        for(var attr in objects[i]){
            //if(attr.charAt(0)=='$' && attr.substr(0,2)!=='$$'){
            if(attr.charAt(0)=='$' && attr.charAt(1) != '$') {
                // exclude internal attributes set by Brython
                continue
            }
            if(!isNaN(parseInt(attr.charAt(0)))){
                // Exclude numerical attributes
                // '0', '1' are in attributes of string 'ab'
                continue
            }
            res[pos++]=attr
        }
    }
    res = _b_.list(_b_.set(res))
    _b_.list.$dict.sort(res)
    return res
}

$ObjectDict.__eq__ = function(self,other){
    // equality test defaults to identity of objects
    //test_issue_1393
    var _class=$B.get_class(self)
    if (_class.$native || _class.__name__ == 'function') {
       var _class1=$B.get_class(other)
       if (!_class1.$native && _class1.__name__ != 'function') {
          return _b_.getattr(other, '__eq__')(self)
       }
    }
    return self===other
}

$ObjectDict.__ge__ = $ObjectNI('__ge__','>=')

$ObjectDict.__getattribute__ = function(obj,attr){
    if (attr == '__doc__') return _b_.None
    var klass = $B.get_class(obj)
    if(attr==='__class__'){
        return klass.$factory
    }
    var res = obj[attr],args=[]

    if(res===undefined){
        // search in classes hierarchy, following method resolution order
        //if(attr=='show'){console.log('object getattr '+attr+' of obj '+obj)}
        var mro = klass.__mro__
        for(var i=0, _len_i = mro.length; i < _len_i;i++){
            var v=mro[i][attr]
            if(v!==undefined){
                res = v
                break
            }else if(attr=='__str__' && mro[i]['__repr__']!==undefined){
                // If the class doesn't define __str__ but defines __repr__,
                // use __repr__
                res = mro[i]['repr']
                break
            }
        }
    }else{
        if(res.__set__===undefined){
            // For non-data descriptors, the attribute found in object
            // dictionary takes precedence
            return res
        }
    }

    if(res!==undefined){
        var get_func = res.__get__

        if(get_func===undefined && (typeof res=='object')){
            var __get__ = _b_.getattr(res,'__get__',null);
            if(__get__ && (typeof __get__=='function')){
                get_func = function(x,y){return __get__.apply(x,[y,klass])}
            }
        }

        if(get_func===undefined && (typeof res=='function')){
            get_func = function(x){return x}
        }
        if(get_func!==undefined){ // descriptor
            res.__name__ = attr
            // __new__ is a static method
            if(attr=='__new__'){res.$type='staticmethod'}
            var res1 = get_func.apply(null,[res,obj,klass])
            if(typeof res1=='function'){
                // If attribute is a class then return it unchanged
                //
                // Example :
                // ===============
                // class A:
                //    def __init__(self,x):
                //        self.x = x
                //
                // class B:
                //    foo = A
                //    def __init__(self):
                //        self.info = self.foo(18)
                //
                // B()
                // ===============
                // In class B, when we call self.foo(18), self.foo is the
                // class A, its method __init__ must be called without B's
                // self as first argument

                if(res1.__class__===$B.$factory) return res

                // instance method object
                return $B.make_method(attr, klass, res, res1)(obj)
                var __self__,__func__=res,__repr__,__str__
                switch(res.$type) {
                  case undefined:
                  case 'function':
                    //if(res.$type===undefined || res.$type=='function'){
                    // the attribute is a function : return an instance method,
                    // called with the instance as first argument
                    args = [obj]
                    __self__ = obj
                    __func__ = res1
                    __repr__ = __str__ = function(){
                        var x = '<bound method '+attr
                        x += " of '"+klass.__name__+"' object>"
                        return x
                    }
                    break
                  case 'instancemethod':
                    //}else if(res.$type==='instancemethod'){
                    // The attribute is a method of an instance of another class
                    // Return it unchanged
                    return res
                  case 'classmethod':
                    //}else if(res.$type==='classmethod'){
                    // class method : called with the class as first argument
                    args = [klass]
                    __self__ = klass
                    __func__ = res1
                    __repr__ = __str__ = function(){
                        var x = '<bound method type'+'.'+attr
                        x += ' of '+klass.__name__+'>'
                        return x
                    }
                    break
                  case 'staticmethod':
                    //}else if(res.$type==='staticmethod'){
                    // static methods have no __self__ or __func__
                    args = []
                    __repr__ = __str__ = function(){
                        return '<function '+klass.__name__+'.'+attr+'>'
                    }
                }

                // build the instance method, called with a list of arguments
                // depending on the method type
                var method = (function(initial_args){
                    return function(){
                        // make a local copy of initial args
                        var local_args = initial_args.slice()
                        var pos=local_args.length
                        for(var i=0, _len_i = arguments.length; i < _len_i;i++){
                            local_args[pos++]=arguments[i]
                        }
                        var x = res.apply(obj,local_args)
                        if(x===undefined) return _b_.None
                        return x
                    }})(args)
                method.__class__ = $B.$InstanceMethodDict
                method.__eq__ = function(other){
                    return other.$res === res
                }
                method.__func__ = __func__
                method.__repr__ = __repr__
                method.__self__ = __self__
                method.__str__ = __str__
                method.__code__ = {'__class__' : $B.CodeDict}
                method.__doc__ = res.__doc__ || ''
                method.$type = 'instancemethod'
                method.$res = res
                return method
            }else{
                // result of __get__ is not a function
                return res1
            }
        }
        // attribute is not a descriptor : return it unchanged
        return res
    }else{
        // search __getattr__
        var _ga = obj['__getattr__']
        if(_ga===undefined){
            var mro = klass.__mro__
            if(mro===undefined){console.log('in getattr mro undefined for '+obj)}
            for(var i=0, _len_i = mro.length; i < _len_i;i++){
                var v=mro[i]['__getattr__']
                if(v!==undefined){
                    _ga = v
                    break
                }
            }
        }
        if(_ga!==undefined){
            try{return _ga(obj,attr)}
            catch(err){$B.$pop_exc()}
        }
        // for special methods such as __mul__, look for __rmul__ on operand
        if(attr.substr(0,2)=='__' && attr.substr(attr.length-2)=='__'){
            var attr1 = attr.substr(2,attr.length-4) // stripped of __
            var rank = opnames.indexOf(attr1)
            if(rank > -1){
                var rop = '__r'+opnames[rank]+'__' // name of reflected operator
                return function(){
                    try{
                        // Operands must be of different types
                        if($B.$get_class(arguments[0])===klass){throw Error('')}
                        return _b_.getattr(arguments[0],rop)(obj)
                    }catch(err){
                        var msg = "unsupported operand types for "+opsigns[rank]+": '"
                        msg += klass.__name__+"' and '" //+arguments[0].__class__.__name__+"'"
                        throw _b_.TypeError(msg)
                    }
                }
            }
        }
        //throw AttributeError('object '+obj.__class__.__name__+" has no attribute '"+attr+"'")
    }
}

$ObjectDict.__gt__ = $ObjectNI('__gt__','>')

$ObjectDict.__hash__ = function (self) {
    $B.$py_next_hash+=1;
    return $B.$py_next_hash;
}

$ObjectDict.__init__ = function(){}

$ObjectDict.__le__ = $ObjectNI('__le__','<=')

$ObjectDict.__lt__ = $ObjectNI('__lt__','<')

$ObjectDict.__mro__ = [$ObjectDict]

$ObjectDict.__new__ = function(cls){
    if(cls===undefined){throw _b_.TypeError('object.__new__(): not enough arguments')}
    return {__class__ : cls.$dict}
}

$ObjectDict.__ne__ = function(self,other){return !$ObjectDict.__eq__(self,other)}

$ObjectDict.__or__ = function(self,other){
    if(_b_.bool(self)) return self
    return other
}

$ObjectDict.__repr__ = function(self){
    if(self===object) return "<class 'object'>"
    if(self.__class__===$B.$factory) return "<class '"+self.$dict.__name__+"'>"
    return "<"+self.__class__.__name__+" object>"
}

$ObjectDict.__setattr__ = function(self,attr,val){
    if(val===undefined){ // setting an attribute to 'object' type is not allowed
        throw _b_.TypeError("can't set attributes of built-in/extension type 'object'")
    }else if(self.__class__===$ObjectDict){
        // setting an attribute to object() is not allowed
        if($ObjectDict[attr]===undefined){
            throw _b_.AttributeError("'object' object has no attribute '"+attr+"'")
        }else{
            throw _b_.AttributeError("'object' object attribute '"+attr+"' is read-only")
        }
    }
    self[attr] = val
}
$ObjectDict.__setattr__.__str__ = function(){return 'method object.setattr'}

$ObjectDict.__str__ = $ObjectDict.__repr__

$ObjectDict.__subclasshook__ = function(){return _b_.NotImplemented}

// constructor of the built-in class 'object'
function object(){return {__class__:$ObjectDict}}

object.$dict = $ObjectDict
// object.__class__ = $factory : this is done in py_types
$ObjectDict.$factory = object
object.__repr__ = object.__str__ = function(){return "<class 'object'>"}

return object

})(__BRYTHON__)
<commit_msg>Remove code from py_object.js, now in py_type.js/$B.make_method<commit_after>// A function that builds the __new__ method for the factory function
__BRYTHON__.$__new__ = function(factory){
    return function(cls){
        /*
        if(cls===undefined){
            throw __BRYTHON__.builtins.TypeError(factory.$dict.__name__+'.__new__(): not enough arguments')
        }
        */
        var res = factory.apply(null,[])
        res.__class__ = cls.$dict
        var init_func = null
        try{init_func = __BRYTHON__.builtins.getattr(res,'__init__')}
        catch(err){__BRYTHON__.$pop_exc()}
        if(init_func!==null){
            var args = [], pos=0
            for(var i=1, _len_i = arguments.length; i < _len_i;i++){args[pos++]=arguments[i]}
            init_func.apply(null,args)
            res.__initialized__ = true
        }
        return res
    }
}

__BRYTHON__.builtins.object = (function($B){

var _b_=$B.builtins

// class object for the built-in class 'object'
var $ObjectDict = {
    //__class__:$type, : not here, added in py_type.js after $type is defined
    // __bases__ : set to an empty tuple in py_list.js after tuple is defined
    __name__:'object',
    $native:true
}

// function used to generate the methods that return 'unorderable types'
var $ObjectNI = function(name,op){
    return function(other){
        throw _b_.TypeError('unorderable types: object() '+op+
            ' '+ _b_.str($B.get_class(other).__name__)+'()')
    }
}

// Name of special methods : if they are not found as attributes, try
// the "reflected" attribute on the argument
// For instance, for "getattr(x,'__mul__')", if object x has no attribute
// "__mul__", try a function using the attribute "__rmul__" of its
// first argument

var opnames = ['add','sub','mul','truediv','floordiv','mod','pow',
    'lshift','rshift','and','xor','or']
var opsigns = ['+','-','*','/','//','%','**','<<','>>','&','^', '|']

$ObjectDict.__delattr__ = function(self,attr){delete self[attr]}

$ObjectDict.__dir__ = function(self) {
    var objects = [self], pos=1
    var mro = $B.get_class(self).__mro__
    for (var i=0, _len_i = mro.length; i < _len_i; i++) {
        objects[pos++]=mro[i]
    }

    var res = [], pos=0
    for (var i=0, _len_i = objects.length; i < _len_i; i++) {
        for(var attr in objects[i]){
            //if(attr.charAt(0)=='$' && attr.substr(0,2)!=='$$'){
            if(attr.charAt(0)=='$' && attr.charAt(1) != '$') {
                // exclude internal attributes set by Brython
                continue
            }
            if(!isNaN(parseInt(attr.charAt(0)))){
                // Exclude numerical attributes
                // '0', '1' are in attributes of string 'ab'
                continue
            }
            res[pos++]=attr
        }
    }
    res = _b_.list(_b_.set(res))
    _b_.list.$dict.sort(res)
    return res
}

$ObjectDict.__eq__ = function(self,other){
    // equality test defaults to identity of objects
    //test_issue_1393
    var _class=$B.get_class(self)
    if (_class.$native || _class.__name__ == 'function') {
       var _class1=$B.get_class(other)
       if (!_class1.$native && _class1.__name__ != 'function') {
          return _b_.getattr(other, '__eq__')(self)
       }
    }
    return self===other
}

$ObjectDict.__ge__ = $ObjectNI('__ge__','>=')

$ObjectDict.__getattribute__ = function(obj,attr){
    if (attr == '__doc__') return _b_.None
    var klass = $B.get_class(obj)
    if(attr==='__class__'){
        return klass.$factory
    }
    var res = obj[attr],args=[]

    if(res===undefined){
        // search in classes hierarchy, following method resolution order
        //if(attr=='show'){console.log('object getattr '+attr+' of obj '+obj)}
        var mro = klass.__mro__
        for(var i=0, _len_i = mro.length; i < _len_i;i++){
            //console.log('class '+mro[i].__name__+' $methods '+mro[i].$methods)
            if(mro[i].$methods){
                var method = mro[i].$methods[attr]
                if(method!==undefined){
                    //console.log('object method '+attr)
                    return method(obj)
                }
            }
            var v=mro[i][attr]
            if(v!==undefined){
                res = v
                break
            }else if(attr=='__str__' && mro[i]['__repr__']!==undefined){
                // If the class doesn't define __str__ but defines __repr__,
                // use __repr__
                res = mro[i]['repr']
                break
            }
        }
    }else{
        if(res.__set__===undefined){
            // For non-data descriptors, the attribute found in object
            // dictionary takes precedence
            return res
        }
    }

    if(res!==undefined){
        var get_func = res.__get__

        if(get_func===undefined && (typeof res=='object')){
            var __get__ = _b_.getattr(res,'__get__',null);
            if(__get__ && (typeof __get__=='function')){
                get_func = function(x,y){return __get__.apply(x,[y,klass])}
            }
        }

        if(get_func===undefined && (typeof res=='function')){
            get_func = function(x){return x}
        }
        if(get_func!==undefined){ // descriptor
            res.__name__ = attr
            // __new__ is a static method
            if(attr=='__new__'){res.$type='staticmethod'}
            var res1 = get_func.apply(null,[res,obj,klass])
            if(typeof res1=='function'){
                // If attribute is a class then return it unchanged
                //
                // Example :
                // ===============
                // class A:
                //    def __init__(self,x):
                //        self.x = x
                //
                // class B:
                //    foo = A
                //    def __init__(self):
                //        self.info = self.foo(18)
                //
                // B()
                // ===============
                // In class B, when we call self.foo(18), self.foo is the
                // class A, its method __init__ must be called without B's
                // self as first argument

                if(res1.__class__===$B.$factory) return res

                // instance method object
                return $B.make_method(attr, klass, res, res1)(obj)
            }else{
                // result of __get__ is not a function
                return res1
            }
        }
        // attribute is not a descriptor : return it unchanged
        return res
    }else{
        // search __getattr__
        var _ga = obj['__getattr__']
        if(_ga===undefined){
            var mro = klass.__mro__
            if(mro===undefined){console.log('in getattr mro undefined for '+obj)}
            for(var i=0, _len_i = mro.length; i < _len_i;i++){
                var v=mro[i]['__getattr__']
                if(v!==undefined){
                    _ga = v
                    break
                }
            }
        }
        if(_ga!==undefined){
            try{return _ga(obj,attr)}
            catch(err){$B.$pop_exc()}
        }
        // for special methods such as __mul__, look for __rmul__ on operand
        if(attr.substr(0,2)=='__' && attr.substr(attr.length-2)=='__'){
            var attr1 = attr.substr(2,attr.length-4) // stripped of __
            var rank = opnames.indexOf(attr1)
            if(rank > -1){
                var rop = '__r'+opnames[rank]+'__' // name of reflected operator
                return function(){
                    try{
                        // Operands must be of different types
                        if($B.$get_class(arguments[0])===klass){throw Error('')}
                        return _b_.getattr(arguments[0],rop)(obj)
                    }catch(err){
                        var msg = "unsupported operand types for "+opsigns[rank]+": '"
                        msg += klass.__name__+"' and '" //+arguments[0].__class__.__name__+"'"
                        throw _b_.TypeError(msg)
                    }
                }
            }
        }
        //throw AttributeError('object '+obj.__class__.__name__+" has no attribute '"+attr+"'")
    }
}

$ObjectDict.__gt__ = $ObjectNI('__gt__','>')

$ObjectDict.__hash__ = function (self) {
    $B.$py_next_hash+=1;
    return $B.$py_next_hash;
}

$ObjectDict.__init__ = function(){}

$ObjectDict.__le__ = $ObjectNI('__le__','<=')

$ObjectDict.__lt__ = $ObjectNI('__lt__','<')

$ObjectDict.__mro__ = [$ObjectDict]

$ObjectDict.__new__ = function(cls){
    if(cls===undefined){throw _b_.TypeError('object.__new__(): not enough arguments')}
    return {__class__ : cls.$dict}
}

$ObjectDict.__ne__ = function(self,other){return !$ObjectDict.__eq__(self,other)}

$ObjectDict.__or__ = function(self,other){
    if(_b_.bool(self)) return self
    return other
}

$ObjectDict.__repr__ = function(self){
    if(self===object) return "<class 'object'>"
    if(self.__class__===$B.$factory) return "<class '"+self.$dict.__name__+"'>"
    return "<"+self.__class__.__name__+" object>"
}

$ObjectDict.__setattr__ = function(self,attr,val){
    if(val===undefined){ // setting an attribute to 'object' type is not allowed
        throw _b_.TypeError("can't set attributes of built-in/extension type 'object'")
    }else if(self.__class__===$ObjectDict){
        // setting an attribute to object() is not allowed
        if($ObjectDict[attr]===undefined){
            throw _b_.AttributeError("'object' object has no attribute '"+attr+"'")
        }else{
            throw _b_.AttributeError("'object' object attribute '"+attr+"' is read-only")
        }
    }
    self[attr] = val
}
$ObjectDict.__setattr__.__str__ = function(){return 'method object.setattr'}

$ObjectDict.__str__ = $ObjectDict.__repr__

$ObjectDict.__subclasshook__ = function(){return _b_.NotImplemented}

// constructor of the built-in class 'object'
function object(){return {__class__:$ObjectDict}}

object.$dict = $ObjectDict
// object.__class__ = $factory : this is done in py_types
$ObjectDict.$factory = object
object.__repr__ = object.__str__ = function(){return "<class 'object'>"}

return object

})(__BRYTHON__)
<|endoftext|>


<commit_before>/*
	The MIT License (MIT)

	Copyright (c) 2013 Fernando Bevilacqua

	Permission is hereby granted, free of charge, to any person obtaining a copy of
	this software and associated documentation files (the "Software"), to deal in
	the Software without restriction, including without limitation the rights to
	use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
	the Software, and to permit persons to whom the Software is furnished to do so,
	subject to the following conditions:

	The above copyright notice and this permission notice shall be included in all
	copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
	FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
	COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
	IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
	CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

var CodebotPreferencesUI = function() {
    var mSelf = 0;
    var mSections = {};
    var mCodebot = null;

    /**
     * Add a new section to the preferences panel. A section is a link that, when clicked, opens
     * a new panel with more preferences (e.g. UI preferences).
     *
     * @param {Object} theObj - an object describing the new section. It has the following structure: {id: string, title: string, icon: string, panel: function}. The panel property should be a function able to render a panel.
     */
    this.addSection = function(theObj) {
        mSections[theObj.id] = theObj;
    }

    var editor = function(theContainer, theContext) {
        var aContent = '';

        aContent += '
';
            aContent += '
'+
                            '
Editor
'+
                            ''+
                        '
';
        aContent += '
';

        theContainer.append(aContent);

        $('#codebotPrefEditorBackButton').click(function() {
            theContext.ui.slidePanel.popState();
        });
    };

    var shortcuts = function(theContainer, theContext) {
        var aContent = '';

        aContent += '
';
            aContent += '
'+
                            '
Shortcuts
'+
                            ''+
                        '
';
        aContent += '
';

        theContainer.append(aContent);

        $('#codebotPrefEditorBackButton').click(function() {
            theContext.ui.slidePanel.popState();
        });
    };

    var appearance = function(theContainer, theContext) {
        var aContent = '';

        aContent += '
';
            aContent += '
'+
                            '
UI and Appearance
'+
                            ''+
                        '
';
        aContent += '
';

        theContainer.append(aContent);

        $('#codebotPrefEditorBackButton').click(function() {
            theContext.ui.slidePanel.popState();
        });
    };

    var extensions = function(theContainer, theContext) {
        var aContent = '';

        aContent += '
';
            aContent += '
'+
                            '
Extensions
'+
                            ''+
                        '
';
        aContent += '
';

        theContainer.append(aContent);

        $('#codebotPrefEditorBackButton').click(function() {
            theContext.ui.slidePanel.popState();
        });
    };

    var devenvs = function(theContainer, theContext) {
        var aContent = '';

        aContent += '
';
            aContent += '
'+
                            '
Development Environments
'+
                            ''+
                        '
';
        aContent += '
';

        theContainer.append(aContent);

        $('#codebotPrefEditorBackButton').click(function() {
            theContext.ui.slidePanel.popState();
        });
    };

    var about = function(theContainer, theContext) {
        var aContent = '';

        aContent += '
';
            aContent += '
'+
                            '
About
'+
                            ''+
                        '
';
        aContent += '
';

        theContainer.append(aContent);

        $('#codebotPrefEditorBackButton').click(function() {
            theContext.ui.slidePanel.popState();
        });
    };

    var bugs = function(theContainer, theContext) {
        var aContent = '';

        aContent += '
';
            aContent += '
'+
                            '
Bugs
'+
                            ''+
                        '
';
        aContent += '
';

        theContainer.append(aContent);

        $('#codebotPrefEditorBackButton').click(function() {
            theContext.ui.slidePanel.popState();
        });
    };

    this.main = function(theContainer, theContext) {
        var aOptions = '';
        var aContent = '';

        aContent += '
';
        aContent += '
'+
                        '
Preferences
'+
                        ''+
                    '
';

        aContent += '
';

        for(var aId in mSections) {
            aContent += '
'+ mSections[aId].icon +' '+ mSections[aId].title +'
';
        }

        aContent += '
';
        aContent += '
';

        theContainer.append(aContent);

        theContainer.find('li a').each(function(i, e) {
            $(e).click(function() {
                var aId = $(this).data('section');
                theContext.ui.slidePanel.pushState(mSections[aId].panel);
            });
        });

        $('#codebotPrefBackButton').click(function() {
            theContext.ui.slidePanel.popState();
        });
    };

    this.init = function(theCodebot) {
        mSelf = this;
        mCodebot = theCodebot;

        // TODO: move it to a better place?
        mSelf.addSection({id: 'editor', title: 'Editor', icon: '', panel: editor});
        mSelf.addSection({id: 'shortcuts', title: 'Shortcuts', icon: '', panel: shortcuts});
        mSelf.addSection({id: 'appearance', title: 'UI and Appearance', icon: '', panel: appearance});
        mSelf.addSection({id: 'extensions', title: 'Extensions', icon: '', panel: extensions});
        mSelf.addSection({id: 'devenvs', title: 'Development Environments', icon: '', panel: devenvs});
        mSelf.addSection({id: 'about', title: 'About and Updates', icon: '', panel: about});
        mSelf.addSection({id: 'bugs', title: 'Feedback and Bug Report', icon: '', panel: bugs});
    };
};<commit_msg>List preference properties on editor section<commit_after>/*
	The MIT License (MIT)

	Copyright (c) 2013 Fernando Bevilacqua

	Permission is hereby granted, free of charge, to any person obtaining a copy of
	this software and associated documentation files (the "Software"), to deal in
	the Software without restriction, including without limitation the rights to
	use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
	the Software, and to permit persons to whom the Software is furnished to do so,
	subject to the following conditions:

	The above copyright notice and this permission notice shall be included in all
	copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
	FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
	COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
	IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
	CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

var CodebotPreferencesUI = function() {
    var mSelf = 0;
    var mSections = {};
    var mCodebot = null;

    // From: https://github.com/ajaxorg/ace/wiki/Configuring-Ace
    // Where not indicated otherwise option values are boolean.
    var mEditorPrefs = {
        // editor
        selectionStyle: {name: 'Selection style', value: ["line", "text"]},
        highlightActiveLine: {name: 'Hightlight active line', value: null},
        highlightSelectedWord: {name: 'Hightlight selected word', value: Number, tip: 'This is a tip.'}
        /*
        readOnly: ,
        cursorStyle: "ace"|"slim"|"smooth"|"wide",
        mergeUndoDeltas: false true "always",
        behavioursEnabled: ,
        wrapBehavioursEnabled:,
        autoScrollEditorIntoView: ,// this is needed if editor is inside scrollable page

        // renderer
        hScrollBarAlwaysVisible: ,
        vScrollBarAlwaysVisible: ,
        highlightGutterLine: ,
        animatedScroll: ,
        showInvisibles:,
        showPrintMargin:,
        printMarginColumn:,
        printMargin:,
        fadeFoldWidgets:,
        showFoldWidgets:,
        showLineNumbers:,
        showGutter:,
        displayIndentGuides:,
        fontSize: number or css font-size string,
        fontFamily: css,
        maxLines: ,
        minLines:,
        scrollPastEnd: ,
        fixedWidthGutter:,
        theme: path to a theme e.g "ace/theme/textmate",

        // mouse
        scrollSpeed: number,
        dragDelay:  number,
        dragEnabled:,
        focusTimout: number,
        tooltipFollowsMouse:,

        // session
        firstLineNumber: number,
        overwrite:,
        newLineMode:,
        useWorker:,
        useSoftTabs:,
        tabSize: number,
        wrap: ,
        foldStyle:,
        mode: path to a mode e.g "ace/mode/text"*/
    };

    var convertConfigOptionToFormElement = function(theConfigId, theConfigDescription, theValues) {
        var aValue = theConfigDescription.value;
        var aRet = '';
        var aDiskValue = theValues ? theValues[theConfigId] || '' : '';

        if(aValue instanceof Array) {
            aRet = '<select name="'+theConfigId+'">';
            for(var i = 0; i < aValue.length; i++) {
                aRet += '<option value="' + aValue[i] + '" '+(aDiskValue == aValue[i] ? ' selected="selected" ' : '')+'>' + aValue[i] + '</option>';
            }
            aRet += '</select>';

        } else if(aValue === null) {
            aRet = '<input type="checkbox" style="margin-top: -5px" id="' + theConfigId + '" value="' + aDiskValue + '" '+(Boolean(aDiskValue) ? ' checked="checked" ' : '')+' />';

        } else {
            aRet = '<input type="text" class="form-control input-sm" style="margin-top: -5px;" id="' + theConfigId + '" value="' + aDiskValue + '" />';
        }

        return aRet;
    };

    /**
     * Add a new section to the preferences panel. A section is a link that, when clicked, opens
     * a new panel with more preferences (e.g. UI preferences).
     *
     * @param {Object} theObj - an object describing the new section. It has the following structure: {id: string, title: string, icon: string, panel: function}. The panel property should be a function able to render a panel.
     */
    this.addSection = function(theObj) {
        mSections[theObj.id] = theObj;
    }

    var editor = function(theContainer, theContext) {
        var aContent = '';
        var aPrefsFromDisk = mCodebot.preferences.get().editor;

        aContent += '
';
            aContent += '
'+
                            '
Editor
'+
                            ''+
                        '
';

            aContent += '<form class="form-horizontal" role="form">';

            for(var aId in mEditorPrefs) {
                aContent += '
';

                  aContent += '
'+
                                '
' + mEditorPrefs[aId].name +
                                    (mEditorPrefs[aId].tip ? ' ' : '') +
                                '
'+
                                '
'+
                                    convertConfigOptionToFormElement(aId, mEditorPrefs[aId], aPrefsFromDisk) +
                                '
'+
                              '
';
                aContent += '
';
            }

            aContent += '</form>';
        aContent += '
';

        theContainer.append(aContent);

        $('#codebotPrefEditorBackButton').click(function() {
            theContext.ui.slidePanel.popState();
        });
    };

    var shortcuts = function(theContainer, theContext) {
        var aContent = '';

        aContent += '
';
            aContent += '
'+
                            '
Shortcuts
'+
                            ''+
                        '
';
        aContent += '
';

        theContainer.append(aContent);

        $('#codebotPrefEditorBackButton').click(function() {
            theContext.ui.slidePanel.popState();
        });
    };

    var appearance = function(theContainer, theContext) {
        var aContent = '';

        aContent += '
';
            aContent += '
'+
                            '
UI and Appearance
'+
                            ''+
                        '
';
        aContent += '
';

        theContainer.append(aContent);

        $('#codebotPrefEditorBackButton').click(function() {
            theContext.ui.slidePanel.popState();
        });
    };

    var extensions = function(theContainer, theContext) {
        var aContent = '';

        aContent += '
';
            aContent += '
'+
                            '
Extensions
'+
                            ''+
                        '
';
        aContent += '
';

        theContainer.append(aContent);

        $('#codebotPrefEditorBackButton').click(function() {
            theContext.ui.slidePanel.popState();
        });
    };

    var devenvs = function(theContainer, theContext) {
        var aContent = '';

        aContent += '
';
            aContent += '
'+
                            '
Development Environments
'+
                            ''+
                        '
';
        aContent += '
';

        theContainer.append(aContent);

        $('#codebotPrefEditorBackButton').click(function() {
            theContext.ui.slidePanel.popState();
        });
    };

    var about = function(theContainer, theContext) {
        var aContent = '';

        aContent += '
';
            aContent += '
'+
                            '
About
'+
                            ''+
                        '
';
        aContent += '
';

        theContainer.append(aContent);

        $('#codebotPrefEditorBackButton').click(function() {
            theContext.ui.slidePanel.popState();
        });
    };

    var bugs = function(theContainer, theContext) {
        var aContent = '';

        aContent += '
';
            aContent += '
'+
                            '
Bugs
'+
                            ''+
                        '
';
        aContent += '
';

        theContainer.append(aContent);

        $('#codebotPrefEditorBackButton').click(function() {
            theContext.ui.slidePanel.popState();
        });
    };

    this.main = function(theContainer, theContext) {
        var aOptions = '';
        var aContent = '';

        aContent += '
';
        aContent += '
'+
                        '
Preferences
'+
                        ''+
                    '
';

        aContent += '
';

        for(var aId in mSections) {
            aContent += '
'+ mSections[aId].icon +' '+ mSections[aId].title +'
';
        }

        aContent += '
';
        aContent += '
';

        theContainer.append(aContent);

        theContainer.find('li a').each(function(i, e) {
            $(e).click(function() {
                var aId = $(this).data('section');
                theContext.ui.slidePanel.pushState(mSections[aId].panel);
            });
        });

        $('#codebotPrefBackButton').click(function() {
            theContext.ui.slidePanel.popState();
        });
    };

    this.init = function(theCodebot) {
        mSelf = this;
        mCodebot = theCodebot;

        // TODO: move it to a better place?
        mSelf.addSection({id: 'editor', title: 'Editor', icon: '', panel: editor});
        mSelf.addSection({id: 'shortcuts', title: 'Shortcuts', icon: '', panel: shortcuts});
        mSelf.addSection({id: 'appearance', title: 'UI and Appearance', icon: '', panel: appearance});
        mSelf.addSection({id: 'extensions', title: 'Extensions', icon: '', panel: extensions});
        mSelf.addSection({id: 'devenvs', title: 'Development Environments', icon: '', panel: devenvs});
        mSelf.addSection({id: 'about', title: 'About and Updates', icon: '', panel: about});
        mSelf.addSection({id: 'bugs', title: 'Feedback and Bug Report', icon: '', panel: bugs});
    };
};<|endoftext|>