238 w = self.write |
238 w = self.write |
239 # 1/ variable declaration if any |
239 # 1/ variable declaration if any |
240 if self.jsvars: |
240 if self.jsvars: |
241 w(u'<script type="text/javascript"><!--//--><![CDATA[//><!--\n') |
241 w(u'<script type="text/javascript"><!--//--><![CDATA[//><!--\n') |
242 for var, value, override in self.jsvars: |
242 for var, value, override in self.jsvars: |
243 vardecl = u'%s = %s;' % (var, dumps(value)) |
243 vardecl = u'%s = %s;' % (var, json.dumps(value)) |
244 if not override: |
244 if not override: |
245 vardecl = (u'if (typeof %s == "undefined") {%s}' % |
245 vardecl = (u'if (typeof %s == "undefined") {%s}' % |
246 (var, vardecl)) |
246 (var, vardecl)) |
247 w(vardecl + u'\n') |
247 w(vardecl + u'\n') |
248 w(u'//--><!]]></script>\n') |
248 w(u'//--><!]]></script>\n') |
308 self.head.getvalue(), |
308 self.head.getvalue(), |
309 self.body.getvalue()) |
309 self.body.getvalue()) |
310 |
310 |
311 |
311 |
312 try: |
312 try: |
313 try: |
313 # may not be there if cubicweb-web not installed |
314 # may not be there if cubicweb-web not installed |
314 if sys.version_info < (2,6): |
315 from json import dumps, JSONEncoder |
315 import simplejson as json |
316 except ImportError: |
316 else: |
317 from simplejson import dumps, JSONEncoder |
317 import json |
318 except ImportError: |
318 except ImportError: |
319 pass |
319 pass |
320 else: |
320 else: |
321 |
321 |
322 class CubicWebJsonEncoder(JSONEncoder): |
322 class CubicWebJsonEncoder(json.JSONEncoder): |
323 """define a json encoder to be able to encode yams std types""" |
323 """define a json encoder to be able to encode yams std types""" |
324 |
324 |
325 # _iterencode is the only entry point I've found to use a custom encode |
325 # _iterencode is the only entry point I've found to use a custom encode |
326 # hook early enough: .default() is called if nothing else matched before, |
326 # hook early enough: .default() is called if nothing else matched before, |
327 # .iterencode() is called once on the main structure to encode and then |
327 # .iterencode() is called once on the main structure to encode and then |
328 # never gets called again. |
328 # never gets called again. |
329 # For the record, our main use case is in FormValidateController with: |
329 # For the record, our main use case is in FormValidateController with: |
330 # dumps((status, args, entity), cls=CubicWebJsonEncoder) |
330 # json.dumps((status, args, entity), cls=CubicWebJsonEncoder) |
331 # where we want all the entity attributes, including eid, to be part |
331 # where we want all the entity attributes, including eid, to be part |
332 # of the json object dumped. |
332 # of the json object dumped. |
333 # This would have once more been easier if Entity didn't extend dict. |
333 # This would have once more been easier if Entity didn't extend dict. |
334 def _iterencode(self, obj, markers=None): |
334 def _iterencode(self, obj, markers=None): |
335 if hasattr(obj, '__json_encode__'): |
335 if hasattr(obj, '__json_encode__'): |
336 obj = obj.__json_encode__() |
336 obj = obj.__json_encode__() |
337 return JSONEncoder._iterencode(self, obj, markers) |
337 return json.JSONEncoder._iterencode(self, obj, markers) |
338 |
338 |
339 def default(self, obj): |
339 def default(self, obj): |
340 if isinstance(obj, datetime.datetime): |
340 if isinstance(obj, datetime.datetime): |
341 return obj.strftime('%Y/%m/%d %H:%M:%S') |
341 return obj.strftime('%Y/%m/%d %H:%M:%S') |
342 elif isinstance(obj, datetime.date): |
342 elif isinstance(obj, datetime.date): |
346 elif isinstance(obj, datetime.timedelta): |
346 elif isinstance(obj, datetime.timedelta): |
347 return (obj.days * 24 * 60 * 60) + obj.seconds |
347 return (obj.days * 24 * 60 * 60) + obj.seconds |
348 elif isinstance(obj, decimal.Decimal): |
348 elif isinstance(obj, decimal.Decimal): |
349 return float(obj) |
349 return float(obj) |
350 try: |
350 try: |
351 return JSONEncoder.default(self, obj) |
351 return json.JSONEncoder.default(self, obj) |
352 except TypeError: |
352 except TypeError: |
353 # we never ever want to fail because of an unknown type, |
353 # we never ever want to fail because of an unknown type, |
354 # just return None in those cases. |
354 # just return None in those cases. |
355 return None |
355 return None |
356 |
356 |