Skip to content

Commit

Permalink
Merge pull request #12596 from rwjblue/ie8-input-type
Browse files Browse the repository at this point in the history
[BUGFIX release-1-13] Fix {{input}} helper on IE8.
  • Loading branch information
rwjblue committed Nov 12, 2015
2 parents 144caef + f0d887b commit 4566dc9
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 6 deletions.
46 changes: 46 additions & 0 deletions packages/ember-htmlbars/tests/helpers/input_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import ComponentLookup from "ember-views/component_lookup";
import TextField from 'ember-views/views/text_field';
import Checkbox from 'ember-views/views/checkbox';
import EventDispatcher from 'ember-views/system/event_dispatcher';
import {
disableInputTypeChanging,
resetInputTypeChanging
} from 'ember-views/system/build-component-template';

var view;
var controller, registry, container;
Expand Down Expand Up @@ -265,6 +269,48 @@ QUnit.test("should change if the type changes", function() {
equal(view.$('input').attr('type'), 'text', "it changes after the type changes");
});

QUnit.module("{{input type='text'}} - dynamic type in IE8 safe environment", {
setup() {
commonSetup();

disableInputTypeChanging();

controller = {
someProperty: 'password',
ie8Safe: true
};

view = View.extend({
container: container,
controller: controller,
template: compile('{{input type=someProperty}}')
}).create();

runAppend(view);
},

teardown() {
resetInputTypeChanging();

runDestroy(view);
runDestroy(container);
}
});

QUnit.test("should insert a text field into DOM", function() {
equal(view.$('input').attr('type'), 'password', "a bound property can be used to determine type in IE8.");
});

QUnit.test("should NOT change if the type changes", function() {
equal(view.$('input').attr('type'), 'password', "a bound property can be used to determine type in IE8.");

run(function() {
set(controller, 'someProperty', 'text');
});

equal(view.$('input').attr('type'), 'password', "it does NOT change after the type changes in IE8");
});

QUnit.module("{{input}} - default type", {
setup() {
commonSetup();
Expand Down
50 changes: 45 additions & 5 deletions packages/ember-views/lib/system/build-component-template.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export default function buildComponentTemplate({ component, layout, isAngleBrack
// element. We use `manualElement` to create a template that represents
// the wrapping element and yields to the previous block.
if (tagName !== '') {
var attributes = normalizeComponentAttributes(component, isAngleBracket, attrs);
var attributes = normalizeComponentAttributes(component, isAngleBracket, attrs, tagName);
var elementTemplate = internal.manualElement(tagName, attributes);
elementTemplate.meta = meta;

Expand All @@ -43,6 +43,30 @@ export default function buildComponentTemplate({ component, layout, isAngleBrack
return { createdElement: !!tagName, block: blockToRender };
}

// Static flag used to see if we can mutate the type attribute on input elements. IE8
// does not support changing the type attribute after an element is inserted in
// a tree.
var isInputTypeAttributeMutable = (function() {
var docFragment = document.createDocumentFragment();
var mutableInputTypeTextElement = document.createElement('input');
mutableInputTypeTextElement.type = 'text';
try {
docFragment.appendChild(mutableInputTypeTextElement);
mutableInputTypeTextElement.setAttribute('type', 'password');
} catch (e) {
return false;
}
return true;
})();

var canChangeInputType = isInputTypeAttributeMutable;
export function disableInputTypeChanging() {
canChangeInputType = false;
}
export function resetInputTypeChanging() {
canChangeInputType = isInputTypeAttributeMutable;
}

function blockFor(template, options) {
Ember.assert("BUG: Must pass a template to blockFor", !!template);
return internal.blockFor(render, template, options);
Expand Down Expand Up @@ -113,7 +137,8 @@ function tagNameFor(view) {

// Takes a component and builds a normalized set of attribute
// bindings consumable by HTMLBars' `attribute` hook.
function normalizeComponentAttributes(component, isAngleBracket, attrs) {
function normalizeComponentAttributes(component, isAngleBracket, attrs, tagName) {
var hardCodeType = tagName === 'input' && !canChangeInputType;
var normalized = {};
var attributeBindings = component.attributeBindings;
var i, l;
Expand All @@ -135,17 +160,32 @@ function normalizeComponentAttributes(component, isAngleBracket, attrs) {
if (colonIndex !== -1) {
var attrProperty = attr.substring(0, colonIndex);
attrName = attr.substring(colonIndex + 1);
expression = ['get', 'view.' + attrProperty];

if (attrName === 'type' && hardCodeType) {
expression = component.get(attrProperty) + '';
} else {
expression = ['get', 'view.' + attrProperty];
}
} else if (attrs[attr]) {
// TODO: For compatibility with 1.x, we probably need to `set`
// the component's attribute here if it is a CP, but we also
// probably want to suspend observers and allow the
// willUpdateAttrs logic to trigger observers at the correct time.
attrName = attr;
expression = ['value', attrs[attr]];

if (attrName === 'type' && hardCodeType) {
expression = getValue(attrs[attr]) + '';
} else {
expression = ['value', attrs[attr]];
}
} else {
attrName = attr;
expression = ['get', 'view.' + attr];

if (attrName === 'type' && hardCodeType) {
expression = component.get(attr) + '';
} else {
expression = ['get', 'view.' + attr];
}
}

Ember.assert('You cannot use class as an attributeBinding, use classNameBindings instead.', attrName !== 'class');
Expand Down
4 changes: 3 additions & 1 deletion packages/ember-views/lib/views/text_field.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,9 @@ export default Component.extend(TextSupport, {
value: "",

/**
The `type` attribute of the input element.
The `type` attribute of the input element. To remain compatible with IE8, this
cannot change after the element has been rendered. It is suggested to avoid using
a dynamic type attribute if you are supporting IE8 since it will be set once and never change.
@property type
@type String
Expand Down

0 comments on commit 4566dc9

Please sign in to comment.