Skip to content

Instantly share code, notes, and snippets.

@robotdana
Created August 16, 2012 12:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save robotdana/3369755 to your computer and use it in GitHub Desktop.
Save robotdana/3369755 to your computer and use it in GitHub Desktop.
Hanging Punctuation
<html>
<head>
<meta charset="utf8" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
$(function(){
$('article').find('h1,h2,h3,h4,h5,h6,p,blockquote,li').hang_quotes();
});
</script>
<style>
/*.hq {color:red;}*/
article {
/*border-left:1px solid red;*/
width:300px;
margin:0 auto;
}
</style>
</head>
<body>
<article>
<h1>&ldquo;Hanging Punctuation for all!&rdquo;</h1>
<p>&ldquo;&lsquo;Nested quotation marks?&rsquo; No problem,&rdquo; he replied</p>
<h2>All marks supported</h2>
<ul>
<li>&ldquo;Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur.&rdquo;</li>
<li>&lsquo;Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur.&rsquo;</li>
<li>&laquo;Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur.&raquo;</li>
<li>&lsaquo;Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur.&rsaquo;</li>
<li>"Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur."</li>
<li>'Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur.'</li>
<li>`Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur.`</li>
</ul>
<p style="text-align:justify">’96 was an excellent year! Lorem ipsum dolor sit amet" consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p><i></i><i><i></i></i>''' it ignores stray empty elememnts, like the &lt;i&gt; at the beginning of this paragraph</p>
<blockquote><p>Blockquotes love it.</p><p>&ldquo; I'm a loving blockquote!&rdquo;</p></blockquote>
<h1>Known issues.</h1>
<p style="text-align:right;">"text align right doesn't right"</p>
<p style="text-align:center;">"center's busted as well"</p>
<p>Quotes that start a line, but aren't the first textual "character" of the block won't be picked up</p>
</article>
</body>
</html>
(function($){
var is_text_node = function(node) {
return node !== undefined && node.nodeType == 3;
};
var first_text_wrapper = function(node){
var ret;
$(node).contents().each(function(i){
var $this = $(this);
console.log(is_text_node(this));
if (is_text_node(this)) {
if(i !== 0) {
//handle case where the first element was empty and we need a new element to play with
ret = $this.wrap($('<span />')).parent()[0];
} else {
ret = node;
}
return false;
} else if ($this !== undefined && $this.width() !== 0) {
ret = first_text_wrapper(this);
return false;
}
});
return ret;
};
var re = /^((?:[`'"“‘’«‹(]|&[rl](?:s|d|a|sa)quo)+)/;
var klass = 'hq';
var hang_quotes = function(){
return $(this).each(function(){
var el = $(first_text_wrapper(this));
if (!el.hasClass(klass)) {
el.html(el.html().replace(re, '<span class="'+klass+'">$1</span>'));
el.css({position:'relative'});
}
var hq = el.find('.' + klass);
hq.css({position:'absolute', left: -hq.width() + 'px'});
});
};
hang_quotes.is_text_node = is_text_node;
hang_quotes.first_text_wrapper = first_text_wrapper;
$.fn.hang_quotes = hang_quotes;
})(jQuery);
<html>
<head>
<meta charset="utf8" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script src="hang_quotes.js"></script>
<script>
$(function(){
$('article').find('h1,h2,h3,h4,h5,h6,p,blockquote,li').hang_quotes();
});
</script>
<style>
/*.hq {color:red;}*/
article {
/*border-left:1px solid red;*/
width:300px;
margin:0 auto;
}
</style>
</head>
<body>
<article>
<h1>&ldquo;Hanging Punctuation for all!&rdquo;</h1>
<p>&ldquo;&lsquo;Nested quotation marks?&rsquo; No problem,&rdquo; he replied</p>
<h2>All marks supported</h2>
<ul>
<li>&ldquo;Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur.&rdquo;</li>
<li>&lsquo;Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur.&rsquo;</li>
<li>&laquo;Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur.&raquo;</li>
<li>&lsaquo;Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur.&rsaquo;</li>
<li>"Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur."</li>
<li>'Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur.'</li>
<li>`Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur.`</li>
</ul>
<p style="text-align:justify">’96 was an excellent year! Lorem ipsum dolor sit amet" consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p><i></i><i><i></i></i>''' it ignores stray empty elememnts, like the &lt;i&gt; at the beginning of this paragraph</p>
<blockquote><p>Blockquotes love it.</p><p>&ldquo; I'm a loving blockquote!&rdquo;</p></blockquote>
<h1>Known issues.</h1>
<p style="text-align:right;">"text align right doesn't right"</p>
<p style="text-align:center;">"center's busted as well"</p>
<p><br />"br tags are a no-go</p>
<p>Quotes that start a line, but aren't the first textual "character" of the block won't be picked up</p>
</article>
</body>
</html>
//basic wrapper for a jquery plugin.
(function($){
})(jQuery);
//anonymous function
function(){
}
//executed anonymous function
function(){
}();
//executed anonymous function with an argument
//jQuery is passed to $ within the function.
//this means you can use jQuery's $ even in a jQuery.noConflict() setting.
function($){
}(jQuery);
//wrap this bit in brackets for some browser compatibility reason.
(function($) {
})(jQuery)
//How to build a jQuery Plugin.
We want a small API.
We want it to be as private as possible - one function exposed.
We want it to be as exposed as possible - so we can test
So - module pattern
We want to get the dom elements to work on from the jquery object.
We want to return those for chaining.
We want to expose some things for testing
<html>
<head>
<meta charset="utf8" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script src="hang_quotes.js"></script>
<script src="test.js"></script>
<script>
new Test("Is Text Node", $.fn.hang_quotes.is_text_node($('<p>text</p>').contents()[0]));
new Test("Isn't Text Node (empty)", $.fn.hang_quotes.is_text_node($('<p></p>').contents()[0]), false);
new Test("Isn't Text Node (element)", $.fn.hang_quotes.is_text_node($('<p><em>text</em></p>').contents()[0]), false);
new Test("No Quotes", $('<p>text</p>').hang_quotes().html(), 'text');
Test.run();
</script>
</head>
<body>
</body>
</html>
var Test = {};
(function(window, undefined){
var tests = [];
Test = function(name, value, expectation, fn) {
this.name = name;
this.value = value;
if (expectation !== undefined) {
this.expectation = expectation;
}
if (fn !== undefined) {
this.fn = fn;
}
tests.push(this);
return this;
};
Test.prototype = (function() {
return {
expectation: true,
fn: function(value, expectation) {
return value == expectation;
},
run: function() {
return this.fn(this.value, this.expectation);
}
};
})();
Test.run = function() {
console.log('*****************');
for(var i = 0; i < tests.length; i++) {
var test = tests[i];
console.log(test);
if (test.run()){
console.log('Passed: ', test.name);
} else {
console.log('Failed: ', test.name);
console.log('Expected: ', test.expectation);
console.log('Got: ', test.value);
}
console.log('*****************');
}
}
})(this);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment