Blame Scripts/CentOS-Web/Apps/xhtml.py

cc10e6
#!/usr/bin/python
cc10e6
#
8f6ee0
# Apps.xhtml -- This module encapsulates XHTML output code needed by
7e8dd3
# web applications.
cc10e6
#
8f6ee0
# Copyright (C) 2011 The CentOS Project
cc10e6
#
cc10e6
# This program is free software; you can redistribute it and/or modify
cc10e6
# it under the terms of the GNU General Public License as published by
cc10e6
# the Free Software Foundation; either version 2 of the License, or (at
cc10e6
# your option) any later version.
cc10e6
#
cc10e6
# This program is distributed in the hope that it will be useful, but
cc10e6
# WITHOUT ANY WARRANTY; without even the implied warranty of
cc10e6
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
cc10e6
# General Public License for more details.
cc10e6
#
cc10e6
# You should have received a copy of the GNU General Public License
cc10e6
# along with this program; if not, write to the Free Software
cc10e6
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
cc10e6
#
cc10e6
# ----------------------------------------------------------------------
cc10e6
# $Id$
cc10e6
# ----------------------------------------------------------------------
cc10e6
cc10e6
import os
cc10e6
import cgi
cc10e6
import cgitb; cgitb.enable()
8f6ee0
8f6ee0
class Page:
cffc47
    """Xhtml page modeling."""
8f6ee0
8f6ee0
8f6ee0
    def __init__(self):
8f6ee0
        """Initialize page data."""
8f6ee0
        self.qs = cgi.parse_qs(os.environ['QUERY_STRING'])
8f6ee0
        self.name = 'Home'
8f6ee0
        self.title = 'The CentOS Project'
8f6ee0
        self.description = 'Community Enterprise Operating System'
8f6ee0
        self.keywords = 'centos, project, community, enterprise, operating system'
8f6ee0
        self.copyright = '2009-2011 The CentOS Project. All rights reserved.'
8f6ee0
        self.language = 'en'
8f6ee0
8f6ee0
8f6ee0
    def tag(self, name, attrs, indent=[8,1], content="", has_child=0):
8f6ee0
        """Returns XHTML tag definition.
8f6ee0
8f6ee0
        Arguments:
8f6ee0
8f6ee0
        name: The XHTML tag's name. Notice that this function doesn't
8f6ee0
            verify nor validate the XHTML tags you provide. It is up
8f6ee0
            to you write them correctly considering the XHTML standard
8f6ee0
            definition.
8f6ee0
8f6ee0
        attrs: The XHTML tag's attribute. Notice that this function
8f6ee0
            doesn't verify the attributes assignation to tags. You
8f6ee0
            need to know what attributes are considered valid to the
8f6ee0
            tag you are creating in order to build a well-formed XHTML
8f6ee0
            document. Such verification can be achived inside firefox
8f6ee0
            browser through the `firebug' plugin.
8f6ee0
8f6ee0
        indent: The XHTML tag's indentation (Optional). This argument
8f6ee0
            is a list of two numerical values. The first value in the
8f6ee0
            list represents the amount of horizontal spaces between
8f6ee0
            the beginning of line and the opening tag.  The second
8f6ee0
            value in the list represents the amount of vertical spaces
8f6ee0
            (new lines) between tags.
8f6ee0
8f6ee0
        content: The XHTML tag's content (Optional). This argument
8f6ee0
            provides the information the tag encloses. When this
8f6ee0
            argument is empty, tag is rendered without content.
8f6ee0
8f6ee0
        has_child: The XHTML tag has a child? (Optional). This
8f6ee0
            argument is specifies whether a tag has another tag inside
8f6ee0
            (1) or not (0).  When a tag has not a child tag,
8f6ee0
            indentation is applied between the tag content and the
8f6ee0
            closing tag provoking an unecessary spaces to be shown.
8f6ee0
            Such kind of problems are prevented by setting this option
8f6ee0
            to `0'. On the other hand, when a tag has a child tag
8f6ee0
            inside, using the value `1' will keep the closing tag
8f6ee0
            indentation aligned with the opening one.
8f6ee0
8f6ee0
        This function encapsulates the construction of XHTML tags.
8f6ee0
        Use this function wherever you need to create XHTML tags. It
8f6ee0
        helps to standardize tag constructions and their final output
650c2d
        and. This function provides a consistent way of producing
650c2d
        output for XHTML documents.
8f6ee0
        """
