character 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. data/.gitignore +1 -0
  2. data/Gemfile +4 -0
  3. data/README.md +20 -0
  4. data/Rakefile +7 -0
  5. data/app/controllers/character/posts_controller.rb +27 -0
  6. data/app/models/character/post.rb +20 -0
  7. data/character.gemspec +24 -0
  8. data/lib/character.rb +3 -0
  9. data/lib/character/engine.rb +5 -0
  10. data/lib/character/routing.rb +11 -0
  11. data/lib/character/version.rb +3 -0
  12. data/lib/generators/character/install_generator.rb +42 -0
  13. data/lib/generators/character/templates/README +1 -0
  14. data/lib/generators/character/templates/admin/character.rb +3 -0
  15. data/vendor/assets/fonts/general_foundicons.eot +0 -0
  16. data/vendor/assets/fonts/general_foundicons.svg +15 -0
  17. data/vendor/assets/fonts/general_foundicons.ttf +0 -0
  18. data/vendor/assets/fonts/general_foundicons.woff +0 -0
  19. data/vendor/assets/javascripts/backbone.js +1431 -0
  20. data/vendor/assets/javascripts/character/index.js.coffee +53 -0
  21. data/vendor/assets/javascripts/character/models/post.js.coffee +39 -0
  22. data/vendor/assets/javascripts/character/views/app.js.coffee +81 -0
  23. data/vendor/assets/javascripts/character/views/editor.js.coffee +231 -0
  24. data/vendor/assets/javascripts/character/views/editor_settings.js.coffee +44 -0
  25. data/vendor/assets/javascripts/character/views/index.js.coffee +116 -0
  26. data/vendor/assets/javascripts/character/views/preview.js.coffee +49 -0
  27. data/vendor/assets/javascripts/jquery.smartresize.js +30 -0
  28. data/vendor/assets/javascripts/lodash.js +4258 -0
  29. data/vendor/assets/javascripts/showdown.js +62 -0
  30. data/vendor/assets/javascripts/underscore.string.js +600 -0
  31. data/vendor/assets/stylesheets/character/_base.css.scss +84 -0
  32. data/vendor/assets/stylesheets/character/_icons.css.scss.erb +96 -0
  33. data/vendor/assets/stylesheets/character/_view_editor.css.scss +115 -0
  34. data/vendor/assets/stylesheets/character/_view_index.css.scss +73 -0
  35. data/vendor/assets/stylesheets/character/_view_preview.css.scss +49 -0
  36. data/vendor/assets/stylesheets/character/index.css.scss +32 -0
  37. metadata +103 -0
