예제 #1
0
def parse(requestPath, fileLocation, content, lang='en'):
  context = {
    'lang': lang,
    'requestPath': requestPath.replace('/index', ''),
    'bodyClass': 'devsite-doc-page',
    'servedFromAppEngine': SERVED_FROM_AE
  }

  ## Get the HTML tag
  htmlTag = re.search(r'<html.*?>', content)
  if htmlTag is None:
    logging.warning('Does not contain <html> root element')
  else:
    htmlTag = htmlTag.group(0)
    # Check the HTML tag contains the devsite
    if htmlTag.find('devsite') == -1:
      return content

  # Isolate the <head>
  headStart = content.find('<head')
  headEnd = content.find('</head>')
  head = content[headStart:headEnd].strip()

  # Isolate the <body>
  bodyStart = content.find('<body')
  bodyEnd = content.rfind('</body>')
  body = content[bodyStart:bodyEnd].strip()
  body = re.sub(r'<body.*?>', '', body)

  # Remove any comments {# something #}
  body = re.sub(r'{#.+?#}', '', body)
  body = re.sub(r'{% comment %}.*?{% endcomment %}(?ms)', '', body)

  # Render any DevSite specific tags
  body = devsiteHelper.renderDevSiteContent(body, lang)

  # Read the project.yaml file
  projectPath = re.search('name=\"project_path\" value=\"(.*?)\"', head)
  projectPath = projectPath.group(1)
  projectYaml = yaml.load(devsiteHelper.readFile(projectPath, lang))
  context['projectYaml'] = projectYaml

  # Read the parent project.yaml file if applicable
  parentProjectYaml = None
  if 'parent_project_metadata_path' in projectYaml:
    parentprojectPath = projectYaml['parent_project_metadata_path']
    parentProjectYaml = yaml.load(devsiteHelper.readFile(parentprojectPath, lang))

  # Read the book.yaml file and generate the left hand nav
  bookPath = re.search('name=\"book_path\" value=\"(.*?)\"', head)
  bookPath = bookPath.group(1)
  bookYaml = devsiteHelper.parseBookYaml(bookPath, lang)
  context['bookYaml'] = devsiteHelper.expandBook(bookYaml)
  context['lowerTabs'] = devsiteHelper.getLowerTabs(bookYaml)
  context['renderedLeftNav'] = devsiteHelper.getLeftNav(requestPath, bookYaml)

  # Get the logo row (TOP ROW) icon
  context['logoRowIcon'] = projectYaml['icon']['path']

  # Get the logo row (TOP ROW) title
  if parentProjectYaml:
    context['logoRowTitle'] = parentProjectYaml['name']
  else:
    context['logoRowTitle'] = projectYaml['name']

  # Get the header title & description
  context['headerTitle'] = projectYaml['name']
  # headerDescription is rarely shown, hiding temporarily
  # context['headerDescription'] = projectYaml['description']

  # Read the page title
  pageTitle = []
  titleRO = re.search('<title>(.*?)</title>', head)
  if titleRO:
    title = titleRO.group(1)
    pageTitle.append(title)
    if body.find('<h1>') == -1:
      body = '<h1 class="page-title">' + title + '</h1>\n\n' + body
  pageTitle.append(projectYaml['name'])
  pageTitle.append('WebFu Staging')
  context['pageTitle'] = ' | '.join(pageTitle)

  # Get the footer path & read/parse the footer file.
  footerPath = projectYaml['footer_path']
  footers = yaml.load(devsiteHelper.readFile(footerPath, lang))['footer']
  for item in footers:
    if 'promos' in item:
      context['footerPromos'] = item['promos']
    elif 'linkboxes' in item:
      context['footerLinks'] = item['linkboxes']

  # Replaces <pre> tags with prettyprint enabled tags
  body = re.sub(r'^<pre>(?m)', r'<pre class="prettyprint devsite-code-highlight">', body)
  # Adds code highlighting support, which requires devsite-code-highlight
  body = re.sub(r'^<pre class="prettyprint">(?m)', r'<pre class="prettyprint devsite-code-highlight">', body)

  context['content'] = body

  # Checks if the page should be displayed in full width mode
  fullWidth = re.search('name=\"full_width\" value=\"true\"', head)
  if fullWidth:
    context['fullWidth'] = True

  # # Build the table of contents & transform so it fits within DevSite
  context['renderedTOC'] = '<b>TOC Not Implemented</b> for DevSite HTML Pages'

  gitHubEditUrl = 'https://github.com/google/WebFundamentals/blob/'
  gitHubEditUrl += 'master/src/content/'
  gitHubEditUrl += fileLocation.replace(SOURCE_PATH, '')
  context['gitHubEditUrl'] = gitHubEditUrl

  gitHubIssueUrl = 'https://github.com/google/WebFundamentals/issues/'
  gitHubIssueUrl += 'new?title=Feedback for: ' + context['pageTitle'] + ' ['
  gitHubIssueUrl += lang + ']&body='
  gitHubIssueUrl += gitHubEditUrl
  context['gitHubIssueUrl'] = gitHubIssueUrl

  # Renders the content into the template
  return render('gae/page-article.html', context)
