uilib.py
author Sylvain Thénault <sylvain.thenault@logilab.fr>
Wed, 11 May 2011 09:38:44 +0200
changeset 7360 dbff01dd3c3c
parent 7166 dde161937d3e
child 7411 238da9684f99
permissions -rw-r--r--
[testlib] fake session can be given a vreg
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
     1
# -*- coding: utf-8 -*-
5421
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4466
diff changeset
     2
# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4466
diff changeset
     3
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4466
diff changeset
     4
#
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4466
diff changeset
     5
# This file is part of CubicWeb.
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4466
diff changeset
     6
#
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4466
diff changeset
     7
# CubicWeb is free software: you can redistribute it and/or modify it under the
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4466
diff changeset
     8
# terms of the GNU Lesser General Public License as published by the Free
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4466
diff changeset
     9
# Software Foundation, either version 2.1 of the License, or (at your option)
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4466
diff changeset
    10
# any later version.
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4466
diff changeset
    11
#
5424
8ecbcbff9777 replace logilab-common by CubicWeb in disclaimer
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5421
diff changeset
    12
# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
5421
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4466
diff changeset
    13
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4466
diff changeset
    14
# FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4466
diff changeset
    15
# details.
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4466
diff changeset
    16
#
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4466
diff changeset
    17
# You should have received a copy of the GNU Lesser General Public License along
8167de96c523 proper licensing information (LGPL-2.1). Hope I get it right this time.
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4466
diff changeset
    18
# with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    19
"""user interface libraries
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    20
5730
784025c15a3c [xhtml] fix soup2xhtml to deal with malformed div,body and html tags which may leads to malformed return value
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5424
diff changeset
    21
contains some functions designed to help implementation of cubicweb user
784025c15a3c [xhtml] fix soup2xhtml to deal with malformed div,body and html tags which may leads to malformed return value
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5424
diff changeset
    22
interface.
784025c15a3c [xhtml] fix soup2xhtml to deal with malformed div,body and html tags which may leads to malformed return value
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5424
diff changeset
    23
"""
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    24
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    25
__docformat__ = "restructuredtext en"
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    26
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    27
import csv
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    28
import re
1635
866563e2d0fc don't depends on simplejson outside web/
sylvain.thenault@logilab.fr
parents: 1623
diff changeset
    29
from StringIO import StringIO
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    30
2312
af4d8f75c5db use xml_escape
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2208
diff changeset
    31
from logilab.mtconverter import xml_escape, html_unescape
4466
8b0ca7904820 moved generic datetime manipulation function to lgc
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    32
from logilab.common.date import ustrftime
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    33
5949
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
    34
from cubicweb.utils import json_dumps
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
    35
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    36
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    37
def rql_for_eid(eid):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    38
    """return the rql query necessary to fetch entity with the given eid.  This
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    39
    function should only be used to generate link with rql inside, not to give
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    40
    to cursor.execute (in which case you won't benefit from rql cache).
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    41
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    42
    :Parameters:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    43
      - `eid`: the eid of the entity we should search
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    44
    :rtype: str
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    45
    :return: the rql query
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    46
    """
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    47
    return 'Any X WHERE X eid %s' % eid
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    48
6106
1e6d93f70d14 [selectors] fix match_transition & introduce new edited_attribute selector
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5951
diff changeset
    49
def eid_param(name, eid):
7058
ea22892e82d4 [uilib] fix eid_param implementation
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6688
diff changeset
    50
    assert name is not None
6106
1e6d93f70d14 [selectors] fix match_transition & introduce new edited_attribute selector
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5951
diff changeset
    51
    assert eid is not None
1e6d93f70d14 [selectors] fix match_transition & introduce new edited_attribute selector
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5951
diff changeset
    52
    return '%s:%s' % (name, eid)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    53
3212
07d11bacfefe displaytime attribute should not have been removed from there
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3165
diff changeset
    54
def printable_value(req, attrtype, value, props=None, displaytime=True):
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    55
    """return a displayable value (i.e. unicode string)"""
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    56
    if value is None or attrtype == 'Bytes':
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    57
        return u''
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    58
    if attrtype == 'String':
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    59
        # don't translate empty value if you don't want strange results
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    60
        if props is not None and value and props.get('internationalizable'):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    61
            return req._(value)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    62
        return value
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    63
    if attrtype == 'Date':
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    64
        return ustrftime(value, req.property_value('ui.date-format'))
7166
dde161937d3e [time zone] support for TZDatetime and TZTime data type
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7058
diff changeset
    65
    if attrtype in ('Time', 'TZTime'):
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    66
        return ustrftime(value, req.property_value('ui.time-format'))