8f6ee0
        if indent[0] > 0:
8f6ee0
            h_indent = ' '*indent[0]
8f6ee0
        else:
8f6ee0
            h_indent = ''
8f6ee0
8f6ee0
        if indent[1] > 0: 
8f6ee0
            v_indent = "\n"*indent[1]
8f6ee0
        else:
8f6ee0
            v_indent = ''
cc10e6
    
8f6ee0
        output = v_indent + h_indent + '<' + str(name)
8f6ee0
        if len(attrs) > 0:
8f6ee0
            attr_names = attrs.keys()
8f6ee0
            attr_names.sort()
8f6ee0
            for attr_name in attr_names:
8f6ee0
                output += ' ' + str(attr_name) + '="' + str(attrs[attr_name]) + '"'
8f6ee0
        if content == '':
8f6ee0
            output += ' />'
cc10e6
        else:
8f6ee0
            output += '>'
8f6ee0
            output += str(content)
8f6ee0
            if has_child == 1:
8f6ee0
                output += h_indent + '</' + str(name) + '>'
8f6ee0
            else:
8f6ee0
                output += '</' + str(name) + '>'
8f6ee0
        output += v_indent
cc10e6
8f6ee0
        return output
cc10e6
cc10e6
8f6ee0
    def page_preamble(self):
8f6ee0
        """Return XHTML code of page preamble.
cc10e6
8f6ee0
        The page preamble sets the document type definition required
8f6ee0
        by the XHTML standard.
cc10e6
8f6ee0
        """
8f6ee0
        output = '' + "\n"
8f6ee0
        output += '
8f6ee0
        output += ' '*4 + 'PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"' + "\n"
8f6ee0
        output += ' '*4 + '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">' + "\n"
cc10e6
8f6ee0
        return output
cc10e6
cc10e6
8f6ee0
    def page_logo(self):
8f6ee0
        """Returns XHTML code of page logo.
cc10e6
8f6ee0
        The page logo is displayed on the top-left corner of the page.
8f6ee0
        We use this area to show The CentOS Logo, the main visual
8f6ee0
        representation of The CentOS Project. In order to print the
8f6ee0
        page logo correctly, the image related must be 78 pixels of
8f6ee0
        height.
7e8dd3
8f6ee0
        """
8f6ee0
        attrs = []
8f6ee0
        attrs.append({'id': 'logo'})
8f6ee0
        attrs.append({'title': 'Community Enterprise Operating System', 'href': '/centos-web/'})
8f6ee0
        attrs.append({'src': '/centos-web-pub/Images/centos-logo.png', 'alt': 'CentOS'})
cc10e6
8f6ee0
        return self.tag('div', attrs[0], [8,1], self.tag('a', attrs[1], [12,1], self.tag('img', attrs[2], [0,0], '', 0), 0), 1)
cc10e6
cc10e6
8f6ee0
    def page_ads_google(self):
8f6ee0
        """Returns XHTML code of Google advertisement (468x60 pixels)."""
8f6ee0
        output = """
cc10e6
        
cc10e6
            Google Advertisement
cc10e6
            <script type="text/javascript">
cc10e6
                google_ad_client = "pub-6973128787810819";
cc10e6
                google_ad_width = 468;
cc10e6
                google_ad_height = 60;
cc10e6
                google_ad_format = "468x60_as";
cc10e6
                google_ad_type = "text_image";
cc10e6
                google_ad_channel = "";
cc10e6
                google_color_border = "204c8d";
cc10e6
                google_color_bg = "345c97";
cc10e6
                google_color_link = "0000FF";
cc10e6
                google_color_text = "FFFFFF";
cc10e6
                google_color_url = "008000";
cc10e6
                //-->
cc10e6
            </script>
cc10e6
            
cc10e6
                src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
cc10e6
            </script>
cc10e6
        
cc10e6
cc10e6
        

8f6ee0
        """
8f6ee0
        return output
cc10e6
cc10e6
8f6ee0
    def page_navibar_top(self):