예제 #2
0
def parse(requestPath, fileLocation, rawYaml, lang='en'):
    body = ''
    parsedYaml = yaml.load(rawYaml)
    bookPath = parsedYaml['book_path']
    bookYaml = devsiteHelper.parseBookYaml(bookPath, lang)
    projectPath = parsedYaml['project_path']
    page = parsedYaml['landing_page']
    rows = page['rows']
    title = 'Web'
    banner = devsiteHelper.getAnnouncementBanner(projectPath, lang)
    header = 'Generic Page Header Here'
    customCss = ''
    lowerTabs = devsiteHelper.getLowerTabs(bookYaml)
    if 'custom_css_path' in page:
        customCss = '<link rel="stylesheet" href="'
        customCss += page['custom_css_path']
        customCss += '">'
    if 'header' in page:
        header = '<div class="devsite-collapsible-section">'
        header += '<div class="devsite-header-background devsite-full-site-width">'
        header += '<div class="devsite-product-id-row devsite-full-site-width">'
        if 'description' in page['header']:
            header += '<div class="devsite-product-description-row">'
            header += '<div class="devsite-product-description">'
            header += page['header']['description']
            header += '</div></div>'
        if 'buttons' in page['header']:
            header += '<div class="devsite-product-button-row">'
            for button in page['header']['buttons']:
                header += '<a class="button" href="'
                header += button['path'] + '">' + button['label'] + '</a>'
            header += '</div>'
        header += '</div></div></div>'
        if 'name' in page['header']:
            title = page['header']['name']
    for row in rows:
        sectionClass = ['devsite-landing-row']
        section = '<section class="[[SECTION_CLASSES]]">'
        if 'classname' in row:
            sectionClass.append(row['classname'])
        numItems = None
        if 'columns' in row:
            numItems = len(row['columns'])
        elif 'items' in row:
            numItems = len(row['items'])
        if numItems:
            sectionClass.append('devsite-landing-row-' + str(numItems) + '-up')
        if 'heading' in row:
            section += '<h2 id="' + devsiteHelper.slugify(
                row['heading']) + '">'
            section += row['heading'] + '</h2>'
        if 'items' in row:
            section += '<div class="devsite-landing-row-group">'
            section += parseIndexYamlItems(row['items'])
            section += '</div>'
        if 'columns' in row:
            for column in row['columns']:
                section += '<div class="devsite-landing-row-column">'
                if 'items' in column:
                    section += parseIndexYamlItems(column['items'])
                section += '</div>'
        section += '</section>'
        section = section.replace('[[SECTION_CLASSES]]',
                                  ' '.join(sectionClass))
        body += section
        body = devsiteHelper.renderDevSiteContent(body, lang)
    return render(
        'gae/home.tpl', {
            'title': title,
            'announcementBanner': banner,
            'requestPath': requestPath,
            'lowerTabs': lowerTabs,
            'customcss': customCss,
            'header': header,
            'content': body,
            'lang': lang,
            'footerPromo': devsiteHelper.getFooterPromo(),
            'footerLinks': devsiteHelper.getFooterLinkBox()
        })
예제 #3
0
def parse(requestPath, fileLocation, content, lang='en'):
    context = {
        'lang': lang,
        'requestPath': requestPath.replace('/index', ''),
        'bodyClass': 'devsite-doc-page',
        'servedFromAppEngine': SERVED_FROM_AE
    }

    ## Get the HTML tag
    htmlTag = re.search(r'<html.*?>', content)
    if htmlTag is None:
        logging.warning('Does not contain <html> root element')
    else:
        htmlTag = htmlTag.group(0)
        # Check the HTML tag contains the devsite
        if htmlTag.find('devsite') == -1:
            return content

    # Isolate the <head>
    headStart = content.find('<head')
    headEnd = content.find('</head>')
    head = content[headStart:headEnd].strip()

    # Isolate the <body>
    bodyStart = content.find('<body')
    bodyEnd = content.rfind('</body>')
    body = content[bodyStart:bodyEnd].strip()
    body = re.sub(r'<body.*?>', '', body)

    # Remove any comments {# something #}
    body = re.sub(r'{#.+?#}', '', body)
    body = re.sub(r'{% comment %}.*?{% endcomment %}(?ms)', '', body)

    # Render any DevSite specific tags
    body = devsiteHelper.renderDevSiteContent(body, lang)

    # Read the project.yaml file
    projectPath = re.search('name=\"project_path\" value=\"(.*?)\"', head)
    projectPath = projectPath.group(1)
    projectYaml = yaml.load(devsiteHelper.readFile(projectPath, lang))
    context['projectYaml'] = projectYaml

    # Read the parent project.yaml file if applicable
    parentProjectYaml = None
    if 'parent_project_metadata_path' in projectYaml:
        parentprojectPath = projectYaml['parent_project_metadata_path']
        parentProjectYaml = yaml.load(
            devsiteHelper.readFile(parentprojectPath, lang))

    # Read the book.yaml file and generate the left hand nav
    bookPath = re.search('name=\"book_path\" value=\"(.*?)\"', head)
    bookPath = bookPath.group(1)
    bookYaml = devsiteHelper.parseBookYaml(bookPath, lang)
    context['bookYaml'] = devsiteHelper.expandBook(bookYaml)
    context['lowerTabs'] = devsiteHelper.getLowerTabs(bookYaml)
    context['renderedLeftNav'] = devsiteHelper.getLeftNav(
        requestPath, bookYaml)

    # Get the logo row (TOP ROW) icon
    context['logoRowIcon'] = projectYaml['icon']['path']

    # Get the logo row (TOP ROW) title
    if parentProjectYaml:
        context['logoRowTitle'] = parentProjectYaml['name']
    else:
        context['logoRowTitle'] = projectYaml['name']

    # Get the header title & description
    context['headerTitle'] = projectYaml['name']
    # headerDescription is rarely shown, hiding temporarily
    # context['headerDescription'] = projectYaml['description']

    # Read the page title
    pageTitle = []
    titleRO = re.search('<title>(.*?)</title>', head)
    if titleRO:
        title = titleRO.group(1)
        pageTitle.append(title)
        if body.find('<h1>') == -1:
            body = '<h1 class="page-title">' + title + '</h1>\n\n' + body
    pageTitle.append(projectYaml['name'])
    pageTitle.append('WebFu Staging')
    context['pageTitle'] = ' | '.join(pageTitle)

    # Get the footer path & read/parse the footer file.
    footerPath = projectYaml['footer_path']
    footers = yaml.load(devsiteHelper.readFile(footerPath, lang))['footer']
    for item in footers:
        if 'promos' in item:
            context['footerPromos'] = item['promos']
        elif 'linkboxes' in item:
            context['footerLinks'] = item['linkboxes']

    # Replaces <pre> tags with prettyprint enabled tags
    body = re.sub(r'^<pre>(?m)',
                  r'<pre class="prettyprint devsite-code-highlight">', body)
    # Adds code highlighting support, which requires devsite-code-highlight
    body = re.sub(r'^<pre class="prettyprint">(?m)',
                  r'<pre class="prettyprint devsite-code-highlight">', body)

    context['content'] = body

    # Checks if the page should be displayed in full width mode
    fullWidth = re.search('name=\"full_width\" value=\"true\"', head)
    if fullWidth:
        context['fullWidth'] = True

    # # Build the table of contents & transform so it fits within DevSite
    context[
        'renderedTOC'] = '<b>TOC Not Implemented</b> for DevSite HTML Pages'

    gitHubEditUrl = 'https://github.com/google/WebFundamentals/blob/'
    gitHubEditUrl += 'main/src/content/'
    gitHubEditUrl += fileLocation.replace(SOURCE_PATH, '')
    context['gitHubEditUrl'] = gitHubEditUrl

    gitHubIssueUrl = 'https://github.com/google/WebFundamentals/issues/'
    gitHubIssueUrl += 'new?title=Feedback for: ' + context['pageTitle'] + ' ['
    gitHubIssueUrl += lang + ']&body='
    gitHubIssueUrl += gitHubEditUrl
    context['gitHubIssueUrl'] = gitHubIssueUrl

    # Renders the content into the template
    return render('gae/page-article.html', context)
