code: def attributes_js(cls, attributes):
          
          assign_template = '{assign}{{id: {obj_name}["id"], value: {obj_name}{attr_getters}}};\n'
          conditional_template = 'if (({obj_name} != undefined)) {{ {assign} }}'
          code = ''
          for key, attr_path in sorted(attributes.items()):
              data_assign = 'data["{key}"] = '.format(key=key)
              attrs = attr_path.split('.')
              obj_name = attrs[0]
              attr_getters = ''.join(['["{attr}"]'.format(attr=attr)
                                      for attr in attrs[1:]])
              if obj_name not in ['cb_obj', 'cb_data']:
                  assign_str = assign_template.format(
                      assign=data_assign, obj_name=obj_name, attr_getters=attr_getters
                  )
                  code += conditional_template.format(
                      obj_name=obj_name, assign=assign_str
                  )
              else:
                  assign_str = ''.join([data_assign, obj_name, attr_getters, ';\n'])
                  code += assign_str
          return code
docs: Generates JS code to look up attributes on JS objects from
          an attributes specification dictionary. If the specification
          references a plotting particular plotting handle it will also
          generate JS code to get the ID of the object.
  
          Simple example (when referencing cb_data or cb_obj):
  
          Input  : {'x': 'cb_data.geometry.x'}
  
          Output : data['x'] = cb_data['geometry']['x']
  
          Example referencing plot handle:
  
          Input  : {'x0': 'x_range.attributes.start'}
  
          Output : if ((x_range !== undefined)) {
                      data['x0'] = {id: x_range['id'], value: x_range['attributes']['start']}
                   }