merge
This commit is contained in:
commit
760494dd6d
57 changed files with 224 additions and 155 deletions
12
.editorconfig
Normal file
12
.editorconfig
Normal file
|
@ -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
|
||||||
|
|
12
ctl
12
ctl
|
@ -162,12 +162,14 @@ if [ "$1" == "open" ]; then
|
||||||
xdg-open "file://${BASE}/openmedialibrary/static/html/load.html"
|
xdg-open "file://${BASE}/openmedialibrary/static/html/load.html"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
$PYTHON "${NAME}/oml/gtkstatus.py" $@
|
#$PYTHON "${NAME}/oml/gtkstatus.py" $@
|
||||||
exit $?
|
#exit $?
|
||||||
|
"$0" start &
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
$PYTHON "$NAME/oml/gtkstatus.py" $@
|
#$PYTHON "$NAME/oml/gtkstatus.py" $@
|
||||||
exit $?
|
#exit $?
|
||||||
|
"$0" start &
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
exit 0
|
exit 0
|
||||||
|
@ -187,7 +189,7 @@ fi
|
||||||
|
|
||||||
if [ "$1" == "ui" ]; then
|
if [ "$1" == "ui" ]; then
|
||||||
shift
|
shift
|
||||||
$PYTHON "$NAME/oml/ui.py" $@
|
$PYTHON "$NAME/oml/ui.py" "$@"
|
||||||
exit $?
|
exit $?
|
||||||
fi
|
fi
|
||||||
if [ "$1" == "init" ]; then
|
if [ "$1" == "init" ]; then
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
|
|
||||||
from os.path import normpath, dirname, abspath, join
|
from os.path import normpath, dirname, abspath, join
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
|
|
||||||
from os.path import join, exists, dirname
|
from os.path import join, exists, dirname
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
|
|
|
@ -9,39 +9,48 @@ import webbrowser
|
||||||
import gi
|
import gi
|
||||||
gi.require_version('Gtk', '3.0')
|
gi.require_version('Gtk', '3.0')
|
||||||
from gi.repository import Gtk, GLib
|
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__))))
|
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"
|
title = "Open Media Library"
|
||||||
ctl = base + '/ctl'
|
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
|
menu = None
|
||||||
icon = None
|
icon = None
|
||||||
indicator = None
|
|
||||||
|
|
||||||
def __init__(self, autostart=False):
|
def __init__(self, autostart=False):
|
||||||
self.autostart = autostart
|
self.autostart = autostart
|
||||||
self.create_pid()
|
self.create_pid()
|
||||||
if appindicator:
|
self.win = Gtk.Window()
|
||||||
self.indicator = appindicator.Indicator.new("OML", icon,
|
self.win.set_icon_from_file(icon)
|
||||||
appindicator.IndicatorCategory.APPLICATION_STATUS)
|
self.win.set_title(title)
|
||||||
self.indicator.set_status(appindicator.IndicatorStatus.ACTIVE)
|
#self.win.show_all()
|
||||||
self.menu = self.get_menu()
|
self.win.iconify()
|
||||||
self.indicator.set_menu(self.menu)
|
'''
|
||||||
else:
|
|
||||||
self.icon = Gtk.StatusIcon()
|
self.icon = Gtk.StatusIcon()
|
||||||
self.icon.set_from_file(icon)
|
self.icon.set_from_file(icon)
|
||||||
self.icon.set_title(title)
|
self.icon.set_title(title)
|
||||||
self.icon.connect("activate", self._click)
|
self.icon.connect("activate", self._click)
|
||||||
self.icon.connect("popup-menu", self._click)
|
self.icon.connect("popup-menu", self._click)
|
||||||
|
'''
|
||||||
subprocess.Popen([ctl, 'start'], close_fds=True, preexec_fn=preexec)
|
subprocess.Popen([ctl, 'start'], close_fds=True, preexec_fn=preexec)
|
||||||
if not self.autostart:
|
if not self.autostart:
|
||||||
GLib.timeout_add_seconds(1, self._open, None)
|
GLib.timeout_add_seconds(1, self._open, None)
|
||||||
|
@ -81,7 +90,7 @@ class OMLIcon:
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_running(cls):
|
def is_running(cls):
|
||||||
pid = cls.get_pid()
|
pid = cls.get_pid()
|
||||||
if pid and os.path.exists(pid):
|
if pid and check_pid(pid):
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
@ -140,16 +149,14 @@ class OMLIcon:
|
||||||
url += '#%s' % port
|
url += '#%s' % port
|
||||||
webbrowser.open_new_tab(url)
|
webbrowser.open_new_tab(url)
|
||||||
|
|
||||||
def preexec(): # Don't forward signals.
|
|
||||||
os.setpgrp()
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import signal
|
import signal
|
||||||
autostart = len(sys.argv) > 1 and sys.argv[1] == '--autostart'
|
autostart = len(sys.argv) > 1 and sys.argv[1] == '--autostart'
|
||||||
if OMLIcon.is_running():
|
if OMLStatus.is_running():
|
||||||
OMLIcon.load()
|
OMLStatus.load()
|
||||||
else:
|
else:
|
||||||
oml = OMLIcon(autostart)
|
oml = OMLStatus(autostart)
|
||||||
main_loop = GLib.MainLoop()
|
main_loop = GLib.MainLoop()
|
||||||
try:
|
try:
|
||||||
main_loop.run()
|
main_loop.run()
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
import json
|
import json
|
||||||
import hashlib
|
import hashlib
|
||||||
import os
|
import os
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
@ -7,6 +6,7 @@ import mimetypes
|
||||||
import os
|
import os
|
||||||
from urllib.request import quote
|
from urllib.request import quote
|
||||||
import zipfile
|
import zipfile
|
||||||
|
import base64
|
||||||
|
|
||||||
import ox
|
import ox
|
||||||
|
|
||||||
|
@ -27,7 +27,42 @@ import state
|
||||||
import logging
|
import logging
|
||||||
logger = logging.getLogger(__name__)
|
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):
|
def initialize(self):
|
||||||
pass
|
pass
|
||||||
|
@ -141,7 +176,7 @@ class ReaderHandler(OMLHandler):
|
||||||
path = os.path.join(settings.static_path, html)
|
path = os.path.join(settings.static_path, html)
|
||||||
return serve_static(self, path, 'text/html')
|
return serve_static(self, path, 'text/html')
|
||||||
|
|
||||||
class UploadHandler(tornado.web.RequestHandler):
|
class UploadHandler(OMLHandler):
|
||||||
|
|
||||||
def initialize(self, context=None):
|
def initialize(self, context=None):
|
||||||
self._context = context
|
self._context = context
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
@ -23,17 +22,26 @@ logger = logging.getLogger(__name__)
|
||||||
MAX_WORKERS = 4
|
MAX_WORKERS = 4
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Icons(dict):
|
class Icons(dict):
|
||||||
|
|
||||||
def __init__(self, db):
|
def __init__(self, db):
|
||||||
self._db = db
|
self._db = db
|
||||||
self.create()
|
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):
|
def connect(self):
|
||||||
conn = sqlite3.connect(self._db, timeout=90)
|
conn = sqlite3.connect(self._db, timeout=90)
|
||||||
return conn
|
return conn
|
||||||
|
|
||||||
def create(self):
|
def create(self):
|
||||||
|
folder = os.path.dirname(self._db)
|
||||||
|
if os.path.exists(folder):
|
||||||
conn = self.connect()
|
conn = self.connect()
|
||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
c.execute('CREATE TABLE IF NOT EXISTS icon (id varchar(64) unique, data blob)')
|
c.execute('CREATE TABLE IF NOT EXISTS icon (id varchar(64) unique, data blob)')
|
||||||
|
@ -105,7 +113,7 @@ class Icons(dict):
|
||||||
c.close()
|
c.close()
|
||||||
conn.close()
|
conn.close()
|
||||||
except:
|
except:
|
||||||
logger.debug('failed to clear icon %s', id)
|
logger.debug('failed to clear icon %s', prefix)
|
||||||
|
|
||||||
def vacuum(self, ids):
|
def vacuum(self, ids):
|
||||||
conn = self.connect()
|
conn = self.connect()
|
||||||
|
@ -140,6 +148,8 @@ def get_icons_db_path():
|
||||||
return icons_db_path
|
return icons_db_path
|
||||||
|
|
||||||
def get_icon_sync(id, type_, size):
|
def get_icon_sync(id, type_, size):
|
||||||
|
if not icons.is_available():
|
||||||
|
return ''
|
||||||
if size:
|
if size:
|
||||||
skey = '%s:%s:%s' % (type_, id, size)
|
skey = '%s:%s:%s' % (type_, id, size)
|
||||||
data = icons[skey]
|
data = icons[skey]
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import base64
|
import base64
|
||||||
import hashlib
|
import hashlib
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
|
|
||||||
import unicodedata
|
import unicodedata
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
import unicodedata
|
import unicodedata
|
||||||
|
|
||||||
from oxtornado import actions
|
from oxtornado import actions
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
|
|
||||||
#does not work in sqlite
|
#does not work in sqlite
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
import unicodedata
|
import unicodedata
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
import socket
|
import socket
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
|
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
|
|
||||||
import stdnum.isbn
|
import stdnum.isbn
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
|
|
||||||
import ox.web.duckduckgo
|
import ox.web.duckduckgo
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
from time import time, sleep
|
from time import time, sleep
|
||||||
from urllib.parse import urlencode
|
from urllib.parse import urlencode
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import os
|
import os
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
|
|
||||||
from user.models import User
|
from user.models import User
|
||||||
|
@ -82,9 +81,9 @@ def api_upload(user_id, items):
|
||||||
from user.models import List
|
from user.models import List
|
||||||
peer = User.get(user_id)
|
peer = User.get(user_id)
|
||||||
if peer:
|
if peer:
|
||||||
l = List.get_or_create(':Public')
|
l = List.get_or_create(':Inbox')
|
||||||
if l:
|
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)
|
l.add_items(items)
|
||||||
trigger_event('change', {})
|
trigger_event('change', {})
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
from socketserver import ThreadingMixIn
|
from socketserver import ThreadingMixIn
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
import base64
|
import base64
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
|
|
||||||
from queue import Queue
|
from queue import Queue
|
||||||
|
@ -462,7 +461,7 @@ class Node(Thread):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def upload(self, items):
|
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)
|
r = self.request('upload', items)
|
||||||
return bool(r)
|
return bool(r)
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
|
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import unicodedata
|
import unicodedata
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
import ssl
|
import ssl
|
||||||
import http.client
|
import http.client
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
from queue import PriorityQueue
|
from queue import PriorityQueue
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
import json
|
import json
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
import ssl
|
import ssl
|
||||||
import http.client
|
import http.client
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
try:
|
try:
|
||||||
|
@ -105,6 +104,7 @@ if __name__ == '__main__':
|
||||||
if len(sys.argv) >= 3:
|
if len(sys.argv) >= 3:
|
||||||
base = sys.argv[2]
|
base = sys.argv[2]
|
||||||
base = os.path.expanduser(base)
|
base = os.path.expanduser(base)
|
||||||
|
if os.path.exists(base):
|
||||||
os.chdir(base)
|
os.chdir(base)
|
||||||
if len(sys.argv) >= 2 and sys.argv[1] == 'folder':
|
if len(sys.argv) >= 2 and sys.argv[1] == 'folder':
|
||||||
print(ui.selectFolder({}))
|
print(ui.selectFolder({}))
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
from contextlib import closing
|
from contextlib import closing
|
||||||
import base64
|
import base64
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
|
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
@ -189,7 +188,7 @@ def getLists(data):
|
||||||
'type': 'libraries',
|
'type': 'libraries',
|
||||||
'user': None,
|
'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)):
|
for u in models.User.query.filter((models.User.peered==True)|(models.User.id==settings.USER_ID)):
|
||||||
lists += u.lists_json()
|
lists += u.lists_json()
|
||||||
return {
|
return {
|
||||||
|
@ -290,7 +289,7 @@ def removeList(data):
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
l = models.List.get(data['id'])
|
l = models.List.get(data['id'])
|
||||||
if l and l.name != 'Public':
|
if l and l.name != 'Inbox':
|
||||||
l.remove()
|
l.remove()
|
||||||
return {}
|
return {}
|
||||||
actions.register(removeList, cache=False)
|
actions.register(removeList, cache=False)
|
||||||
|
@ -309,12 +308,10 @@ def addListItems(data):
|
||||||
i = Item.get(item_id)
|
i = Item.get(item_id)
|
||||||
i.queue_download()
|
i.queue_download()
|
||||||
i.update()
|
i.update()
|
||||||
elif data['list'] and (data['list'].startswith(':') or
|
elif data['list'] and (data['list'].startswith(':') or data['list'].endswith(':')):
|
||||||
data['list'].endswith(':Public') or
|
|
||||||
data['list'].enswtih(':')):
|
|
||||||
l = models.List.get_or_create(data['list'])
|
l = models.List.get_or_create(data['list'])
|
||||||
if l:
|
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', {
|
state.tasks.queue('upload', {
|
||||||
'user': l.user_id,
|
'user': l.user_id,
|
||||||
'items': data['items']
|
'items': data['items']
|
||||||
|
@ -351,12 +348,11 @@ def sortLists(data):
|
||||||
'''
|
'''
|
||||||
n = 0
|
n = 0
|
||||||
logger.debug('sortLists %s', data)
|
logger.debug('sortLists %s', data)
|
||||||
lists = ['Public']
|
|
||||||
for id in data['ids']:
|
for id in data['ids']:
|
||||||
l = models.List.get(id)
|
l = models.List.get(id)
|
||||||
l.index_ = n
|
l.index_ = n
|
||||||
n += 1
|
n += 1
|
||||||
if l.type == 'static':
|
if l.type == 'static' and l.name not in ('', 'Inbox'):
|
||||||
lists.append(l.name)
|
lists.append(l.name)
|
||||||
state.db.session.add(l)
|
state.db.session.add(l)
|
||||||
state.db.session.commit()
|
state.db.session.commit()
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
@ -218,7 +217,7 @@ class User(db.Model):
|
||||||
Changelog.record(self, 'edititem', item.id, item.meta, _commit=False)
|
Changelog.record(self, 'edititem', item.id, item.meta, _commit=False)
|
||||||
lists = []
|
lists = []
|
||||||
for l in List.query.filter_by(user_id=self.id, type='static').order_by('index_'):
|
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)
|
lists.append(l.name)
|
||||||
Changelog.record(self, 'addlist', l.name, _commit=False)
|
Changelog.record(self, 'addlist', l.name, _commit=False)
|
||||||
items = [i.id for i in l.get_items().options(load_only('id'))]
|
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.add(l)
|
||||||
state.db.session.commit()
|
state.db.session.commit()
|
||||||
if user_id == settings.USER_ID:
|
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)
|
add_record('addlist', l.name)
|
||||||
return l
|
return l
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# vi:si:et:sw=4:sts=4:ts=4
|
|
||||||
|
|
||||||
|
|
||||||
from tornado.websocket import WebSocketHandler
|
from tornado.websocket import WebSocketHandler
|
||||||
|
|
|
@ -1,34 +1,56 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
oml.ui.annotation = function(data, $iframe) {
|
oml.ui.annotation = function(annotation, $iframe) {
|
||||||
var $quote = Ox.Element().addClass('OxSelectable OMLQuote').css({
|
var $quote = Ox.Element().addClass('OxSelectable OMLQuote').css({
|
||||||
|
backgroundColor: 'white',
|
||||||
color: 'black',
|
color: 'black',
|
||||||
fontFamily: 'Georgia, Palatino, DejaVu Serif, Book Antiqua, Palatino Linotype, Times New Roman, serif',
|
fontFamily: 'Georgia, Palatino, DejaVu Serif, Book Antiqua, Palatino Linotype, Times New Roman, serif',
|
||||||
fontSize: '14px',
|
fontSize: '14px',
|
||||||
lineHeight: '21px',
|
lineHeight: '21px',
|
||||||
padding: '8px'
|
padding: '8px'
|
||||||
}).html(Ox.encodeHTMLEntities(data.text).replace(/\n/g, '<br/>')).on({
|
}).html(Ox.encodeHTMLEntities(annotation.text).replace(/\n/g, '<br/>')).on({
|
||||||
click: function(event) {
|
click: function(event) {
|
||||||
that.select()
|
that.select()
|
||||||
$iframe.postMessage('selectAnnotation', {
|
$iframe.postMessage('selectAnnotation', {
|
||||||
id: data.id
|
id: annotation.id
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
var $note = Ox.Editable({
|
var $note = Ox.ArrayEditable({
|
||||||
editing: true,
|
editing: true,
|
||||||
|
items: (annotation.comments || []).map(function(comment) {
|
||||||
|
comment.editable = true
|
||||||
|
return comment
|
||||||
|
}),
|
||||||
type: 'textarea'
|
type: 'textarea'
|
||||||
}).css({
|
}).css({
|
||||||
margin: '2px',
|
margin: '2px',
|
||||||
minHeight: '12px'
|
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({
|
var that = Ox.Element().attr({
|
||||||
id: 'a-' + data.id
|
id: 'a-' + annotation.id
|
||||||
}).addClass(
|
}).addClass(
|
||||||
'OxSelectable OMLAnnotation'
|
'OxSelectable OMLAnnotation'
|
||||||
).css({
|
).css({
|
||||||
borderBottom: '1px solid rgb(208, 208, 208)',
|
borderBottom: '1px solid rgb(208, 208, 208)',
|
||||||
}).append($quote).append($note);
|
}).append($quote).append($note);
|
||||||
|
|
||||||
that.annotate = function() {
|
that.annotate = function() {
|
||||||
var item = {
|
var item = {
|
||||||
id: 'note', value: '', editable: true
|
id: 'note', value: '', editable: true
|
||||||
|
|
|
@ -3,6 +3,7 @@ oml.ui.annotationFolder = function() {
|
||||||
var ui = oml.user.ui,
|
var ui = oml.user.ui,
|
||||||
that = Ox.Element().css({
|
that = Ox.Element().css({
|
||||||
overflowY: 'auto',
|
overflowY: 'auto',
|
||||||
|
overflowX: 'hidden',
|
||||||
});
|
});
|
||||||
|
|
||||||
return that;
|
return that;
|
||||||
|
|
|
@ -13,7 +13,7 @@ oml.ui.folderList = function(options) {
|
||||||
src: Ox.UI.getImageURL(
|
src: Ox.UI.getImageURL(
|
||||||
value == 'libraries' ? 'symbolData'
|
value == 'libraries' ? 'symbolData'
|
||||||
: value == 'library' ? 'symbolUser'
|
: value == 'library' ? 'symbolUser'
|
||||||
: data.name == 'Public' ? 'symbolPublish'
|
: data.name == 'Inbox' ? 'symbolPublish'
|
||||||
: value == 'static' ? 'symbolClick'
|
: value == 'static' ? 'symbolClick'
|
||||||
: 'symbolFind'
|
: 'symbolFind'
|
||||||
)
|
)
|
||||||
|
|
|
@ -42,7 +42,7 @@ oml.ui.folders = function() {
|
||||||
}).indexOf(list.user) : null;
|
}).indexOf(list.user) : null;
|
||||||
return list.id == '' ? oml.$ui.librariesList
|
return list.id == '' ? oml.$ui.librariesList
|
||||||
: Ox.endsWith(list.id, ':') ? oml.$ui.libraryList[index]
|
: 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];
|
: oml.$ui.folderList[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ oml.ui.folders = function() {
|
||||||
!list ? 'libraryList'
|
!list ? 'libraryList'
|
||||||
: 'folderList'
|
: 'folderList'
|
||||||
][index]
|
][index]
|
||||||
: list == 'Public' ? oml.$ui.publicList[index]
|
: list == 'Inbox' ? oml.$ui.inboxList[index]
|
||||||
: oml.$ui.folderList[index];
|
: oml.$ui.folderList[index];
|
||||||
$lists.forEach(function($list) {
|
$lists.forEach(function($list) {
|
||||||
if ($list == $selectedList) {
|
if ($list == $selectedList) {
|
||||||
|
@ -87,7 +87,7 @@ oml.ui.folders = function() {
|
||||||
oml.$ui.folder = [];
|
oml.$ui.folder = [];
|
||||||
oml.$ui.libraryList = [];
|
oml.$ui.libraryList = [];
|
||||||
oml.$ui.folderList = [];
|
oml.$ui.folderList = [];
|
||||||
oml.$ui.publicList = [];
|
oml.$ui.inboxList = [];
|
||||||
|
|
||||||
getUsersAndLists(function(users, lists) {
|
getUsersAndLists(function(users, lists) {
|
||||||
|
|
||||||
|
@ -120,10 +120,11 @@ oml.ui.folders = function() {
|
||||||
var $content,
|
var $content,
|
||||||
items = lists.filter(function(list) {
|
items = lists.filter(function(list) {
|
||||||
return list.user === user.name
|
return list.user === user.name
|
||||||
&& list.type != 'library' && list.name != 'Public';
|
&& list.type != 'library' && list.name != 'Inbox';
|
||||||
}),
|
}),
|
||||||
libraryId = user.name + ':',
|
libraryId = user.name + ':',
|
||||||
publicId = user.name + ':Public';
|
inboxId = user.name + ':Inbox',
|
||||||
|
offset = 16;
|
||||||
|
|
||||||
userIndex[user.name] = index;
|
userIndex[user.name] = index;
|
||||||
|
|
||||||
|
@ -175,7 +176,8 @@ oml.ui.folders = function() {
|
||||||
|
|
||||||
$content = oml.$ui.folder[index].$content
|
$content = oml.$ui.folder[index].$content
|
||||||
.css({
|
.css({
|
||||||
height: (2 + items.length) * 16 + 'px'
|
// user also has inbox
|
||||||
|
height: ((index ? 1 : 2) + items.length) * 16 + 'px'
|
||||||
});
|
});
|
||||||
|
|
||||||
$lists.push(
|
$lists.push(
|
||||||
|
@ -193,7 +195,7 @@ oml.ui.folders = function() {
|
||||||
oml.UI.set({find: getFind(data.ids[0])});
|
oml.UI.set({find: getFind(data.ids[0])});
|
||||||
},
|
},
|
||||||
selectnext: function() {
|
selectnext: function() {
|
||||||
oml.UI.set({find: getFind(publicId)});
|
oml.UI.set({find: getFind(inboxId)});
|
||||||
},
|
},
|
||||||
selectprevious: function() {
|
selectprevious: function() {
|
||||||
// FIXME: ugly
|
// FIXME: ugly
|
||||||
|
@ -216,11 +218,11 @@ oml.ui.folders = function() {
|
||||||
})
|
})
|
||||||
.appendTo($content)
|
.appendTo($content)
|
||||||
);
|
);
|
||||||
|
if (user.name == '') {
|
||||||
$lists.push(
|
$lists.push(
|
||||||
oml.$ui.publicList[index] = oml.ui.folderList({
|
oml.$ui.inboxList[index] = oml.ui.folderList({
|
||||||
items: lists.filter(function(list) {
|
items: lists.filter(function(list) {
|
||||||
return list.user == user.name && list.name == 'Public';
|
return list.user == user.name && list.name == 'Inbox';
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.bindEvent({
|
.bindEvent({
|
||||||
|
@ -236,7 +238,9 @@ oml.ui.folders = function() {
|
||||||
})
|
})
|
||||||
.appendTo($content)
|
.appendTo($content)
|
||||||
);
|
);
|
||||||
oml.$ui.publicList[index].$body.css({top: '16px'});
|
oml.$ui.inboxList[index].$body.css({top: offset + 'px'});
|
||||||
|
offset += 16;
|
||||||
|
}
|
||||||
|
|
||||||
$lists.push(
|
$lists.push(
|
||||||
oml.$ui.folderList[index] = oml.ui.folderList({
|
oml.$ui.folderList[index] = oml.ui.folderList({
|
||||||
|
@ -258,7 +262,7 @@ oml.ui.folders = function() {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'delete': function(data) {
|
'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() {
|
key_control_d: function() {
|
||||||
oml.addList(ui._list);
|
oml.addList(ui._list);
|
||||||
|
@ -275,7 +279,7 @@ oml.ui.folders = function() {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
open: function(data) {
|
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) {
|
select: function(data) {
|
||||||
oml.UI.set({find: getFind(data.ids[0])});
|
oml.UI.set({find: getFind(data.ids[0])});
|
||||||
|
@ -290,14 +294,14 @@ oml.ui.folders = function() {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
selectprevious: function() {
|
selectprevious: function() {
|
||||||
oml.UI.set({find: getFind(publicId)});
|
oml.UI.set({find: getFind(inboxId)});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.css({height: items.length * 16 + 'px'})
|
.css({height: items.length * 16 + 'px'})
|
||||||
.appendTo($content)
|
.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.$ui.folder[index].options({title: Ox.encodeHTMLEntities(name)});
|
||||||
oml.getLists(function(lists) {
|
oml.getLists(function(lists) {
|
||||||
var items = lists.filter(function(list) {
|
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) {
|
library = lists.filter(function(list) {
|
||||||
return list.user == name && list.type == 'library';
|
return list.user == name && list.type == 'library';
|
||||||
|
@ -362,8 +366,9 @@ oml.ui.folders = function() {
|
||||||
oml.$ui.libraryList[index].options({
|
oml.$ui.libraryList[index].options({
|
||||||
items: library
|
items: library
|
||||||
});
|
});
|
||||||
|
// library + inbox + lists
|
||||||
oml.$ui.folder[index].$content
|
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({
|
oml.$ui.folderList[index].options({
|
||||||
items: items
|
items: items
|
||||||
})
|
})
|
||||||
|
|
|
@ -601,6 +601,7 @@ oml.ui.mainMenu = function() {
|
||||||
that[data.value ? 'enableItem' : 'disableItem']('book');
|
that[data.value ? 'enableItem' : 'disableItem']('book');
|
||||||
that[data.value ? 'disableItem' : 'enableItem']('showfilters');
|
that[data.value ? 'disableItem' : 'enableItem']('showfilters');
|
||||||
that[data.value ? 'enableItem' : 'disableItem']('showbrowser');
|
that[data.value ? 'enableItem' : 'disableItem']('showbrowser');
|
||||||
|
that[data.value ? 'enableItem' : 'disableItem']('showannotations');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
oml_itemview: function(data) {
|
oml_itemview: function(data) {
|
||||||
|
@ -955,7 +956,7 @@ oml.ui.mainMenu = function() {
|
||||||
isLibrary = Ox.endsWith(ui._list, ':'),
|
isLibrary = Ox.endsWith(ui._list, ':'),
|
||||||
isList = !isLibraries && !isLibrary,
|
isList = !isLibraries && !isLibrary,
|
||||||
isOwnList = ui._list[0] == ':',
|
isOwnList = ui._list[0] == ':',
|
||||||
isPublic = ui._list == ':Public';
|
isInbox = ui._list == ':Inbox';
|
||||||
|
|
||||||
if (oml.readOnly) {
|
if (oml.readOnly) {
|
||||||
return {
|
return {
|
||||||
|
@ -1019,13 +1020,13 @@ oml.ui.mainMenu = function() {
|
||||||
id: 'editlist',
|
id: 'editlist',
|
||||||
title: Ox._('Edit List...'),
|
title: Ox._('Edit List...'),
|
||||||
keyboard: 'return',
|
keyboard: 'return',
|
||||||
disabled: !isList || !isOwnList || isPublic
|
disabled: !isList || !isOwnList || isInbox
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'deletelist',
|
id: 'deletelist',
|
||||||
title: Ox._('Delete List...'),
|
title: Ox._('Delete List...'),
|
||||||
keyboard: 'delete',
|
keyboard: 'delete',
|
||||||
disabled: !isList || !isOwnList || isPublic
|
disabled: !isList || !isOwnList || isInbox
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
};
|
};
|
||||||
|
|
|
@ -316,7 +316,7 @@ oml.enableDragAndDrop = function($list, canMove) {
|
||||||
|
|
||||||
$list.bindEvent({
|
$list.bindEvent({
|
||||||
draganddropstart: function(data) {
|
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.action = 'copy';
|
||||||
drag.ids = $list.options('selected');
|
drag.ids = $list.options('selected');
|
||||||
drag.item = drag.ids.length == 1
|
drag.item = drag.ids.length == 1
|
||||||
|
@ -335,9 +335,9 @@ oml.enableDragAndDrop = function($list, canMove) {
|
||||||
&& drag.source.user != ''
|
&& drag.source.user != ''
|
||||||
&& data.user == ''
|
&& data.user == ''
|
||||||
) || (
|
) || (
|
||||||
data.type == 'static'
|
data.type == 'library'
|
||||||
&& data.name == 'Public'
|
|
||||||
&& drag.source.user == ''
|
&& drag.source.user == ''
|
||||||
|
&& data.user != ''
|
||||||
),
|
),
|
||||||
selected: data.id == ui._list
|
selected: data.id == ui._list
|
||||||
}, data);
|
}, data);
|
||||||
|
@ -492,8 +492,12 @@ oml.enableDragAndDrop = function($list, canMove) {
|
||||||
text = Ox._('You cannot move books<br>out of a smart list.');
|
text = Ox._('You cannot move books<br>out of a smart list.');
|
||||||
}
|
}
|
||||||
} else if (drag.target) {
|
} else if (drag.target) {
|
||||||
|
console.log(drag.target)
|
||||||
targetText = drag.target.type == 'libraries' ? Ox._('a library')
|
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))]);
|
: Ox._('the list "{0}"', [Ox.encodeHTMLEntities(Ox.truncate(drag.target.name, 32))]);
|
||||||
if (
|
if (
|
||||||
(
|
(
|
||||||
|
@ -507,7 +511,7 @@ oml.enableDragAndDrop = function($list, canMove) {
|
||||||
Ox._(itemText[0] == '"' ? '' : 'These ') + itemText,
|
Ox._(itemText[0] == '"' ? '' : 'These ') + itemText,
|
||||||
targetText
|
targetText
|
||||||
]);
|
]);
|
||||||
} else if (drag.target.user != '' && drag.target.name != 'Public') {
|
} else if (drag.target.user != '' && drag.target.type != 'library') {
|
||||||
text = Ox._(
|
text = Ox._(
|
||||||
'You can only {0} books<br>to your own {1}.',
|
'You can only {0} books<br>to your own {1}.',
|
||||||
[actionText, drag.target.type == 'library' ? 'library' : 'lists']
|
[actionText, drag.target.type == 'library' ? 'library' : 'lists']
|
||||||
|
@ -992,7 +996,7 @@ oml.resizeListFolders = function() {
|
||||||
oml.$ui.libraryList[index]
|
oml.$ui.libraryList[index]
|
||||||
.css({width: width + 'px'})
|
.css({width: width + 'px'})
|
||||||
.resizeColumn('name', columnWidth);
|
.resizeColumn('name', columnWidth);
|
||||||
oml.$ui.publicList[index]
|
oml.$ui.inboxList[index] && oml.$ui.inboxList[index]
|
||||||
.css({width: width + 'px'})
|
.css({width: width + 'px'})
|
||||||
.resizeColumn('name', columnWidth);
|
.resizeColumn('name', columnWidth);
|
||||||
oml.$ui.folderList[index]
|
oml.$ui.folderList[index]
|
||||||
|
|
|
@ -46,6 +46,7 @@ oml.ui.viewer = function() {
|
||||||
function saveAnnotations(data) {
|
function saveAnnotations(data) {
|
||||||
if (data) {
|
if (data) {
|
||||||
data.created = data.created || (new Date).toISOString();
|
data.created = data.created || (new Date).toISOString();
|
||||||
|
data.comments = data.comments || [];
|
||||||
annotations.push(data);
|
annotations.push(data);
|
||||||
}
|
}
|
||||||
localStorage[item + '.annotations'] = JSON.stringify(annotations)
|
localStorage[item + '.annotations'] = JSON.stringify(annotations)
|
||||||
|
@ -57,6 +58,14 @@ oml.ui.viewer = function() {
|
||||||
saveAnnotations()
|
saveAnnotations()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var annotationEvents = {
|
||||||
|
change: function() {
|
||||||
|
console.log('change...')
|
||||||
|
console.log(annotations)
|
||||||
|
saveAnnotations()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
that.updateElement = function() {
|
that.updateElement = function() {
|
||||||
item = ui.item;
|
item = ui.item;
|
||||||
if (item && item.length) {
|
if (item && item.length) {
|
||||||
|
@ -75,7 +84,7 @@ oml.ui.viewer = function() {
|
||||||
if (event == 'addAnnotation') {
|
if (event == 'addAnnotation') {
|
||||||
console.log('adding', data.id)
|
console.log('adding', data.id)
|
||||||
saveAnnotations(data);
|
saveAnnotations(data);
|
||||||
var $annotation = oml.ui.annotation(data, $iframe)
|
var $annotation = oml.ui.annotation(data, $iframe).bindEvent(annotationEvents)
|
||||||
oml.$ui.annotationFolder.append($annotation);
|
oml.$ui.annotationFolder.append($annotation);
|
||||||
$annotation.annotate();
|
$annotation.annotate();
|
||||||
} else if (event == 'removeAnnotation') {
|
} else if (event == 'removeAnnotation') {
|
||||||
|
@ -93,7 +102,7 @@ oml.ui.viewer = function() {
|
||||||
init: function() {
|
init: function() {
|
||||||
loadAnnotations(function(annotations) {
|
loadAnnotations(function(annotations) {
|
||||||
annotations.forEach(function(data) {
|
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);
|
oml.$ui.annotationFolder.append($annotation);
|
||||||
})
|
})
|
||||||
// fixme: trigger loaded event from reader instead?
|
// fixme: trigger loaded event from reader instead?
|
||||||
|
|
|
@ -11,14 +11,21 @@ Ox.load({
|
||||||
console.log('got', event, 'data', data)
|
console.log('got', event, 'data', data)
|
||||||
if (event == 'selectAnnotation') {
|
if (event == 'selectAnnotation') {
|
||||||
var annotation = annotations.filter(function(a) { return a.id == data.id })[0]
|
var annotation = annotations.filter(function(a) { return a.id == data.id })[0]
|
||||||
|
var delay = 0
|
||||||
if (
|
if (
|
||||||
annotation &&
|
annotation &&
|
||||||
annotation.page &&
|
annotation.page &&
|
||||||
PDFViewerApplication.pdfViewer.currentPageNumber != annotation.page
|
PDFViewerApplication.pdfViewer.currentPageNumber != annotation.page
|
||||||
) {
|
) {
|
||||||
//FIXME: scroll into view
|
|
||||||
PDFViewerApplication.pdfViewer.currentPageNumber = annotation.page;
|
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)
|
selectAnnotation(data.id)
|
||||||
} else if (event == 'addAnnotations') {
|
} else if (event == 'addAnnotations') {
|
||||||
data.annotations.forEach(function(annotation) {
|
data.annotations.forEach(function(annotation) {
|
||||||
|
@ -144,7 +151,7 @@ function removeAnnotation(id) {
|
||||||
annotations = annotations.filter(function(annotation) {
|
annotations = annotations.filter(function(annotation) {
|
||||||
return annotation.id != id
|
return annotation.id != id
|
||||||
})
|
})
|
||||||
Ox.$parent.postMessage('removeAnnotation', {id: selected.dataset.id})
|
Ox.$parent.postMessage('removeAnnotation', {id: id})
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadAnnotations(page) {
|
function loadAnnotations(page) {
|
||||||
|
|
Loading…
Reference in a new issue