133""" Make escape_string function """134big_sub_b=_big_sub_b135unicode_,str_,isinstance_=unicode,str,isinstance136escape_inlined_,norm_enc=escape_inlined,_norm_enc137138need_solid='\\'.encode('string_escape')=='\\'139need_solid_u=u'\\'.encode('unicode_escape')=='\\'140need_apos="'".encode('string_escape')=="'"141need_apos_u=u"'".encode('unicode_escape')=="'"142need_quote='"'.encode('string_escape')=='"'143need_quote_u=u'"'.encode('unicode_escape')=='"'144145defescape_string(toescape,inlined=True,encoding=None):146"""147 Escape a string for JS output (to be inserted into a JS string)148149 This function is one of the building blocks of the150 `tdi.tools.javascript.replace` function. You probably shouldn't151 use it directly in your rendering code.152153 :See:154 - `tdi.tools.javascript.fill`155 - `tdi.tools.javascript.fill_attr`156 - `tdi.tools.javascript.replace`157158 :Parameters:159 `toescape` : ``basestring``160 The string to escape161162 `inlined` : ``bool``163 Do additional escapings (possibly needed for inlining the script164 within a HTML page)?165166 `encoding` : ``str``167 Encoding in case that toescape is a ``str``. If omitted or168 ``None``, no encoding is applied and `toescape` is expected to be169 ASCII compatible.170171 :Return: The escaped string (ascii)172 :Rtype: ``str``173 """174# pylint: disable = redefined-outer-name175176isuni=isinstance_(toescape,unicode_)177ifisuniorencodingisnotNone:178ifnotisuni:179# don't decode ascii, but latin-1. just in case, if it's a180# dumb default. The result is similar to encoding = None.181ifnorm_enc(encoding)=='ascii':182encoding='latin-1'183toescape=str_(toescape).decode(encoding)184ifneed_solid_u:185toescape=toescape.replace(u'\\',u'\\\\')186result=big_sub_b(toescape.encode('unicode_escape'))187ifneed_apos_u:188result=result.replace("'","\\'")189ifneed_quote_u:190result=result.replace('"','\\"')191else:192result=str_(toescape)193ifneed_solid:194result=result.replace('\\','\\\\')195result=result.encode('string_escape')196ifneed_apos:197result=result.replace("'","\\'")198ifneed_quote:199result=result.replace('"','\\"')200201ifinlined:202returnescape_inlined_(result)203returnresult

211""" Make replace function """212default_sub=_re.compile(ur'__(?P<name>[^_]*(?:_[^_]+)*)__').sub213escape_string_,getattr_,unicode_=escape_string,getattr,unicode214isinstance_,escape_inlined_,str_=isinstance,escape_inlined,str215big_sub,small_sub,norm_enc=_big_sub,_small_sub,_norm_enc216217defreplace(script,holders,pattern=None,as_json=True,inlined=True,218encoding=None):219"""220 Replace javascript values221222 See `fill` and `fill_attr` for more specific usage.223224 This functions provides safe (single pass) javascript value225 replacement::226227 filled = javascript.replace(script_template, dict(228 a=10,229 b=u'Andr\\xe9',230 c=javascript.SimpleJSON(dict(foo='bar')),231 ))232233 Where script_template is something like::234235 // more script...236 var count = __a__;237 var name = '__b__';238 var param = __c__;239 // more script...240241 :See:242 - `fill`243 - `fill_attr`244245 :Parameters:246 `script` : ``basestring``247 Script content to modify248249 `holders` : ``dict``250 Placeholders mappings (name -> value). If a placeholder is found251 within the script which has no mapping, it's simply left as-is.252 If `as_json` is true, the values are checked if they have an253 ``as_json`` method. *If* they do have one, the method is called254 and the result (of type ``unicode``) is used as replacement.255 Otherwise the mapped value is piped through the `escape_string`256 function and that result is used as replacement. ``as_json`` is257 passed a boolean ``inlined`` parameter which indicates whether the258 method should escape for inline usage or not.259260 Use the `LiteralJSON` class for passing any JSON content literally261 to the script. There is also a `SimpleJSON` class for converting262 complex structures to JSON using the simplejson converter. You may263 pass your own classes as well, of course, as long as they provide264 a proper ``as_json()`` method.265266 `pattern` : ``unicode`` or compiled ``re`` object267 Placeholder name pattern. If omitted or ``None``, the pattern is268 (simplified [#]_): ``__(?P<name>.+)__``, i.e. the placeholder name269 enclosed in double-underscores. The name group is expected.270271 .. [#] The actual pattern is: ``__(?P<name>[^_]*(?:_[^_]+)*)__``272273 `as_json` : ``bool``274 Check the placeholder values for an ``as_json`` method? See the275 description of the `holders` parameter for details.276277 `inlined` : ``bool``278 Escape simple content for being inlined (e.g.279 no CDATA endmarkers, ``</script>``).280281 `encoding` : ``str``282 Script encoding if `script` is a ``str``. If omitted or ``None``,283 the script is expected to be ASCII compatible.284285 If ``script`` is of type ``unicode``, the encoding is applied to286 ``as_json`` method return values. This is to make sure, the JSON287 stuff is encoded safely. If omitted or ``None``, ASCII is assumed.288 JSON result characters not fitting into the this encoding are289 escaped (\\uxxxx).290291 :Return: The modified script, typed as input292 :Rtype: ``basestring``293 """294# pylint: disable = redefined-outer-name295296ifnotholders:297returnscript298isuni=isinstance_(script,unicode_)299ifisuni:300ifencodingisNone:301json_encoding='ascii'302else:303json_encoding=encoding304else:305ifencodingisNone:306encoding='latin-1'307json_encoding='ascii'308else:309json_encoding=encoding310# don't decode ascii, but latin-1. just in case, if it's a311# dumb default. Doesn't hurt here, but avoids failures.312ifnorm_enc(encoding)=='ascii':313encoding='latin-1'314script=str_(script).decode(encoding)315ifpatternisNone:316pattern=default_sub317else:318pattern=_re.compile(pattern).sub319320defsimple_subber(match):321""" Substitution function without checking .as_json() """322name=match.group(u'name')323ifnameandnameinholders:324returnescape_string_(325holders[name],encoding=encoding,inlined=inlined326).decode('ascii')327returnmatch.group(0)

