<commit_before>var TestCheddarFrom = require('../../globals').TestCheddarFrom;
var chai = require('chai');
var expect = chai.expect;
chai.should();

describe('Numbers', function(){
    describe('addition', function(){
        it('should work', TestCheddarFrom.Code(
            'print "2+3=" + String::(2+3)',
            '2+3=5'
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(+)'
//        ))
    })

    describe('subtraction', function(){
        describe('negative number', function(){
            it('should work', TestCheddarFrom.Code(
                'print "-3=" + String::(-3)',
                '-3=-3'
            ))
        })
        it('should work', TestCheddarFrom.Code(
            'print "5-3=" + String::(5-3)',
            '5-3=2'
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(-)'
//        ))
    })
    describe('multiplication', function(){
        it('should work', TestCheddarFrom.Code(
            'print "3*3=" + String::(3*3)',
            '3*3=9'
        ))
    })
    describe('repetition', function(){
        it('should work', TestCheddarFrom.Code(
            'print \'3*"foo"=\' + 3*"foo"',
            '3*"foo"=foofoofoo'
        ))
    })
    describe('division', function(){
        it('should work', TestCheddarFrom.Code(
            'print "10/5=" + String::(10/5)',
            '10/5=2'
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(/)'
//        ))
    })
    describe('powers', function(){
        it('should work', TestCheddarFrom.Code(
            'print "2^2=" + String::(2^2)',
            '2^2=4'
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(^)'
//        ))
    })
    describe('modulo', function(){
        it('should work', TestCheddarFrom.Code(
            'print "10%100=" + String::(10%100)',
            '10%100=10'
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(%)'
//        ))
    })
    describe('less than', function(){
        it('should work', TestCheddarFrom.Code(
            'print "5>4=" + String::(5>4)',
            '5>4=true'
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(>)'
//        ))
    })
    describe('more than', function(){
        it('should work', TestCheddarFrom.Code(
            'print "5<4=" + String::(5<4)',
            '5<4=false'
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(<)'
//        ))
    })
    describe('equal to', function(){
        it('should work', TestCheddarFrom.Code(
            'print "4==4=" + String::(4==4)',
            '4==4=true'
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(==)'
//        ))
    })
    describe('not equal to', function(){
        it('should work', TestCheddarFrom.Code(
            'print "4!=4=" + String::(4!=4)',
            '4!=4=false'
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(!=)'
//        ))
    })
    describe('less than or equal to', function(){
        it('should work', TestCheddarFrom.Code(
            'print "4>=4=" + String::(4>=4)',
            '4>=4=true'
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(>=)'
//        ))
    })
    describe('more than or equal to', function(){
        it('should work', TestCheddarFrom.Code(
            'print "4<=4=" + String::(4<=4)',
            '4<=4=true'
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(<=)'
//        ))
    })
    describe('bitwise and', function(){
        it('should work', TestCheddarFrom.Code(
            'print "4&4=" + String::(4 & 4)',
            '4&4=' + (4 & 4)
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(&)'
//        ))
    })
    describe('bitwise or', function(){
        it('should work', TestCheddarFrom.Code(
            'print "4|4=" + String::(4 | 4)',
            '4|4=' + (4 | 4)
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(|)'
//        ))
    })

    describe('xor', function(){
        it('should work', TestCheddarFrom.Code(
            'print "4 xor 3=" + String::(4 xor 3)',
            '4 xor 3=' + (4 ^ 3)
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(|)'
//        ))
    })

    describe('right shift', function(){
        it('should work', TestCheddarFrom.Code(
            'print "4>>3=" + String::(4>>3)',
            '4>>3=' + (4 >> 3)
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(|)'
//        ))
    })

    describe('left shift', function(){
        it('should work', TestCheddarFrom.Code(
            'print "4<<3=" + String::(4<<3)',
            '4<<3=' + (4<<3)
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(|)'
//        ))
    })

    describe('sign', function(){
        it('unary should work', TestCheddarFrom.Code(
            'print "sign 3=" + String::(sign 3)',
            'sign 3=' + Math.sign(3)
        ))

        it('binary should work', TestCheddarFrom.Code(
            'print "1 sign 3=" + String::(1 sign 3)',
            '1 sign 3=-1'
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(sign)'
//        ))
    })
    describe('square root', function(){
        it('should work', TestCheddarFrom.Code(
            'print "sqrt 9=" + String::(sqrt 9)',
            'sqrt 9=' + Math.sqrt(9)
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(sqrt)'
//        ))
    })
    describe('cube root', function(){
        it('should work', TestCheddarFrom.Code(
            'print "cbrt 8=" + String::(cbrt 8)',
            'cbrt 8=' + Math.cbrt(8)
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(cbrt)'
//        ))
    })
    describe('n root', function(){
        it('should work', TestCheddarFrom.Code(
            'print "8 root 3=" + String::(8 root 3)',
            '8 root 3=2'
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(root)'
//        ))
    })

    describe('log', function(){
        it('unary should work', TestCheddarFrom.Code(
            'print "log Math.E=" + String::(log Math.E)',
            'log Math.E=1'
        ))

        it('binary should work', TestCheddarFrom.Code(
            'print "16 log 2=" + String::(16 log 2)',
            '16 log 2=4'
        ))
    })

    describe('ceil', function(){
        it('should work', TestCheddarFrom.Code(
            'print "ceil 1.6=" + String::(ceil 1.6)',
            'ceil 1.6=2'
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(ceil)'
//        ))
    })
    describe('floor', function(){
        it('should work', TestCheddarFrom.Code(
            'print "floor 1.2=" + String::(floor 1.2)',
            'floor 1.2=1'
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(floor)'
//        ))
    })
    describe('round', function(){
        it('should work', TestCheddarFrom.Code(
            'print "round 1.2=" + String::(round 1.2)',
            'round 1.2=1'
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(round)'
//        ))
    })

    describe('abs', function(){
        it('should work', TestCheddarFrom.Code(
            'print "abs -1=" + String::(abs -1)',
            'abs -1=1'
        ))
    })

    describe('range', function(){
        it('should work', TestCheddarFrom.Code(
            'print "1:5=" + String::(1:5)',
            '1:5=[1, 2, 3, 4, 5]'
        ))

        it('should work reversed', TestCheddarFrom.Code(
            'print "5:1=" + String::(5:1)',
            '5:1=[5, 4, 3, 2, 1]'
        ))
    })

    describe('char', function(){
        it('should work', TestCheddarFrom.Code(
            'print \'@"65=\' + @" 65',
            '@"65=A'
        ))
    })
});
<commit_msg>fix [range]: update tests<commit_after>var TestCheddarFrom = require('../../globals').TestCheddarFrom;
var chai = require('chai');
var expect = chai.expect;
chai.should();

describe('Numbers', function(){
    describe('addition', function(){
        it('should work', TestCheddarFrom.Code(
            'print "2+3=" + String::(2+3)',
            '2+3=5'
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(+)'
//        ))
    })

    describe('subtraction', function(){
        describe('negative number', function(){
            it('should work', TestCheddarFrom.Code(
                'print "-3=" + String::(-3)',
                '-3=-3'
            ))
        })
        it('should work', TestCheddarFrom.Code(
            'print "5-3=" + String::(5-3)',
            '5-3=2'
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(-)'
//        ))
    })
    describe('multiplication', function(){
        it('should work', TestCheddarFrom.Code(
            'print "3*3=" + String::(3*3)',
            '3*3=9'
        ))
    })
    describe('repetition', function(){
        it('should work', TestCheddarFrom.Code(
            'print \'3*"foo"=\' + 3*"foo"',
            '3*"foo"=foofoofoo'
        ))
    })
    describe('division', function(){
        it('should work', TestCheddarFrom.Code(
            'print "10/5=" + String::(10/5)',
            '10/5=2'
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(/)'
//        ))
    })
    describe('powers', function(){
        it('should work', TestCheddarFrom.Code(
            'print "2^2=" + String::(2^2)',
            '2^2=4'
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(^)'
//        ))
    })
    describe('modulo', function(){
        it('should work', TestCheddarFrom.Code(
            'print "10%100=" + String::(10%100)',
            '10%100=10'
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(%)'
//        ))
    })
    describe('less than', function(){
        it('should work', TestCheddarFrom.Code(
            'print "5>4=" + String::(5>4)',
            '5>4=true'
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(>)'
//        ))
    })
    describe('more than', function(){
        it('should work', TestCheddarFrom.Code(
            'print "5<4=" + String::(5<4)',
            '5<4=false'
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(<)'
//        ))
    })
    describe('equal to', function(){
        it('should work', TestCheddarFrom.Code(
            'print "4==4=" + String::(4==4)',
            '4==4=true'
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(==)'
//        ))
    })
    describe('not equal to', function(){
        it('should work', TestCheddarFrom.Code(
            'print "4!=4=" + String::(4!=4)',
            '4!=4=false'
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(!=)'
//        ))
    })
    describe('less than or equal to', function(){
        it('should work', TestCheddarFrom.Code(
            'print "4>=4=" + String::(4>=4)',
            '4>=4=true'
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(>=)'
//        ))
    })
    describe('more than or equal to', function(){
        it('should work', TestCheddarFrom.Code(
            'print "4<=4=" + String::(4<=4)',
            '4<=4=true'
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(<=)'
//        ))
    })
    describe('bitwise and', function(){
        it('should work', TestCheddarFrom.Code(
            'print "4&4=" + String::(4 & 4)',
            '4&4=' + (4 & 4)
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(&)'
//        ))
    })
    describe('bitwise or', function(){
        it('should work', TestCheddarFrom.Code(
            'print "4|4=" + String::(4 | 4)',
            '4|4=' + (4 | 4)
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(|)'
//        ))
    })

    describe('xor', function(){
        it('should work', TestCheddarFrom.Code(
            'print "4 xor 3=" + String::(4 xor 3)',
            '4 xor 3=' + (4 ^ 3)
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(|)'
//        ))
    })

    describe('right shift', function(){
        it('should work', TestCheddarFrom.Code(
            'print "4>>3=" + String::(4>>3)',
            '4>>3=' + (4 >> 3)
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(|)'
//        ))
    })

    describe('left shift', function(){
        it('should work', TestCheddarFrom.Code(
            'print "4<<3=" + String::(4<<3)',
            '4<<3=' + (4<<3)
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(|)'
//        ))
    })

    describe('sign', function(){
        it('unary should work', TestCheddarFrom.Code(
            'print "sign 3=" + String::(sign 3)',
            'sign 3=' + Math.sign(3)
        ))

        it('binary should work', TestCheddarFrom.Code(
            'print "1 sign 3=" + String::(1 sign 3)',
            '1 sign 3=-1'
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(sign)'
//        ))
    })
    describe('square root', function(){
        it('should work', TestCheddarFrom.Code(
            'print "sqrt 9=" + String::(sqrt 9)',
            'sqrt 9=' + Math.sqrt(9)
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(sqrt)'
//        ))
    })
    describe('cube root', function(){
        it('should work', TestCheddarFrom.Code(
            'print "cbrt 8=" + String::(cbrt 8)',
            'cbrt 8=' + Math.cbrt(8)
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(cbrt)'
//        ))
    })
    describe('n root', function(){
        it('should work', TestCheddarFrom.Code(
            'print "8 root 3=" + String::(8 root 3)',
            '8 root 3=2'
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(root)'
//        ))
    })

    describe('log', function(){
        it('unary should work', TestCheddarFrom.Code(
            'print "log Math.E=" + String::(log Math.E)',
            'log Math.E=1'
        ))

        it('binary should work', TestCheddarFrom.Code(
            'print "16 log 2=" + String::(16 log 2)',
            '16 log 2=4'
        ))
    })

    describe('ceil', function(){
        it('should work', TestCheddarFrom.Code(
            'print "ceil 1.6=" + String::(ceil 1.6)',
            'ceil 1.6=2'
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(ceil)'
//        ))
    })
    describe('floor', function(){
        it('should work', TestCheddarFrom.Code(
            'print "floor 1.2=" + String::(floor 1.2)',
            'floor 1.2=1'
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(floor)'
//        ))
    })
    describe('round', function(){
        it('should work', TestCheddarFrom.Code(
            'print "round 1.2=" + String::(round 1.2)',
            'round 1.2=1'
        ))
//        it('should break', TestCheddarFrom.Code(
//            'print String::(round)'
//        ))
    })

    describe('abs', function(){
        it('should work', TestCheddarFrom.Code(
            'print "abs -1=" + String::(abs -1)',
            'abs -1=1'
        ))
    })

    describe('range', function(){
        it('should work', TestCheddarFrom.Code(
            'print "1|>5=" + String::(1:5)',
            '1|>5=[1, 2, 3, 4, 5]'
        ))

        it('should work reversed', TestCheddarFrom.Code(
            'print "5|>1=" + String::(5|>1)',
            '5|>1=[5, 4, 3, 2, 1]'
        ))
    })

    describe('char', function(){
        it('should work', TestCheddarFrom.Code(
            'print \'@"65=\' + @" 65',
            '@"65=A'
        ))
    })
});
<|endoftext|>


<commit_before>import React from 'react'
import { Link as RouterLink } from 'react-router-dom'
import { Tabs, TabItem } from 'rebass'
import styled, { ThemeProvider } from 'styled-components'
import { lighten } from 'polished'

const theme = {
    primary: '#15317e',
    secondary: '#A3BAE9',
    tabText: 'white'
}

const TabRow = styled(Tabs)`
    border-bottom: 0px;
`

const Tab = styled(TabItem)`
    background: #A3BAE9;
    border-top: 1px solid black;
    border-right: 1px solid black;
    border-left: 1px solid black;
    border-top-right-radius: 2px;
    border-top-left-radius: 2px;
    margin-right: 3px;
    margin-top: 1px;
    padding: 5px;

    &:hover {
    background: ${ props => !props.active && props.theme.secondary ? lighten(0.1, props.theme.secondary) : '#15317e' };
  }
`

const Link = styled(RouterLink)`
    text-decoration: none;
    padding: 10px 15px;
    color: black;
`

const GoTabs = () => {
    return (
        <ThemeProvider theme={theme}>
            <TabRow>
                <Tab>
                    <Link to="/gene/:id/go">All GO</Link>
                </Tab>
                <Tab>
                    <Link to="/gene/:id/go">Manual GO</Link>
                </Tab>
                <Tab>
                    <Link to="/gene/:id/go">Experimental GO</Link>
                </Tab>
                <Tab>
                    <Link to="/gene/:id/go">Electronic GO</Link>
                </Tab>
            </TabRow>
        </ThemeProvider>
    )
}

export default GoTabs<commit_msg>rewrite tabs as array and add active tab styling<commit_after>import React, { Component } from 'react'
import { Flex, Tabs, TabItem } from 'rebass'
import styled, { ThemeProvider } from 'styled-components'
import { lighten } from 'polished'

const TabList = ['All GO', 'Manual GO', 'Experimental GO', 'Electronic GO']

const theme = {
    primary: '#15317e',
    secondary: '#A3BAE9',
    tabText: 'white'
}

const TabRow = styled(Tabs)`
    border-bottom: 0px;
`

const Tab = styled(TabItem)`
    background: ${ props => !props.active && props.theme.secondary ? '#A3BAE9' : '#15317e' };
    border-top: 1px solid black;
    border-right: 1px solid black;
    border-left: 1px solid black;
    border-top-right-radius: 2px;
    border-top-left-radius: 2px;
    margin-right: 3px;
    margin-top: 1px;
    padding: 5px;
    width: 150px;
    color: ${ props => !props.active && props.theme.secondary ? 'black' : 'white' };
    border-color: ${ props => props.active ? 'black' : ''};

    &:hover {
        background: ${ props => !props.active && props.theme.secondary ? lighten(0.1, props.theme.secondary) : '#15317e' };
        color: ${ props => !props.active && props.theme.secondary ? 'black' : 'white' };;
        cursor: pointer;
    }
`

class GoTabs extends Component {
    state = {
        active: 0
    }

    setActive = active => {
        this.setState({ active })
    }

    renderTabs = ({ value, index }) => {
        const { active } = this.state
        const isActive = index === active

        return (
            <Tab
                key={index}
                active={isActive}
                onClick={e => {
                    this.setActive(index)
                }}
            >
                { value }
            </Tab>
        )
    }

    render() {
        return (
            <ThemeProvider theme={theme}>
                <TabRow>
                    <Flex justify='center' mx='auto'>
                        {TabList.map((value, index) =>
                            this.renderTabs({ value, index })
                        )}
                    </Flex>
                </TabRow>
            </ThemeProvider>
        )
    }
}

export default GoTabs<|endoftext|>


<commit_before>const through = require('through2');
const pjson = require('../package.json');
const path = require('path');

/**
 * Resolve path to library file
 * @param  {String} file
 * @return {String}
 */
function pathTo(file) {
  return pjson.name + '/src/' + file;
}

/**
 * Initialize react live patch
 * @description Inject React & WS, create namespace
 * @param  {Object} options
 * @return {String}
 */
function initialize(options) {
  var port = options.port;

  return '\n' +
    'var $$scope = window.__RLP = (window.__RLP || {});\n' +
    'if (!$$scope.initialized) {\n' +
      'var Proxies = require("' + pathTo('Proxies') + '");\n' +
      'require("' + pathTo('injectReactDeps') + '")($$scope);\n' +
      'require("' + pathTo('injectWebSocket') + '")($$scope, require, ' + port + ');\n' +
      '$$scope.proxies = new Proxies();\n' +
      '$$scope.initialized = true;\n' +
    '}\n';
}

/**
 * Check if file is JSON (duck test)
 * @param  {String}  file
 * @return {Boolean}
 */
function isJSON(file) {
  return file.slice(-4) === 'json';
}

function overrideRequire(file) {
  return '\n' +
  'require = require("' + pathTo('overrideRequire') + '")' +
  '($$scope, require, "' + file + '");\n';
}

module.exports = function applyReactHotAPI(file, options) {
  var content = [];
  var port = options.port;

  return through(
    function transform(part, enc, next) {
      content.push(part);
      next();
    },

    function finish(done) {
      var bundle;
      content = content.join('');

      if (isJSON(file)) {
        bundle = content;
      } else {
        bundle = initialize({ port: port, }) +
          overrideRequire(file) +
          content;
      }

      this.push(bundle);
      done();
    }
  );
};
<commit_msg>Some clean-ups in transform.js file<commit_after>const through = require('through2');
const pjson = require('../package.json');
const path = require('path');

/**
 * Resolve path to library file
 * @param  {String} file
 * @return {String}
 */
function pathTo(file) {
  return pjson.name + '/src/' + file;
}

/**
 * Initialize react live patch
 * @description Inject React & WS, create namespace
 * @param  {Object} options
 * @return {String}
 */
function initialize(options) {
  var port = options.port;

  return '\n' +
    'var $$scope = window.__RLP = (window.__RLP || {});\n' +
    'if (!$$scope.initialized) {\n' +
      'var Proxies = require("' + pathTo('Proxies') + '");\n' +
      'require("' + pathTo('injectReactDeps') + '")($$scope);\n' +
      'require("' + pathTo('injectWebSocket') + '")($$scope, require, ' + port + ');\n' +
      '$$scope.proxies = new Proxies();\n' +
      '$$scope.initialized = true;\n' +
    '}\n';
}

/**
 * Check if file is JSON (duck test)
 * @param  {String}  file
 * @return {Boolean}
 */
function isJSON(file) {
  return file.slice(-4) === 'json';
}

/**
 * Generate overriden require function
 * @param  {String} filename
 * @return {String} Overriden require injection
 */
function overrideRequire(filename) {
  return 'require = require("' + pathTo('overrideRequire') + '")' +
  '($$scope, require, "' + filename + '");\n';
}

module.exports = function applyReactHotAPI(file, options) {
  var content = [];
  var port = options.port;

  return through(
    function transform(part, enc, next) {
      content.push(part); next();
    },

    function finish(done) {
      var prelude = '';
      content = content.join('');

      if (!isJSON(file)) {
        prelude = initialize({ port: port, }) + overrideRequire(file);
      }

      this.push(prelude + content); done();
    }
  );
};
<|endoftext|>


<commit_before>function Parser() {
  var that = {};

  function parse(string) {
    var domparser = new DOMParser(), xmlDoc = domparser.parseFromString(string,"text/xml"),
	  root = xmlDoc.documentElement;

	if(root.hasChildNodes()) {
	  console.log(root.hasChildNodes());
	  console.log(root.childNodes.length);
	  console.log(root.childNodes.item(0).nodeName);
      console.log(root.childNodes.item(0).attributes.item(0).value);
	  console.log(root.childNodes.item(0).attributes.item(1).name);
	  console.log(root.childNodes.item(0).attributes.item(1).value);
	}

    var atrs = {};
	if (root.hasAttributes()) {
      for (x=0; x < root.attributes.length; x++) {
	    atrs[root.attributes.item(x).name] = root.attributes.item(x).value;
	  }
	}

	var children = {};

	if(root.hasChildNodes()) {
	  for(x=0; x < root.childNodes.length; x++) {
	    children[root.childNodes.item(x).nodeName] = root.childNodes.item(x);
	  }
	}

	return {
	   name: root.nodeName,
	   children: children,
	   attributes: atrs
	};
  }

  that.parse = parse;

  return that;

}<commit_msg>cleaned up tab usage<commit_after>function Parser() {
  var that = {};

  function parse(string) {
    var domparser = new DOMParser(), xmlDoc = domparser.parseFromString(string,"text/xml"),
    root = xmlDoc.documentElement;

  if(root.hasChildNodes()) {
    console.log(root.hasChildNodes());
    console.log(root.childNodes.length);
    console.log(root.childNodes.item(0).nodeName);
      console.log(root.childNodes.item(0).attributes.item(0).value);
    console.log(root.childNodes.item(0).attributes.item(1).name);
    console.log(root.childNodes.item(0).attributes.item(1).value);
  }

    var atrs = {};
  if (root.hasAttributes()) {
      for (x=0; x < root.attributes.length; x++) {
      atrs[root.attributes.item(x).name] = root.attributes.item(x).value;
    }
  }

  var children = {};

  if(root.hasChildNodes()) {
    for(x=0; x < root.childNodes.length; x++) {
      children[root.childNodes.item(x).nodeName] = root.childNodes.item(x);
    }
  }

  return {
     name: root.nodeName,
     children: children,
     attributes: atrs
  };
  }

  that.parse = parse;

  return that;

}<|endoftext|>


<commit_before>angular.module('pascalprecht.translate', ['ng'])

.run(['$translate', function ($translate) {

  var key = $translate.storageKey(),
      storage = $translate.storage();

  if (storage) {
    if (!storage.get(key)) {

      if (angular.isString($translate.preferredLanguage())) {
        // $translate.uses method will both set up and remember the language in case it's loaded successfully
        $translate.uses($translate.preferredLanguage());
      } else {
        storage.set(key, $translate.uses());
      }

    } else {
      $translate.uses(storage.get(key));
    }
  } else if (angular.isString($translate.preferredLanguage())) {
    $translate.uses($translate.preferredLanguage());
  }

}]);

angular.module('pascalprecht.translate').constant('$STORAGE_KEY', 'NG_TRANSLATE_LANG_KEY');

/**
 * @ngdoc object
 * @name translate.$translateProvider
 * @description
 *
 * $tranlateProvider allows developers to register translation-tables, asynchronous loaders
 * and similar to configure translation behavior directly inside of a module.
 *
 */
angular.module('pascalprecht.translate').provider('$translate', ['$STORAGE_KEY', function ($STORAGE_KEY) {

  var $translationTable = {},
      $preferredLanguage,
      $fallbackLanguage,
      $uses,
      $storageFactory,
      $storageKey = $STORAGE_KEY,
      $storagePrefix,
      $missingTranslationHandlerFactory,
      $loaderFactory,
      $loaderOptions,
      NESTED_OBJECT_DELIMITER = '.';

 /**
   * @ngdoc function
   * @name translate.$translateProvider#translations
   * @methodOf translate.$translateProvider
   *
   * @description
   * Registers a new translation table either in general or for specific language key.
   *
   * You can register a translation table just by passing an object hash where a key
   * represents a translation id and a value the concrete translation. Here is an
   * example:
   *
   *

   *  // register translation table
   *  $translateProvider.translations({
   *    'HEADLINE_TEXT':'Hey Guys, this is a headline!',
   *    'SOME_TEXT': 'A text anywhere in the app.'
   *  });
   *

   *
   * In the example above there are two registered translations,
   * HEADLINE_TEXT and SOME_TEXT.
   *
   * To register a translation table for specific language, pass a defined language
   * key as first parameter.
   *
   *

   *  // register translation table for language: 'de_DE'
   *  $translateProvider.translations('de_DE', {
   *    'GREETING': 'Hallo Welt!'
   *  });
   *
   *  // register another one
   *  $translateProvider.translations('en_US', {
   *    'GREETING': 'Hello world!'
   *  });
   *

   *
   * When registering multiple translation tables for for the same language key,
   * the actual translation table gets extended. This allows you to define module
   * specific translation which only get added, once a specific module is loaded in
   * your app.
   *
   * Invoking this method with no arguments returns the translation table which was
   * registered with no language key. Invoking it with a language key returns the
   * related translation table.
   *
   * @param {string} key A language key.
   * @param {object} translationTable A plain old JavaScript object that represents a translation table.
   *
   */
  var translations = function (langKey, translationTable) {

    if (!langKey && !translationTable) {
      return $translationTable;
    }

    if (langKey && !translationTable) {
      if (angular.isString(langKey)) {
        return $translationTable[langKey];
      } else {
        angular.extend($translationTable, flatObject(langKey));
      }
    } else {
      if (!angular.isObject($translationTable[langKey])) {
        $translationTable[langKey] = {};
      }
      angular.extend($translationTable[langKey], flatObject(translationTable));
    }
  };

  var flatObject = function (data, path, result) {
    var key, keyWithPath, val;

    if (!path) {
      path = [];
    }
    if (!result) {
      result = {};
    }
    for (key in data) {
      if (!data.hasOwnProperty(key)) continue;
      val = data[key];
      if (angular.isObject(val)) {
        flatObject(val, path.concat(key), result);
      } else {
        keyWithPath = path.length ? ("" + path.join(NESTED_OBJECT_DELIMITER) + NESTED_OBJECT_DELIMITER + key) : key;
        result[keyWithPath] = val;
      }
    }
    return result;
  };

  this.translations = translations;

 /**
   * @ngdoc function
   * @name translate.$translateProvider#preferredLanguage
   * @methodOf translate.$translateProvider
   *
   * @description
   * Tells the module which of the registered translation tables to use for translation
   * at initial startup by passing a language key. Similar to `$translateProvider#uses`
   * only that it says which language to **prefer**.
   *
   * @param {string} langKey A language key.
   *
   */
  this.preferredLanguage = function(langKey) {
    if (langKey) {
      $preferredLanguage = langKey;
    } else {
      return $preferredLanguage;
    }
  };

   /**
   * @ngdoc function
   * @name pascalprecht.translate.$translateProvider#fallbackLanguage
   * @methodOf pascalprecht.translate.$translateProvider
   *
   * @description
   * Tells the module which of the registered translation tables to use when missing translations
   * at initial startup by passing a language key. Similar to `$translateProvider#uses`
   * only that it says which language to **fallback**.
   *
   * @param {string} langKey A language key.
   *
   */
  this.fallbackLanguage = function(langKey) {
    if (langKey) {
      $fallbackLanguage = langKey;
    } else {
      return $fallbackLanguage;
    }
  };

 /**
   * @ngdoc function
   * @name translate.$translateProvider#uses
   * @methodOf translate.$translateProvider
   *
   * @description
   * Set which translation table to use for translation by given language key. When
   * trying to 'use' a language which isn't provided, it'll throw an error.
   *
   * You actually don't have to use this method since `$translateProvider#preferredLanguage`
   * does the job too.
   *
   * @param {string} langKey A language key.
   *
   */
  this.uses = function (langKey) {
    if (langKey) {
      if (!$translationTable[langKey] && (!$loaderFactory)) {
        // only throw an error, when not loading translation data asynchronously
        throw new Error("$translateProvider couldn't find translationTable for langKey: '" + langKey + "'");
      }
      $uses = langKey;
    } else {
      return $uses;
    }
  };

 /**
   * @ngdoc function
   * @name translate.$translateProvider#storageKey
   * @methodOf translate.$translateProvider
   *
   * @description
   * Tells the module which key must represent the choosed language by a user in the storage.
   *
   * @param {string} key A key for the storage.
   *
   */
  var storageKey = function(key) {
    if (!key) {
      if ($storagePrefix) {
        return $storagePrefix + $storageKey;
      }
      return $storageKey;
    }
    $storageKey = key;
  };

  this.storageKey = storageKey;

  /**
   * @ngdoc function
   * @name translate.$translateProvider#useUrlLoader
   * @methodOf translate.$translateProvider
   *
   * @description
   * Tells angular-translate to use `$translateUrlLoader` extension service as loader.
   *
   * @param {string} url Url
   */
  this.useUrlLoader = function (url) {
    this.useLoader('$translateUrlLoader', { url: url });
  };

  /**
   * @ngdoc function
   * @name translate.$translateProvider#useStaticFilesLoader
   * @methodOf translate.$translateProvider
   *
   * @description
   * Tells angular-translate to use `$translateStaticFilesLoader` extension service as loader.
   *
   * @param {Object=} options Optional configuration object
   */
  this.useStaticFilesLoader = function (options) {
    this.useLoader('$translateStaticFilesLoader', options);
  };

  /**
   * @ngdoc function
   * @name translate.$translateProvider#useLoader
   * @methodOf translate.$translateProvider
   *
   * @description
   * Tells angular-translate to use any other service as loader.
   *
   * @param {string} loaderFactory Factory name to use
   * @param {Object=} options Optional configuration object
   */
  this.useLoader = function (loaderFactory, options) {
    $loaderFactory = loaderFactory;
    $loaderOptions = options;
  };

  /**
   * @ngdoc function
   * @name translate.$translateProvider#useLocalStorage
   * @methodOf translate.$translateProvider
   *
   * @description
   * Tells angular-translate to use `$translateLocalStorage` service as storage layer.
   *
   */
  this.useLocalStorage = function () {
    this.useStorage('$translateLocalStorage');
  };

  /**
   * @ngdoc function
   * @name translate.$translateProvider#useCookieStorage
   * @methodOf translate.$translateProvider
   *
   * @description
   * Tells angular-translate to use `$translateCookieStorage` service as storage layer.
   *
   */
  this.useCookieStorage = function () {
    this.useStorage('$translateCookieStorage');
  };

  /**
   * @ngdoc function
   * @name translate.$translateProvider#useStorage
   * @methodOf translate.$translateProvider
   *
   * @description
   * Tells angular-translate to use custom service as storage layer.
   *
   */
  this.useStorage = function (storageFactory) {
    $storageFactory = storageFactory;
  };

  /**
   * @ngdoc function
   * @name translate.$translateProvider#storagePrefix
   * @methodOf translate.$translateProvider
   *
   * @description
   * Sets prefix for storage key.
   *
   * @param {string} prefix Storage key prefix
   */
  this.storagePrefix = function (prefix) {
    if (!prefix) {
      return prefix;
    }
    $storagePrefix = prefix;
  };

  /**
   * @ngdoc function
   * @name translate.$translateProvider#useMissingTranslationHandlerLog
   * @methodOf translate.$translateProvider
   *
   * @description
   * Tells angular-translate to use built-in log handler when trying to translate
   * a translation Id which doesn't exist.
   *
   * This is actually a shortcut method for `useMissingTranslationHandler()`.
   *
   */
  this.useMissingTranslationHandlerLog = function () {
    this.useMissingTranslationHandler('$translateMissingTranslationHandlerLog');
  };

  /**
   * @ngdoc function
   * @name translate.$translateProvider#useMissingTranslationHandler
   * @methodOf translate.$translateProvider
   *
   * @description
   * Expects a factory name which later gets instantiated with `$injector`.
   * This method can be used to tell angular-translate to use a custom
   * missingTranslationHandler. Just build a factory which returns a function
   * and expects a translation id as argument.
   *
   * Example:
   *

   *  app.config(function ($translateProvider) {
   *    $translateProvider.useMissingTranslationHandler('customHandler');
   *  });
   *
   *  app.factory('customHandler', function (dep1, dep2) {
   *    return function (translationId) {
   *      // something with translationId and dep1 and dep2
   *    };
   *  });
   *

   *
   * @param {string} factory Factory name
   */
  this.useMissingTranslationHandler = function (factory) {
    $missingTranslationHandlerFactory = factory;
  };

  /**
   * @ngdoc object
   * @name translate.$translate
   * @requires $interpolate
   * @requires $log
   * @requires $rootScope
   * @requires $q
   *
   * @description
   * The `$translate` service is the actual core of angular-translate. It excepts a translation id
   * and optional interpolate parameters to translate contents.
   *
   *

   *  $scope.translatedText = $translate('HEADLINE_TEXT');
   *

   *
   * @param {string} translationId A token which represents a translation id
   * @param {object=} interpolateParams An object hash for dynamic values
   */
  this.$get = [
    '$interpolate',
    '$log',
    '$injector',
    '$rootScope',
    '$q',
    function ($interpolate, $log, $injector, $rootScope, $q) {

    var Storage;

    if ($storageFactory) {
      Storage = $injector.get($storageFactory);

      if (!Storage.get || !Storage.set) {
        throw new Error('Couldn\'t use storage \'' + $storageFactory + '\', missing get() or set() method!');
      }
    }

    var $translate = function (translationId, interpolateParams) {
      var table = $uses ? $translationTable[$uses] : $translationTable;

      if (table && table.hasOwnProperty(translationId)) {
        return $interpolate(table[translationId])(interpolateParams);
      }

      if ($missingTranslationHandlerFactory) {
        $injector.get($missingTranslationHandlerFactory)(translationId);
      }

      if ($uses && $fallbackLanguage && $uses !== $fallbackLanguage){
        var translation = $translationTable[$fallbackLanguage][translationId];
        if (translation) {
          return $interpolate(translation)(interpolateParams);
        }
      }

      return translationId;
    };

    /**
     * @ngdoc function
     * @name translate.$translate#preferredLanguage
     * @methodOf translate.$translate
     *
     * @description
     * Returns the language key for the preferred language.
     *
     * @return {string} preferred language key
     */
    $translate.preferredLanguage = function () {
      return $preferredLanguage;
    };
    /**
     * @ngdoc function
     * @name pascalprecht.translate.$translate#fallbackLanguage
     * @methodOf pascalprecht.translate.$fallbackLanguage
     *
     * @description
     * Returns the language key for the fallback language.
     *
     * @return {string} fallback language key
     */
    $translate.fallbackLanguage = function () {
      return $fallbackLanguage;
    };

    /**
     * @ngdoc function
     * @name translate.$translate#storage
     * @methodOf translate.$translate
     *
     * @description
     * Returns registered storage.
     *
     * @return {object} Storage
     */
    $translate.storage = function () {
      return Storage;
    };

    /**
     * @ngdoc function
     * @name translate.$translate#uses
     * @methodOf translate.$translate
     *
     * @description
     * Tells angular-translate which language to uses by given language key. This method is
     * used to change language at runtime. It also takes care of storing the language
     * key in a configured store to let your app remember the choosed language.
     *
     * When trying to 'use' a language which isn't available it tries to load it
     * asynchronously with registered loaders.
     *
     * @param {string} key Language key
     * @return {string} Language key
     */
    $translate.uses = function (key) {

      if (!key) {
        return $uses;
      }

      var deferred = $q.defer();

      if (!$translationTable[key]) {

        $injector.get($loaderFactory)(angular.extend($loaderOptions, {
          key: key
        })).then(function (data) {
          $uses = key;
          translations(key, data);

          if ($storageFactory) {
            Storage.set($translate.storageKey(), $uses);
          }
          $rootScope.$broadcast('translationChangeSuccess');
          deferred.resolve($uses);
        }, function (key) {
          $rootScope.$broadcast('translationChangeError');
          deferred.reject(key);
        });

        return deferred.promise;
      }

      $uses = key;

      if ($storageFactory) {
        Storage.set($translate.storageKey(), $uses);
      }

      deferred.resolve($uses);
      $rootScope.$broadcast('translationChangeSuccess');
      return deferred.promise;
    };

    /**
     * @ngdoc function
     * @name translate.$translate#storageKey
     * @methodOf translate.$translate
     *
     * @description
     * Returns the key for the storage.
     *
     * @return {string} storage key
     */
    $translate.storageKey = function() {
      return storageKey();
    };

    // If at least one async loader is defined and there are no (default) translations available
    // we should try to load them.
    if ($loaderFactory && angular.equals($translationTable, {})) {
      $translate.uses($translate.uses());
    }

    return $translate;
  }];
}]);
<commit_msg>comment fix<commit_after>angular.module('pascalprecht.translate', ['ng'])

.run(['$translate', function ($translate) {

  var key = $translate.storageKey(),
      storage = $translate.storage();

  if (storage) {
    if (!storage.get(key)) {

      if (angular.isString($translate.preferredLanguage())) {
        // $translate.uses method will both set up and remember the language in case it's loaded successfully
        $translate.uses($translate.preferredLanguage());
      } else {
        storage.set(key, $translate.uses());
      }

    } else {
      $translate.uses(storage.get(key));
    }
  } else if (angular.isString($translate.preferredLanguage())) {
    $translate.uses($translate.preferredLanguage());
  }

}]);

angular.module('pascalprecht.translate').constant('$STORAGE_KEY', 'NG_TRANSLATE_LANG_KEY');

/**
 * @ngdoc object
 * @name translate.$translateProvider
 * @description
 *
 * $tranlateProvider allows developers to register translation-tables, asynchronous loaders
 * and similar to configure translation behavior directly inside of a module.
 *
 */
angular.module('pascalprecht.translate').provider('$translate', ['$STORAGE_KEY', function ($STORAGE_KEY) {

  var $translationTable = {},
      $preferredLanguage,
      $fallbackLanguage,
      $uses,
      $storageFactory,
      $storageKey = $STORAGE_KEY,
      $storagePrefix,
      $missingTranslationHandlerFactory,
      $loaderFactory,
      $loaderOptions,
      NESTED_OBJECT_DELIMITER = '.';

 /**
   * @ngdoc function
   * @name translate.$translateProvider#translations
   * @methodOf translate.$translateProvider
   *
   * @description
   * Registers a new translation table either in general or for specific language key.
   *
   * You can register a translation table just by passing an object hash where a key
   * represents a translation id and a value the concrete translation. Here is an
   * example:
   *
   *

   *  // register translation table
   *  $translateProvider.translations({
   *    'HEADLINE_TEXT':'Hey Guys, this is a headline!',
   *    'SOME_TEXT': 'A text anywhere in the app.'
   *  });
   *

   *
   * In the example above there are two registered translations,
   * HEADLINE_TEXT and SOME_TEXT.
   *
   * To register a translation table for specific language, pass a defined language
   * key as first parameter.
   *
   *

   *  // register translation table for language: 'de_DE'
   *  $translateProvider.translations('de_DE', {
   *    'GREETING': 'Hallo Welt!'
   *  });
   *
   *  // register another one
   *  $translateProvider.translations('en_US', {
   *    'GREETING': 'Hello world!'
   *  });
   *

   *
   * When registering multiple translation tables for for the same language key,
   * the actual translation table gets extended. This allows you to define module
   * specific translation which only get added, once a specific module is loaded in
   * your app.
   *
   * Invoking this method with no arguments returns the translation table which was
   * registered with no language key. Invoking it with a language key returns the
   * related translation table.
   *
   * @param {string} key A language key.
   * @param {object} translationTable A plain old JavaScript object that represents a translation table.
   *
   */
  var translations = function (langKey, translationTable) {

    if (!langKey && !translationTable) {
      return $translationTable;
    }

    if (langKey && !translationTable) {
      if (angular.isString(langKey)) {
        return $translationTable[langKey];
      } else {
        angular.extend($translationTable, flatObject(langKey));
      }
    } else {
      if (!angular.isObject($translationTable[langKey])) {
        $translationTable[langKey] = {};
      }
      angular.extend($translationTable[langKey], flatObject(translationTable));
    }
  };

  var flatObject = function (data, path, result) {
    var key, keyWithPath, val;

    if (!path) {
      path = [];
    }
    if (!result) {
      result = {};
    }
    for (key in data) {
      if (!data.hasOwnProperty(key)) continue;
      val = data[key];
      if (angular.isObject(val)) {
        flatObject(val, path.concat(key), result);
      } else {
        keyWithPath = path.length ? ("" + path.join(NESTED_OBJECT_DELIMITER) + NESTED_OBJECT_DELIMITER + key) : key;
        result[keyWithPath] = val;
      }
    }
    return result;
  };

  this.translations = translations;

 /**
   * @ngdoc function
   * @name translate.$translateProvider#preferredLanguage
   * @methodOf translate.$translateProvider
   *
   * @description
   * Tells the module which of the registered translation tables to use for translation
   * at initial startup by passing a language key. Similar to `$translateProvider#uses`
   * only that it says which language to **prefer**.
   *
   * @param {string} langKey A language key.
   *
   */
  this.preferredLanguage = function(langKey) {
    if (langKey) {
      $preferredLanguage = langKey;
    } else {
      return $preferredLanguage;
    }
  };

   /**
   * @ngdoc function
   * @name translate.$translateProvider#fallbackLanguage
   * @methodOf translate.$translateProvider
   *
   * @description
   * Tells the module which of the registered translation tables to use when missing translations
   * at initial startup by passing a language key. Similar to `$translateProvider#uses`
   * only that it says which language to **fallback**.
   *
   * @param {string} langKey A language key.
   *
   */
  this.fallbackLanguage = function(langKey) {
    if (langKey) {
      $fallbackLanguage = langKey;
    } else {
      return $fallbackLanguage;
    }
  };

 /**
   * @ngdoc function
   * @name translate.$translateProvider#uses
   * @methodOf translate.$translateProvider
   *
   * @description
   * Set which translation table to use for translation by given language key. When
   * trying to 'use' a language which isn't provided, it'll throw an error.
   *
   * You actually don't have to use this method since `$translateProvider#preferredLanguage`
   * does the job too.
   *
   * @param {string} langKey A language key.
   *
   */
  this.uses = function (langKey) {
    if (langKey) {
      if (!$translationTable[langKey] && (!$loaderFactory)) {
        // only throw an error, when not loading translation data asynchronously
        throw new Error("$translateProvider couldn't find translationTable for langKey: '" + langKey + "'");
      }
      $uses = langKey;
    } else {
      return $uses;
    }
  };

 /**
   * @ngdoc function
   * @name translate.$translateProvider#storageKey
   * @methodOf translate.$translateProvider
   *
   * @description
   * Tells the module which key must represent the choosed language by a user in the storage.
   *
   * @param {string} key A key for the storage.
   *
   */
  var storageKey = function(key) {
    if (!key) {
      if ($storagePrefix) {
        return $storagePrefix + $storageKey;
      }
      return $storageKey;
    }
    $storageKey = key;
  };

  this.storageKey = storageKey;

  /**
   * @ngdoc function
   * @name translate.$translateProvider#useUrlLoader
   * @methodOf translate.$translateProvider
   *
   * @description
   * Tells angular-translate to use `$translateUrlLoader` extension service as loader.
   *
   * @param {string} url Url
   */
  this.useUrlLoader = function (url) {
    this.useLoader('$translateUrlLoader', { url: url });
  };

  /**
   * @ngdoc function
   * @name translate.$translateProvider#useStaticFilesLoader
   * @methodOf translate.$translateProvider
   *
   * @description
   * Tells angular-translate to use `$translateStaticFilesLoader` extension service as loader.
   *
   * @param {Object=} options Optional configuration object
   */
  this.useStaticFilesLoader = function (options) {
    this.useLoader('$translateStaticFilesLoader', options);
  };

  /**
   * @ngdoc function
   * @name translate.$translateProvider#useLoader
   * @methodOf translate.$translateProvider
   *
   * @description
   * Tells angular-translate to use any other service as loader.
   *
   * @param {string} loaderFactory Factory name to use
   * @param {Object=} options Optional configuration object
   */
  this.useLoader = function (loaderFactory, options) {
    $loaderFactory = loaderFactory;
    $loaderOptions = options;
  };

  /**
   * @ngdoc function
   * @name translate.$translateProvider#useLocalStorage
   * @methodOf translate.$translateProvider
   *
   * @description
   * Tells angular-translate to use `$translateLocalStorage` service as storage layer.
   *
   */
  this.useLocalStorage = function () {
    this.useStorage('$translateLocalStorage');
  };

  /**
   * @ngdoc function
   * @name translate.$translateProvider#useCookieStorage
   * @methodOf translate.$translateProvider
   *
   * @description
   * Tells angular-translate to use `$translateCookieStorage` service as storage layer.
   *
   */
  this.useCookieStorage = function () {
    this.useStorage('$translateCookieStorage');
  };

  /**
   * @ngdoc function
   * @name translate.$translateProvider#useStorage
   * @methodOf translate.$translateProvider
   *
   * @description
   * Tells angular-translate to use custom service as storage layer.
   *
   */
  this.useStorage = function (storageFactory) {
    $storageFactory = storageFactory;
  };

  /**
   * @ngdoc function
   * @name translate.$translateProvider#storagePrefix
   * @methodOf translate.$translateProvider
   *
   * @description
   * Sets prefix for storage key.
   *
   * @param {string} prefix Storage key prefix
   */
  this.storagePrefix = function (prefix) {
    if (!prefix) {
      return prefix;
    }
    $storagePrefix = prefix;
  };

  /**
   * @ngdoc function
   * @name translate.$translateProvider#useMissingTranslationHandlerLog
   * @methodOf translate.$translateProvider
   *
   * @description
   * Tells angular-translate to use built-in log handler when trying to translate
   * a translation Id which doesn't exist.
   *
   * This is actually a shortcut method for `useMissingTranslationHandler()`.
   *
   */
  this.useMissingTranslationHandlerLog = function () {
    this.useMissingTranslationHandler('$translateMissingTranslationHandlerLog');
  };

  /**
   * @ngdoc function
   * @name translate.$translateProvider#useMissingTranslationHandler
   * @methodOf translate.$translateProvider
   *
   * @description
   * Expects a factory name which later gets instantiated with `$injector`.
   * This method can be used to tell angular-translate to use a custom
   * missingTranslationHandler. Just build a factory which returns a function
   * and expects a translation id as argument.
   *
   * Example:
   *

   *  app.config(function ($translateProvider) {
   *    $translateProvider.useMissingTranslationHandler('customHandler');
   *  });
   *
   *  app.factory('customHandler', function (dep1, dep2) {
   *    return function (translationId) {
   *      // something with translationId and dep1 and dep2
   *    };
   *  });
   *

   *
   * @param {string} factory Factory name
   */
  this.useMissingTranslationHandler = function (factory) {
    $missingTranslationHandlerFactory = factory;
  };

  /**
   * @ngdoc object
   * @name translate.$translate
   * @requires $interpolate
   * @requires $log
   * @requires $rootScope
   * @requires $q
   *
   * @description
   * The `$translate` service is the actual core of angular-translate. It excepts a translation id
   * and optional interpolate parameters to translate contents.
   *
   *

   *  $scope.translatedText = $translate('HEADLINE_TEXT');
   *

   *
   * @param {string} translationId A token which represents a translation id
   * @param {object=} interpolateParams An object hash for dynamic values
   */
  this.$get = [
    '$interpolate',
    '$log',
    '$injector',
    '$rootScope',
    '$q',
    function ($interpolate, $log, $injector, $rootScope, $q) {

    var Storage;

    if ($storageFactory) {
      Storage = $injector.get($storageFactory);

      if (!Storage.get || !Storage.set) {
        throw new Error('Couldn\'t use storage \'' + $storageFactory + '\', missing get() or set() method!');
      }
    }

    var $translate = function (translationId, interpolateParams) {
      var table = $uses ? $translationTable[$uses] : $translationTable;

      if (table && table.hasOwnProperty(translationId)) {
        return $interpolate(table[translationId])(interpolateParams);
      }

      if ($missingTranslationHandlerFactory) {
        $injector.get($missingTranslationHandlerFactory)(translationId);
      }

      if ($uses && $fallbackLanguage && $uses !== $fallbackLanguage){
        var translation = $translationTable[$fallbackLanguage][translationId];
        if (translation) {
          return $interpolate(translation)(interpolateParams);
        }
      }

      return translationId;
    };

    /**
     * @ngdoc function
     * @name translate.$translate#preferredLanguage
     * @methodOf translate.$translate
     *
     * @description
     * Returns the language key for the preferred language.
     *
     * @return {string} preferred language key
     */
    $translate.preferredLanguage = function () {
      return $preferredLanguage;
    };
    /**
     * @ngdoc function
     * @name pascalprecht.translate.$translate#fallbackLanguage
     * @methodOf pascalprecht.translate.$fallbackLanguage
     *
     * @description
     * Returns the language key for the fallback language.
     *
     * @return {string} fallback language key
     */
    $translate.fallbackLanguage = function () {
      return $fallbackLanguage;
    };

    /**
     * @ngdoc function
     * @name translate.$translate#storage
     * @methodOf translate.$translate
     *
     * @description
     * Returns registered storage.
     *
     * @return {object} Storage
     */
    $translate.storage = function () {
      return Storage;
    };

    /**
     * @ngdoc function
     * @name translate.$translate#uses
     * @methodOf translate.$translate
     *
     * @description
     * Tells angular-translate which language to uses by given language key. This method is
     * used to change language at runtime. It also takes care of storing the language
     * key in a configured store to let your app remember the choosed language.
     *
     * When trying to 'use' a language which isn't available it tries to load it
     * asynchronously with registered loaders.
     *
     * @param {string} key Language key
     * @return {string} Language key
     */
    $translate.uses = function (key) {

      if (!key) {
        return $uses;
      }

      var deferred = $q.defer();

      if (!$translationTable[key]) {

        $injector.get($loaderFactory)(angular.extend($loaderOptions, {
          key: key
        })).then(function (data) {
          $uses = key;
          translations(key, data);

          if ($storageFactory) {
            Storage.set($translate.storageKey(), $uses);
          }
          $rootScope.$broadcast('translationChangeSuccess');
          deferred.resolve($uses);
        }, function (key) {
          $rootScope.$broadcast('translationChangeError');
          deferred.reject(key);
        });

        return deferred.promise;
      }

      $uses = key;

      if ($storageFactory) {
        Storage.set($translate.storageKey(), $uses);
      }

      deferred.resolve($uses);
      $rootScope.$broadcast('translationChangeSuccess');
      return deferred.promise;
    };

    /**
     * @ngdoc function
     * @name translate.$translate#storageKey
     * @methodOf translate.$translate
     *
     * @description
     * Returns the key for the storage.
     *
     * @return {string} storage key
     */
    $translate.storageKey = function() {
      return storageKey();
    };

    // If at least one async loader is defined and there are no (default) translations available
    // we should try to load them.
    if ($loaderFactory && angular.equals($translationTable, {})) {
      $translate.uses($translate.uses());
    }

    return $translate;
  }];
}]);
<|endoftext|>


<commit_before>/*
 * BSD 3-Clause License
 *
 * Copyright (c) 2017, MapCreator
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 *
 *  Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 *  Neither the name of the copyright holder nor the names of its
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

import {AbstractClassError} from '../../errors/AbstractError';
import {isParentOf} from '../../utils/reflection';
import ResourceBase from './ResourceBase';

/**
 * Base of all resource items that support Crud operations
 * @abstract
 */
export default class CrudBase extends ResourceBase {
  /**
   * @param {Maps4News} api - Api instance
   * @param {Object<String, *>} data - Item data
   */
  constructor(api, data = {}) {
    super(api, data);

    if (this.constructor === CrudBase) {
      throw new AbstractClassError();
    }
  }

  /**
   * Build data for create operation
   * @returns {Object<String, *>} - Create data
   * @protected
   */
  _buildCreateData() {
    this._updateProperties();

    const out = {};
    const keys = [].concat(
      Object.keys(this._properties),
      Object.keys(this._baseProperties),
    ).filter((item, pos, self) => self.indexOf(item) === pos);

    for (const key of keys) {
      out[key] = this._properties[key] || this._baseProperties[key];
    }

    delete out.id;
    return out;
  }

  /**
   * Save item. This will create a new item if `id` is unset
   * @returns {Promise} - Resolves with {@link CrudBase} instance and rejects with {@link ApiError}
   */
  save() {
    return !this.id ? this._create() : this._update();
  }

  /**
   * Store new item
   * @param {Boolean} updateSelf - Update the current instance
   * @returns {Promise} - Resolves with {@link CrudBase} instance and rejects with {@link ApiError}
   * @private
   */
  _create() {
    return new Promise((resolve, reject) => {
      this.api
        .request(this.baseUrl, 'POST', this._buildCreateData())
        .catch(reject)
        .then(data => {
          this._properties = {};
          this._baseProperties = data;

          this._updateProperties();
          resolve(this);
        });
    });
  }

  /**
   * Update existing item
   * @param {Boolean} updateSelf - Update the current instance
   * @returns {Promise} - Resolves with {@link CrudBase} instance and rejects with {@link ApiError}
   * @private
   */
  _update() {
    this._updateProperties();

    return new Promise((resolve, reject) => {
      this.api
        .request(this.url, 'PATCH', this._properties)
        .catch(reject)
        .then(() => {
          if (this.api.defaults.autoUpdateSharedCache) {
            this.api.cache.update(this);
          }

          resolve(this);
        });
    });
  }

  /**
   * Delete item
   * @returns {Promise} - Resolves with an empty {@link Object} and rejects with {@link ApiError}
   */
  delete(updateSelf = true) {
    return this.api
      .request(this.url, 'DELETE')
      .then(data => {
        if (updateSelf) {
          this._baseProperties['deleted_at'] = new Date();
        }

        return data;
      });
  }

  /**
   * Restore item
   * @returns {Promise} - Resolves with {@link CrudBase} instance and rejects with {@link ApiError}
   */
  restore(updateSelf = true) {
    return this.api
      .request(this.url, 'PUT')
      .then(data => {
        const instance = new this.constructor(this.api, data);

        if (updateSelf) {
          this._properties = {};
          this._baseProperties = data;

          this._updateProperties();
        }

        return instance;
      });

  }

  /**
   * Sync, attach or unlink resources
   * @param {Array<Organisation>|Array<Number>} items - List of items to sync or attach
   * @param {String} method - Http method to use
   * @param {ResourceBase} Type - Resource type
   * @param {?String} path - Optional appended resource path, will guess if null
   * @returns {Promise} - Promise will resolve with no value and reject with an {@link ApiError} instance.
   * @todo refactor to CrudBase and remove organisation specific method from trait
   * @protected
   */
  _modifyLink(items, method, Type, path) {
    if (!path) {
      const resource = (new Type(this.api)).resourceName.replace(/s+$/, '');

      path = `${resource}s`;
    }

    const filter = x => !isParentOf(Type, x) && !isParentOf(Number, x);
    const isValid = items.filter(filter).length === 0;

    if (!isValid) {
      throw new TypeError(`Array must contain either Numbers (resource id) or "${Type.name}".`);
    }

    const keys = items.map(x => typeof x === 'number' ? x : x.id).map(Number);

    return this.api.request(`${this.url}/${path}`, method, {keys});
  }
}
<commit_msg>Add @example to wrapper::refresh<commit_after>/*
 * BSD 3-Clause License
 *
 * Copyright (c) 2017, MapCreator
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 *
 *  Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 *  Neither the name of the copyright holder nor the names of its
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

import {AbstractClassError} from '../../errors/AbstractError';
import {isParentOf} from '../../utils/reflection';
import ResourceBase from './ResourceBase';

/**
 * Base of all resource items that support Crud operations
 * @abstract
 */
export default class CrudBase extends ResourceBase {
  /**
   * @param {Maps4News} api - Api instance
   * @param {Object<String, *>} data - Item data
   */
  constructor(api, data = {}) {
    super(api, data);

    if (this.constructor === CrudBase) {
      throw new AbstractClassError();
    }
  }

  /**
   * Build data for create operation
   * @returns {Object<String, *>} - Create data
   * @protected
   */
  _buildCreateData() {
    this._updateProperties();

    const out = {};
    const keys = [].concat(
      Object.keys(this._properties),
      Object.keys(this._baseProperties),
    ).filter((item, pos, self) => self.indexOf(item) === pos);

    for (const key of keys) {
      out[key] = this._properties[key] || this._baseProperties[key];
    }

    delete out.id;
    return out;
  }

  /**
   * Save item. This will create a new item if `id` is unset
   * @returns {Promise} - Resolves with {@link CrudBase} instance and rejects with {@link ApiError}
   .catch(reject)
   .then(data => {
          this._properties = {};
          this._baseProperties = data;

          this._updateProperties();
          resolve(this);
        });
   */
  save() {
    return !this.id ? this._create() : this._update();
  }

  /**
   * Store new item
   * @param {Boolean} updateSelf - Update the current instance
   * @returns {Promise} - Resolves with {@link CrudBase} instance and rejects with {@link ApiError}
   * @private
   */
  _create() {
    return new Promise((resolve, reject) => {
      this.api
        .request(this.baseUrl, 'POST', this._buildCreateData())
    });
  }

  /**
   * Update existing item
   * @param {Boolean} updateSelf - Update the current instance
   * @returns {Promise} - Resolves with {@link CrudBase} instance and rejects with {@link ApiError}
   * @private
   */
  _update() {
    this._updateProperties();

    return new Promise((resolve, reject) => {
      this.api
        .request(this.url, 'PATCH', this._properties)
        .catch(reject)
        .then(() => {
          if (this.api.defaults.autoUpdateSharedCache) {
            this.api.cache.update(this);
          }

          resolve(this);
        });
    });
  }

  /**
   * Delete item
   * @returns {Promise} - Resolves with an empty {@link Object} and rejects with {@link ApiError}
   */
  delete(updateSelf = true) {
    return this.api
      .request(this.url, 'DELETE')
      .then(data => {
        if (updateSelf) {
          this._baseProperties['deleted_at'] = new Date();
        }

        return data;
      });
  }

  /**
   * Restore item
   * @returns {Promise} - Resolves with {@link CrudBase} instance and rejects with {@link ApiError}
   */
  restore(updateSelf = true) {
    return this.api
      .request(this.url, 'PUT')
      .then(data => {
        const instance = new this.constructor(this.api, data);

        if (updateSelf) {
          this._properties = {};
          this._baseProperties = data;

          this._updateProperties();
        }

        return instance;
      });

  }

  /**
   * Sync, attach or unlink resources
   * @param {Array<Organisation>|Array<Number>} items - List of items to sync or attach
   * @param {String} method - Http method to use
   * @param {ResourceBase} Type - Resource type
   * @param {?String} path - Optional appended resource path, will guess if null
   * @returns {Promise} - Promise will resolve with no value and reject with an {@link ApiError} instance.
   * @todo refactor to CrudBase and remove organisation specific method from trait
   * @protected
   */
  _modifyLink(items, method, Type, path) {
    if (!path) {
      const resource = (new Type(this.api)).resourceName.replace(/s+$/, '');

      path = `${resource}s`;
    }

    const filter = x => !isParentOf(Type, x) && !isParentOf(Number, x);
    const isValid = items.filter(filter).length === 0;

    if (!isValid) {
      throw new TypeError(`Array must contain either Numbers (resource id) or "${Type.name}".`);
    }

    const keys = items.map(x => typeof x === 'number' ? x : x.id).map(Number);

    return this.api.request(`${this.url}/${path}`, method, {keys});
  }
}
<|endoftext|>


<commit_before>/** section: wysihat
 * class WysiHat.Toolbar
 **/
WysiHat.Toolbar = Class.create((function() {
  /**
   * new WysiHat.Toolbar(editor)
   * - editor (WysiHat.Editor): the editor object that you want to attach to
   *
   *  Creates a toolbar element above the editor. The WysiHat.Toolbar object
   *  has many helper methods to easily add buttons to the toolbar.
   *
   *  This toolbar class is not required for the Editor object to function.
   *  It is merely a set of helper methods to get you started and to build
   *  on top of. If you are going to use this class in your application,
   *  it is highly recommended that you subclass it and override methods
   *  to add custom functionality.
   **/
  function initialize(editor) {
    this.editor = editor;
    this.element = this.createToolbarElement();
  }

  /**
   * WysiHat.Toolbar#createToolbarElement() -> Element
   *  Creates a toolbar container element and inserts it right above the
   *  original textarea element. The element is a div with the class
   *  'editor_toolbar'.
   *
   *  You can override this method to customize the element attributes and
   *  insert position. Be sure to return the element after it has been
   *  inserted.
   **/
  function createToolbarElement() {
    var toolbar = new Element('div', { 'class': 'editor_toolbar' });
    this.editor.insert({before: toolbar});
    return toolbar;
  }

  /**
   * WysiHat.Toolbar#addButtonSet(set) -> undefined
   *  - set (Array): The set array contains nested arrays that hold the
   *  button options, and handler.
   *
   *  Adds a button set to the toolbar.
   **/
  function addButtonSet(set) {
    var toolbar = this;
    $A(set).each(function(button){
      toolbar.addButton(button);
    });
  }

  /**
   * WysiHat.Toolbar#addButton(options[, handler]) -> undefined
   * - options (Hash): Required options hash
   * - handler (Function): Function to bind to the button
   *
   *  The options hash accepts two required keys, name and label. The label
   *  value is used as the link's inner text. The name value is set to the
   *  link's class and is used to check the button state. However the name
   *  may be omitted if the name and label are the same. In that case, the
   *  label will be down cased to make the name value. So a "Bold" label
   *  will default to "bold" name.
   *
   *  The second optional handler argument will be used if no handler
   *  function is supplied in the options hash.
   *
   *  toolbar.addButton({
   *    name: 'bold', label: "Bold" }, function(editor) {
   *      editor.boldSelection();
   *  });
   *
   *  Would create a link,
   *  "Bold"
   **/
  function addButton(options, handler) {
    options = $H(options);

    if (!options.get('name'))
      options.set('name', options.get('label').toLowerCase());
    var name = options.get('name');

    var button = this.createButtonElement(this.element, options);

    var handler = this.buttonHandler(name, options);
    this.observeButtonClick(button, handler);

    var handler = this.buttonStateHandler(name, options);
    this.observeStateChanges(button, name, handler)
  }

  /**
   * WysiHat.Toolbar#createButtonElement(toolbar, options) -> Element
   * - toolbar (Element): Toolbar element created by createToolbarElement
   * - options (Hash): Options hash that pass from addButton
   *
   *  Creates individual button elements and inserts them into the toolbar
   *  container. The default elements are 'a' tags with a 'button' class.
   *
   *  You can override this method to customize the element attributes and
   *  insert positions. Be sure to return the element after it has been
   *  inserted.
   **/
  function createButtonElement(toolbar, options) {
    var button = Element('a', {
      'class': 'button', 'href': '#'
    });
    button.update('' + options.get('label') + '');
    button.addClassName(options.get('name'));

    toolbar.appendChild(button);

    return button;
  }

  /**
   * WysiHat.Toolbar#buttonHandler(name, options) -> Function
   * - name (String): Name of button command: 'bold', 'italic'
   * - options (Hash): Options hash that pass from addButton
   *
   *  Returns the button handler function to bind to the buttons onclick
   *  event. It checks the options for a 'handler' attribute otherwise it
   *  defaults to a function that calls execCommand with the button name.
   **/
  function buttonHandler(name, options) {
    if (options.handler)
      return options.handler;
    else if (options.get('handler'))
      return options.get('handler');
    else
      return function(editor) { editor.execCommand(name); };
  }

  /**
   * WysiHat.Toolbar#observeButtonClick(element, handler) -> undefined
   * - element (Element): Button element
   * - handler (Function): Handler function to bind to element
   *
   *  Bind handler to elements onclick event.
   **/
  function observeButtonClick(element, handler) {
    var toolbar = this;
    element.observe('click', function(event) {
      handler(toolbar.editor);
      toolbar.editor.fire("wysihat:change");
      toolbar.editor.fire("wysihat:cursormove");
      Event.stop(event);
    });
  }

  /**
   * WysiHat.Toolbar#buttonStateHandler(name, options) -> Function
   * - name (String): Name of button command: 'bold', 'italic'
   * - options (Hash): Options hash that pass from addButton
   *
   *  Returns the button handler function that checks whether the button
   *  state is on (true) or off (false). It checks the options for a
   *  'query' attribute otherwise it defaults to a function that calls
   *  queryCommandState with the button name.
   **/
  function buttonStateHandler(name, options) {
    if (options.query)
      return options.query;
    else if (options.get('query'))
      return options.get('query');
    else
      return function(editor) { return editor.queryCommandState(name); };
  }

  /**
   * WysiHat.Toolbar#observeStateChanges(element, name, handler) -> undefined
   * - element (Element): Button element
   * - name (String): Button name
   * - handler (Function): State query function
   *
   *  Determines buttons state by calling the query handler function then
   *  calls updateButtonState.
   **/
  function observeStateChanges(element, name, handler) {
    var toolbar = this;
    toolbar.editor.observe("wysihat:cursormove", function(event) {
      var state = handler(toolbar.editor);
      toolbar.updateButtonState(element, name, state);
    });
  }

  /**
   * WysiHat.Toolbar#updateButtonState(element, name, state) -> undefined
   * - element (Element): Button element
   * - name (String): Button name
   * - state (Boolean): Whether button state is on/off
   *
   *  If the state is on, it adds a 'selected' class to the button element.
   *  Otherwise it removes the 'selected' class.
   *
   *  You can override this method to change the class name or styles
   *  applied to buttons when their state changes.
   **/
  function updateButtonState(element, name, state) {
    if (state)
      element.addClassName('selected');
    else
      element.removeClassName('selected');
  }

  return {
    initialize:           initialize,
    createToolbarElement: createToolbarElement,
    addButtonSet:         addButtonSet,
    addButton:            addButton,
    createButtonElement:  createButtonElement,
    buttonHandler:        buttonHandler,
    observeButtonClick:   observeButtonClick,
    buttonStateHandler:   buttonStateHandler,
    observeStateChanges:  observeStateChanges,
    updateButtonState:    updateButtonState
  };
})());

//= require "toolbar/button_sets"
<commit_msg>reduce the number of times Toolbar#updateButtonState is fired<commit_after>/** section: wysihat
 * class WysiHat.Toolbar
 **/
WysiHat.Toolbar = Class.create((function() {
  /**
   * new WysiHat.Toolbar(editor)
   * - editor (WysiHat.Editor): the editor object that you want to attach to
   *
   *  Creates a toolbar element above the editor. The WysiHat.Toolbar object
   *  has many helper methods to easily add buttons to the toolbar.
   *
   *  This toolbar class is not required for the Editor object to function.
   *  It is merely a set of helper methods to get you started and to build
   *  on top of. If you are going to use this class in your application,
   *  it is highly recommended that you subclass it and override methods
   *  to add custom functionality.
   **/
  function initialize(editor) {
    this.editor = editor;
    this.element = this.createToolbarElement();
  }

  /**
   * WysiHat.Toolbar#createToolbarElement() -> Element
   *  Creates a toolbar container element and inserts it right above the
   *  original textarea element. The element is a div with the class
   *  'editor_toolbar'.
   *
   *  You can override this method to customize the element attributes and
   *  insert position. Be sure to return the element after it has been
   *  inserted.
   **/
  function createToolbarElement() {
    var toolbar = new Element('div', { 'class': 'editor_toolbar' });
    this.editor.insert({before: toolbar});
    return toolbar;
  }

  /**
   * WysiHat.Toolbar#addButtonSet(set) -> undefined
   *  - set (Array): The set array contains nested arrays that hold the
   *  button options, and handler.
   *
   *  Adds a button set to the toolbar.
   **/
  function addButtonSet(set) {
    var toolbar = this;
    $A(set).each(function(button){
      toolbar.addButton(button);
    });
  }

  /**
   * WysiHat.Toolbar#addButton(options[, handler]) -> undefined
   * - options (Hash): Required options hash
   * - handler (Function): Function to bind to the button
   *
   *  The options hash accepts two required keys, name and label. The label
   *  value is used as the link's inner text. The name value is set to the
   *  link's class and is used to check the button state. However the name
   *  may be omitted if the name and label are the same. In that case, the
   *  label will be down cased to make the name value. So a "Bold" label
   *  will default to "bold" name.
   *
   *  The second optional handler argument will be used if no handler
   *  function is supplied in the options hash.
   *
   *  toolbar.addButton({
   *    name: 'bold', label: "Bold" }, function(editor) {
   *      editor.boldSelection();
   *  });
   *
   *  Would create a link,
   *  "Bold"
   **/
  function addButton(options, handler) {
    options = $H(options);

    if (!options.get('name'))
      options.set('name', options.get('label').toLowerCase());
    var name = options.get('name');

    var button = this.createButtonElement(this.element, options);

    var handler = this.buttonHandler(name, options);
    this.observeButtonClick(button, handler);

    var handler = this.buttonStateHandler(name, options);
    this.observeStateChanges(button, name, handler)
  }

  /**
   * WysiHat.Toolbar#createButtonElement(toolbar, options) -> Element
   * - toolbar (Element): Toolbar element created by createToolbarElement
   * - options (Hash): Options hash that pass from addButton
   *
   *  Creates individual button elements and inserts them into the toolbar
   *  container. The default elements are 'a' tags with a 'button' class.
   *
   *  You can override this method to customize the element attributes and
   *  insert positions. Be sure to return the element after it has been
   *  inserted.
   **/
  function createButtonElement(toolbar, options) {
    var button = Element('a', {
      'class': 'button', 'href': '#'
    });
    button.update('' + options.get('label') + '');
    button.addClassName(options.get('name'));

    toolbar.appendChild(button);

    return button;
  }

  /**
   * WysiHat.Toolbar#buttonHandler(name, options) -> Function
   * - name (String): Name of button command: 'bold', 'italic'
   * - options (Hash): Options hash that pass from addButton
   *
   *  Returns the button handler function to bind to the buttons onclick
   *  event. It checks the options for a 'handler' attribute otherwise it
   *  defaults to a function that calls execCommand with the button name.
   **/
  function buttonHandler(name, options) {
    if (options.handler)
      return options.handler;
    else if (options.get('handler'))
      return options.get('handler');
    else
      return function(editor) { editor.execCommand(name); };
  }

  /**
   * WysiHat.Toolbar#observeButtonClick(element, handler) -> undefined
   * - element (Element): Button element
   * - handler (Function): Handler function to bind to element
   *
   *  Bind handler to elements onclick event.
   **/
  function observeButtonClick(element, handler) {
    var toolbar = this;
    element.observe('click', function(event) {
      handler(toolbar.editor);
      toolbar.editor.fire("wysihat:change");
      toolbar.editor.fire("wysihat:cursormove");
      Event.stop(event);
    });
  }

  /**
   * WysiHat.Toolbar#buttonStateHandler(name, options) -> Function
   * - name (String): Name of button command: 'bold', 'italic'
   * - options (Hash): Options hash that pass from addButton
   *
   *  Returns the button handler function that checks whether the button
   *  state is on (true) or off (false). It checks the options for a
   *  'query' attribute otherwise it defaults to a function that calls
   *  queryCommandState with the button name.
   **/
  function buttonStateHandler(name, options) {
    if (options.query)
      return options.query;
    else if (options.get('query'))
      return options.get('query');
    else
      return function(editor) { return editor.queryCommandState(name); };
  }

  /**
   * WysiHat.Toolbar#observeStateChanges(element, name, handler) -> undefined
   * - element (Element): Button element
   * - name (String): Button name
   * - handler (Function): State query function
   *
   *  Determines buttons state by calling the query handler function then
   *  calls updateButtonState.
   **/
  function observeStateChanges(element, name, handler) {
    var toolbar = this;
    var previousState = handler(toolbar.editor);
    toolbar.editor.observe("wysihat:cursormove", function(event) {
      var state = handler(toolbar.editor);
      if (state != previousState) {
        previousState = state;
        toolbar.updateButtonState(element, name, state);
      }
    });
  }

  /**
   * WysiHat.Toolbar#updateButtonState(element, name, state) -> undefined
   * - element (Element): Button element
   * - name (String): Button name
   * - state (Boolean): Whether button state is on/off
   *
   *  If the state is on, it adds a 'selected' class to the button element.
   *  Otherwise it removes the 'selected' class.
   *
   *  You can override this method to change the class name or styles
   *  applied to buttons when their state changes.
   **/
  function updateButtonState(element, name, state) {
    if (state)
      element.addClassName('selected');
    else
      element.removeClassName('selected');
  }

  return {
    initialize:           initialize,
    createToolbarElement: createToolbarElement,
    addButtonSet:         addButtonSet,
    addButton:            addButton,
    createButtonElement:  createButtonElement,
    buttonHandler:        buttonHandler,
    observeButtonClick:   observeButtonClick,
    buttonStateHandler:   buttonStateHandler,
    observeStateChanges:  observeStateChanges,
    updateButtonState:    updateButtonState
  };
})());

//= require "toolbar/button_sets"
<|endoftext|>