Merge .xsl & html template
Turns out they somehow serve a similar purpose
This commit is contained in:
		@@ -94,7 +94,7 @@ path =
 | 
			
		||||
  http://localhost/
 | 
			
		||||
 | 
			
		||||
title = //div[@id='header']/h1
 | 
			
		||||
desc = //div[@id='header']/h2
 | 
			
		||||
desc = //div[@id='header']/p
 | 
			
		||||
items = //div[@id='content']/div
 | 
			
		||||
 | 
			
		||||
item_title = ./a
 | 
			
		||||
@@ -102,7 +102,7 @@ item_link = ./a/@href
 | 
			
		||||
item_desc = ./div[class=desc]
 | 
			
		||||
item_content = ./div[class=content]
 | 
			
		||||
 | 
			
		||||
base = file:reader.html.template
 | 
			
		||||
base = file:www/sheet.xsl
 | 
			
		||||
 | 
			
		||||
[twitter]
 | 
			
		||||
mode = html
 | 
			
		||||
 
 | 
			
		||||
@@ -46,10 +46,23 @@ def parse_rules(filename=None):
 | 
			
		||||
    rules = dict([(x, dict(config.items(x))) for x in config.sections()])
 | 
			
		||||
 | 
			
		||||
    for section in rules.keys():
 | 
			
		||||
        # for each ruleset
 | 
			
		||||
 | 
			
		||||
        for arg in rules[section].keys():
 | 
			
		||||
            # for each rule
 | 
			
		||||
 | 
			
		||||
            if rules[section][arg].startswith('file:'):
 | 
			
		||||
                import_file = os.path.join(os.path.dirname(__file__), rules[section][arg][5:])
 | 
			
		||||
                rules[section][arg] = open(import_file).read()
 | 
			
		||||
                paths = [os.path.join(sys.prefix, 'share/morss', rules[section][arg][5:]),
 | 
			
		||||
                    os.path.join(os.path.dirname(__file__), '..', rules[section][arg][5:])]
 | 
			
		||||
 | 
			
		||||
                for path in paths:
 | 
			
		||||
                    try:
 | 
			
		||||
                        file_raw = open(path).read()
 | 
			
		||||
                        file_clean = re.sub('<[/?]?(xsl|xml)[^>]+?>', '', file_raw)
 | 
			
		||||
                        rules[section][arg] = file_clean
 | 
			
		||||
 | 
			
		||||
                    except IOError:
 | 
			
		||||
                        pass
 | 
			
		||||
 | 
			
		||||
            elif '\n' in rules[section][arg]:
 | 
			
		||||
                rules[section][arg] = rules[section][arg].split('\n')[1:]
 | 
			
		||||
