<commit_before>import DualList from '../'

it('test dualList with props `items` and `onChange`', async() => {
  const pokemon = [
    'Squirtle',
    'Caterpie',
    'Raichu',
    'Pikachu'
  ]
  const getData = (data) => {}
  let vm
  await new Promise((done) => {
    vm = shallow({
      render(h) {
        return (
          <DualList items={pokemon} onChange={getData} />
        )
      }
    })
    expect(vm.listToAdd).toEqual({
      0: 'Squirtle',
      1: 'Caterpie',
      2: 'Raichu',
      3: 'Pikachu',
    })
    expect(vm.leftList).toEqual({
      0: 'Squirtle',
      1: 'Caterpie',
      2: 'Raichu',
      3: 'Pikachu',
    })
    vm.$nextTick(done)
  })
  //click on 2: 'Raichu'
  $(vm.$children[6].$el).trigger('click')
  expect(vm.leftList).toEqual({
    0: 'Squirtle',
    1: 'Caterpie',
    3: 'Pikachu',
  })
  expect(vm.listToAdd).toEqual({
    0: 'Squirtle',
    1: 'Caterpie',
    3: 'Pikachu',
  })
  expect(vm.rightList).toEqual({
    2: 'Raichu'
  })
  expect(vm.listToRemove).toEqual({
    2: 'Raichu'
  })
})

it('test dualList with props `selectedItems` and without `items`', async() => {
  const pokemon = [
    'Squirtle',
    'Caterpie'
  ]
  let vm
  await new Promise((done) => {
    vm = shallow({
      render(h) {
        return (
          <DualList selectedItems={pokemon} />
        )
      }
    })
    expect(vm.listToRemove).toEqual({
      0: 'Squirtle',
      1: 'Caterpie'
    })
    expect(vm.rightList).toEqual({
      0: 'Squirtle',
      1: 'Caterpie'
    })
    expect(vm.listToAdd).toEqual({})
    expect(vm.leftList).toEqual({})
    vm.$nextTick(done)
  })
  // click on 2 again: 'Raichu'
  $(vm.$children[5].$el).trigger('click')
  expect(vm.listToRemove).toEqual({
    0: 'Squirtle'
  })
  expect(vm.rightList).toEqual({
    0: 'Squirtle'
  })
  expect(vm.listToAdd).toEqual({
    1: 'Caterpie'
  })
  expect(vm.leftList).toEqual({
    1: 'Caterpie'
  })
})

it('test search features', async() => {
  const pokemon = [
    'Squirtle',
    'Caterpie',
    'Raichu',
    'Pikachu'
  ]
  const getData = (data) => {}
  let vm
  await new Promise((done) => {
    vm = shallow({
      render(h) {
        return (
          <DualList items={pokemon} onChange={getData} />
        )
      }
    })
    //search leftList
    vm.$refs.searchListToAdd.value = 'chu'
    $(vm.$refs.searchListToAdd.$el).val('chu')

    const e = { charCode: 13 }
    vm.handleSearchListLeft(e)// $(vm.$children[0].$el).trigger('keypress', e) is not effective
    expect(vm.listToAdd).toEqual({
      2: 'Raichu',
      3: 'Pikachu'
    })
    expect(vm.highlightLeft).toBe('chu')
    vm.$nextTick(done)
  })
  //click on selectAll
  $(vm.$children[1].$el).trigger('click')
  expect(vm.leftList).toEqual({
    0: 'Squirtle',
    1: 'Caterpie'
  })
  expect(vm.listToAdd).toEqual({})
  expect(vm.rightList).toEqual({
    2: 'Raichu',
    3: 'Pikachu',
  })
  expect(vm.listToRemove).toEqual({
    2: 'Raichu',
    3: 'Pikachu',
  })

  //clickOnX
  vm.handleClickOnX('left')// $(vm.$children[0].$children[1].$el).trigger('click') is not effective
  expect(vm.listToAdd).toEqual({
    0: 'Squirtle',
    1: 'Caterpie'
  })
  expect(vm.highlightLeft).toBe('')

  //search rightList
  vm.$refs.searchListToRemove.value = 'Rai'
  $(vm.$refs.searchListToRemove.$el).val('Rai')

  const e = { charCode: 13 }
  vm.handleSearchListRight(e)
  expect(vm.listToRemove).toEqual({
    2: 'Raichu'
  })
  expect(vm.highlightRight).toBe('Rai')

  //click on unSelectAll
  $(vm.$children[2].$el).trigger('click')
  expect(vm.rightList).toEqual({
    3: 'Pikachu'
  })
  expect(vm.listToRemove).toEqual({})
  expect(vm.leftList).toEqual({
    0: 'Squirtle',
    1: 'Caterpie',
    2: 'Raichu'
  })
  expect(vm.listToAdd).toEqual({
    0: 'Squirtle',
    1: 'Caterpie',
    2: 'Raichu'
  })

  //clickOnX
  vm.handleClickOnX('right')
  expect(vm.listToRemove).toEqual({
    3: 'Pikachu'
  })
  expect(vm.highlightRight).toBe('')
})

it('test apiMode props `items` dynamic change', async() => {
  const getInputValue = (data) => {}
  const removeInput = () => {}
  let vm
  await new Promise((done) => {
    vm = shallow({
      data() {
        return {
          pokemon: [
            'Squirtle',
            'Caterpie',
            'Raichu',
            'Pikachu',
          ]
        }
      },
      mounted() {
        this.pokemon = [
          'Squirtle',
          'Caterpie'
        ]
        this.$nextTick(done)
      },
      render(h) {
        return (
          <DualList apiMode items={this.pokemon} onInputchange={getInputValue} onRemove={removeInput} leftLoading={true} />
        )
      }
    })
  })
  expect(vm.listToAdd).toEqual({
    0: 'Squirtle',
    1: 'Caterpie'
  })
  expect(vm.leftList).toEqual({
    0: 'Squirtle',
    1: 'Caterpie'
  })
})

it('test apiMode `<Input />` event', async() => {
  let vm
  const pokemon = [
    'Squirtle',
    'Caterpie',
    'Raichu',
    'Pikachu',
  ]
  const getInputValue = (data) => {
    expect(data).toBe('chu')
  }
  const removeInput = () => {}
  await new Promise((done) => {
    vm = shallow({
      render(h) {
        return (
          <DualList apiMode items={pokemon} onInputchange={getInputValue} onRemove={removeInput} leftLoading={true} />
        )
      }
    })
    //search leftList
    vm.$refs.searchListToAdd.value = 'chu'
    $(vm.$refs.searchListToAdd.$el).val('chu')

    const e = { charCode: 13 }
    vm.handleSearchListLeft(e)
    vm.$nextTick(done)
  })
  //clickOnX
  vm.handleClickOnX('left')
})
<commit_msg>[DualList] add test specs for `selectAll` and `unSelectAll`<commit_after>import DualList from '../'

it('test dualList with props `items` and `onChange`', async() => {
  const pokemon = [
    'Squirtle',
    'Caterpie',
    'Raichu',
    'Pikachu'
  ]
  const getData = (data) => {}
  let vm
  await new Promise((done) => {
    vm = shallow({
      render(h) {
        return (
          <DualList items={pokemon} onChange={getData} />
        )
      }
    })
    expect(vm.listToAdd).toEqual({
      0: 'Squirtle',
      1: 'Caterpie',
      2: 'Raichu',
      3: 'Pikachu',
    })
    expect(vm.leftList).toEqual({
      0: 'Squirtle',
      1: 'Caterpie',
      2: 'Raichu',
      3: 'Pikachu',
    })
    vm.$nextTick(done)
  })
  //click on 2: 'Raichu'
  $(vm.$children[6].$el).trigger('click')
  expect(vm.leftList).toEqual({
    0: 'Squirtle',
    1: 'Caterpie',
    3: 'Pikachu',
  })
  expect(vm.listToAdd).toEqual({
    0: 'Squirtle',
    1: 'Caterpie',
    3: 'Pikachu',
  })
  expect(vm.rightList).toEqual({
    2: 'Raichu'
  })
  expect(vm.listToRemove).toEqual({
    2: 'Raichu'
  })
})

it('test dualList with props `selectedItems` and without `items`', async() => {
  const pokemon = [
    'Squirtle',
    'Caterpie'
  ]
  let vm
  await new Promise((done) => {
    vm = shallow({
      render(h) {
        return (
          <DualList selectedItems={pokemon} />
        )
      }
    })
    expect(vm.listToRemove).toEqual({
      0: 'Squirtle',
      1: 'Caterpie'
    })
    expect(vm.rightList).toEqual({
      0: 'Squirtle',
      1: 'Caterpie'
    })
    expect(vm.listToAdd).toEqual({})
    expect(vm.leftList).toEqual({})
    vm.$nextTick(done)
  })
  // click on 2 again: 'Raichu'
  $(vm.$children[5].$el).trigger('click')
  expect(vm.listToRemove).toEqual({
    0: 'Squirtle'
  })
  expect(vm.rightList).toEqual({
    0: 'Squirtle'
  })
  expect(vm.listToAdd).toEqual({
    1: 'Caterpie'
  })
  expect(vm.leftList).toEqual({
    1: 'Caterpie'
  })
})

it('test search feature', async() => {
  const pokemon = [
    'Squirtle',
    'Caterpie',
    'Raichu',
    'Pikachu'
  ]
  const getData = (data) => {}
  let vm
  await new Promise((done) => {
    vm = shallow({
      render(h) {
        return (
          <DualList items={pokemon} onChange={getData} />
        )
      }
    })
    //search leftList
    vm.$refs.searchListToAdd.value = 'chu'
    $(vm.$refs.searchListToAdd.$el).val('chu')

    const e = { charCode: 13 }
    vm.handleSearchListLeft(e)// $(vm.$children[0].$el).trigger('keypress', e) is not effective
    expect(vm.listToAdd).toEqual({
      2: 'Raichu',
      3: 'Pikachu'
    })
    expect(vm.highlightLeft).toBe('chu')
    vm.$nextTick(done)
  })
  //click on selectAll
  $(vm.$children[1].$el).trigger('click')
  expect(vm.leftList).toEqual({
    0: 'Squirtle',
    1: 'Caterpie'
  })
  expect(vm.listToAdd).toEqual({})
  expect(vm.rightList).toEqual({
    2: 'Raichu',
    3: 'Pikachu',
  })
  expect(vm.listToRemove).toEqual({
    2: 'Raichu',
    3: 'Pikachu',
  })

  //clickOnX
  vm.handleClickOnX('left')// $(vm.$children[0].$children[1].$el).trigger('click') is not effective
  expect(vm.listToAdd).toEqual({
    0: 'Squirtle',
    1: 'Caterpie'
  })
  expect(vm.highlightLeft).toBe('')

  //search rightList
  vm.$refs.searchListToRemove.value = 'Rai'
  $(vm.$refs.searchListToRemove.$el).val('Rai')

  const e = { charCode: 13 }
  vm.handleSearchListRight(e)
  expect(vm.listToRemove).toEqual({
    2: 'Raichu'
  })
  expect(vm.highlightRight).toBe('Rai')

  //click on unSelectAll
  $(vm.$children[2].$el).trigger('click')
  expect(vm.rightList).toEqual({
    3: 'Pikachu'
  })
  expect(vm.listToRemove).toEqual({})
  expect(vm.leftList).toEqual({
    0: 'Squirtle',
    1: 'Caterpie',
    2: 'Raichu'
  })
  expect(vm.listToAdd).toEqual({
    0: 'Squirtle',
    1: 'Caterpie',
    2: 'Raichu'
  })

  //clickOnX
  vm.handleClickOnX('right')
  expect(vm.listToRemove).toEqual({
    3: 'Pikachu'
  })
  expect(vm.highlightRight).toBe('')
})