360"""361 Replace javascript values in a script node362363 This functions provides safe (single pass) javascript value364 replacement (utilizing the `replace` function)::365366 javascript.fill(node, dict(367 a=10,368 b=u'Andr\\xe9',369 c=javascript.SimpleJSON(dict(foo='bar')),370 ))371372 Where `node` is something like::373374 <script tdi="name">375 var count = __a__;376 var name = '__b__';377 var param = __c__;378 </script>379380 :See:381 - `fill_attr`382 - `replace`383384 :Parameters:385 `node` : TDI node386 The script node387388 `holders` : ``dict``389 Placeholders mappings (name -> value). If a placeholder is found390 within the script which has no mapping, it's simply left as-is.391 If `as_json` is true, the values are checked if they have an392 ``as_json`` method. *If* they do have one, the method is called393 and the result (of type ``unicode``) is used as replacement.394 Otherwise the mapped value is piped through the `escape_string`395 function and the result is used as replacement. ``as_json`` is396 passed a boolean ``inlined`` parameter which indicates whether the397 method should escape for inline usage or not.398399 Use the `LiteralJSON` class for passing any JSON content literally400 to the script. There is also a `SimpleJSON` class for converting401 complex structures to JSON using the simplejson converter. You may402 pass your own classes as well, of course, as long as they provide403 a proper ``as_json()`` method.404405 `pattern` : ``unicode`` or compiled ``re`` object406 Placeholder name pattern. If omitted or ``None``, the pattern is407 (simplified [#]_): ``__(?P<name>.+)__``, i.e. the placeholder name408 enclosed in double-underscores. The name group is expected.409410 .. [#] The actual pattern is: ``__(?P<name>[^_]*(?:_[^_]+)*)__``411412 `as_json` : ``bool``413 Check the placeholder values for an ``as_json`` method? See the414 description of the `holders` parameter for details.415 """416node.raw.content=replace(417node.raw.content,418holders,419pattern=pattern,420as_json=as_json,421inlined=True,422encoding=node.raw.encoder.encoding,423)

427"""428 Replace javascript values in a script attribute429430 This functions provides safe (single pass) javascript value431 replacement (utilizing the `replace` function)::432433 javascript.fill_attr(node, u'onclick', dict(434 a=10,435 b=u'Andr\\xe9',436 c=javascript.SimpleJSON(dict(foo='bar')),437 ))438439 Where `node` is something like::440441 <div onclick="return foo(__a__)">...</div>442443 :See:444 - `fill`445 - `replace`446447 :Parameters:448 `node` : TDI node449 The script node450451 `attr` : ``basestring``452 The name of the attribute453454 `holders` : ``dict``455 Placeholders mappings (name -> value). If a placeholder is found456 within the script which has no mapping, it's simply left as-is.457 If `as_json` is true, the values are checked if they have an458 ``as_json`` method. *If* they do have one, the method is called459 and the result (of type ``unicode``) is used as replacement.460 Otherwise the mapped value is piped through the `escape_string`461 function and that result is used as replacement. ``as_json`` is462 passed a boolean ``inlined`` parameter which indicates whether the463 method should escape for inline usage or not.464465 Use the `LiteralJSON` class for passing any JSON content literally466 to the script. There is also a `SimpleJSON` class for converting467 complex structures to JSON using the simplejson converter. You may468 pass your own classes as well, of course, as long as they provide469 a proper ``as_json()`` method.470471 `pattern` : ``unicode`` or compiled ``re`` object472 Placeholder name pattern. If omitted or ``None``, the pattern is473 (simplified [#]_): ``__(?P<name>.+)__``, i.e. the placeholder name474 enclosed in double-underscores. The name group is expected.475476 .. [#] The actual pattern is: ``__(?P<name>[^_]*(?:_[^_]+)*)__``477478 `as_json` : ``bool``479 Check the placeholder values for an ``as_json`` method? See the480 description of the `holders` parameter for details.481 """482encoding=node.raw.encoder.encoding483node[attr]=replace(484_htmldecode.decode(node[attr],encoding=encoding),holders,485pattern=pattern,486as_json=as_json,487inlined=False,488encoding=encoding,489)

863"""864 Handle endtag865866 When currently collecting, it must be a script endtag. The script867 element content is then modified (using the modifiy function passed868 during initialization). The result replaces the original. If it's869 empty and the starttag neither provides ``src`` nor ``tdi`` attributes870 and the filter was configured to do so: the whole element is thrown871 away.872873 :See: `tdi.interfaces.ListenerInterface`874 """875normalize=self._normalize876ifself._collecting:877ifnormalize(name)!='script':878raiseAssertionError("Invalid event stream")879880self._collecting=False881script,self._buffer=''.join(self._buffer),[]882script=self._modify(script)883884ifnotscriptandself._strip:885attrdict=dict((886normalize(name),val887)forname,valinself._starttag[1])888ifnormalize('src')notinattrdict:889ifself._attributeisNoneor \ 890self._attributenotinattrdict:891return892893self.builder.handle_starttag(*self._starttag)894self._starttag=None895self.builder.handle_text(script)896897self.builder.handle_endtag(name,data)