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
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
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
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
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;
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
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, )