it('test apiMode props `items` dynamic change', async() => {
  const getInputValue = (data) => {}
  const removeInput = () => {}
  let vm
  await new Promise((done) => {
    vm = shallow({
      data() {
        return {
          pokemon: [
            'Squirtle',
            'Caterpie',
            'Raichu',
            'Pikachu',
          ]
        }
      },
      mounted() {
        this.pokemon = [
          'Squirtle',
          'Caterpie'
        ]
        this.$nextTick(done)
      },
      render(h) {
        return (
          <DualList apiMode items={this.pokemon} onInputchange={getInputValue} onRemove={removeInput} leftLoading={true} />
        )
      }
    })
  })
  expect(vm.listToAdd).toEqual({
    0: 'Squirtle',
    1: 'Caterpie'
  })
  expect(vm.leftList).toEqual({
    0: 'Squirtle',
    1: 'Caterpie'
  })
})

it('test apiMode `<Input />` event', async() => {
  let vm
  const pokemon = [
    'Squirtle',
    'Caterpie',
    'Raichu',
    'Pikachu',
  ]
  const getInputValue = (data) => {
    expect(data).toBe('chu')
  }
  const removeInput = () => {}
  await new Promise((done) => {
    vm = shallow({
      render(h) {
        return (
          <DualList apiMode items={pokemon} onInputchange={getInputValue} onRemove={removeInput} leftLoading={true} />
        )
      }
    })
    //search leftList
    vm.$refs.searchListToAdd.value = 'chu'
    $(vm.$refs.searchListToAdd.$el).val('chu')

    const e = { charCode: 13 }
    vm.handleSearchListLeft(e)
    vm.$nextTick(done)
  })
  //clickOnX
  vm.handleClickOnX('left')
})

it('test selectAll feature', async() => {
  let vm
  const pokemon = [
    'Squirtle',
    'Caterpie',
    'Raichu',
    'Pikachu',
  ]
  await new Promise((done) => {
    vm = shallow({
      render(h) {
        return (
          <DualList items={pokemon} />
        )
      }
    })
    //selectAll
    $(vm.$children[1].$el).trigger('click')
    vm.$nextTick(done)
  })
  expect(vm.listToRemove).toEqual({
    0: 'Squirtle',
    1: 'Caterpie',
    2: 'Raichu',
    3: 'Pikachu'
  })
  expect(vm.rightList).toEqual({
    0: 'Squirtle',
    1: 'Caterpie',
    2: 'Raichu',
    3: 'Pikachu'
  })
})

it('test unSelectAll feature', async() => {
  let vm
  const pokemon = [
    'Squirtle',
    'Caterpie',
    'Raichu',
    'Pikachu',
  ]
  await new Promise((done) => {
    vm = shallow({
      render(h) {
        return (
          <DualList selectedItems={pokemon} />
        )
      }
    })
    //unSelectAll
    $(vm.$children[2].$el).trigger('click')
    vm.$nextTick(done)
  })
  expect(vm.listToAdd).toEqual({
    0: 'Squirtle',
    1: 'Caterpie',
    2: 'Raichu',
    3: 'Pikachu'
  })
  expect(vm.leftList).toEqual({
    0: 'Squirtle',
    1: 'Caterpie',
    2: 'Raichu',
    3: 'Pikachu'
  })
})
<|endoftext|>


<commit_before>//#import "calabash_script_uia.js"

if (typeof JSON !== 'object') {
    JSON = {};
}
(function () {
    'use strict';
    function f(n) {
        return n < 10 ? '0' + n : n;
    }

    if (typeof Date.prototype.toJSON !== 'function') {
        Date.prototype.toJSON = function (key) {
            return isFinite(this.valueOf()) ? this.getUTCFullYear() + '-' +
                f(this.getUTCMonth() + 1) + '-' +
                f(this.getUTCDate()) + 'T' +
                f(this.getUTCHours()) + ':' +
                f(this.getUTCMinutes()) + ':' +
                f(this.getUTCSeconds()) + 'Z' : null;
        };
        String.prototype.toJSON = Number.prototype.toJSON = Boolean.prototype.toJSON = function (key) {
            return this.valueOf();
        };
    }
    var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, gap, indent, meta = {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"': '\\"', '\\': '\\\\'}, rep;

    function quote(string) {
        escapable.lastIndex = 0;
        return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
            var c = meta[a];
            return typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
        }) + '"' : '"' + string + '"';
    }

    function str(key, holder) {
        var i, k, v, length, mind = gap, partial, value = holder[key];
        if (value && typeof value === 'object' && typeof value.toJSON === 'function') {
            value = value.toJSON(key);
        }
        if (typeof rep === 'function') {
            value = rep.call(holder, key, value);
        }
        switch (typeof value) {
            case'string':
                return quote(value);
            case'number':
                return isFinite(value) ? String(value) : 'null';
            case'boolean':
            case'null':
                return String(value);
            case'object':
                if (!value) {
                    return'null';
                }
                gap += indent;
                partial = [];
                if (Object.prototype.toString.apply(value) === '[object Array]') {
                    length = value.length;
                    for (i = 0; i < length; i += 1) {
                        partial[i] = str(i, value) || 'null';
                    }
                    v = partial.length === 0 ? '[]' : gap ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' : '[' + partial.join(',') + ']';
                    gap = mind;
                    return v;
                }
                if (rep && typeof rep === 'object') {
                    length = rep.length;
                    for (i = 0; i < length; i += 1) {
                        if (typeof rep[i] === 'string') {
                            k = rep[i];
                            v = str(k, value);
                            if (v) {
                                partial.push(quote(k) + (gap ? ': ' : ':') + v);
                            }
                        }
                    }
                } else {
                    for (k in value) {
                        if (Object.prototype.hasOwnProperty.call(value, k)) {
                            v = str(k, value);
                            if (v) {
                                partial.push(quote(k) + (gap ? ': ' : ':') + v);
                            }
                        }
                    }
                }
                v = partial.length === 0 ? '{}' : gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' : '{' + partial.join(',') + '}';
                gap = mind;
                return v;
        }
    }

    if (typeof JSON.stringify !== 'function') {
        JSON.stringify = function (value, replacer, space) {
            var i;
            gap = '';
            indent = '';
            if (typeof space === 'number') {
                for (i = 0; i < space; i += 1) {
                    indent += ' ';
                }
            } else if (typeof space === 'string') {
                indent = space;
            }
            rep = replacer;
            if (replacer && typeof replacer !== 'function' && (typeof replacer !== 'object' || typeof replacer.length !== 'number')) {
                throw new Error('JSON.stringify');
            }
            return str('', {'': value});
        };
    }
    if (typeof JSON.parse !== 'function') {
        JSON.parse = function (text, reviver) {
            var j;

            function walk(holder, key) {
                var k, v, value = holder[key];
                if (value && typeof value === 'object') {
                    for (k in value) {
                        if (Object.prototype.hasOwnProperty.call(value, k)) {
                            v = walk(value, k);
                            if (v !== undefined) {
                                value[k] = v;
                            } else {
                                delete value[k];
                            }
                        }
                    }
                }
                return reviver.call(holder, key, value);
            }

            text = String(text);
            cx.lastIndex = 0;
            if (cx.test(text)) {
                text = text.replace(cx, function (a) {
                    return'\\u' +
                        ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
                });
            }
            if (/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
                j = eval('(' + text + ')');
                return typeof reviver === 'function' ? walk({'': j}, '') : j;
            }
            throw new SyntaxError('JSON.parse');
        };
    }
}());

var commandPath = "$PATH";
if (!/\/$/.test(commandPath)) {
    commandPath += "/";
}
commandPath += "repl-cmd.pipe";

var blockingReadScriptPath = "$READ_SCRIPT_PATH";

var _expectedIndex = 0,//expected index of next command
    _actualIndex,//actual index of next command by reading commandPath
    _index,//index of ':' char in command
    _exp,//expression to be eval'ed
    _result,//result of eval
    _input,//command
    _process;//host command process

var Log = (function () {
    var forceFlush = [],
        N = "$MODE" == "FLUSH" ? 16384 : 0,
        i = N;
    while (i--) {
        forceFlush[i] = "*";
    }
    forceFlush = forceFlush.join('');

    function log_json(object)
    {
        UIALogger.logMessage("OUTPUT_JSON:\n"+JSON.stringify(object)+"\nEND_OUTPUT");
    }

    return {
        result: function (status, data) {
            log_json({"status": status, "value": data, "index":_actualIndex})
            if (forceFlush.length > 0) {
                UIALogger.logMessage(forceFlush);
            }
        },
        output: function (msg) {
            log_json({"output": msg,"last_index":_actualIndex});
            if (forceFlush.length > 0) {
                UIALogger.logMessage(forceFlush);
            }
        }
    };
})();

function findAlertViewText(alert) {
    if (!alert) {
        return false;
    }
    var txt = alert.name(),
        txts;
    if (txt == null) {
        txts = alert.staticTexts();
        if (txts != null && txts.length > 0) {
            txt = txts[0].name();
        }
    }
    return txt;
}

function isLocationPrompt(alert) {
    var exps = [
            ["OK", /vil bruge din aktuelle placering/],
            ["OK", /Would Like to Use Your Current Location/],
            ["Ja", /Darf (?:.)+ Ihren aktuellen Ort verwenden/],
            ["OK", /Would Like to Access Your Photos/],
            ["OK", /Would Like to Access Your Contacts/],
            ["OK", /запрашивает разрешение на использование Ващей текущей пгеопозиции/]
        ],
        ans, exp,
        txt;

    txt = findAlertViewText(alert);
    Log.output({"output":"alert: "+txt}, true);
    for (var i = 0; i < exps.length; i++) {
        ans = exps[i][0];
        exp = exps[i][1];
        if (exp.test(txt)) {
            return ans;
        }
    }
    return false;
}

UIATarget.onAlert = function (alert) {
    Log.output({"output":"on alert"}, true);
    var target = UIATarget.localTarget();
    target.pushTimeout(10);
    function attemptTouchOKOnLocation(retry_count) {
        retry_count = retry_count || 0;
        if (retry_count >= 5) {
            Log.output("Maxed out retry (5) - unable to dismiss location dialog.");
            return;
        }
        try {
            var answer = isLocationPrompt(alert);
            if (answer) {
                alert.buttons()[answer].tap();
            }
        }
        catch (e) {
            Log.output("Exception while trying to touch alert dialog. Retrying...");
            if (e && typeof e.toString == 'function') {
                Log.output(e.toString());
            }
            target.delay(1);
            attemptTouchOKOnLocation(retry_count + 1);
        }
    }

    attemptTouchOKOnLocation(0);
    target.popTimeout();
    return true;
};

