Example #1
0
    def ListOfWikiPages(self, formatter, content):
        """
== Description ==

Website: http://trac-hacks.org/wiki/ListOfWikiPagesMacro

`$Id$`

The macro `ListOfWikiPages` prints a table of all (user generated, i.e. 
non-trac-default) wiki pages with last changed date and author as requested in 
Request-a-Hack th:#2427.
Version 0.2 provides also a long format which also includes the newest version 
number and links to the difference and the history as well as the last comment.  
This was requested by th:#4717.

The second macro provided by this package is `LastChangesBy` which prints the 
last changes made by the given user or the logged-in user if no username is 
given. 

== Usage ==

You can use the `ListOfWikiPages` macro like this:
{{{
[[ListOfWikiPages]]                     # default format as configured in the config file
[[ListOfWikiPages(format=short)]]       # short format
[[ListOfWikiPages(format=long)]]        # long format (new v0.2)
}}}
which prints a table of all wiki pages, or with a list of wiki pages:
{{{
[[ListOfWikiPages(ThatWikiPage,ThisWikiPage,AnotherWikiPage,format=...)]]
}}}

Since v0.3 the optional arguments `from` and `to` can be used to specify a 
time/date range as requested by th:#5344.
The values of this arguments are taken as negative offsets to the current time 
(i.e. the time the wiki page is displayed).
Allowed is a number followed by a unit which can be `s`,`m`,`h`,`d`,`w`,`o`,`y` 
for seconds, minutes, hours, days, weeks, month and years.
If the unit is missing seconds are assumed.

{{{
[[ListOfWikiPages(from=3d)]]            # displays all wiki pages changed in the last three days
[[ListOfWikiPages(to=15m)]]             # displays all wiki pages was where changed longer than 15 minutes ago
[[ListOfWikiPages(from=4.5w,to=15h)]]   # displays all wiki pages was where changed between 4 1/2 week and 15 hours ago
}}}

A headline can be given using a `headline` argument:
{{{
[[ListOfWikiPages(headline=Headline text without any comma)]]     # sets a table headline, may not contain '`,`'
}}}

The order can be reversed, i.e. list the oldest wikis first, using:
{{{
[[ListOfWikiPages(order=reverse)]]
}}}

Unwanted wiki ranges (e.g. `Trac*`) can be excluded by the `exclude=pattern` option which can be given multiple times.
The wildcards '`*`' (matches everything) and '`?`' (matches a single character) can be used in the pattern. (Requested by #6074)
{{{
[[ListOfWikiPages(exclude=Trac*,exclude=abc?)]]
}}}

        """
        largs, kwargs = parse_args( content, multi = ['exclude'] )

        self.href = formatter.req.href

        long_format = self.default_format.lower() == 'long'
        if 'format' in kwargs:
          long_format = kwargs['format'].lower() == 'long'
        self.long_format = long_format

        db = self.env.get_db_cnx()
        cursor = db.cursor()
        #cursor.log = self.env.log

        sql_wikis = ''
        if largs:
          sql_wikis = self._get_sql_include(largs)

        sql_exclude = ''
        if 'exclude' in kwargs:
          sql_exclude = self._get_sql_exclude(kwargs['exclude'])

        self.kwargs = kwargs
        dfrom, fromtext = self.timeval('from', (0,''))
        dto, totext     = self.timeval('to',   (int(unixtime()),''))

        if 'from' in kwargs or 'to' in kwargs:
          sql_time = " time BETWEEN %d AND %d AND " % (dfrom,dto)
        else:
          sql_time = ''

        if kwargs.get('order','normal') == 'reverse':
          order = " "
        else:
          order = " DESC "

        sqlcmd = \
            "SELECT name,time,author,version,comment FROM wiki AS w1 WHERE " \
            + sql_time + \
            "author NOT IN ('%s') "  % "','".join( self.ignore_users ) + sql_wikis + sql_exclude + \
            "AND version=(SELECT MAX(version) FROM wiki AS w2 WHERE w1.name=w2.name) ORDER BY time " + \
            order
        cursor.execute(sqlcmd)

        rows = [ self.formatrow(n,name,time,version,comment,author)
              for n,[name,time,author,version,comment] in enumerate(cursor) ]

        if self.long_format:
          cols = ( "WikiPage", "Last Changed At", "By",
                   "Version", "Diff", "History", "Comment" )
        else:
          cols = ( "WikiPage", "Last Changed At", "By" )

        if 'headline' in kwargs:
          headlinetag = tag.tr( tag.th( kwargs['headline'],
            colspan = len(cols) ) )
        else:
          headlinetag = tag()

        head  = tag.thead ( headlinetag, tag.tr(
          map(lambda x: tag.th(x, class_=x.replace(" ", "").lower() ), cols) ) )
        table = tag.table ( head, rows, class_ = 'listofwikipages' )

        self.href = None
        return table