예제 #4
0
def parse(requestPath, fileLocation, rawYaml, lang='en'):
  context = {
    'lang': lang,
    'requestPath': requestPath.replace('/index', ''),
    'bodyClass': 'devsite-landing-page',
    'servedFromAppEngine': SERVED_FROM_AE
  }

  # Parse the Yaml
  parsedYaml = yaml.load(rawYaml)
  page = parsedYaml['landing_page']
  if 'body_class' in page:
    context['bodyClass'] += ' ' + page['body_class']

  # Get the project_path and read/parse the project file.
  projectPath = parsedYaml['project_path']
  projectYaml = yaml.load(devsiteHelper.readFile(projectPath, lang))
  context['projectYaml'] = projectYaml

  # Read the parent project.yaml file if applicable
  parentProjectYaml = None
  if 'parent_project_metadata_path' in projectYaml:
    parentprojectPath = projectYaml['parent_project_metadata_path']
    parentProjectYaml = yaml.load(devsiteHelper.readFile(parentprojectPath, lang))

  # Get the book path and read/parse the book file, then add the lower tabs.
  bookPath = parsedYaml['book_path']
  bookYaml = devsiteHelper.parseBookYaml(bookPath, lang)
  context['bookYaml'] = devsiteHelper.expandBook(bookYaml)
  context['lowerTabs'] = devsiteHelper.getLowerTabs(bookYaml)

  # Get the row or column count for each row
  for row in page['rows']:
    if 'items' in row:
      count = len(row['items'])
      row['itemCount'] = count
      for item in row['items']:
        if 'custom_html' in item:
          c = item['custom_html']
          item['custom_html'] = devsiteHelper.renderDevSiteContent(c, lang)
    elif 'columns' in row:
      count = len(row['columns'])
      row['itemCount'] = count
    elif 'custom_html' in row:
      row['itemCount'] = 1
      c = row['custom_html']
      row['custom_html'] = devsiteHelper.renderDevSiteContent(c, lang)
  context['rows'] = page['rows']

  # Get the custom CSS path
  if 'custom_css_path' in page:
    context['customCSSPath'] = page['custom_css_path']

  # Get the logo row (TOP ROW) icon
  context['logoRowIcon'] = projectYaml['icon']['path']

  # Get the logo row (TOP ROW) title
  if 'header' in page and 'name' in page['header']:
    context['logoRowTitle'] = page['header']['name']
  elif parentProjectYaml:
    context['logoRowTitle'] = parentProjectYaml['name']
  else:
    context['logoRowTitle'] = projectYaml['name']

  # Get the custom_html for the header if appropriate
  if 'header' in page and 'custom_html' in page['header']:
    context['customHeader'] = page['header']['custom_html']

  # Get the header title
  if 'parent_project_metadata_path' in projectYaml:
    context['headerTitle'] = projectYaml['name']
  elif 'title' in parsedYaml:
    context['headerTitle'] = parsedYaml['title']
  else:
    context['headerTitle'] = projectYaml['name']

  # Get the header description
  if 'header' in page and 'description' in page['header']:
    context['headerDescription'] = page['header']['description']
  else:
    context['headerDescription'] = projectYaml['description']

  # Get the header buttons
  if 'header' in page and 'buttons' in page['header']:
    context['headerButtons'] = page['header']['buttons']

  # Set the page title
  pageTitle = []
  if 'title' in parsedYaml:
    pageTitle.append(parsedYaml['title'])
  pageTitle.append(projectYaml['name'])
  pageTitle.append('WebFu Staging')
  context['pageTitle'] = ' | '.join(pageTitle)

  # Get the footer path & read/parse the footer file.
  footerPath = projectYaml['footer_path']
  footers = yaml.load(devsiteHelper.readFile(footerPath, lang))['footer']
  for item in footers:
    if 'promos' in item:
      context['footerPromos'] = item['promos']
    elif 'linkboxes' in item:
      context['footerLinks'] = item['linkboxes']

  return render('gae/page-landing.html', context)