var target = null,
    host = null;

while (true) {
    target = UIATarget.localTarget();

    host = target.host();
    try {
        _process = host.performTaskWithPathArgumentsTimeout("/bin/bash",
            [blockingReadScriptPath, commandPath],
            //[commandPath],
            5);

    } catch (e) {
        Log.output("Timeout on read command...");
        continue;
    }
    if (_process.exitCode != 0) {
        if (_process.exitCode != 15) {
            Log.output("unable to execute: " + blockingReadScriptPath + " " + commandPath + " exitCode " + _process.exitCode + ". Error: " + _process.stderr + _process.stdout);
        }
    }
    else {
        _input = _process.stdout;
        try {
            _index = _input.indexOf(":", 0);
            if (_index > -1) {
                _actualIndex = parseInt(_input.substring(0, _index), 10);
                if (!isNaN(_actualIndex) && _actualIndex >= _expectedIndex) {
                    _exp = _input.substring(_index + 1, _input.length);
                    Log.output("Execute: "+_exp);
                    _result = eval(_exp);
                }
                else {//likely old command is lingering...
                    continue;
                }
            }
            else {
                continue;
            }

        }
        catch (err) {
            Log.result("error", err.toString() + "  " + (err.stack ? err.stack.toString() : ""));
            _expectedIndex++;
            continue;
        }

        _expectedIndex = Math.max(_actualIndex+1, _expectedIndex+1);
        Log.result("success", _result);
    }
}<commit_msg>Decrease timeout 1<commit_after>//#import "calabash_script_uia.js"

if (typeof JSON !== 'object') {
    JSON = {};
}
(function () {
    'use strict';
    function f(n) {
        return n < 10 ? '0' + n : n;
    }

    if (typeof Date.prototype.toJSON !== 'function') {
        Date.prototype.toJSON = function (key) {
            return isFinite(this.valueOf()) ? this.getUTCFullYear() + '-' +
                f(this.getUTCMonth() + 1) + '-' +
                f(this.getUTCDate()) + 'T' +
                f(this.getUTCHours()) + ':' +
                f(this.getUTCMinutes()) + ':' +
                f(this.getUTCSeconds()) + 'Z' : null;
        };
        String.prototype.toJSON = Number.prototype.toJSON = Boolean.prototype.toJSON = function (key) {
            return this.valueOf();
        };
    }
    var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, gap, indent, meta = {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"': '\\"', '\\': '\\\\'}, rep;

    function quote(string) {
        escapable.lastIndex = 0;
        return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
            var c = meta[a];
            return typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
        }) + '"' : '"' + string + '"';
    }

    function str(key, holder) {
        var i, k, v, length, mind = gap, partial, value = holder[key];
        if (value && typeof value === 'object' && typeof value.toJSON === 'function') {
            value = value.toJSON(key);
        }
        if (typeof rep === 'function') {
            value = rep.call(holder, key, value);
        }
        switch (typeof value) {
            case'string':
                return quote(value);
            case'number':
                return isFinite(value) ? String(value) : 'null';
            case'boolean':
            case'null':
                return String(value);
            case'object':
                if (!value) {
                    return'null';
                }
                gap += indent;
                partial = [];
                if (Object.prototype.toString.apply(value) === '[object Array]') {
                    length = value.length;
                    for (i = 0; i < length; i += 1) {
                        partial[i] = str(i, value) || 'null';
                    }
                    v = partial.length === 0 ? '[]' : gap ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' : '[' + partial.join(',') + ']';
                    gap = mind;
                    return v;
                }
                if (rep && typeof rep === 'object') {
                    length = rep.length;
                    for (i = 0; i < length; i += 1) {
                        if (typeof rep[i] === 'string') {
                            k = rep[i];
                            v = str(k, value);
                            if (v) {
                                partial.push(quote(k) + (gap ? ': ' : ':') + v);
                            }
                        }
                    }
                } else {
                    for (k in value) {
                        if (Object.prototype.hasOwnProperty.call(value, k)) {
                            v = str(k, value);
                            if (v) {
                                partial.push(quote(k) + (gap ? ': ' : ':') + v);
                            }
                        }
                    }
                }
                v = partial.length === 0 ? '{}' : gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' : '{' + partial.join(',') + '}';
                gap = mind;
                return v;
        }
    }

    if (typeof JSON.stringify !== 'function') {
        JSON.stringify = function (value, replacer, space) {
            var i;
            gap = '';
            indent = '';
            if (typeof space === 'number') {
                for (i = 0; i < space; i += 1) {
                    indent += ' ';
                }
            } else if (typeof space === 'string') {
                indent = space;
            }
            rep = replacer;
            if (replacer && typeof replacer !== 'function' && (typeof replacer !== 'object' || typeof replacer.length !== 'number')) {
                throw new Error('JSON.stringify');
            }
            return str('', {'': value});
        };
    }
    if (typeof JSON.parse !== 'function') {
        JSON.parse = function (text, reviver) {
            var j;

            function walk(holder, key) {
                var k, v, value = holder[key];
                if (value && typeof value === 'object') {
                    for (k in value) {
                        if (Object.prototype.hasOwnProperty.call(value, k)) {
                            v = walk(value, k);
                            if (v !== undefined) {
                                value[k] = v;
                            } else {
                                delete value[k];
                            }
                        }
                    }
                }
                return reviver.call(holder, key, value);
            }

            text = String(text);
            cx.lastIndex = 0;
            if (cx.test(text)) {
                text = text.replace(cx, function (a) {
                    return'\\u' +
                        ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
                });
            }
            if (/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
                j = eval('(' + text + ')');
                return typeof reviver === 'function' ? walk({'': j}, '') : j;
            }
            throw new SyntaxError('JSON.parse');
        };
    }
}());

var commandPath = "$PATH";
if (!/\/$/.test(commandPath)) {
    commandPath += "/";
}
commandPath += "repl-cmd.pipe";

var blockingReadScriptPath = "$READ_SCRIPT_PATH";

var _expectedIndex = 0,//expected index of next command
    _actualIndex,//actual index of next command by reading commandPath
    _index,//index of ':' char in command
    _exp,//expression to be eval'ed
    _result,//result of eval
    _input,//command
    _process;//host command process

var Log = (function () {
    var forceFlush = [],
        N = "$MODE" == "FLUSH" ? 16384 : 0,
        i = N;
    while (i--) {
        forceFlush[i] = "*";
    }
    forceFlush = forceFlush.join('');

    function log_json(object)
    {
        UIALogger.logMessage("OUTPUT_JSON:\n"+JSON.stringify(object)+"\nEND_OUTPUT");
    }

    return {
        result: function (status, data) {
            log_json({"status": status, "value": data, "index":_actualIndex})
            if (forceFlush.length > 0) {
                UIALogger.logMessage(forceFlush);
            }
        },
        output: function (msg) {
            log_json({"output": msg,"last_index":_actualIndex});
            if (forceFlush.length > 0) {
                UIALogger.logMessage(forceFlush);
            }
        }
    };
})();

function findAlertViewText(alert) {
    if (!alert) {
        return false;
    }
    var txt = alert.name(),
        txts;
    if (txt == null) {
        txts = alert.staticTexts();
        if (txts != null && txts.length > 0) {
            txt = txts[0].name();
        }
    }
    return txt;
}

function isLocationPrompt(alert) {
    var exps = [
            ["OK", /vil bruge din aktuelle placering/],
            ["OK", /Would Like to Use Your Current Location/],
            ["Ja", /Darf (?:.)+ Ihren aktuellen Ort verwenden/],
            ["OK", /Would Like to Access Your Photos/],
            ["OK", /Would Like to Access Your Contacts/],
            ["OK", /запрашивает разрешение на использование Ващей текущей пгеопозиции/]
        ],
        ans, exp,
        txt;

    txt = findAlertViewText(alert);
    Log.output({"output":"alert: "+txt}, true);
    for (var i = 0; i < exps.length; i++) {
        ans = exps[i][0];
        exp = exps[i][1];
        if (exp.test(txt)) {
            return ans;
        }
    }
    return false;
}

UIATarget.onAlert = function (alert) {
    Log.output({"output":"on alert"}, true);
    var target = UIATarget.localTarget();
    target.pushTimeout(10);
    function attemptTouchOKOnLocation(retry_count) {
        retry_count = retry_count || 0;
        if (retry_count >= 5) {
            Log.output("Maxed out retry (5) - unable to dismiss location dialog.");
            return;
        }
        try {
            var answer = isLocationPrompt(alert);
            if (answer) {
                alert.buttons()[answer].tap();
            }
        }
        catch (e) {
            Log.output("Exception while trying to touch alert dialog. Retrying...");
            if (e && typeof e.toString == 'function') {
                Log.output(e.toString());
            }
            target.delay(1);
            attemptTouchOKOnLocation(retry_count + 1);
        }
    }

    attemptTouchOKOnLocation(0);
    target.popTimeout();
    return true;
};

var target = null,
    host = null;

while (true) {
    target = UIATarget.localTarget();

    host = target.host();
    try {
        _process = host.performTaskWithPathArgumentsTimeout("/bin/bash",
            [blockingReadScriptPath, commandPath],
            //[commandPath],
           1);

    } catch (e) {
        Log.output("Timeout on read command...");
        continue;
    }
    if (_process.exitCode != 0) {
        if (_process.exitCode != 15) {
            Log.output("unable to execute: " + blockingReadScriptPath + " " + commandPath + " exitCode " + _process.exitCode + ". Error: " + _process.stderr + _process.stdout);
        }
    }
    else {
        _input = _process.stdout;
        try {
            _index = _input.indexOf(":", 0);
            if (_index > -1) {
                _actualIndex = parseInt(_input.substring(0, _index), 10);
                if (!isNaN(_actualIndex) && _actualIndex >= _expectedIndex) {
                    _exp = _input.substring(_index + 1, _input.length);
                    Log.output("Execute: "+_exp);
                    _result = eval(_exp);
                }
                else {//likely old command is lingering...
                    continue;
                }
            }
            else {
                continue;
            }

        }
        catch (err) {
            Log.result("error", err.toString() + "  " + (err.stack ? err.stack.toString() : ""));
            _expectedIndex++;
            continue;
        }

        _expectedIndex = Math.max(_actualIndex+1, _expectedIndex+1);
        Log.result("success", _result);
    }
}<|endoftext|>


<commit_before>'use strict';

const Test = require('./include/runner');

const setUp = (context) => (context.repo = context.gitP(context.root)).init();