@@ -293,10 +306,7 @@ class ParserXML(ParserBase):
 | 
			
		||||
 | 
			
		||||
    NSMAP = {'atom': 'http://www.w3.org/2005/Atom',
 | 
			
		||||
        'atom03': 'http://purl.org/atom/ns#',
 | 
			
		||||
        'media': 'http://search.yahoo.com/mrss/',
 | 
			
		||||
        'rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
 | 
			
		||||
        'slash': 'http://purl.org/rss/1.0/modules/slash/',
 | 
			
		||||
        'dc': 'http://purl.org/dc/elements/1.1/',
 | 
			
		||||
        'content': 'http://purl.org/rss/1.0/modules/content/',
 | 
			
		||||
        'rssfake': 'http://purl.org/rss/1.0/'}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,196 +0,0 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html>
 | 
			
		||||
	<head>
 | 
			
		||||
		<title>Feed reader by morss</title>
 | 
			
		||||
		<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0;" />
 | 
			
		||||
		<meta name="robots" content="noindex" />
 | 
			
		||||
 | 
			
		||||
		<style type="text/css">
 | 
			
		||||
			/* columns - from https://thisisdallas.github.io/Simple-Grid/simpleGrid.css */
 | 
			
		||||
 | 
			
		||||
			* {
 | 
			
		||||
				box-sizing: border-box;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			#content {
 | 
			
		||||
				width: 100%;
 | 
			
		||||
				max-width: 1140px;
 | 
			
		||||
				min-width: 755px;
 | 
			
		||||
				margin: 0 auto;
 | 
			
		||||
				overflow: hidden;
 | 
			
		||||
 | 
			
		||||
				padding-top: 20px;
 | 
			
		||||
				padding-left: 20px; /* grid-space to left */
 | 
			
		||||
				padding-right: 0px; /* grid-space to right: (grid-space-left - column-space) e.g. 20px-20px=0 */
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			.item {
 | 
			
		||||
				width: 33.33%;
 | 
			
		||||
				float: left;
 | 
			
		||||
				padding-right: 20px; /* column-space */
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			@media handheld, only screen and (max-width: 767px) {
 | 
			
		||||
				#content {
 | 
			
		||||
					width: 100%;
 | 
			
		||||
					min-width: 0;
 | 
			
		||||
					margin-left: 0px;
 | 
			
		||||
					margin-right: 0px;
 | 
			
		||||
					padding-left: 20px; /* grid-space to left */
 | 
			
		||||
					padding-right: 10px; /* grid-space to right: (grid-space-left - column-space) e.g. 20px-10px=10px */
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				.item {
 | 
			
		||||
					width: auto;
 | 
			
		||||
					float: none;
 | 
			
		||||
					margin-left: 0px;
 | 
			
		||||
					margin-right: 0px;
 | 
			
		||||
					margin-top: 10px;
 | 
			
		||||
					margin-bottom: 10px;
 | 
			
		||||
					padding-left: 0px;
 | 
			
		||||
					padding-right: 10px; /* column-space */
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			/* design */
 | 
			
		||||
 | 
			
		||||
			#header h1, #header h2, #header p {
 | 
			
		||||
				font-family: sans;
 | 
			
		||||
				text-align: center;
 | 
			
		||||
				margin: 0;
 | 
			
		||||
				padding: 0;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			#header h1 {
 | 
			
		||||
				font-size: 2.5em;
 | 
			
		||||
				font-weight: bold;
 | 
			
		||||
				padding: 1em 0 0.25em;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			#header h2 {
 | 
			
		||||
				font-size: 1em;
 | 
			
		||||
				font-weight: normal;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			#header p {
 | 
			
		||||
				color: gray;
 | 
			
		||||
				font-style: italic;
 | 
			
		||||
				font-size: 0.75em;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			#content {
 | 
			
		||||
				text-align: justify;
 | 
			
		||||
				line-height: 1.5em;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
				.item .title {
 | 
			
		||||
					font-weight: bold;
 | 
			
		||||
					display: block;
 | 
			
		||||
					text-align: center;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				.item .link {
 | 
			
		||||
					color: inherit;
 | 
			
		||||
					text-decoration: none;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				.item:not(.active) {
 | 
			
		||||
					cursor: pointer;
 | 
			
		||||
 | 
			
		||||
					height: 20em;
 | 
			
		||||
					margin-bottom: 20px;
 | 
			
		||||
					overflow: hidden;
 | 
			
		||||
					text-overflow: ellpisps;
 | 
			
		||||
 | 
			
		||||
					padding: 0.25em;
 | 
			
		||||
					position: relative;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
					.item:not(.active) .title {
 | 
			
		||||
						padding-bottom: 0.1em;
 | 
			
		||||
						margin-bottom: 0.1em;
 | 
			
		||||
						border-bottom: 1px solid silver;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					.item:not(.active):before {
 | 
			
		||||
						content: " ";
 | 
			
		||||
						display: block;
 | 
			
		||||
						width: 100%;
 | 
			
		||||
						position: absolute;
 | 
			
		||||
						top: 18.5em;
 | 
			
		||||
						height: 1.5em;
 | 
			
		||||
						background: linear-gradient(to bottom, rgba(255,255,255,0) 0%, rgba(255,255,255,1) 100%);
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					.item:not(.active) .article * {
 | 
			
		||||
						max-width: 100%;
 | 
			
		||||
						font-size: 1em !important;
 | 
			
		||||
						font-weight: normal;
 | 
			
		||||
						display: inline;
 | 
			
		||||
						margin: 0;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
				.item.active {
 | 
			
		||||
					background: white;
 | 
			
		||||
					position: fixed;
 | 
			
		||||
					overflow: auto;
 | 
			
		||||
					top: 0;
 | 
			
		||||
					left: 0;
 | 
			
		||||
					height: 100%;
 | 
			
		||||
					width: 100%;
 | 
			
		||||
					z-index: 1;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
					body.noscroll {
 | 
			
		||||
						overflow: hidden;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					.item.active > * {
 | 
			
		||||
						max-width: 700px;
 | 
			
		||||
						margin: auto;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					.item.active .title {
 | 
			
		||||
						font-size: 2em;
 | 
			
		||||
						padding: 0.5em 0;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					.item.active .article object,
 | 
			
		||||
					.item.active .article video,
 | 
			
		||||
					.item.active .article audio {
 | 
			
		||||
						display: none;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					.item.active .article img {
 | 
			
		||||
						max-height: 20em;
 | 
			
		||||
						max-width: 100%;
 | 
			
		||||
					}
 | 
			
		||||
		</style>
 | 
			
		||||
	</head>
 | 
			
		||||
 | 
			
		||||
	<body>
 | 
			
		||||
		<div id="header">
 | 
			
		||||
			<h1>RSS feed</h1>
 | 
			
		||||
			<h2>with full text articles</h2>
 | 
			
		||||
			<p>- via morss</p>
 | 
			
		||||
		</div>
 | 
			
		||||
 | 
			
		||||
		<div id="content">
 | 
			
		||||
				<div class="item">
 | 
			
		||||
					<a class="title link" href="@item.link" target="_blank"></a>
 | 
			
		||||
					<div class="desc"></div>
 | 
			
		||||
					<div class="content"></div>
 | 
			
		||||
				</div>
 | 
			
		||||
		</div>
 | 
			
		||||
 | 
			
		||||
	<script>
 | 
			
		||||
		var items = document.getElementsByClassName('item')
 | 
			
		||||
		for (var i in items)
 | 
			
		||||
			items[i].onclick = function()
 | 
			
		||||
			{
 | 
			
		||||
				this.classList.toggle('active')
 | 
			
		||||
				document.body.classList.toggle('noscroll')
 | 
			
		||||
			}
 | 
			
		||||
	</script>
 | 
			
		||||
	</body>
 | 
			
		||||
</html>
 | 
			
		||||
							
								
								
									
										2
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								setup.py
									
									
									
									
									
								
							@@ -13,7 +13,7 @@ setup(
 | 
			
		||||
    license = 'AGPL v3',
 | 
			
		||||
    packages = [package_name],
 | 
			
		||||
    install_requires = ['lxml', 'bs4', 'python-dateutil', 'chardet', 'pymysql'],
 | 
			
		||||
    package_data = {package_name: ['feedify.ini', 'reader.html.template']},
 | 
			
		||||
    package_data = {package_name: ['feedify.ini']},
 | 
			
		||||
    data_files = [
 | 
			
		||||
        ('share/' + package_name, ['README.md', 'LICENSE']),
 | 
			
		||||
        ('share/' + package_name + '/www', glob('www/*.*')),
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										124
									
								
								www/sheet.xsl
									
									
									
									
									
								
							
							
						
						
									
										124
									
								
								www/sheet.xsl
									
									
									
									
									
								
							@@ -1,13 +1,22 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 | 
			
		||||
<xsl:stylesheet version="1.1"
 | 
			
		||||
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 | 
			
		||||
	xmlns:atom="http://www.w3.org/2005/Atom"
 | 
			
		||||
	xmlns:atom03="http://purl.org/atom/ns#"
 | 
			
		||||
	xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 | 
			
		||||
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
 | 
			
		||||
	xmlns:rssfake="http://purl.org/rss/1.0/"
 | 
			
		||||
	>
 | 
			
		||||
 | 
			
		||||
	<xsl:output method="html"/>
 | 
			
		||||
 | 
			
		||||
	<xsl:template match="/">
 | 
			
		||||
		<!DOCTYPE html>
 | 
			
		||||
		<html>
 | 
			
		||||
		<head>
 | 
			
		||||
			<title>RSS feed by morss</title>
 | 
			
		||||
			<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0;" />
 | 
			
		||||
			<meta name="robots" content="noindex" />
 | 
			
		||||
 | 
			
		||||
			<style type="text/css">
 | 
			
		||||
				body {
 | 
			
		||||
@@ -23,36 +32,16 @@
 | 
			
		||||
					max-width: 100%;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				body > ul {
 | 
			
		||||
				.item {
 | 
			
		||||
					background-color: #FFFAF4;
 | 
			
		||||
					border: 1px solid silver;
 | 
			
		||||
					padding: 1%;
 | 
			
		||||
					margin: 1%;
 | 
			
		||||
					max-width: 100%;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				ul {
 | 
			
		||||
					list-style-type: none;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				.tag {
 | 
			
		||||
					color: darkred;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				.attr {
 | 
			
		||||
					color: darksalmon;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				.value {
 | 
			
		||||
					color: darkblue;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				.comment {
 | 
			
		||||
					color: lightgrey;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				pre {
 | 
			
		||||
					margin: 0;
 | 
			
		||||
					max-width: 100%;
 | 
			
		||||
					white-space: normal;
 | 
			
		||||
				.item > a {
 | 
			
		||||
					border-bottom: 1px solid silver;
 | 
			
		||||
				}
 | 
			
		||||
			</style>
 | 
			
		||||
		</head>
 | 
			
		||||
@@ -65,59 +54,44 @@
 | 
			
		||||
 | 
			
		||||
			<div id="url"></div>
 | 
			
		||||
 | 
			
		||||
			<ul>
 | 
			
		||||
				<xsl:apply-templates/>
 | 
			
		||||
			</ul>
 | 
			
		||||
			<hr/>
 | 
			
		||||
 | 
			
		||||
			<div id="header">
 | 
			
		||||
				<h1>
 | 
			
		||||
					<xsl:value-of select="rdf:RDF/rssfake:channel/rssfake:title|rss/channel/title|atom:feed/atom:title|atom03:feed/atom03:title"/>
 | 
			
		||||
				</h1>
 | 
			
		||||
 | 
			
		||||
				<p>
 | 
			
		||||
					<xsl:value-of select="rdf:RDF/rssfake:channel/rssfake:description|rss/channel/description|atom:feed/atom:subtitle|atom03:feed/atom03:subtitle"/>
 | 
			
		||||
				</p>
 | 
			
		||||
			</div>
 | 
			
		||||
 | 
			
		||||
			<div id="content">
 | 
			
		||||
				<xsl:for-each select="rdf:RDF/rssfake:channel/rssfake:item|rss/channel/item|atom:feed/atom:entry|atom03:feed/atom03:entry">
 | 
			
		||||
					<div class="item">
 | 
			
		||||
						<a href="/" target="_blank"><xsl:attribute name="href"><xsl:value-of select="rssfake:link|link|atom:link/@href|atom03:link/@href"/></xsl:attribute>
 | 
			
		||||
								<xsl:value-of select="rssfake:title|title|atom:title|atom03:title"/>
 | 
			
		||||
						</a>
 | 
			
		||||
 | 
			
		||||
						<div class="desc">
 | 
			
		||||
							<xsl:value-of select="rssfake:description|description|atom:summary|atom03:summary"/>
 | 
			
		||||
						</div>
 | 
			
		||||
 | 
			
		||||
						<div class="content">
 | 
			
		||||
							<xsl:value-of select="content:encoded|atom:content|atom03:content"/>
 | 
			
		||||
						</div>
 | 
			
		||||
					</div>
 | 
			
		||||
				</xsl:for-each>
 | 
			
		||||
			</div>
 | 
			
		||||
 | 
			
		||||
			<script>
 | 
			
		||||
				document.getElementById("url").innerHTML = window.location.href;
 | 
			
		||||
				document.getElementById("url").innerHTML = window.location.href.replace(':html/', '')
 | 
			
		||||
 | 
			
		||||
				if (!/:html/.test(window.location.href))
 | 
			
		||||
					for (var content of document.getElementsByClassName("content"))
 | 
			
		||||
						content.innerHTML = content.innerText
 | 
			
		||||
			</script>
 | 
			
		||||
		</body>
 | 
			
		||||
		</html>
 | 
			
		||||
	</xsl:template>
 | 
			
		||||
 | 
			
		||||
	<xsl:template match="*">
 | 
			
		||||
		<li>
 | 
			
		||||
			<span class="element">
 | 
			
		||||
				<
 | 
			
		||||
					<span class="tag"><xsl:value-of select="name()"/></span>
 | 
			
		||||
 | 
			
		||||
					<xsl:for-each select="@*">
 | 
			
		||||
						<span class="attr"> <xsl:value-of select="name()"/></span>
 | 
			
		||||
						=
 | 
			
		||||
						"<span class="value"><xsl:value-of select="."/></span>"
 | 
			
		||||
					</xsl:for-each>
 | 
			
		||||
				>
 | 
			
		||||
			</span>
 | 
			
		||||
 | 
			
		||||
			<xsl:if test="node()">
 | 
			
		||||
				<ul>
 | 
			
		||||
					<xsl:apply-templates/>
 | 
			
		||||
				</ul>
 | 
			
		||||
			</xsl:if>
 | 
			
		||||
 | 
			
		||||
			<span class="element">
 | 
			
		||||
				</
 | 
			
		||||
					<span class="tag"><xsl:value-of select="name()"/></span>
 | 
			
		||||
				>
 | 
			
		||||
			</span>
 | 
			
		||||
		</li>
 | 
			
		||||
	</xsl:template>
 | 
			
		||||
 | 
			
		||||
	<xsl:template match="comment()">
 | 
			
		||||
		<li>
 | 
			
		||||
			<pre class="comment"><![CDATA[<!--]]><xsl:value-of select="."/><![CDATA[-->]]></pre>
 | 
			
		||||
		</li>
 | 
			
		||||
	</xsl:template>
 | 
			
		||||
 | 
			
		||||
	<xsl:template match="text()">
 | 
			
		||||
		<li>
 | 
			
		||||
			<pre>
 | 
			
		||||
				<xsl:value-of select="normalize-space(.)"/>
 | 
			
		||||
			</pre>
 | 
			
		||||
		</li>
 | 
			
		||||
	</xsl:template>
 | 
			
		||||
 | 
			
		||||
	<xsl:template match="text()[not(normalize-space())]"/>
 | 
			
		||||
 | 
			
		||||
</xsl:stylesheet>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user