Example #2
0
    def LastChangesBy(self, formatter, content):
        """
This macro prints a table similar to the `[[ListOfWikiPages]]` only with the 
''By'' column missing and the author name in the table head.
{{{
[[LastChangesBy(martin_s)]]          # the last 5 changes by user `martin_s`
[[LastChangesBy(martin_s,10)]]       # the last 10 changes by user `martin_s`

[[LastChangesBy]]                    # or
[[LastChangesBy()]]                  # the last 5 changes by the current user (i.e. every user sees it's own changes, if logged-on)
[[LastChangesBy(,12)]]               # the last 12 changes by the current user

[[LastChangesBy(...,format=...]]     # Selects `long` or `short` table format
[[LastChangesBy(...,from=..,to=..]]  # Selects `from` and `to` time/date range

[[LastChangesBy(...,headline=...]]   # Overwrites headline, may not contain `','`

[[LastChangesBy(...,order=reverse]]  # Lists the wikis in reverse order. Only really useful with few wikis or with `to`/`from`.

[[LastChangesBy(..,exclude=pattern]] # Excludes wikis matching `pattern`. Wildcards `*` and `?` are supported.
}}}
        """

        largs, kwargs = parse_args( content )

        #self.base_path = formatter.req.base_path
        self.href = formatter.req.href
        section = 'listofwikipages'

        long_format = self.env.config.get(section, 'default_format', 
            'short').lower() == 'long'
        if 'format' in kwargs:
          long_format = kwargs['format'].lower() == 'long'
        self.long_format = long_format

        self.kwargs = kwargs
        dfrom, fromtext = self.timeval('from', (0,''))
        dto, totext     = self.timeval('to',   (int(unixtime()),''))

        if 'from' in kwargs or 'to' in kwargs:
          sql_time = " AND time BETWEEN %d AND %d " % (dfrom,dto)
        else:
          sql_time = ''

        sql_exclude = ''
        if 'exclude' in kwargs:
          sql_exclude = self._get_sql_exclude(kwargs['exclude'])

        author = len(largs) > 0 and largs[0] or formatter.req.authname
        count  = len(largs) > 1 and largs[1] or 5
        try:
            count = int(count)
            if count < 1:
                raise
        except:
            raise TracError("Second list argument must be a positive integer!")

        db = self.env.get_db_cnx()
        cursor = db.cursor()
        #cursor.log = self.env.log

        if kwargs.get('order','normal') == 'reverse':
          order = " "
        else:
          order = " DESC "

        cursor.execute ( """
              SELECT name,time,version,comment
              FROM wiki AS w1 WHERE author = %s """ + sql_time + sql_exclude + """
              AND version=(SELECT MAX(version) FROM wiki AS w2 WHERE w1.name=w2.name)
              ORDER BY time
          """ + order + " LIMIT 0,%d " % count, (author,) )

        rows = [ self.formatrow(n,name,time,version,comment) for
              n,[name,time,version,comment] in enumerate(cursor) if n < count ]
        if count == 1:
            count = ''
            s = ''
        else:
            s = 's'

        if self.long_format:
          cols = ( "WikiPage", "Last Changed At",
                   "Version", "Diff", "History", "Comment" )
        else:
          cols = ( "WikiPage", "Last Changed At" )

        headline = "Last %s change%s by  " % (count,s)
        if sql_time:
          if fromtext:
            if totext:
              timetag = " between %s and %s ago" % (fromtext,totext)
            else:
              timetag = " in the last %s" % fromtext
          else:
            if totext:
              timetag = " before the last %s" % totext
            else:
              timetag = ""
        else:
          timetag = ''

        if 'headline' in kwargs:
          headlinetag = tag.tr(
              tag.th(kwargs['headline'],
              colspan = len(cols) ))
        else:
          headlinetag = tag.tr(
              tag.th(headline, tag.strong(author), timetag,
              colspan = len(cols) ))

        head = tag.thead ( headlinetag,
                tag.tr(
          map(lambda x: tag.th(x, class_=x.replace(" ", "").lower() ), cols)
        ) )
        table = tag.table( head, rows, class_ = 'lastchangesby' )

        self.href = None
        return table
