wepub

Check-in [9b93ca38a9]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Save/restore file position on blur/mouseleave and reload.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | master | trunk
Files: files | file ages | folders
SHA3-256:9b93ca38a959537855b4c617c89c57fc430bfa2915762575d64258ad4b749bc0
User & Date: ajv-899-334-8894@vsta.org 2016-10-17 23:54:01
Context
2016-11-17
17:29
Convert to account server. Firewall friendly port numbering. check-in: fac2f64eea user: ajv-899-334-8894@vsta.org tags: master, trunk
2016-10-17
23:54
Save/restore file position on blur/mouseleave and reload. check-in: 9b93ca38a9 user: ajv-899-334-8894@vsta.org tags: master, trunk
19:57
cookie storage check-in: b831168982 user: ajv-899-334-8894@vsta.org tags: master, trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to .gitignore.

1
2

*.pyc
chore



>
1
2
3
*.pyc
chore
var

Changes to get.py.

9
10
11
12
13
14
15
16
17
18
19
20
21
22

23
24
25
26
27
28
29
..
59
60
61
62
63
64
65

66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86



87




88
89
90
91
92
93
94
...
148
149
150
151
152
153
154



















#	For each prefix of files, its contents is served by
#	way of its path under here.
import pdb
import os, stat, urllib
import epub

# The GET part of our handling
class GET_Mixin(object):

    # Configure our WPlayer GET treatment
    def __init__(self):

	# GET handlers
	self.dispatchers.append( ("GET", self.open_path) )


    # "/"; main UI
    def send_top(self):
	app = self.server
	webroot = app.approot
        buf = self.build_header("EPUB categories")

................................................................................

        # Deflect nonsense
        parts = [p for p in os.path.split(rest) if p]
        if any((f == "..") for f in parts):
            return False,None

        # Is this an active book?

        if (len(parts) > 1) and parts[-2].endswith(".epub"):
            try:
                chapnum = int(parts[-1])
            except:
                return False,None
            if chapnum < 0:
                return False,None

            # Access the book file
            try:
                doc = epub.open_epub(
                 os.path.join(path, *(parts[:-1])), "r")
                book = epub.Book(doc)
                chap = book.chapters[chapnum]
            except:
                return False,None

            # Here's your chapter
            nm = book.titles[0] if book.titles else parts[-2]
            head = "%s chapter %d" % (nm, chapnum)
            buf = self.build_header(head)



            buf += chap.read()




            buf = self.build_tailer(buf)

            return True,self.send_result(buf, "text/html")

        # Index of book?
        if parts and parts[-1].endswith(".epub"):
            try:
................................................................................
                buf += ' <li><a href="%s">%s</a></li>\n' % \
                    (os.path.join(self.path, d), d)
            buf += "</ul>\n"

        buf = self.build_tailer(buf)
        return True,self.send_result(buf, "text/html")



























|






>







 







>










|
|









>
>
>

>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
..
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
...
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#	For each prefix of files, its contents is served by
#	way of its path under here.
import pdb
import os, stat, urllib
import epub

# The GET part of our handling
class GET_mixin(object):

    # Configure our WPlayer GET treatment
    def __init__(self):

	# GET handlers
	self.dispatchers.append( ("GET", self.open_path) )
	self.dispatchers.append( ("GET", self.get_state) )

    # "/"; main UI
    def send_top(self):
	app = self.server
	webroot = app.approot
        buf = self.build_header("EPUB categories")

................................................................................

        # Deflect nonsense
        parts = [p for p in os.path.split(rest) if p]
        if any((f == "..") for f in parts):
            return False,None

        # Is this an active book?
        # /prefix/...path.../<book>/<chap#>
        if (len(parts) > 1) and parts[-2].endswith(".epub"):
            try:
                chapnum = int(parts[-1])
            except:
                return False,None
            if chapnum < 0:
                return False,None

            # Access the book file
            try:
                docpath = os.path.join(path, *(parts[:-1]))
                doc = epub.open_epub(docpath, "r")
                book = epub.Book(doc)
                chap = book.chapters[chapnum]
            except:
                return False,None

            # Here's your chapter
            nm = book.titles[0] if book.titles else parts[-2]
            head = "%s chapter %d" % (nm, chapnum)
            buf = self.build_header(head)
            buf += '<script src="/js/reader.js"></script>\n'
            buf += '<div id="textview"\n'
            buf += '  style="width: 100%;">\n'
            buf += chap.read()
            buf += '</div>\n'
            doc.close()
            buf += '<script>reading("%s", "%s", "%s");</script>\n' % \
                (self.user, docpath, "textview")
            buf = self.build_tailer(buf)

            return True,self.send_result(buf, "text/html")

        # Index of book?
        if parts and parts[-1].endswith(".epub"):
            try:
................................................................................
                buf += ' <li><a href="%s">%s</a></li>\n' % \
                    (os.path.join(self.path, d), d)
            buf += "</ul>\n"

        buf = self.build_tailer(buf)
        return True,self.send_result(buf, "text/html")

    # /state.json?doc=X
    # User's saved state for reading the document with path X
    def get_state(self):
        if not self.path_match("state.json"):
            return False,None
        doc = self.vals.get("doc")
        if doc is None:
            return False,None

        # Get a filesystem safe name, see if we can get the info
        try:
            doc = urllib.quote_plus(urllib.unquote(doc))
            f = open("var/state/%s/%s.json" % (self.user, doc), "r")
            buf = f.read()
            f.close()
        except:
            return False,None

        return True,self.send_result(buf, "application/json")

