diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..28971c5
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,12 @@
+[*]
+end_of_line = lf
+insert_final_newline = true
+
+[*.{js,py,html}]
+indent_style = space
+indent_size = 4
+charset = utf-8
+
+[Makefile]
+indent_style = tab
+
diff --git a/ctl b/ctl
index 805595c..4c05511 100755
--- a/ctl
+++ b/ctl
@@ -162,12 +162,14 @@ if [ "$1" == "open" ]; then
xdg-open "file://${BASE}/openmedialibrary/static/html/load.html"
fi
else
- $PYTHON "${NAME}/oml/gtkstatus.py" $@
- exit $?
+ #$PYTHON "${NAME}/oml/gtkstatus.py" $@
+ #exit $?
+ "$0" start &
fi
else
- $PYTHON "$NAME/oml/gtkstatus.py" $@
- exit $?
+ #$PYTHON "$NAME/oml/gtkstatus.py" $@
+ #exit $?
+ "$0" start &
fi
fi
exit 0
@@ -187,7 +189,7 @@ fi
if [ "$1" == "ui" ]; then
shift
- $PYTHON "$NAME/oml/ui.py" $@
+ $PYTHON "$NAME/oml/ui.py" "$@"
exit $?
fi
if [ "$1" == "init" ]; then
diff --git a/oml/__main__.py b/oml/__main__.py
index f888dd5..f5e2b5e 100644
--- a/oml/__main__.py
+++ b/oml/__main__.py
@@ -1,6 +1,5 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
import os
import sys
diff --git a/oml/api.py b/oml/api.py
index 32b31bc..bf44566 100644
--- a/oml/api.py
+++ b/oml/api.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
from os.path import normpath, dirname, abspath, join
diff --git a/oml/changelog.py b/oml/changelog.py
index 483a708..c16834c 100644
--- a/oml/changelog.py
+++ b/oml/changelog.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
import os
from datetime import datetime
diff --git a/oml/commands.py b/oml/commands.py
index 7e0a05d..d147b2e 100644
--- a/oml/commands.py
+++ b/oml/commands.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
from os.path import join, exists, dirname
diff --git a/oml/downloads.py b/oml/downloads.py
index 8374f95..1835ec1 100644
--- a/oml/downloads.py
+++ b/oml/downloads.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
import os
from threading import Thread
diff --git a/oml/gtkstatus.py b/oml/gtkstatus.py
index 726afc5..4dc3ce5 100644
--- a/oml/gtkstatus.py
+++ b/oml/gtkstatus.py
@@ -9,39 +9,48 @@ import webbrowser
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GLib
-try:
- gi.require_version('AppIndicator3', '0.1')
- from gi.repository import AppIndicator3 as appindicator
-except:
- appindicator = None
-
base = dirname(dirname(dirname(abspath(__file__))))
-icon = os.path.join(base, 'openmedialibrary/static/png/oml.png')
+icon = os.path.join(base, 'openmedialibrary/static/svg/oml.svg')
title = "Open Media Library"
ctl = base + '/ctl'
-class OMLIcon:
+def check_pid(pid):
+ if not os.path.exists(pid):
+ return False
+ try:
+ with open(pid, 'r') as fd:
+ pid = int(fd.read().strip())
+ os.kill(pid, 0)
+ except OSError:
+ return False
+ else:
+ return True
+
+def preexec(): # Don't forward signals.
+ os.setpgrp()
+
+
+class OMLStatus:
menu = None
icon = None
- indicator = None
def __init__(self, autostart=False):
self.autostart = autostart
self.create_pid()
- if appindicator:
- self.indicator = appindicator.Indicator.new("OML", icon,
- appindicator.IndicatorCategory.APPLICATION_STATUS)
- self.indicator.set_status(appindicator.IndicatorStatus.ACTIVE)
- self.menu = self.get_menu()
- self.indicator.set_menu(self.menu)
- else:
- self.icon = Gtk.StatusIcon()
- self.icon.set_from_file(icon)
- self.icon.set_title(title)
- self.icon.connect("activate", self._click)
- self.icon.connect("popup-menu", self._click)
+ self.win = Gtk.Window()
+ self.win.set_icon_from_file(icon)
+ self.win.set_title(title)
+ #self.win.show_all()
+ self.win.iconify()
+ '''
+ self.icon = Gtk.StatusIcon()
+ self.icon.set_from_file(icon)
+ self.icon.set_title(title)
+ self.icon.connect("activate", self._click)
+ self.icon.connect("popup-menu", self._click)
+ '''
subprocess.Popen([ctl, 'start'], close_fds=True, preexec_fn=preexec)
if not self.autostart:
GLib.timeout_add_seconds(1, self._open, None)
@@ -81,7 +90,7 @@ class OMLIcon:
@classmethod
def is_running(cls):
pid = cls.get_pid()
- if pid and os.path.exists(pid):
+ if pid and check_pid(pid):
return True
else:
return False
@@ -140,16 +149,14 @@ class OMLIcon:
url += '#%s' % port
webbrowser.open_new_tab(url)
-def preexec(): # Don't forward signals.
- os.setpgrp()
if __name__ == '__main__':
import signal
autostart = len(sys.argv) > 1 and sys.argv[1] == '--autostart'
- if OMLIcon.is_running():
- OMLIcon.load()
+ if OMLStatus.is_running():
+ OMLStatus.load()
else:
- oml = OMLIcon(autostart)
+ oml = OMLStatus(autostart)
main_loop = GLib.MainLoop()
try:
main_loop.run()
diff --git a/oml/item/api.py b/oml/item/api.py
index c94d7cf..d0c04a5 100644
--- a/oml/item/api.py
+++ b/oml/item/api.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
import json
import hashlib
import os
diff --git a/oml/item/handlers.py b/oml/item/handlers.py
index b13c9f4..19d6460 100644
--- a/oml/item/handlers.py
+++ b/oml/item/handlers.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
from datetime import datetime
@@ -7,6 +6,7 @@ import mimetypes
import os
from urllib.request import quote
import zipfile
+import base64
import ox
@@ -27,7 +27,42 @@ import state
import logging
logger = logging.getLogger(__name__)
-class OMLHandler(tornado.web.RequestHandler):
+
+class OptionalBasicAuthMixin(object):
+ class SendChallenge(Exception):
+ pass
+
+ def prepare(self):
+ if settings.preferences.get('authentication'):
+ try:
+ self.authenticate_user()
+ except self.SendChallenge:
+ self.send_auth_challenge()
+
+ def send_auth_challenge(self):
+ realm = "Open Media Library"
+ hdr = 'Basic realm="%s"' % realm
+ self.set_status(401)
+ self.set_header('www-authenticate', hdr)
+ self.finish()
+ return False
+
+ def authenticate_user(self):
+ auth_header = self.request.headers.get('Authorization')
+ if not auth_header or not auth_header.startswith('Basic '):
+ raise self.SendChallenge()
+
+ auth_data = auth_header.split(None, 1)[-1]
+ auth_data = base64.b64decode(auth_data).decode('ascii')
+ username, password = auth_data.split(':', 1)
+
+ auth = settings.preferences.get('authentication')
+ if auth.get('username') == username and auth.get('password') == password:
+ self._current_user = username
+ else:
+ raise self.SendChallenge()
+
+class OMLHandler(OptionalBasicAuthMixin, tornado.web.RequestHandler):
def initialize(self):
pass
@@ -141,7 +176,7 @@ class ReaderHandler(OMLHandler):
path = os.path.join(settings.static_path, html)
return serve_static(self, path, 'text/html')
-class UploadHandler(tornado.web.RequestHandler):
+class UploadHandler(OMLHandler):
def initialize(self, context=None):
self._context = context
diff --git a/oml/item/icons.py b/oml/item/icons.py
index 7d96d39..37d89fb 100644
--- a/oml/item/icons.py
+++ b/oml/item/icons.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
import os
import sqlite3
@@ -23,23 +22,32 @@ logger = logging.getLogger(__name__)
MAX_WORKERS = 4
-
class Icons(dict):
+
def __init__(self, db):
self._db = db
self.create()
+ def is_available(self):
+ folder = os.path.dirname(self._db)
+ if os.path.exists(folder):
+ if not os.path.exists(self._db):
+ self.create()
+ return os.path.exists(self._db)
+
def connect(self):
conn = sqlite3.connect(self._db, timeout=90)
return conn
def create(self):
- conn = self.connect()
- c = conn.cursor()
- c.execute('CREATE TABLE IF NOT EXISTS icon (id varchar(64) unique, data blob)')
- c.execute('CREATE TABLE IF NOT EXISTS setting (key varchar(256) unique, value text)')
- if int(self.get_setting(c, 'version', 0)) < 1:
- self.set_setting(c, 'version', 1)
+ folder = os.path.dirname(self._db)
+ if os.path.exists(folder):
+ conn = self.connect()
+ c = conn.cursor()
+ c.execute('CREATE TABLE IF NOT EXISTS icon (id varchar(64) unique, data blob)')
+ c.execute('CREATE TABLE IF NOT EXISTS setting (key varchar(256) unique, value text)')
+ if int(self.get_setting(c, 'version', 0)) < 1:
+ self.set_setting(c, 'version', 1)
def get_setting(self, c, key, default=None):
c.execute('SELECT value FROM setting WHERE key = ?', (key, ))
@@ -105,7 +113,7 @@ class Icons(dict):
c.close()
conn.close()
except:
- logger.debug('failed to clear icon %s', id)
+ logger.debug('failed to clear icon %s', prefix)
def vacuum(self, ids):
conn = self.connect()
@@ -140,6 +148,8 @@ def get_icons_db_path():
return icons_db_path
def get_icon_sync(id, type_, size):
+ if not icons.is_available():
+ return ''
if size:
skey = '%s:%s:%s' % (type_, id, size)
data = icons[skey]
diff --git a/oml/item/models.py b/oml/item/models.py
index b2d5c3a..cfc44e3 100644
--- a/oml/item/models.py
+++ b/oml/item/models.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
from datetime import datetime
import base64
import hashlib
diff --git a/oml/item/person.py b/oml/item/person.py
index 4e68205..27ad8f7 100644
--- a/oml/item/person.py
+++ b/oml/item/person.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
import unicodedata
diff --git a/oml/item/person_api.py b/oml/item/person_api.py
index e6cb8dc..1293f34 100644
--- a/oml/item/person_api.py
+++ b/oml/item/person_api.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
import unicodedata
from oxtornado import actions
diff --git a/oml/item/query.py b/oml/item/query.py
index b48fe29..9683dee 100644
--- a/oml/item/query.py
+++ b/oml/item/query.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
#does not work in sqlite
diff --git a/oml/item/scan.py b/oml/item/scan.py
index 04a58c9..4869ac9 100644
--- a/oml/item/scan.py
+++ b/oml/item/scan.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
from datetime import datetime
diff --git a/oml/item/title_api.py b/oml/item/title_api.py
index b34a70c..22fb3b5 100644
--- a/oml/item/title_api.py
+++ b/oml/item/title_api.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
import hashlib
import json
import unicodedata
diff --git a/oml/library.py b/oml/library.py
index 510e7d2..c80fc4d 100644
--- a/oml/library.py
+++ b/oml/library.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
import json
import os
import time
diff --git a/oml/localnodes.py b/oml/localnodes.py
index 5e7129b..f3fa7ec 100644
--- a/oml/localnodes.py
+++ b/oml/localnodes.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
import socket
diff --git a/oml/media/__init__.py b/oml/media/__init__.py
index 5cebfcf..dd9d32b 100644
--- a/oml/media/__init__.py
+++ b/oml/media/__init__.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
import base64
diff --git a/oml/media/cbr.py b/oml/media/cbr.py
index 9f72a71..66e1324 100644
--- a/oml/media/cbr.py
+++ b/oml/media/cbr.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
import os
diff --git a/oml/media/epub.py b/oml/media/epub.py
index 81ccb17..cd5a6f0 100644
--- a/oml/media/epub.py
+++ b/oml/media/epub.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
import os
diff --git a/oml/media/opf.py b/oml/media/opf.py
index b8a20b8..8070c40 100644
--- a/oml/media/opf.py
+++ b/oml/media/opf.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
import xml.etree.ElementTree as ET
diff --git a/oml/media/pdf.py b/oml/media/pdf.py
index c4e9719..bc342d0 100644
--- a/oml/media/pdf.py
+++ b/oml/media/pdf.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
import sys
diff --git a/oml/media/txt.py b/oml/media/txt.py
index 193441c..ca76253 100644
--- a/oml/media/txt.py
+++ b/oml/media/txt.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
import os
diff --git a/oml/meta/__init__.py b/oml/meta/__init__.py
index 45c3d3e..13209c0 100644
--- a/oml/meta/__init__.py
+++ b/oml/meta/__init__.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
import stdnum.isbn
diff --git a/oml/meta/duckduckgo.py b/oml/meta/duckduckgo.py
index 105426b..b3c28e6 100644
--- a/oml/meta/duckduckgo.py
+++ b/oml/meta/duckduckgo.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
import ox.web.duckduckgo
diff --git a/oml/meta/google.py b/oml/meta/google.py
index 4b628bf..713647d 100644
--- a/oml/meta/google.py
+++ b/oml/meta/google.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
from time import time, sleep
from urllib.parse import urlencode
diff --git a/oml/meta/utils.py b/oml/meta/utils.py
index 49f0703..741fce8 100644
--- a/oml/meta/utils.py
+++ b/oml/meta/utils.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
import re
diff --git a/oml/node/cert.py b/oml/node/cert.py
index 64cb741..8b7e5d1 100644
--- a/oml/node/cert.py
+++ b/oml/node/cert.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
import hashlib
import os
diff --git a/oml/node/nodeapi.py b/oml/node/nodeapi.py
index a3f16d5..93c0d49 100644
--- a/oml/node/nodeapi.py
+++ b/oml/node/nodeapi.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
from user.models import User
@@ -82,9 +81,9 @@ def api_upload(user_id, items):
from user.models import List
peer = User.get(user_id)
if peer:
- l = List.get_or_create(':Public')
+ l = List.get_or_create(':Inbox')
if l:
- logger.debug('%s added items to public folder: %s', user_id, items)
+ logger.debug('%s added items to inbox: %s', user_id, items)
l.add_items(items)
trigger_event('change', {})
return True
diff --git a/oml/node/server.py b/oml/node/server.py
index 4673441..0e5694e 100644
--- a/oml/node/server.py
+++ b/oml/node/server.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
from socketserver import ThreadingMixIn
from threading import Thread
import base64
diff --git a/oml/nodes.py b/oml/nodes.py
index 70fae05..f9b3ff2 100644
--- a/oml/nodes.py
+++ b/oml/nodes.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
from queue import Queue
@@ -462,7 +461,7 @@ class Node(Thread):
return False
def upload(self, items):
- logger.debug('add items to %s\'s public folder: %s', self.id, items)
+ logger.debug('add items to %s\'s inbox: %s', self.user_id, items)
r = self.request('upload', items)
return bool(r)
diff --git a/oml/oxtornado.py b/oml/oxtornado.py
index 7215e9a..b34cdfe 100644
--- a/oml/oxtornado.py
+++ b/oml/oxtornado.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
from contextlib import contextmanager
diff --git a/oml/pdict.py b/oml/pdict.py
index a648d24..cf1d37b 100644
--- a/oml/pdict.py
+++ b/oml/pdict.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
import os
import json
diff --git a/oml/queryparser.py b/oml/queryparser.py
index 5ccc68a..033e068 100644
--- a/oml/queryparser.py
+++ b/oml/queryparser.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
from datetime import datetime
import unicodedata
diff --git a/oml/server.py b/oml/server.py
index f98ed7b..b01d598 100644
--- a/oml/server.py
+++ b/oml/server.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
import os
import sys
diff --git a/oml/settings.py b/oml/settings.py
index 631b398..f70b930 100644
--- a/oml/settings.py
+++ b/oml/settings.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
import json
import os
diff --git a/oml/setup.py b/oml/setup.py
index 85c2bae..b243a00 100644
--- a/oml/setup.py
+++ b/oml/setup.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
import os
diff --git a/oml/ssl_request.py b/oml/ssl_request.py
index 538ea75..43b4fb3 100644
--- a/oml/ssl_request.py
+++ b/oml/ssl_request.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
import ssl
import http.client
diff --git a/oml/tasks.py b/oml/tasks.py
index af02c3c..3f97379 100644
--- a/oml/tasks.py
+++ b/oml/tasks.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
from queue import PriorityQueue
from threading import Thread
import json
diff --git a/oml/tor_request.py b/oml/tor_request.py
index 7b10063..0fd6455 100644
--- a/oml/tor_request.py
+++ b/oml/tor_request.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
import ssl
import http.client
diff --git a/oml/ui.py b/oml/ui.py
index a15dfac..5b9dc26 100644
--- a/oml/ui.py
+++ b/oml/ui.py
@@ -1,5 +1,4 @@
# encoding: utf-8
-# vi:si:et:sw=4:sts=4:ts=4
import sys
import os
try:
@@ -105,7 +104,8 @@ if __name__ == '__main__':
if len(sys.argv) >= 3:
base = sys.argv[2]
base = os.path.expanduser(base)
- os.chdir(base)
+ if os.path.exists(base):
+ os.chdir(base)
if len(sys.argv) >= 2 and sys.argv[1] == 'folder':
print(ui.selectFolder({}))
else:
diff --git a/oml/ui_websocket.py b/oml/ui_websocket.py
index 7efdddd..3bd5204 100644
--- a/oml/ui_websocket.py
+++ b/oml/ui_websocket.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
import json
diff --git a/oml/update.py b/oml/update.py
index 8ab472c..83c490a 100644
--- a/oml/update.py
+++ b/oml/update.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
from contextlib import closing
import base64
diff --git a/oml/user/api.py b/oml/user/api.py
index d8fecfa..7f138c8 100644
--- a/oml/user/api.py
+++ b/oml/user/api.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
from copy import deepcopy
@@ -189,7 +188,7 @@ def getLists(data):
'type': 'libraries',
'user': None,
})
- List.get_or_create(':Public')
+ List.get_or_create(':Inbox')
for u in models.User.query.filter((models.User.peered==True)|(models.User.id==settings.USER_ID)):
lists += u.lists_json()
return {
@@ -290,7 +289,7 @@ def removeList(data):
}
'''
l = models.List.get(data['id'])
- if l and l.name != 'Public':
+ if l and l.name != 'Inbox':
l.remove()
return {}
actions.register(removeList, cache=False)
@@ -309,12 +308,10 @@ def addListItems(data):
i = Item.get(item_id)
i.queue_download()
i.update()
- elif data['list'] and (data['list'].startswith(':') or
- data['list'].endswith(':Public') or
- data['list'].enswtih(':')):
+ elif data['list'] and (data['list'].startswith(':') or data['list'].endswith(':')):
l = models.List.get_or_create(data['list'])
if l:
- if l.name in ('Public', '') and l.user_id != settings.USER_ID:
+ if l.name in ('Inbox', '') and l.user_id != settings.USER_ID:
state.tasks.queue('upload', {
'user': l.user_id,
'items': data['items']
@@ -351,12 +348,11 @@ def sortLists(data):
'''
n = 0
logger.debug('sortLists %s', data)
- lists = ['Public']
for id in data['ids']:
l = models.List.get(id)
l.index_ = n
n += 1
- if l.type == 'static':
+ if l.type == 'static' and l.name not in ('', 'Inbox'):
lists.append(l.name)
state.db.session.add(l)
state.db.session.commit()
diff --git a/oml/user/models.py b/oml/user/models.py
index ad75f0d..f90cf89 100644
--- a/oml/user/models.py
+++ b/oml/user/models.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
from datetime import datetime
import json
import os
@@ -218,7 +217,7 @@ class User(db.Model):
Changelog.record(self, 'edititem', item.id, item.meta, _commit=False)
lists = []
for l in List.query.filter_by(user_id=self.id, type='static').order_by('index_'):
- if l.name:
+ if l.name and l.name != 'Inbox':
lists.append(l.name)
Changelog.record(self, 'addlist', l.name, _commit=False)
items = [i.id for i in l.get_items().options(load_only('id'))]
@@ -301,7 +300,7 @@ class List(db.Model):
state.db.session.add(l)
state.db.session.commit()
if user_id == settings.USER_ID:
- if l.type == 'static' and name != '':
+ if l.type == 'static' and name != '' and name != 'Inbox':
add_record('addlist', l.name)
return l
diff --git a/oml/utils.py b/oml/utils.py
index e5b9337..5130156 100644
--- a/oml/utils.py
+++ b/oml/utils.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
from datetime import datetime
diff --git a/oml/websocket.py b/oml/websocket.py
index 90821bb..27a3d4e 100644
--- a/oml/websocket.py
+++ b/oml/websocket.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-# vi:si:et:sw=4:sts=4:ts=4
from tornado.websocket import WebSocketHandler
diff --git a/static/js/annotation.js b/static/js/annotation.js
index f524b34..8003e73 100644
--- a/static/js/annotation.js
+++ b/static/js/annotation.js
@@ -1,34 +1,56 @@
'use strict';
-oml.ui.annotation = function(data, $iframe) {
+oml.ui.annotation = function(annotation, $iframe) {
var $quote = Ox.Element().addClass('OxSelectable OMLQuote').css({
+ backgroundColor: 'white',
color: 'black',
fontFamily: 'Georgia, Palatino, DejaVu Serif, Book Antiqua, Palatino Linotype, Times New Roman, serif',
fontSize: '14px',
lineHeight: '21px',
padding: '8px'
- }).html(Ox.encodeHTMLEntities(data.text).replace(/\n/g, '
')).on({
+ }).html(Ox.encodeHTMLEntities(annotation.text).replace(/\n/g, '
')).on({
click: function(event) {
that.select()
$iframe.postMessage('selectAnnotation', {
- id: data.id
+ id: annotation.id
})
}
})
- var $note = Ox.Editable({
+ var $note = Ox.ArrayEditable({
editing: true,
+ items: (annotation.comments || []).map(function(comment) {
+ comment.editable = true
+ return comment
+ }),
type: 'textarea'
}).css({
margin: '2px',
minHeight: '12px'
+ }).bindEvent({
+ submit: function(data) {
+ var comment = Ox.getObjectById(annotation.comments, data.id)
+ if (comment) {
+ comment.value = data.value
+ comment.modified = (new Date).toISOString()
+ } else {
+ annotation.comments.push({
+ created: data.created || (new Date).toISOString(),
+ modified: (new Date).toISOString(),
+ id: data.id,
+ value: data.value
+ })
+ }
+ that.triggerEvent('change')
+ }
});
var that = Ox.Element().attr({
- id: 'a-' + data.id
+ id: 'a-' + annotation.id
}).addClass(
'OxSelectable OMLAnnotation'
).css({
borderBottom: '1px solid rgb(208, 208, 208)',
}).append($quote).append($note);
+
that.annotate = function() {
var item = {
id: 'note', value: '', editable: true
diff --git a/static/js/annotationFolder.js b/static/js/annotationFolder.js
index 0472bce..b9d7760 100644
--- a/static/js/annotationFolder.js
+++ b/static/js/annotationFolder.js
@@ -3,8 +3,9 @@ oml.ui.annotationFolder = function() {
var ui = oml.user.ui,
that = Ox.Element().css({
overflowY: 'auto',
+ overflowX: 'hidden',
});
return that;
-};
\ No newline at end of file
+};
diff --git a/static/js/folderList.js b/static/js/folderList.js
index 44d5a57..323766e 100644
--- a/static/js/folderList.js
+++ b/static/js/folderList.js
@@ -13,7 +13,7 @@ oml.ui.folderList = function(options) {
src: Ox.UI.getImageURL(
value == 'libraries' ? 'symbolData'
: value == 'library' ? 'symbolUser'
- : data.name == 'Public' ? 'symbolPublish'
+ : data.name == 'Inbox' ? 'symbolPublish'
: value == 'static' ? 'symbolClick'
: 'symbolFind'
)
diff --git a/static/js/folders.js b/static/js/folders.js
index d943e62..f4e84a3 100644
--- a/static/js/folders.js
+++ b/static/js/folders.js
@@ -42,7 +42,7 @@ oml.ui.folders = function() {
}).indexOf(list.user) : null;
return list.id == '' ? oml.$ui.librariesList
: Ox.endsWith(list.id, ':') ? oml.$ui.libraryList[index]
- : Ox.endsWith(list.id, ':Public') ? oml.$ui.publicList[index]
+ : Ox.endsWith(list.id, ':Inbox') ? oml.$ui.inboxList[index]
: oml.$ui.folderList[index];
}
@@ -66,7 +66,7 @@ oml.ui.folders = function() {
!list ? 'libraryList'
: 'folderList'
][index]
- : list == 'Public' ? oml.$ui.publicList[index]
+ : list == 'Inbox' ? oml.$ui.inboxList[index]
: oml.$ui.folderList[index];
$lists.forEach(function($list) {
if ($list == $selectedList) {
@@ -87,7 +87,7 @@ oml.ui.folders = function() {
oml.$ui.folder = [];
oml.$ui.libraryList = [];
oml.$ui.folderList = [];
- oml.$ui.publicList = [];
+ oml.$ui.inboxList = [];
getUsersAndLists(function(users, lists) {
@@ -120,10 +120,11 @@ oml.ui.folders = function() {
var $content,
items = lists.filter(function(list) {
return list.user === user.name
- && list.type != 'library' && list.name != 'Public';
+ && list.type != 'library' && list.name != 'Inbox';
}),
libraryId = user.name + ':',
- publicId = user.name + ':Public';
+ inboxId = user.name + ':Inbox',
+ offset = 16;
userIndex[user.name] = index;
@@ -175,7 +176,8 @@ oml.ui.folders = function() {
$content = oml.$ui.folder[index].$content
.css({
- height: (2 + items.length) * 16 + 'px'
+ // user also has inbox
+ height: ((index ? 1 : 2) + items.length) * 16 + 'px'
});
$lists.push(
@@ -193,7 +195,7 @@ oml.ui.folders = function() {
oml.UI.set({find: getFind(data.ids[0])});
},
selectnext: function() {
- oml.UI.set({find: getFind(publicId)});
+ oml.UI.set({find: getFind(inboxId)});
},
selectprevious: function() {
// FIXME: ugly
@@ -216,27 +218,29 @@ oml.ui.folders = function() {
})
.appendTo($content)
);
-
- $lists.push(
- oml.$ui.publicList[index] = oml.ui.folderList({
- items: lists.filter(function(list) {
- return list.user == user.name && list.name == 'Public';
+ if (user.name == '') {
+ $lists.push(
+ oml.$ui.inboxList[index] = oml.ui.folderList({
+ items: lists.filter(function(list) {
+ return list.user == user.name && list.name == 'Inbox';
+ })
})
- })
- .bindEvent({
- select: function(data) {
- oml.UI.set({find: getFind(data.ids[0])});
- },
- selectnext: function() {
- oml.UI.set({find: getFind(items[0].id)});
- },
- selectprevious: function() {
- oml.UI.set({find: getFind(libraryId)});
- }
- })
- .appendTo($content)
- );
- oml.$ui.publicList[index].$body.css({top: '16px'});
+ .bindEvent({
+ select: function(data) {
+ oml.UI.set({find: getFind(data.ids[0])});
+ },
+ selectnext: function() {
+ oml.UI.set({find: getFind(items[0].id)});
+ },
+ selectprevious: function() {
+ oml.UI.set({find: getFind(libraryId)});
+ }
+ })
+ .appendTo($content)
+ );
+ oml.$ui.inboxList[index].$body.css({top: offset + 'px'});
+ offset += 16;
+ }
$lists.push(
oml.$ui.folderList[index] = oml.ui.folderList({
@@ -258,7 +262,7 @@ oml.ui.folders = function() {
}
},
'delete': function(data) {
- !index && !Ox.contains(data.ids, ':Public') && oml.ui.deleteListDialog().open();
+ !index && !Ox.contains(data.ids, ':Inbox') && oml.ui.deleteListDialog().open();
},
key_control_d: function() {
oml.addList(ui._list);
@@ -275,7 +279,7 @@ oml.ui.folders = function() {
});
},
open: function(data) {
- !index && !Ox.contains(data.ids, ':Public') && oml.ui.listDialog().open();
+ !index && !Ox.contains(data.ids, ':Inbox') && oml.ui.listDialog().open();
},
select: function(data) {
oml.UI.set({find: getFind(data.ids[0])});
@@ -290,14 +294,14 @@ oml.ui.folders = function() {
}
},
selectprevious: function() {
- oml.UI.set({find: getFind(publicId)});
+ oml.UI.set({find: getFind(inboxId)});
}
})
.css({height: items.length * 16 + 'px'})
.appendTo($content)
);
- oml.$ui.folderList[index].$body.css({top: '32px'});
+ oml.$ui.folderList[index].$body.css({top: offset + 'px'});
});
@@ -353,7 +357,7 @@ oml.ui.folders = function() {
oml.$ui.folder[index].options({title: Ox.encodeHTMLEntities(name)});
oml.getLists(function(lists) {
var items = lists.filter(function(list) {
- return list.user == name && list.type != 'library' && list.name != 'Public';
+ return list.user == name && list.type != 'library' && list.name != 'Inbox';
}),
library = lists.filter(function(list) {
return list.user == name && list.type == 'library';
@@ -362,8 +366,9 @@ oml.ui.folders = function() {
oml.$ui.libraryList[index].options({
items: library
});
+ // library + inbox + lists
oml.$ui.folder[index].$content
- .css({height: 16 + items.length * 16 + 'px'});
+ .css({height: (index ? 16 : 32) + items.length * 16 + 'px'});
oml.$ui.folderList[index].options({
items: items
})
diff --git a/static/js/mainMenu.js b/static/js/mainMenu.js
index e8c4c35..501cc03 100644
--- a/static/js/mainMenu.js
+++ b/static/js/mainMenu.js
@@ -601,6 +601,7 @@ oml.ui.mainMenu = function() {
that[data.value ? 'enableItem' : 'disableItem']('book');
that[data.value ? 'disableItem' : 'enableItem']('showfilters');
that[data.value ? 'enableItem' : 'disableItem']('showbrowser');
+ that[data.value ? 'enableItem' : 'disableItem']('showannotations');
}
},
oml_itemview: function(data) {
@@ -955,7 +956,7 @@ oml.ui.mainMenu = function() {
isLibrary = Ox.endsWith(ui._list, ':'),
isList = !isLibraries && !isLibrary,
isOwnList = ui._list[0] == ':',
- isPublic = ui._list == ':Public';
+ isInbox = ui._list == ':Inbox';
if (oml.readOnly) {
return {
@@ -1019,13 +1020,13 @@ oml.ui.mainMenu = function() {
id: 'editlist',
title: Ox._('Edit List...'),
keyboard: 'return',
- disabled: !isList || !isOwnList || isPublic
+ disabled: !isList || !isOwnList || isInbox
},
{
id: 'deletelist',
title: Ox._('Delete List...'),
keyboard: 'delete',
- disabled: !isList || !isOwnList || isPublic
+ disabled: !isList || !isOwnList || isInbox
}
])
};
diff --git a/static/js/utils.js b/static/js/utils.js
index f64412a..bdbdb27 100644
--- a/static/js/utils.js
+++ b/static/js/utils.js
@@ -316,7 +316,7 @@ oml.enableDragAndDrop = function($list, canMove) {
$list.bindEvent({
draganddropstart: function(data) {
- var $lists = oml.$ui.libraryList.concat(oml.$ui.publicList).concat(oml.$ui.folderList);
+ var $lists = oml.$ui.libraryList.concat(oml.$ui.inboxList).concat(oml.$ui.folderList);
drag.action = 'copy';
drag.ids = $list.options('selected');
drag.item = drag.ids.length == 1
@@ -335,9 +335,9 @@ oml.enableDragAndDrop = function($list, canMove) {
&& drag.source.user != ''
&& data.user == ''
) || (
- data.type == 'static'
- && data.name == 'Public'
+ data.type == 'library'
&& drag.source.user == ''
+ && data.user != ''
),
selected: data.id == ui._list
}, data);
@@ -492,8 +492,12 @@ oml.enableDragAndDrop = function($list, canMove) {
text = Ox._('You cannot move books
out of a smart list.');
}
} else if (drag.target) {
+ console.log(drag.target)
targetText = drag.target.type == 'libraries' ? Ox._('a library')
- : drag.target.type == 'library' ? Ox._('your library')
+ : drag.target.type == 'library' ?
+ drag.target.user == ''
+ ? Ox._('your library')
+ : Ox._('{0}\'s library', [Ox.encodeHTMLEntities(Ox.truncate(drag.target.user, 32))])
: Ox._('the list "{0}"', [Ox.encodeHTMLEntities(Ox.truncate(drag.target.name, 32))]);
if (
(
@@ -507,7 +511,7 @@ oml.enableDragAndDrop = function($list, canMove) {
Ox._(itemText[0] == '"' ? '' : 'These ') + itemText,
targetText
]);
- } else if (drag.target.user != '' && drag.target.name != 'Public') {
+ } else if (drag.target.user != '' && drag.target.type != 'library') {
text = Ox._(
'You can only {0} books
to your own {1}.',
[actionText, drag.target.type == 'library' ? 'library' : 'lists']
@@ -992,7 +996,7 @@ oml.resizeListFolders = function() {
oml.$ui.libraryList[index]
.css({width: width + 'px'})
.resizeColumn('name', columnWidth);
- oml.$ui.publicList[index]
+ oml.$ui.inboxList[index] && oml.$ui.inboxList[index]
.css({width: width + 'px'})
.resizeColumn('name', columnWidth);
oml.$ui.folderList[index]
diff --git a/static/js/viewer.js b/static/js/viewer.js
index 8cb4842..848364a 100644
--- a/static/js/viewer.js
+++ b/static/js/viewer.js
@@ -46,6 +46,7 @@ oml.ui.viewer = function() {
function saveAnnotations(data) {
if (data) {
data.created = data.created || (new Date).toISOString();
+ data.comments = data.comments || [];
annotations.push(data);
}
localStorage[item + '.annotations'] = JSON.stringify(annotations)
@@ -57,6 +58,14 @@ oml.ui.viewer = function() {
saveAnnotations()
}
+ var annotationEvents = {
+ change: function() {
+ console.log('change...')
+ console.log(annotations)
+ saveAnnotations()
+ }
+ }
+
that.updateElement = function() {
item = ui.item;
if (item && item.length) {
@@ -75,7 +84,7 @@ oml.ui.viewer = function() {
if (event == 'addAnnotation') {
console.log('adding', data.id)
saveAnnotations(data);
- var $annotation = oml.ui.annotation(data, $iframe)
+ var $annotation = oml.ui.annotation(data, $iframe).bindEvent(annotationEvents)
oml.$ui.annotationFolder.append($annotation);
$annotation.annotate();
} else if (event == 'removeAnnotation') {
@@ -93,7 +102,7 @@ oml.ui.viewer = function() {
init: function() {
loadAnnotations(function(annotations) {
annotations.forEach(function(data) {
- var $annotation = oml.ui.annotation(data, $iframe)
+ var $annotation = oml.ui.annotation(data, $iframe).bindEvent(annotationEvents)
oml.$ui.annotationFolder.append($annotation);
})
// fixme: trigger loaded event from reader instead?
diff --git a/static/reader/pdf.js b/static/reader/pdf.js
index b4bbed3..15b4487 100644
--- a/static/reader/pdf.js
+++ b/static/reader/pdf.js
@@ -11,14 +11,21 @@ Ox.load({
console.log('got', event, 'data', data)
if (event == 'selectAnnotation') {
var annotation = annotations.filter(function(a) { return a.id == data.id })[0]
+ var delay = 0
if (
annotation &&
annotation.page &&
PDFViewerApplication.pdfViewer.currentPageNumber != annotation.page
) {
- //FIXME: scroll into view
PDFViewerApplication.pdfViewer.currentPageNumber = annotation.page;
+ delay = 250
}
+ setTimeout(function() {
+ var el = document.querySelector('.a' + annotation.id);
+ if (el) {
+ document.querySelector('#viewerContainer').scrollTop = el.offsetTop + el.parentElement.offsetTop - 64;
+ }
+ }, delay)
selectAnnotation(data.id)
} else if (event == 'addAnnotations') {
data.annotations.forEach(function(annotation) {
@@ -144,7 +151,7 @@ function removeAnnotation(id) {
annotations = annotations.filter(function(annotation) {
return annotation.id != id
})
- Ox.$parent.postMessage('removeAnnotation', {id: selected.dataset.id})
+ Ox.$parent.postMessage('removeAnnotation', {id: id})
}
function loadAnnotations(page) {