Compare commits

..

No commits in common. "e0cba14d6af59433ff61951e7e76ef00ad624595" and "ef2b56e0a96acd23356d6ab5ff040059cf3f72e3" have entirely different histories.

24 changed files with 81 additions and 553 deletions

View file

@ -241,18 +241,6 @@
"format": {"type": "boolean", "args": []}, "format": {"type": "boolean", "args": []},
"sort": true "sort": true
}, },
{
"id": "quotes",
"title": "Quotes",
"find": true,
"type": "text"
},
{
"id": "notes",
"title": "Notes",
"find": true,
"type": "text"
},
{ {
"id": "fulltext", "id": "fulltext",
"title": "Full Text", "title": "Full Text",
@ -380,7 +368,6 @@
"showFilters": true, "showFilters": true,
"showIconInfo": true, "showIconInfo": true,
"showInfo": true, "showInfo": true,
"showPeers": true,
"showSection": { "showSection": {
"notifications": { "notifications": {
"received": true, "received": true,

4
ctl
View file

@ -180,10 +180,14 @@ if [ "$1" == "open" ]; then
if ps -p `cat "$PID"` > /dev/null; then if ps -p `cat "$PID"` > /dev/null; then
open_linux open_linux
else else
#$PYTHON "${NAME}/oml/gtkstatus.py" $@
#exit $?
open_linux open_linux
"$0" start & "$0" start &
fi fi
else else
#$PYTHON "$NAME/oml/gtkstatus.py" $@
#exit $?
open_linux open_linux
"$0" start & "$0" start &
fi fi

View file

@ -1,48 +0,0 @@
# -*- coding: utf-8 -*-
from oxtornado import actions
from . import models
import settings
import state
from changelog import add_record
import logging
logger = logging.getLogger(__name__)
def getAnnotations(data):
response = {}
response['annotations'] = models.Annotation.get_by_item(data['id'])
return response
actions.register(getAnnotations)
def addAnnotation(data):
item_id = data.pop('item')
a = models.Annotation.create(item_id, settings.USER_ID, data)
a.add_record('addannotation')
response = a.json()
return response
actions.register(addAnnotation)
def editNote(data):
a = models.Annotation.get(state.user(), data['item'], data['annotation'])
if a:
a.data['notes'] = data['notes']
a.add_record('editannotation')
a.save()
response = a.json()
else:
response = {}
return response
actions.register(editNote)
def removeAnnotation(data):
a = models.Annotation.get(state.user(), data['item'], data['annotation'])
if a:
a.add_record('removeannotation')
a.delete()
response = {}
return response
actions.register(removeAnnotation)

View file

@ -1,124 +0,0 @@
# -*- coding: utf-8 -*-
from datetime import datetime
import json
import logging
import os
import shutil
import unicodedata
from sqlalchemy.orm import load_only
import ox
import sqlalchemy as sa
from changelog import add_record
from db import MutableDict
import db
import json_pickler
import settings
import state
import utils
import media
from websocket import trigger_event
logger = logging.getLogger(__name__)
class Annotation(db.Model):
__tablename__ = 'annotation'
_id = sa.Column(sa.Integer(), primary_key=True)
id = sa.Column(sa.String(43))
created = sa.Column(sa.DateTime())
modified = sa.Column(sa.DateTime())
user_id = sa.Column(sa.String(43), sa.ForeignKey('user.id'))
user = sa.orm.relationship('User', backref=sa.orm.backref('annotations', lazy='dynamic'))
item_id = sa.Column(sa.String(43), sa.ForeignKey('item.id'))
item = sa.orm.relationship('Item', backref=sa.orm.backref('items', lazy='dynamic'))
data = sa.Column(MutableDict.as_mutable(sa.PickleType(pickler=json_pickler)))
findquotes = sa.Column(sa.Text(), index=True)
findnotes = sa.Column(sa.Text(), index=True)
def __init__(self, item_id, user_id, data):
self.created = datetime.utcnow()
self.modified = datetime.utcnow()
self.item_id = item_id
self.user_id = user_id
self.data = data
@classmethod
def create(cls, item_id, user_id, data):
a = cls(item_id, user_id, data)
a.save()
return a
def delete(self):
state.db.session.delete(self)
state.db.session.commit()
@classmethod
def get(cls, user, item_id, annotation_id):
if isinstance(user, str):
qs = cls.query.filter_by(item_id=item_id, user_id=user, id=annotation_id)
else:
qs = cls.query.filter_by(item_id=item_id, user=user, id=annotation_id)
for a in qs:
return a
@classmethod
def get_by_item(cls, item_id):
annotations = []
for a in cls.query.filter_by(item_id=item_id):
annotations.append(a.json())
return annotations
def save(self):
id = self.data.get('id')
if id:
self.id = id
self.findquotes = unicodedata.normalize('NFKD', self.data.get('text', '')).lower()
note = self.data.get('notes', {})
if isinstance(note, list) and note:
note = note[0]
if isinstance(note, dict):
note = note.get('value', '')
else:
note = ''
self.findnotes = unicodedata.normalize('NFKD', note).lower()
state.db.session.add(self)
state.db.session.commit()
def json(self):
data = self.data.copy()
data['created'] = self.created
data['modified'] = self.modified
data['user'] = self.user_id
data['_id'] = ox.toAZ(self._id)
if isinstance(data.get('notes'), dict):
note = data['notes']
if self.user_id != settings.USER_ID:
note['user'] = self.user_id
if not note.get('id'):
note['id'] = 'A'
data['notes'] = [data['notes']]
if 'notes' not in data:
data['notes'] = []
return data
def add_record(self, action):
args = [self.item_id]
if action == 'addannotation':
args.append(self.data)
elif action == 'editannotation':
args.append(self.id)
args.append({
'notes': self.data['notes']
})
elif action == 'removeannotation':
args.append(self.id)
else:
raise Exception('unknown action')
add_record(action, *args)

View file

@ -12,7 +12,6 @@ from oxtornado import actions
import item.api import item.api
import user.api import user.api
import annotation.api
import update import update
import utils import utils

View file

@ -1,8 +1,8 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import os
from datetime import datetime from datetime import datetime
import json import json
import os
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy.sql.expression import text from sqlalchemy.sql.expression import text
@ -76,10 +76,6 @@ class Changelog(db.Model):
addpeer peerid peername addpeer peerid peername
removepeer peerid peername removepeer peerid peername
editpeer peerid {username: string, contact: string} editpeer peerid {username: string, contact: string}
addannotation itemid data
editannotation itemid annotationid data
removeannotation itemid annotationid
''' '''
__tablename__ = 'changelog' __tablename__ = 'changelog'
id = sa.Column(sa.Integer(), primary_key=True) id = sa.Column(sa.Integer(), primary_key=True)
@ -331,27 +327,6 @@ class Changelog(db.Model):
peer.save() peer.save()
return True return True
def action_addannotation(self, user, timestamp, itemid, data):
from annotation.models import Annotation
Annotation.create(item_id=itemid, user_id=user.id, data=data)
return True
def action_editannotation(self, user, timestamp, itemid, annotationid, data):
from annotation.models import Annotation
a = Annotation.get(user, itemid, annotationid)
if a:
for key in data:
a.data[key] = data[key]
a.save()
return True
def action_removeannotation(self, user, timestamp, itemid, annotationid):
from annotation.models import Annotation
a = Annotation.get(user, itemid, annotationid)
if a:
a.delete()
return True
@classmethod @classmethod
def aggregated_changes(cls, since=None, user_id=None): def aggregated_changes(cls, since=None, user_id=None):
from item.models import Item from item.models import Item

View file

@ -190,33 +190,6 @@ class Peer(object):
self.info['username'] = args[0] self.info['username'] = args[0]
elif action == 'editcontact': elif action == 'editcontact':
self.info['contact'] = args[0] self.info['contact'] = args[0]
elif action == 'addannotation':
from annotation.models import Annotation
if len(args) == 2:
itemid, data = args
Annotation.create(item_id=itemid, user_id=self.id, data=data)
else:
logger.error('invalid entry %s %s', action, args)
elif action == 'editannotation':
from annotation.models import Annotation
if len(args) == 3:
itemid, annotationid, data = args
a = Annotation.get(self.id, itemid, annotationid)
if a:
for key in data:
a.data[key] = data[key]
a.save()
else:
logger.error('invalid entry %s %s', action, args)
elif action == 'removeannotation':
from annotation.models import Annotation
if len(args) == 2:
itemid, annotationid = args
a = Annotation.get(self.id, itemid, annotationid)
if a:
a.delete()
else:
logger.error('invalid entry %s %s', action, args)
else: else:
logger.debug('UNKNOWN ACTION:', action) logger.debug('UNKNOWN ACTION:', action)
self.info['revision'] = revision self.info['revision'] = revision

View file

@ -152,8 +152,8 @@ class LocalNodes(dict):
if state.tasks: if state.tasks:
state.tasks.queue('removelocalinfo', id) state.tasks.queue('removelocalinfo', id)
def get_data(self, user_id): def get(self, user_id):
data = self.get(user_id) data = super().get(user_id)
if data and can_connect(data): if data and can_connect(data):
return data return data
return None return None

View file

@ -124,12 +124,9 @@ class Node(Thread):
self.local = None self.local = None
self.port = 9851 self.port = 9851
def is_local(self):
return self._nodes and self.user_id in self._nodes.local
def get_local(self): def get_local(self):
if self._nodes and self._nodes.local: if self._nodes and self._nodes.local:
return self._nodes.local.get_data(self.user_id) return self._nodes.local.get(self.user_id)
return None return None
def request(self, action, *args): def request(self, action, *args):
@ -219,7 +216,7 @@ class Node(Thread):
return False return False
def is_online(self): def is_online(self):
return self.online or self.is_local() return self.online or self.get_local() is not None
def send_response(self): def send_response(self):
self._q.put('send_response') self._q.put('send_response')
@ -526,8 +523,7 @@ class Nodes(Thread):
while not state.shutdown: while not state.shutdown:
args = self._q.get() args = self._q.get()
if args: if args:
if DEBUG_NODES: logger.debug('processing nodes queue: next: "%s", %s entries in queue', args[0], self._q.qsize())
logger.debug('processing nodes queue: next: "%s", %s entries in queue', args[0], self._q.qsize())
if args[0] == 'add': if args[0] == 'add':
self._add(*args[1:]) self._add(*args[1:])
elif args[0] == 'pull': elif args[0] == 'pull':
@ -536,7 +532,7 @@ class Nodes(Thread):
self._call(*args) self._call(*args)
def queue(self, *args): def queue(self, *args):
if args and DEBUG_NODES: if args:
logger.debug('queue "%s", %s entries in queue', args, self._q.qsize()) logger.debug('queue "%s", %s entries in queue', args, self._q.qsize())
self._q.put(list(args)) self._q.put(list(args))

View file

@ -116,18 +116,7 @@ class Parser(object):
elif k == 'fulltext': elif k == 'fulltext':
ids = find_fulltext(v) ids = find_fulltext(v)
return self.in_ids(ids, exclude) return self.in_ids(ids, exclude)
elif k in ('notes', 'quotes'):
from annotation.models import Annotation
if isinstance(v, str):
v = unicodedata.normalize('NFKD', v).lower()
ids = set()
if k == 'notes':
qs = Annotation.query.filter(get_operator('=')(Annotation.findnotes, v))
elif k == 'quotes':
qs = Annotation.query.filter(get_operator('=')(Annotation.findquotes, v))
for a in qs:
ids.add(a.item_id)
return self.in_ids(ids, exclude)
elif key_type in ("string", "text"): elif key_type in ("string", "text"):
if isinstance(v, str): if isinstance(v, str):
v = unicodedata.normalize('NFKD', v).lower() v = unicodedata.normalize('NFKD', v).lower()

View file

@ -170,8 +170,8 @@ def run():
import bandwidth import bandwidth
state.bandwidth = bandwidth.Bandwidth() state.bandwidth = bandwidth.Bandwidth()
state.tor = tor.Tor() state.tor = tor.Tor()
state.nodes = nodes.Nodes()
state.node = node.server.start() state.node = node.server.start()
state.nodes = nodes.Nodes()
def publish(): def publish():
if not state.tor.is_online(): if not state.tor.is_online():

View file

@ -82,7 +82,7 @@ if 'modules' in release and 'openmedialibrary' in release['modules']:
else: else:
MINOR_VERSION = 'git' MINOR_VERSION = 'git'
NODE_PROTOCOL = "0.9" NODE_PROTOCOL = "0.8"
VERSION = "%s.%s" % (NODE_PROTOCOL, MINOR_VERSION) VERSION = "%s.%s" % (NODE_PROTOCOL, MINOR_VERSION)
USER_AGENT = 'OpenMediaLibrary/%s' % VERSION USER_AGENT = 'OpenMediaLibrary/%s' % VERSION
@ -95,4 +95,4 @@ FULLTEXT_SUPPORT = fulltext.platform_supported()
if not FULLTEXT_SUPPORT: if not FULLTEXT_SUPPORT:
config['itemKeys'] = [k for k in config['itemKeys'] if k['id'] != 'fulltext'] config['itemKeys'] = [k for k in config['itemKeys'] if k['id'] != 'fulltext']
DB_VERSION = 18 DB_VERSION = 17

View file

@ -151,22 +151,6 @@ CREATE TABLE listitem (
FOREIGN KEY(item_id) REFERENCES item (id), FOREIGN KEY(item_id) REFERENCES item (id),
FOREIGN KEY(list_id) REFERENCES list (id) FOREIGN KEY(list_id) REFERENCES list (id)
); );
CREATE TABLE annotation (
_id INTEGER NOT NULL,
id VARCHAR(43),
created DATETIME,
modified DATETIME,
user_id VARCHAR(43),
item_id VARCHAR(43),
data BLOB,
findquotes TEXT,
findnotes TEXT,
PRIMARY KEY (_id),
FOREIGN KEY(user_id) REFERENCES user (id),
FOREIGN KEY(item_id) REFERENCES item (id)
);
CREATE INDEX ix_annotation_findquotes ON annotation (findquotes);
CREATE INDEX ix_annotation_findnotes ON annotation (findnotes);
PRAGMA journal_mode=WAL PRAGMA journal_mode=WAL
''' '''
for statement in sql.split(';'): for statement in sql.split(';'):

View file

@ -377,8 +377,6 @@ class Update(Thread):
db_version = migrate_16() db_version = migrate_16()
if db_version < 17: if db_version < 17:
db_version = migrate_17() db_version = migrate_17()
if db_version < 18:
db_version = migrate_18()
settings.server['db_version'] = db_version settings.server['db_version'] = db_version
def run(self): def run(self):
@ -676,25 +674,3 @@ def migrate_17():
lists.append(l.name) lists.append(l.name)
add_record('orderlists', lists) add_record('orderlists', lists)
return 17 return 17
def migrate_18():
db.run_sql([
'''CREATE TABLE annotation (
_id INTEGER NOT NULL,
id VARCHAR(43),
created DATETIME,
modified DATETIME,
user_id VARCHAR(43),
item_id VARCHAR(43),
data BLOB,
findquotes TEXT,
findnotes TEXT,
PRIMARY KEY (_id),
FOREIGN KEY(user_id) REFERENCES user (id),
FOREIGN KEY(item_id) REFERENCES item (id)
)'''])
db.run_sql([
'CREATE INDEX ix_annotation_findquotes ON annotation (findquotes)',
'CREATE INDEX ix_annotation_findnotes ON annotation (findnotes)'
])
return 18

View file

@ -474,7 +474,7 @@ def removePeering(data):
if len(data.get('id', '')) not in (16, 43): if len(data.get('id', '')) not in (16, 43):
logger.debug('invalid user id') logger.debug('invalid user id')
return {} return {}
u = models.User.get(data['id'], for_update=True) u = models.User.get(data['id'], for_udpate=True)
if u: if u:
u.info['message'] = data.get('message', '') u.info['message'] = data.get('message', '')
u.update_peering(False) u.update_peering(False)

View file

@ -187,9 +187,7 @@ class User(db.Model):
def cleanup(self): def cleanup(self):
from item.models import user_items, Item from item.models import user_items, Item
from annotation.models import Annotation
List.query.filter_by(user_id=self.id).delete() List.query.filter_by(user_id=self.id).delete()
Annotation.query.filter_by(user_id=self.id).delete()
c_user_id = user_items.columns['user_id'] c_user_id = user_items.columns['user_id']
q = user_items.delete().where(c_user_id.is_(self.id)) q = user_items.delete().where(c_user_id.is_(self.id))
state.db.session.execute(q) state.db.session.execute(q)
@ -199,7 +197,6 @@ class User(db.Model):
state.peers[self.id].remove() state.peers[self.id].remove()
del state.peers[self.id] del state.peers[self.id]
def update_name(self): def update_name(self):
if self.id == settings.USER_ID: if self.id == settings.USER_ID:
name = settings.preferences.get('username', 'anonymous') name = settings.preferences.get('username', 'anonymous')

View file

@ -6,16 +6,9 @@ oml.ui.annotation = function(annotation, $iframe) {
.html(Ox.encodeHTMLEntities(annotation.text).replace(/\n/g, '<br/>')) .html(Ox.encodeHTMLEntities(annotation.text).replace(/\n/g, '<br/>'))
.on({ .on({
click: function(event) { click: function(event) {
var id that.select()
if (event.ctrlKey) {
that.deselect()
id = null
} else {
that.select()
id = annotation.id
}
$iframe.postMessage('selectAnnotation', { $iframe.postMessage('selectAnnotation', {
id: id id: annotation.id
}) })
} }
}); });
@ -46,22 +39,14 @@ oml.ui.annotation = function(annotation, $iframe) {
note.value = data.value note.value = data.value
note.modified = (new Date).toISOString() note.modified = (new Date).toISOString()
} else { } else {
annotation.notes.push(note = { annotation.notes.push({
created: data.created || (new Date).toISOString(), created: data.created || (new Date).toISOString(),
modified: (new Date).toISOString(), modified: (new Date).toISOString(),
id: data.id, id: data.id,
user: '',
value: data.value value: data.value
}) })
} }
oml.api.editNote({
item: oml.user.ui.item,
annotation: annotation.id,
notes: {
created: note.created,
modified: note.modified,
value: note.value
}
})
that.triggerEvent('change') that.triggerEvent('change')
} }
}); });
@ -97,11 +82,6 @@ oml.ui.annotation = function(annotation, $iframe) {
addNote() addNote()
} }
} }
that.delete = function() {
that.triggerEvent('delete', {
id: annotation.id
})
}
that.deselect = function() { that.deselect = function() {
that.removeClass('selected') that.removeClass('selected')
that.loseFocus() that.loseFocus()
@ -114,8 +94,7 @@ oml.ui.annotation = function(annotation, $iframe) {
selected && selected.classList.remove('selected') selected && selected.classList.remove('selected')
that.addClass('selected') that.addClass('selected')
that.gainFocus() that.gainFocus()
oml.$ui.annotationPanel.updateSelection(false) that[0].scrollIntoViewIfNeeded()
that[0].scrollIntoViewIfNeeded && that[0].scrollIntoViewIfNeeded()
} }
return that; return that;
}; };