Example #3
0
    def LastChangesBy(self, formatter, content):
        """
This macro prints a table similar to the `[[ListOfWikiPages]]` only with the 
''By'' column missing and the author name in the table head.
{{{
[[LastChangesBy(martin_s)]]          # the last 5 changes by user `martin_s`
[[LastChangesBy(martin_s,10)]]       # the last 10 changes by user `martin_s`

[[LastChangesBy]]                    # or
[[LastChangesBy()]]                  # the last 5 changes by the current user (i.e. every user sees it's own changes, if logged-on)
[[LastChangesBy(,12)]]               # the last 12 changes by the current user

[[LastChangesBy(...,format=...]]     # Selects `long` or `short` table format
[[LastChangesBy(...,from=..,to=..]]  # Selects `from` and `to` time/date range

[[LastChangesBy(...,headline=...]]   # Overwrites headline, may not contain `','`

[[LastChangesBy(...,order=reverse]]  # Lists the wikis in reverse order. Only really useful with few wikis or with `to`/`from`.

[[LastChangesBy(..,exclude=pattern]] # Excludes wikis matching `pattern`. Wildcards `*` and `?` are supported.
}}}
        """

        largs, kwargs = parse_args(content)

        #self.base_path = formatter.req.base_path
        self.href = formatter.req.href
        section = 'listofwikipages'

        long_format = self.env.config.get(section, 'default_format',
                                          'short').lower() == 'long'
        if 'format' in kwargs:
            long_format = kwargs['format'].lower() == 'long'
        self.long_format = long_format

        self.kwargs = kwargs
        dfrom, fromtext = self.timeval('from', (0, ''))
        dto, totext = self.timeval('to', (int(unixtime()), ''))

        if 'from' in kwargs or 'to' in kwargs:
            sql_time = " AND time BETWEEN %d AND %d " % (dfrom, dto)
        else:
            sql_time = ''

        sql_exclude = ''
        if 'exclude' in kwargs:
            sql_exclude = self._get_sql_exclude(kwargs['exclude'])

        author = len(largs) > 0 and largs[0] or formatter.req.authname
        count = len(largs) > 1 and largs[1] or 5
        try:
            count = int(count)
            if count < 1:
                raise
        except:
            raise TracError("Second list argument must be a positive integer!")

        db = self.env.get_db_cnx()
        cursor = db.cursor()
        #cursor.log = self.env.log

        if kwargs.get('order', 'normal') == 'reverse':
            order = " "
        else:
            order = " DESC "

        cursor.execute(
            """
              SELECT name,time,version,comment
              FROM wiki AS w1 WHERE author = %s """ + sql_time + sql_exclude +
            """
              AND version=(SELECT MAX(version) FROM wiki AS w2 WHERE w1.name=w2.name)
              ORDER BY time
          """ + order + " LIMIT 0,%d " % count, (author, ))

        rows = [
            self.formatrow(n, name, time, version, comment)
            for n, [name, time, version, comment] in enumerate(cursor)
            if n < count
        ]
        if count == 1:
            count = ''
            s = ''
        else:
            s = 's'

        if self.long_format:
            cols = ("WikiPage", "Last Changed At", "Version", "Diff",
                    "History", "Comment")
        else:
            cols = ("WikiPage", "Last Changed At")

        headline = "Last %s change%s by  " % (count, s)
        if sql_time:
            if fromtext:
                if totext:
                    timetag = " between %s and %s ago" % (fromtext, totext)
                else:
                    timetag = " in the last %s" % fromtext
            else:
                if totext:
                    timetag = " before the last %s" % totext
                else:
                    timetag = ""
        else:
            timetag = ''

        if 'headline' in kwargs:
            headlinetag = tag.tr(tag.th(kwargs['headline'], colspan=len(cols)))
        else:
            headlinetag = tag.tr(
                tag.th(headline,
                       tag.strong(author),
                       timetag,
                       colspan=len(cols)))

        head = tag.thead(
            headlinetag,
            tag.tr(
                map(lambda x: tag.th(x, class_=x.replace(" ", "").lower()),
                    cols)))
        table = tag.table(head, rows, class_='lastchangesby')

        self.href = None
        return table