8f6ee0
        """Returns XHTML code of top-level navigation bar. 
cc10e6
    
8f6ee0
        The top-level navigation bar organizes links to the web
8f6ee0
        application The CentOS Project makes use of. Links in the
8f6ee0
        top-level navigation bar remain always visible, no matter what
8f6ee0
        web application you be visiting.
cc10e6
8f6ee0
        Notice that web application differe one another and is not
8f6ee0
        convenient to point them all to this definition. Instead, a
8f6ee0
        specific definition for each web application will be created
8f6ee0
        (based on this definition) in order for them to give the
8f6ee0
        impression of being connected. In this process, the top-level
8f6ee0
        navigation bar is adapted to each web application
8f6ee0
        characteristics and the related tab is set as current.
cc10e6
8f6ee0
        """
8f6ee0
        names = ['Home', 'Wiki', 'Lists', 'Forums', 'Projects', 'Bugs', 'Docs', 'Downloads', 'Sponsors']
8f6ee0
        attrs = []
8f6ee0
        focus = self.name
cc10e6
8f6ee0
        for i in range(len(names)):
8f6ee0
            attrs.append({'href': '/centos-web/?app=' + names[i].lower()})
8f6ee0
8f6ee0
        tabs = self.page_navibar_tabs(names, attrs, focus)
8f6ee0
        tabs += self.page_line()
8f6ee0
8f6ee0
        return tabs
8f6ee0
8f6ee0
8f6ee0
    def page_navibar_tabs(self, names, attrs, focus=''):
8f6ee0
        """Returns navigation tabs.
8f6ee0
8f6ee0
        Arguments:
8f6ee0
8f6ee0
        names: List of tab names.
8f6ee0
8f6ee0
        attrs: List of dictionaries for each tab name inside the
8f6ee0
            `names' list. Dictionaries inside attrs argument contain
8f6ee0
            the XHTML link attributes (e.g., accesskey, title, and
8f6ee0
            href) used by tab names so they can be linkable once
8f6ee0
            rendered.
cc10e6
    
8f6ee0
        focus: Name of the tab marked as current. When no value is
8f6ee0
            passed to this argument the `Home' value is used as
8f6ee0
            default value.
cc10e6
    
8f6ee0
        """
8f6ee0
        navibar_tabs = ''
cc10e6
8f6ee0
        for i in range(len(names)):
8f6ee0
            content = self.tag('span', '', [0,0], str(names[i]))
8f6ee0
            content = self.tag('a', attrs[i], [16,1], content)
8f6ee0
            if str(names[i]).lower() == focus.lower():
8f6ee0
                content = self.tag('span', {'class': 'current'}, [12,1], content, 1)
8f6ee0
            else:
8f6ee0
                content = self.tag('span', '', [12,1], content, 1)
8f6ee0
            navibar_tabs += content
cc10e6
8f6ee0
        return self.tag('div', {'class': 'tabs'}, [8,1], navibar_tabs, 1)
cc10e6
cc10e6
8f6ee0
    def page_lastreleases(self, names=['6.0'], attrs=[{'href': '/centos-web/?p=releases&id=6.0'}]):
8f6ee0
        """Returns last-release information and related RSS link."""
8f6ee0
        releases = ''
7e8dd3
b4f9dd
        title = self.tag('a', {'href': '/centos-web/?p=releases'}, [0,0], 'Last Releases') + ':'
b4f9dd
        title = self.tag('span', {'class': 'title'}, [16,1], title)
cc10e6
8f6ee0
        for i in range(len(names)):
8f6ee0
            link = self.tag('a', attrs[i], [20,1], names[i])
8f6ee0
            if i == len(names) - 1:
8f6ee0
                span = self.tag('span', {'class': 'last release'}, [16,1], link, 1) 
8f6ee0
            else:
8f6ee0
                span = self.tag('span', {'class': 'release'}, [16,1], link, 1) 
8f6ee0
            releases += span
8f6ee0
        releases = self.tag('div', {'class': 'left'}, [12,1], title + releases, 1)
cc10e6
b4f9dd
        rsslink = self.tag('span', '', [0,0], 'RSS')