7166
dde161937d3e [time zone] support for TZDatetime and TZTime data type
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7058
diff changeset
    67
    if attrtype in ('Datetime', 'TZDatetime'):
3212
07d11bacfefe displaytime attribute should not have been removed from there
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3165
diff changeset
    68
        if displaytime:
07d11bacfefe displaytime attribute should not have been removed from there
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3165
diff changeset
    69
            return ustrftime(value, req.property_value('ui.datetime-format'))
07d11bacfefe displaytime attribute should not have been removed from there
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3165
diff changeset
    70
        return ustrftime(value, req.property_value('ui.date-format'))
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    71
    if attrtype == 'Boolean':
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    72
        if value:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    73
            return req._('yes')
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    74
        return req._('no')
7166
dde161937d3e [time zone] support for TZDatetime and TZTime data type
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7058
diff changeset
    75
    if attrtype in ('Float', 'Decimal'):
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    76
        value = req.property_value('ui.float-format') % value
7166
dde161937d3e [time zone] support for TZDatetime and TZTime data type
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7058
diff changeset
    77
    # XXX Interval
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    78
    return unicode(value)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    79
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    80
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    81
# text publishing #############################################################
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    82
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    83
try:
6491
ee9a10b6620e pylint option update
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6106
diff changeset
    84
    from cubicweb.ext.rest import rest_publish # pylint: disable=W0611
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    85
except ImportError:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    86
    def rest_publish(entity, data):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    87
        """default behaviour if docutils was not found"""
2312
af4d8f75c5db use xml_escape
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2208
diff changeset
    88
        return xml_escape(data)
1581
80ee6397c087 fix rest import, html_escape in null rest_publish
sylvain.thenault@logilab.fr
parents: 1263
diff changeset
    89
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    90
TAG_PROG = re.compile(r'</?.*?>', re.U)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    91
def remove_html_tags(text):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    92
    """Removes HTML tags from text
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    93
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    94
    >>> remove_html_tags('<td>hi <a href="http://www.google.fr">world</a></td>')
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    95
    'hi world'
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    96
    >>>
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    97
    """
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    98
    return TAG_PROG.sub('', text)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    99
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   100
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   101
REF_PROG = re.compile(r"<ref\s+rql=([\'\"])([^\1]*?)\1\s*>([^<]*)</ref>", re.U)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   102
def _subst_rql(view, obj):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   103
    delim, rql, descr = obj.groups()
3418
7b49fa7e942d [api] use _cw, cw_row, cw_col, cw_rset etc.
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 3369
diff changeset
   104
    return u'<a href="%s">%s</a>' % (view._cw.build_url(rql=rql), descr)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   105
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   106
def html_publish(view, text):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   107
    """replace <ref rql=''> links by <a href="...">"""
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   108
    if not text:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   109
        return u''
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   110
    return REF_PROG.sub(lambda obj, view=view:_subst_rql(view, obj), text)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   111
277
a11a3c231050 fix lxml is available, we can have a nicer version of soup2xhtml even if its lxml < 2.0
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 228
diff changeset
   112
# fallback implementation, nicer one defined below if lxml> 2.0 is available
a11a3c231050 fix lxml is available, we can have a nicer version of soup2xhtml even if its lxml < 2.0
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 228
diff changeset
   113
def safe_cut(text, length):
a11a3c231050 fix lxml is available, we can have a nicer version of soup2xhtml even if its lxml < 2.0
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 228
diff changeset
   114
    """returns a string of length <length> based on <text>, removing any html
a11a3c231050 fix lxml is available, we can have a nicer version of soup2xhtml even if its lxml < 2.0
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 228
diff changeset
   115
    tags from given text if cut is necessary."""
a11a3c231050 fix lxml is available, we can have a nicer version of soup2xhtml even if its lxml < 2.0
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 228
diff changeset
   116
    if text is None:
a11a3c231050 fix lxml is available, we can have a nicer version of soup2xhtml even if its lxml < 2.0
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 228
diff changeset
   117
        return u''
362
a6a319f000c3 use mtconverter's html_unescape rather than saxutils' escape to deal with any html entity
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 350
diff changeset
   118
    noenttext = html_unescape(text)
350
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   119
    text_nohtml = remove_html_tags(noenttext)
277
a11a3c231050 fix lxml is available, we can have a nicer version of soup2xhtml even if its lxml < 2.0
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 228
diff changeset
   120
    # try to keep html tags if text is short enough
a11a3c231050 fix lxml is available, we can have a nicer version of soup2xhtml even if its lxml < 2.0
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 228
diff changeset
   121
    if len(text_nohtml) <= length:
a11a3c231050 fix lxml is available, we can have a nicer version of soup2xhtml even if its lxml < 2.0
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 228
diff changeset
   122
        return text
a11a3c231050 fix lxml is available, we can have a nicer version of soup2xhtml even if its lxml < 2.0
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 228
diff changeset
   123
    # else if un-tagged text is too long, cut it
2312
af4d8f75c5db use xml_escape
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2208
diff changeset
   124
    return xml_escape(text_nohtml[:length] + u'...')
350
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   125
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   126
fallback_safe_cut = safe_cut
277
a11a3c231050 fix lxml is available, we can have a nicer version of soup2xhtml even if its lxml < 2.0
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 228
diff changeset
   127
5730
784025c15a3c [xhtml] fix soup2xhtml to deal with malformed div,body and html tags which may leads to malformed return value
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5424
diff changeset
   128
REM_ROOT_HTML_TAGS = re.compile('</(body|html)>', re.U)
6685
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   129
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   130
try:
6685
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   131
    from lxml import etree, html
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   132
    from lxml.html import clean, defs
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   133
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   134
    ALLOWED_TAGS = (defs.general_block_tags | defs.list_tags | defs.table_tags |
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   135
                    defs.phrase_tags | defs.font_style_tags |
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   136
                    set(('span', 'a', 'br', 'img', 'map', 'area', 'sub', 'sup'))
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   137
                    )
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   138
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   139
    CLEANER = clean.Cleaner(allow_tags=ALLOWED_TAGS, remove_unknown_tags=False,
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   140
                            style=True, safe_attrs_only=True,
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   141
                            add_nofollow=False,
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   142
                            )
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   143
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   144
    def soup2xhtml(data, encoding):
6685
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   145
        """tidy html soup by allowing some element tags and return the result
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   146
        """
5730
784025c15a3c [xhtml] fix soup2xhtml to deal with malformed div,body and html tags which may leads to malformed return value
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5424
diff changeset
   147
        # remove spurious </body> and </html> tags, then normalize line break
784025c15a3c [xhtml] fix soup2xhtml to deal with malformed div,body and html tags which may leads to malformed return value
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5424
diff changeset
   148
        # (see http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7.1)
784025c15a3c [xhtml] fix soup2xhtml to deal with malformed div,body and html tags which may leads to malformed return value
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5424
diff changeset
   149
        data = REM_ROOT_HTML_TAGS.sub('', u'\n'.join(data.splitlines()))
6685
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   150
        xmltree = etree.HTML(CLEANER.clean_html('<div>%s</div>' % data))
6688
51ddb4842c56 update note
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6685
diff changeset
   151
        # NOTE: lxml 2.0 does support encoding='unicode', but last time I (syt)
51ddb4842c56 update note
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6685
diff changeset
   152
        # tried I got weird results (lxml 2.2.8)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   153
        body = etree.tostring(xmltree[0], encoding=encoding)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   154
        # remove <body> and </body> and decode to unicode
5730
784025c15a3c [xhtml] fix soup2xhtml to deal with malformed div,body and html tags which may leads to malformed return value
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5424
diff changeset
   155
        snippet = body[6:-7].decode(encoding)
784025c15a3c [xhtml] fix soup2xhtml to deal with malformed div,body and html tags which may leads to malformed return value
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5424
diff changeset
   156
        # take care to bad xhtml (for instance starting with </div>) which
784025c15a3c [xhtml] fix soup2xhtml to deal with malformed div,body and html tags which may leads to malformed return value
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5424
diff changeset
   157
        # may mess with the <div> we added below. Only remove it if it's
784025c15a3c [xhtml] fix soup2xhtml to deal with malformed div,body and html tags which may leads to malformed return value
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5424
diff changeset
   158
        # still there...
784025c15a3c [xhtml] fix soup2xhtml to deal with malformed div,body and html tags which may leads to malformed return value
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5424
diff changeset
   159
        if snippet.startswith('<div>') and snippet.endswith('</div>'):
784025c15a3c [xhtml] fix soup2xhtml to deal with malformed div,body and html tags which may leads to malformed return value
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5424
diff changeset
   160
            snippet = snippet[5:-6]