예제 #5
0
def parse(requestPath, fileLocation, content, lang='en'):
    context = {
        'lang': lang,
        'requestPath': requestPath.replace('/index', ''),
        'bodyClass': 'devsite-doc-page',
        'servedFromAppEngine': SERVED_FROM_AE
    }

    ## Injects markdown includes into the markdown as appropriate
    includes = re.findall(r'^<<.+?\.md>>(?m)', content)
    for includeTag in includes:
        fileName = includeTag.replace('<<', '').replace('>>', '')
        fileName = os.path.join(os.path.dirname(fileLocation), fileName)
        include = devsiteHelper.readFile(fileName, lang)
        if include is None:
            include = 'Warning: Unable to find included markdown file.\n\n'
        content = content.replace(includeTag, include)

    # Remove any comments {# something #}
    content = re.sub(r'{#.+?#}', '', content)
    content = re.sub(r'{% comment %}.*?{% endcomment %}(?ms)', '', content)

    # Remove any markdown=1 since it's not supported
    content = re.sub(r'markdown=[\'\"]?1[\'\"]?', '', content)

    # Render any DevSite specific tags
    content = devsiteHelper.renderDevSiteContent(content, lang)

    # Turn Callouts into the appropriate HTML elements
    content = re.sub(
        r'^Note: (.*?)\n^\n(?ms)',
        r'<aside class="note" markdown="1"><strong>Note:</strong> <span>\1</span></aside>',
        content)
    content = re.sub(
        r'^Caution: (.*?)\n^\n(?ms)',
        r'<aside class="caution" markdown="1"><strong>Caution:</strong> <span>\1</span></aside>',
        content)
    content = re.sub(
        r'^Warning: (.*?)\n^\n(?ms)',
        r'<aside class="warning" markdown="1"><strong>Warning:</strong> <span>\1</span></aside>',
        content)
    content = re.sub(
        r'^Key Point: (.*?)\n^\n(?ms)',
        r'<aside class="key-point" markdown="1"><strong>Key Point:</strong> <span>\1</span></aside>',
        content)
    content = re.sub(
        r'^Key Term: (.*?)\n^\n(?ms)',
        r'<aside class="key-term" markdown="1"><strong>Key Term:</strong> <span>\1</span></aside>',
        content)
    content = re.sub(
        r'^Objective: (.*?)\n^\n(?ms)',
        r'<aside class="objective" markdown="1"><strong>Objective:</strong> <span>\1</span></aside>',
        content)
    content = re.sub(
        r'^Success: (.*?)\n^\n(?ms)',
        r'<aside class="success" markdown="1"><strong>Success:</strong> <span>\1</span></aside>',
        content)
    content = re.sub(
        r'^Dogfood: (.*?)\n^\n(?ms)',
        r'<aside class="dogfood" markdown="1"><strong>Dogfood:</strong> <span>\1</span></aside>',
        content)

    # Adds a set of markdown extensions available to us on DevSite
    ext = [
        'markdown.extensions.attr_list',  # Adds support for {: #someid }
        'markdown.extensions.meta',  # Removes the meta data from the top of the doc
        'markdown.extensions.toc',  # Generate the TOC for the right side
        'markdown.extensions.tables',  # Support for Markdown Tables
        'markdown.extensions.def_list',  # Support for definition lists
        'markdown.extensions.extra'  #
    ]
    md = markdown.Markdown(extensions=ext)
    content = md.convert(content)

    # Replaces <pre> tags with prettyprint enabled tags
    content = re.sub(r'^<pre>(?m)',
                     r'<pre class="prettyprint devsite-code-highlight">',
                     content)
    # Adds code highlighting support, which requires devsite-code-highlight
    content = re.sub(r'^<pre class="prettyprint">(?m)',
                     r'<pre class="prettyprint devsite-code-highlight">',
                     content)

    # Save the content
    context['content'] = content

    # Get the project_path and read/parse the project file.
    projectPath = md.Meta['project_path'][0]
    projectYaml = yaml.load(devsiteHelper.readFile(projectPath, lang))
    context['projectYaml'] = projectYaml

    # Read the parent project.yaml file if applicable
    parentProjectYaml = None
    if 'parent_project_metadata_path' in projectYaml:
        parentprojectPath = projectYaml['parent_project_metadata_path']
        parentProjectYaml = yaml.load(
            devsiteHelper.readFile(parentprojectPath, lang))

    # Reads the book.yaml file and generate the lefthand nav
    bookPath = md.Meta['book_path'][0]
    bookYaml = devsiteHelper.parseBookYaml(bookPath, lang)
    context['bookYaml'] = devsiteHelper.expandBook(bookYaml)
    # context['lowerTabs'] = devsiteHelper.getLowerTabs(bookYaml)
    context['renderedLeftNav'] = devsiteHelper.getLeftNav(
        requestPath, bookYaml)

    lowerTabs = devsiteHelper.getLowerTabs(bookYaml)
    context['lowerTabs'] = lowerTabs

    # Get the logo row (TOP ROW) icon
    context['logoRowIcon'] = projectYaml['icon']['path']

    # Get the logo row (TOP ROW) title
    if parentProjectYaml:
        context['logoRowTitle'] = parentProjectYaml['name']
    else:
        context['logoRowTitle'] = projectYaml['name']

    # Get the header title & description
    context['headerTitle'] = projectYaml['name']
    # headerDescription is rarely shown, hiding temporarily
    # context['headerDescription'] = projectYaml['description']

    # Get the page title
    pageTitle = []
    titleRO = re.search(r'<h1 class="page-title".*?>(.*?)<\/h1>', content)
    if titleRO:
        pageTitle.append(titleRO.group(1))
    pageTitle.append(projectYaml['name'])
    pageTitle.append('WebFu Staging')
    context['pageTitle'] = ' | '.join(pageTitle)

    # Get the footer path & read/parse the footer file.
    footerPath = projectYaml['footer_path']
    footers = yaml.load(devsiteHelper.readFile(footerPath, lang))['footer']
    for item in footers:
        if 'promos' in item:
            context['footerPromos'] = item['promos']
        elif 'linkboxes' in item:
            context['footerLinks'] = item['linkboxes']

    if 'full_width' in md.Meta and len(md.Meta['full_width']) == 1:
        context['fullWidth'] = True

    # Build the table of contents & transform so it fits within DevSite
    toc = md.toc
    toc = toc.strip()
    # Strips the outer wrapper and the page title from the doc
    toc = re.sub(r'<div class="toc">(.*?<ul>){2}(?s)', '', toc)
    toc = re.sub(r'</ul>\s*</li>\s*</ul>\s*</div>(?s)', '', toc)
    # Add appropriate classes
    toc = re.sub(r'<ul>', '<ul class="devsite-page-nav-list">', toc)
    toc = re.sub(r'<a href', '<a class="devsite-nav-title" href', toc)
    toc = re.sub(r'<li>', '<li class="devsite-nav-item">', toc)
    context['renderedTOC'] = toc

    gitHubEditUrl = 'https://github.com/google/WebFundamentals/blob/'
    gitHubEditUrl += 'main/src/content/'
    gitHubEditUrl += fileLocation.replace(SOURCE_PATH, '')
    context['gitHubEditUrl'] = gitHubEditUrl

    gitHubIssueUrl = 'https://github.com/google/WebFundamentals/issues/'
    gitHubIssueUrl += 'new?title=Feedback for: ' + context['pageTitle'] + ' ['
    gitHubIssueUrl += lang + ']&body='
    gitHubIssueUrl += gitHubEditUrl
    context['gitHubIssueUrl'] = gitHubIssueUrl

    return render('gae/page-article.html', context)