b4f9dd
        rsslink = self.tag('a', {'href': '/centos-web/?print=rss', 'title': 'RSS'}, [20,1], rsslink)
b4f9dd
        rsslink = self.tag('span', {'class': 'rss'}, [16,1], rsslink, 1)
8f6ee0
        rsslink = self.tag('div', {'class': 'right'}, [12, 1], rsslink, 1)
7e8dd3
8f6ee0
        return self.tag('div', {'id': 'last-releases'}, [8,1], releases + rsslink, 1)
7e8dd3
cc10e6
8f6ee0
    def page_appslinks(self):
8f6ee0
        """Returns application related links."""
8f6ee0
        appslinks = self.page_userlinks()
8f6ee0
        return self.tag('div', {'id': 'appslinks'}, [8,1], appslinks, 1)
cc10e6
cc10e6
8f6ee0
    def page_lastvisit(self):
650c2d
        last_visit = self.tag('a', {'href': '/centos-web/?p=lastvisit'}, [0,0], 'Your last visit was at')
b4f9dd
        last_visit = self.tag('span', {'class': 'title'}, [16, 1], last_visit)
b4f9dd
        last_visit += self.tag('span', {'class': 'datetime'}, [16, 1], '...')
8f6ee0
        return self.tag('div', {'class': 'lastvisit'}, [12, 1], last_visit, 1)
cc10e6
cc10e6
8f6ee0
    def page_session(self):
8f6ee0
        """Returns information related to user's session."""
8f6ee0
        names = []
8f6ee0
        attrs = []
8f6ee0
        session = ''
8f6ee0
8f6ee0
        names.append('Lost your password?')
8f6ee0
        attrs.append({'href': '/centos-web/?p=lostpwd'})
8f6ee0
        names.append('Register')
8f6ee0
        attrs.append({'href': '/centos-web/?p=register'})
8f6ee0
        names.append('Login')
8f6ee0
        attrs.append({'href': '/centos-web/?p=login'})
8f6ee0
8f6ee0
        for i in range(len(names)):
8f6ee0
            output = self.tag('a', attrs[i], [20,1], str(names[i]), 0)
8f6ee0
            if i == len(names) - 1:
8f6ee0
                output = self.tag('span', {'class': 'last'}, [16,1], output, 1)
8f6ee0
            else:
8f6ee0
                output = self.tag('span', '', [16,1], output, 1)
8f6ee0
            session += output
8f6ee0
8f6ee0
        return self.tag('div', {'class': 'session'}, [12,1], session, 1)
cc10e6
cc10e6
8f6ee0
    def page_trail(self, names=['None'], attrs=[{'href': '/centos-web/'}]):
8f6ee0
        """Returns page trails (a.k.a. breadcrumbs).
cc10e6
    
8f6ee0
        The page breadcrumbs record the last pages visited inside the
8f6ee0
        current web application. Notice that page breadcrumbs are
8f6ee0
        user-specific information, so it isn't possible to implement
8f6ee0
        them until a way to manage user sessions be implemeneted
8f6ee0
        inside `centos-web.cgi' script. Until then, keep the tag
8f6ee0
        construction commented and return an empty value.
8f6ee0
8f6ee0
        """
8f6ee0
        links = ''
8f6ee0
8f6ee0
        for i in range(len(names)):
8f6ee0
            if i == len(names) - 1:
8f6ee0
                content = self.tag('span', {'class':'last'}, [16,1], self.tag('a', attrs[i], [20, 1], names[i]), 1)
8f6ee0
            else:
8f6ee0
                content = self.tag('span', '', [16,1], self.tag('a', attrs[i], [20, 1], names[i], 0), 1)
cffc47
            links += content
cc10e6
8f6ee0
        return self.tag('div', {'class': 'trail'}, [12,1], links, 1)
cc10e6
cc10e6
8f6ee0
    def page_userlinks(self):
8f6ee0
        """Returns user links.
cc10e6
8f6ee0
        Arguments:
cc10e6
8f6ee0
        names: List of links you want to have.
cc10e6
8f6ee0
        attrs: List of dictionaries with link attributes. In order for
8f6ee0
            links to be built correctly, both names and attrs lists
8f6ee0
            must coincide their indexes.
cc10e6
8f6ee0
        The user links are specific to each web application. They are
8f6ee0
        shown in the right-top corner of the application navigation
8f6ee0
        bar, just over the application navigation tabs.
cc10e6
8f6ee0
        """