784025c15a3c [xhtml] fix soup2xhtml to deal with malformed div,body and html tags which may leads to malformed return value
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5424
diff changeset
   161
        return snippet
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   162
6685
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   163
        # lxml.Cleaner envelops text elements by internal logic (not accessible)
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   164
        # see http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7.1
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   165
        # TODO drop attributes in elements
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   166
        # TODO add policy configuration (content only, embedded content, ...)
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   167
        # XXX this is buggy for "<p>text1</p><p>text2</p>"...
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   168
        # XXX drop these two snippets action and follow the lxml behaviour
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   169
        # XXX (tests need to be updated)
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   170
        # if snippet.startswith('<div>') and snippet.endswith('</div>'):
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   171
        #     snippet = snippet[5:-6]
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   172
        # if snippet.startswith('<p>') and snippet.endswith('</p>'):
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   173
        #     snippet = snippet[3:-4]
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   174
        return snippet.decode(encoding)
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   175
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   176
except (ImportError, AttributeError):
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   177
    # gae environment: lxml not available
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   178
    # fallback implementation
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   179
    def soup2xhtml(data, encoding):
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   180
        # normalize line break
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   181
        # see http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7.1
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   182
        return u'\n'.join(data.splitlines())
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   183
else:
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   184
eeedb3575d25 [uilib] soup2xhtml uses now lxml.html.Cleaner
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 6683
diff changeset
   185
    if hasattr(etree.HTML('<div>test</div>'), 'iter'): # XXX still necessary?
165
c5ff97312b8a cleaning code
Laure Bourgois <Laure.Bourgois@logilab.fr>
parents: 164
diff changeset
   186
277
a11a3c231050 fix lxml is available, we can have a nicer version of soup2xhtml even if its lxml < 2.0
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 228
diff changeset
   187
        def safe_cut(text, length):
a11a3c231050 fix lxml is available, we can have a nicer version of soup2xhtml even if its lxml < 2.0
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 228
diff changeset
   188
            """returns an html document of length <length> based on <text>,
a11a3c231050 fix lxml is available, we can have a nicer version of soup2xhtml even if its lxml < 2.0
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 228
diff changeset
   189
            and cut is necessary.
a11a3c231050 fix lxml is available, we can have a nicer version of soup2xhtml even if its lxml < 2.0
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 228
diff changeset
   190
            """
a11a3c231050 fix lxml is available, we can have a nicer version of soup2xhtml even if its lxml < 2.0
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 228
diff changeset
   191
            if text is None:
a11a3c231050 fix lxml is available, we can have a nicer version of soup2xhtml even if its lxml < 2.0
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 228
diff changeset
   192
                return u''
350
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   193
            dom = etree.HTML(text)
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   194
            curlength = 0
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   195
            add_ellipsis = False
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   196
            for element in dom.iter():
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   197
                if curlength >= length:
277
a11a3c231050 fix lxml is available, we can have a nicer version of soup2xhtml even if its lxml < 2.0
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 228
diff changeset
   198
                    parent = element.getparent()
a11a3c231050 fix lxml is available, we can have a nicer version of soup2xhtml even if its lxml < 2.0
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 228
diff changeset
   199
                    parent.remove(element)
350
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   200
                    if curlength == length and (element.text or element.tail):
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   201
                        add_ellipsis = True
277
a11a3c231050 fix lxml is available, we can have a nicer version of soup2xhtml even if its lxml < 2.0
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 228
diff changeset
   202
                else:
a11a3c231050 fix lxml is available, we can have a nicer version of soup2xhtml even if its lxml < 2.0
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 228
diff changeset
   203
                    if element.text is not None:
350
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   204
                        element.text = cut(element.text, length - curlength)
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   205
                        curlength += len(element.text)
277
a11a3c231050 fix lxml is available, we can have a nicer version of soup2xhtml even if its lxml < 2.0
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 228
diff changeset
   206
                    if element.tail is not None:
350
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   207
                        if curlength < length:
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   208
                            element.tail = cut(element.tail, length - curlength)
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   209
                            curlength += len(element.tail)
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   210
                        elif curlength == length:
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   211
                            element.tail = '...'
277
a11a3c231050 fix lxml is available, we can have a nicer version of soup2xhtml even if its lxml < 2.0
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 228
diff changeset
   212
                        else:
a11a3c231050 fix lxml is available, we can have a nicer version of soup2xhtml even if its lxml < 2.0
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 228
diff changeset
   213
                            element.tail = ''
350
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   214
            text = etree.tounicode(dom[0])[6:-7] # remove wrapping <body></body>
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   215
            if add_ellipsis:
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   216
                return text + u'...'
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   217
            return text
1157
81a383cdda5c text_cut() accepts a gotoperiod parameter
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 927
diff changeset
   218
81a383cdda5c text_cut() accepts a gotoperiod parameter
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 927
diff changeset
   219