Example #4
0
    def ListOfWikiPages(self, formatter, content):
        """
== Description ==

Website: http://trac-hacks.org/wiki/ListOfWikiPagesMacro

`$Id$`

The macro `ListOfWikiPages` prints a table of all (user generated, i.e. 
non-trac-default) wiki pages with last changed date and author as requested in 
Request-a-Hack th:#2427.
Version 0.2 provides also a long format which also includes the newest version 
number and links to the difference and the history as well as the last comment.  
This was requested by th:#4717.

The second macro provided by this package is `LastChangesBy` which prints the 
last changes made by the given user or the logged-in user if no username is 
given. 

== Usage ==

You can use the `ListOfWikiPages` macro like this:
{{{
[[ListOfWikiPages]]                     # default format as configured in the config file
[[ListOfWikiPages(format=short)]]       # short format
[[ListOfWikiPages(format=long)]]        # long format (new v0.2)
}}}
which prints a table of all wiki pages, or with a list of wiki pages:
{{{
[[ListOfWikiPages(ThatWikiPage,ThisWikiPage,AnotherWikiPage,format=...)]]
}}}

Since v0.3 the optional arguments `from` and `to` can be used to specify a 
time/date range as requested by th:#5344.
The values of this arguments are taken as negative offsets to the current time 
(i.e. the time the wiki page is displayed).
Allowed is a number followed by a unit which can be `s`,`m`,`h`,`d`,`w`,`o`,`y` 
for seconds, minutes, hours, days, weeks, month and years.
If the unit is missing seconds are assumed.

{{{
[[ListOfWikiPages(from=3d)]]            # displays all wiki pages changed in the last three days
[[ListOfWikiPages(to=15m)]]             # displays all wiki pages was where changed longer than 15 minutes ago
[[ListOfWikiPages(from=4.5w,to=15h)]]   # displays all wiki pages was where changed between 4 1/2 week and 15 hours ago
}}}

A headline can be given using a `headline` argument:
{{{
[[ListOfWikiPages(headline=Headline text without any comma)]]     # sets a table headline, may not contain '`,`'
}}}

The order can be reversed, i.e. list the oldest wikis first, using:
{{{
[[ListOfWikiPages(order=reverse)]]
}}}

Unwanted wiki ranges (e.g. `Trac*`) can be excluded by the `exclude=pattern` option which can be given multiple times.
The wildcards '`*`' (matches everything) and '`?`' (matches a single character) can be used in the pattern. (Requested by #6074)
{{{
[[ListOfWikiPages(exclude=Trac*,exclude=abc?)]]
}}}

        """
        largs, kwargs = parse_args(content, multi=['exclude'])

        self.href = formatter.req.href

        long_format = self.default_format.lower() == 'long'
        if 'format' in kwargs:
            long_format = kwargs['format'].lower() == 'long'
        self.long_format = long_format

        db = self.env.get_db_cnx()
        cursor = db.cursor()
        #cursor.log = self.env.log

        sql_wikis = ''
        if largs:
            sql_wikis = self._get_sql_include(largs)

        sql_exclude = ''
        if 'exclude' in kwargs:
            sql_exclude = self._get_sql_exclude(kwargs['exclude'])

        self.kwargs = kwargs
        dfrom, fromtext = self.timeval('from', (0, ''))
        dto, totext = self.timeval('to', (int(unixtime()), ''))

        if 'from' in kwargs or 'to' in kwargs:
            sql_time = " time BETWEEN %d AND %d AND " % (dfrom, dto)
        else:
            sql_time = ''

        if kwargs.get('order', 'normal') == 'reverse':
            order = " "
        else:
            order = " DESC "

        sqlcmd = \
            "SELECT name,time,author,version,comment FROM wiki AS w1 WHERE " \
            + sql_time + \
            "author NOT IN ('%s') "  % "','".join( self.ignore_users ) + sql_wikis + sql_exclude + \
            "AND version=(SELECT MAX(version) FROM wiki AS w2 WHERE w1.name=w2.name) ORDER BY time " + \
            order
        cursor.execute(sqlcmd)

        rows = [
            self.formatrow(n, name, time, version, comment, author)
            for n, [name, time, author, version, comment] in enumerate(cursor)
        ]

        if self.long_format:
            cols = ("WikiPage", "Last Changed At", "By", "Version", "Diff",
                    "History", "Comment")
        else:
            cols = ("WikiPage", "Last Changed At", "By")

        if 'headline' in kwargs:
            headlinetag = tag.tr(tag.th(kwargs['headline'], colspan=len(cols)))
        else:
            headlinetag = tag()

        head = tag.thead(
            headlinetag,
            tag.tr(
                map(lambda x: tag.th(x, class_=x.replace(" ", "").lower()),
                    cols)))
        table = tag.table(head, rows, class_='listofwikipages')

        self.href = None
        return table