8f6ee0
        userlinks = self.page_lastvisit()
8f6ee0
        userlinks += self.page_session()
8f6ee0
        userlinks += self.page_trail()
cc10e6
8f6ee0
        return self.tag('div', {'class': 'userlinks'}, [8,1], userlinks, 1)
cc10e6
cc10e6
8f6ee0
    def page_navibar_app(self, names=['Welcome'], attrs=[{'href':'/centos-web/?p=welcome'}], focus='Welcome'):
8f6ee0
        """Returns application's navigation bar."""
8f6ee0
8f6ee0
        navibar_app = self.page_navibar_tabs(names, attrs, focus)
8f6ee0
        navibar_app += self.page_line({'class': 'page-line white'}, [8,1])
8f6ee0
8f6ee0
        return navibar_app
8f6ee0
 
cc10e6
8f6ee0
    def page_line(self, attrs={'class': 'page-line'}, indent=[8,1]):
8f6ee0
        """Returns a division line."""
8f6ee0
        page_line = self.tag('hr', {'style': 'display:none;'}, [0,0])
8f6ee0
        page_line = self.tag('div', attrs, indent, page_line)
cc10e6
8f6ee0
        return page_line
cc10e6
cc10e6
8f6ee0
    def page_license(self):
8f6ee0
        """Retruns link to page license."""
8f6ee0
        license = 'Creative Commons Attribution-Share Alike 3.0 Unported License'
8f6ee0
        license = self.tag('a', {'href': 'http://creativecommons.org/licenses/by-sa/3.0/'}, [0,0], license) + '.'
cffc47
8f6ee0
        return license
cc10e6
cc10e6
8f6ee0
    def page_metadata(self):
8f6ee0
        """Returns page metadata."""
8f6ee0
        metadata = self.tag('meta', {'http-equiv': 'content-type', 'content': 'text/html; charset=UTF-8'}, [4,1])
8f6ee0
        metadata += self.tag('meta', {'http-equiv': 'content-style-type', 'content': 'text/css'}, [4,0])
8f6ee0
        metadata += self.tag('meta', {'http-equiv': 'content-language', 'content': str(self.language)}, [4,1])
8f6ee0
        metadata += self.tag('meta', {'name': 'keywords', 'content': str(self.keywords)}, [4,0])
8f6ee0
        metadata += self.tag('meta', {'name': 'description', 'content': str(self.description)}, [4,1])
8f6ee0
        metadata += self.tag('meta', {'name': 'copyright', 'content': 'Copyright © ' + str(self.copyright)}, [4,0])
8f6ee0
        metadata += self.tag('title', '', [4,1], self.title)
b4f9dd
        metadata += self.tag('link', {'href': '/centos-web-pub/stylesheet.css','rel': 'stylesheet', 'type': 'text/css'}, [4,0])
b4f9dd
        metadata += self.tag('link', {'href': '/centos-web-pub/Images/centos-fav.png', 'rel': 'shortcut icon', 'type': 'image/png'}, [4,1])
cc10e6
8f6ee0
        return self.tag('head', '', [0,1], metadata)
cc10e6
cc10e6
8f6ee0
    def page_content(self, content='Page empty.'):
8f6ee0
        """Returns page content."""
8f6ee0
        return content
cc10e6
cc10e6
cffc47
    def page_admonition(self, title='Note', subtitle="", content=""):
cffc47
        """Returns page admonition.
cffc47
        
cffc47
        Arguments:
cffc47
cffc47
        title: Admonition's title.
cffc47
cffc47
        subtitle: Admonition's subtitle. The value of this argument is
cffc47
            concatenated on the right side of title using a colon (:)
cffc47
            as separator. Notice that this value is expanded inside
cffc47
            the 

tag and there is no need to introduce extra tags

cffc47
            here.
cffc47
cffc47
        content: Admonition's content. The values passed through this
cffc47
            arguments needs to be XHTML code returned from
cffc47
            `self.tag()'. Preferably, paragraphs (p), tables (table),
cffc47
            lists (ul, ol, dl) and pre-formatted texts (pre).
cffc47
cffc47
        """