View file

@ -1,13 +1,12 @@
'use strict'; 'use strict';
oml.ui.annotationPanel = function() { oml.ui.annotationPanel = function() {
var ui = oml.user.ui;
var ui = oml.user.ui; var ui = oml.user.ui;
var $bar = Ox.Bar({size: 16}); var $bar = Ox.Bar({size: 16});
var $addQuote = Ox.Button({ var $button = Ox.Button({
disabled: true, disabled: true,
style: 'symbol', style: 'symbol',
title: 'add', title: 'add',
@ -19,20 +18,6 @@ oml.ui.annotationPanel = function() {
} }
}).appendTo($bar); }).appendTo($bar);
var $deleteQuote = Ox.Button({
disabled: true,
style: 'symbol',
title: 'remove',
tooltip: Ox._('Delete Quote'),
type: 'image'
}).bindEvent({
click: function() {
var $annotation = oml.$ui.annotationFolder.find('.OMLAnnotation.selected')
$annotation.length && $annotation.delete()
$deleteQuote.options({disabled: true})
}
}).appendTo($bar);
var $menuButton = Ox.MenuButton({ var $menuButton = Ox.MenuButton({
items: [ items: [
{id: 'addAnnotation', title: 'Add Annotation', disabled: true}, {id: 'addAnnotation', title: 'Add Annotation', disabled: true},
@ -82,21 +67,6 @@ oml.ui.annotationPanel = function() {
}, function(result) { }, function(result) {
oml.ui.exportAnnotationsDialog(result.data).open() oml.ui.exportAnnotationsDialog(result.data).open()
}) })
} else {
console.log('click', id, data)
}
},
change: function(data) {
var id = data.id;
console.log('change', data)
if (id == 'show') {
console.log('show', data)
oml.UI.set({annotationsShow: data.checked[0].id});
} else if (id == 'sort') {
console.log('sort', data)
oml.UI.set({annotationsSort: data.checked[0].id});
} else {
console.log('change', id, data)
} }
} }
}).appendTo($bar); }).appendTo($bar);
@ -116,13 +86,9 @@ oml.ui.annotationPanel = function() {
}); });
that.updateSelection = function(selection) { that.updateSelection = function(selection) {
$addQuote.options({ $button.options({
disabled: !selection disabled: !selection
}) })
var $annotation = oml.$ui.annotationFolder.find('.OMLAnnotation.selected')
$deleteQuote.options({
disabled: !$annotation.length
})
} }
return that; return that;