Example #5
0
    def expand_macro(self, formatter, name, content, args=None):
        content = content.replace('\n',',')
        largs, kwargs = parse_args(content, multi=['marker','to'])
        if len(largs) > 0:
            arg = unicode(largs[0])
            if _reCOORDS.match(arg):
                if not 'center' in kwargs:
                    kwargs['center'] = arg
            else:
                if not 'address' in kwargs:
                    kwargs['address'] = arg
        if 'from' in kwargs and not 'address' in kwargs and not 'center' in kwargs:
            arg = unicode(kwargs['from'])
            if _reCOORDS.match(arg):
                if not 'center' in kwargs:
                    kwargs['center'] = arg
            else:
                if not 'address' in kwargs:
                    kwargs['address'] = arg

        # Check if Google API key is set (if not the Google Map script file
        # wasn't inserted by `post_process_request` and the map wont load)
        if not self.api_key:
            raise TracError("No Google Maps API key given! Tell your web admin to get one at http://code.google.com/apis/maps/signup.html .\n")

        # Use default values if needed
        zoom = None
        size = None
        try:
            if 'zoom' in kwargs:
                zoom = unicode( int( kwargs['zoom'] ) )
            else:
                zoom = unicode( self.default_zoom )
        except:
            raise TracError("Invalid value for zoom given! Please provide an integer from 0 to 19.")

        if 'size' in kwargs:
            size = unicode( kwargs['size'] )
        else:
            size = unicode( self.default_size )

        # Set target for hyperlinked markers
        target = ""
        if not 'target' in kwargs:
            kwargs['target'] = self.default_target
        if kwargs['target'] in ('new','newwindow','_blank'):
            target = "newwindow"

        # Get height and width
        width  = None
        height = None
        try:
            if size.find(':') != -1:
                (width,height) = size.lower().split(':')
                # Check for correct units:
                if    not width[-2:]  in _css_units \
                   or not height[-2:] in _css_units:
                       raise TracError("Wrong unit(s)!")
                # The rest must be a number:
                float( width[:-2]  )
                float( height[:-2] )
            else:
                (width,height) = size.lower().split('x')
                width  = str( int( width  ) ) + "px"
                height = str( int( height ) ) + "px"
        except:
            raise TracError("Invalid value for size given! Please provide "
                            "{width}x{height} in pixels (without unit) or "
                            "{width}{unit}:{height}{unit} in CSS units (%s)." \
                                    % ', '.join(_css_units) )


        # Correct separator for 'center' argument because comma isn't allowed in
        # macro arguments
        center = ""
        if 'center' in kwargs:
            center = unicode(kwargs['center']).replace(':',',').strip(' "\'')
            if not _reCOORDS.match(center):
                raise TracError("Invalid center coordinates given!")

        # Format address
        address = ""
        if 'address' in kwargs:
            address = self._format_address(kwargs['address'])
            if self.geocoding_server:
                coord = self._get_coords(address)
                center = ",".join(coord[0:2])
                address = ""
                if not 'zoom' in kwargs:
                    zoom = _accuracy_to_zoom[ int( coord[2] ) ]

        # Internal formatting functions:
        def gtyp (stype):
            return "G_%s_MAP" % str(stype)
        def gcontrol (control):
            return "map.addControl(new G%sControl());\n" % str(control)
        def gmarker (lat,lng,letter='',link='',title=''):
            if not title:
                title = link
            if not letter:
                letter = ''
            else:
                letter = str(letter).upper()
                if str(letter).startswith('.'):
                    letter = ''
                else:
                    letter = letter[0]
            return "SetMarkerByCoords(map,%s,%s,'%s','%s','%s', '%s');\n" \
                    % (str(lat),str(lng),letter,str(link),str(title),str(target))
        def gmarkeraddr (address,letter='',link='',title=''):
            if not title:
                title = link
            if not letter:
                letter = ''
            else:
                letter = str(letter).upper()
                if str(letter).startswith('.'):
                    letter = ''
                else:
                    letter = letter[0]
            return "SetMarkerByAddress(map,'%s','%s','%s','%s','%s',geocoder);\n" \
                    % (str(address),letter,str(link),str(title),str(target))

        # Set initial map type
        type = 'NORMAL'
        types = []
        types_str = None
        if 'types' in kwargs:
            types = unicode(kwargs['types']).upper().split(':')
            types_str = ','.join(map(gtyp,types))
            type = types[0]

        if 'type' in kwargs:
            type = unicode(kwargs['type']).upper()
            if 'types' in kwargs and not type in types:
                types_str += ',' + type
                types.insert(0, type)
            elif not type in _supported_map_types:
                type = 'NORMAL'
            # if types aren't set and a type is set which is supported 
            # but not a default type:
            if not 'types' in kwargs and type in _supported_map_types and not type in _default_map_types:
                   # enable type (and all default types):
                   types = _default_map_types + [type]
                   types_str = ','.join(map(gtyp,types))

        if types_str:
            types_str = '[' + types_str + ']'
        else:
            types_str = 'G_DEFAULT_MAP_TYPES'

        # Produce controls
        control_str = ""
        controls = ['LargeMap','MapType']
        if 'controls' in kwargs:
            controls = []
            for control in unicode(kwargs['controls']).upper().split(':'):
                if control in _supported_controls:
                    controls.append( _supported_controls[control] )
        controls_str = ''.join(map(gcontrol,controls))

        # Produce markers
        markers_str = ""
        if not 'marker' in kwargs:
            kwargs['marker'] = []
        if 'markers' in kwargs:
            kwargs['marker'].extend( parse_args( unicode(kwargs['markers']), delim='|',
                                      listonly=True) )
        if kwargs['marker']:
            markers = []
            for marker in kwargs['marker']:
                location, letter, link, title = parse_args( marker,
                        delim=';', listonly=True, minlen=4 )[:4]
                if not title:
                    title = link

                # Convert wiki to HTML link:
                link = extract_link(self.env, formatter.context, link)
                if isinstance(link, Element):
                    link = link.attrib.get('href')
                else:
                    link = ''

                location = self._format_address(location)
                if _reCOORDS.match(location):
                    coord = location.split(':')
                    markers.append( gmarker( coord[0], coord[1], letter, link, title ) )
                else:
                    if self.geocoding_server:
                        coord = []
                        if location == 'center':
                            if address:
                                coord = self._get_coords(address)
                            else:
                                coord = center.split(',')
                        else:
                            coord = self._get_coords(location)
                        markers.append( gmarker( coord[0], coord[1], letter, link, title ) )
                    else:
                        if location == 'center':
                            if address:
                                markers.append( gmarkeraddr( address, letter, link, title ) )
                            else:
                                coord = center.split(',')
                                markers.append( gmarker( coord[0], coord[1], letter, link, title ) )
                        else:
                            markers.append( gmarkeraddr( location, letter, link, title) )
            markers_str = ''.join( markers )

        # Get macro count from request object
        req = formatter.req
        count = getattr (req, COUNT, 0)
        id = 'tracgooglemap-%s' % count
        setattr (req, COUNT, count + 1)

        # Canvas for this map
        mapdiv = tag.div (
                    "Google Map is loading ... (JavaScript enabled?)",
                    id=id,
                    style = "width: %s; height: %s;" % (width,height),
                    class_ = "tracgooglemap"
                )

        if 'from' in kwargs and 'to' in kwargs:
            directions = "from: %s to: %s" % (kwargs['from'],' to: '.join(list(kwargs['to'])))
            mapnmore = tag.table(
                            tag.tr(
                                tag.td(
                                    tag.div( "", 
                                        class_ = 'tracgooglemap-directions',
                                        id     = 'tracgooglemap-directions-%s' % count
                                    ),
                                    style="vertical-align:top;",
                                ),
                                tag.td(
                                    mapdiv,
                                    style="vertical-align:top;",
                                )
                            ),
                          class_ = 'tracgooglemaps'
                       )

        else:
            directions = ""
            mapnmore = mapdiv

        # put everything in a tidy div
        html = tag.div(
                [
                    # Initialization script for this map
                    tag.script ( Markup( _javascript_code % { 'id':id,
                        'center':center,
                        'zoom':zoom, 'address':address,
                        'type':type, 'width':width, 'height':height,
                        'types_str':types_str, 'controls_str':controls_str,
                        'markers_str':markers_str, 'directions':directions,
                        } ),
                        type = "text/javascript"),
                    mapnmore
                    ],
                class_ = "tracgooglemap-parent"
                );

        return html;
