Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Make original text smilies selectable (closes #2)
* Make smilies a background image of an <abbrev> element with transparent text. This leaves the original text in place, so copying and pasting will keep the original text smiley * Updated tests. Now they're probably a bit more fragile than they were, but it shouldn't be too bad.
- Loading branch information
Showing
5 changed files
with
314 additions
and
246 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,33 +1,46 @@ | ||
var SmileyParser = function(smileyTable) { this.init(smileyTable); }; | ||
(function () | ||
{ | ||
this._smileyTable = {}; | ||
this.init = function(smileyTable) { | ||
this._smileyTable = smileyTable || defaultSmileyTable; | ||
this._handlers = []; | ||
for (var smiley in this._smileyTable) { | ||
if (this._smileyTable.hasOwnProperty(smiley)) { | ||
var self = this; | ||
this._handlers.push({pattern: new RegExp('(["a-zA-Z0-9#])?' + smiley, "g"), | ||
replacement: (function (s) { | ||
return function(text, lb) { | ||
if (lb) return document.createTextNode(text); | ||
var img = | ||
document.createElement('img'); | ||
img.src = self._smileyTable[s]; | ||
img.alt = img.title = | ||
text.replace(/&/g, '&'). | ||
replace(/</g, '<'). | ||
replace(/>/g, '>'); | ||
return img; | ||
}; | ||
})(smiley)}); | ||
} | ||
} | ||
}; | ||
this._smileyTable = {}; | ||
this.init = function(smileyTable) { | ||
/* Returns a function that receives the matched text and the | ||
first matched group in the regular expression. The first group | ||
is always a fake lookbehind. If there's anything, we should | ||
return the text back, without creating any graphical smiley */ | ||
function replaceFunction(s) { | ||
return function(text, lb) { | ||
if (lb) return document.createTextNode(text); | ||
var smileyInfo = self._smileyTable[s]; | ||
var smileyDom = document.createElement('abbrev'); | ||
smileyDom.innerHTML = text.replace(/&/g, '&'). | ||
replace(/</g, '<'). | ||
replace(/>/g, '>'); | ||
var url = "data:image/png;base64," + smileyInfo.imageDataBase64; | ||
smileyDom.style.backgroundImage = "url(" + url + ")"; | ||
if (smileyInfo.height !== undefined) | ||
smileyDom.style.height = smileyInfo.height + "px"; | ||
if (smileyInfo.width !== undefined) | ||
smileyDom.style.width = smileyInfo.width + "px"; | ||
smileyDom.style.display = 'inline-block'; | ||
smileyDom.style.color = 'transparent'; | ||
smileyDom.style.overflow = 'hidden'; | ||
return smileyDom; | ||
}; | ||
} | ||
this._smileyTable = smileyTable || defaultSmileyTable; | ||
this._handlers = []; | ||
for (var smiley in this._smileyTable) { | ||
if (this._smileyTable.hasOwnProperty(smiley)) { | ||
var self = this; | ||
this._handlers.push({pattern: new RegExp('(["a-zA-Z0-9#])?' + | ||
smiley, "g"), | ||
replacement: replaceFunction(smiley)}); | ||
} | ||
} | ||
}; | ||
|
||
this.parseSmileys = function(element) { | ||
replaceTextWithElements(element, {excludedTags: /textarea/, | ||
handlers: this._handlers}); | ||
}; | ||
this.parseSmileys = function(element) { | ||
replaceTextWithElements(element, {excludedTags: /textarea/, | ||
handlers: this._handlers}); | ||
}; | ||
}).call(SmileyParser.prototype); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,41 +1,68 @@ | ||
function isHtmlEquivalent(one, two) { | ||
var domElement = document.createElement('div'); | ||
var domElement2 = document.createElement('div'); | ||
domElement.innerHTML = one; | ||
domElement2.innerHTML = two; | ||
return canonicalHtml(domElement) === canonicalHtml(domElement2); | ||
} | ||
|
||
describe("canonicalHtml", function() { | ||
var domElement; | ||
beforeEach(function() { | ||
this.addMatchers({ | ||
toBeCanonically: function(expected) { | ||
return isHtmlEquivalent(this.actual, expected); | ||
}, | ||
toNotBeCanonically: function(expected) { | ||
return ! isHtmlEquivalent(this.actual, expected); | ||
} | ||
}); | ||
}); | ||
|
||
beforeEach(function() { | ||
domElement = document.createElement('div'); | ||
it("should return the same string when there isn't any markup", function() { | ||
var someString = "Some string without any markup"; | ||
expect(someString).toBeCanonically(someString); | ||
}); | ||
|
||
this.addMatchers({ | ||
toBeCanonically: function(expected) { | ||
domElement.innerHTML = this.actual; | ||
return this.env.equals_(canonicalHtml(domElement), expected); | ||
} | ||
}); | ||
}); | ||
it("should return the same string when there are simple elements", function() { | ||
var someString = "Some string with <strong>some</strong> markup"; | ||
expect(someString).toBeCanonically(someString); | ||
}); | ||
|
||
it("should return the same string when there isn't any markup", function() { | ||
var someString = "Some string without any markup"; | ||
expect(someString).toBeCanonically(someString); | ||
}); | ||
it("should return attributes in alphabetical order", function() { | ||
var source = 'Some <a title="foo" href="http://example.com">link</a>'; | ||
var expected = 'Some <a href="http://example.com" title="foo">link</a>'; | ||
expect(source).toBeCanonically(expected); | ||
}); | ||
|
||
it("should return the same string when there are simple elements", function() { | ||
var someString = "Some string with <strong>some</strong> markup"; | ||
expect(someString).toBeCanonically(someString); | ||
}); | ||
it("should return self-closing tags correctly", function() { | ||
var source = 'An <img src="image.png">'; | ||
var expected = 'An <img src="image.png" />'; | ||
expect(source).toBeCanonically(expected); | ||
}); | ||
|
||
it("should return attributes in alphabetical order", function() { | ||
var source = 'Some <a title="foo" href="http://example.com">link</a>'; | ||
var expected = 'Some <a href="http://example.com" title="foo">link</a>'; | ||
expect(source).toBeCanonically(expected); | ||
}); | ||
it("should return HTML entities correctly", function() { | ||
var source = 'A Smith & Wesson weapon'; | ||
expect(source).toBeCanonically(source); | ||
}); | ||
|
||
it("should return self-closing tags correctly", function() { | ||
var source = 'An <img src="image.png">'; | ||
var expected = 'An <img src="image.png" />'; | ||
expect(source).toBeCanonically(expected); | ||
}); | ||
it("should recognise a simple smiley correctly", function() { | ||
var source1 = 'A smiley: <abbrev style="background-image: url(foo.png); width: 30px; height: 25px">some text</abbrev>'; | ||
var source2 = 'A smiley: <abbrev style="background-image: url(foo.png); height: 25px; width: 30px">some text</abbrev>'; | ||
var source3 = 'A smiley: <abbrev style="background-image: url(foo.png); height: 25px; width: 30px">some other text</abbrev>'; | ||
expect(source1).toBeCanonically(source2); | ||
expect(source1).toNotBeCanonically(source3); | ||
expect(source2).toNotBeCanonically(source3); | ||
}); | ||
|
||
it("should return HTML entities correctly", function() { | ||
var source = 'A Smith & Wesson weapon'; | ||
expect(source).toBeCanonically(source); | ||
}); | ||
it("should recognise a smiley w/ extra properties as different", function() { | ||
var source1 = 'A smiley: <abbrev style="background-image: url(foo.png); width: 30px">some text</abbrev>'; | ||
var source2 = 'A smiley: <abbrev style="background-image: url(foo.png); width: 30px; height: 25px">some text</abbrev>'; | ||
expect(source1).toNotBeCanonically(source2); | ||
}); | ||
|
||
it("should recognise a smiley w/ angle brackets", function() { | ||
var source1 = 'A smiley: <abbrev style="background-image: url(foo.png); height: 25px; width: 30px"></troll></abbrev>'; | ||
var source2 = 'A smiley: <abbrev style="background-image: url(foo.png); width: 30px; height: 25px"></troll></abbrev>'; | ||
expect(source1).toBeCanonically(source2); | ||
}); | ||
}); |
Oops, something went wrong.