예제 #6
0
def parse(requestPath, fileLocation, rawYaml, lang='en'):
    context = {
        'lang': lang,
        'requestPath': requestPath.replace('/index', ''),
        'bodyClass': 'devsite-landing-page',
        'servedFromAppEngine': SERVED_FROM_AE
    }

    # Parse the Yaml
    parsedYaml = yaml.load(rawYaml)
    page = parsedYaml['landing_page']

    # Get the project_path and read/parse the project file.
    projectPath = parsedYaml['project_path']
    projectYaml = yaml.load(devsiteHelper.readFile(projectPath, lang))
    context['projectYaml'] = projectYaml

    # Read the parent project.yaml file if applicable
    parentProjectYaml = None
    if 'parent_project_metadata_path' in projectYaml:
        parentprojectPath = projectYaml['parent_project_metadata_path']
        parentProjectYaml = yaml.load(
            devsiteHelper.readFile(parentprojectPath, lang))

    # Get the book path and read/parse the book file, then add the lower tabs.
    bookPath = parsedYaml['book_path']
    bookYaml = devsiteHelper.parseBookYaml(bookPath, lang)
    context['bookYaml'] = devsiteHelper.expandBook(bookYaml)
    context['lowerTabs'] = devsiteHelper.getLowerTabs(bookYaml)

    # Get the row or column count for each row
    for row in page['rows']:
        if 'items' in row:
            count = len(row['items'])
            row['itemCount'] = count
            for item in row['items']:
                if 'custom_html' in item:
                    c = item['custom_html']
                    item['custom_html'] = devsiteHelper.renderDevSiteContent(
                        c, lang)
        elif 'columns' in row:
            count = len(row['columns'])
            row['itemCount'] = count
        elif 'custom_html' in row:
            row['itemCount'] = 1
            c = row['custom_html']
            row['custom_html'] = devsiteHelper.renderDevSiteContent(c, lang)
    context['rows'] = page['rows']

    # Get the custom CSS path
    if 'custom_css_path' in page:
        context['customCSSPath'] = page['custom_css_path']

    # Get the logo row (TOP ROW) icon
    context['logoRowIcon'] = projectYaml['icon']['path']

    # Get the logo row (TOP ROW) title
    if 'header' in page and 'name' in page['header']:
        context['logoRowTitle'] = page['header']['name']
    elif parentProjectYaml:
        context['logoRowTitle'] = parentProjectYaml['name']
    else:
        context['logoRowTitle'] = projectYaml['name']

    # Get the custom_html for the header if appropriate
    if 'header' in page and 'custom_html' in page['header']:
        context['customHeader'] = page['header']['custom_html']

    # Get the header title
    if 'parent_project_metadata_path' in projectYaml:
        context['headerTitle'] = projectYaml['name']
    elif 'title' in parsedYaml:
        context['headerTitle'] = parsedYaml['title']
    else:
        context['headerTitle'] = projectYaml['name']

    # Get the header description
    if 'header' in page and 'description' in page['header']:
        context['headerDescription'] = page['header']['description']
    else:
        context['headerDescription'] = projectYaml['description']

    # Get the header buttons
    if 'header' in page and 'buttons' in page['header']:
        context['headerButtons'] = page['header']['buttons']

    # Set the page title
    pageTitle = []
    if 'title' in parsedYaml:
        pageTitle.append(parsedYaml['title'])
    pageTitle.append(projectYaml['name'])
    pageTitle.append('WebFu Staging')
    context['pageTitle'] = ' | '.join(pageTitle)

    # Get the footer path & read/parse the footer file.
    footerPath = projectYaml['footer_path']
    footers = yaml.load(devsiteHelper.readFile(footerPath, lang))['footer']
    for item in footers:
        if 'promos' in item:
            context['footerPromos'] = item['promos']
        elif 'linkboxes' in item:
            context['footerLinks'] = item['linkboxes']

    return render('gae/page-landing.html', context)
예제 #7
0
def parse(requestPath, fileLocation, content, lang='en'):
    template = 'gae/article.tpl'

    ## Get the HTML tag
    htmlTag = re.search(r'<html.*?>', content)
    if htmlTag is None:
        log.warning('Does not contain <html> root element')
    else:
        htmlTag = htmlTag.group(0)
        # Check the HTML tag contains the devsite
        if htmlTag.find('devsite') == -1:
            return content

    # Isolate the <head>
    headStart = content.find('<head')
    headEnd = content.find('</head>')
    head = content[headStart:headEnd].strip()

    # Isolate the <body>
    bodyStart = content.find('<body')
    bodyEnd = content.rfind('</body>')
    body = content[bodyStart:bodyEnd].strip()
    body = re.sub(r'<body.*?>', '', body)

    dateUpdated = re.search(r"{# wf_updated_on:[ ]?(.*)[ ]?#}", content)
    if dateUpdated is None:
        dateUpdated = 'Unknown'
    else:
        dateUpdated = dateUpdated.group(1)

    # Remove any comments {# something #}
    body = re.sub(r'{#.+?#}', '', body)
    body = re.sub(r'{% comment %}.*?{% endcomment %}(?ms)', '', body)

    # Show warning for unsupported elements
    for tag in UNSUPPORTED_TAGS:
        if re.search(tag, body) is not None:
            logging.error(' - Unsupported tag: ' + tag)
            replaceWith = '<aside class="warning">Web<strong>Fundamentals</strong>: '
            replaceWith += '<span>Unsupported tag: <code>' + tag + '</code></span></aside>'
            body = re.sub(tag, replaceWith, body)

    # Show warning for template tags
    if re.search('{{', body) is not None:
        logging.warn(' - Warning: possible unescaped template tag')

    # Render any DevSite specific tags
    body = devsiteHelper.renderDevSiteContent(body, lang)

    # Read the page title
    title = re.search('<title>(.*?)</title>', head)
    if title is None:
        title = '** UNKNOWN TITLE **'
    else:
        title = title.group(1)
        if body.find('<h1>') == -1:
            body = '<h1 class="page-title">' + title + '</h1>\n\n' + body

    # Read the book.yaml file and generate the left hand nav
    bookPath = re.search('name=\"book_path\" value=\"(.*?)\"', head)
    if bookPath is None:
        logging.error('Unable to read book_path')
        leftNav = 'Book not found.'
        lowerTabs = ''
    else:
        bookPath = bookPath.group(1)
        bookYaml = devsiteHelper.parseBookYaml(bookPath, lang)
        leftNav = devsiteHelper.getLeftNav(requestPath, bookYaml)
        lowerTabs = devsiteHelper.getLowerTabs(bookYaml)

    # Read the project.yaml file
    projectPath = re.search('name=\"project_path\" value=\"(.*?)\"', head)
    if bookPath is None:
        logging.error('Unable to read project_path')
    else:
        projectPath = projectPath.group(1)
        announcementBanner = devsiteHelper.getAnnouncementBanner(
            projectPath, lang)

    # Replaces <pre> tags with prettyprint enabled tags
    body = re.sub(r'^<pre>(?m)', r'<pre class="prettyprint">', body)

    # Checks if the page should be displayed in full width mode
    fullWidth = re.search('name=\"full_width\" value=\"true\"', head)
    if fullWidth is not None:
        template = 'gae/home.tpl'

    # # Build the table of contents & transform so it fits within DevSite
    toc = '- TOC NYI - '
    # toc = md.toc
    # toc = toc.strip()
    # # Strips the outer wrapper and the page title from the doc
    # toc = re.sub(r'<div class="toc">(.*?<ul>){2}(?s)', '', toc)
    # toc = re.sub(r'</ul>\s*</li>\s*</ul>\s*</div>(?s)', '', toc)
    # # Add appropriate classes
    # toc = re.sub(r'<ul>', '<ul class="devsite-page-nav-list">', toc)
    # toc = re.sub(r'<a href', '<a class="devsite-nav-title" href', toc)
    # toc = re.sub(r'<li>', '<li class="devsite-nav-item">', toc)

    gitHubEditUrl = 'https://github.com/google/WebFundamentals/blob/'
    gitHubEditUrl += 'master/src/content/'
    gitHubEditUrl += fileLocation.replace(SOURCE_PATH, '')

    gitHubIssueUrl = 'https://github.com/google/WebFundamentals/issues/'
    gitHubIssueUrl += 'new?title=Feedback for: ' + title + ' ['
    gitHubIssueUrl += lang + ']&body='
    gitHubIssueUrl += gitHubEditUrl

    # Renders the content into the template
    return render(
        template, {
            'title': title,
            'head': head,
            'announcementBanner': announcementBanner,
            'lowerTabs': lowerTabs,
            'gitHubIssueUrl': gitHubIssueUrl,
            'gitHubEditUrl': gitHubEditUrl,
            'requestPath': requestPath.replace('/index', ''),
            'leftNav': leftNav,
            'content': body,
            'toc': toc,
            'dateUpdated': dateUpdated,
            'lang': lang,
            'footerPromo': devsiteHelper.getFooterPromo(),
            'footerLinks': devsiteHelper.getFooterLinkBox()
        })