cffc47
        if title == '':
cffc47
            return ''
cffc47
        else:
cffc47
            title = str(title.capitalize())
cffc47
cffc47
        if subtitle != '':
cffc47
            subtitle = ': ' + str(subtitle.capitalize())
cffc47
cffc47
        if content != '':
cffc47
            content = str(content)
cffc47
cffc47
        admonitions = ['Note', 'Tip', 'Important', 'Caution', 'Warning', 'Redirected', 'Success', 'Error']
cffc47
        
cffc47
        if title in admonitions:
cffc47
            attrs = {'class': 'admonition ' + title.lower()}
cffc47
            image = self.tag('img', {'src': '/centos-web-pub/Images/' + title.lower() + '.png', 'alt': title}, [0,0])
cffc47
            title = self.tag('h3', {'class': 'title'}, [0,0], title + subtitle, 0)
cffc47
            output = image + title + content + self.page_line()
cffc47
        else:
cffc47
            attrs = {'class': 'admonition unknown'}
cffc47
            title = self.tag('h3', {'class': 'title'}, [16,1], title + subtitle, 1)
cffc47
            output = title + content
cffc47
        
cffc47
        return self.tag('div', attrs, [12,1], output, 1)
cffc47
cffc47
8f6ee0
    def page_credits(self):
8f6ee0
        """Returns page credits."""
b4f9dd
        copyright = self.tag('p', {'class': 'copyright'}, [12,1], 'Copyright © ' + str(self.copyright))
b4f9dd
        license = self.tag('p', {'class': 'license'}, [12,1], 'This website is licensed under a ' + str(self.page_license()))
8f6ee0
        credits = self.tag('img', {'src': '/centos-web-pub/Images/top.png', 'alt': 'Top'}, [0,0])
8f6ee0
        credits = self.tag('a', {'title': 'Top', 'href': '#top'}, [16,1], credits)
8f6ee0
        credits = self.tag('div', {'class': 'top'}, [12,1], credits, 1)
8f6ee0
        credits = str(credits) + str(copyright) + str(license) 
8f6ee0
        credits = self.tag('div', {'class': 'credits'}, [8,1], credits, 1)
7e8dd3
8f6ee0
        return credits
cc10e6
cc10e6
8f6ee0
    def page(self):
8f6ee0
        """Returns page final output."""
8f6ee0
        page_header = self.page_logo()
8f6ee0
        page_header += self.page_ads_google()
8f6ee0
        page_header += self.page_navibar_top()
8f6ee0
        page_header += self.page_lastreleases()
8f6ee0
        page_header += self.page_appslinks()
8f6ee0
        page_header += self.page_navibar_app()
8f6ee0
        page_header = self.tag('div', {'id': 'page-header'}, [4,1], page_header, 1)
cc10e6
8f6ee0
        page_body = self.page_content()
8f6ee0
        page_body = self.tag('div', {'id':'content'}, [8,1], page_body, 1)
8f6ee0
        page_body = self.tag('div', {'id':'page-body'}, [4,1], page_body, 1)
cc10e6
8f6ee0
        page_footer = self.tag('div', {'id': 'page-footer'}, [4,1], self.page_credits(), 1)
7e8dd3
    
8f6ee0
        top = self.tag('a', {'name':'top'}, [0,1])
8f6ee0
        wrap = self.tag('div', {'id': 'wrap'}, [0,1], page_header + page_body + page_footer, 1)
8f6ee0
        body = self.tag('body', '', [0,1], top + wrap)
7e8dd3
8f6ee0
        html = self.page_preamble()
8f6ee0
        html += self.tag('html', {'xmlns': 'http://www.w3.org/1999/xhtml', 'dir': 'ltr', 
8f6ee0
                         'lang': str(self.language), 'xml:lang':
8f6ee0
                         str(self.language)}, [0,1], self.page_metadata() +  body)
7e8dd3
8f6ee0
        return html
7e8dd3
7e8dd3
8f6ee0
    def main(self):
8f6ee0
        """The Xhtml code of a complete page."""
8f6ee0
        print self.page()