Example #6
0
    def expand_macro(self, formatter, name, content, args=None):
        content = content.replace('\n', ',')
        largs, kwargs = parse_args(content, multi=['marker', 'to'])
        if len(largs) > 0:
            arg = unicode(largs[0])
            if _reCOORDS.match(arg):
                if not 'center' in kwargs:
                    kwargs['center'] = arg
            else:
                if not 'address' in kwargs:
                    kwargs['address'] = arg
        if 'from' in kwargs and not 'address' in kwargs and not 'center' in kwargs:
            arg = unicode(kwargs['from'])
            if _reCOORDS.match(arg):
                if not 'center' in kwargs:
                    kwargs['center'] = arg
            else:
                if not 'address' in kwargs:
                    kwargs['address'] = arg

        # Check if Google API key is set (if not the Google Map script file
        # wasn't inserted by `post_process_request` and the map wont load)
        if not self.api_key:
            raise TracError(
                "No Google Maps API key given! Tell your web admin to get one at http://code.google.com/apis/maps/signup.html .\n"
            )

        # Use default values if needed
        zoom = None
        size = None
        try:
            if 'zoom' in kwargs:
                zoom = unicode(int(kwargs['zoom']))
            else:
                zoom = unicode(self.default_zoom)
        except:
            raise TracError(
                "Invalid value for zoom given! Please provide an integer from 0 to 19."
            )

        if 'size' in kwargs:
            size = unicode(kwargs['size'])
        else:
            size = unicode(self.default_size)

        # Set target for hyperlinked markers
        target = ""
        if not 'target' in kwargs:
            kwargs['target'] = self.default_target
        if kwargs['target'] in ('new', 'newwindow', '_blank'):
            target = "newwindow"

        # Get height and width
        width = None
        height = None
        try:
            if size.find(':') != -1:
                (width, height) = size.lower().split(':')
                # Check for correct units:
                if    not width[-2:]  in _css_units \
                   or not height[-2:] in _css_units:
                    raise TracError("Wrong unit(s)!")
                # The rest must be a number:
                float(width[:-2])
                float(height[:-2])
            else:
                (width, height) = size.lower().split('x')
                width = str(int(width)) + "px"
                height = str(int(height)) + "px"
        except:
            raise TracError("Invalid value for size given! Please provide "
                            "{width}x{height} in pixels (without unit) or "
                            "{width}{unit}:{height}{unit} in CSS units (%s)." \
                                    % ', '.join(_css_units) )

        # Correct separator for 'center' argument because comma isn't allowed in
        # macro arguments
        center = ""
        if 'center' in kwargs:
            center = unicode(kwargs['center']).replace(':', ',').strip(' "\'')
            if not _reCOORDS.match(center):
                raise TracError("Invalid center coordinates given!")

        # Format address
        address = ""
        if 'address' in kwargs:
            address = self._format_address(kwargs['address'])
            if self.geocoding_server:
                coord = self._get_coords(address)
                center = ",".join(coord[0:2])
                address = ""
                if not 'zoom' in kwargs:
                    zoom = _accuracy_to_zoom[int(coord[2])]

        # Internal formatting functions:
        def gtyp(stype):
            return "G_%s_MAP" % str(stype)

        def gcontrol(control):
            return "map.addControl(new G%sControl());\n" % str(control)

        def gmarker(lat, lng, letter='', link='', title=''):
            if not title:
                title = link
            if not letter:
                letter = ''
            else:
                letter = str(letter).upper()
                if str(letter).startswith('.'):
                    letter = ''
                else:
                    letter = letter[0]
            return "SetMarkerByCoords(map,%s,%s,'%s','%s','%s', '%s');\n" \
                    % (str(lat),str(lng),letter,str(link),str(title),str(target))

        def gmarkeraddr(address, letter='', link='', title=''):
            if not title:
                title = link
            if not letter:
                letter = ''
            else:
                letter = str(letter).upper()
                if str(letter).startswith('.'):
                    letter = ''
                else:
                    letter = letter[0]
            return "SetMarkerByAddress(map,'%s','%s','%s','%s','%s',geocoder);\n" \
                    % (str(address),letter,str(link),str(title),str(target))

        # Set initial map type
        type = 'NORMAL'
        types = []
        types_str = None
        if 'types' in kwargs:
            types = unicode(kwargs['types']).upper().split(':')
            types_str = ','.join(map(gtyp, types))
            type = types[0]

        if 'type' in kwargs:
            type = unicode(kwargs['type']).upper()
            if 'types' in kwargs and not type in types:
                types_str += ',' + type
                types.insert(0, type)
            elif not type in _supported_map_types:
                type = 'NORMAL'
            # if types aren't set and a type is set which is supported
            # but not a default type:
            if not 'types' in kwargs and type in _supported_map_types and not type in _default_map_types:
                # enable type (and all default types):
                types = _default_map_types + [type]
                types_str = ','.join(map(gtyp, types))

        if types_str:
            types_str = '[' + types_str + ']'
        else:
            types_str = 'G_DEFAULT_MAP_TYPES'

        # Produce controls
        control_str = ""
        controls = ['LargeMap', 'MapType']
        if 'controls' in kwargs:
            controls = []
            for control in unicode(kwargs['controls']).upper().split(':'):
                if control in _supported_controls:
                    controls.append(_supported_controls[control])
        controls_str = ''.join(map(gcontrol, controls))

        # Produce markers
        markers_str = ""
        if not 'marker' in kwargs:
            kwargs['marker'] = []
        if 'markers' in kwargs:
            kwargs['marker'].extend(
                parse_args(unicode(kwargs['markers']),
                           delim='|',
                           listonly=True))
        if kwargs['marker']:
            markers = []
            for marker in kwargs['marker']:
                location, letter, link, title = parse_args(marker,
                                                           delim=';',
                                                           listonly=True,
                                                           minlen=4)[:4]
                if not title:
                    title = link

                # Convert wiki to HTML link:
                link = extract_link(self.env, formatter.context, link)
                if isinstance(link, Element):
                    link = link.attrib.get('href')
                else:
                    link = ''

                location = self._format_address(location)
                if _reCOORDS.match(location):
                    coord = location.split(':')
                    markers.append(
                        gmarker(coord[0], coord[1], letter, link, title))
                else:
                    if self.geocoding_server:
                        coord = []
                        if location == 'center':
                            if address:
                                coord = self._get_coords(address)
                            else:
                                coord = center.split(',')
                        else:
                            coord = self._get_coords(location)
                        markers.append(
                            gmarker(coord[0], coord[1], letter, link, title))
                    else:
                        if location == 'center':
                            if address:
                                markers.append(
                                    gmarkeraddr(address, letter, link, title))
                            else:
                                coord = center.split(',')
                                markers.append(
                                    gmarker(coord[0], coord[1], letter, link,
                                            title))
                        else:
                            markers.append(
                                gmarkeraddr(location, letter, link, title))
            markers_str = ''.join(markers)

        # Get macro count from request object
        req = formatter.req
        count = getattr(req, COUNT, 0)
        id = 'tracgooglemap-%s' % count
        setattr(req, COUNT, count + 1)

        # Canvas for this map
        mapdiv = tag.div("Google Map is loading ... (JavaScript enabled?)",
                         id=id,
                         style="width: %s; height: %s;" % (width, height),
                         class_="tracgooglemap")

        if 'from' in kwargs and 'to' in kwargs:
            directions = "from: %s to: %s" % (kwargs['from'], ' to: '.join(
                list(kwargs['to'])))
            mapnmore = tag.table(tag.tr(
                tag.td(
                    tag.div("",
                            class_='tracgooglemap-directions',
                            id='tracgooglemap-directions-%s' % count),
                    style="vertical-align:top;",
                ), tag.td(
                    mapdiv,
                    style="vertical-align:top;",
                )),
                                 class_='tracgooglemaps')

        else:
            directions = ""
            mapnmore = mapdiv

        # put everything in a tidy div
        html = tag.div(
            [
                # Initialization script for this map
                tag.script(Markup(
                    _javascript_code % {
                        'id': id,
                        'center': center,
                        'zoom': zoom,
                        'address': address,
                        'type': type,
                        'width': width,
                        'height': height,
                        'types_str': types_str,
                        'controls_str': controls_str,
                        'markers_str': markers_str,
                        'directions': directions,
                    }),
                           type="text/javascript"),
                mapnmore
            ],
            class_="tracgooglemap-parent")

        return html