module.exports = {

   'adds a single file': new Test(setUp, async (context, assert) => {
      context.file('src', 'file.txt', 'file content');

      await context.repo.add('src/file.txt');
      const status = await context.repo.status();

      assert.same(status.created, ['src/file.txt']);
      assert.same(status.files.length, 1);

   }),

   'adds a all files': new Test(setUp, async (context, assert) => {
      context.file('src', 'a.txt', 'aaa content');
      context.file('src', 'b.txt', 'bbb content');

      await context.repo.add('*');
      const status = await context.repo.status();

      assert(status.created).same(['src/a.txt', 'src/b.txt']);
      assert(status.files.length).same(2);

   }),

};
<commit_msg>Fix use of `assert`<commit_after>'use strict';

const Test = require('./include/runner');

const setUp = (context) => (context.repo = context.gitP(context.root)).init();

module.exports = {

   'adds a single file': new Test(setUp, async (context, assert) => {
      context.file('src', 'file.txt', 'file content');

      await context.repo.add('src/file.txt');
      const status = await context.repo.status();

      assert.same(status.created, ['src/file.txt']);
      assert.same(status.files.length, 1);

   }),

   'adds a all files': new Test(setUp, async (context, assert) => {
      context.file('src', 'a.txt', 'aaa content');
      context.file('src', 'b.txt', 'bbb content');

      await context.repo.add('*');
      const status = await context.repo.status();

      assert.same(status.created, ['src/a.txt', 'src/b.txt']);
      assert.same(status.files.length, 2);

   }),

};
<|endoftext|>


<commit_before>import assert from 'assert';
import * as diff from '../../lib/index';
import validateMemory from '../util/validate-memory';