View file

@ -47,8 +47,7 @@ oml.ui.exportAnnotationsDialog = function(data) {
var annotations = oml.$ui.viewer.getAnnotations() var annotations = oml.$ui.viewer.getAnnotations()
var text = 'Annotations for ' + data.title + ' (' + data.author.join(', ') + ')\n\n\n\n' var text = 'Annotations for ' + data.title + ' (' + data.author.join(', ') + ')\n\n\n\n'
text += annotations.map(function(annotation) { text += annotations.map(function(annotation) {
var page = annotation.pageLabel || annotation.page var text = 'Quote:\n\n' + annotation.text
var text = 'Quote' + (page ? ' Page ' + page : '' )+ ':\n\n' + annotation.text
if (annotation.notes.length) { if (annotation.notes.length) {
text += '\n\nNotes:\n' + annotation.notes.map(function(note) { text += '\n\nNotes:\n' + annotation.notes.map(function(note) {
return note.value return note.value

View file

@ -20,9 +20,6 @@ oml.ui.folders = function() {
oml_showfolder: function() { oml_showfolder: function() {
oml.resizeListFolders(); oml.resizeListFolders();
}, },
oml_showpeers: function() {
that.updateElement();
},
oml_showinfo: function() { oml_showinfo: function() {
oml.resizeListFolders(); oml.resizeListFolders();
} }
@ -51,15 +48,9 @@ oml.ui.folders = function() {
function getUsersAndLists(callback) { function getUsersAndLists(callback) {
oml.getUsers(function(users_) { oml.getUsers(function(users_) {
if (ui.showPeers) { users = users_.filter(function(user) {
users = users_.filter(function(user) { return user.id == oml.user.id || user.peered;
return user.id == oml.user.id || user.peered; });
});
} else {
users = users_.filter(function(user) {
return user.id == oml.user.id;
});
}
oml.getLists(function(lists) { oml.getLists(function(lists) {
callback(users, lists); callback(users, lists);
}); });

View file

@ -214,12 +214,6 @@ oml.ui.mainMenu = function() {
title: Ox._((ui.showSidebar ? 'Hide' : 'Show') + ' Sidebar'), title: Ox._((ui.showSidebar ? 'Hide' : 'Show') + ' Sidebar'),
keyboard: 'shift s' keyboard: 'shift s'
}, },
{
id: 'showpeers',
title: Ox._((ui.showPeers ? 'Hide' : 'Show') + ' Peers'),
keyboard: 'shift p',
disabled: !ui.showSidebar
},
{ {
id: 'showinfo', id: 'showinfo',
title: Ox._((ui.showInfo ? 'Hide' : 'Show') + ' Info'), title: Ox._((ui.showInfo ? 'Hide' : 'Show') + ' Info'),
@ -545,8 +539,6 @@ oml.ui.mainMenu = function() {
oml.history.clear(); oml.history.clear();
} else if (id == 'showsidebar') { } else if (id == 'showsidebar') {
oml.UI.set({showSidebar: !ui.showSidebar}); oml.UI.set({showSidebar: !ui.showSidebar});
} else if (id == 'showpeers') {
oml.UI.set({showPeers: !ui.showPeers});
} else if (id == 'showinfo') { } else if (id == 'showinfo') {
oml.UI.set({showInfo: !ui.showInfo}); oml.UI.set({showInfo: !ui.showInfo});
} else if (id == 'showfilters') { } else if (id == 'showfilters') {
@ -644,16 +636,12 @@ oml.ui.mainMenu = function() {
that[action]('viewMenu_iconsSubmenu_extension'); that[action]('viewMenu_iconsSubmenu_extension');
that[action]('viewMenu_iconsSubmenu_size'); that[action]('viewMenu_iconsSubmenu_size');
}, },
oml_showpeers: function(data) {
that.setItemTitle('showpeers', Ox._((data.value ? 'Hide' : 'Show') + ' Peers'));
},
oml_showinfo: function(data) { oml_showinfo: function(data) {
that.setItemTitle('showinfo', Ox._((data.value ? 'Hide' : 'Show') + ' Info')); that.setItemTitle('showinfo', Ox._((data.value ? 'Hide' : 'Show') + ' Info'));
}, },
oml_showsidebar: function(data) { oml_showsidebar: function(data) {
that.setItemTitle('showsidebar', Ox._((data.value ? 'Hide' : 'Show') + ' Sidebar')); that.setItemTitle('showsidebar', Ox._((data.value ? 'Hide' : 'Show') + ' Sidebar'));
that[data.value ? 'enableItem' : 'disableItem']('showinfo'); that[data.value ? 'enableItem' : 'disableItem']('showinfo');
that[data.value ? 'enableItem' : 'disableItem']('showpeers');
}, },
}); });
Ox.Event.bind({ Ox.Event.bind({
@ -738,17 +726,8 @@ oml.ui.mainMenu = function() {
key_shift_f: function() { key_shift_f: function() {
!ui.item && oml.UI.set({showFilters: !ui.showFilters}); !ui.item && oml.UI.set({showFilters: !ui.showFilters});
}, },
key_shift_p: function(event, name, target) { key_shift_i: function() {
// FIXME: event triggers twice ui.showSidebar && oml.UI.set({showInfo: !ui.showInfo});
if (target.hasClass('OxFocus')) {
ui.showSidebar && oml.UI.set({showPeers: !ui.showPeers});
}
},
key_shift_i: function(event, name, target) {
// FIXME: event triggers twice
if (target.hasClass('OxFocus')) {
ui.showSidebar && oml.UI.set({showInfo: !ui.showInfo});
}
}, },
key_shift_s: function() { key_shift_s: function() {
oml.UI.set({showSidebar: !ui.showSidebar}); oml.UI.set({showSidebar: !ui.showSidebar});

View file

@ -15,12 +15,6 @@ oml.ui.viewer = function() {
}, },
oml_showannotations: function() { oml_showannotations: function() {
panel.toggleElement(1); panel.toggleElement(1);
},
oml_sortannotations: function(data) {
that.renderAnnotations()
},
oml_annotationusers: function(data) {
that.renderAnnotations()
} }
}), }),
panel = Ox.SplitPanel({ panel = Ox.SplitPanel({
@ -46,81 +40,38 @@ oml.ui.viewer = function() {
$iframe, item; $iframe, item;
function loadAnnotations(callback) { function loadAnnotations(callback) {
if (localStorage[item + '.annotations']) { annotations = JSON.parse(localStorage[item + '.annotations'] || '[]')
annotations = JSON.parse(localStorage[item + '.annotations'] || '[]') annotations.forEach(function(data) {
var ids = [] if (data.comments && !data.notes) {
annotations.forEach(function(data) { data.notes = data.comments
if (data.comments && !data.notes) { delete data.comments
data.notes = data.comments }
delete data.comments data.notes = data.notes || [];
}
if (!Ox.contains(ids, data.id)) {
ids.push(data.id)
var note
if (data.notes && data.notes.length) {
note = data.notes[0]
delete data.notes
}
addAnnotation(data, false)
if (note) {
data.notes = [note]
} else {
data.notes = []
}
if (data.notes.length) {
var note = data.notes[0]
oml.api.editNote({
item: ui.item,
annotation: data.id,
notes: {
created: note.created,
modified: note.modified,
value: note.value
}
})
}
} else {
console.log('ignore second time', data)
}
})
localStorage[oml.user.ui.item + '.annotations_'] = localStorage[oml.user.ui.item + '.annotations']
delete localStorage[oml.user.ui.item + '.annotations']
callback && callback(annotations)
} else {
oml.api.getAnnotations({
id: ui.item
}, function(result) {
console.log(result)
annotations = result.data.annotations
callback && callback(annotations)
})
}
}
function addAnnotation(data, save) {
var a = Ox.extend({}, data)
a.created = a.created || (new Date).toISOString();
a.item = ui.item
if (save !== false) {
oml.api.addAnnotation(a)
}
data.notes = data.notes || [];
annotations.push(data);
}
function removeAnnotation(id) {
oml.api.removeAnnotation({
item: ui.item,
annotation: id
}, function(result) {
annotations = annotations.filter(function(annotation) {
return annotation.id != id
})
}) })
callback && callback(annotations)
}
function saveAnnotations(data) {
if (data) {
data.created = data.created || (new Date).toISOString();
if (data.comments && !data.notes) {
data.notes = data.comments
delete data.comments
}
data.notes = data.notes || [];
annotations.push(data);
}
localStorage[item + '.annotations'] = JSON.stringify(annotations)
}
function removeAnnotation(id) {
annotations = annotations.filter(function(annotation) {
return annotation.id != id
})
saveAnnotations()
} }
var annotationEvents = { var annotationEvents = {
change: function(data) { change: function() {
// console.log('change', data) saveAnnotations()
}, },
'delete': function(data) { 'delete': function(data) {
oml.$ui.annotationFolder.find('#a-' + data.id).remove() oml.$ui.annotationFolder.find('#a-' + data.id).remove()
@ -142,16 +93,14 @@ oml.ui.viewer = function() {
height: '100%', height: '100%',
border: 0 border: 0
}).onMessage(function(data, event) { }).onMessage(function(data, event) {
console.log('got', event, data)
if (event == 'addAnnotation') { if (event == 'addAnnotation') {
addAnnotation(data); saveAnnotations(data);
var $annotation = oml.ui.annotation(data, $iframe).bindEvent(annotationEvents) var $annotation = oml.ui.annotation(data, $iframe).bindEvent(annotationEvents)
oml.$ui.annotationFolder.append($annotation); oml.$ui.annotationFolder.append($annotation);
$annotation.annotate(); $annotation.annotate();
oml.$ui.annotationPanel.updateSelection(false)
} else if (event == 'removeAnnotation') { } else if (event == 'removeAnnotation') {
oml.$ui.annotationFolder.find('#a-' + data.id).remove() oml.$ui.annotationFolder.find('#a-' + data.id).remove()
data.id && removeAnnotation(data.id) removeAnnotation(data.id)
} else if (event == 'selectAnnotation') { } else if (event == 'selectAnnotation') {
if (data.id) { if (data.id) {
var $annotation = oml.$ui.annotationFolder.find('#a-' + data.id) var $annotation = oml.$ui.annotationFolder.find('#a-' + data.id)
@ -160,17 +109,22 @@ oml.ui.viewer = function() {
var $annotation = oml.$ui.annotationFolder.find('.OMLAnnotation.selected') var $annotation = oml.$ui.annotationFolder.find('.OMLAnnotation.selected')
$annotation.length && $annotation.deselect() $annotation.length && $annotation.deselect()
} }
oml.$ui.annotationPanel.updateSelection(false)
} else if (event == 'selectText') { } else if (event == 'selectText') {
oml.$ui.annotationPanel.updateSelection(data) oml.$ui.annotationPanel.updateSelection(data)
} else { } else {
console.log('trigger unknwon event', event, data) console.log('got', event, data)
that.triggerEvent(event, data); that.triggerEvent(event, data);
} }
}).bindEvent({ }).bindEvent({
init: function() { init: function() {
loadAnnotations(function(annotations) { loadAnnotations(function(annotations) {
that.renderAnnotations() that.renderAnnotations()
// fixme: trigger loaded event from reader instead?
setTimeout(function() {
that.postMessage('addAnnotations', {
annotations: annotations
})
}, 500)
}) })
} }
}).appendTo(frame); }).appendTo(frame);
@ -189,34 +143,12 @@ oml.ui.viewer = function() {
return annotations; return annotations;
} }
that.renderAnnotations = function() { that.renderAnnotations = function() {
var sortKey = ui.sortAnnotations
if (sortKey == 'date') {
sortKey = 'created'
}
if (sortKey == 'date') {
sortKey = 'created'
}
if (sortKey == 'quote') {
sortKey = 'text'
}
annotations = Ox.sortBy(annotations, sortKey)
oml.$ui.annotationFolder.empty(); oml.$ui.annotationFolder.empty();
var visibleAnnotations = []; Ox.sortBy(annotations, ui.sortAnnotations);
annotations.forEach(function(data) { annotations.forEach(function(data) {
//that.postMessage('removeAnnotation', {id: data.id}) var $annotation = oml.ui.annotation(data, $iframe).bindEvent(annotationEvents)
if (ui.showAnnotationUsers == 'all' || data.user == oml.user.id) { oml.$ui.annotationFolder.append($annotation);
var $annotation = oml.ui.annotation(data, $iframe).bindEvent(annotationEvents)
oml.$ui.annotationFolder.append($annotation);
visibleAnnotations.push(data)
}
}) })
// fixme: trigger loaded event from reader instead?
setTimeout(function() {
that.postMessage('addAnnotations', {
annotations: visibleAnnotations,
replace: true
})
}, 500)
} }
return that.updateElement(); return that.updateElement();
}; };

View file

@ -4,7 +4,6 @@ var id = document.location.pathname.split('/')[1];
var annotations = []; var annotations = [];
var currentSelection; var currentSelection;
var fontSize = parseInt(localStorage.epubFontSize || '100', 10) var fontSize = parseInt(localStorage.epubFontSize || '100', 10)
var justSelected = false;
Ox.load({ Ox.load({
'UI': { 'UI': {
@ -22,12 +21,6 @@ Ox.load({
} else if (event == 'addAnnotation') { } else if (event == 'addAnnotation') {
createAnnotation() createAnnotation()
} else if (event == 'addAnnotations') { } else if (event == 'addAnnotations') {
if (data.replace) {
annotations.forEach(function(a) {
reader.rendition.annotations.remove(a.cfiRange)
})
annotations = []
}
data.annotations.forEach(function(annotation) { data.annotations.forEach(function(annotation) {
annotations.push(annotation) annotations.push(annotation)
renderAnnotation(annotation) renderAnnotation(annotation)
@ -57,7 +50,6 @@ function createAnnotation() {
document.querySelectorAll('.epubjs-hl.selected').forEach(function(other) { document.querySelectorAll('.epubjs-hl.selected').forEach(function(other) {
other.classList.remove('selected') other.classList.remove('selected')
}) })
console.log('create annot')
currentSelection = null currentSelection = null
} }
} }
@ -152,8 +144,6 @@ document.onreadystatechange = function () {
} }
if (event.key == 'n' || event.keyCode == 13) { if (event.key == 'n' || event.keyCode == 13) {
var selected = document.querySelector('.epubjs-hl.selected') var selected = document.querySelector('.epubjs-hl.selected')
console.log('!!', currentSelection, selected)
if (currentSelection) { if (currentSelection) {
if (selected) { if (selected) {
deselectAllAnnotations() deselectAllAnnotations()
@ -161,6 +151,7 @@ document.onreadystatechange = function () {
createAnnotation() createAnnotation()
} else if (selected) { } else if (selected) {
console.log('editNote?', selected.dataset.id) console.log('editNote?', selected.dataset.id)
} }
} }
if (event.keyCode == 61 && event.shiftKey) { if (event.keyCode == 61 && event.shiftKey) {
@ -180,7 +171,7 @@ document.onreadystatechange = function () {
event.preventDefault() event.preventDefault()
} }
}).on('mouseup', function(event) { }).on('mouseup', function(event) {
if (!justSelected) { if (currentSelection) {
var selection = window.getSelection() var selection = window.getSelection()
if (selection.isCollapsed) { if (selection.isCollapsed) {
currentSelection = null currentSelection = null
@ -189,20 +180,15 @@ document.onreadystatechange = function () {
Ox.$parent.postMessage('selectText', false) Ox.$parent.postMessage('selectText', false)
} }
} }
deselectAllAnnotations()
justSelected = false
}) })
rendition.on("mark", function(cfiRange, contents) { rendition.on("mark", function(cfiRange, contents) {
console.log('!! mark', cfiRange) console.log('!! mark', cfiRange)
}) })
rendition.on("selected", function(cfiRange, contents) { rendition.on("selected", function(cfiRange, contents) {
justSelected = true
getText(book, cfiRange, function(text) { getText(book, cfiRange, function(text) {
var position = cfiRange;
currentSelection = { currentSelection = {
id: Ox.SHA1(cfiRange), id: Ox.SHA1(cfiRange),
cfiRange: cfiRange, cfiRange: cfiRange,
position: position,
text: text, text: text,
contents: contents contents: contents
} }

View file

@ -8,6 +8,7 @@ Ox.load({
} }
}, function() { }, function() {
Ox.$parent.bindMessage(function(data, event) { Ox.$parent.bindMessage(function(data, event) {
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 var delay = 0
@ -19,7 +20,7 @@ Ox.load({
PDFViewerApplication.pdfViewer.currentPageNumber = annotation.page; PDFViewerApplication.pdfViewer.currentPageNumber = annotation.page;
delay = 250 delay = 250
} }
annotation && setTimeout(function() { setTimeout(function() {
var el = document.querySelector('.a' + annotation.id); var el = document.querySelector('.a' + annotation.id);
if (el && !isInView(el)) { if (el && !isInView(el)) {
document.querySelector('#viewerContainer').scrollTop = el.offsetTop + el.parentElement.offsetTop - 64; document.querySelector('#viewerContainer').scrollTop = el.offsetTop + el.parentElement.offsetTop - 64;
@ -29,20 +30,12 @@ Ox.load({
} else if (event == 'addAnnotation') { } else if (event == 'addAnnotation') {
createAnnotation() createAnnotation()
} else if (event == 'addAnnotations') { } else if (event == 'addAnnotations') {
if (data.replace) {
document.querySelectorAll('.oml-annotation').forEach(function(a) {
a.remove()
})
annotations = []
}
data.annotations.forEach(function(annotation) { data.annotations.forEach(function(annotation) {
annotations.push(annotation) annotations.push(annotation)
renderAnnotation(annotation) renderAnnotation(annotation)
}) })
} else if (event == 'removeAnnotation') { } else if (event == 'removeAnnotation') {
removeAnnotation(data.id) removeAnnotation(data.id)
} else {
console.log('got', event, 'data', data)
} }
}) })
}) })
@ -54,16 +47,14 @@ window.addEventListener('keydown', function(event) {
removeAnnotation(selected.dataset.id) removeAnnotation(selected.dataset.id)
} }
} else if (event.key == 'n' || event.keyCode == 13) { } else if (event.key == 'n' || event.keyCode == 13) {
if (event.target.nodeName != 'INPUT') { var selected = document.querySelector('.oml-annotation.selected')
var selected = document.querySelector('.oml-annotation.selected') if (!window.getSelection().isCollapsed) {
if (!window.getSelection().isCollapsed) { createAnnotation()
createAnnotation() } else if (selected) {
} else if (selected) { console.log('editNote?', selected.dataset.id)
console.log('editNote?', selected.dataset.id)
}
event.stopPropagation()
event.preventDefault()
} }
event.stopPropagation()
event.preventDefault()
} }
}) })
window.addEventListener('mouseup', function(event) { window.addEventListener('mouseup', function(event) {
@ -100,11 +91,8 @@ function getHighlight() {
viewport.convertToPdfPoint(r.right - pageRect.x, r.bottom - pageRect.y)); viewport.convertToPdfPoint(r.right - pageRect.x, r.bottom - pageRect.y));
}); });
var text = selection.toString(); var text = selection.toString();
var position = [pageNumber].concat(Ox.sort(selected.map(function(c) { return [c[1], c[0]]}))[0]);
return { return {
page: pageNumber, page: pageNumber,
pageLabel: PDFViewerApplication.pdfViewer.currentPageLabel,
position: position,
coords: selected, coords: selected,
text: text, text: text,
id: Ox.SHA1(pageNumber.toString() + JSON.stringify(selected)) id: Ox.SHA1(pageNumber.toString() + JSON.stringify(selected))
@ -184,7 +172,7 @@ function deselectAllAnnotations() {
g.classList.remove('selected') g.classList.remove('selected')
g.style.backgroundColor = 'yellow' g.style.backgroundColor = 'yellow'
var id = $(g).parents('.oml-annotation').data('id') var id = $(g).parents('.oml-annotation').data('id')
//console.log('deselect', g, id) console.log('deselect', g, id)
if (!Ox.contains(ids, id)) { if (!Ox.contains(ids, id)) {
ids.push(id) ids.push(id)
Ox.$parent.postMessage('selectAnnotation', {id: null}) Ox.$parent.postMessage('selectAnnotation', {id: null})