@@ -0,0 +1,62 @@
1
+ //
2
+ // showdown.js -- A javascript port of Markdown.
3
+ //
4
+ // Copyright (c) 2007 John Fraser.
5
+ //
6
+ // Original Markdown Copyright (c) 2004-2005 John Gruber
7
+ // <http://daringfireball.net/projects/markdown/>
8
+ //
9
+ // Redistributable under a BSD-style open source license.
10
+ // See license.txt for more information.
11
+ //
12
+ // The full source distribution is at:
13
+ //
14
+ // A A L
15
+ // T C A
16
+ // T K B
17
+ //
18
+ // <http://www.attacklab.net/>
19
+ //
20
+ //
21
+ // Wherever possible, Showdown is a straight, line-by-line port
22
+ // of the Perl version of Markdown.
23
+ //
24
+ // This is not a normal parser design; it's basically just a
25
+ // series of string substitutions. It's hard to read and
26
+ // maintain this way, but keeping Showdown close to the original
27
+ // design makes it easier to port new features.
28
+ //
29
+ // More importantly, Showdown behaves like markdown.pl in most
30
+ // edge cases. So web applications can do client-side preview
31
+ // in Javascript, and then build identical HTML on the server.
32
+ //
33
+ // This port needs the new RegExp functionality of ECMA 262,
34
+ // 3rd Edition (i.e. Javascript 1.5). Most modern web browsers
35
+ // should do fine. Even with the new regular expression features,
36
+ // We do a lot of work to emulate Perl's regex functionality.
37
+ // The tricky changes in this file mostly have the "attacklab:"
38
+ // label. Major or self-explanatory changes don't.
39
+ //
40
+ // Smart diff tools like Araxis Merge will be able to match up
41
+ // this file with markdown.pl in a useful way. A little tweaking
42
+ // helps: in a copy of markdown.pl, replace "#" with "//" and
43
+ // replace "$text" with "text". Be sure to ignore whitespace
44
+ // and line endings.
45
+ //
46
+ //
47
+ // Showdown usage:
48
+ //
49
+ // var text = "Markdown *rocks*.";
50
+ //
51
+ // var converter = new Showdown.converter();
52
+ // var html = converter.makeHtml(text);
53
+ //
54
+ // alert(html);
55
+ //
56
+ // Note: move the sample code to the bottom of this
57
+ // file before uncommenting it.
58
+ //
59
+ //
60
+ // Showdown namespace
61
+ //
62
+ var Showdown={extensions:{}},forEach=Showdown.forEach=function(a,b){if(typeof a.forEach=="function")a.forEach(b);else{var c,d=a.length;for(c=0;c<d;c++)b(a[c],c,a)}},stdExtName=function(a){return a.replace(/[_-]||\s/g,"").toLowerCase()};Showdown.converter=function(a){var b,c,d,e=0,f=[],g=[];if(typeof module!="undefind"&&typeof exports!="undefined"&&typeof require!="undefind"){var h=require("fs");if(h){var i=h.readdirSync((__dirname||".")+"/extensions").filter(function(a){return~a.indexOf(".js")}).map(function(a){return a.replace(/\.js$/,"")});Showdown.forEach(i,function(a){var b=stdExtName(a);Showdown.extensions[b]=require("./extensions/"+a)})}}this.makeHtml=function(a){return b={},c={},d=[],a=a.replace(/~/g,"~T"),a=a.replace(/\$/g,"~D"),a=a.replace(/\r\n/g,"\n"),a=a.replace(/\r/g,"\n"),a="\n\n"+a+"\n\n",a=M(a),a=a.replace(/^[ \t]+$/mg,""),Showdown.forEach(f,function(b){a=k(b,a)}),a=z(a),a=m(a),a=l(a),a=o(a),a=K(a),a=a.replace(/~D/g,"$$"),a=a.replace(/~T/g,"~"),Showdown.forEach(g,function(b){a=k(b,a)}),a};if(a&&a.extensions){var j=this;Showdown.forEach(a.extensions,function(a){typeof a=="string"&&(a=Showdown.extensions[stdExtName(a)]);if(typeof a!="function")throw"Extension '"+a+"' could not be loaded. It was either not found or is not a valid extension.";Showdown.forEach(a(j),function(a){a.type?a.type==="language"||a.type==="lang"?f.push(a):(a.type==="output"||a.type==="html")&&g.push(a):g.push(a)})})}var k=function(a,b){if(a.regex){var c=new RegExp(a.regex,"g");return b.replace(c,a.replace)}if(a.filter)return a.filter(b)},l=function(a){return a+="~0",a=a.replace(/^[ ]{0,3}\[(.+)\]:[ \t]*\n?[ \t]*<?(\S+?)>?[ \t]*\n?[ \t]*(?:(\n*)["(](.+?)[")][ \t]*)?(?:\n+|(?=~0))/gm,function(a,d,e,f,g){return d=d.toLowerCase(),b[d]=G(e),f?f+g:(g&&(c[d]=g.replace(/"/g,"&quot;")),"")}),a=a.replace(/~0/,""),a},m=function(a){a=a.replace(/\n/g,"\n\n");var b="p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del|style|section|header|footer|nav|article|aside",c="p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|style|section|header|footer|nav|article|aside";return a=a.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del)\b[^\r]*?\n<\/\2>[ \t]*(?=\n+))/gm,n),a=a.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|style|section|header|footer|nav|article|aside)\b[^\r]*?<\/\2>[ \t]*(?=\n+)\n)/gm,n),a=a.replace(/(\n[ ]{0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g,n),a=a.replace(/(\n\n[ ]{0,3}<!(--[^\r]*?--\s*)+>[ \t]*(?=\n{2,}))/g,n),a=a.replace(/(?:\n\n)([ ]{0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g,n),a=a.replace(/\n\n/g,"\n"),a},n=function(a,b){var c=b;return c=c.replace(/\n\n/g,"\n"),c=c.replace(/^\n/,""),c=c.replace(/\n+$/g,""),c="\n\n~K"+(d.push(c)-1)+"K\n\n",c},o=function(a){a=v(a);var b=A("<hr />");return a=a.replace(/^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$/gm,b),a=a.replace(/^[ ]{0,2}([ ]?\-[ ]?){3,}[ \t]*$/gm,b),a=a.replace(/^[ ]{0,2}([ ]?\_[ ]?){3,}[ \t]*$/gm,b),a=x(a),a=y(a),a=E(a),a=m(a),a=F(a),a},p=function(a){return a=B(a),a=q(a),a=H(a),a=t(a),a=r(a),a=I(a),a=G(a),a=D(a),a=a.replace(/ +\n/g," <br />\n"),a},q=function(a){var b=/(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|<!(--.*?--\s*)+>)/gi;return a=a.replace(b,function(a){var b=a.replace(/(.)<\/?code>(?=.)/g,"$1`");return b=N(b,"\\`*_"),b}),a},r=function(a){return a=a.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g,s),a=a.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\]\([ \t]*()<?(.*?(?:\(.*?\).*?)?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,s),a=a.replace(/(\[([^\[\]]+)\])()()()()()/g,s),a},s=function(a,d,e,f,g,h,i,j){j==undefined&&(j="");var k=d,l=e,m=f.toLowerCase(),n=g,o=j;if(n==""){m==""&&(m=l.toLowerCase().replace(/ ?\n/g," ")),n="#"+m;if(b[m]!=undefined)n=b[m],c[m]!=undefined&&(o=c[m]);else{if(!(k.search(/\(\s*\)$/m)>-1))return k;n=""}}n=N(n,"*_");var p='<a href="'+n+'"';return o!=""&&(o=o.replace(/"/g,"&quot;"),o=N(o,"*_"),p+=' title="'+o+'"'),p+=">"+l+"</a>",p},t=function(a){return a=a.replace(/(!\[(.*?)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g,u),a=a.replace(/(!\[(.*?)\]\s?\([ \t]*()<?(\S+?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,u),a},u=function(a,d,e,f,g,h,i,j){var k=d,l=e,m=f.toLowerCase(),n=g,o=j;o||(o="");if(n==""){m==""&&(m=l.toLowerCase().replace(/ ?\n/g," ")),n="#"+m;if(b[m]==undefined)return k;n=b[m],c[m]!=undefined&&(o=c[m])}l=l.replace(/"/g,"&quot;"),n=N(n,"*_");var p='<img src="'+n+'" alt="'+l+'"';return o=o.replace(/"/g,"&quot;"),o=N(o,"*_"),p+=' title="'+o+'"',p+=" />",p},v=function(a){function b(a){return a.replace(/[^\w]/g,"").toLowerCase()}return a=a.replace(/^(.+)[ \t]*\n=+[ \t]*\n+/gm,function(a,c){return A('<h1 id="'+b(c)+'">'+p(c)+"</h1>")}),a=a.replace(/^(.+)[ \t]*\n-+[ \t]*\n+/gm,function(a,c){return A('<h2 id="'+b(c)+'">'+p(c)+"</h2>")}),a=a.replace(/^(\#{1,6})[ \t]*(.+?)[ \t]*\#*\n+/gm,function(a,c,d){var e=c.length;return A("<h"+e+' id="'+b(d)+'">'+p(d)+"</h"+e+">")}),a},w,x=function(a){a+="~0";var b=/^(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm;return e?a=a.replace(b,function(a,b,c){var d=b,e=c.search(/[*+-]/g)>-1?"ul":"ol";d=d.replace(/\n{2,}/g,"\n\n\n");var f=w(d);return f=f.replace(/\s+$/,""),f="<"+e+">"+f+"</"+e+">\n",f}):(b=/(\n\n|^\n?)(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/g,a=a.replace(b,function(a,b,c,d){var e=b,f=c,g=d.search(/[*+-]/g)>-1?"ul":"ol",f=f.replace(/\n{2,}/g,"\n\n\n"),h=w(f);return h=e+"<"+g+">\n"+h+"</"+g+">\n",h})),a=a.replace(/~0/,""),a};w=function(a){return e++,a=a.replace(/\n{2,}$/,"\n"),a+="~0",a=a.replace(/(\n)?(^[ \t]*)([*+-]|\d+[.])[ \t]+([^\r]+?(\n{1,2}))(?=\n*(~0|\2([*+-]|\d+[.])[ \t]+))/gm,function(a,b,c,d,e){var f=e,g=b,h=c;return g||f.search(/\n{2,}/)>-1?f=o(L(f)):(f=x(L(f)),f=f.replace(/\n$/,""),f=p(f)),"<li>"+f+"</li>\n"}),a=a.replace(/~0/g,""),e--,a};var y=function(a){return a+="~0",a=a.replace(/(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=~0))/g,function(a,b,c){var d=b,e=c;return d=C(L(d)),d=M(d),d=d.replace(/^\n+/g,""),d=d.replace(/\n+$/g,""),d="<pre><code>"+d+"\n</code></pre>",A(d)+e}),a=a.replace(/~0/,""),a},z=function(a){return a+="~0",a=a.replace(/(?:^|\n)```(.*)\n([\s\S]*?)\n```/g,function(a,b,c){var d=b,e=c;return e=C(e),e=M(e),e=e.replace(/^\n+/g,""),e=e.replace(/\n+$/g,""),e="<pre><code"+(d?' class="'+d+'"':"")+">"+e+"\n</code></pre>",A(e)}),a=a.replace(/~0/,""),a},A=function(a){return a=a.replace(/(^\n+|\n+$)/g,""),"\n\n~K"+(d.push(a)-1)+"K\n\n"},B=function(a){return a=a.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,function(a,b,c,d,e){var f=d;return f=f.replace(/^([ \t]*)/g,""),f=f.replace(/[ \t]*$/g,""),f=C(f),b+"<code>"+f+"</code>"}),a},C=function(a){return a=a.replace(/&/g,"&amp;"),a=a.replace(/</g,"&lt;"),a=a.replace(/>/g,"&gt;"),a=N(a,"*_{}[]\\",!1),a},D=function(a){return a=a.replace(/(\*\*|__)(?=\S)([^\r]*?\S[*_]*)\1/g,"<strong>$2</strong>"),a=a.replace(/(\*|_)(?=\S)([^\r]*?\S)\1/g,"<em>$2</em>"),a},E=function(a){return a=a.replace(/((^[ \t]*>[ \t]?.+\n(.+\n)*\n*)+)/gm,function(a,b){var c=b;return c=c.replace(/^[ \t]*>[ \t]?/gm,"~0"),c=c.replace(/~0/g,""),c=c.replace(/^[ \t]+$/gm,""),c=o(c),c=c.replace(/(^|\n)/g,"$1 "),c=c.replace(/(\s*<pre>[^\r]+?<\/pre>)/gm,function(a,b){var c=b;return c=c.replace(/^ /mg,"~0"),c=c.replace(/~0/g,""),c}),A("<blockquote>\n"+c+"\n</blockquote>")}),a},F=function(a){a=a.replace(/^\n+/g,""),a=a.replace(/\n+$/g,"");var b=a.split(/\n{2,}/g),c=[],e=b.length;for(var f=0;f<e;f++){var g=b[f];g.search(/~K(\d+)K/g)>=0?c.push(g):g.search(/\S/)>=0&&(g=p(g),g=g.replace(/^([ \t]*)/g,"<p>"),g+="</p>",c.push(g))}e=c.length;for(var f=0;f<e;f++)while(c[f].search(/~K(\d+)K/)>=0){var h=d[RegExp.$1];h=h.replace(/\$/g,"$$$$"),c[f]=c[f].replace(/~K\d+K/,h)}return c.join("\n\n")},G=function(a){return a=a.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/g,"&amp;"),a=a.replace(/<(?![a-z\/?\$!])/gi,"&lt;"),a},H=function(a){return a=a.replace(/\\(\\)/g,O),a=a.replace(/\\([`*_{}\[\]()>#+-.!])/g,O),a},I=function(a){return a=a.replace(/<((https?|ftp|dict):[^'">\s]+)>/gi,'<a href="$1">$1</a>'),a=a.replace(/<(?:mailto:)?([-.\w]+\@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi,function(a,b){return J(K(b))}),a},J=function(a){var b=[function(a){return"&#"+a.charCodeAt(0)+";"},function(a){return"&#x"+a.charCodeAt(0).toString(16)+";"},function(a){return a}];return a="mailto:"+a,a=a.replace(/./g,function(a){if(a=="@")a=b[Math.floor(Math.random()*2)](a);else if(a!=":"){var c=Math.random();a=c>.9?b[2](a):c>.45?b[1](a):b[0](a)}return a}),a='<a href="'+a+'">'+a+"</a>",a=a.replace(/">.+:/g,'">'),a},K=function(a){return a=a.replace(/~E(\d+)E/g,function(a,b){var c=parseInt(b);return String.fromCharCode(c)}),a},L=function(a){return a=a.replace(/^(\t|[ ]{1,4})/gm,"~0"),a=a.replace(/~0/g,""),a},M=function(a){return a=a.replace(/\t(?=\t)/g," "),a=a.replace(/\t/g,"~A~B"),a=a.replace(/~B(.+?)~A/g,function(a,b,c){var d=b,e=4-d.length%4;for(var f=0;f<e;f++)d+=" ";return d}),a=a.replace(/~A/g," "),a=a.replace(/~B/g,""),a},N=function(a,b,c){var d="(["+b.replace(/([\[\]\\])/g,"\\$1")+"])";c&&(d="\\\\"+d);var e=new RegExp(d,"g");return a=a.replace(e,O),a},O=function(a,b){var c=b.charCodeAt(0);return"~E"+c+"E"}},typeof module!="undefined"&&(module.exports=Showdown),typeof define=="function"&&define.amd&&define("showdown",function(){return Showdown});
@@ -0,0 +1,600 @@
1
+ // Underscore.string
2
+ // (c) 2010 Esa-Matti Suuronen <esa-matti aet suuronen dot org>
3
+ // Underscore.string is freely distributable under the terms of the MIT license.
4
+ // Documentation: https://github.com/epeli/underscore.string
5
+ // Some code is borrowed from MooTools and Alexandru Marasteanu.
6
+ // Version '2.3.0'
7
+
8
+ !function(root, String){
9
+ 'use strict';
10
+
11
+ // Defining helper functions.
12
+
13
+ var nativeTrim = String.prototype.trim;
14
+ var nativeTrimRight = String.prototype.trimRight;
15
+ var nativeTrimLeft = String.prototype.trimLeft;
16
+
17
+ var parseNumber = function(source) { return source * 1 || 0; };
18
+
19
+ var strRepeat = function(str, qty){
20
+ if (qty < 1) return '';
21
+ var result = '';
22
+ while (qty > 0) {
23
+ if (qty & 1) result += str;
24
+ qty >>= 1, str += str;
25
+ }
26
+ return result;
27
+ };
28
+
29
+ var slice = [].slice;
30
+
31
+ var defaultToWhiteSpace = function(characters) {
32
+ if (characters == null)
33
+ return '\\s';
34
+ else if (characters.source)
35
+ return characters.source;
36
+ else
37
+ return '[' + _s.escapeRegExp(characters) + ']';
38
+ };
39
+
40
+ var escapeChars = {
41
+ lt: '<',
42
+ gt: '>',
43
+ quot: '"',
44
+ apos: "'",
45
+ amp: '&'
46
+ };
47
+
48
+ var reversedEscapeChars = {};
49
+ for(var key in escapeChars){ reversedEscapeChars[escapeChars[key]] = key; }
50
+
51
+ // sprintf() for JavaScript 0.7-beta1
52
+ // http://www.diveintojavascript.com/projects/javascript-sprintf
53
+ //
54
+ // Copyright (c) Alexandru Marasteanu <alexaholic [at) gmail (dot] com>
55
+ // All rights reserved.
56
+
57
+ var sprintf = (function() {
58
+ function get_type(variable) {
59
+ return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase();
60
+ }
61
+
62
+ var str_repeat = strRepeat;
63
+
64
+ var str_format = function() {
65
+ if (!str_format.cache.hasOwnProperty(arguments[0])) {
66
+ str_format.cache[arguments[0]] = str_format.parse(arguments[0]);
67
+ }
68
+ return str_format.format.call(null, str_format.cache[arguments[0]], arguments);
69
+ };
70
+
71
+ str_format.format = function(parse_tree, argv) {
72
+ var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length;
73
+ for (i = 0; i < tree_length; i++) {
74
+ node_type = get_type(parse_tree[i]);
75
+ if (node_type === 'string') {
76
+ output.push(parse_tree[i]);
77
+ }
78
+ else if (node_type === 'array') {
79
+ match = parse_tree[i]; // convenience purposes only
80
+ if (match[2]) { // keyword argument
81
+ arg = argv[cursor];
82
+ for (k = 0; k < match[2].length; k++) {
83
+ if (!arg.hasOwnProperty(match[2][k])) {
84
+ throw new Error(sprintf('[_.sprintf] property "%s" does not exist', match[2][k]));
85
+ }
86
+ arg = arg[match[2][k]];
87
+ }
88
+ } else if (match[1]) { // positional argument (explicit)
89
+ arg = argv[match[1]];
90
+ }
91
+ else { // positional argument (implicit)
92
+ arg = argv[cursor++];
93
+ }
94
+
95
+ if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) {
96
+ throw new Error(sprintf('[_.sprintf] expecting number but found %s', get_type(arg)));
97
+ }
98
+ switch (match[8]) {
99
+ case 'b': arg = arg.toString(2); break;
100
+ case 'c': arg = String.fromCharCode(arg); break;
101
+ case 'd': arg = parseInt(arg, 10); break;
102
+ case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break;
103
+ case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break;
104
+ case 'o': arg = arg.toString(8); break;
105
+ case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); break;
106
+ case 'u': arg = Math.abs(arg); break;
107
+ case 'x': arg = arg.toString(16); break;
108
+ case 'X': arg = arg.toString(16).toUpperCase(); break;
109
+ }
110
+ arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg);
111
+ pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' ';
112
+ pad_length = match[6] - String(arg).length;
113
+ pad = match[6] ? str_repeat(pad_character, pad_length) : '';
114
+ output.push(match[5] ? arg + pad : pad + arg);
115
+ }
116
+ }
117
+ return output.join('');
118
+ };
119
+
120
+ str_format.cache = {};
121
+
122
+ str_format.parse = function(fmt) {
123
+ var _fmt = fmt, match = [], parse_tree = [], arg_names = 0;
124
+ while (_fmt) {
125
+ if ((match = /^[^\x25]+/.exec(_fmt)) !== null) {
126
+ parse_tree.push(match[0]);
127
+ }
128
+ else if ((match = /^\x25{2}/.exec(_fmt)) !== null) {
129
+ parse_tree.push('%');
130
+ }
131
+ else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) {
132
+ if (match[2]) {
133
+ arg_names |= 1;
134
+ var field_list = [], replacement_field = match[2], field_match = [];
135
+ if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
136
+ field_list.push(field_match[1]);
137
+ while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') {
138
+ if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
139
+ field_list.push(field_match[1]);
140
+ }
141
+ else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) {
142
+ field_list.push(field_match[1]);
143
+ }
144
+ else {
145
+ throw new Error('[_.sprintf] huh?');
146
+ }
147
+ }
148
+ }
149
+ else {
150
+ throw new Error('[_.sprintf] huh?');
151
+ }
152
+ match[2] = field_list;
153
+ }
154
+ else {
155
+ arg_names |= 2;
156
+ }
157
+ if (arg_names === 3) {
158
+ throw new Error('[_.sprintf] mixing positional and named placeholders is not (yet) supported');
159
+ }
160
+ parse_tree.push(match);
161
+ }
162
+ else {
163
+ throw new Error('[_.sprintf] huh?');
164
+ }
165
+ _fmt = _fmt.substring(match[0].length);
166
+ }
167
+ return parse_tree;
168
+ };
169
+
170
+ return str_format;
171
+ })();
172
+
173
+
174
+
175
+ // Defining underscore.string
176
+
177
+ var _s = {
178
+
179
+ VERSION: '2.3.0',
180
+
181
+ isBlank: function(str){
182
+ if (str == null) str = '';
183
+ return (/^\s*$/).test(str);
184
+ },
185
+
186
+ stripTags: function(str){
187
+ if (str == null) return '';
188
+ return String(str).replace(/<\/?[^>]+>/g, '');
189
+ },
190
+
191
+ capitalize : function(str){
192
+ str = str == null ? '' : String(str);
193
+ return str.charAt(0).toUpperCase() + str.slice(1);
194
+ },
195
+
196
+ chop: function(str, step){
197
+ if (str == null) return [];
198
+ str = String(str);
199
+ step = ~~step;
200
+ return step > 0 ? str.match(new RegExp('.{1,' + step + '}', 'g')) : [str];
201
+ },
202
+
203
+ clean: function(str){
204
+ return _s.strip(str).replace(/\s+/g, ' ');
205
+ },
206
+
207
+ count: function(str, substr){
208
+ if (str == null || substr == null) return 0;
209
+ return String(str).split(substr).length - 1;
210
+ },
211
+
212
+ chars: function(str) {
213
+ if (str == null) return [];
214
+ return String(str).split('');
215
+ },
216
+
217
+ swapCase: function(str) {
218
+ if (str == null) return '';
219
+ return String(str).replace(/\S/g, function(c){
220
+ return c === c.toUpperCase() ? c.toLowerCase() : c.toUpperCase();
221
+ });
222
+ },
223
+
224
+ escapeHTML: function(str) {
225
+ if (str == null) return '';
226
+ return String(str).replace(/[&<>"']/g, function(m){ return '&' + reversedEscapeChars[m] + ';'; });
227
+ },
228
+
229
+ unescapeHTML: function(str) {
230
+ if (str == null) return '';
231
+ return String(str).replace(/\&([^;]+);/g, function(entity, entityCode){
232
+ var match;
233
+
234
+ if (entityCode in escapeChars) {
235
+ return escapeChars[entityCode];
236
+ } else if (match = entityCode.match(/^#x([\da-fA-F]+)$/)) {
237
+ return String.fromCharCode(parseInt(match[1], 16));
238
+ } else if (match = entityCode.match(/^#(\d+)$/)) {
239
+ return String.fromCharCode(~~match[1]);
240
+ } else {
241
+ return entity;
242
+ }
243
+ });
244
+ },
245
+
246
+ escapeRegExp: function(str){
247
+ if (str == null) return '';
248
+ return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
249
+ },
250
+
251
+ splice: function(str, i, howmany, substr){
252
+ var arr = _s.chars(str);
253
+ arr.splice(~~i, ~~howmany, substr);
254
+ return arr.join('');
255
+ },
256
+
257
+ insert: function(str, i, substr){
258
+ return _s.splice(str, i, 0, substr);
259
+ },
260
+
261
+ include: function(str, needle){
262
+ if (needle === '') return true;
263
+ if (str == null) return false;
264
+ return String(str).indexOf(needle) !== -1;
265
+ },
266
+
267
+ join: function() {
268
+ var args = slice.call(arguments),
269
+ separator = args.shift();
270
+
271
+ if (separator == null) separator = '';
272
+
273
+ return args.join(separator);
274
+ },
275
+
276
+ lines: function(str) {
277
+ if (str == null) return [];
278
+ return String(str).split("\n");
279
+ },
280
+
281
+ reverse: function(str){
282
+ return _s.chars(str).reverse().join('');
283
+ },
284
+
285
+ startsWith: function(str, starts){
286
+ if (starts === '') return true;
287
+ if (str == null || starts == null) return false;
288
+ str = String(str); starts = String(starts);
289
+ return str.length >= starts.length && str.slice(0, starts.length) === starts;
290
+ },
291
+
292
+ endsWith: function(str, ends){
293
+ if (ends === '') return true;
294
+ if (str == null || ends == null) return false;
295
+ str = String(str); ends = String(ends);
296
+ return str.length >= ends.length && str.slice(str.length - ends.length) === ends;
297
+ },
298
+
299
+ succ: function(str){
300
+ if (str == null) return '';
301
+ str = String(str);
302
+ return str.slice(0, -1) + String.fromCharCode(str.charCodeAt(str.length-1) + 1);
303
+ },
304
+
305
+ titleize: function(str){
306
+ if (str == null) return '';
307
+ return String(str).replace(/(?:^|\s)\S/g, function(c){ return c.toUpperCase(); });
308
+ },
309
+
310
+ camelize: function(str){
311
+ return _s.trim(str).replace(/[-_\s]+(.)?/g, function(match, c){ return c.toUpperCase(); });
312
+ },
313
+
314
+ underscored: function(str){
315
+ return _s.trim(str).replace(/([a-z\d])([A-Z]+)/g, '$1_$2').replace(/[-\s]+/g, '_').toLowerCase();
316
+ },
317
+
318
+ dasherize: function(str){
319
+ return _s.trim(str).replace(/([A-Z])/g, '-$1').replace(/[-_\s]+/g, '-').toLowerCase();
320
+ },
321
+
322
+ classify: function(str){
323
+ return _s.titleize(String(str).replace(/_/g, ' ')).replace(/\s/g, '');
324
+ },
325
+
326
+ humanize: function(str){
327
+ return _s.capitalize(_s.underscored(str).replace(/_id$/,'').replace(/_/g, ' '));
328
+ },
329
+
330
+ trim: function(str, characters){
331
+ if (str == null) return '';
332
+ if (!characters && nativeTrim) return nativeTrim.call(str);
333
+ characters = defaultToWhiteSpace(characters);
334
+ return String(str).replace(new RegExp('\^' + characters + '+|' + characters + '+$', 'g'), '');
335
+ },
336
+
337
+ ltrim: function(str, characters){
338
+ if (str == null) return '';
339
+ if (!characters && nativeTrimLeft) return nativeTrimLeft.call(str);
340
+ characters = defaultToWhiteSpace(characters);
341
+ return String(str).replace(new RegExp('^' + characters + '+'), '');
342
+ },
343
+
344
+ rtrim: function(str, characters){
345
+ if (str == null) return '';
346
+ if (!characters && nativeTrimRight) return nativeTrimRight.call(str);
347
+ characters = defaultToWhiteSpace(characters);
348
+ return String(str).replace(new RegExp(characters + '+$'), '');
349
+ },
350
+
351
+ truncate: function(str, length, truncateStr){
352
+ if (str == null) return '';
353
+ str = String(str); truncateStr = truncateStr || '...';
354
+ length = ~~length;
355
+ return str.length > length ? str.slice(0, length) + truncateStr : str;
356
+ },
357
+
358
+ /**
359
+ * _s.prune: a more elegant version of truncate
360
+ * prune extra chars, never leaving a half-chopped word.
361
+ * @author github.com/rwz
362
+ */
363
+ prune: function(str, length, pruneStr){
364
+ if (str == null) return '';
365
+
366
+ str = String(str); length = ~~length;
367
+ pruneStr = pruneStr != null ? String(pruneStr) : '...';
368
+
369
+ if (str.length <= length) return str;
370
+
371
+ var tmpl = function(c){ return c.toUpperCase() !== c.toLowerCase() ? 'A' : ' '; },
372
+ template = str.slice(0, length+1).replace(/.(?=\W*\w*$)/g, tmpl); // 'Hello, world' -> 'HellAA AAAAA'
373
+
374
+ if (template.slice(template.length-2).match(/\w\w/))
375
+ template = template.replace(/\s*\S+$/, '');
376
+ else
377
+ template = _s.rtrim(template.slice(0, template.length-1));
378
+
379
+ return (template+pruneStr).length > str.length ? str : str.slice(0, template.length)+pruneStr;
380
+ },
381
+
382
+ words: function(str, delimiter) {
383
+ if (_s.isBlank(str)) return [];
384
+ return _s.trim(str, delimiter).split(delimiter || /\s+/);
385
+ },
386
+
387
+ pad: function(str, length, padStr, type) {
388
+ str = str == null ? '' : String(str);
389
+ length = ~~length;
390
+
391
+ var padlen = 0;
392
+
393
+ if (!padStr)
394
+ padStr = ' ';
395
+ else if (padStr.length > 1)
396
+ padStr = padStr.charAt(0);
397
+
398
+ switch(type) {
399
+ case 'right':
400
+ padlen = length - str.length;
401
+ return str + strRepeat(padStr, padlen);
402
+ case 'both':
403
+ padlen = length - str.length;
404
+ return strRepeat(padStr, Math.ceil(padlen/2)) + str
405
+ + strRepeat(padStr, Math.floor(padlen/2));
406
+ default: // 'left'
407
+ padlen = length - str.length;
408
+ return strRepeat(padStr, padlen) + str;
409
+ }
410
+ },
411
+
412
+ lpad: function(str, length, padStr) {
413
+ return _s.pad(str, length, padStr);
414
+ },
415
+
416
+ rpad: function(str, length, padStr) {
417
+ return _s.pad(str, length, padStr, 'right');
418
+ },
419
+
420
+ lrpad: function(str, length, padStr) {
421
+ return _s.pad(str, length, padStr, 'both');
422
+ },
423
+
424
+ sprintf: sprintf,
425
+
426
+ vsprintf: function(fmt, argv){
427
+ argv.unshift(fmt);
428
+ return sprintf.apply(null, argv);
429
+ },
430
+
431
+ toNumber: function(str, decimals) {
432
+ if (str == null || str == '') return 0;
433
+ str = String(str);
434
+ var num = parseNumber(parseNumber(str).toFixed(~~decimals));
435
+ return num === 0 && !str.match(/^0+$/) ? Number.NaN : num;
436
+ },
437
+
438
+ numberFormat : function(number, dec, dsep, tsep) {
439
+ if (isNaN(number) || number == null) return '';
440
+
441
+ number = number.toFixed(~~dec);
442
+ tsep = tsep || ',';
443
+
444
+ var parts = number.split('.'), fnums = parts[0],
445
+ decimals = parts[1] ? (dsep || '.') + parts[1] : '';
446
+
447
+ return fnums.replace(/(\d)(?=(?:\d{3})+$)/g, '$1' + tsep) + decimals;
448
+ },
449
+
450
+ strRight: function(str, sep){
451
+ if (str == null) return '';
452
+ str = String(str); sep = sep != null ? String(sep) : sep;
453
+ var pos = !sep ? -1 : str.indexOf(sep);
454
+ return ~pos ? str.slice(pos+sep.length, str.length) : str;
455
+ },
456
+
457
+ strRightBack: function(str, sep){
458
+ if (str == null) return '';
459
+ str = String(str); sep = sep != null ? String(sep) : sep;
460
+ var pos = !sep ? -1 : str.lastIndexOf(sep);
461
+ return ~pos ? str.slice(pos+sep.length, str.length) : str;
462
+ },
463
+
464
+ strLeft: function(str, sep){
465
+ if (str == null) return '';
466
+ str = String(str); sep = sep != null ? String(sep) : sep;
467
+ var pos = !sep ? -1 : str.indexOf(sep);
468
+ return ~pos ? str.slice(0, pos) : str;
469
+ },
470
+
471
+ strLeftBack: function(str, sep){
472
+ if (str == null) return '';
473
+ str += ''; sep = sep != null ? ''+sep : sep;
474
+ var pos = str.lastIndexOf(sep);
475
+ return ~pos ? str.slice(0, pos) : str;
476
+ },
477
+
478
+ toSentence: function(array, separator, lastSeparator, serial) {
479
+ separator = separator || ', '
480
+ lastSeparator = lastSeparator || ' and '
481
+ var a = array.slice(), lastMember = a.pop();
482
+
483
+ if (array.length > 2 && serial) lastSeparator = _s.rtrim(separator) + lastSeparator;
484
+
485
+ return a.length ? a.join(separator) + lastSeparator + lastMember : lastMember;
486
+ },
487
+
488
+ toSentenceSerial: function() {
489
+ var args = slice.call(arguments);
490
+ args[3] = true;
491
+ return _s.toSentence.apply(_s, args);
492
+ },
493
+
494
+ slugify: function(str) {
495
+ if (str == null) return '';
496
+
497
+ var from = "ąàáäâãåæćęèéëêìíïîłńòóöôõøùúüûñçżź",
498
+ to = "aaaaaaaaceeeeeiiiilnoooooouuuunczz",
499
+ regex = new RegExp(defaultToWhiteSpace(from), 'g');
500
+
501
+ str = String(str).toLowerCase().replace(regex, function(c){
502
+ var index = from.indexOf(c);
503
+ return to.charAt(index) || '-';
504
+ });
505
+
506
+ return _s.dasherize(str.replace(/[^\w\sабвгдеёжзийклмнопрстуфхцчшщъыьэюя-]/g, ''));
507
+ },
508
+
509
+ surround: function(str, wrapper) {
510
+ return [wrapper, str, wrapper].join('');
511
+ },
512
+
513
+ quote: function(str) {
514
+ return _s.surround(str, '"');
515
+ },
516
+
517
+ exports: function() {
518
+ var result = {};
519
+
520
+ for (var prop in this) {
521
+ if (!this.hasOwnProperty(prop) || prop.match(/^(?:include|contains|reverse)$/)) continue;
522
+ result[prop] = this[prop];
523
+ }
524
+
525
+ return result;
526
+ },
527
+
528
+ repeat: function(str, qty, separator){
529
+ if (str == null) return '';
530
+
531
+ qty = ~~qty;
532
+
533
+ // using faster implementation if separator is not needed;
534
+ if (separator == null) return strRepeat(String(str), qty);
535
+
536
+ // this one is about 300x slower in Google Chrome
537
+ for (var repeat = []; qty > 0; repeat[--qty] = str) {}
538
+ return repeat.join(separator);
539
+ },
540
+
541
+ levenshtein: function(str1, str2) {
542
+ if (str1 == null && str2 == null) return 0;
543
+ if (str1 == null) return String(str2).length;
544
+ if (str2 == null) return String(str1).length;
545
+
546
+ str1 = String(str1); str2 = String(str2);
547
+
548
+ var current = [], prev, value;
549
+
550
+ for (var i = 0; i <= str2.length; i++)
551
+ for (var j = 0; j <= str1.length; j++) {
552
+ if (i && j)
553
+ if (str1.charAt(j - 1) === str2.charAt(i - 1))
554
+ value = prev;
555
+ else
556
+ value = Math.min(current[j], current[j - 1], prev) + 1;
557
+ else
558
+ value = i + j;
559
+
560
+ prev = current[j];
561
+ current[j] = value;
562
+ }
563
+
564
+ return current.pop();
565
+ }
566
+ };
567
+
568
+ // Aliases
569
+
570
+ _s.strip = _s.trim;
571
+ _s.lstrip = _s.ltrim;
572
+ _s.rstrip = _s.rtrim;
573
+ _s.center = _s.lrpad;
574
+ _s.rjust = _s.lpad;
575
+ _s.ljust = _s.rpad;
576
+ _s.contains = _s.include;
577
+ _s.q = _s.quote;
578
+
579
+ // CommonJS module is defined
580
+ if (typeof exports !== 'undefined') {
581
+ if (typeof module !== 'undefined' && module.exports) {
582
+ // Export module
583
+ module.exports = _s;
584
+ }
585
+ exports._s = _s;
586
+
587
+ } else if (typeof define === 'function' && define.amd) {
588
+ // Register as a named module with AMD.
589
+ define('underscore.string', [], function() {
590
+ return _s;
591
+ });
592
+
593
+ } else {
594
+ // Integrate with Underscore.js if defined
595
+ // or create our own underscore object.
596
+ root._ = root._ || {};
597
+ root._.string = root._.str = _s;
598
+ }
599
+
600
+ }(this, String);