Example #7
0
    def expand_macro(self, formatter, name, content, args=None):
        content = content.replace('\n', ',')
        args, kwargs = parse_args(content,
                                  multi=['markers', 'path', 'visible'])

        # HTML arguments used in Google Maps URL
        hargs = {
            'center': "50.805935,10.349121",
            #'zoom'   : "6",
            'key': self.key,
            'size': self.size,
            'hl': self.hl,
            'sensor': 'false',
        }

        # Set API version
        api = kwargs.get('api', self.api)
        if api not in self.google_url:
            api = self.api

        # Delete default zoom if user provides 'span' argument:
        if 'span' in kwargs:
            del hargs['zoom']

        # Copy given macro arguments to the HTML arguments
        for k, v in kwargs.iteritems():
            if k in self.allowed_args and v:
                hargs[k] = v

        # Check if API key exists
        if not 'key' in hargs and api == '1':  # TODO: check if old API still needs the key
            raise TracError("No Google Maps API key given!\n")

        # Get height and width
        try:
            if 'x' not in hargs['size']:
                hargs['size'] = hargs['size'] + 'x' + hargs['size']
            (width, height) = hargs['size'].split('x')
            if int(height) < 1:
                height = "1"
            elif int(height) > 640:
                height = "640"
            if int(width) < 1:
                width = "1"
            elif int(width) > 640:
                width = "640"
            hargs['size'] = "%sx%s" % (width, height)
        except:
            raise TracError(
                "Invalid `size` argument. Should be `<width>x<height>`.")

        if api == '1':
            # Correct separator for 'center' argument because comma isn't allowed in
            # macro arguments
            hargs['center'] = hargs['center'].replace(':', ',')
            if 'markers' in hargs:
                hargs['markers'] = [
                    marker.replace(':', ',') for marker in hargs['markers']
                ]

        # Build URL
        src = Href(self.google_url.get(api, ''))(**hargs)

        title = alt = "Google Static Map at %s" % hargs['center']
        # TODO: provide sane alternative text and image title

        if 'title' in kwargs:
            title = kwargs['title']

        return tag.img(
            class_="googlestaticmap",
            src=src,
            title=title,
            alt=alt,
            height=height,
            width=width,
        )