def text_cut(text, nbwords=30, gotoperiod=True):
350
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   220
    """from the given plain text, return a text with at least <nbwords> words,
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   221
    trying to go to the end of the current sentence.
277
a11a3c231050 fix lxml is available, we can have a nicer version of soup2xhtml even if its lxml < 2.0
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 228
diff changeset
   222
1157
81a383cdda5c text_cut() accepts a gotoperiod parameter
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 927
diff changeset
   223
    :param nbwords: the minimum number of words required
81a383cdda5c text_cut() accepts a gotoperiod parameter
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 927
diff changeset
   224
    :param gotoperiod: specifies if the function should try to go to
81a383cdda5c text_cut() accepts a gotoperiod parameter
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 927
diff changeset
   225
                       the first period after the cut (i.e. finish
81a383cdda5c text_cut() accepts a gotoperiod parameter
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 927
diff changeset
   226
                       the sentence if possible)
81a383cdda5c text_cut() accepts a gotoperiod parameter
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 927
diff changeset
   227
350
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   228
    Note that spaces are normalized.
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   229
    """
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   230
    if text is None:
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   231
        return u''
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   232
    words = text.split()
927
bfcc610c3d5e text_cut must return unicode not string
Stephanie Marcu <stephanie.marcu@logilab.fr>
parents: 525
diff changeset
   233
    text = u' '.join(words) # normalize spaces
1157
81a383cdda5c text_cut() accepts a gotoperiod parameter
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 927
diff changeset
   234
    textlength = minlength = len(' '.join(words[:nbwords]))
81a383cdda5c text_cut() accepts a gotoperiod parameter
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 927
diff changeset
   235
    if gotoperiod:
81a383cdda5c text_cut() accepts a gotoperiod parameter
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 927
diff changeset
   236
        textlength = text.find('.', minlength) + 1
81a383cdda5c text_cut() accepts a gotoperiod parameter
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 927
diff changeset
   237
        if textlength == 0: # no period found
81a383cdda5c text_cut() accepts a gotoperiod parameter
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 927
diff changeset
   238
            textlength = minlength
350
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   239
    return text[:textlength]
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   240
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   241
def cut(text, length):
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   242
    """returns a string of a maximum length <length> based on <text>
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   243
    (approximatively, since if text has been  cut, '...' is added to the end of the string,
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   244
    resulting in a string of len <length> + 3)
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   245
    """
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   246
    if text is None:
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   247
        return u''
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   248
    if len(text) <= length:
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   249
        return text
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   250
    # else if un-tagged text is too long, cut it
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   251
    return text[:length] + u'...'
f34ef2c64605 cleanup/fix cut variants
Sylvain Thenault <sylvain.thenault@logilab.fr>
parents: 277
diff changeset
   252
165
c5ff97312b8a cleaning code
Laure Bourgois <Laure.Bourgois@logilab.fr>
parents: 164
diff changeset
   253
1581
80ee6397c087 fix rest import, html_escape in null rest_publish
sylvain.thenault@logilab.fr
parents: 1263
diff changeset
   254
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   255
# HTML generation helper functions ############################################
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   256
5949
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   257
class _JSId(object):
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   258
    def __init__(self, id, parent=None):
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   259
        self.id = id
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   260
        self.parent = parent
5951
6026582ae4f1 [uilib] js objects implements __unicode__
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5949
diff changeset
   261
    def __unicode__(self):
5949
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   262
        if self.parent:
5951
6026582ae4f1 [uilib] js objects implements __unicode__
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5949
diff changeset
   263
            return u'%s.%s' % (self.parent, self.id)
6026582ae4f1 [uilib] js objects implements __unicode__
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5949
diff changeset
   264
        return unicode(self.id)
6026582ae4f1 [uilib] js objects implements __unicode__
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5949
diff changeset
   265
    def __str__(self):
6026582ae4f1 [uilib] js objects implements __unicode__
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5949
diff changeset
   266
        return unicode(self).encode('utf8')
5949
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   267
    def __getattr__(self, attr):
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   268
        return _JSId(attr, self)
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   269
    def __call__(self, *args):
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   270
        return _JSCallArgs(args, self)
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   271
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   272
class _JSCallArgs(_JSId):
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   273
    def __init__(self, args, parent=None):
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   274
        assert isinstance(args, tuple)
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   275
        self.args = args
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   276
        self.parent = parent
5951
6026582ae4f1 [uilib] js objects implements __unicode__
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5949
diff changeset
   277
    def __unicode__(self):
6026582ae4f1 [uilib] js objects implements __unicode__
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5949
diff changeset
   278
        args = u','.join(json_dumps(arg) for arg in self.args)
5949
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   279
        if self.parent:
5951
6026582ae4f1 [uilib] js objects implements __unicode__
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5949
diff changeset
   280
            return u'%s(%s)' % (self.parent, args)
5949
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   281
        return args
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   282
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   283
class _JS(object):
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   284
    def __getattr__(self, attr):
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   285
        return _JSId(attr)
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   286
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   287
"""magic object to return strings suitable to call some javascript function with
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   288
the given arguments (which should be correctly typed).
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   289
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   290
>>> str(js.pouet(1, "2"))
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   291
'pouet(1,"2")'
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   292
>>> str(js.cw.pouet(1, "2"))
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   293
'cw.pouet(1,"2")'
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   294
>>> str(js.cw.pouet(1, "2").pouet(None))
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   295
'cw.pouet(1,"2").pouet(null)')
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   296
"""
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   297
js = _JS()
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   298
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   299
def domid(string):
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   300
    """return a valid DOM id from a string (should also be usable in jQuery
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   301
    search expression...)
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   302
    """
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   303
    return string.replace('.', '_').replace('-', '_')
2a273c896a38 [box] provide a new generic base box class to edit relation to simple entities, backported from the 'tag' cube
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5730
diff changeset
   304
2398
a8d18e320ef3 a standard-conformant fix for sgml_tags
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2375
diff changeset
   305
HTML4_EMPTY_TAGS = frozenset(('base', 'meta', 'link', 'hr', 'br', 'param',
a8d18e320ef3 a standard-conformant fix for sgml_tags
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2375
diff changeset
   306
                              'img', 'area', 'input', 'col'))
a8d18e320ef3 a standard-conformant fix for sgml_tags
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2375
diff changeset
   307
2516
b58826130680 extract function: sgml_attributes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2458
diff changeset
   308
def sgml_attributes(attrs):
b58826130680 extract function: sgml_attributes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2458
diff changeset
   309
    return u' '.join(u'%s="%s"' % (attr, xml_escape(unicode(value)))
b58826130680 extract function: sgml_attributes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2458
diff changeset
   310
                     for attr, value in sorted(attrs.items())
b58826130680 extract function: sgml_attributes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2458
diff changeset
   311
                     if value is not None)
b58826130680 extract function: sgml_attributes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2458
diff changeset
   312
1623
sylvain.thenault@logilab.fr
parents: 1581
diff changeset
   313
def simple_sgml_tag(tag, content=None, escapecontent=True, **attrs):
525
bd4e03297cf0 function to make generation of a simple sgml tag
sylvain.thenault@logilab.fr
parents: 362
diff changeset
   314
    """generation of a simple sgml tag (eg without children tags) easier
bd4e03297cf0 function to make generation of a simple sgml tag
sylvain.thenault@logilab.fr
parents: 362
diff changeset
   315
2399
68799e25f893 a standard-conformant fix for sgml_tags
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2375
diff changeset
   316
    content and attri butes will be escaped
525
bd4e03297cf0 function to make generation of a simple sgml tag
sylvain.thenault@logilab.fr
parents: 362
diff changeset
   317
    """
bd4e03297cf0 function to make generation of a simple sgml tag
sylvain.thenault@logilab.fr
parents: 362
diff changeset
   318
    value = u'<%s' % tag
bd4e03297cf0 function to make generation of a simple sgml tag
sylvain.thenault@logilab.fr
parents: 362
diff changeset
   319
    if attrs:
980
59552ba2015f more tags, map klass -> class avoiding needs to use **dict
sylvain.thenault@logilab.fr
parents: 862
diff changeset
   320
        try:
59552ba2015f more tags, map klass -> class avoiding needs to use **dict
sylvain.thenault@logilab.fr
parents: 862
diff changeset
   321
            attrs['class'] = attrs.pop('klass')
59552ba2015f more tags, map klass -> class avoiding needs to use **dict
sylvain.thenault@logilab.fr
parents: 862
diff changeset
   322
        except KeyError:
59552ba2015f more tags, map klass -> class avoiding needs to use **dict
sylvain.thenault@logilab.fr
parents: 862
diff changeset
   323
            pass
2516
b58826130680 extract function: sgml_attributes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2458
diff changeset
   324
        value += u' ' + sgml_attributes(attrs)
525
bd4e03297cf0 function to make generation of a simple sgml tag
sylvain.thenault@logilab.fr
parents: 362
diff changeset
   325
    if content:
1623
sylvain.thenault@logilab.fr
parents: 1581
diff changeset
   326
        if escapecontent:
2312
af4d8f75c5db use xml_escape
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2208
diff changeset
   327
            content = xml_escape(unicode(content))
1623
sylvain.thenault@logilab.fr
parents: 1581
diff changeset
   328
        value += u'>%s</%s>' % (content, tag)