예제 #8
0
def parse(requestPath, fileLocation, rawYaml, lang='en'):
    body = ''
    parsedYaml = yaml.load(rawYaml)
    bookPath = parsedYaml['book_path']
    bookYaml = devsiteHelper.parseBookYaml(bookPath, lang)
    projectPath = parsedYaml['project_path']
    page = parsedYaml['landing_page']
    rows = page['rows']
    title = 'Web'
    if 'title' in parsedYaml:
        title = parsedYaml['title']
    headerTitle = None
    description = 'Description pulled from <code>_project.yaml</code>'
    headerButtons = None
    banner = devsiteHelper.getAnnouncementBanner(projectPath, lang)
    customHeader = None
    customCSS = None
    lowerTabs = devsiteHelper.getLowerTabs(bookYaml)
    if len(lowerTabs) <= 1:
        lowerTabs = None
    if 'custom_css_path' in page:
        customCSS = '<link rel="stylesheet" href="'
        customCSS += page['custom_css_path']
        customCSS += '">'
    if 'header' in page:
        if 'custom_html' in page['header']:
            customHeader = page['header']['custom_html']
        else:
            if 'name' in page['header']:
                headerTitle = page['header']['name']
            if 'description' in page['header']:
                description = page['header']['description']
            if 'buttons' in page['header']:
                headerButtons = []
                for button in page['header']['buttons']:
                    headerButton = '<a class="button" href="'
                    headerButton += button['path'] + '">' + button[
                        'label'] + '</a>'
                    headerButtons.append(headerButton)
    for row in rows:
        sectionClass = ['devsite-landing-row']
        section = '<section class="[[SECTION_CLASSES]]">'
        if 'classname' in row:
            sectionClass.append(row['classname'])
        numItems = None
        if 'columns' in row:
            numItems = len(row['columns'])
        elif 'items' in row:
            numItems = len(row['items'])
        if numItems:
            sectionClass.append('devsite-landing-row-' + str(numItems) + '-up')
        if 'heading' in row:
            section += '<h2 id="' + devsiteHelper.slugify(
                row['heading']) + '">'
            section += row['heading'] + '</h2>'
        if 'description' in row:
            section += '<p class="devsite-landing-row-description">'
            section += row['description'] + '</p>'
        if 'items' in row:
            section += '<div class="devsite-landing-row-group">'
            section += parseIndexYamlItems(row['items'])
            section += '</div>'
        if 'columns' in row:
            section += '<div class="devsite-landing-row-group">'
            for column in row['columns']:
                section += '<div class="devsite-landing-row-column">'
                # if 'items' in column:
                section += parseIndexYamlItems([column])
                section += '</div>'
            section += '</div>'
        section += '</section>'
        section = section.replace('[[SECTION_CLASSES]]',
                                  ' '.join(sectionClass))
        body += section
        body = devsiteHelper.renderDevSiteContent(body, lang)
    return render(
        'gae/home.tpl', {
            'title': title,
            'headerTitle': title,
            'description': description,
            'headerButtons': headerButtons,
            'announcementBanner': banner,
            'requestPath': requestPath,
            'lowerTabs': lowerTabs,
            'customCSS': customCSS,
            'customHeader': customHeader,
            'content': body,
            'lang': lang,
            'footerPromo': devsiteHelper.getFooterPromo(),
            'footerLinks': devsiteHelper.getFooterLinkBox()
        })
