| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| """Support page construction. |
| |
| The page construction is an XHTML document consisting of several |
| independent components that, when put together, provide organization |
| to content. Each of these components is set as a method of Layout |
| class that can be instantiated later from application specific modules. |
| |
| When you create a new application package, you need to create a page |
| module for it and instantiate the Layout class provided here inside |
| it. Later, the following functions must be created: page_content(), |
| page_navibar() and main(). These functions are used to define the |
| content and navigation bar of your application. Both application |
| content and application navigation are logically organized using |
| variables passed through the URL. |
| |
| Application |
| =========== |
| |
| URL variable: app |
| |
| This variable contains the application id. It is a unique numerical |
| value that starts at 0 and increments one for each new application |
| that might be added. The application identified by number 0 is the one |
| used as default when no other application is provided. The |
| application identified by number 0 is added to database the first time |
| it is created as part of the initial configuration process. |
| |
| Application is the highest level of organization inside |
| `webenv.cgi' script. Inside applications, there is content in form |
| of pages and entries. Content can be grouped by categories. |
| |
| Pages |
| ===== |
| |
| URL variable: page |
| |
| This variable contains the page id. It is a unique numerical value |
| that starts at 0 and increments in one for each new page added to the |
| application. In contrast to applications, the page identified by |
| number 0 is not used as default page when no other page is provided. |
| This configuration is specific to each application and can be |
| customized inside each application individually, using string values |
| instead of numerical values when passing values to page variable. |
| |
| Generally, when a page variable isn't passed through the URL, the |
| application module uses the `content_list()' method from Layout class |
| to display a list of all available content entries while links to |
| content pages are displayed in the application navigation bar so users |
| can access them. The unique numerical value of content pages is |
| specific to each application, so there is one page 0 for each |
| application available. No page is added to database the first time the |
| database is created as part of the initial configuration process. |
| |
| Pages contain similar information to that described by contents with |
| few exceptions. Pages, in contrast to entries, can differentiate the |
| page title from the page name. The page title goes in the page content |
| itself and describes what the page is about with a phrase. On the |
| other hand, the page name is generaly one word describing the page |
| content and is used as link on the application navigation bar. When |
| no page name is explicitly provided, the first word of page title is |
| used instead. |
| |
| Pages are always accessible inside the same application while contents |
| aren't. Pages are permanently visible and linkend from each |
| application specific navigation bar. This kind of pages can be |
| managed by editors or administrators and can be marked as `draft' to |
| put it on a special state where it is possible for administrator, |
| editors and authors to work on it, but impossible for others to read |
| it until the page be marked as `published' by either the page author |
| or any members of editor's or administrator's groups. |
| |
| Pages can be converted to entires and the oposite. When convertion |
| occurs, unused information looses its meaning and is kept for |
| informative purpose, specially in situations when it might be needed |
| to realize a convertion back into the former state. Notice that in |
| order to realize such a back and forth convertion it is required that |
| both pages and entires share the same definition structure. In fact, |
| that they be the same thing, but able to differentiate themselves |
| either as page or entry (e.g., through a `type' field.). |
| |
| Pages content is under version control. When a page (or entry) is |
| changed, a verification is performed to determine whether the |
| information entered in edition matches the last record in the page |
| history table. When both the information coming from edition and the |
| last record in the page history table are the same (e.g., no change |
| happened) the edition action is cancelled and a message is printed out |
| to notify the action. Otherwise, when the information entered in |
| edition differs from the last record in the page history table, the |
| information comming from edition passes to be the last record in the |
| page history table. In case, a page be reverted to a revision |
| different to that one being currently the active page, the reverted |
| revision becomes the active page (e.g., by changing a `status' field |
| from `false' to `true' in the history table). |
| |
| Categories |
| ========== |
| |
| Categories exists to organize contents. When an entry is created it is |
| automatically linked to a category. Categories are managed by |
| administrators and editors only. Categories can be nested one another |
| and provide another way of finding information inside the web |
| environment. Categories are specific to each web application, just as |
| contents and pages are. The `Unknown' category is created when the |
| categories table is created for first time, as part of the initial |
| configuration process so if no explicit category assignation is set by |
| the user, a default value (the `Unknown' category in this case) is |
| used to satisfy the connection between contents and categories. |
| |
| Referential integrity |
| ===================== |
| |
| Referential integrity is not handle in the logic layer provided by |
| this module, but set inside the database system used to store the |
| information handled by this module. The most we do about it here, is |
| to display a confirmation message before committing such actions, so |
| you can be aware of them. |
| |
| """ |
| |
| import cgi |
| import cgitb; cgitb.enable() |
| import ConfigParser |
| from Apps import xhtml |
| |
| config = ConfigParser() |
| qs = cgi.parse() |
| |
| def qs_args(names={}): |
| """Returns query string arguments. |
| |
| The query string arguments are used to build links dynamically |
| and, this way, to create a browsable and logically organized web |
| environment. Such a construction generally needs to retrive some |
| of the values previously passed to the query string and add new |
| ones to it. |
| |
| names: A dictionary containing the variable name and value pair |
| used to build a new query string. |
| |
| When a variable is provied without a value, then its value is |
| retrived from the current query string. If a value isn't found |
| there neither, then the variable is removed from the new query |
| string. |
| |
| When a variable is provided with its value, then its value is used |
| to build the new query string. |
| |
| """ |
| output = '' |
| |
| names_keys = names.keys() |
| names_keys.sort() |
| |
| for key in names_keys: |
| if names[key] == '': |
| if key in qs: |
| names[key] = qs[key][0] |
| else: |
| continue |
| if output == '': |
| output = '?' |
| else: |
| output += '&' |
| output += key + '=' + str(names[key]) |
| |
| return config.get('webserver', 'baseurl') + output |
| |
| class Layout(xhtml.Strict): |
| """The Page Layout. |
| |
| The page layout is made by combining XHTML tags in specific ways. |
| These specific combinations make the page components which in turn |
| can be also combined. Some of these components can be reused and |
| others don't. The goal of this class is to define what such |
| components are and describe them well in order to understand how |
| to use them from application modules when building XHTML documents |
| dynamically. |
| |
| The page layout is initialized with a functional layout that can |
| be used as reference inside application modules, to create |
| variations of it. Generally, inside application packages, this |
| class is instantiated in a module named `page', variables are |
| reset and functions created in order to satisfy that application |
| needs. When you need to output one of the page components then you |
| use this class instantiated methods. When the method you need |
| doesn't exist in this class, then it is a good time for it to be |
| created, here ;). |
| |
| Notice that most methods defined in this class make direct use of |
| methods defined by Strict class inside the `xhtml' module. The |
| Strict class inside xhtml module is inherited inside this class so |
| all the methods there are also available here. Methods which |
| doesn't make a direct use of Strict methods are dependencies of |
| those which do make direct use of Strict methods. |
| |
| """ |
| |
| def __init__(self): |
| """Initialize page data.""" |
| self.name = 'Home' |
| self.title = 'The CentOS Project' |
| self.description = 'Community Enterprise Operating System' |
| self.keywords = 'centos, project, community, enterprise, operating system' |
| self.copyright = '2009-2011 The CentOS Project. All rights reserved.' |
| self.language = 'en' |
| |
| |
| |
| self.header = self.logo() |
| self.header += self.google_ad() |
| self.header += self.navibar() |
| self.header += self.releases() |
| self.header += self.page_links() |
| self.header += self.page_navibar() |
| |
| |
| |
| self.body = 'None' |
| |
| |
| |
| |
| self.footer = self.credits() |
| |
| def logo(self): |
| """Returns The CentOS Logo. |
| |
| The page logo is displayed on the top-left corner of the page. |
| We use this area to show The CentOS Logo, the main visual |
| representation of The CentOS Project. In order to print the |
| page logo correctly, the image related must be 78 pixels of |
| height. |
| |
| """ |
| attrs = [] |
| attrs.append({'id': 'logo'}) |
| attrs.append({'title': 'Community Enterprise Operating System', 'href': '/webenv/'}) |
| attrs.append({'src': config.get('webserver','baseurl') + 'public/images/centos-logo.png', 'alt': 'CentOS'}) |
| |
| return self.tag_div(attrs[0], [8,1], self.tag_a(attrs[1], [12,1], self.tag_img(attrs[2], [0,0]), 0), 1) |
| |
| def google_ad_example(self): |
| """Returns Google advertisement for offline testings.""" |
| title = 'Google Advertisement' |
| url = config.get('webserver','baseurl') + 'public/images/ads-sample-468x60.png' |
| image = self.tag_img({'src': url, 'alt': title}, [0,0]) |
| link = self.tag_a({'href': url, 'title': title}, [12,1], image) |
| output = self.tag_div({'class':'google-ad'}, [8,1], link, 1) |
| output += self.separator({'class':'page-line'}, [8,1]) |
| |
| return output |
| |
| def google_ad(self): |
| """Returns Google advertisement for online using.""" |
| |
| properties = {} |
| properties['google_ad_client'] = 'pub-6973128787810819' |
| properties['google_ad_width'] = '468' |
| properties['google_ad_height'] = '60' |
| properties['google_ad_format'] = '468x60_as' |
| properties['google_ad_type'] = 'text_image' |
| properties['google_ad_channel'] = '' |
| properties['google_color_border'] = '204c8d' |
| properties['google_color_bg'] = '345c97' |
| properties['google_color_link'] = '0000FF' |
| properties['google_color_text'] = 'FFFFFF' |
| properties['google_color_url'] = '008000' |
| |
| attrs = {} |
| attrs['type'] = "text/javascript" |
| |
| output = '<!--\n' |
| for key, value in properties.iteritems(): |
| output += ' '*16 + key + '="' + value + '";\n' |
| output += ' '*16 + '//-->\n' |
| |
| properties = self.tag_script(attrs, [12,1], output, 1) |
| |
| attrs['src'] = "http://pagead2.googlesyndication.com/pagead/show_ads.js" |
| |
| source = self.tag_script(attrs, [12,1], ' ', 0) |
| |
| output = self.tag_div({'class':'google-ad'}, [8,1], properties + source, 1) |
| output += self.separator({'class':'page-line'}, [8,1]) |
| |
| return output |
| |
| def navibar(self): |
| """Returns webenv navigation bar. |
| |
| The webenv navigation bar organizes links to main web |
| applications The CentOS Project makes use of. Links to these |
| web applications stay always visible, no matter what web |
| application the user be visiting (e.g., Wiki, Lists, Forums, |
| Projects, Bugs, Docs, Downloads and Sponsors.). Notice that |
| some of these web applications are out of `webenv.cgi' |
| scope and they need to code their own webenv navigation bars |
| in a way that coincide the one set by `webenv.cgi'. |
| |
| """ |
| names = ['Home', 'Wiki', 'Lists', 'Forums', 'Projects', 'Bugs', 'Docs', 'Downloads', 'Sponsors'] |
| attrs = [] |
| focus = self.name |
| |
| for i in range(len(names)): |
| if names[i].lower() == 'home': |
| attrs.append({'href': '/webenv/'}) |
| else: |
| attrs.append({'href': '/webenv/?app=' + names[i].lower()}) |
| |
| tabs = self.navibar_tabs(names, attrs, focus) |
| tabs += self.separator() |
| |
| return tabs |
| |
| def navibar_tabs(self, names, attrs, focus=''): |
| """Returns navigation tabs. |
| |
| The navigation tabs are the smaller components a navigation |
| bar like "top-level navigation bar" and "application |
| navigation bar" are made of. |
| |
| names: List containing link names of tabs. |
| |
| attrs: List containing a dictionary for each tab link name |
| inside the `names' list. Dictionaries inside attrs |
| argument contain the link attributes (e.g., accesskey, |
| title, and href) used by link names so they can be |
| linkable once rendered. |
| |
| focus: Name of the link marked as current. |
| |
| """ |
| navibar_tabs = '' |
| |
| for i in range(len(names)): |
| output = self.tag_span('', [0,0], str(names[i])) |
| output = self.tag_a(attrs[i], [16,1], output) |
| if str(names[i]).lower() == focus.lower(): |
| output = self.tag_span({'class': 'current'}, [12,1], output, 1) |
| else: |
| output = self.tag_span('', [12,1], output, 1) |
| navibar_tabs += output |
| |
| return self.tag_div({'class': 'tabs'}, [8,1], navibar_tabs, 1) |
| |
| def releases(self): |
| """Returns The CentOS Distribution last releases. |
| |
| This method introduces the `releases' method by providing |
| links to it. |
| |
| names: List containing release numbers in the form M.N, where M |
| means major release and N minor release. |
| |
| attrs: List containing a dictionary for each release number |
| provided in `names' argument. These dictionaries provide |
| the link attributes required by release numbers in order |
| for them to be transformed into valid links once the page |
| be rendered. |
| |
| """ |
| releases = '' |
| |
| names = [] |
| names.append('6.0') |
| |
| attrs = [] |
| attrs.append({'href': qs_args({'p':'releases', 'id': 6.0})}) |
| |
| |
| title = self.tag_a({'href': qs_args({'p':'releases'})}, [0,0], 'Last Releases') + ':' |
| title = self.tag_span({'class': 'title'}, [16,1], title) |
| |
| for i in range(len(names)): |
| link = self.tag_a(attrs[i], [20,1], names[i]) |
| if i == len(names) - 1: |
| span = self.tag_span({'class': 'last release'}, [16,1], link, 1) |
| else: |
| span = self.tag_span({'class': 'release'}, [16,1], link, 1) |
| releases += span |
| releases = self.tag_div({'class': 'left'}, [12,1], title + releases, 1) |
| |
| rsslink = self.tag_span('', [0,0], 'RSS') |
| rsslink = self.tag_a({'href': qs_args({'rss':'releases'}), 'title': 'RSS'}, [20,1], rsslink) |
| rsslink = self.tag_span({'class': 'rss'}, [16,1], rsslink, 1) |
| rsslink = self.tag_div({'class': 'right'}, [12, 1], rsslink, 1) |
| |
| return self.tag_div({'id': 'last-releases'}, [8,1], releases + rsslink, 1) |
| |
| def user_links_logs(self): |
| """Return links related to user's logs. |
| |
| This function introduces the `logs' module. The `logs' module |
| registers all user's activity, from login to logout. This link |
| must be display/accessible only after a user has successfully |
| login. |
| |
| """ |
| last_visit = self.tag_a({'href': qs_args({'app':'', 'p':'logs'})}, [0,0], 'Logs') |
| return self.tag_div({'class': 'logs'}, [12, 1], last_visit, 1) |
| |
| def user_links_session(self): |
| """Returns links related to user's session. |
| |
| This function introduces the `session' module. The `session' |
| module provides state to user interactions so their action can |
| be registered individually. |
| |
| """ |
| names = [] |
| attrs = [] |
| session = '' |
| |
| names.append('Lost your password?') |
| attrs.append({'href': qs_args({'app':'', 'p':'lostpwd'})}) |
| names.append('Register') |
| attrs.append({'href': qs_args({'app':'', 'p':'register'})}) |
| names.append('Login') |
| attrs.append({'href': qs_args({'app':'', 'p':'login'})}) |
| |
| for i in range(len(names)): |
| output = self.tag_a(attrs[i], [20,1], str(names[i]), 0) |
| if i == len(names) - 1: |
| output = self.tag_span({'class': 'last'}, [16,1], output, 1) |
| else: |
| output = self.tag_span('', [16,1], output, 1) |
| session += output |
| |
| return self.tag_div({'class': 'session'}, [12,1], session, 1) |
| |
| def user_links_trails(self, names=['None'], attrs=[{'href': '/webenv/'}]): |
| """Returns page trails (a.k.a. breadcrumbs). |
| |
| The page breadcrumbs record the last pages the user visited |
| inside the current web application. Notice that page |
| breadcrumbs are user-specific information, so it isn't |
| possible to implement them until a way to manage user sessions |
| be implemeneted inside `webenv.cgi' script. Until then, |
| keep the tag construction commented and return an empty value. |
| |
| names: List with trail link names. |
| |
| attrs: Dictionary with trail link attributes. |
| |
| """ |
| links = '' |
| |
| for i in range(len(names)): |
| if i == len(names) - 1: |
| output = self.tag_span({'class':'last'}, [16,1], self.tag_a(attrs[i], [20, 1], names[i]), 1) |
| else: |
| output = self.tag_span('', [16,1], self.tag_a(attrs[i], [20, 1], names[i], 0), 1) |
| links += output |
| |
| return self.tag_div({'class': 'trail'}, [12,1], links, 1) |
| |
| def user_links(self): |
| """Returns user related links. |
| |
| The user links are specific to each web application. They are |
| shown over the application navigation bar. |
| |
| """ |
| userlinks = self.user_links_logs() |
| userlinks += self.user_links_session() |
| userlinks += self.user_links_trails() |
| |
| return self.tag_div({'class': 'userlinks'}, [8,1], userlinks, 1) |
| |
| def page_navibar(self, names=['Welcome'], attrs=[{'href':'/webenv/?p=welcome'}], focus='Welcome'): |
| """Returns navigation bar for application main pages. |
| |
| names: List containing link names. |
| |
| attrs: List containing one dictionary for each link name in |
| `names' argument. Dictionaries here contain the link |
| attributes needed to make linkable tabs once the page is |
| rendered. |
| |
| """ |
| navibar_app = self.navibar_tabs(names, attrs, focus) |
| navibar_app += self.separator({'class': 'page-line white'}, [8,1]) |
| |
| return navibar_app |
| |
| def separator(self, attrs={'class': 'page-line'}, indent=[16,1]): |
| """Returns separator. |
| |
| The separator construction is mainly used to clear both sides |
| inside the page, specially when floating elements are around. |
| |
| attrs: Dictionary containing hr's div attributes. |
| |
| indent: List containing hr's div indentation values. |
| |
| """ |
| line = self.tag_hr({'style': 'display:none;'}, [0,0]) |
| line = self.tag_div(attrs, indent, line) |
| |
| return line |
| |
| def license(self): |
| """Retruns license link.""" |
| license = 'Creative Commons Attribution-Share Alike 3.0 Unported License' |
| license = self.tag_a({'href': 'http://creativecommons.org/licenses/by-sa/3.0/'}, [0,0], license) + '.' |
| |
| return license |
| |
| def metadata(self): |
| """Returns metadata.""" |
| metadata = self.tag_meta({'http-equiv': 'content-type', 'content': 'text/html; charset=UTF-8'}, [4,1]) |
| metadata += self.tag_meta({'http-equiv': 'content-style-type', 'content': 'text/css'}, [4,0]) |
| metadata += self.tag_meta({'http-equiv': 'content-language', 'content': str(self.language)}, [4,1]) |
| metadata += self.tag_meta({'name': 'keywords', 'content': str(self.keywords)}, [4,0]) |
| metadata += self.tag_meta({'name': 'description', 'content': str(self.description)}, [4,1]) |
| metadata += self.tag_meta({'name': 'copyright', 'content': 'Copyright © ' + str(self.copyright)}, [4,0]) |
| metadata += self.tag_title('', [4,1], self.title) |
| metadata += self.tag_link({'href': config.get('webserver','baseurl') + 'public/stylesheet.css','rel': 'stylesheet', 'type': 'text/css'}, [4,0]) |
| metadata += self.tag_link({'href': config.get('webserver','baseurl') + 'public/centos-fav.png', 'rel': 'shortcut icon', 'type': 'image/png'}, [4,1]) |
| |
| return self.tag_head('', [0,1], metadata) |
| |
| def searchform(self, size=15): |
| """Returns search form. |
| |
| The search form redirects user from the current page onto the |
| search page, where the keywords previously introduced in the |
| input field are processed then. |
| |
| size: A number discribing how large the search box is. |
| |
| """ |
| input = self.tag_input({'type':'text', 'value':'', 'size':size}, [0,0]) |
| |
| action = self.tag_dt({}, [20,1], 'Search') |
| action += self.tag_dd({}, [20,1], input) |
| action = self.tag_dl({'class':'search'}, [16,1], action, 1) |
| |
| return self.tag_form({'action': qs_args({'app':'', 'p':'search'}), |
| 'method':'post', 'title':'Search'}, |
| [12,1], action, 1) |
| |
| def content_resumen(self, attrs, id, title, user_id, commit_date, |
| update_date, category_id, comments, abstract): |
| """Returns content resumen. |
| |
| The content resumen is used to build the list of contents, |
| output by `content_list()' method. The content resumen intends |
| to be concise and informative so the user can grab a general |
| idea about the related content and what it is about. |
| |
| attrs: A dictionary discribing the rows style. This is useful |
| to alternate the row background colors. |
| |
| id: A unique numerical value referring the content |
| identification. This is the value used on administrative |
| tasks like updating and deleting. |
| |
| title: A few words phrase describing the content, up to 255 |
| characters. |
| |
| author_id: A string referring the user email address, as |
| specified by RFC2822. The user email address is used as id |
| inside The CentOS User LDAP server, where user specific |
| information (e.g., surname, lastname, office, phone, etc.) |
| are stored in. This is the field that bonds the user with |
| the content he/she produces. |
| |
| commit_date: A string referring the timestamp the content |
| arrived to database for time. |
| |
| update_date: A string representing the timestamp the content |
| was updated/revised for last time. |
| |
| category_id: A number refering the category id the content is |
| attached to. |
| |
| abstract: One paragraphs describing the content. This |
| information is used to build the page metadata |
| information. When this value is not provided no abstract |
| information is displayed in the page, but the <meta |
| name="description".../> is built using article's first 255 |
| characters. |
| |
| comments: A number representing how many comments the content |
| has received since it is in the database. |
| |
| The content itself is not displayed in the resumen, but in |
| `content_details()'. |
| |
| """ |
| title = self.tag_a({'href': qs_args({'app':'', 'p':'entry', 'id':id})}, [0,0], title) |
| title = self.tag_h3({'class': 'title'}, [20,1], title, 0) |
| info = self.content_info(id, user_id, commit_date, |
| update_date, category_id, comments, |
| abstract) |
| return self.tag_div(attrs, [16,1], title + info, 1) |
| |
| def pagination(self): |
| """Return content pagination.""" |
| previous = self.tag_a({'href':''}, [0,0], 'Previous') |
| previous = self.tag_span({'class':'previous'}, [20,1], previous) |
| next = self.tag_a({'href':''}, [0,0], 'Next') |
| next = self.tag_span({'class':'next'}, [20,1], next) |
| separator = self.separator({'class':'page-line'}, [20,1]) |
| return self.tag_div({'class':'pagination'}, [16,1], previous + |
| next + separator, 1) |
| |
| def content_info(self, content_id, user_id, commit_date, |
| update_date, category_id, comments, abstract): |
| """Return content information. |
| |
| The content information provides a reduced view of content so |
| people can make themselves an idea of what the content talks |
| about. The content information displays content's title, |
| author, timestamp, related category, number of comments and an |
| abstract of the whole content. |
| |
| """ |
| categories = [] |
| categories.append('Unknown') |
| categories.append('Erratas') |
| categories.append('Articles') |
| categories.append('Events') |
| |
| if category_id <= len(categories): |
| category_name = categories[category_id].capitalize() |
| else: |
| category_id = 0 |
| category_name = categories[category_id].capitalize() |
| |
| category_name = self.tag_a({'href': qs_args({'app':'', 'p':'categories', 'id':category_id})}, [0,0], category_name) |
| category_name = self.tag_span({'class':'category'}, [24,1], category_name) |
| |
| users = {} |
| users['al@centos.org'] = 'Alain Reguera Delgado' |
| users['ana@centos.org'] = 'Ana Tamara Reguera Gattorno' |
| users['alina@centos.org'] = 'Alina Reguera Gattorno' |
| |
| if user_id in users.keys(): |
| user_name = self.tag_a({'href':'mailto:' + user_id}, [0,0], users[user_id]) |
| user_name = self.tag_span({'class':'author'}, [24,1], 'Written by ' + user_name) |
| |
| if update_date != commit_date: |
| date = self.tag_span({'class':'date'}, [24,1], update_date) |
| else: |
| date = self.tag_span({'class':'date'}, [24,1], commit_date) |
| |
| |
| comments_attrs = {'href': qs_args({'app':'', 'p':'entry', 'id':content_id}) + '#comments'} |
| if comments == 1: |
| comments = self.tag_a(comments_attrs, [0,0], str(comments) + ' comment') |
| elif comments > 1: |
| comments = self.tag_a(comments_attrs, [0,0], str(comments) + ' comments') |
| else: |
| comments = 'No comments' |
| comments = self.tag_span({'class':'comment'}, [24,1], comments) |
| |
| abstract = self.tag_p({'class':'abstract'}, [24,1], abstract) |
| |
| return self.tag_div({'class': 'info'}, [20,1], user_name + date + category_name + comments + abstract, 1) |
| |
| def content_list(self): |
| """Return list of content. |
| |
| The list of content is used to explore the content available |
| inside specific pages of specific web applications. The |
| information is displayed through paginated rows of content |
| that can be filtered to reduce the search results based on |
| patterns. By default, the list of content displays 15 rows, |
| but this value can be changed in user's preferences. |
| |
| """ |
| output = '' |
| count = 0 |
| rows = [] |
| rows.append([0, 'Introduction to CentOS Web Environment', |
| 'al@centos.org', |
| '2011-8-30 12:33:11', |
| '2011-8-30 12:33:11', |
| 0, |
| 0, |
| 'This is the abstract paragrah of content. '*10]) |
| rows.append([1, 'Creating New Applications', |
| 'al@centos.org', |
| '2011-8-30 12:33:11', |
| '2011-8-30 12:33:11', |
| 2, |
| 1, |
| 'This is the abstract paragrah of content. '*5]) |
| rows.append([2, 'Texinfo Documentation Backend', |
| 'al@centos.org', |
| '2011-8-30 12:33:11', |
| '2011-8-30 12:33:11', |
| 1, |
| 5, |
| 'This is the abstract paragrah of content. '*8]) |
| |
| for row in rows: |
| if count == 0: |
| attrs = {'class': 'dark row'} |
| count += 1 |
| else: |
| attrs = {'class': 'light row'} |
| count = 0 |
| output += self.content_resumen(attrs, *row) |
| |
| list = output + self.pagination() + self.separator() |
| list = self.tag_div({'id':'content-list'}, [12,1], list, 1) |
| actions = self.searchform() + self.categories() + self.archives() |
| actions = self.tag_div({'id':'content-actions'}, [8,1], actions, 1) |
| |
| return actions + list |
| |
| def content_details(self): |
| """Return content details. |
| |
| The content detail is shown for contents and pages. |
| """ |
| output = '' |
| rows = [] |
| rows.append([0, 'Introduction to CentOS Web Environment', |
| 'al@centos.org', |
| '2011-8-30 12:33:11', |
| '2011-8-30 12:33:11', |
| 0, |
| 0, |
| 'This is the abstract paragrah of content. '*10, |
| 'This is the first paragraph of content'*10 + "\n" |
| 'This is the second paragraph of content'*20 + |
| "\n" + 'This is the third paragraph of content.'*10 + "\n"]) |
| rows.append([1, 'Creating New Applications', |
| 'al@centos.org', |
| '2011-8-30 12:33:11', |
| '2011-8-30 12:33:11', |
| 2, |
| 1, |
| 'This is the abstract paragrah of content. '*5, |
| "This is the first paragraph of content\n\ |
| This is the second paragraph of content.\n\ |
| This is the third paragraph of content."]) |
| rows.append([2, 'Texinfo Documentation Backend', |
| 'al@centos.org', |
| '2011-8-30 12:33:11', |
| '2011-8-30 12:33:11', |
| 1, |
| 5, |
| 'This is the abstract paragrah of content. '*8, |
| "This is the first paragraph of content.\n\ |
| This is the second paragraph of content.\n\ |
| This is the third paragraph of content."]) |
| |
| if 'id' in qs: |
| id = int(qs['id'][0]) |
| title = rows[id][1] |
| email = rows[id][2] |
| commit_date = rows[id][3] |
| update_date = rows[id][4] |
| category = rows[id][5] |
| comments = rows[id][6] |
| abstract = self.tag_p({}, [0,0], rows[id][7]) |
| |
| output = self.tag_h1({'class':'title'}, [12,1], title) |
| output += self.content_info(id, email, commit_date, update_date, category, comments, abstract) |
| output += self.tag_p({}, [20,1], rows[id][8]) |
| output += self.comments() |
| |
| return self.tag_div({'id':'content-details'}, [12,1], output, 1) |
| |
| def comments(self): |
| """Returns content specific list of comments. |
| |
| """ |
| output = self.tag_a({'name':'comments'}, [0,0], 'Comments') |
| output = self.tag_h2({'class':'title comments'}, [12,1], output, 0) |
| |
| return output |
| |
| def categories(self): |
| """Returns list of categories. |
| |
| """ |
| categories = ['Unknown', 'Articles', 'Erratas', 'Events'] |
| dt = self.tag_dt({}, [16,1], 'Categories') |
| dd = '' |
| for id in range(len(categories)): |
| category_attrs = {'href': qs_args({'app':'', 'p':'categories', 'id':id})} |
| a = self.tag_a(category_attrs, [0,0], categories[id] + ' (0)') |
| dd += self.tag_dd({}, [16,1], a) |
| |
| return self.tag_dl({},[12,1], dt + dd, 1) |
| |
| def archives(self): |
| """Returns archives.""" |
| archives = {} |
| archives['2011'] = ['January', 'February', 'March', 'April', 'May'] |
| archives['2010'] = ['January', 'February'] |
| |
| dt = self.tag_dt({}, [16,1], 'Archives') |
| year_dl = '' |
| year_dd = '' |
| |
| for key in archives.keys(): |
| year_dt = self.tag_dt({},[20,1], key) |
| for id in range(len(archives[key])): |
| a = self.tag_a({'href': qs_args({'app':'', 'p':'archives', 'year': key, 'month': id + 1})}, [0,0], archives[key][id] + ' (0)') |
| year_dd += self.tag_dd({}, [20,1], a) |
| year_dl += self.tag_dl({'class':'year'}, [16,1], year_dt + year_dd, 1) |
| year_dd = '' |
| |
| return self.tag_dl({},[12,1], dt + year_dl, 1) |
| |
| def page_top(self): |
| """Returns page top anchor.""" |
| return self.tag_a({'name':'top'}, [0,1]) |
| |
| def page_header(self): |
| """Returns page header. |
| |
| The page_header is common to all application modules and |
| """ |
| return self.tag_div({'id': 'page-header'}, [4,1], self.header, 1) |
| |
| def page_body(self): |
| """Returns page body. |
| |
| The page_body is specific to each application module and is |
| there where it must be constructed. The construction itself |
| takes place through the `page_content()' function which does a |
| return through an instantiated `content_' prefixed method. |
| The `content_' prefixed method used depends on the kind of |
| content you want to print out (e.g., `content_list()' for a |
| content list, `detail()' for a detailed view of content, |
| etc.). Later, the `body' variable instantiated from this class |
| is reset in the `main()' function with the value returned from |
| `page_content()' so the desired content layout can be printed |
| out. |
| |
| """ |
| return self.tag_div({'id':'page-body'}, [4,1], self.body, 1) |
| |
| def page_links(self): |
| """Returns page links.""" |
| page_links = self.user_links() |
| return self.tag_div({'id': 'pagelinks'}, [8,1], page_links, 1) |
| |
| def page_footer(self): |
| """Retruns page footer.""" |
| return self.tag_div({'id': 'page-footer'}, [4,1], self.credits(), 1) |
| |
| def page_wrap(self): |
| """Returns page wrap.""" |
| return self.tag_div({'id': 'wrap'}, [0,1], self.page_header() + self.page_body() + self.page_footer(), 1) |
| |
| def admonition(self, title='Note', subtitle="", body=""): |
| """Returns page admonition. |
| |
| title: Admonition's title. |
| |
| subtitle: Admonition's subtitle. The value of this argument is |
| concatenated on the right side of title using a colon (:) |
| as separator. Notice that this value is expanded inside |
| the <h3> tag and there is no need to introduce extra tags |
| here. |
| |
| body: Admonition's body. The values passed through this |
| arguments needs to be XHTML code returned from |
| `self.tag()'. Preferably, paragraphs (p), tables (table), |
| lists (ul, ol, dl) and pre-formatted texts (pre). |
| |
| """ |
| if title == '': |
| return '' |
| else: |
| title = str(title.capitalize()) |
| |
| if subtitle != '': |
| subtitle = ': ' + str(subtitle.capitalize()) |
| |
| if body != '': |
| body = str(body) |
| |
| admonitions = ['Note', 'Tip', 'Important', 'Caution', 'Warning', 'Redirected', 'Success', 'Error'] |
| |
| if title in admonitions: |
| attrs = {'class': 'admonition ' + title.lower()} |
| image = self.tag_img({'src': config.get('webserver','baseurl') + 'public/images/' + title.lower() + '.png', 'alt': title}, [16,1]) |
| title = self.tag_h3({'class': 'title'}, [16,1], title + subtitle, 0) |
| output = image + title + body + self.separator() |
| else: |
| attrs = {'class': 'admonition unknown'} |
| title = self.tag_h3({'class': 'title'}, [16,1], title + subtitle, 1) |
| output = title + body |
| |
| return self.tag_div(attrs, [12,1], output, 1) |
| |
| def credits(self): |
| """Returns page credits.""" |
| copyright = self.tag_p({'class': 'copyright'}, [12,1], 'Copyright © ' + str(self.copyright)) |
| license = self.tag_p({'class': 'license'}, [12,1], 'This website is licensed under a ' + str(self.license())) |
| credits = self.tag_img({'src': config.get('webserver','baseurl') + 'public/images/top.png', 'alt': 'Top'}, [0,0]) |
| credits = self.tag_a({'title': 'Top', 'href': '#top'}, [16,1], credits) |
| credits = self.tag_div({'class': 'top'}, [12,1], credits, 1) |
| credits = str(credits) + str(copyright) + str(license) |
| credits = self.tag_div({'class': 'credits'}, [8,1], credits, 1) |
| |
| return credits |
| |
| def page(self): |
| """Returns page final output.""" |
| html = self.doctype() |
| html += self.tag_html({'xmlns': 'http://www.w3.org/1999/xhtml', 'dir': 'ltr', |
| 'lang': str(self.language), 'xml:lang': str(self.language)}, [0,1], |
| self.metadata() + self.page_top() + self.page_wrap()) |
| |
| return html |