describe('Integration: Basics', function() {
  beforeEach(function() {
    this.fixture = document.createElement('div');
    this.fixture.innerHTML = '

';
  });

  afterEach(function() {
    diff.release(undefined);
    diff.release(this.fixture);
    diff.removeTransitionState();

    validateMemory();
  });

  describe('Expose API', function() {
    it('will expose the diffhtml global', function() {
      assert.equal(typeof diff, 'object');
    });

    it('will use the last core version loaded', async function() {
      delete global[Symbol.for('diffHTML')];
      const testBinding = { VERSION: 'test' };
      global[Symbol.for('diffHTML')] = testBinding;
      const { default: api } = await import('../../lib/index?' + Date.now());

      assert.strictEqual(global[Symbol.for('diffHTML')], api);
    });

    it('will use the last lite version loaded', async function() {
      delete global[Symbol.for('diffHTML')];
      const testBinding = { VERSION: 'test' };
      global[Symbol.for('diffHTML')] = testBinding;
      const { default: api } = await import('../../lib/lite?' + Date.now());

      assert.strictEqual(global[Symbol.for('diffHTML')], api);
    });
  });

  describe('Call API', function() {
    it('will error if element is missing', function() {
      assert.throws(function() {
        /** @type {any} */ (diff).innerHTML();
      });

      assert.throws(function() {
        /** @type {any} */ (diff).outerHTML();
      });
    });

    it('will not error if markup is missing', function() {
      var test = this;

      assert.doesNotThrow(function() {
        diff.outerHTML(test.fixture, '');
      });

      assert.doesNotThrow(function() {
        diff.innerHTML(test.fixture, '');
      });
    });

    it('will not error if options are missing', function() {
      var test = this;

      assert.doesNotThrow(function() {
        diff.outerHTML(test.fixture, '

');
      });

      assert.doesNotThrow(function() {
        diff.innerHTML(test.fixture, '

');
      });
    });
  });

  describe('Properties and Attributes Handling', () => {
    it('can "spread" inline objects into empty trees', function() {
      const vTree = diff.html`

      `;

      assert.equal(vTree.childNodes[1].attributes.a, 1);
      assert.equal(vTree.childNodes[1].attributes.b, false);
    });

    it('can "spread" inline objects into attributes', function() {
      const vTree = diff.html`

      `;

      assert.equal(vTree.childNodes[1].attributes.class, 'test');
      assert.equal(vTree.childNodes[1].attributes.a, 1);
      assert.equal(vTree.childNodes[1].attributes.b, false);
      assert.equal(vTree.childNodes[1].attributes.id, 'example');
    });

    it('can use a dynamic tag name', function() {
      const tagName = 'div';
      const vTree = diff.html`
        <${tagName}
          class="test"
        >

        </${tagName}>
      `;

      assert.equal(vTree.childNodes[1].nodeName, 'div');
      assert.equal(vTree.childNodes[1].attributes.class, 'test');
      assert.equal(vTree.childNodes[1].childNodes[1].nodeName, 'span');
    });

    it('can "spread" objects into attributes', function() {
      const obj = { a: 1, b: false };
      const vTree = diff.html`

      `;

      assert.equal(vTree.childNodes[1].attributes.class, 'test');
      assert.equal(vTree.childNodes[1].attributes.a, 1);
      assert.equal(vTree.childNodes[1].attributes.b, false);
      assert.equal(vTree.childNodes[1].attributes.id, 'example');
    });

    it('will silently ignore arrays that are attempted to be spread in production', function() {
      process.env.NODE_ENV = 'production';

      const obj = [1, false];
      const vTree = diff.html`

      `;

      process.env.NODE_ENV = 'development';

      assert.deepEqual(vTree.childNodes[1].attributes, {
        class: 'test',
        id: 'example',
      });
    });

    it('will error if arrays are attempted to be spread in strict mode', function() {
      const obj = [1, false];

      assert.throws(() => diff.html.strict`

      `, /Arrays cannot be spread as attributes/);

      diff.Internals.memory.gc();
    });

    it('will support safely removing properties with delete disabled', function() {
      const element = new Proxy(document.createElement('div'), {
        deleteProperty() {
          throw new Error('Should not cause uncaught failure');
        }
      });

      assert.doesNotThrow(() => {
        diff.outerHTML(element, diff.html`<div of="true" />`);
        diff.outerHTML(element, diff.html`<div />`);
        diff.release(element);
      });
    });
  });

  describe('Special features', function() {
    it('can modify the document\'s title', function() {
      var doc = document.implementation.createHTMLDocument('');

      doc.open();
      doc.write('<title></title>');

      var documentElement = doc.documentElement;
      diff.outerHTML(documentElement, '<title>Test</title>');

      assert.equal(doc.title, 'Test');

      diff.release(documentElement);
      doc.close();
    });
  });

  describe('DocumentFragment', function() {
    it('can diff elements into a fragment', function() {
      var fragment = document.createDocumentFragment();

      diff.innerHTML(fragment, `

Supports DocumentFragments

      `);

      assert.equal(fragment.childNodes[1].nodeName.toLowerCase(), 'p');
      assert.equal(fragment.childNodes[1].childNodes[0].nodeValue, 'Supports DocumentFragments');

      diff.release(fragment);
    });

    // Temporarily removed this function, saving this test until a suitable
    // replacement is created. This test will be migrated then.
    it('can diff a fragment into an element', function() {
      var fragment = document.createDocumentFragment();

      diff.innerHTML(fragment, `

It works

      `);

      diff.innerHTML(this.fixture, fragment);

      assert.equal(this.fixture.childNodes[1].nodeName.toLowerCase(), 'h1');
      assert.equal(this.fixture.childNodes[1].childNodes[0].nodeValue, 'It works');

      diff.release(fragment);
    });
  });

  describe('Custom elements', function() {
    it('supports the use of custom elements', function() {
      diff.innerHTML(this.fixture, '<custom-element></custom-element>');

      assert.ok(this.fixture.querySelector('custom-element'));
    });
  });
});
<commit_msg>Add test for disabling mutation observer<commit_after>import assert from 'assert';
import * as Sinon from 'sinon';
import * as diff from '../../lib/index';
import validateMemory from '../util/validate-memory';

// To appease nodejs
const { spy, SinonSpy } = Sinon.default;

describe('Integration: Basics', function() {
  beforeEach(function() {
    this.fixture = document.createElement('div');
    this.fixture.innerHTML = '

';
  });

  afterEach(function() {
    diff.release(undefined);
    diff.release(this.fixture);
    diff.removeTransitionState();

    validateMemory();
  });

  describe('Expose API', function() {
    it('will expose the diffhtml global', function() {
      assert.equal(typeof diff, 'object');
    });

    it('will use the last core version loaded', async function() {
      delete global[Symbol.for('diffHTML')];
      const testBinding = { VERSION: 'test' };
      global[Symbol.for('diffHTML')] = testBinding;
      const { default: api } = await import('../../lib/index?' + Date.now());

      assert.strictEqual(global[Symbol.for('diffHTML')], api);
    });

    it('will use the last lite version loaded', async function() {
      delete global[Symbol.for('diffHTML')];
      const testBinding = { VERSION: 'test' };
      global[Symbol.for('diffHTML')] = testBinding;
      const { default: api } = await import('../../lib/lite?' + Date.now());

      assert.strictEqual(global[Symbol.for('diffHTML')], api);
    });

    it('will support disabling MutationObserver', async function() {
      const oldMutationObserver = global.window.MutationObserver;
      global.window.MutationObserver = spy(oldMutationObserver);
      const { innerHTML } = await import('../../lib/index?' + Date.now());

      innerHTML(this.fixture, 'Hello world', { disableMutationObserver: true });

      assert.strictEqual(/** @type {SinonSpy} */(global.window.MutationObserver).called, false);
      global.window.MutationObserver = oldMutationObserver;
    });
  });

  describe('Call API', function() {
    it('will error if element is missing', function() {
      assert.throws(function() {
        /** @type {any} */ (diff).innerHTML();
      });

      assert.throws(function() {
        /** @type {any} */ (diff).outerHTML();
      });
    });

    it('will not error if markup is missing', function() {
      var test = this;

      assert.doesNotThrow(function() {
        diff.outerHTML(test.fixture, '');
      });

      assert.doesNotThrow(function() {
        diff.innerHTML(test.fixture, '');
      });
    });

    it('will not error if options are missing', function() {
      var test = this;

      assert.doesNotThrow(function() {
        diff.outerHTML(test.fixture, '

');
      });

      assert.doesNotThrow(function() {
        diff.innerHTML(test.fixture, '

');
      });
    });
  });

  describe('Properties and Attributes Handling', () => {
    it('can "spread" inline objects into empty trees', function() {
      const vTree = diff.html`

      `;

      assert.equal(vTree.childNodes[1].attributes.a, 1);
      assert.equal(vTree.childNodes[1].attributes.b, false);
    });

    it('can "spread" inline objects into attributes', function() {
      const vTree = diff.html`

      `;

      assert.equal(vTree.childNodes[1].attributes.class, 'test');
      assert.equal(vTree.childNodes[1].attributes.a, 1);
      assert.equal(vTree.childNodes[1].attributes.b, false);
      assert.equal(vTree.childNodes[1].attributes.id, 'example');
    });

    it('can use a dynamic tag name', function() {
      const tagName = 'div';
      const vTree = diff.html`
        <${tagName}
          class="test"
        >

        </${tagName}>
      `;

      assert.equal(vTree.childNodes[1].nodeName, 'div');
      assert.equal(vTree.childNodes[1].attributes.class, 'test');
      assert.equal(vTree.childNodes[1].childNodes[1].nodeName, 'span');
    });

    it('can "spread" objects into attributes', function() {
      const obj = { a: 1, b: false };
      const vTree = diff.html`

      `;

      assert.equal(vTree.childNodes[1].attributes.class, 'test');
      assert.equal(vTree.childNodes[1].attributes.a, 1);
      assert.equal(vTree.childNodes[1].attributes.b, false);
      assert.equal(vTree.childNodes[1].attributes.id, 'example');
    });

    it('will silently ignore arrays that are attempted to be spread in production', function() {
      process.env.NODE_ENV = 'production';

      const obj = [1, false];
      const vTree = diff.html`

      `;

      process.env.NODE_ENV = 'development';

      assert.deepEqual(vTree.childNodes[1].attributes, {
        class: 'test',
        id: 'example',
      });
    });

    it('will error if arrays are attempted to be spread in strict mode', function() {
      const obj = [1, false];

      assert.throws(() => diff.html.strict`

      `, /Arrays cannot be spread as attributes/);

      diff.Internals.memory.gc();
    });

    it('will support safely removing properties with delete disabled', function() {
      const element = new Proxy(document.createElement('div'), {
        deleteProperty() {
          throw new Error('Should not cause uncaught failure');
        }
      });

      assert.doesNotThrow(() => {
        diff.outerHTML(element, diff.html`<div of="true" />`);
        diff.outerHTML(element, diff.html`<div />`);
        diff.release(element);
      });
    });
  });

  describe('Special features', function() {
    it('can modify the document\'s title', function() {
      var doc = document.implementation.createHTMLDocument('');

      doc.open();
      doc.write('<title></title>');

      var documentElement = doc.documentElement;
      diff.outerHTML(documentElement, '<title>Test</title>');

      assert.equal(doc.title, 'Test');

      diff.release(documentElement);
      doc.close();
    });
  });

  describe('DocumentFragment', function() {
    it('can diff elements into a fragment', function() {
      var fragment = document.createDocumentFragment();

      diff.innerHTML(fragment, `

Supports DocumentFragments

      `);

      assert.equal(fragment.childNodes[1].nodeName.toLowerCase(), 'p');
      assert.equal(fragment.childNodes[1].childNodes[0].nodeValue, 'Supports DocumentFragments');

      diff.release(fragment);
    });

    // Temporarily removed this function, saving this test until a suitable
    // replacement is created. This test will be migrated then.
    it('can diff a fragment into an element', function() {
      var fragment = document.createDocumentFragment();

      diff.innerHTML(fragment, `

It works

      `);

      diff.innerHTML(this.fixture, fragment);

      assert.equal(this.fixture.childNodes[1].nodeName.toLowerCase(), 'h1');
      assert.equal(this.fixture.childNodes[1].childNodes[0].nodeValue, 'It works');

      diff.release(fragment);
    });
  });

  describe('Custom elements', function() {
    it('supports the use of custom elements', function() {
      diff.innerHTML(this.fixture, '<custom-element></custom-element>');

      assert.ok(this.fixture.querySelector('custom-element'));
    });
  });
});
<|endoftext|>


<commit_before><commit_msg>Add bootstrap css<commit_after><|endoftext|>


<commit_before>/**
@module ember
@submodule ember-routing
*/

require('ember-handlebars/ext');
require('ember-handlebars/helpers/view');

Ember.onLoad('Ember.Handlebars', function(Handlebars) {

  var resolveParams = Ember.Router.resolveParams,
      isSimpleClick = Ember.ViewUtils.isSimpleClick;

  var EmberHandlebars = Ember.Handlebars,
      handlebarsGet = EmberHandlebars.get,
      SafeString = EmberHandlebars.SafeString,
      forEach = Ember.ArrayPolyfills.forEach,
      get = Ember.get,
      a_slice = Array.prototype.slice;

  function args(options, actionName) {
    var ret = [];
    if (actionName) { ret.push(actionName); }

    var types = options.options.types.slice(1),
        data = options.options.data;

    return ret.concat(resolveParams(options.context, options.params, { types: types, data: data }));
  }

  var ActionHelper = EmberHandlebars.ActionHelper = {
    registeredActions: {}
  };

  var keys = ["alt", "shift", "meta", "ctrl"];

  var isAllowedClick = function(event, allowedKeys) {
    if (typeof allowedKeys === "undefined") {
      return isSimpleClick(event);
    }

    if (allowedKeys.indexOf("any") >= 0) {
      return true;
    }

    var allowed = true;

    forEach.call(keys, function(key) {
      if (event[key + "Key"] && allowedKeys.indexOf(key) === -1) {
        allowed = false;
      }
    });

    return allowed;
  };

  ActionHelper.registerAction = function(actionName, options, allowedKeys) {
    var actionId = (++Ember.uuid).toString();

    ActionHelper.registeredActions[actionId] = {
      eventName: options.eventName,
      handler: function(event) {
        if (!isAllowedClick(event, allowedKeys)) { return true; }

        event.preventDefault();

        if (options.bubbles === false) {
          event.stopPropagation();
        }

        var target = options.target;

        if (target.target) {
          target = handlebarsGet(target.root, target.target, target.options);
        } else {
          target = target.root;
        }

        Ember.run(function() {
          if (target.send) {
            target.send.apply(target, args(options.parameters, actionName));
          } else {
            Ember.assert("The action '" + actionName + "' did not exist on " + target, typeof target[actionName] === 'function');
            target[actionName].apply(target, args(options.parameters));
          }
        });
      }
    };

    options.view.on('willClearRender', function() {
      delete ActionHelper.registeredActions[actionId];
    });

    return actionId;
  };

  /**
    The `{{action}}` helper registers an HTML element within a template for DOM
    event handling and forwards that interaction to the view's controller
    or supplied `target` option (see 'Specifying a Target').

    If the view's controller does not implement the event, the event is sent
    to the current route, and it bubbles up the route hierarchy from there.

    User interaction with that element will invoke the supplied action name on
    the appropriate target.

    Given the following Handlebars template on the page

    ```handlebars
    <div {{action 'anActionName'}}>
      click me
    </div>
    ```

    And application code

    ```javascript
    AController = Ember.Controller.extend({
      actions: {
        anActionName: function() {}
      }
    });

    AView = Ember.View.extend({
      controller: AController.create(),
      templateName: 'a-template'
    });

    aView = AView.create();
    aView.appendTo('body');
    ```

    Will result in the following rendered HTML

    ```html
    <div class="ember-view">
      <div data-ember-action="1">
        click me
      </div>
    </div>
    ```

    Clicking "click me" will trigger the `anActionName` method in the `actions
    hash of the `AController`. In this case, no additional parameters will be
    passed.

    If you provide additional parameters to the helper:

    ```handlebars
    <button {{action 'edit' post}}>Edit</button>
    ```

    Those parameters will be passed along as arguments to the JavaScript
    function implementing the action.

    ### Event Propagation

    Events triggered through the action helper will automatically have
    `.preventDefault()` called on them. You do not need to do so in your event
    handlers.

    To also disable bubbling, pass `bubbles=false` to the helper:

    ```handlebars
    <button {{action 'edit' post bubbles=false}}>Edit</button>
    ```

    If you need the default handler to trigger you should either register your
    own event handler, or use event methods on your view class. See [Ember.View](/api/classes/Ember.View.html)
    'Responding to Browser Events' for more information.

    ### Specifying DOM event type

    By default the `{{action}}` helper registers for DOM `click` events. You can
    supply an `on` option to the helper to specify a different DOM event name:

    ```handlebars
    <script type="text/x-handlebars" data-template-name='a-template'>
      <div {{action 'anActionName' on="doubleClick"}}>
        click me
      </div>
    </script>
    ```

    See `Ember.View` 'Responding to Browser Events' for a list of
    acceptable DOM event names.

    NOTE: Because `{{action}}` depends on Ember's event dispatch system it will
    only function if an `Ember.EventDispatcher` instance is available. An
    `Ember.EventDispatcher` instance will be created when a new `Ember.Application`
    is created. Having an instance of `Ember.Application` will satisfy this
    requirement.

    ### Specifying whitelisted modifier keys

    By default the `{{action}}` helper will ignore click event with pressed modifier
    keys. You can supply an `allowedKeys` option to specify which keys should not be ignored.

    ```handlebars
    <script type="text/x-handlebars" data-template-name='a-template'>
      <div {{action 'anActionName' allowedKeys="alt"}}>
        click me
      </div>
    </script>
    ```

    This way the `{{action}}` will fire when clicking with the alt key pressed down.

    Alternatively, supply "any" to the `allowedKeys` option to accept any combination of modifier keys.

    ```handlebars
    <script type="text/x-handlebars" data-template-name='a-template'>
      <div {{action 'anActionName' allowedKeys="any"}}>
        click me with any key pressed
      </div>
    </script>
    ```

    ### Specifying a Target

    There are several possible target objects for `{{action}}` helpers:

    In a typical Ember application, where views are managed through use of the
    `{{outlet}}` helper, actions will bubble to the current controller, then
    to the current route, and then up the route hierarchy.

    Alternatively, a `target` option can be provided to the helper to change
    which object will receive the method call. This option must be a path
    to an object, accessible in the current context:

    ```handlebars
    <script type="text/x-handlebars" data-template-name='a-template'>
      <div {{action 'anActionName' target="MyApplication.someObject"}}>
        click me
      </div>
    </script>
    ```

    Clicking "click me" in the rendered HTML of the above template will trigger
    the  `anActionName` method of the object at `MyApplication.someObject`.

    If an action's target does not implement a method that matches the supplied
    action name an error will be thrown.

    ```handlebars
    <script type="text/x-handlebars" data-template-name='a-template'>
      <div {{action 'aMethodNameThatIsMissing'}}>
        click me
      </div>
    </script>
    ```

    With the following application code

    ```javascript
    AView = Ember.View.extend({
      templateName; 'a-template',
      // note: no method 'aMethodNameThatIsMissing'
      anActionName: function(event) {}
    });

    aView = AView.create();
    aView.appendTo('body');
    ```

    Will throw `Uncaught TypeError: Cannot call method 'call' of undefined` when
    "click me" is clicked.

    ### Additional Parameters

    You may specify additional parameters to the `{{action}}` helper. These
    parameters are passed along as the arguments to the JavaScript function
    implementing the action.

    ```handlebars
    <script type="text/x-handlebars" data-template-name='a-template'>
      {{#each person in people}}
        <div {{action 'edit' person}}>
          click me
        </div>
      {{/each}}
    </script>
    ```

    Clicking "click me" will trigger the `edit` method on the current view's
    controller with the current person as a parameter.

    @method action
    @for Ember.Handlebars.helpers
    @param {String} actionName
    @param {Object} [context]*
    @param {Hash} options
  */
  EmberHandlebars.registerHelper('action', function(actionName) {
    var options = arguments[arguments.length - 1],
        contexts = a_slice.call(arguments, 1, -1);

    var hash = options.hash,
        controller;

    // create a hash to pass along to registerAction
    var action = {
      eventName: hash.on || "click"
    };

    action.parameters = {
      context: this,
      options: options,
      params: contexts
    };

    action.view = options.data.view;

    var root, target;

    if (hash.target) {
      root = this;
      target = hash.target;
    } else if (controller = options.data.keywords.controller) {
      root = controller;
    }

    action.target = { root: root, target: target, options: options };
    action.bubbles = hash.bubbles;

    var actionId = ActionHelper.registerAction(actionName, action, hash.allowedKeys);
    return new SafeString('data-ember-action="' + actionId + '"');
  });

});
<commit_msg>Improves {{action}} helper docs<commit_after>/**
@module ember
@submodule ember-routing
*/

require('ember-handlebars/ext');
require('ember-handlebars/helpers/view');

Ember.onLoad('Ember.Handlebars', function(Handlebars) {

  var resolveParams = Ember.Router.resolveParams,
      isSimpleClick = Ember.ViewUtils.isSimpleClick;

  var EmberHandlebars = Ember.Handlebars,
      handlebarsGet = EmberHandlebars.get,
      SafeString = EmberHandlebars.SafeString,
      forEach = Ember.ArrayPolyfills.forEach,
      get = Ember.get,
      a_slice = Array.prototype.slice;

  function args(options, actionName) {
    var ret = [];
    if (actionName) { ret.push(actionName); }

    var types = options.options.types.slice(1),
        data = options.options.data;

    return ret.concat(resolveParams(options.context, options.params, { types: types, data: data }));
  }

  var ActionHelper = EmberHandlebars.ActionHelper = {
    registeredActions: {}
  };

  var keys = ["alt", "shift", "meta", "ctrl"];

  var isAllowedClick = function(event, allowedKeys) {
    if (typeof allowedKeys === "undefined") {
      return isSimpleClick(event);
    }

    if (allowedKeys.indexOf("any") >= 0) {
      return true;
    }

    var allowed = true;

    forEach.call(keys, function(key) {
      if (event[key + "Key"] && allowedKeys.indexOf(key) === -1) {
        allowed = false;
      }
    });

    return allowed;
  };

  ActionHelper.registerAction = function(actionName, options, allowedKeys) {
    var actionId = (++Ember.uuid).toString();

    ActionHelper.registeredActions[actionId] = {
      eventName: options.eventName,
      handler: function(event) {
        if (!isAllowedClick(event, allowedKeys)) { return true; }

        event.preventDefault();

        if (options.bubbles === false) {
          event.stopPropagation();
        }

        var target = options.target;

        if (target.target) {
          target = handlebarsGet(target.root, target.target, target.options);
        } else {
          target = target.root;
        }

        Ember.run(function() {
          if (target.send) {
            target.send.apply(target, args(options.parameters, actionName));
          } else {
            Ember.assert("The action '" + actionName + "' did not exist on " + target, typeof target[actionName] === 'function');
            target[actionName].apply(target, args(options.parameters));
          }
        });
      }
    };

    options.view.on('willClearRender', function() {
      delete ActionHelper.registeredActions[actionId];
    });

    return actionId;
  };

  /**
    The `{{action}}` helper registers an HTML element within a template for DOM
    event handling and forwards that interaction to the templates's controller
    or supplied `target` option (see 'Specifying a Target').

    If the controller does not implement the event, the event is sent
    to the current route, and it bubbles up the route hierarchy from there.

    User interaction with that element will invoke the supplied action name on
    the appropriate target.

    Given the following application Handlebars template on the page

    ```handlebars
    <div {{action 'anActionName'}}>
      click me
    </div>
    ```

    And application code

    ```javascript
    App.ApplicationController = Ember.Controller.extend({
      actions: {
        anActionName: function() {

        }
      }
    });
    ```

    Will result in the following rendered HTML

    ```html
    <div class="ember-view">
      <div data-ember-action="1">
        click me
      </div>
    </div>
    ```

    Clicking "click me" will trigger the `anActionName` action of the
    `App.ApplicationController`. In this case, no additional parameters will be passed.

    If you provide additional parameters to the helper:

    ```handlebars
    <button {{action 'edit' post}}>Edit</button>
    ```

    Those parameters will be passed along as arguments to the JavaScript
    function implementing the action.

    ### Event Propagation

    Events triggered through the action helper will automatically have
    `.preventDefault()` called on them. You do not need to do so in your event
    handlers.

    To also disable bubbling, pass `bubbles=false` to the helper:

    ```handlebars
    <button {{action 'edit' post bubbles=false}}>Edit</button>
    ```

    If you need the default handler to trigger you should either register your
    own event handler, or use event methods on your view class. See [Ember.View](/api/classes/Ember.View.html)
    'Responding to Browser Events' for more information.

    ### Specifying DOM event type

    By default the `{{action}}` helper registers for DOM `click` events. You can
    supply an `on` option to the helper to specify a different DOM event name:

    ```handlebars
    <div {{action "anActionName" on="doubleClick"}}>
      click me
    </div>
    ```

    See `Ember.View` 'Responding to Browser Events' for a list of
    acceptable DOM event names.

    NOTE: Because `{{action}}` depends on Ember's event dispatch system it will
    only function if an `Ember.EventDispatcher` instance is available. An
    `Ember.EventDispatcher` instance will be created when a new `Ember.Application`
    is created. Having an instance of `Ember.Application` will satisfy this
    requirement.

    ### Specifying whitelisted modifier keys

    By default the `{{action}}` helper will ignore click event with pressed modifier
    keys. You can supply an `allowedKeys` option to specify which keys should not be ignored.

    ```handlebars
    <div {{action "anActionName" allowedKeys="alt"}}>
      click me
    </div>
    ```

    This way the `{{action}}` will fire when clicking with the alt key pressed down.

    Alternatively, supply "any" to the `allowedKeys` option to accept any combination of modifier keys.

    ```handlebars
    <div {{action "anActionName" allowedKeys="any"}}>
      click me with any key pressed
    </div>
    ```

    ### Specifying a Target

    There are several possible target objects for `{{action}}` helpers:

    In a typical Ember application, where views are managed through use of the
    `{{outlet}}` helper, actions will bubble to the current controller, then
    to the current route, and then up the route hierarchy.

    Alternatively, a `target` option can be provided to the helper to change
    which object will receive the method call. This option must be a path
    to an object, accessible in the current context:

    ```handlebars
    {{! the application template }}
    <div {{action "anActionName" target=view}}>
      click me
    </div>
    ```

    ```javascript
    App.ApplicationView = Ember.View.extend({
      actions: {
        anActionName: function(){}
      }
    });

    ```

    ### Additional Parameters

    You may specify additional parameters to the `{{action}}` helper. These
    parameters are passed along as the arguments to the JavaScript function
    implementing the action.

    ```handlebars
    {{#each person in people}}
      <div {{action "edit" person}}>
        click me
      </div>
    {{/each}}
    ```

    Clicking "click me" will trigger the `edit` method on the current controller
    with the value of `person` as a parameter.

    @method action
    @for Ember.Handlebars.helpers
    @param {String} actionName
    @param {Object} [context]*
    @param {Hash} options
  */
  EmberHandlebars.registerHelper('action', function(actionName) {
    var options = arguments[arguments.length - 1],
        contexts = a_slice.call(arguments, 1, -1);

    var hash = options.hash,
        controller;

    // create a hash to pass along to registerAction
    var action = {
      eventName: hash.on || "click"
    };

    action.parameters = {
      context: this,
      options: options,
      params: contexts
    };

    action.view = options.data.view;

    var root, target;

    if (hash.target) {
      root = this;
      target = hash.target;
    } else if (controller = options.data.keywords.controller) {
      root = controller;
    }

    action.target = { root: root, target: target, options: options };
    action.bubbles = hash.bubbles;

    var actionId = ActionHelper.registerAction(actionName, action, hash.allowedKeys);
    return new SafeString('data-ember-action="' + actionId + '"');
  });

});
<|endoftext|>


<commit_before>var Router, App, AppView, templates, router, eventDispatcher, container;
var get = Ember.get, set = Ember.set;

function bootApplication() {
  router = container.lookup('router:main');
  Ember.run(App, 'advanceReadiness');
}

// IE includes the host name
function normalizeUrl(url) {
  return url.replace(/https?:\/\/[^\/]+/,'');
}

function compile(template) {
  return Ember.Handlebars.compile(template);
}

module("The {{linkTo}} helper", {
  setup: function() {
    Ember.run(function() {
      App = Ember.Application.create({
        name: "App",
        rootElement: '#qunit-fixture'
      });

      App.deferReadiness();

      App.Router.reopen({
        location: 'none'
      });

      Router = App.Router;

      Ember.TEMPLATES.app = Ember.Handlebars.compile("{{outlet}}");
      Ember.TEMPLATES.index = Ember.Handlebars.compile("
Home
{{#linkTo about id='about-link'}}About{{/linkTo}}{{#linkTo index id='self-link'}}Self{{/linkTo}}");
      Ember.TEMPLATES.about = Ember.Handlebars.compile("
About
{{#linkTo index id='home-link'}}Home{{/linkTo}}{{#linkTo about id='self-link'}}Self{{/linkTo}}");
      Ember.TEMPLATES.item = Ember.Handlebars.compile("
Item

{{name}}
{{#linkTo index id='home-link'}}Home{{/linkTo}}");

      AppView = Ember.View.extend({
        templateName: 'app'
      });

      container = App.__container__;

      container.register('view', 'app');
      container.register('router', 'main', Router);

      App.initialize();
    });
  },

  teardown: function() {
    Ember.run(function() { App.destroy(); });
  }
});

test("The {{linkTo}} helper moves into the named route", function() {
  Router.map(function(match) {
    this.route("about");
  });

  bootApplication();

  Ember.run(function() {
    router.handleURL("/");
  });

  equal(Ember.$('h3:contains(Home)', '#qunit-fixture').length, 1, "The home template was rendered");
  equal(Ember.$('#self-link.active', '#qunit-fixture').length, 1, "The self-link was rendered with active class");
  equal(Ember.$('#about-link:not(.active)', '#qunit-fixture').length, 1, "The other link was rendered without active class");

  Ember.run(function() {
    Ember.$('#about-link', '#qunit-fixture').click();
  });

  equal(Ember.$('h3:contains(About)', '#qunit-fixture').length, 1, "The about template was rendered");
  equal(Ember.$('#self-link.active', '#qunit-fixture').length, 1, "The self-link was rendered with active class");
  equal(Ember.$('#home-link:not(.active)', '#qunit-fixture').length, 1, "The other link was rendered without active class");
});

test("The {{linkTo}} helper supports URL replacement", function() {
  var setCount = 0,
      replaceCount = 0;

  Ember.TEMPLATES.index = Ember.Handlebars.compile("
Home
{{#linkTo about id='about-link' replace=true}}About{{/linkTo}}");

  Router.reopen({
    location: Ember.NoneLocation.createWithMixins({
      setURL: function(path) {
        setCount++;
        set(this, 'path', path);
      },

      replaceURL: function(path) {
        replaceCount++;
        set(this, 'path', path);
      }
    })
  });

  Router.map(function() {
    this.route("about");
  });

  bootApplication();

  Ember.run(function() {
    router.handleURL("/");
  });

  equal(setCount, 0, 'precond: setURL has not been called');
  equal(replaceCount, 0, 'precond: replaceURL has not been called');

  Ember.run(function() {
    Ember.$('#about-link', '#qunit-fixture').click();
  });

  equal(setCount, 0, 'setURL should not be called');
  equal(replaceCount, 1, 'replaceURL should be called once');
});

test("The {{linkTo}} helper supports a custom activeClass", function() {
  Ember.TEMPLATES.index = Ember.Handlebars.compile("
Home
{{#linkTo about id='about-link'}}About{{/linkTo}}{{#linkTo index id='self-link' activeClass='zomg-active'}}Self{{/linkTo}}");

  Router.map(function() {
    this.route("about");
  });

  bootApplication();

  Ember.run(function() {
    router.handleURL("/");
  });

  equal(Ember.$('h3:contains(Home)', '#qunit-fixture').length, 1, "The home template was rendered");
  equal(Ember.$('#self-link.zomg-active', '#qunit-fixture').length, 1, "The self-link was rendered with active class");
  equal(Ember.$('#about-link:not(.active)', '#qunit-fixture').length, 1, "The other link was rendered without active class");
});

test("The {{linkTo}} helper supports leaving off .index for nested routes", function() {
  Router.map(function() {
    this.resource("about", function() {
      this.route("item");
    });
  });

  Ember.TEMPLATES.about = compile("
About
{{outlet}}");
  Ember.TEMPLATES['about/index'] = compile("
Index
");
  Ember.TEMPLATES['about/item'] = compile("
{{#linkTo 'about'}}About{{/linkTo}}
");

  bootApplication();

  Ember.run(function() {
    router.handleURL("/about/item");
  });

  equal(Ember.$('#item a', '#qunit-fixture').attr('href'), '/about');
});

test("The {{linkTo}} helper supports custom, nested, currentWhen", function() {
  Router.map(function(match) {
    this.resource("index", { path: "/" }, function() {
      this.route("about");
    });

    this.route("item");
  });

  Ember.TEMPLATES.index = Ember.Handlebars.compile("
Home
{{outlet}}");
  Ember.TEMPLATES['index/about'] = Ember.Handlebars.compile("{{#linkTo item id='other-link' currentWhen='index'}}ITEM{{/linkTo}}");

  bootApplication();

  Ember.run(function() {
    router.handleURL("/about");
  });

  equal(Ember.$('#other-link.active', '#qunit-fixture').length, 1, "The link is active since currentWhen is a parent route");
});

test("The {{linkTo}} helper defaults to bubbling", function() {
  Ember.TEMPLATES.about = Ember.Handlebars.compile("<button {{action 'hide'}}>{{#linkTo 'about.contact' id='about-contact'}}About{{/linkTo}}</button>{{outlet}}");
  Ember.TEMPLATES['about/contact'] = Ember.Handlebars.compile("
Contact
");

  Router.map(function() {
    this.resource("about", function() {
      this.route("contact");
    });
  });

  var hidden = 0;

  App.AboutRoute = Ember.Route.extend({
    events: {
      hide: function() {
        hidden++;
      }
    }
  });

  bootApplication();

  Ember.run(function() {
    router.handleURL("/about");
  });

  Ember.run(function() {
    Ember.$('#about-contact', '#qunit-fixture').click();
  });

  equal(Ember.$("#contact", "#qunit-fixture").text(), "Contact", "precond - the link worked");

  equal(hidden, 1, "The link bubbles");
});

test("The {{linkTo}} helper supports bubbles=false", function() {
  Ember.TEMPLATES.about = Ember.Handlebars.compile("<button {{action 'hide'}}>{{#linkTo 'about.contact' id='about-contact' bubbles=false}}About{{/linkTo}}</button>{{outlet}}");
  Ember.TEMPLATES['about/contact'] = Ember.Handlebars.compile("
Contact
");

  Router.map(function() {
    this.resource("about", function() {
      this.route("contact");
    });
  });

  var hidden = 0;

  App.AboutRoute = Ember.Route.extend({
    events: {
      hide: function() {
        hidden++;
      }
    }
  });

  bootApplication();

  Ember.run(function() {
    router.handleURL("/about");
  });

  Ember.run(function() {
    Ember.$('#about-contact', '#qunit-fixture').click();
  });

  equal(Ember.$("#contact", "#qunit-fixture").text(), "Contact", "precond - the link worked");

  equal(hidden, 0, "The link didn't bubble");
});

test("The {{linkTo}} helper moves into the named route with context", function() {
  Router.map(function(match) {
    this.route("about");
    this.resource("item", { path: "/item/:id" });
  });

  Ember.TEMPLATES.about = Ember.Handlebars.compile("
List

{{#each controller}}
{{#linkTo item this}}{{name}}{{/linkTo}}
{{/each}}
{{#linkTo index id='home-link'}}Home{{/linkTo}}");

  var people = {
    yehuda: "Yehuda Katz",
    tom: "Tom Dale",
    erik: "Erik Brynroflsson"
  };

  App.AboutRoute = Ember.Route.extend({
    model: function() {
      return Ember.A([
        { id: "yehuda", name: "Yehuda Katz" },
        { id: "tom", name: "Tom Dale" },
        { id: "erik", name: "Erik Brynroflsson" }
      ]);
    }
  });

  App.ItemRoute = Ember.Route.extend({
    serialize: function(object) {
      return { id: object.id };
    },

    deserialize: function(params) {
      return { id: params.id, name: people[params.id] };
    }
  });

  bootApplication();

  Ember.run(function() {
    router.handleURL("/about");
  });

  equal(Ember.$('h3:contains(List)', '#qunit-fixture').length, 1, "The home template was rendered");
  equal(normalizeUrl(Ember.$('#home-link').attr('href')), '/', "The home link points back at /");

  Ember.run(function() {
    Ember.$('li a:contains(Yehuda)', '#qunit-fixture').click();
  });

  equal(Ember.$('h3:contains(Item)', '#qunit-fixture').length, 1, "The item template was rendered");
  equal(Ember.$('p', '#qunit-fixture').text(), "Yehuda Katz", "The name is correct");

  Ember.run(function() { Ember.$('#home-link').click(); });
  Ember.run(function() { Ember.$('#about-link').click(); });

  equal(normalizeUrl(Ember.$('li a:contains(Yehuda)').attr('href')), "/item/yehuda");
  equal(normalizeUrl(Ember.$('li a:contains(Tom)').attr('href')), "/item/tom");
  equal(normalizeUrl(Ember.$('li a:contains(Erik)').attr('href')), "/item/erik");

  Ember.run(function() {
    Ember.$('li a:contains(Erik)', '#qunit-fixture').click();
  });

  equal(Ember.$('h3:contains(Item)', '#qunit-fixture').length, 1, "The item template was rendered");
  equal(Ember.$('p', '#qunit-fixture').text(), "Erik Brynroflsson", "The name is correct");
});

test("The {{linkTo}} helper binds some anchor html tag common attributes", function() {
  Ember.TEMPLATES.index = Ember.Handlebars.compile("
Home
{{#linkTo index id='self-link' title='title-attr'}}Self{{/linkTo}}");
  bootApplication();

  Ember.run(function() {
    router.handleURL("/");
  });

  equal(Ember.$('#self-link', '#qunit-fixture').attr('title'), 'title-attr', "The self-link contains title attribute");
});

test("The {{linkTo}} helper accepts string arguments", function() {
  Router.map(function() {
    this.route('filter', { path: '/filters/:filter' });
  });

  Ember.TEMPLATES.filter = compile('
{{filter}}
{{#linkTo filter "unpopular" id="link"}}Unpopular{{/linkTo}}');
  Ember.TEMPLATES.index = compile('');

  bootApplication();

  Ember.run(function() { router.handleURL("/filters/popular"); });

  equal(Ember.$('#link', '#qunit-fixture').attr('href'), "/filters/unpopular");
});

test("The {{linkTo}} helper unwraps controllers", function() {
  // The serialize hook is called twice: once to generate the href for the
  // link and once to generate the URL when the link is clicked.
  expect(2);

  Router.map(function() {
    this.route('filter', { path: '/filters/:filter' });
  });

  var indexObject = { filter: 'popular' };

  App.FilterRoute = Ember.Route.extend({
    model: function(params) {
      return indexObject;
    },

    serialize: function(passedObject) {
      equal(passedObject, indexObject, "The unwrapped object is passed");
      return { filter: 'popular' };
    }
  });

  App.IndexRoute = Ember.Route.extend({
    model: function() {
      return indexObject;
    }
  });

  Ember.TEMPLATES.filter = compile('
{{filter}}
');
  Ember.TEMPLATES.index = compile('{{#linkTo filter this id="link"}}Filter{{/linkTo}}');

  bootApplication();

  Ember.run(function() { router.handleURL("/"); });

  Ember.$('#link', '#qunit-fixture').trigger('click');
});

test("The {{linkTo}} helper doesn't change view context", function() {
  App.IndexView = Ember.View.extend({
    elementId: 'index',
    name: 'test'
  });

  Ember.TEMPLATES.index = Ember.Handlebars.compile("{{view.name}}-{{#linkTo index id='self-link'}}Link: {{view.name}}{{/linkTo}}");

  bootApplication();

  Ember.run(function() {
    router.handleURL("/");
  });

  equal(Ember.$('#index', '#qunit-fixture').text(), 'test-Link: test', "accesses correct view");
});
<commit_msg>Fix two linkTo unit tests that fail in IE9.  Tests used an  tag inside of a <button> tag, which IE9 does not like but works in other browsers.  Example: http://jsbin.com/ozemig/1/edit<commit_after>var Router, App, AppView, templates, router, eventDispatcher, container;
var get = Ember.get, set = Ember.set;

function bootApplication() {
  router = container.lookup('router:main');
  Ember.run(App, 'advanceReadiness');
}

// IE includes the host name
function normalizeUrl(url) {
  return url.replace(/https?:\/\/[^\/]+/,'');
}

function compile(template) {
  return Ember.Handlebars.compile(template);
}

module("The {{linkTo}} helper", {
  setup: function() {
    Ember.run(function() {
      App = Ember.Application.create({
        name: "App",
        rootElement: '#qunit-fixture'
      });

      App.deferReadiness();

      App.Router.reopen({
        location: 'none'
      });

      Router = App.Router;

      Ember.TEMPLATES.app = Ember.Handlebars.compile("{{outlet}}");
      Ember.TEMPLATES.index = Ember.Handlebars.compile("
Home
{{#linkTo about id='about-link'}}About{{/linkTo}}{{#linkTo index id='self-link'}}Self{{/linkTo}}");
      Ember.TEMPLATES.about = Ember.Handlebars.compile("
About
{{#linkTo index id='home-link'}}Home{{/linkTo}}{{#linkTo about id='self-link'}}Self{{/linkTo}}");
      Ember.TEMPLATES.item = Ember.Handlebars.compile("
Item

{{name}}
{{#linkTo index id='home-link'}}Home{{/linkTo}}");

      AppView = Ember.View.extend({
        templateName: 'app'
      });

      container = App.__container__;

      container.register('view', 'app');
      container.register('router', 'main', Router);

      App.initialize();
    });
  },

  teardown: function() {
    Ember.run(function() { App.destroy(); });
  }
});

test("The {{linkTo}} helper moves into the named route", function() {
  Router.map(function(match) {
    this.route("about");
  });

  bootApplication();

  Ember.run(function() {
    router.handleURL("/");
  });

  equal(Ember.$('h3:contains(Home)', '#qunit-fixture').length, 1, "The home template was rendered");
  equal(Ember.$('#self-link.active', '#qunit-fixture').length, 1, "The self-link was rendered with active class");
  equal(Ember.$('#about-link:not(.active)', '#qunit-fixture').length, 1, "The other link was rendered without active class");

  Ember.run(function() {
    Ember.$('#about-link', '#qunit-fixture').click();
  });

  equal(Ember.$('h3:contains(About)', '#qunit-fixture').length, 1, "The about template was rendered");
  equal(Ember.$('#self-link.active', '#qunit-fixture').length, 1, "The self-link was rendered with active class");
  equal(Ember.$('#home-link:not(.active)', '#qunit-fixture').length, 1, "The other link was rendered without active class");
});

test("The {{linkTo}} helper supports URL replacement", function() {
  var setCount = 0,
      replaceCount = 0;

  Ember.TEMPLATES.index = Ember.Handlebars.compile("
Home
{{#linkTo about id='about-link' replace=true}}About{{/linkTo}}");

  Router.reopen({
    location: Ember.NoneLocation.createWithMixins({
      setURL: function(path) {
        setCount++;
        set(this, 'path', path);
      },

      replaceURL: function(path) {
        replaceCount++;
        set(this, 'path', path);
      }
    })
  });

  Router.map(function() {
    this.route("about");
  });

  bootApplication();

  Ember.run(function() {
    router.handleURL("/");
  });

  equal(setCount, 0, 'precond: setURL has not been called');
  equal(replaceCount, 0, 'precond: replaceURL has not been called');

  Ember.run(function() {
    Ember.$('#about-link', '#qunit-fixture').click();
  });

  equal(setCount, 0, 'setURL should not be called');
  equal(replaceCount, 1, 'replaceURL should be called once');
});

test("The {{linkTo}} helper supports a custom activeClass", function() {
  Ember.TEMPLATES.index = Ember.Handlebars.compile("
Home
{{#linkTo about id='about-link'}}About{{/linkTo}}{{#linkTo index id='self-link' activeClass='zomg-active'}}Self{{/linkTo}}");

  Router.map(function() {
    this.route("about");
  });

  bootApplication();

  Ember.run(function() {
    router.handleURL("/");
  });

  equal(Ember.$('h3:contains(Home)', '#qunit-fixture').length, 1, "The home template was rendered");
  equal(Ember.$('#self-link.zomg-active', '#qunit-fixture').length, 1, "The self-link was rendered with active class");
  equal(Ember.$('#about-link:not(.active)', '#qunit-fixture').length, 1, "The other link was rendered without active class");
});

test("The {{linkTo}} helper supports leaving off .index for nested routes", function() {
  Router.map(function() {
    this.resource("about", function() {
      this.route("item");
    });
  });

  Ember.TEMPLATES.about = compile("
About
{{outlet}}");
  Ember.TEMPLATES['about/index'] = compile("
Index
");
  Ember.TEMPLATES['about/item'] = compile("
{{#linkTo 'about'}}About{{/linkTo}}
");

  bootApplication();

  Ember.run(function() {
    router.handleURL("/about/item");
  });

  equal(Ember.$('#item a', '#qunit-fixture').attr('href'), '/about');
});

test("The {{linkTo}} helper supports custom, nested, currentWhen", function() {
  Router.map(function(match) {
    this.resource("index", { path: "/" }, function() {
      this.route("about");
    });

    this.route("item");
  });

  Ember.TEMPLATES.index = Ember.Handlebars.compile("
Home
{{outlet}}");
  Ember.TEMPLATES['index/about'] = Ember.Handlebars.compile("{{#linkTo item id='other-link' currentWhen='index'}}ITEM{{/linkTo}}");

  bootApplication();

  Ember.run(function() {
    router.handleURL("/about");
  });

  equal(Ember.$('#other-link.active', '#qunit-fixture').length, 1, "The link is active since currentWhen is a parent route");
});

test("The {{linkTo}} helper defaults to bubbling", function() {
  Ember.TEMPLATES.about = Ember.Handlebars.compile("
{{#linkTo 'about.contact' id='about-contact'}}About{{/linkTo}}
{{outlet}}");
  Ember.TEMPLATES['about/contact'] = Ember.Handlebars.compile("
Contact
");

  Router.map(function() {
    this.resource("about", function() {
      this.route("contact");
    });
  });

  var hidden = 0;

  App.AboutRoute = Ember.Route.extend({
    events: {
      hide: function() {
        hidden++;
      }
    }
  });

  bootApplication();

  Ember.run(function() {
    router.handleURL("/about");
  });

  Ember.run(function() {
    Ember.$('#about-contact', '#qunit-fixture').click();
  });

  equal(Ember.$("#contact", "#qunit-fixture").text(), "Contact", "precond - the link worked");

  equal(hidden, 1, "The link bubbles");
});

test("The {{linkTo}} helper supports bubbles=false", function() {
  Ember.TEMPLATES.about = Ember.Handlebars.compile("
{{#linkTo 'about.contact' id='about-contact' bubbles=false}}About{{/linkTo}}
{{outlet}}");
  Ember.TEMPLATES['about/contact'] = Ember.Handlebars.compile("
Contact
");

  Router.map(function() {
    this.resource("about", function() {
      this.route("contact");
    });
  });

  var hidden = 0;

  App.AboutRoute = Ember.Route.extend({
    events: {
      hide: function() {
        hidden++;
      }
    }
  });

  bootApplication();

  Ember.run(function() {
    router.handleURL("/about");
  });

  Ember.run(function() {
    Ember.$('#about-contact', '#qunit-fixture').click();
  });

  equal(Ember.$("#contact", "#qunit-fixture").text(), "Contact", "precond - the link worked");

  equal(hidden, 0, "The link didn't bubble");
});

test("The {{linkTo}} helper moves into the named route with context", function() {
  Router.map(function(match) {
    this.route("about");
    this.resource("item", { path: "/item/:id" });
  });

  Ember.TEMPLATES.about = Ember.Handlebars.compile("
List

{{#each controller}}
{{#linkTo item this}}{{name}}{{/linkTo}}
{{/each}}
{{#linkTo index id='home-link'}}Home{{/linkTo}}");

  var people = {
    yehuda: "Yehuda Katz",
    tom: "Tom Dale",
    erik: "Erik Brynroflsson"
  };

  App.AboutRoute = Ember.Route.extend({
    model: function() {
      return Ember.A([
        { id: "yehuda", name: "Yehuda Katz" },
        { id: "tom", name: "Tom Dale" },
        { id: "erik", name: "Erik Brynroflsson" }
      ]);
    }
  });

  App.ItemRoute = Ember.Route.extend({
    serialize: function(object) {
      return { id: object.id };
    },

    deserialize: function(params) {
      return { id: params.id, name: people[params.id] };
    }
  });

  bootApplication();

  Ember.run(function() {
    router.handleURL("/about");
  });

  equal(Ember.$('h3:contains(List)', '#qunit-fixture').length, 1, "The home template was rendered");
  equal(normalizeUrl(Ember.$('#home-link').attr('href')), '/', "The home link points back at /");

  Ember.run(function() {
    Ember.$('li a:contains(Yehuda)', '#qunit-fixture').click();
  });

  equal(Ember.$('h3:contains(Item)', '#qunit-fixture').length, 1, "The item template was rendered");
  equal(Ember.$('p', '#qunit-fixture').text(), "Yehuda Katz", "The name is correct");

  Ember.run(function() { Ember.$('#home-link').click(); });
  Ember.run(function() { Ember.$('#about-link').click(); });

  equal(normalizeUrl(Ember.$('li a:contains(Yehuda)').attr('href')), "/item/yehuda");
  equal(normalizeUrl(Ember.$('li a:contains(Tom)').attr('href')), "/item/tom");
  equal(normalizeUrl(Ember.$('li a:contains(Erik)').attr('href')), "/item/erik");

  Ember.run(function() {
    Ember.$('li a:contains(Erik)', '#qunit-fixture').click();
  });

  equal(Ember.$('h3:contains(Item)', '#qunit-fixture').length, 1, "The item template was rendered");
  equal(Ember.$('p', '#qunit-fixture').text(), "Erik Brynroflsson", "The name is correct");
});

test("The {{linkTo}} helper binds some anchor html tag common attributes", function() {
  Ember.TEMPLATES.index = Ember.Handlebars.compile("
Home
{{#linkTo index id='self-link' title='title-attr'}}Self{{/linkTo}}");
  bootApplication();

  Ember.run(function() {
    router.handleURL("/");
  });

  equal(Ember.$('#self-link', '#qunit-fixture').attr('title'), 'title-attr', "The self-link contains title attribute");
});

test("The {{linkTo}} helper accepts string arguments", function() {
  Router.map(function() {
    this.route('filter', { path: '/filters/:filter' });
  });

  Ember.TEMPLATES.filter = compile('
{{filter}}
{{#linkTo filter "unpopular" id="link"}}Unpopular{{/linkTo}}');
  Ember.TEMPLATES.index = compile('');

  bootApplication();

  Ember.run(function() { router.handleURL("/filters/popular"); });

  equal(Ember.$('#link', '#qunit-fixture').attr('href'), "/filters/unpopular");
});

test("The {{linkTo}} helper unwraps controllers", function() {
  // The serialize hook is called twice: once to generate the href for the
  // link and once to generate the URL when the link is clicked.
  expect(2);

  Router.map(function() {
    this.route('filter', { path: '/filters/:filter' });
  });

  var indexObject = { filter: 'popular' };

  App.FilterRoute = Ember.Route.extend({
    model: function(params) {
      return indexObject;
    },

    serialize: function(passedObject) {
      equal(passedObject, indexObject, "The unwrapped object is passed");
      return { filter: 'popular' };
    }
  });

  App.IndexRoute = Ember.Route.extend({
    model: function() {
      return indexObject;
    }
  });

  Ember.TEMPLATES.filter = compile('
{{filter}}
');
  Ember.TEMPLATES.index = compile('{{#linkTo filter this id="link"}}Filter{{/linkTo}}');

  bootApplication();

  Ember.run(function() { router.handleURL("/"); });

  Ember.$('#link', '#qunit-fixture').trigger('click');
});

test("The {{linkTo}} helper doesn't change view context", function() {
  App.IndexView = Ember.View.extend({
    elementId: 'index',
    name: 'test'
  });

  Ember.TEMPLATES.index = Ember.Handlebars.compile("{{view.name}}-{{#linkTo index id='self-link'}}Link: {{view.name}}{{/linkTo}}");

  bootApplication();

  Ember.run(function() {
    router.handleURL("/");
  });

  equal(Ember.$('#index', '#qunit-fixture').text(), 'test-Link: test', "accesses correct view");
});
<|endoftext|>