From 618c8bb5adf85c04a68bf44659b80201691b1a6a Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 30 Jan 2014 09:38:01 -0800 Subject: [PATCH] Add ` as a character to escape/unescape and a doc note on unquoted html attribute values. --- dist/lodash.compat.js | 21 +++++++++++++-------- dist/lodash.compat.min.js | 4 ++-- dist/lodash.js | 21 +++++++++++++-------- dist/lodash.min.js | 4 ++-- dist/lodash.underscore.js | 21 +++++++++++++-------- dist/lodash.underscore.min.js | 2 +- lodash.js | 21 +++++++++++++-------- test/test.js | 8 ++++---- 8 files changed, 61 insertions(+), 41 deletions(-) diff --git a/dist/lodash.compat.js b/dist/lodash.compat.js index 251ee2dd5..6ca8689e6 100644 --- a/dist/lodash.compat.js +++ b/dist/lodash.compat.js @@ -41,8 +41,8 @@ reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g; /** Used to match HTML entities and HTML characters */ - var reEscapedHtml = /&(?:amp|lt|gt|quot|#39);/g, - reUnescapedHtml = /[&<>"']/g; + var reEscapedHtml = /&(?:amp|lt|gt|quot|#39|#96);/g, + reUnescapedHtml = /[&<>"'`]/g; /** Used to match template delimiters */ var reEscape = /<%-([\s\S]+?)%>/g, @@ -153,7 +153,8 @@ '<': '<', '>': '>', '"': '"', - "'": ''' + "'": ''', + '`': '`' }; /** Used to convert HTML entities to characters */ @@ -162,7 +163,8 @@ '<': '<', '>': '>', '"': '"', - ''': "'" + ''': "'", + '`': '`' }; /** Used to determine if values are of the language type Object */ @@ -6568,11 +6570,14 @@ } /** - * Converts the characters `&`, `<`, `>`, `"`, and `'` in `string` to + * Converts the characters `&`, `<`, `>`, `"`, `'`, and ``` in `string` to * their corresponding HTML entities. * * Note: No other characters are escaped. To escape additional characters - * use a third-party library like [_he_](http://mths.be/he). + * use a third-party library like [_he_](http://mths.be/he). When working + * with HTML you should always quote attribute values to reduce XSS vectors. + * See [Ryan Grove's article](http://wonko.com/post/html-escaping) for more + * details. * * @static * @memberOf _ @@ -6848,8 +6853,8 @@ /** * The inverse of `_.escape`; this method converts the HTML entities - * `&`, `<`, `>`, `"`, and `'` in `string` to their - * corresponding characters. + * `&`, `<`, `>`, `"`, `'`, and ``` in `string` to + * their corresponding characters. * * Note: No other HTML entities are unescaped. To unescape additional HTML * entities use a third-party library like [_he_](http://mths.be/he). diff --git a/dist/lodash.compat.min.js b/dist/lodash.compat.min.js index 9c51d5875..92d936391 100644 --- a/dist/lodash.compat.min.js +++ b/dist/lodash.compat.min.js @@ -63,6 +63,6 @@ n.replace(l,function(t,r,e,u,a,l){return e||(e=u),c+=n.slice(i,l).replace(X,f),r }catch(s){throw s.source=c,s}return t?p(t):(p.source=c,p)},u.trim=we,u.trimLeft=je,u.trimRight=xe,u.unescape=function(n){return null==n?"":(n=Cr(n),0>n.indexOf(";")?n:n.replace(F,b))},u.uniqueId=function(n){var t=++R;return Cr(null==n?"":n)+t},u.all=zt,u.any=Yt,u.detect=Mt,u.findWhere=Mt,u.foldl=Ht,u.foldr=Jt,u.include=Wt,u.inject=Ht,gr(function(){var n={};return dt(u,function(t,r){u.prototype[r]||(n[r]=t)}),n}(),false),u.first=Rt,u.last=function(n,t,r){var e=0,o=n?n.length:0;if(typeof t!="number"&&null!=t){var a=o; for(t=u.createCallback(t,r,3);a--&&t(n[a],a,n);)e++}else if(e=t,null==e||r)return n?n[o-1]:w;return e=o-e,qt(n,0"']/g,L=/<%-([\s\S]+?)%>/g,B=/<%([\s\S]+?)%>/g,D=/<%=([\s\S]+?)%>/g,W=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,z=/\w*$/,K=/^\s*function[ \n\r\t]+\w/,M=/^0[xX]/,U=/($^)/,V=/\bthis\b/,X=/['\n\r\t\u2028\u2029\\]/g,G=" \t\x0B\f\xa0\ufeff\n\r\u2028\u2029\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000",H=[],J=[],Q="Array Boolean Date Error Function Math Number Object RegExp Set String _ clearTimeout document isFinite isNaN parseInt setTimeout TypeError window WinRTError".split(" "),Y="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" "),Z="[object Arguments]",nt="[object Array]",tt="[object Boolean]",rt="[object Date]",et="[object Error]",ut="[object Function]",ot="[object Number]",at="[object Object]",it="[object RegExp]",lt="[object String]",ft={}; -ft[ut]=false,ft[Z]=ft[nt]=ft[tt]=ft[rt]=ft[ot]=ft[at]=ft[it]=ft[lt]=true;var ct={leading:false,maxWait:0,trailing:false},pt={configurable:false,enumerable:false,value:null,writable:false},st={"&":"&","<":"<",">":">",'"':""","'":"'"},gt={"&":"&","<":"<",">":">",""":'"',"'":"'"},ht={"function":true,object:true},vt={"\\":"\\","'":"'","\n":"n","\r":"r","\t":"t","\u2028":"u2028","\u2029":"u2029"},yt=ht[typeof window]&&window||this,mt=ht[typeof exports]&&exports&&!exports.nodeType&&exports,ht=ht[typeof module]&&module&&!module.nodeType&&module,dt=mt&&ht&&typeof global=="object"&&global; +u.prototype[n]=function(){return new o(t.apply(this.__wrapped__,arguments),this.__chain__)}}),fe.spliceObjects||ht(["pop","shift","splice"],function(n){var t=Or[n],r="splice"==n;u.prototype[n]=function(){var n=this.__chain__,e=this.__wrapped__,u=t.apply(e,arguments);return 0===e.length&&delete e[0],n||r?new o(u,n):u}}),u}var w,j=1,x=2,C=4,k=8,O=16,E=32,S=40,A=40,I="2.4.1",N="__lodash@"+I+"__",R=0,T=/\b__p\+='';/g,P=/\b(__p\+=)''\+/g,q=/(__e\(.*?\)|\b__t\))\+'';/g,F=/&(?:amp|lt|gt|quot|#39|#96);/g,$=/[&<>"'`]/g,L=/<%-([\s\S]+?)%>/g,B=/<%([\s\S]+?)%>/g,D=/<%=([\s\S]+?)%>/g,W=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,z=/\w*$/,K=/^\s*function[ \n\r\t]+\w/,M=/^0[xX]/,U=/($^)/,V=/\bthis\b/,X=/['\n\r\t\u2028\u2029\\]/g,G=" \t\x0B\f\xa0\ufeff\n\r\u2028\u2029\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000",H=[],J=[],Q="Array Boolean Date Error Function Math Number Object RegExp Set String _ clearTimeout document isFinite isNaN parseInt setTimeout TypeError window WinRTError".split(" "),Y="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" "),Z="[object Arguments]",nt="[object Array]",tt="[object Boolean]",rt="[object Date]",et="[object Error]",ut="[object Function]",ot="[object Number]",at="[object Object]",it="[object RegExp]",lt="[object String]",ft={}; +ft[ut]=false,ft[Z]=ft[nt]=ft[tt]=ft[rt]=ft[ot]=ft[at]=ft[it]=ft[lt]=true;var ct={leading:false,maxWait:0,trailing:false},pt={configurable:false,enumerable:false,value:null,writable:false},st={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},gt={"&":"&","<":"<",">":">",""":'"',"'":"'","`":"`"},ht={"function":true,object:true},vt={"\\":"\\","'":"'","\n":"n","\r":"r","\t":"t","\u2028":"u2028","\u2029":"u2029"},yt=ht[typeof window]&&window||this,mt=ht[typeof exports]&&exports&&!exports.nodeType&&exports,ht=ht[typeof module]&&module&&!module.nodeType&&module,dt=mt&&ht&&typeof global=="object"&&global; !dt||dt.global!==dt&&dt.window!==dt&&dt.self!==dt||(yt=dt);var dt=ht&&ht.exports===mt&&mt,bt=_();typeof define=="function"&&typeof define.amd=="object"&&define.amd?(yt._=bt, define(function(){return bt})):mt&&ht?dt?(ht.exports=bt)._=bt:mt._=bt:yt._=bt}).call(this); \ No newline at end of file diff --git a/dist/lodash.js b/dist/lodash.js index dce847929..dd7994aec 100644 --- a/dist/lodash.js +++ b/dist/lodash.js @@ -41,8 +41,8 @@ reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g; /** Used to match HTML entities and HTML characters */ - var reEscapedHtml = /&(?:amp|lt|gt|quot|#39);/g, - reUnescapedHtml = /[&<>"']/g; + var reEscapedHtml = /&(?:amp|lt|gt|quot|#39|#96);/g, + reUnescapedHtml = /[&<>"'`]/g; /** Used to match template delimiters */ var reEscape = /<%-([\s\S]+?)%>/g, @@ -146,7 +146,8 @@ '<': '<', '>': '>', '"': '"', - "'": ''' + "'": ''', + '`': '`' }; /** Used to convert HTML entities to characters */ @@ -155,7 +156,8 @@ '<': '<', '>': '>', '"': '"', - ''': "'" + ''': "'", + '`': '`' }; /** Used to determine if values are of the language type Object */ @@ -6289,11 +6291,14 @@ } /** - * Converts the characters `&`, `<`, `>`, `"`, and `'` in `string` to + * Converts the characters `&`, `<`, `>`, `"`, `'`, and ``` in `string` to * their corresponding HTML entities. * * Note: No other characters are escaped. To escape additional characters - * use a third-party library like [_he_](http://mths.be/he). + * use a third-party library like [_he_](http://mths.be/he). When working + * with HTML you should always quote attribute values to reduce XSS vectors. + * See [Ryan Grove's article](http://wonko.com/post/html-escaping) for more + * details. * * @static * @memberOf _ @@ -6569,8 +6574,8 @@ /** * The inverse of `_.escape`; this method converts the HTML entities - * `&`, `<`, `>`, `"`, and `'` in `string` to their - * corresponding characters. + * `&`, `<`, `>`, `"`, `'`, and ``` in `string` to + * their corresponding characters. * * Note: No other HTML entities are unescaped. To unescape additional HTML * entities use a third-party library like [_he_](http://mths.be/he). diff --git a/dist/lodash.min.js b/dist/lodash.min.js index 7f828d5f0..2c7a3befe 100644 --- a/dist/lodash.min.js +++ b/dist/lodash.min.js @@ -58,6 +58,6 @@ if(!n)return t;var r=Er.call(n),e=n.length;return r==Y||r==ot||r==Q||r==et&&type }),f+="';",a=r=r.variable,a||(r="obj",f="with("+r+"){"+f+"}"),f=(u?f.replace(I,""):f).replace(T,"$1").replace(F,"$1;"),f="function("+r+"){"+(a?"":r+"||("+r+"={});")+"var __t,__p='',__e=_.escape"+(u?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}":";")+f+"return __p}";try{var c=mr(e,"return "+f).apply(_,o)}catch(p){throw p.source=f,p}return t?c(t):(c.source=f,c)},y.trim=ve,y.trimLeft=ye,y.trimRight=me,y.unescape=function(n){return null==n?"":(n=kr(n),0>n.indexOf(";")?n:n.replace($,d)) },y.uniqueId=function(n){var t=++R;return kr(null==n?"":n)+t},y.all=zt,y.any=Jt,y.detect=Pt,y.findWhere=Pt,y.foldl=Xt,y.foldr=Gt,y.include=Wt,y.inject=Xt,pr(function(){var n={};return dt(y,function(t,r){y.prototype[r]||(n[r]=t)}),n}(),false),y.first=Nt,y.last=function(n,t,r){var e=0,u=n?n.length:0;if(typeof t!="number"&&null!=t){var o=u;for(t=y.createCallback(t,r,3);o--&&t(n[o],o,n);)e++}else if(e=t,null==e||r)return n?n[u-1]:_;return e=u-e,Tt(n,0"']/g,D=/<%-([\s\S]+?)%>/g,q=/<%([\s\S]+?)%>/g,W=/<%=([\s\S]+?)%>/g,z=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,L=/\w*$/,P=/^\s*function[ \n\r\t]+\w/,K=/^0[xX]/,M=/($^)/,U=/\bthis\b/,V=/['\n\r\t\u2028\u2029\\]/g,X=" \t\x0B\f\xa0\ufeff\n\r\u2028\u2029\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000",G=[],H=[],J="Array Boolean Date Function Math Number Object RegExp Set String _ clearTimeout document isFinite isNaN parseInt setTimeout TypeError window WinRTError".split(" "),Q="[object Arguments]",Y="[object Array]",Z="[object Boolean]",nt="[object Date]",tt="[object Function]",rt="[object Number]",et="[object Object]",ut="[object RegExp]",ot="[object String]",it={}; -it[tt]=false,it[Q]=it[Y]=it[Z]=it[nt]=it[rt]=it[et]=it[ut]=it[ot]=true;var at={leading:false,maxWait:0,trailing:false},ft={configurable:false,enumerable:false,value:null,writable:false},lt={"&":"&","<":"<",">":">",'"':""","'":"'"},ct={"&":"&","<":"<",">":">",""":'"',"'":"'"},pt={"function":true,object:true},st={"\\":"\\","'":"'","\n":"n","\r":"r","\t":"t","\u2028":"u2028","\u2029":"u2029"},gt=pt[typeof window]&&window||this,ht=pt[typeof exports]&&exports&&!exports.nodeType&&exports,pt=pt[typeof module]&&module&&!module.nodeType&&module,vt=ht&&pt&&typeof global=="object"&&global; +return n?new m(r,n):r}}),ht(["push","reverse","sort","unshift"],function(n){var t=xr[n];y.prototype[n]=function(){return t.apply(this.__wrapped__,arguments),this}}),ht(["concat","splice"],function(n){var t=xr[n];y.prototype[n]=function(){return new m(t.apply(this.__wrapped__,arguments),this.__chain__)}}),y}var _,w=1,k=2,j=4,x=8,C=16,O=32,A=40,S=40,E="2.4.1",N="__lodash@"+E+"__",R=0,I=/\b__p\+='';/g,T=/\b(__p\+=)''\+/g,F=/(__e\(.*?\)|\b__t\))\+'';/g,$=/&(?:amp|lt|gt|quot|#39|#96);/g,B=/[&<>"'`]/g,D=/<%-([\s\S]+?)%>/g,q=/<%([\s\S]+?)%>/g,W=/<%=([\s\S]+?)%>/g,z=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,L=/\w*$/,P=/^\s*function[ \n\r\t]+\w/,K=/^0[xX]/,M=/($^)/,U=/\bthis\b/,V=/['\n\r\t\u2028\u2029\\]/g,X=" \t\x0B\f\xa0\ufeff\n\r\u2028\u2029\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000",G=[],H=[],J="Array Boolean Date Function Math Number Object RegExp Set String _ clearTimeout document isFinite isNaN parseInt setTimeout TypeError window WinRTError".split(" "),Q="[object Arguments]",Y="[object Array]",Z="[object Boolean]",nt="[object Date]",tt="[object Function]",rt="[object Number]",et="[object Object]",ut="[object RegExp]",ot="[object String]",it={}; +it[tt]=false,it[Q]=it[Y]=it[Z]=it[nt]=it[rt]=it[et]=it[ut]=it[ot]=true;var at={leading:false,maxWait:0,trailing:false},ft={configurable:false,enumerable:false,value:null,writable:false},lt={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},ct={"&":"&","<":"<",">":">",""":'"',"'":"'","`":"`"},pt={"function":true,object:true},st={"\\":"\\","'":"'","\n":"n","\r":"r","\t":"t","\u2028":"u2028","\u2029":"u2029"},gt=pt[typeof window]&&window||this,ht=pt[typeof exports]&&exports&&!exports.nodeType&&exports,pt=pt[typeof module]&&module&&!module.nodeType&&module,vt=ht&&pt&&typeof global=="object"&&global; !vt||vt.global!==vt&&vt.window!==vt&&vt.self!==vt||(gt=vt);var vt=pt&&pt.exports===ht&&ht,yt=b();typeof define=="function"&&typeof define.amd=="object"&&define.amd?(gt._=yt, define(function(){return yt})):ht&&pt?vt?(pt.exports=yt)._=yt:ht._=yt:gt._=yt}).call(this); \ No newline at end of file diff --git a/dist/lodash.underscore.js b/dist/lodash.underscore.js index 6b4f07151..b2c0a4df0 100644 --- a/dist/lodash.underscore.js +++ b/dist/lodash.underscore.js @@ -33,8 +33,8 @@ var idCounter = 0; /** Used to match HTML entities and HTML characters */ - var reEscapedHtml = /&(?:amp|lt|gt|quot|#x27);/g, - reUnescapedHtml = /[&<>"']/g; + var reEscapedHtml = /&(?:amp|lt|gt|quot|#x27|#96);/g, + reUnescapedHtml = /[&<>"'`]/g; /** Used to match template delimiters */ var reEscape = /<%-([\s\S]+?)%>/g, @@ -71,7 +71,8 @@ '<': '<', '>': '>', '"': '"', - "'": ''' + "'": ''', + '`': '`' }; /** Used to convert HTML entities to characters */ @@ -80,7 +81,8 @@ '<': '<', '>': '>', '"': '"', - ''': "'" + ''': "'", + '`': '`' }; /** Used to determine if values are of the language type Object */ @@ -4417,11 +4419,14 @@ /*--------------------------------------------------------------------------*/ /** - * Converts the characters `&`, `<`, `>`, `"`, and `'` in `string` to + * Converts the characters `&`, `<`, `>`, `"`, `'`, and ``` in `string` to * their corresponding HTML entities. * * Note: No other characters are escaped. To escape additional characters - * use a third-party library like [_he_](http://mths.be/he). + * use a third-party library like [_he_](http://mths.be/he). When working + * with HTML you should always quote attribute values to reduce XSS vectors. + * See [Ryan Grove's article](http://wonko.com/post/html-escaping) for more + * details. * * @static * @memberOf _ @@ -4581,8 +4586,8 @@ /** * The inverse of `_.escape`; this method converts the HTML entities - * `&`, `<`, `>`, `"`, and `'` in `string` to their - * corresponding characters. + * `&`, `<`, `>`, `"`, `'`, and ``` in `string` to + * their corresponding characters. * * Note: No other HTML entities are unescaped. To unescape additional HTML * entities use a third-party library like [_he_](http://mths.be/he). diff --git a/dist/lodash.underscore.min.js b/dist/lodash.underscore.min.js index e3dd5fd18..1b0c9684a 100644 --- a/dist/lodash.underscore.min.js +++ b/dist/lodash.underscore.min.js @@ -20,7 +20,7 @@ if(typeof i=="number")for(u&&i&&(t=n[++o]);++o=y;m?(u&&(u=clearTimeout(u)),c=i,o=n.apply(f,e)):u||(u=setTimeout(h,y))}return m&&a?a=clearTimeout(a):a||r===p||(a=setTimeout(v,r)),t&&(m=true,o=n.apply(f,e)),!m||a||u||(e=f=null),o}}function P(n,r,t){if(!n)return n;var e=arguments,u=0,o=e.length,i=typeof t;for("number"!=i&&"string"!=i||!e[3]||e[3][t]!==r||(o=2);++u"']/g,vr=/($^)/,hr=/['\n\r\t\u2028\u2029\\]/g,yr="[object Arguments]",mr="[object Array]",br="[object Boolean]",_r="[object Date]",dr="[object Number]",wr="[object Object]",jr="[object RegExp]",xr="[object String]",Tr={"&":"&","<":"<",">":">",'"':""","'":"'"},Ar={"&":"&","<":"<",">":">",""":'"',"'":"'"},Er={"function":true,object:true},Or={"\\":"\\","'":"'","\n":"n","\r":"r","\t":"t","\u2028":"u2028","\u2029":"u2029"},Sr=Er[typeof window]&&window||this,kr=Er[typeof exports]&&exports&&!exports.nodeType&&exports,Nr=Er[typeof module]&&module&&!module.nodeType&&module,qr=kr&&Nr&&typeof global=="object"&&global; +}}function nr(n){for(var r=-1,t=V(n),e=t.length;++r"'`]/g,vr=/($^)/,hr=/['\n\r\t\u2028\u2029\\]/g,yr="[object Arguments]",mr="[object Array]",br="[object Boolean]",_r="[object Date]",dr="[object Number]",wr="[object Object]",jr="[object RegExp]",xr="[object String]",Tr={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},Ar={"&":"&","<":"<",">":">",""":'"',"'":"'","`":"`"},Er={"function":true,object:true},Or={"\\":"\\","'":"'","\n":"n","\r":"r","\t":"t","\u2028":"u2028","\u2029":"u2029"},Sr=Er[typeof window]&&window||this,kr=Er[typeof exports]&&exports&&!exports.nodeType&&exports,Nr=Er[typeof module]&&module&&!module.nodeType&&module,qr=kr&&Nr&&typeof global=="object"&&global; !qr||qr.global!==qr&&qr.window!==qr&&qr.self!==qr||(Sr=qr);var Fr=Nr&&Nr.exports===kr&&kr,Br=Array.prototype,Rr=Object.prototype,$r=Sr._,Ir=Rr.toString,Mr=RegExp("^"+(Ir+"").replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/toString|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),Dr=Math.ceil,Wr=Math.floor,zr=Function.prototype.toString,Cr=Rr.hasOwnProperty,Pr=Br.push,Ur=Rr.propertyIsEnumerable,Vr=Br.splice,Gr=d(Gr=Object.create)&&Gr,Hr=d(Hr=Array.isArray)&&Hr,Jr=Sr.isFinite,Kr=Sr.isNaN,Lr=d(Lr=Object.keys)&&Lr,Qr=Math.max,Xr=Math.min,Yr=d(Yr=Date.now)&&Yr,Zr=Math.random; i.prototype=o.prototype;var nt={};!function(){var n={0:1,length:1};nt.spliceObjects=(Vr.call(n,0,1),!n[0])}(1),o.templateSettings={escape:/<%-([\s\S]+?)%>/g,evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,variable:""},Gr||(a=function(){function n(){}return function(r){if(J(r)){n.prototype=r;var t=new n;n.prototype=null}return t||Sr.Object()}}()),w(arguments)||(w=function(n){return n&&typeof n=="object"&&typeof n.length=="number"&&Cr.call(n,"callee")&&!Ur.call(n,"callee")||false});var rt=function(n,r){if(!J(n))return n; for(var t in n)if(r(n[t],t,n)===cr)break;return n},tt=function(n){var r=[];if(!J(n))return r;for(var t in n)Cr.call(n,t)&&r.push(t);return r},et=m(function(n,r,t){Cr.call(n,t)?n[t]++:n[t]=1}),ut=m(function(n,r,t){Cr.call(n,t)?n[t].push(r):n[t]=[r]}),ot=m(function(n,r,t){n[t]=r}),it=B,ft=Hr||function(n){return n&&typeof n=="object"&&typeof n.length=="number"&&Ir.call(n)==mr||false};H(/x/)&&(H=function(n){return typeof n=="function"&&"[object Function]"==Ir.call(n)});var at=Lr?function(n){return J(n)?Lr(n):[] diff --git a/lodash.js b/lodash.js index b5ec95eb4..17102c2ab 100644 --- a/lodash.js +++ b/lodash.js @@ -40,8 +40,8 @@ reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g; /** Used to match HTML entities and HTML characters */ - var reEscapedHtml = /&(?:amp|lt|gt|quot|#39);/g, - reUnescapedHtml = /[&<>"']/g; + var reEscapedHtml = /&(?:amp|lt|gt|quot|#39|#96);/g, + reUnescapedHtml = /[&<>"'`]/g; /** Used to match template delimiters */ var reEscape = /<%-([\s\S]+?)%>/g, @@ -152,7 +152,8 @@ '<': '<', '>': '>', '"': '"', - "'": ''' + "'": ''', + '`': '`' }; /** Used to convert HTML entities to characters */ @@ -161,7 +162,8 @@ '<': '<', '>': '>', '"': '"', - ''': "'" + ''': "'", + '`': '`' }; /** Used to determine if values are of the language type Object */ @@ -6585,11 +6587,14 @@ } /** - * Converts the characters `&`, `<`, `>`, `"`, and `'` in `string` to + * Converts the characters `&`, `<`, `>`, `"`, `'`, and ``` in `string` to * their corresponding HTML entities. * * Note: No other characters are escaped. To escape additional characters - * use a third-party library like [_he_](http://mths.be/he). + * use a third-party library like [_he_](http://mths.be/he). When working + * with HTML you should always quote attribute values to reduce XSS vectors. + * See [Ryan Grove's article](http://wonko.com/post/html-escaping) for more + * details. * * @static * @memberOf _ @@ -6865,8 +6870,8 @@ /** * The inverse of `_.escape`; this method converts the HTML entities - * `&`, `<`, `>`, `"`, and `'` in `string` to their - * corresponding characters. + * `&`, `<`, `>`, `"`, `'`, and ``` in `string` to + * their corresponding characters. * * Note: No other HTML entities are unescaped. To unescape additional HTML * entities use a third-party library like [_he_](http://mths.be/he). diff --git a/test/test.js b/test/test.js index 39f052631..9905f1549 100644 --- a/test/test.js +++ b/test/test.js @@ -2146,8 +2146,8 @@ QUnit.module('lodash.escape'); (function() { - var escaped = '&<>"'\/', - unescaped = '&<>"\'\/'; + var escaped = '&<>"'`\/', + unescaped = '&<>"\'`\/'; test('should escape values', 1, function() { equal(_.escape(unescaped), escaped); @@ -8209,8 +8209,8 @@ QUnit.module('lodash.unescape'); (function() { - var escaped = '&<>"'\/', - unescaped = '&<>"\'\/'; + var escaped = '&<>"'`\/', + unescaped = '&<>"\'`\/'; test('should unescape entities in the correct order', 1, function() { equal(_.unescape('&lt;'), '<');