solid-ui
Version:
UI library for writing Solid read-write-web applications
342 lines (285 loc) • 11 kB
JavaScript
;
// Common code for a discussion are a of messages about something
//
var UI = {
authn: require('./signin'),
icons: require('./iconBase'),
log: require('./log'),
ns: require('./ns'),
pad: require('./'),
rdf: require('rdflib'),
store: require('./store'),
style: require('./style'),
widgets: require('./widgets')
};
var utils = require('./utils'); // var buttonStyle = 'font-size: 100%; margin: 0.8em; padding:0.5em; background-color: white;'
module.exports = function (dom, kb, subject, messageStore, options) {
kb = kb || UI.store;
messageStore = messageStore.doc(); // No hash
var ns = UI.ns;
var WF = $rdf.Namespace('http://www.w3.org/2005/01/wf/flow#');
var DCT = $rdf.Namespace('http://purl.org/dc/terms/');
options = options || {};
var newestFirst = !!options.newestFirst;
var messageBodyStyle = 'white-space: pre-wrap; width: 90%; font-size:100%; border: 0.07em solid #eee; padding: .2em 0.5em; margin: 0.1em 1em 0.1em 1em;'; // 'font-size: 100%; margin: 0.1em 1em 0.1em 1em; background-color: white; white-space: pre-wrap; padding: 0.1em;'
var div = dom.createElement('div');
var messageTable; // Shared by initial build and addMessageFromBindings
var me;
var updater = UI.store.updater;
var anchor = function anchor(text, term) {
// If there is no link return an element anyway
var a = dom.createElement('a');
if (term && term.uri) {
a.setAttribute('href', term.uri);
a.addEventListener('click', UI.widgets.openHrefInOutlineMode, true);
a.setAttribute('style', 'color: #3B5998; text-decoration: none; '); // font-weight: bold
}
a.textContent = text;
return a;
};
var mention = function mention(message, style) {
var pre = dom.createElement('pre');
pre.setAttribute('style', style || 'color: grey');
div.appendChild(pre);
pre.appendChild(dom.createTextNode(message));
return pre;
};
var announce = {
log: function log(message) {
mention(message, 'color: #111;');
},
warn: function warn(message) {
mention(message, 'color: #880;');
},
error: function error(message) {
mention(message, 'color: #800;');
}
}; // Form for a new message
//
var newMessageForm = function newMessageForm() {
var form = dom.createElement('tr');
var lhs = dom.createElement('td');
var middle = dom.createElement('td');
var rhs = dom.createElement('td');
form.appendChild(lhs);
form.appendChild(middle);
form.appendChild(rhs);
form.AJAR_date = '9999-01-01T00:00:00Z'; // ISO format for field sort
var sendMessage = function sendMessage() {
// titlefield.setAttribute('class','pendingedit')
// titlefield.disabled = true
field.setAttribute('class', 'pendingedit');
field.disabled = true;
var sts = [];
var now = new Date();
var timestamp = '' + now.getTime();
var dateStamp = $rdf.term(now); // http://www.w3schools.com/jsref/jsref_obj_date.asp
var message = kb.sym(messageStore.uri + '#' + 'Msg' + timestamp);
sts.push(new $rdf.Statement(subject, ns.wf('message'), message, messageStore)); // sts.push(new $rdf.Statement(message, ns.dc('title'), kb.literal(titlefield.value), messageStore))
sts.push(new $rdf.Statement(message, ns.sioc('content'), kb.literal(field.value), messageStore));
sts.push(new $rdf.Statement(message, DCT('created'), dateStamp, messageStore));
if (me) sts.push(new $rdf.Statement(message, ns.foaf('maker'), me, messageStore));
var sendComplete = function sendComplete(uri, success, body) {
if (!success) {
form.appendChild(UI.widgets.errorMessageBlock(dom, 'Error writing message: ' + body));
} else {
var bindings = {
'?msg': message,
'?content': kb.literal(field.value),
'?date': dateStamp,
'?creator': me
};
renderMessage(bindings, false); // not green
field.value = ''; // clear from out for reuse
field.setAttribute('class', '');
field.disabled = false;
}
};
updater.update([], sts, sendComplete);
};
form.appendChild(dom.createElement('br'));
var field, sendButton;
var turnOnInput = function turnOnInput() {
creatorAndDate(lhs, me, '', null);
field = dom.createElement('textarea');
middle.innerHTML = '';
middle.appendChild(field);
field.rows = 3; // field.cols = 40
field.setAttribute('style', messageBodyStyle + 'background-color: #eef;');
field.addEventListener('keyup', function (e) {
// User preference?
if (e.keyCode === 13) {
if (!e.altKey) {
// Alt-Enter just adds a new line
sendMessage();
}
}
}, false);
rhs.innerHTML = '';
sendButton = UI.widgets.button(dom, UI.icons.iconBase + 'noun_383448.svg', 'Send');
sendButton.setAttribute('style', UI.style.buttonStyle + 'float: right;');
sendButton.addEventListener('click', sendMessage, false);
rhs.appendChild(sendButton);
};
var context = {
div: middle,
dom: dom
};
UI.authn.logIn(context).then(function (context) {
me = context.me;
turnOnInput();
});
return form;
};
function nick(person) {
var s = UI.store.any(person, UI.ns.foaf('nick'));
if (s) return '' + s.value;
return '' + utils.label(person);
}
function creatorAndDate(td1, creator, date, message) {
var nickAnchor = td1.appendChild(anchor(nick(creator), creator));
if (creator.uri) {
UI.store.fetcher.nowOrWhenFetched(creator.doc(), undefined, function (ok, body) {
nickAnchor.textContent = nick(creator);
});
}
td1.appendChild(dom.createElement('br'));
td1.appendChild(anchor(date, message));
} // ///////////////////////////////////////////////////////////////////////
function syncMessages(about, messageTable) {
var displayed = {};
var ele, ele2;
for (ele = messageTable.firstChild; ele; ele = ele.nextSibling) {
if (ele.AJAR_subject) {
displayed[ele.AJAR_subject.uri] = true;
}
}
var messages = kb.each(about, ns.wf('message'));
var stored = {};
messages.map(function (m) {
stored[m.uri] = true;
if (!displayed[m.uri]) {
addMessage(m);
}
});
for (ele = messageTable.firstChild; ele;) {
ele2 = ele.nextSibling;
if (ele.AJAR_subject && !stored[ele.AJAR_subject.uri]) {
messageTable.removeChild(ele);
}
ele = ele2;
}
}
var deleteMessage = function deleteMessage(message) {
var deletions = kb.statementsMatching(message).concat(kb.statementsMatching(undefined, undefined, message));
updater.update(deletions, [], function (uri, ok, body) {
if (!ok) {
announce.error('Cant delete messages:' + body);
} else {
syncMessages(subject, messageTable);
}
});
};
var addMessage = function addMessage(message) {
var bindings = {
'?msg': message,
'?creator': kb.any(message, ns.foaf('maker')),
'?date': kb.any(message, DCT('created')),
'?content': kb.any(message, ns.sioc('content'))
};
renderMessage(bindings, true); // fresh from elsewhere
};
var renderMessage = function renderMessage(bindings, fresh) {
var creator = bindings['?creator'];
var message = bindings['?msg'];
var date = bindings['?date'];
var content = bindings['?content'];
var dateString = date.value;
var tr = dom.createElement('tr');
tr.AJAR_date = dateString;
tr.AJAR_subject = message;
var done = false;
for (var ele = messageTable.firstChild;; ele = ele.nextSibling) {
if (!ele) {
// empty
break;
}
if (dateString > ele.AJAR_date && newestFirst || dateString < ele.AJAR_date && !newestFirst) {
messageTable.insertBefore(tr, ele);
done = true;
break;
}
}
if (!done) {
messageTable.appendChild(tr);
}
var td1 = dom.createElement('td');
tr.appendChild(td1);
creatorAndDate(td1, creator, UI.widgets.shortDate(dateString), message);
var td2 = dom.createElement('td');
tr.appendChild(td2);
var pre = dom.createElement('p');
pre.setAttribute('style', messageBodyStyle + (fresh ? 'background-color: #e8ffe8;' : 'background-color: #white;'));
td2.appendChild(pre);
pre.textContent = content.value;
var td3 = dom.createElement('td');
tr.appendChild(td3);
var delButton = dom.createElement('button');
td3.appendChild(delButton);
delButton.textContent = '-';
tr.setAttribute('class', 'hoverControl'); // See tabbedtab.css (sigh global CSS)
delButton.setAttribute('class', 'hoverControlHide');
delButton.setAttribute('style', 'color: red;');
delButton.addEventListener('click', function (e) {
td3.removeChild(delButton); // Ask -- are you sure?
var cancelButton = dom.createElement('button');
cancelButton.textContent = 'cancel';
td3.appendChild(cancelButton).addEventListener('click', function (e) {
td3.removeChild(sureButton);
td3.removeChild(cancelButton);
td3.appendChild(delButton);
}, false);
var sureButton = dom.createElement('button');
sureButton.textContent = 'Delete message';
td3.appendChild(sureButton).addEventListener('click', function (e) {
td3.removeChild(sureButton);
td3.removeChild(cancelButton);
deleteMessage(message);
}, false);
}, false);
}; // Messages with date, author etc
messageTable = dom.createElement('table');
messageTable.fresh = false;
div.appendChild(messageTable);
messageTable.setAttribute('style', 'width: 100%;'); // fill that div!
var tr = newMessageForm();
if (newestFirst) {
messageTable.insertBefore(tr, messageTable.firstChild); // If newestFirst
} else {
messageTable.appendChild(tr); // not newestFirst
}
var query; // Do this with a live query to pull in messages from web
if (options.query) {
query = options.query;
} else {
query = new $rdf.Query('Messages');
var v = {}; // semicolon needed
var vs = ['msg', 'date', 'creator', 'content'];
vs.map(function (x) {
query.vars.push(v[x] = $rdf.variable(x));
});
query.pat.add(subject, WF('message'), v['msg']);
query.pat.add(v['msg'], ns.dct('created'), v['date']);
query.pat.add(v['msg'], ns.foaf('maker'), v['creator']);
query.pat.add(v['msg'], ns.sioc('content'), v['content']);
}
function doneQuery() {
messageTable.fresh = true; // any new are fresh and so will be greenish
}
kb.query(query, renderMessage, undefined, doneQuery);
div.refresh = function () {
syncMessages(subject, messageTable);
}; // syncMessages(subject, messageTable) // no the query will do this async
return div;
};
//# sourceMappingURL=messageArea.js.map