525
bd4e03297cf0 function to make generation of a simple sgml tag
sylvain.thenault@logilab.fr
parents: 362
diff changeset
   329
    else:
2398
a8d18e320ef3 a standard-conformant fix for sgml_tags
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2375
diff changeset
   330
        if tag in HTML4_EMPTY_TAGS:
a8d18e320ef3 a standard-conformant fix for sgml_tags
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2375
diff changeset
   331
            value += u' />'
a8d18e320ef3 a standard-conformant fix for sgml_tags
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2375
diff changeset
   332
        else:
a8d18e320ef3 a standard-conformant fix for sgml_tags
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2375
diff changeset
   333
            value += u'></%s>' % tag
525
bd4e03297cf0 function to make generation of a simple sgml tag
sylvain.thenault@logilab.fr
parents: 362
diff changeset
   334
    return value
bd4e03297cf0 function to make generation of a simple sgml tag
sylvain.thenault@logilab.fr
parents: 362
diff changeset
   335
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   336
def tooltipize(text, tooltip, url=None):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   337
    """make an HTML tooltip"""
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   338
    url = url or '#'
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   339
    return u'<a href="%s" title="%s">%s</a>' % (url, tooltip, text)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   340
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   341
def toggle_action(nodeid):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   342
    """builds a HTML link that uses the js toggleVisibility function"""
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   343
    return u"javascript: toggleVisibility('%s')" % nodeid
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   344
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   345
def toggle_link(nodeid, label):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   346
    """builds a HTML link that uses the js toggleVisibility function"""
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   347
    return u'<a href="%s">%s</a>' % (toggle_action(nodeid), label)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   348
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   349
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   350
def ureport_as_html(layout):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   351
    from logilab.common.ureports import HTMLWriter
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   352
    formater = HTMLWriter(True)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   353
    stream = StringIO() #UStringIO() don't want unicode assertion
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   354
    formater.format(layout, stream)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   355
    res = stream.getvalue()
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   356
    if isinstance(res, str):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   357
        res = unicode(res, 'UTF8')
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   358
    return res
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   359
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   360
# traceback formatting ########################################################
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   361
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   362
import traceback
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   363
6683
68cfebd3b9f3 fix #724689: exception's display during ajax call
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6491
diff changeset
   364
def exc_message(ex, encoding):
68cfebd3b9f3 fix #724689: exception's display during ajax call
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6491
diff changeset
   365
    try:
68cfebd3b9f3 fix #724689: exception's display during ajax call
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6491
diff changeset
   366
        return unicode(ex)
68cfebd3b9f3 fix #724689: exception's display during ajax call
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6491
diff changeset
   367
    except:
68cfebd3b9f3 fix #724689: exception's display during ajax call
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6491
diff changeset
   368
        try:
68cfebd3b9f3 fix #724689: exception's display during ajax call
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6491
diff changeset
   369
            return unicode(str(ex), encoding, 'replace')
68cfebd3b9f3 fix #724689: exception's display during ajax call
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6491
diff changeset
   370
        except:
68cfebd3b9f3 fix #724689: exception's display during ajax call
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6491
diff changeset
   371
            return unicode(repr(ex), encoding, 'replace')
68cfebd3b9f3 fix #724689: exception's display during ajax call
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6491
diff changeset
   372
68cfebd3b9f3 fix #724689: exception's display during ajax call
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 6491
diff changeset
   373
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   374
def rest_traceback(info, exception):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   375
    """return a ReST formated traceback"""
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   376
    res = [u'Traceback\n---------\n::\n']
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   377
    for stackentry in traceback.extract_tb(info[2]):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   378
        res.append(u'\tFile %s, line %s, function %s' % tuple(stackentry[:3]))
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   379
        if stackentry[3]:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   380
            res.append(u'\t  %s' % stackentry[3].decode('utf-8', 'replace'))
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   381
    res.append(u'\n')
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   382
    try:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   383
        res.append(u'\t Error: %s\n' % exception)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   384
    except:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   385
        pass
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   386
    return u'\n'.join(res)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   387
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   388
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   389
def html_traceback(info, exception, title='',
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   390
                   encoding='ISO-8859-1', body=''):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   391
    """ return an html formatted traceback from python exception infos.
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   392
    """
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   393
    tcbk = info[2]
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   394
    stacktb = traceback.extract_tb(tcbk)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   395
    strings = []
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   396
    if body:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   397
        strings.append(u'<div class="error_body">')
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   398
        # FIXME
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   399
        strings.append(body)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   400
        strings.append(u'</div>')
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   401
    if title:
2312
af4d8f75c5db use xml_escape
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2208
diff changeset
   402
        strings.append(u'<h1 class="error">%s</h1>'% xml_escape(title))
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   403
    try:
2312
af4d8f75c5db use xml_escape
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2208
diff changeset
   404
        strings.append(u'<p class="error">%s</p>' % xml_escape(str(exception)).replace("\n","<br />"))
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   405
    except UnicodeError:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   406
        pass
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   407
    strings.append(u'<div class="error_traceback">')
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   408
    for index, stackentry in enumerate(stacktb):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   409
        strings.append(u'<b>File</b> <b class="file">%s</b>, <b>line</b> '
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   410
                       u'<b class="line">%s</b>, <b>function</b> '
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   411
                       u'<b class="function">%s</b>:<br/>'%(
2312
af4d8f75c5db use xml_escape
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2208
diff changeset
   412
            xml_escape(stackentry[0]), stackentry[1], xml_escape(stackentry[2])))
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   413
        if stackentry[3]:
2312
af4d8f75c5db use xml_escape
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2208
diff changeset
   414
            string = xml_escape(stackentry[3]).decode('utf-8', 'replace')
2996
866a2c135c33 B #345282 xhtml requires to use &#160; instead of &nbsp;
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 2516
diff changeset
   415
            strings.append(u'&#160;&#160;%s<br/>\n' % (string))
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   416
        # add locals info for each entry
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   417
        try:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   418
            local_context = tcbk.tb_frame.f_locals
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   419
            html_info = []
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   420
            chars = 0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   421
            for name, value in local_context.iteritems():
2312
af4d8f75c5db use xml_escape
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2208
diff changeset
   422
                value = xml_escape(repr(value))
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   423
                info = u'<span class="name">%s</span>=%s, ' % (name, value)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   424
                line_length = len(name) + len(value)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   425
                chars += line_length
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   426
                # 150 is the result of *years* of research ;-) (CSS might be helpful here)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   427
                if chars > 150:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   428
                    info = u'<br/>' + info
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   429
                    chars = line_length
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   430
                html_info.append(info)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   431
            boxid = 'ctxlevel%d' % index
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   432
            strings.append(u'[%s]' % toggle_link(boxid, '+'))
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   433
            strings.append(u'<div id="%s" class="pycontext hidden">%s</div>' %
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   434
                           (boxid, ''.join(html_info)))
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   435
            tcbk = tcbk.tb_next
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   436
        except Exception:
1581
80ee6397c087 fix rest import, html_escape in null rest_publish
sylvain.thenault@logilab.fr
parents: 1263
diff changeset
   437
            pass # doesn't really matter if we have no context info
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   438
    strings.append(u'</div>')
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   439
    return '\n'.join(strings)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   440
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   441
# csv files / unicode support #################################################
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   442
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   443
class UnicodeCSVWriter:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   444
    """proxies calls to csv.writer.writerow to be able to deal with unicode"""
1581
80ee6397c087 fix rest import, html_escape in null rest_publish
sylvain.thenault@logilab.fr
parents: 1263
diff changeset
   445
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   446
    def __init__(self, wfunc, encoding, **kwargs):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   447
        self.writer = csv.writer(self, **kwargs)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   448
        self.wfunc = wfunc
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   449
        self.encoding = encoding
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   450
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   451
    def write(self, data):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   452
        self.wfunc(data)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   453
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   454
    def writerow(self, row):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   455
        csvrow = []
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   456
        for elt in row:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   457
            if isinstance(elt, unicode):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   458
                csvrow.append(elt.encode(self.encoding))
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   459
            else:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   460
                csvrow.append(str(elt))
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   461
        self.writer.writerow(csvrow)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   462
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   463
    def writerows(self, rows):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   464
        for row in rows:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   465
            self.writerow(row)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   466
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   467
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   468
# some decorators #############################################################
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   469
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   470
class limitsize(object):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   471
    def __init__(self, maxsize):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   472
        self.maxsize = maxsize
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   473
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   474
    def __call__(self, function):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   475
        def newfunc(*args, **kwargs):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   476
            ret = function(*args, **kwargs)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   477
            if isinstance(ret, basestring):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   478
                return ret[:self.maxsize]
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   479
            return ret
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   480
        return newfunc
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   481
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   482
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   483
def htmlescape(function):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   484
    def newfunc(*args, **kwargs):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   485
        ret = function(*args, **kwargs)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   486
        assert isinstance(ret, basestring)
2312
af4d8f75c5db use xml_escape
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2208
diff changeset
   487
        return xml_escape(ret)
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   488
    return newfunc