Added js/reader.js.





































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
//
// reader.js
//      Support functions for reading a chapter on a web page
//

// User name
var who = null;

// Document path
var docname = null;

// Web element with text content which scrolls
var pane = null;

// Wrappers for XMLHttpRequest
function xhr_get(url, fn) {
    var req = new XMLHttpRequest();
    req.open("GET", url);
    req.onreadystatechange = function() {
        // Ignore progress/errors
        if ((req.readyState != 4) || (req.status != 200)) {
            return;
        }

        // Response (or ignore)
        if (fn != null) {
            fn(req.responseText);
        }
    }
    req.send();
}
function xhr_put_json(url, buf, fn) {
    var req = new XMLHttpRequest();
    req.open("PUT", url);
    req.setRequestHeader("Content-type", "application/json");
    req.setRequestHeader("Content-length", buf.length);
    req.onreadystatechange = function() {
        // Ignore progress/errors
        if ((req.readyState != 4) || (req.status != 200)) {
            return;
        }

        // Response (or ignore)
        if (fn != null) {
            fn(req.responseText);
        }
    }
    req.send(buf);
}

// Saved state for this user on this document
function start_state(txt) {
    var resp = JSON.parse(txt);

    // Position is saved as a float percentage 0..1, so
    //  scale fractional position against overall scroll
    //  height to set position.
    var d = document.scrollingElement;
    if (d != null) {
        d.scrollTop = d.scrollHeight * resp.pos;
    }

    // TBD, styling to patch into CSS?
}

// Push our position
function save_state() {
    var st = {};
    var d = document.scrollingElement;
    if (d != null) {
        st.pos = d.scrollTop / d.scrollHeight;
        xhr_put_json("/state.json?doc=" + encodeURIComponent(docname),
            JSON.stringify(st), null);
    }
}

// On page load, configure to track this user for this scrollable
//  text content of this document.  If there's a saved position,
//  scroll to it.
function reading(arg_who, arg_doc, arg_pane) {
    // Save for future
    who = arg_who;
    docname = arg_doc;
    pane = document.getElementById(arg_pane);

    // Snapshot our reading position when we switch away
    document.addEventListener("blur", save_state);
    document.addEventListener("mouseleave", save_state);
    document.addEventListener("visibilitychange", function () {
        if (document.hidden) {
            save_state();
        }
    });

    // Get any saved state
    xhr_get("/state.json?doc=" + encodeURIComponent(docname),
        start_state);
}

Changes to main.py.

1
2
3
4
5
6
7

8
9
10

11




12
13
14
15
16
17
18
19
20
#
# main.py
#	Main driver for WWW-Usenet interface
#
import sys, time
import chore
from get import GET_Mixin


# Tie our various handlers together
class App_Handler(chore.handlers.Chore_Handler, GET_Mixin):

    def __init__(self, conn, tup, approot):




	chore.handlers.Chore_Handler.__init__(self, conn, tup, approot,
	    (GET_Mixin.__init__,))

# Load our configuration file
#
# This includes configuring our config file elements,
#  then processing the supplied file.
def load_cfg(fn):







|
>


|
>

>
>
>
>

|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#
# main.py
#	Main driver for WWW-Usenet interface
#
import sys, time
import chore
from get import GET_mixin
from put import PUT_mixin

# Tie our various handlers together
class App_Handler(chore.handlers.Chore_Handler, GET_mixin, PUT_mixin,
        chore.authen.Authen_mixin):
    def __init__(self, conn, tup, approot):

        # Cookie, or back to accounts file
        self.authentication = (self.auth_cookie, self.auth_password)

	chore.handlers.Chore_Handler.__init__(self, conn, tup, approot,
	    (GET_mixin.__init__,PUT_mixin.__init__))

# Load our configuration file
#
# This includes configuring our config file elements,
#  then processing the supplied file.
def load_cfg(fn):

Added put.py.











































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#
# put.py
#       Handle PUT operations to the ePub reader
#
import os, sys, urllib

class PUT_mixin(object):

    def __init__(self):
        self.dispatchers.append( ("PUT", self.put_state) )

    # Here's some fresh state?
    # /state.json?doc=X
    def put_state(self, buf):
        if not self.path_match("state.json"):
            return False,None
        doc = self.vals.get("doc")
        if doc is None:
            return False,None

        # Get a filesystem safe name, see if we can save the info
        try:
            os.mkdir("var/state/%s" % (self.user,))
        except:
            # Already exists, probably
            pass
        try:
            doc = urllib.quote_plus(urllib.unquote(doc))
            statepath = "var/state/%s/%s.json" % (self.user, doc)
            f = open(statepath, "w")
            f.write(buf)
            f.close()
        except:
            sys.stderr.write("Can't save state to %s\n" % (statepath,))
            return False,None

        return True,self.send_result("", "text/html")