예제 #9
0
def parse(requestPath, fileLocation, content, lang='en'):
    template = 'gae/article.tpl'

    dateUpdated = re.search(r"{# wf_updated_on:[ ]?(.*)[ ]?#}", content)
    if dateUpdated is None:
        logging.warn('Missing wf_updated_on tag.')
        dateUpdated = 'Unknown'
    else:
        dateUpdated = dateUpdated.group(1)

    ## Injects markdown includes into the markdown as appropriate
    includes = re.findall(r'^<<.+?\.md>>(?m)', content)
    for includeTag in includes:
        fileName = includeTag.replace('<<', '').replace('>>', '')
        fileName = os.path.join(os.path.dirname(fileLocation), fileName)
        include = devsiteHelper.readFile(fileName, lang)
        if include is None:
            include = 'Warning: Unable to find included markdown file.\n\n'
        content = content.replace(includeTag, include)

    # Remove any comments {# something #}
    content = re.sub(r'{#.+?#}', '', content)
    content = re.sub(r'{% comment %}.*?{% endcomment %}(?ms)', '', content)

    # Show warning for unsupported elements
    for tag in UNSUPPORTED_TAGS:
        if re.search(tag, content) is not None:
            logging.error(' - Unsupported tag: ' + tag)
            replaceWith = '<aside class="warning">Web<strong>Fundamentals</strong>: '
            replaceWith += '<span>Unsupported tag: <code>' + tag + '</code></span></aside>'
            content = re.sub(tag, replaceWith, content)

    # Show warning for template tags
    if re.search('{{', content) is not None:
        logging.warn(' - Warning: possible unescaped template tag')

    # Render any DevSite specific tags
    content = devsiteHelper.renderDevSiteContent(content, lang)

    # If it's a markdown file, parse it to HTML
    content = re.sub(
        r'^Note: (.*?)\n^\n(?ms)',
        r'<aside class="note" markdown="1"><strong>Note:</strong> <span>\1</span></aside>',
        content)
    content = re.sub(
        r'^Caution: (.*?)\n^\n(?ms)',
        r'<aside class="caution" markdown="1"><strong>Caution:</strong> <span>\1</span></aside>',
        content)
    content = re.sub(
        r'^Warning: (.*?)\n^\n(?ms)',
        r'<aside class="warning" markdown="1"><strong>Warning:</strong> <span>\1</span></aside>',
        content)
    content = re.sub(
        r'^Key Point: (.*?)\n^\n(?ms)',
        r'<aside class="key-point" markdown="1"><strong>Key Point:</strong> <span>\1</span></aside>',
        content)
    content = re.sub(
        r'^Key Term: (.*?)\n^\n(?ms)',
        r'<aside class="key-term" markdown="1"><strong>Key Term:</strong> <span>\1</span></aside>',
        content)
    content = re.sub(
        r'^Objective: (.*?)\n^\n(?ms)',
        r'<aside class="objective" markdown="1"><strong>Objective:</strong> <span>\1</span></aside>',
        content)
    content = re.sub(
        r'^Success: (.*?)\n^\n(?ms)',
        r'<aside class="success" markdown="1"><strong>Success:</strong> <span>\1</span></aside>',
        content)
    content = re.sub(
        r'^Dogfood: (.*?)\n^\n(?ms)',
        r'<aside class="dogfood" markdown="1"><strong>Dogfood:</strong> <span>\1</span></aside>',
        content)

    # Adds a set of markdown extensions available to us on DevSite
    ext = [
        'markdown.extensions.attr_list',  # Adds support for {: #someid }
        'markdown.extensions.meta',  # Removes the meta data from the top of the doc
        'markdown.extensions.toc',  # Generate the TOC for the right side
        'markdown.extensions.tables',  # Support for Markdown Tables
        'markdown.extensions.def_list',  # Support for definition lists
        'markdown.extensions.extra'  # Support for markdown='1' in tags
    ]
    md = markdown.Markdown(extensions=ext)
    content = md.convert(content)

    # Reads the book.yaml file and generate the lefthand nav
    if 'book_path' in md.Meta and len(md.Meta['book_path']) == 1:
        bookPath = md.Meta['book_path'][0]
        bookYaml = devsiteHelper.parseBookYaml(bookPath, lang)

    if 'project_path' in md.Meta and len(md.Meta['project_path']) == 1:
        projectPath = md.Meta['project_path'][0]

    if 'full_width' in md.Meta and len(md.Meta['full_width']) == 1:
        template = 'gae/home.tpl'

    # Build the table of contents & transform so it fits within DevSite
    toc = md.toc
    toc = toc.strip()
    # Strips the outer wrapper and the page title from the doc
    toc = re.sub(r'<div class="toc">(.*?<ul>){2}(?s)', '', toc)
    toc = re.sub(r'</ul>\s*</li>\s*</ul>\s*</div>(?s)', '', toc)
    # Add appropriate classes
    toc = re.sub(r'<ul>', '<ul class="devsite-page-nav-list">', toc)
    toc = re.sub(r'<a href', '<a class="devsite-nav-title" href', toc)
    toc = re.sub(r'<li>', '<li class="devsite-nav-item">', toc)

    # Replaces <pre> tags with prettyprint enabled tags
    content = re.sub(r'^<pre>(?m)', r'<pre class="prettyprint">', content)

    # Get the page title from the markup.
    titleRO = re.search(r'<h1 class="page-title".*?>(.*?)<\/h1>', content)
    if titleRO:
        title = titleRO.group(1)
    else:
        title = ':('

    gitHubEditUrl = 'https://github.com/google/WebFundamentals/blob/'
    gitHubEditUrl += 'master/src/content/'
    gitHubEditUrl += fileLocation.replace(SOURCE_PATH, '')

    gitHubIssueUrl = 'https://github.com/google/WebFundamentals/issues/'
    gitHubIssueUrl += 'new?title=Feedback for: ' + title + ' ['
    gitHubIssueUrl += lang + ']&body='
    gitHubIssueUrl += gitHubEditUrl

    # Renders the content into the template
    return render(
        template, {
            'title':
            title,
            'announcementBanner':
            devsiteHelper.getAnnouncementBanner(projectPath, lang),
            'lowerTabs':
            devsiteHelper.getLowerTabs(bookYaml),
            'gitHubIssueUrl':
            gitHubIssueUrl,
            'gitHubEditUrl':
            gitHubEditUrl,
            'requestPath':
            requestPath.replace('/index', ''),
            'leftNav':
            devsiteHelper.getLeftNav(requestPath, bookYaml),
            'content':
            content,
            'toc':
            toc,
            'dateUpdated':
            dateUpdated,
            'lang':
            lang,
            'footerPromo':
            devsiteHelper.getFooterPromo(),
            'footerLinks':
            devsiteHelper.getFooterLinkBox()
        })
예제 #10
0
def parse(requestPath, fileLocation, content, lang='en'):
  context = {
    'lang': lang,
    'requestPath': requestPath.replace('/index', ''),
    'bodyClass': 'devsite-doc-page',
    'servedFromAppEngine': SERVED_FROM_AE
  }

  ## Injects markdown includes into the markdown as appropriate
  includes = re.findall(r'^<<.+?\.md>>(?m)', content)
  for includeTag in includes:
    fileName = includeTag.replace('<<', '').replace('>>', '')
    fileName = os.path.join(os.path.dirname(fileLocation), fileName)
    include = devsiteHelper.readFile(fileName, lang)
    if include is None:
      include = 'Warning: Unable to find included markdown file.\n\n'
    content = content.replace(includeTag, include)

  # Remove any comments {# something #}
  content = re.sub(r'{#.+?#}', '', content)
  content = re.sub(r'{% comment %}.*?{% endcomment %}(?ms)', '', content)

  # Remove any markdown=1 since it's not supported
  content = re.sub(r'markdown=[\'\"]?1[\'\"]?', '', content)

  # Render any DevSite specific tags
  content = devsiteHelper.renderDevSiteContent(content, lang)

  # Turn Callouts into the appropriate HTML elements
  content = re.sub(r'^Note: (.*?)\n^\n(?ms)', r'<aside class="note" markdown="1"><strong>Note:</strong> <span>\1</span></aside>', content)
  content = re.sub(r'^Caution: (.*?)\n^\n(?ms)', r'<aside class="caution" markdown="1"><strong>Caution:</strong> <span>\1</span></aside>', content)
  content = re.sub(r'^Warning: (.*?)\n^\n(?ms)', r'<aside class="warning" markdown="1"><strong>Warning:</strong> <span>\1</span></aside>', content)
  content = re.sub(r'^Key Point: (.*?)\n^\n(?ms)', r'<aside class="key-point" markdown="1"><strong>Key Point:</strong> <span>\1</span></aside>', content)
  content = re.sub(r'^Key Term: (.*?)\n^\n(?ms)', r'<aside class="key-term" markdown="1"><strong>Key Term:</strong> <span>\1</span></aside>', content)
  content = re.sub(r'^Objective: (.*?)\n^\n(?ms)', r'<aside class="objective" markdown="1"><strong>Objective:</strong> <span>\1</span></aside>', content)
  content = re.sub(r'^Success: (.*?)\n^\n(?ms)', r'<aside class="success" markdown="1"><strong>Success:</strong> <span>\1</span></aside>', content)
  content = re.sub(r'^Dogfood: (.*?)\n^\n(?ms)', r'<aside class="dogfood" markdown="1"><strong>Dogfood:</strong> <span>\1</span></aside>', content)

  # Adds a set of markdown extensions available to us on DevSite
  ext = [
    'markdown.extensions.attr_list', # Adds support for {: #someid }
    'markdown.extensions.meta', # Removes the meta data from the top of the doc
    'markdown.extensions.toc', # Generate the TOC for the right side
    'markdown.extensions.tables', # Support for Markdown Tables
    'markdown.extensions.def_list', # Support for definition lists
    'markdown.extensions.extra' #
  ]
  md = markdown.Markdown(extensions=ext)
  content = md.convert(content)

  # Replaces <pre> tags with prettyprint enabled tags
  content = re.sub(r'^<pre>(?m)', r'<pre class="prettyprint devsite-code-highlight">', content)
  # Adds code highlighting support, which requires devsite-code-highlight
  content = re.sub(r'^<pre class="prettyprint">(?m)', r'<pre class="prettyprint devsite-code-highlight">', content)

  # Save the content
  context['content'] = content

  # Get the project_path and read/parse the project file.
  projectPath = md.Meta['project_path'][0]
  projectYaml = yaml.load(devsiteHelper.readFile(projectPath, lang))
  context['projectYaml'] = projectYaml

  # Read the parent project.yaml file if applicable
  parentProjectYaml = None
  if 'parent_project_metadata_path' in projectYaml:
    parentprojectPath = projectYaml['parent_project_metadata_path']
    parentProjectYaml = yaml.load(devsiteHelper.readFile(parentprojectPath, lang))

  # Reads the book.yaml file and generate the lefthand nav
  bookPath = md.Meta['book_path'][0]
  bookYaml = devsiteHelper.parseBookYaml(bookPath, lang)
  context['bookYaml'] = devsiteHelper.expandBook(bookYaml)
  # context['lowerTabs'] = devsiteHelper.getLowerTabs(bookYaml)
  context['renderedLeftNav'] = devsiteHelper.getLeftNav(requestPath, bookYaml)

  lowerTabs = devsiteHelper.getLowerTabs(bookYaml)
  context['lowerTabs'] = lowerTabs

  # Get the logo row (TOP ROW) icon
  context['logoRowIcon'] = projectYaml['icon']['path']

  # Get the logo row (TOP ROW) title
  if parentProjectYaml:
    context['logoRowTitle'] = parentProjectYaml['name']
  else:
    context['logoRowTitle'] = projectYaml['name']

  # Get the header title & description
  context['headerTitle'] = projectYaml['name']
  # headerDescription is rarely shown, hiding temporarily
  # context['headerDescription'] = projectYaml['description']

  # Get the page title
  pageTitle = []
  titleRO = re.search(r'<h1 class="page-title".*?>(.*?)<\/h1>', content)
  if titleRO:
    pageTitle.append(titleRO.group(1))
  pageTitle.append(projectYaml['name'])
  pageTitle.append('WebFu Staging')
  context['pageTitle'] = ' | '.join(pageTitle)

  # Get the footer path & read/parse the footer file.
  footerPath = projectYaml['footer_path']
  footers = yaml.load(devsiteHelper.readFile(footerPath, lang))['footer']
  for item in footers:
    if 'promos' in item:
      context['footerPromos'] = item['promos']
    elif 'linkboxes' in item:
      context['footerLinks'] = item['linkboxes']

  if 'full_width' in md.Meta and len(md.Meta['full_width']) == 1:
    context['fullWidth'] = True

  # Build the table of contents & transform so it fits within DevSite
  toc = md.toc
  toc = toc.strip()
  # Strips the outer wrapper and the page title from the doc
  toc = re.sub(r'<div class="toc">(.*?<ul>){2}(?s)', '', toc)
  toc = re.sub(r'</ul>\s*</li>\s*</ul>\s*</div>(?s)', '', toc)
  # Add appropriate classes
  toc = re.sub(r'<ul>', '<ul class="devsite-page-nav-list">', toc)
  toc = re.sub(r'<a href', '<a class="devsite-nav-title" href', toc)
  toc = re.sub(r'<li>', '<li class="devsite-nav-item">', toc)
  context['renderedTOC'] = toc;

  gitHubEditUrl = 'https://github.com/google/WebFundamentals/blob/'
  gitHubEditUrl += 'master/src/content/'
  gitHubEditUrl += fileLocation.replace(SOURCE_PATH, '')
  context['gitHubEditUrl'] = gitHubEditUrl

  gitHubIssueUrl = 'https://github.com/google/WebFundamentals/issues/'
  gitHubIssueUrl += 'new?title=Feedback for: ' + context['pageTitle'] + ' ['
  gitHubIssueUrl += lang + ']&body='
  gitHubIssueUrl += gitHubEditUrl
  context['gitHubIssueUrl'] = gitHubIssueUrl

  return render('gae/page-article.html', context)