|
|
define([
|
|
|
'jquery',
|
|
|
'/api/config',
|
|
|
'/common/common-util.js',
|
|
|
'/common/common-hash.js',
|
|
|
'/common/common-language.js',
|
|
|
'/common/common-interface.js',
|
|
|
'/common/common-constants.js',
|
|
|
'/common/common-feedback.js',
|
|
|
'/common/hyperscript.js',
|
|
|
'/common/media-tag.js',
|
|
|
'/common/clipboard.js',
|
|
|
'/customize/messages.js',
|
|
|
'/customize/application_config.js',
|
|
|
'/customize/pages.js',
|
|
|
'/bower_components/nthen/index.js',
|
|
|
'/common/invitation.js',
|
|
|
|
|
|
'css!/customize/fonts/cptools/style.css',
|
|
|
'/bower_components/croppie/croppie.min.js',
|
|
|
'css!/bower_components/croppie/croppie.css',
|
|
|
], function ($, Config, Util, Hash, Language, UI, Constants, Feedback, h, MediaTag, Clipboard,
|
|
|
Messages, AppConfig, Pages, NThen, InviteInner) {
|
|
|
var UIElements = {};
|
|
|
|
|
|
// Configure MediaTags to use our local viewer
|
|
|
if (MediaTag) {
|
|
|
MediaTag.setDefaultConfig('pdf', {
|
|
|
viewer: '/common/pdfjs/web/viewer.html'
|
|
|
});
|
|
|
}
|
|
|
|
|
|
UIElements.updateTags = function (common, href) {
|
|
|
var existing, tags;
|
|
|
NThen(function(waitFor) {
|
|
|
common.getSframeChannel().query("Q_GET_ALL_TAGS", null, waitFor(function(err, res) {
|
|
|
if (err || res.error) { return void console.error(err || res.error); }
|
|
|
existing = Object.keys(res.tags).sort();
|
|
|
}));
|
|
|
}).nThen(function (waitFor) {
|
|
|
common.getPadAttribute('tags', waitFor(function (err, res) {
|
|
|
if (err) {
|
|
|
if (err === 'NO_ENTRY') {
|
|
|
UI.alert(Messages.tags_noentry);
|
|
|
}
|
|
|
waitFor.abort();
|
|
|
return void console.error(err);
|
|
|
}
|
|
|
tags = res || [];
|
|
|
}), href);
|
|
|
}).nThen(function () {
|
|
|
UI.dialog.tagPrompt(tags, existing, function (newTags) {
|
|
|
if (!Array.isArray(newTags)) { return; }
|
|
|
common.setPadAttribute('tags', newTags, null, href);
|
|
|
});
|
|
|
});
|
|
|
};
|
|
|
|
|
|
var importContent = function (type, f, cfg) {
|
|
|
return function () {
|
|
|
var $files = $('<input>', {type:"file"});
|
|
|
if (cfg && cfg.accept) {
|
|
|
$files.attr('accept', cfg.accept);
|
|
|
}
|
|
|
$files.click();
|
|
|
$files.on('change', function (e) {
|
|
|
var file = e.target.files[0];
|
|
|
var reader = new FileReader();
|
|
|
reader.onload = function (e) { f(e.target.result, file); };
|
|
|
reader.readAsText(file, type);
|
|
|
});
|
|
|
};
|
|
|
};
|
|
|
|
|
|
var getPropertiesData = function (common, cb) {
|
|
|
var data = {};
|
|
|
NThen(function (waitFor) {
|
|
|
var base = common.getMetadataMgr().getPrivateData().origin;
|
|
|
common.getPadAttribute('', waitFor(function (err, val) {
|
|
|
if (err || !val) {
|
|
|
waitFor.abort();
|
|
|
return void cb(err || 'EEMPTY');
|
|
|
}
|
|
|
if (!val.fileType) {
|
|
|
delete val.owners;
|
|
|
delete val.expire;
|
|
|
}
|
|
|
Util.extend(data, val);
|
|
|
if (data.href) { data.href = base + data.href; }
|
|
|
if (data.roHref) { data.roHref = base + data.roHref; }
|
|
|
}));
|
|
|
common.getPadMetadata(null, waitFor(function (obj) {
|
|
|
if (obj && obj.error) { return; }
|
|
|
data.owners = obj.owners;
|
|
|
data.expire = obj.expire;
|
|
|
data.pending_owners = obj.pending_owners;
|
|
|
}));
|
|
|
}).nThen(function () {
|
|
|
cb(void 0, data);
|
|
|
});
|
|
|
};
|
|
|
var createOwnerModal = function (common, data) {
|
|
|
var friends = common.getFriends(true);
|
|
|
var sframeChan = common.getSframeChannel();
|
|
|
var priv = common.getMetadataMgr().getPrivateData();
|
|
|
var user = common.getMetadataMgr().getUserData();
|
|
|
var edPublic = priv.edPublic;
|
|
|
var channel = data.channel;
|
|
|
var owners = data.owners || [];
|
|
|
var pending_owners = data.pending_owners || [];
|
|
|
var teams = priv.teams;
|
|
|
var teamOwner = data.teamId;
|
|
|
|
|
|
var redrawAll = function () {};
|
|
|
|
|
|
var div1 = h('div.cp-usergrid-user.cp-share-column.cp-ownership');
|
|
|
var div2 = h('div.cp-usergrid-user.cp-share-column.cp-ownership');
|
|
|
var $div1 = $(div1);
|
|
|
var $div2 = $(div2);
|
|
|
|
|
|
// Remove owner column
|
|
|
var drawRemove = function (pending) {
|
|
|
var _owners = {};
|
|
|
var o = (pending ? pending_owners : owners) || [];
|
|
|
o.forEach(function (ed) {
|
|
|
var f;
|
|
|
Object.keys(friends).some(function (c) {
|
|
|
if (friends[c].edPublic === ed) {
|
|
|
f = friends[c];
|
|
|
return true;
|
|
|
}
|
|
|
});
|
|
|
Object.keys(teams).some(function (id) {
|
|
|
if (teams[id].edPublic === ed) {
|
|
|
f = teams[id];
|
|
|
f.teamId = id;
|
|
|
}
|
|
|
});
|
|
|
if (ed === edPublic) {
|
|
|
f = f || user;
|
|
|
if (f.name) { f.edPublic = edPublic; }
|
|
|
}
|
|
|
_owners[ed] = f || {
|
|
|
displayName: Messages._getKey('owner_unknownUser', [ed]),
|
|
|
edPublic: ed,
|
|
|
};
|
|
|
});
|
|
|
var msg = pending ? Messages.owner_removePendingText
|
|
|
: Messages.owner_removeText;
|
|
|
var removeCol = UIElements.getUserGrid(msg, {
|
|
|
common: common,
|
|
|
large: true,
|
|
|
data: _owners,
|
|
|
noFilter: true
|
|
|
}, function () {
|
|
|
});
|
|
|
var $div = $(removeCol.div);
|
|
|
// When clicking on the remove button, we check the selected users.
|
|
|
// If you try to remove yourself, we'll display an additional warning message
|
|
|
var btnMsg = pending ? Messages.owner_removePendingButton : Messages.owner_removeButton;
|
|
|
var removeButton = h('button.no-margin', btnMsg);
|
|
|
$(removeButton).click(function () {
|
|
|
// Check selection
|
|
|
var $sel = $div.find('.cp-usergrid-user.cp-selected');
|
|
|
var sel = $sel.toArray();
|
|
|
if (!sel.length) { return; }
|
|
|
var me = false;
|
|
|
var toRemove = sel.map(function (el) {
|
|
|
var ed = $(el).attr('data-ed');
|
|
|
if (!ed) { return; }
|
|
|
if (teamOwner && teams[teamOwner] && teams[teamOwner].edPublic === ed) { me = true; }
|
|
|
if (ed === edPublic && !teamOwner) { me = true; }
|
|
|
return ed;
|
|
|
}).filter(function (x) { return x; });
|
|
|
NThen(function (waitFor) {
|
|
|
var msg = me ? Messages.owner_removeMeConfirm : Messages.owner_removeConfirm;
|
|
|
UI.confirm(msg, waitFor(function (yes) {
|
|
|
if (!yes) {
|
|
|
waitFor.abort();
|
|
|
return;
|
|
|
}
|
|
|
}));
|
|
|
}).nThen(function (waitFor) {
|
|
|
// Send the command
|
|
|
sframeChan.query('Q_SET_PAD_METADATA', {
|
|
|
channel: channel,
|
|
|
command: pending ? 'RM_PENDING_OWNERS' : 'RM_OWNERS',
|
|
|
value: toRemove,
|
|
|
teamId: teamOwner
|
|
|
}, waitFor(function (err, res) {
|
|
|
err = err || (res && res.error);
|
|
|
if (err) {
|
|
|
waitFor.abort();
|
|
|
redrawAll();
|
|
|
var text = err === "INSUFFICIENT_PERMISSIONS" ? Messages.fm_forbidden
|
|
|
: Messages.error;
|
|
|
return void UI.warn(text);
|
|
|
}
|
|
|
UI.log(Messages.saved);
|
|
|
}));
|
|
|
}).nThen(function (waitFor) {
|
|
|
sel.forEach(function (el) {
|
|
|
var curve = $(el).attr('data-curve');
|
|
|
var friend = curve === user.curvePublic ? user : friends[curve];
|
|
|
if (!friend) { return; }
|
|
|
common.mailbox.sendTo("RM_OWNER", {
|
|
|
channel: channel,
|
|
|
title: data.title,
|
|
|
pending: pending,
|
|
|
user: {
|
|
|
displayName: user.name,
|
|
|
avatar: user.avatar,
|
|
|
profile: user.profile,
|
|
|
notifications: user.notifications,
|
|
|
curvePublic: user.curvePublic,
|
|
|
edPublic: priv.edPublic
|
|
|
}
|
|
|
}, {
|
|
|
channel: friend.notifications,
|
|
|
curvePublic: friend.curvePublic
|
|
|
}, waitFor());
|
|
|
});
|
|
|
}).nThen(function () {
|
|
|
redrawAll();
|
|
|
});
|
|
|
});
|
|
|
$div.append(h('p', removeButton));
|
|
|
return $div;
|
|
|
};
|
|
|
|
|
|
// Add owners column
|
|
|
var drawAdd = function () {
|
|
|
var $div = $(h('div.cp-share-column'));
|
|
|
var _friends = JSON.parse(JSON.stringify(friends));
|
|
|
Object.keys(_friends).forEach(function (curve) {
|
|
|
if (owners.indexOf(_friends[curve].edPublic) !== -1 ||
|
|
|
pending_owners.indexOf(_friends[curve].edPublic) !== -1 ||
|
|
|
!_friends[curve].notifications) {
|
|
|
delete _friends[curve];
|
|
|
}
|
|
|
});
|
|
|
var addCol = UIElements.getUserGrid(Messages.owner_addText, {
|
|
|
common: common,
|
|
|
large: true,
|
|
|
data: _friends
|
|
|
}, function () {
|
|
|
//console.log(arguments);
|
|
|
});
|
|
|
$div.append(addCol.div);
|
|
|
|
|
|
var teamsData = Util.tryParse(JSON.stringify(priv.teams)) || {};
|
|
|
Object.keys(teamsData).forEach(function (id) {
|
|
|
var t = teamsData[id];
|
|
|
t.teamId = id;
|
|
|
if (owners.indexOf(t.edPublic) !== -1 || pending_owners.indexOf(t.edPublic) !== -1) {
|
|
|
delete teamsData[id];
|
|
|
}
|
|
|
});
|
|
|
var teamsList = UIElements.getUserGrid(Messages.owner_addTeamText, {
|
|
|
common: common,
|
|
|
large: true,
|
|
|
noFilter: true,
|
|
|
data: teamsData
|
|
|
}, function () {});
|
|
|
$div.append(teamsList.div);
|
|
|
|
|
|
// When clicking on the add button, we get the selected users.
|
|
|
var addButton = h('button.no-margin', Messages.owner_addButton);
|
|
|
$(addButton).click(function () {
|
|
|
// Check selection
|
|
|
var $sel = $div.find('.cp-usergrid-user.cp-selected');
|
|
|
var sel = $sel.toArray();
|
|
|
if (!sel.length) { return; }
|
|
|
var toAdd = sel.map(function (el) {
|
|
|
var curve = $(el).attr('data-curve');
|
|
|
// If the pad is woned by a team, we can transfer ownership to ourselves
|
|
|
if (curve === user.curvePublic && teamOwner) { return priv.edPublic; }
|
|
|
var friend = friends[curve];
|
|
|
if (!friend) { return; }
|
|
|
return friend.edPublic;
|
|
|
}).filter(function (x) { return x; });
|
|
|
var toAddTeams = sel.map(function (el) {
|
|
|
var team = teamsData[$(el).attr('data-teamid')];
|
|
|
if (!team || !team.edPublic) { return; }
|
|
|
return {
|
|
|
edPublic: team.edPublic,
|
|
|
id: $(el).attr('data-teamid')
|
|
|
};
|
|
|
}).filter(function (x) { return x; });
|
|
|
|
|
|
NThen(function (waitFor) {
|
|
|
var msg = Messages.owner_addConfirm;
|
|
|
UI.confirm(msg, waitFor(function (yes) {
|
|
|
if (!yes) {
|
|
|
waitFor.abort();
|
|
|
return;
|
|
|
}
|
|
|
}));
|
|
|
}).nThen(function (waitFor) {
|
|
|
// Add one of our teams as an owner
|
|
|
if (toAddTeams.length) {
|
|
|
// Send the command
|
|
|
sframeChan.query('Q_SET_PAD_METADATA', {
|
|
|
channel: channel,
|
|
|
command: 'ADD_OWNERS',
|
|
|
value: toAddTeams.map(function (obj) { return obj.edPublic; }),
|
|
|
teamId: teamOwner
|
|
|
}, waitFor(function (err, res) {
|
|
|
err = err || (res && res.error);
|
|
|
if (err) {
|
|
|
waitFor.abort();
|
|
|
redrawAll();
|
|
|
var text = err === "INSUFFICIENT_PERMISSIONS" ?
|
|
|
Messages.fm_forbidden : Messages.error;
|
|
|
return void UI.warn(text);
|
|
|
}
|
|
|
var isTemplate = priv.isTemplate || data.isTemplate;
|
|
|
toAddTeams.forEach(function (obj) {
|
|
|
sframeChan.query('Q_STORE_IN_TEAM', {
|
|
|
href: data.href || data.rohref,
|
|
|
password: data.password,
|
|
|
path: isTemplate ? ['template'] : undefined,
|
|
|
title: data.title || '',
|
|
|
teamId: obj.id
|
|
|
}, waitFor(function (err) {
|
|
|
if (err) { return void console.error(err); }
|
|
|
}));
|
|
|
});
|
|
|
}));
|
|
|
}
|
|
|
}).nThen(function (waitFor) {
|
|
|
// Offer ownership to a friend
|
|
|
if (toAdd.length) {
|
|
|
// Send the command
|
|
|
sframeChan.query('Q_SET_PAD_METADATA', {
|
|
|
channel: channel,
|
|
|
command: 'ADD_PENDING_OWNERS',
|
|
|
value: toAdd,
|
|
|
teamId: teamOwner
|
|
|
}, waitFor(function (err, res) {
|
|
|
err = err || (res && res.error);
|
|
|
if (err) {
|
|
|
waitFor.abort();
|
|
|
redrawAll();
|
|
|
var text = err === "INSUFFICIENT_PERMISSIONS" ? Messages.fm_forbidden
|
|
|
: Messages.error;
|
|
|
return void UI.warn(text);
|
|
|
}
|
|
|
}));
|
|
|
}
|
|
|
}).nThen(function (waitFor) {
|
|
|
sel.forEach(function (el) {
|
|
|
var curve = $(el).attr('data-curve');
|
|
|
var friend = curve === user.curvePublic ? user : friends[curve];
|
|
|
if (!friend) { return; }
|
|
|
common.mailbox.sendTo("ADD_OWNER", {
|
|
|
channel: channel,
|
|
|
href: data.href,
|
|
|
password: data.password,
|
|
|
title: data.title,
|
|
|
user: {
|
|
|
displayName: user.name,
|
|
|
avatar: user.avatar,
|
|
|
profile: user.profile,
|
|
|
notifications: user.notifications,
|
|
|
curvePublic: user.curvePublic,
|
|
|
edPublic: priv.edPublic
|
|
|
}
|
|
|
}, {
|
|
|
channel: friend.notifications,
|
|
|
curvePublic: friend.curvePublic
|
|
|
}, waitFor());
|
|
|
});
|
|
|
}).nThen(function () {
|
|
|
redrawAll();
|
|
|
UI.log(Messages.saved);
|
|
|
});
|
|
|
});
|
|
|
$div.append(h('p', addButton));
|
|
|
return $div;
|
|
|
};
|
|
|
|
|
|
redrawAll = function (md) {
|
|
|
var todo = function (obj) {
|
|
|
if (obj && obj.error) { return; }
|
|
|
owners = obj.owners || [];
|
|
|
pending_owners = obj.pending_owners || [];
|
|
|
$div1.empty();
|
|
|
$div2.empty();
|
|
|
$div1.append(drawRemove(false)).append(drawRemove(true));
|
|
|
$div2.append(drawAdd());
|
|
|
};
|
|
|
|
|
|
if (md) { return void todo(md); }
|
|
|
common.getPadMetadata({
|
|
|
channel: data.channel
|
|
|
}, todo);
|
|
|
};
|
|
|
|
|
|
$div1.append(drawRemove(false)).append(drawRemove(true));
|
|
|
$div2.append(drawAdd());
|
|
|
|
|
|
var handler = sframeChan.on('EV_RT_METADATA', function (md) {
|
|
|
if (!$div1.length) {
|
|
|
return void handler.stop();
|
|
|
}
|
|
|
owners = md.owners || [];
|
|
|
pending_owners = md.pending_owners || [];
|
|
|
redrawAll(md);
|
|
|
});
|
|
|
|
|
|
// Create modal
|
|
|
var link = h('div.cp-share-columns', [
|
|
|
div1,
|
|
|
div2
|
|
|
/*drawRemove()[0],
|
|
|
drawAdd()[0]*/
|
|
|
]);
|
|
|
var linkButtons = [{
|
|
|
className: 'cancel',
|
|
|
name: Messages.filePicker_close,
|
|
|
onClick: function () {},
|
|
|
keys: [27]
|
|
|
}];
|
|
|
return UI.dialog.customModal(link, {buttons: linkButtons});
|
|
|
};
|
|
|
var getRightsProperties = function (common, data, cb) {
|
|
|
var $div = $('<div>');
|
|
|
if (!data) { return void cb(void 0, $div); }
|
|
|
|
|
|
var draw = function () {
|
|
|
var $d = $('<div>');
|
|
|
var priv = common.getMetadataMgr().getPrivateData();
|
|
|
var user = common.getMetadataMgr().getUserData();
|
|
|
var edPublic = priv.edPublic;
|
|
|
var owned = false;
|
|
|
var _owners = {};
|
|
|
if (data.owners && data.owners.length) {
|
|
|
if (data.owners.indexOf(edPublic) !== -1) {
|
|
|
owned = true;
|
|
|
} else {
|
|
|
Object.keys(priv.teams || {}).some(function (id) {
|
|
|
var team = priv.teams[id] || {};
|
|
|
if (team.viewer) { return; }
|
|
|
if (data.owners.indexOf(team.edPublic) === -1) { return; }
|
|
|
owned = id;
|
|
|
return true;
|
|
|
});
|
|
|
}
|
|
|
var strangers = 0;
|
|
|
data.owners.forEach(function (ed) {
|
|
|
// If a friend is an owner, add their name to the list
|
|
|
// otherwise, increment the list of strangers
|
|
|
|
|
|
// Our edPublic? print "Yourself"
|
|
|
if (ed === edPublic) {
|
|
|
_owners[ed] = {
|
|
|
selected: true,
|
|
|
name: user.name,
|
|
|
avatar: user.avatar
|
|
|
};
|
|
|
return;
|
|
|
}
|
|
|
// One of our teams? print the team name
|
|
|
if (Object.keys(priv.teams || {}).some(function (id) {
|
|
|
var team = priv.teams[id] || {};
|
|
|
if (team.edPublic !== ed) { return; }
|
|
|
_owners[ed] = {
|
|
|
name: team.name,
|
|
|
avatar: team.avatar
|
|
|
};
|
|
|
return true;
|
|
|
})) {
|
|
|
return;
|
|
|
}
|
|
|
// One of our friends? print the friend name
|
|
|
if (Object.keys(priv.friends || {}).some(function (c) {
|
|
|
var friend = priv.friends[c] || {};
|
|
|
if (friend.edPublic !== ed || c === 'me') { return; }
|
|
|
_owners[friend.edPublic] = {
|
|
|
name: friend.displayName,
|
|
|
avatar: friend.avatar
|
|
|
};
|
|
|
return true;
|
|
|
})) {
|
|
|
return;
|
|
|
}
|
|
|
// Otherwise it's a stranger
|
|
|
strangers++;
|
|
|
});
|
|
|
if (strangers) {
|
|
|
_owners['stangers'] = {
|
|
|
name: Messages._getKey('properties_unknownUser', [strangers]),
|
|
|
};
|
|
|
}
|
|
|
}
|
|
|
var _ownersGrid = UIElements.getUserGrid(Messages.creation_owners, {
|
|
|
common: common,
|
|
|
noSelect: true,
|
|
|
data: _owners,
|
|
|
large: true
|
|
|
}, function () {});
|
|
|
if (_ownersGrid && Object.keys(_owners).length) {
|
|
|
$d.append(_ownersGrid.div);
|
|
|
} else {
|
|
|
$d.append([
|
|
|
h('label', Messages.creation_owners),
|
|
|
]);
|
|
|
$d.append(UI.dialog.selectable(Messages.creation_noOwner, {
|
|
|
id: 'cp-app-prop-owners',
|
|
|
}));
|
|
|
|
|
|
}
|
|
|
|
|
|
var parsed;
|
|
|
if (data.href || data.roHref) {
|
|
|
parsed = Hash.parsePadUrl(data.href || data.roHref);
|
|
|
}
|
|
|
if (owned && parsed.hashData.type === 'pad') {
|
|
|
var manageOwners = h('button.no-margin', Messages.owner_openModalButton);
|
|
|
$(manageOwners).click(function () {
|
|
|
data.teamId = typeof(owned) !== "boolean" ? owned : undefined;
|
|
|
var modal = createOwnerModal(common, data);
|
|
|
UI.openCustomModal(modal, {
|
|
|
wide: true,
|
|
|
});
|
|
|
});
|
|
|
$d.append(h('p', manageOwners));
|
|
|
}
|
|
|
|
|
|
if (!data.noExpiration) {
|
|
|
var expire = Messages.creation_expireFalse;
|
|
|
if (data.expire && typeof (data.expire) === "number") {
|
|
|
expire = new Date(data.expire).toLocaleString();
|
|
|
}
|
|
|
$('<label>', {'for': 'cp-app-prop-expire'}).text(Messages.creation_expiration)
|
|
|
.appendTo($d);
|
|
|
$d.append(UI.dialog.selectable(expire, {
|
|
|
id: 'cp-app-prop-expire',
|
|
|
}));
|
|
|
}
|
|
|
|
|
|
if (!data.noPassword) {
|
|
|
var hasPassword = data.password;
|
|
|
if (hasPassword) {
|
|
|
$('<label>', {'for': 'cp-app-prop-password'}).text(Messages.creation_passwordValue)
|
|
|
.appendTo($d);
|
|
|
var password = UI.passwordInput({
|
|
|
id: 'cp-app-prop-password',
|
|
|
readonly: 'readonly'
|
|
|
});
|
|
|
var $pwInput = $(password).find('.cp-password-input');
|
|
|
$pwInput.val(data.password).click(function () {
|
|
|
$pwInput[0].select();
|
|
|
});
|
|
|
$d.append(password);
|
|
|
}
|
|
|
|
|
|
if (!data.noEditPassword && owned) { // FIXME SHEET fix password change for sheets
|
|
|
var sframeChan = common.getSframeChannel();
|
|
|
|
|
|
var isOO = parsed.type === 'sheet';
|
|
|
var isFile = parsed.hashData.type === 'file';
|
|
|
var isSharedFolder = parsed.type === 'drive';
|
|
|
|
|
|
var changePwTitle = Messages.properties_changePassword;
|
|
|
var changePwConfirm = isFile ? Messages.properties_confirmChangeFile : Messages.properties_confirmChange;
|
|
|
if (!hasPassword) {
|
|
|
changePwTitle = Messages.properties_addPassword;
|
|
|
changePwConfirm = isFile ? Messages.properties_confirmNewFile : Messages.properties_confirmNew;
|
|
|
}
|
|
|
$('<label>', {'for': 'cp-app-prop-change-password'})
|
|
|
.text(changePwTitle).appendTo($d);
|
|
|
var newPassword = UI.passwordInput({
|
|
|
id: 'cp-app-prop-change-password',
|
|
|
style: 'flex: 1;'
|
|
|
});
|
|
|
var passwordOk = h('button', Messages.properties_changePasswordButton);
|
|
|
var changePass = h('span.cp-password-change-container', [
|
|
|
newPassword,
|
|
|
passwordOk
|
|
|
]);
|
|
|
var pLocked = false;
|
|
|
$(passwordOk).click(function () {
|
|
|
var newPass = $(newPassword).find('input').val();
|
|
|
if (data.password === newPass ||
|
|
|
(!data.password && !newPass)) {
|
|
|
return void UI.alert(Messages.properties_passwordSame);
|
|
|
}
|
|
|
if (pLocked) { return; }
|
|
|
pLocked = true;
|
|
|
UI.confirm(changePwConfirm, function (yes) {
|
|
|
if (!yes) { pLocked = false; return; }
|
|
|
$(passwordOk).html('').append(h('span.fa.fa-spinner.fa-spin', {style: 'margin-left: 0'}));
|
|
|
var q = isFile ? 'Q_BLOB_PASSWORD_CHANGE' :
|
|
|
(isOO ? 'Q_OO_PASSWORD_CHANGE' : 'Q_PAD_PASSWORD_CHANGE');
|
|
|
|
|
|
// If this is a file password change, register to the upload events:
|
|
|
// * if there is a pending upload, ask if we shoudl interrupt
|
|
|
// * display upload progress
|
|
|
var onPending;
|
|
|
var onProgress;
|
|
|
if (isFile) {
|
|
|
onPending = sframeChan.on('Q_BLOB_PASSWORD_CHANGE_PENDING', function (data, cb) {
|
|
|
onPending.stop();
|
|
|
UI.confirm(Messages.upload_uploadPending, function (yes) {
|
|
|
cb({cancel: yes});
|
|
|
});
|
|
|
});
|
|
|
onProgress = sframeChan.on('EV_BLOB_PASSWORD_CHANGE_PROGRESS', function (data) {
|
|
|
if (typeof (data) !== "number") { return; }
|
|
|
var p = Math.round(data);
|
|
|
$(passwordOk).text(p + '%');
|
|
|
});
|
|
|
}
|
|
|
|
|
|
sframeChan.query(q, {
|
|
|
teamId: typeof(owned) !== "boolean" ? owned : undefined,
|
|
|
href: data.href || data.roHref,
|
|
|
password: newPass
|
|
|
}, function (err, data) {
|
|
|
$(passwordOk).text(Messages.properties_changePasswordButton);
|
|
|
pLocked = false;
|
|
|
if (err || data.error) {
|
|
|
console.error(err || data.error);
|
|
|
return void UI.alert(Messages.properties_passwordError);
|
|
|
}
|
|
|
UI.findOKButton().click();
|
|
|
if (isFile) {
|
|
|
onProgress.stop();
|
|
|
$(passwordOk).text(Messages.properties_changePasswordButton);
|
|
|
var alertMsg = data.warning ? Messages.properties_passwordWarningFile
|
|
|
: Messages.properties_passwordSuccessFile;
|
|
|
return void UI.alert(alertMsg, undefined, {force: true});
|
|
|
}
|
|
|
// If we didn't have a password, we have to add the /p/
|
|
|
// If we had a password and we changed it to a new one, we just have to reload
|
|
|
// If we had a password and we removed it, we have to remove the /p/
|
|
|
if (data.warning) {
|
|
|
return void UI.alert(Messages.properties_passwordWarning, function () {
|
|
|
common.gotoURL(hasPassword && newPass ? undefined : (data.href || data.roHref));
|
|
|
}, {force: true});
|
|
|
}
|
|
|
return void UI.alert(Messages.properties_passwordSuccess, function () {
|
|
|
if (!isSharedFolder) {
|
|
|
common.gotoURL(hasPassword && newPass ? undefined : (data.href || data.roHref));
|
|
|
}
|
|
|
}, {force: true});
|
|
|
});
|
|
|
});
|
|
|
});
|
|
|
$d.append(changePass);
|
|
|
}
|
|
|
}
|
|
|
return $d;
|
|
|
};
|
|
|
|
|
|
var sframeChan = common.getSframeChannel();
|
|
|
var handler = sframeChan.on('EV_RT_METADATA', function (md) {
|
|
|
if (!$div.length) {
|
|
|
handler.stop();
|
|
|
return;
|
|
|
}
|
|
|
md = JSON.parse(JSON.stringify(md));
|
|
|
data.owners = md.owners;
|
|
|
data.expire = md.expire;
|
|
|
data.pending_owners = md.pending_owners;
|
|
|
$div.empty();
|
|
|
$div.append(draw());
|
|
|
});
|
|
|
$div.append(draw());
|
|
|
|
|
|
cb(void 0, $div);
|
|
|
};
|
|
|
var getPadProperties = function (common, data, cb) {
|
|
|
var $d = $('<div>');
|
|
|
if (!data) { return void cb(void 0, $d); }
|
|
|
|
|
|
if (data.href) {
|
|
|
$('<label>', {'for': 'cp-app-prop-link'}).text(Messages.editShare).appendTo($d);
|
|
|
$d.append(UI.dialog.selectable(data.href, {
|
|
|
id: 'cp-app-prop-link',
|
|
|
}));
|
|
|
}
|
|
|
|
|
|
if (data.roHref) {
|
|
|
$('<label>', {'for': 'cp-app-prop-rolink'}).text(Messages.viewShare).appendTo($d);
|
|
|
$d.append(UI.dialog.selectable(data.roHref, {
|
|
|
id: 'cp-app-prop-rolink',
|
|
|
}));
|
|
|
}
|
|
|
|
|
|
if (data.tags && Array.isArray(data.tags)) {
|
|
|
$d.append(h('div.cp-app-prop', [Messages.fm_prop_tagsList, h('br'), h('span.cp-app-prop-content', data.tags.join(', '))]));
|
|
|
}
|
|
|
|
|
|
if (data.ctime) {
|
|
|
$d.append(h('div.cp-app-prop', [Messages.fm_creation, h('br'), h('span.cp-app-prop-content', new Date(data.ctime).toLocaleString())]));
|
|
|
}
|
|
|
|
|
|
if (data.atime) {
|
|
|
$d.append(h('div.cp-app-prop', [Messages.fm_lastAccess, h('br'), h('span.cp-app-prop-content', new Date(data.atime).toLocaleString())]));
|
|
|
}
|
|
|
|
|
|
if (common.isLoggedIn()) {
|
|
|
// check the size of this file...
|
|
|
var bytes = 0;
|
|
|
NThen(function (waitFor) {
|
|
|
var chan = [data.channel];
|
|
|
if (data.rtChannel) { chan.push(data.rtChannel); }
|
|
|
if (data.lastVersion) { chan.push(Hash.hrefToHexChannelId(data.lastVersion)); }
|
|
|
chan.forEach(function (c) {
|
|
|
common.getFileSize(c, waitFor(function (e, _bytes) {
|
|
|
if (e) {
|
|
|
// there was a problem with the RPC
|
|
|
console.error(e);
|
|
|
}
|
|
|
bytes += _bytes;
|
|
|
}));
|
|
|
});
|
|
|
}).nThen(function () {
|
|
|
if (bytes === 0) { return void cb(void 0, $d); }
|
|
|
var KB = Util.bytesToKilobytes(bytes);
|
|
|
|
|
|
var formatted = Messages._getKey('formattedKB', [KB]);
|
|
|
$d.append(h('div.cp-app-prop', [Messages.upload_size, h('br'), h('span.cp-app-prop-content', formatted)]));
|
|
|
|
|
|
if (data.sharedFolder && false) {
|
|
|
$('<label>', {'for': 'cp-app-prop-channel'}).text('Channel ID').appendTo($d);
|
|
|
if (AppConfig.pinBugRecovery) { $d.append(h('p', AppConfig.pinBugRecovery)); }
|
|
|
$d.append(UI.dialog.selectable(data.channel, {
|
|
|
id: 'cp-app-prop-link',
|
|
|
}));
|
|
|
}
|
|
|
|
|
|
cb(void 0, $d);
|
|
|
});
|
|
|
} else {
|
|
|
cb(void 0, $d);
|
|
|
}
|
|
|
|
|
|
|
|
|
};
|
|
|
UIElements.getProperties = function (common, data, cb) {
|
|
|
var c1;
|
|
|
var c2;
|
|
|
var button = [{
|
|
|
className: 'primary',
|
|
|
name: Messages.okButton,
|
|
|
onClick: function () {},
|
|
|
keys: [13]
|
|
|
}];
|
|
|
NThen(function (waitFor) {
|
|
|
getPadProperties(common, data, waitFor(function (e, c) {
|
|
|
c1 = UI.dialog.customModal(c[0], {
|
|
|
buttons: button
|
|
|
});
|
|
|
}));
|
|
|
getRightsProperties(common, data, waitFor(function (e, c) {
|
|
|
c2 = UI.dialog.customModal(c[0], {
|
|
|
buttons: button
|
|
|
});
|
|
|
}));
|
|
|
}).nThen(function () {
|
|
|
var tabs = UI.dialog.tabs([{
|
|
|
title: Messages.fc_prop,
|
|
|
content: c1
|
|
|
}, {
|
|
|
title: Messages.creation_propertiesTitle,
|
|
|
content: c2
|
|
|
}]);
|
|
|
cb (void 0, $(tabs));
|
|
|
});
|
|
|
};
|
|
|
|
|
|
UIElements.getUserGrid = function (label, config, onSelect) {
|
|
|
var common = config.common;
|
|
|
var users = config.data;
|
|
|
if (!users) { return; }
|
|
|
|
|
|
var icons = Object.keys(users).map(function (key, i) {
|
|
|
var data = users[key];
|
|
|
var name = data.displayName || data.name || Messages.anonymous;
|
|
|
var avatar = h('span.cp-usergrid-avatar.cp-avatar');
|
|
|
UIElements.displayAvatar(common, $(avatar), data.avatar, name);
|
|
|
return h('div.cp-usergrid-user'+(data.selected?'.cp-selected':'')+(config.large?'.large':''), {
|
|
|
'data-ed': data.edPublic,
|
|
|
'data-teamid': data.teamId,
|
|
|
'data-curve': data.curvePublic || '',
|
|
|
'data-name': name.toLowerCase(),
|
|
|
'data-order': i,
|
|
|
title: name,
|
|
|
style: 'order:'+i+';'
|
|
|
},[
|
|
|
avatar,
|
|
|
h('span.cp-usergrid-user-name', name)
|
|
|
]);
|
|
|
}).filter(function (x) { return x; });
|
|
|
|
|
|
var noOthers = icons.length === 0 ? '.cp-usergrid-empty' : '';
|
|
|
|
|
|
var inputFilter = h('input', {
|
|
|
placeholder: Messages.share_filterFriend
|
|
|
});
|
|
|
|
|
|
var div = h('div.cp-usergrid-container' + noOthers + (config.large?'.large':''), [
|
|
|
label ? h('label', label) : undefined,
|
|
|
h('div.cp-usergrid-filter', (config.noFilter || config.noSelect) ? undefined : [
|
|
|
inputFilter
|
|
|
]),
|
|
|
]);
|
|
|
var $div = $(div);
|
|
|
|
|
|
// Hide friends when they are filtered using the text input
|
|
|
var redraw = function () {
|
|
|
var name = $(inputFilter).val().trim().replace(/"/g, '').toLowerCase();
|
|
|
$div.find('.cp-usergrid-user').show();
|
|
|
if (name) {
|
|
|
$div.find('.cp-usergrid-user:not(.cp-selected):not([data-name*="'+name+'"])').hide();
|
|
|
}
|
|
|
};
|
|
|
$(inputFilter).on('keydown keyup change', redraw);
|
|
|
|
|
|
$(div).append(h('div.cp-usergrid-grid', icons));
|
|
|
if (!config.noSelect) {
|
|
|
$div.on('click', '.cp-usergrid-user', function () {
|
|
|
var sel = $(this).hasClass('cp-selected');
|
|
|
if (!sel) {
|
|
|
$(this).addClass('cp-selected');
|
|
|
} else {
|
|
|
var order = $(this).attr('data-order');
|
|
|
order = order ? 'order:'+order : '';
|
|
|
$(this).removeClass('cp-selected').attr('style', order);
|
|
|
}
|
|
|
onSelect();
|
|
|
});
|
|
|
}
|
|
|
|
|
|
return {
|
|
|
icons: icons,
|
|
|
div: div
|
|
|
};
|
|
|
};
|
|
|
|
|
|
|
|
|
var createShareWithFriends = function (config, onShare, linkGetter) {
|
|
|
var common = config.common;
|
|
|
var sframeChan = common.getSframeChannel();
|
|
|
var title = config.title;
|
|
|
var friends = config.friends;
|
|
|
var myName = common.getMetadataMgr().getUserData().name;
|
|
|
if (!friends) { return; }
|
|
|
var order = [];
|
|
|
|
|
|
var smallCurves = Object.keys(friends).map(function (c) {
|
|
|
return friends[c].curvePublic.slice(0,8);
|
|
|
});
|
|
|
|
|
|
var div = h('div.contains-nav');
|
|
|
var $div = $(div);
|
|
|
// Replace "copy link" by "share with friends" if at least one friend is selected
|
|
|
// Also create the "share with friends" button if it doesn't exist
|
|
|
var refreshButtons = function () {
|
|
|
var $nav = $div.closest('.alertify').find('nav');
|
|
|
|
|
|
var friendMode = $div.find('.cp-usergrid-user.cp-selected').length;
|
|
|
if (friendMode) {
|
|
|
$nav.find('button.cp-share-with-friends').prop('disabled', '');
|
|
|
} else {
|
|
|
$nav.find('button.cp-share-with-friends').prop('disabled', 'disabled');
|
|
|
}
|
|
|
};
|
|
|
|
|
|
config.noInclude = true;
|
|
|
Object.keys(friends).forEach(function (curve) {
|
|
|
var data = friends[curve];
|
|
|
if (curve.length > 40 && data.notifications) { return; }
|
|
|
delete friends[curve];
|
|
|
});
|
|
|
|
|
|
var friendsList = UIElements.getUserGrid(Messages.share_linkFriends, {
|
|
|
common: common,
|
|
|
data: friends,
|
|
|
noFilter: false,
|
|
|
large: true
|
|
|
}, refreshButtons);
|
|
|
var friendDiv = friendsList.div;
|
|
|
$div.append(friendDiv);
|
|
|
var others = friendsList.icons;
|
|
|
|
|
|
var privateData = common.getMetadataMgr().getPrivateData();
|
|
|
var teamsData = Util.tryParse(JSON.stringify(privateData.teams)) || {};
|
|
|
var teams = {};
|
|
|
Object.keys(teamsData).forEach(function (id) {
|
|
|
// config.teamId only exists when we're trying to share a pad from a team drive
|
|
|
// In this case, we don't want to share the pad with the current team
|
|
|
if (config.teamId && config.teamId === id) { return; }
|
|
|
if (!teamsData[id].hasSecondaryKey) { return; }
|
|
|
var t = teamsData[id];
|
|
|
teams[t.edPublic] = {
|
|
|
notifications: true,
|
|
|
displayName: t.name,
|
|
|
edPublic: t.edPublic,
|
|
|
avatar: t.avatar,
|
|
|
id: id
|
|
|
};
|
|
|
});
|
|
|
var teamsList = UIElements.getUserGrid(Messages.share_linkTeam, {
|
|
|
common: common,
|
|
|
noFilter: true,
|
|
|
large: true,
|
|
|
data: teams
|
|
|
}, refreshButtons);
|
|
|
$div.append(teamsList.div);
|
|
|
|
|
|
var shareButton = {
|
|
|
className: 'primary cp-share-with-friends',
|
|
|
name: Messages.share_withFriends,
|
|
|
onClick: function () {
|
|
|
var href;
|
|
|
NThen(function (waitFor) {
|
|
|
var w = waitFor();
|
|
|
// linkGetter can be async if this is a burn after reading URL
|
|
|
var res = linkGetter({}, function (url) {
|
|
|
if (!url) {
|
|
|
waitFor.abort();
|
|
|
return;
|
|
|
}
|
|
|
console.warn('BAR');
|
|
|
href = url;
|
|
|
setTimeout(w);
|
|
|
});
|
|
|
if (res && /^http/.test(res)) {
|
|
|
href = Hash.getRelativeHref(res);
|
|
|
setTimeout(w);
|
|
|
return;
|
|
|
}
|
|
|
}).nThen(function () {
|
|
|
var $friends = $div.find('.cp-usergrid-user.cp-selected');
|
|
|
$friends.each(function (i, el) {
|
|
|
var curve = $(el).attr('data-curve');
|
|
|
// Check if the selected element is a friend or a team
|
|
|
if (curve) { // Friend
|
|
|
if (!curve || !friends[curve]) { return; }
|
|
|
var friend = friends[curve];
|
|
|
if (!friend.notifications || !friend.curvePublic) { return; }
|
|
|
common.mailbox.sendTo("SHARE_PAD", {
|
|
|
href: href,
|
|
|
password: config.password,
|
|
|
isTemplate: config.isTemplate,
|
|
|
name: myName,
|
|
|
title: title
|
|
|
}, {
|
|
|
channel: friend.notifications,
|
|
|
curvePublic: friend.curvePublic
|
|
|
});
|
|
|
return;
|
|
|
}
|
|
|
// Team
|
|
|
var ed = $(el).attr('data-ed');
|
|
|
var team = teams[ed];
|
|
|
if (!team) { return; }
|
|
|
sframeChan.query('Q_STORE_IN_TEAM', {
|
|
|
href: href,
|
|
|
password: config.password,
|
|
|
path: config.isTemplate ? ['template'] : undefined,
|
|
|
title: title,
|
|
|
teamId: team.id
|
|
|
}, function (err) {
|
|
|
if (err) { return void console.error(err); }
|
|
|
});
|
|
|
});
|
|
|
|
|
|
UI.findCancelButton().click();
|
|
|
|
|
|
// Update the "recently shared with" array:
|
|
|
// Get the selected curves
|
|
|
var curves = $friends.toArray().map(function (el) {
|
|
|
return ($(el).attr('data-curve') || '').slice(0,8);
|
|
|
}).filter(function (x) { return x; });
|
|
|
// Prepend them to the "order" array
|
|
|
Array.prototype.unshift.apply(order, curves);
|
|
|
order = Util.deduplicateString(order);
|
|
|
// Make sure we don't have "old" friends and save
|
|
|
order = order.filter(function (curve) {
|
|
|
return smallCurves.indexOf(curve) !== -1;
|
|
|
});
|
|
|
common.setAttribute(['general', 'share-friends'], order);
|
|
|
if (onShare) {
|
|
|
onShare.fire();
|
|
|
}
|
|
|
});
|
|
|
},
|
|
|
keys: [13]
|
|
|
};
|
|
|
|
|
|
common.getAttribute(['general', 'share-friends'], function (err, val) {
|
|
|
order = val || [];
|
|
|
// Sort friends by "recently shared with"
|
|
|
others.sort(function (a, b) {
|
|
|
var ca = ($(a).attr('data-curve') || '').slice(0,8);
|
|
|
var cb = ($(b).attr('data-curve') || '').slice(0,8);
|
|
|
if (!ca && !cb) { return 0; }
|
|
|
if (!ca) { return 1; }
|
|
|
if (!cb) { return -1; }
|
|
|
var ia = order.indexOf(ca);
|
|
|
var ib = order.indexOf(cb);
|
|
|
if (ia === -1 && ib === -1) { return 0; }
|
|
|
if (ia === -1) { return 1; }
|
|
|
if (ib === -1) { return -1; }
|
|
|
return ia - ib;
|
|
|
});
|
|
|
// Reorder the friend icons
|
|
|
others.forEach(function (el, i) {
|
|
|
$(el).attr('data-order', i).css('order', i);
|
|
|
});
|
|
|
// Display them
|
|
|
$(friendDiv).find('.cp-usergrid-grid').detach();
|
|
|
$(friendDiv).append(h('div.cp-usergrid-grid', others));
|
|
|
refreshButtons();
|
|
|
});
|
|
|
return {
|
|
|
content: div,
|
|
|
buttons: [shareButton]
|
|
|
};
|
|
|
};
|
|
|
|
|
|
var noContactsMessage = function(common){
|
|
|
var metadataMgr = common.getMetadataMgr();
|
|
|
var data = metadataMgr.getUserData();
|
|
|
var origin = metadataMgr.getPrivateData().origin;
|
|
|
if (common.isLoggedIn()) {
|
|
|
return {
|
|
|
content: h('p', Messages.share_noContactsLoggedIn),
|
|
|
buttons: [{
|
|
|
className: 'secondary',
|
|
|
name: Messages.share_copyProfileLink,
|
|
|
onClick: function () {
|
|
|
var profile = data.profile ? (origin + '/profile/#' + data.profile) : '';
|
|
|
var success = Clipboard.copy(profile);
|
|
|
if (success) { UI.log(Messages.shareSuccess); }
|
|
|
},
|
|
|
keys: [13]
|
|
|
}]
|
|
|
};
|
|
|
} else {
|
|
|
return {
|
|
|
content: h('p', Messages.share_noContactsNotLoggedIn),
|
|
|
buttons: [{
|
|
|
className: 'secondary',
|
|
|
name: Messages.login_register,
|
|
|
onClick: function () {
|
|
|
common.setLoginRedirect(function () {
|
|
|
common.gotoURL('/register/');
|
|
|
});
|
|
|
}
|
|
|
}, {
|
|
|
className: 'secondary',
|
|
|
name: Messages.login_login,
|
|
|
onClick: function () {
|
|
|
common.setLoginRedirect(function () {
|
|
|
common.gotoURL('/login/');
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
]
|
|
|
};
|
|
|
}
|
|
|
};
|
|
|
|
|
|
var makeBurnAfterReadingUrl = function (common, href, channel, cb) {
|
|
|
var keyPair = Hash.generateSignPair();
|
|
|
var parsed = Hash.parsePadUrl(href);
|
|
|
console.error(href, parsed);
|
|
|
var newHref = parsed.getUrl({
|
|
|
ownerKey: keyPair.safeSignKey
|
|
|
});
|
|
|
var sframeChan = common.getSframeChannel();
|
|
|
NThen(function (waitFor) {
|
|
|
sframeChan.query('Q_SET_PAD_METADATA', {
|
|
|
channel: channel,
|
|
|
command: 'ADD_OWNERS',
|
|
|
value: [keyPair.validateKey]
|
|
|
}, waitFor(function (err) {
|
|
|
if (err) {
|
|
|
waitFor.abort();
|
|
|
UI.warn(Messages.error);
|
|
|
}
|
|
|
}));
|
|
|
}).nThen(function () {
|
|
|
cb(newHref);
|
|
|
});
|
|
|
};
|
|
|
UIElements.createShareModal = function (config) {
|
|
|
var origin = config.origin;
|
|
|
var pathname = config.pathname;
|
|
|
var hashes = config.hashes;
|
|
|
var common = config.common;
|
|
|
|
|
|
if (!hashes || (!hashes.editHash && !hashes.viewHash)) { return; }
|
|
|
|
|
|
// check if the pad is password protected
|
|
|
var hash = hashes.editHash || hashes.viewHash;
|
|
|
var href = origin + pathname + '#' + hash;
|
|
|
var parsedHref = Hash.parsePadUrl(href);
|
|
|
var hasPassword = parsedHref.hashData.password;
|
|
|
|
|
|
var makeFaqLink = function () {
|
|
|
var link = h('span', [
|
|
|
h('i.fa.fa-question-circle'),
|
|
|
h('a', {href: '#'}, Messages.passwordFaqLink)
|
|
|
]);
|
|
|
$(link).click(function () {
|
|
|
common.openURL(config.origin + "/faq.html#security-pad_password");
|
|
|
});
|
|
|
return link;
|
|
|
};
|
|
|
|
|
|
|
|
|
var parsed = Hash.parsePadUrl(pathname);
|
|
|
var canPresent = ['code', 'slide'].indexOf(parsed.type) !== -1;
|
|
|
|
|
|
var burnAfterReading;
|
|
|
var rights = h('div.msg.cp-inline-radio-group', [
|
|
|
h('label', Messages.share_linkAccess),
|
|
|
h('div.radio-group',[
|
|
|
UI.createRadio('accessRights', 'cp-share-editable-false',
|
|
|
Messages.share_linkView, true, { mark: {tabindex:1} }),
|
|
|
canPresent ? UI.createRadio('accessRights', 'cp-share-present',
|
|
|
Messages.share_linkPresent, false, { mark: {tabindex:1} }) : undefined,
|
|
|
UI.createRadio('accessRights', 'cp-share-editable-true',
|
|
|
Messages.share_linkEdit, false, { mark: {tabindex:1} })]),
|
|
|
burnAfterReading = hashes.viewHash ? UI.createRadio('accessRights', 'cp-share-bar',
|
|
|
'View once and self-destruct', false, { mark: {tabindex:1}, label: {style: "display: none;"} }) : undefined // XXX KEY
|
|
|
]);
|
|
|
|
|
|
// Burn after reading
|
|
|
// Check if we are an owner of this pad. If we are, we can show the burn after reading option.
|
|
|
// When BAR is selected, display a red message indicating the consequence and add
|
|
|
// the options to generate the BAR url
|
|
|
var barAlert = h('div.alert.alert-danger.cp-alertify-bar-selected', {
|
|
|
style: 'display: none;'
|
|
|
}, " You have set this pad to self-destruct. Once a recipient opens this pad, it will be permanently deleted from the server. "); // XXX KEY
|
|
|
var channel = Hash.getSecrets('pad', hash, config.password).channel;
|
|
|
common.getPadMetadata({
|
|
|
channel: channel
|
|
|
}, function (obj) {
|
|
|
if (!obj || obj.error) { return; }
|
|
|
var priv = common.getMetadataMgr().getPrivateData();
|
|
|
// Not an owner: don't display the burn after reading option
|
|
|
if (!Array.isArray(obj.owners) || obj.owners.indexOf(priv.edPublic) === -1) {
|
|
|
$(burnAfterReading).remove();
|
|
|
return;
|
|
|
}
|
|
|
// When the burn after reading option is selected, transform the modal buttons
|
|
|
$(burnAfterReading).show();
|
|
|
});
|
|
|
|
|
|
var $rights = $(rights);
|
|
|
|
|
|
var saveValue = function () {
|
|
|
var edit = Util.isChecked($rights.find('#cp-share-editable-true'));
|
|
|
var present = Util.isChecked($rights.find('#cp-share-present'));
|
|
|
common.setAttribute(['general', 'share'], {
|
|
|
edit: edit,
|
|
|
present: present
|
|
|
});
|
|
|
};
|
|
|
|
|
|
var burnAfterReadingUrl;
|
|
|
|
|
|
var getLinkValue = function (initValue, cb) {
|
|
|
var val = initValue || {};
|
|
|
var edit = val.edit !== undefined ? val.edit : Util.isChecked($rights.find('#cp-share-editable-true'));
|
|
|
var embed = val.embed;
|
|
|
var present = val.present !== undefined ? val.present : Util.isChecked($rights.find('#cp-share-present'));
|
|
|
var burnAfterReading = Util.isChecked($rights.find('#cp-share-bar'));
|
|
|
if (burnAfterReading && !burnAfterReadingUrl) {
|
|
|
if (cb) { // Called from the contacts tab, "share" button
|
|
|
var barHref = origin + pathname + '#' + (hashes.viewHash || hashes.editHash);
|
|
|
return makeBurnAfterReadingUrl(common, barHref, channel, function (url) {
|
|
|
cb(url);
|
|
|
});
|
|
|
}
|
|
|
return 'Click on the button below to generate a link'; // XXX KEY
|
|
|
}
|
|
|
var hash = (!hashes.viewHash || (edit && hashes.editHash)) ? hashes.editHash : hashes.viewHash;
|
|
|
var href = burnAfterReading ? burnAfterReadingUrl : (origin + pathname + '#' + hash);
|
|
|
var parsed = Hash.parsePadUrl(href);
|
|
|
return origin + parsed.getUrl({embed: embed, present: present});
|
|
|
};
|
|
|
|
|
|
var makeCancelButton = function() {
|
|
|
return {
|
|
|
className: 'cancel',
|
|
|
name: Messages.cancel,
|
|
|
onClick: function () {},
|
|
|
keys: [27]
|
|
|
};
|
|
|
};
|
|
|
|
|
|
// Share link tab
|
|
|
var linkContent = config.sharedFolder ? [
|
|
|
h('label', Messages.sharedFolders_share),
|
|
|
h('br'),
|
|
|
] : [
|
|
|
UI.createCheckbox('cp-share-embed', Messages.share_linkEmbed, false, { mark: {tabindex:1} }),
|
|
|
];
|
|
|
linkContent.push(h('div.cp-spacer'));
|
|
|
linkContent.push(UI.dialog.selectableArea('', { id: 'cp-share-link-preview', tabindex: 1, rows:3}));
|
|
|
|
|
|
// Show alert if the pad is password protected
|
|
|
if (hasPassword) {
|
|
|
linkContent.push(h('div.alert.alert-primary', [
|
|
|
h('i.fa.fa-lock'),
|
|
|
Messages.share_linkPasswordAlert, h('br'),
|
|
|
makeFaqLink()
|
|
|
]));
|
|
|
}
|
|
|
|
|
|
// warning about sharing links
|
|
|
var localStore = window.cryptpadStore;
|
|
|
var dismissButton = h('span.fa.fa-times');
|
|
|
var shareLinkWarning = h('div.alert.alert-warning.dismissable',
|
|
|
{ style: 'display: none;' },
|
|
|
[
|
|
|
h('span.cp-inline-alert-text', Messages.share_linkWarning),
|
|
|
dismissButton
|
|
|
]);
|
|
|
linkContent.push(shareLinkWarning);
|
|
|
|
|
|
localStore.get('hide-alert-shareLinkWarning', function (val) {
|
|
|
if (val === '1') { return; }
|
|
|
$(shareLinkWarning).show();
|
|
|
|
|
|
$(dismissButton).on('click', function () {
|
|
|
localStore.put('hide-alert-shareLinkWarning', '1');
|
|
|
$(shareLinkWarning).remove();
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
linkContent.push($(barAlert).clone()[0]); // Burn after reading
|
|
|
|
|
|
var link = h('div.cp-share-modal', linkContent);
|
|
|
var $link = $(link);
|
|
|
|
|
|
var linkButtons = [
|
|
|
makeCancelButton(),
|
|
|
!config.sharedFolder && {
|
|
|
className: 'secondary cp-nobar',
|
|
|
name: Messages.share_linkOpen,
|
|
|
onClick: function () {
|
|
|
saveValue();
|
|
|
var v = getLinkValue({
|
|
|
embed: Util.isChecked($link.find('#cp-share-embed'))
|
|
|
});
|
|
|
window.open(v);
|
|
|
return true;
|
|
|
},
|
|
|
keys: [[13, 'ctrl']]
|
|
|
}, {
|
|
|
className: 'primary cp-nobar',
|
|
|
name: Messages.share_linkCopy,
|
|
|
onClick: function () {
|
|
|
saveValue();
|
|
|
var v = getLinkValue({
|
|
|
embed: Util.isChecked($link.find('#cp-share-embed'))
|
|
|
});
|
|
|
var success = Clipboard.copy(v);
|
|
|
if (success) { UI.log(Messages.shareSuccess); }
|
|
|
},
|
|
|
keys: [13]
|
|
|
}, {
|
|
|
className: 'primary cp-bar',
|
|
|
name: 'GENERATE LINK',
|
|
|
onClick: function () {
|
|
|
var barHref = origin + pathname + '#' + (hashes.viewHash || hashes.editHash);
|
|
|
makeBurnAfterReadingUrl(common, barHref, channel, function (url) {
|
|
|
burnAfterReadingUrl = url;
|
|
|
$rights.find('input[type="radio"]').trigger('change');
|
|
|
});
|
|
|
return true;
|
|
|
},
|
|
|
keys: []
|
|
|
}
|
|
|
];
|
|
|
|
|
|
var frameLink = UI.dialog.customModal(link, {
|
|
|
buttons: linkButtons,
|
|
|
onClose: config.onClose,
|
|
|
});
|
|
|
$(frameLink).find('.cp-bar').hide();
|
|
|
|
|
|
// Share with contacts tab
|
|
|
|
|
|
var hasFriends = Object.keys(config.friends || {}).length !== 0;
|
|
|
var onFriendShare = Util.mkEvent();
|
|
|
|
|
|
|
|
|
var friendsObject = hasFriends ? createShareWithFriends(config, onFriendShare, getLinkValue) : noContactsMessage(common);
|
|
|
var friendsList = friendsObject.content;
|
|
|
|
|
|
onFriendShare.reg(saveValue);
|
|
|
|
|
|
// XXX Don't display access rights if no contacts
|
|
|
var contactsContent = h('div.cp-share-modal');
|
|
|
var $contactsContent = $(contactsContent);
|
|
|
|
|
|
$contactsContent.append(friendsList);
|
|
|
|
|
|
// Show alert if the pad is password protected
|
|
|
if (hasPassword) {
|
|
|
$contactsContent.append(h('div.alert.alert-primary', [
|
|
|
h('i.fa.fa-unlock'),
|
|
|
Messages.share_contactPasswordAlert, h('br'),
|
|
|
makeFaqLink()
|
|
|
]));
|
|
|
}
|
|
|
|
|
|
$(contactsContent).append($(barAlert).clone()); // Burn after reading
|
|
|
|
|
|
var contactButtons = friendsObject.buttons;
|
|
|
contactButtons.unshift(makeCancelButton());
|
|
|
|
|
|
var onShowContacts = function () {
|
|
|
if (!hasFriends) {
|
|
|
$rights.hide();
|
|
|
}
|
|
|
};
|
|
|
|
|
|
var frameContacts = UI.dialog.customModal(contactsContent, {
|
|
|
buttons: contactButtons,
|
|
|
onClose: config.onClose,
|
|
|
});
|
|
|
|
|
|
// Embed tab
|
|
|
var getEmbedValue = function () {
|
|
|
var url = getLinkValue({
|
|
|
embed: true
|
|
|
});
|
|
|
return '<iframe src="' + url + '"></iframe>';
|
|
|
};
|
|
|
var embedContent = [
|
|
|
h('p', Messages.viewEmbedTag),
|
|
|
UI.dialog.selectableArea(getEmbedValue(), { id: 'cp-embed-link-preview', tabindex: 1, rows: 3})
|
|
|
];
|
|
|
|
|
|
// Show alert if the pad is password protected
|
|
|
if (hasPassword) {
|
|
|
embedContent.push(h('div.alert.alert-primary', [
|
|
|
h('i.fa.fa-lock'), ' ',
|
|
|
Messages.share_embedPasswordAlert, h('br'),
|
|
|
makeFaqLink()
|
|
|
]));
|
|
|
}
|
|
|
|
|
|
var embedButtons = [
|
|
|
makeCancelButton(), {
|
|
|
className: 'primary',
|
|
|
name: Messages.share_linkCopy,
|
|
|
onClick: function () {
|
|
|
var v = getEmbedValue();
|
|
|
var success = Clipboard.copy(v);
|
|
|
if (success) { UI.log(Messages.shareSuccess); }
|
|
|
},
|
|
|
keys: [13]
|
|
|
}];
|
|
|
|
|
|
var onShowEmbed = function () {
|
|
|
$rights.find('#cp-share-bar').closest('label').hide();
|
|
|
$rights.find('input[type="radio"]:enabled').first().prop('checked', 'checked');
|
|
|
$rights.find('input[type="radio"]').trigger('change');
|
|
|
};
|
|
|
|
|
|
var embed = h('div.cp-share-modal', embedContent);
|
|
|
var $embed = $(embed);
|
|
|
|
|
|
var frameEmbed = UI.dialog.customModal(embed, {
|
|
|
buttons: embedButtons,
|
|
|
onClose: config.onClose,
|
|
|
});
|
|
|
|
|
|
// update values for link and embed preview when radio btns change
|
|
|
$embed.find('#cp-embed-link-preview').val(getEmbedValue());
|
|
|
$link.find('#cp-share-link-preview').val(getLinkValue());
|
|
|
$rights.find('input[type="radio"]').on('change', function () {
|
|
|
$link.find('#cp-share-link-preview').val(getLinkValue({
|
|
|
embed: Util.isChecked($link.find('#cp-share-embed'))
|
|
|
}));
|
|
|
// Hide or show the burn after reading alert
|
|
|
if (Util.isChecked($rights.find('#cp-share-bar')) && !burnAfterReadingUrl) {
|
|
|
$('.cp-alertify-bar-selected').show();
|
|
|
// Show burn after reading button
|
|
|
$('.alertify').find('.cp-bar').show();
|
|
|
$('.alertify').find('.cp-nobar').hide();
|
|
|
return;
|
|
|
}
|
|
|
$embed.find('#cp-embed-link-preview').val(getEmbedValue());
|
|
|
// Hide burn after reading button
|
|
|
$('.alertify').find('.cp-nobar').show();
|
|
|
$('.alertify').find('.cp-bar').hide();
|
|
|
$('.cp-alertify-bar-selected').hide();
|
|
|
});
|
|
|
$link.find('input[type="checkbox"]').on('change', function () {
|
|
|
$link.find('#cp-share-link-preview').val(getLinkValue({
|
|
|
embed: Util.isChecked($link.find('#cp-share-embed'))
|
|
|
}));
|
|
|
});
|
|
|
|
|
|
|
|
|
// Create modal
|
|
|
var resetTab = function () {
|
|
|
$rights.show();
|
|
|
$rights.find('label.cp-radio').show();
|
|
|
};
|
|
|
var tabs = [{
|
|
|
title: Messages.share_contactCategory,
|
|
|
icon: "fa fa-address-book",
|
|
|
content: frameContacts,
|
|
|
active: hasFriends,
|
|
|
onShow: onShowContacts,
|
|
|
onHide: resetTab
|
|
|
}, {
|
|
|
title: Messages.share_linkCategory,
|
|
|
icon: "fa fa-link",
|
|
|
content: frameLink,
|
|
|
active: !hasFriends
|
|
|
}, {
|
|
|
title: Messages.share_embedCategory,
|
|
|
icon: "fa fa-code",
|
|
|
content: frameEmbed,
|
|
|
onShow: onShowEmbed,
|
|
|
onHide: resetTab
|
|
|
}];
|
|
|
if (typeof(AppConfig.customizeShareOptions) === 'function') {
|
|
|
AppConfig.customizeShareOptions(hashes, tabs, {
|
|
|
type: 'DEFAULT',
|
|
|
origin: origin,
|
|
|
pathname: pathname
|
|
|
});
|
|
|
}
|
|
|
|
|
|
var modal = UI.dialog.tabs(tabs);
|
|
|
$(modal).find('.alertify-tabs-titles').after(rights);
|
|
|
|
|
|
// disable edit share options if you don't have edit rights
|
|
|
if (!hashes.editHash) {
|
|
|
$rights.find('#cp-share-editable-false').attr('checked', true);
|
|
|
$rights.find('#cp-share-editable-true').removeAttr('checked').attr('disabled', true);
|
|
|
} else if (!hashes.viewHash) {
|
|
|
$rights.find('#cp-share-editable-false').removeAttr('checked').attr('disabled', true);
|
|
|
$rights.find('#cp-share-present').removeAttr('checked').attr('disabled', true);
|
|
|
$rights.find('#cp-share-editable-true').attr('checked', true);
|
|
|
}
|
|
|
|
|
|
common.getAttribute(['general', 'share'], function (err, val) {
|
|
|
val = val || {};
|
|
|
if (val.present && canPresent) {
|
|
|
$rights.find('#cp-share-editable-false').prop('checked', false);
|
|
|
$rights.find('#cp-share-editable-true').prop('checked', false);
|
|
|
$rights.find('#cp-share-present').prop('checked', true);
|
|
|
} else if ((val.edit === false && hashes.viewHash) || !hashes.editHash) {
|
|
|
$rights.find('#cp-share-editable-false').prop('checked', true);
|
|
|
$rights.find('#cp-share-editable-true').prop('checked', false);
|
|
|
$rights.find('#cp-share-present').prop('checked', false);
|
|
|
} else {
|
|
|
$rights.find('#cp-share-editable-true').prop('checked', true);
|
|
|
$rights.find('#cp-share-editable-false').prop('checked', false);
|
|
|
$rights.find('#cp-share-present').prop('checked', false);
|
|
|
}
|
|
|
delete val.embed;
|
|
|
if (!canPresent) {
|
|
|
delete val.present;
|
|
|
}
|
|
|
$link.find('#cp-share-link-preview').val(getLinkValue(val));
|
|
|
});
|
|
|
common.getMetadataMgr().onChange(function () {
|
|
|
// "hashes" is only available is the secure "share" app
|
|
|
var _hashes = common.getMetadataMgr().getPrivateData().hashes;
|
|
|
if (!_hashes) { return; }
|
|
|
hashes = _hashes;
|
|
|
$link.find('#cp-share-link-preview').val(getLinkValue());
|
|
|
});
|
|
|
return modal;
|
|
|
};
|
|
|
|
|
|
UIElements.createFileShareModal = function (config) {
|
|
|
var origin = config.origin;
|
|
|
var pathname = config.pathname;
|
|
|
var hashes = config.hashes;
|
|
|
var common = config.common;
|
|
|
var fileData = config.fileData;
|
|
|
|
|
|
if (!hashes.fileHash) { throw new Error("You must provide a file hash"); }
|
|
|
var url = origin + pathname + '#' + hashes.fileHash;
|
|
|
|
|
|
// check if the file is password protected
|
|
|
var parsedHref = Hash.parsePadUrl(url);
|
|
|
var hasPassword = parsedHref.hashData.password;
|
|
|
|
|
|
var makeFaqLink = function () {
|
|
|
var link = h('span', [
|
|
|
h('i.fa.fa-question-circle'),
|
|
|
h('a', {href: '#'}, Messages.passwordFaqLink)
|
|
|
]);
|
|
|
$(link).click(function () {
|
|
|
common.openURL(config.origin + "/faq.html#security-pad_password");
|
|
|
});
|
|
|
return link;
|
|
|
};
|
|
|
|
|
|
var getLinkValue = function () { return url; };
|
|
|
|
|
|
var makeCancelButton = function() {
|
|
|
return {className: 'cancel',
|
|
|
name: Messages.cancel,
|
|
|
onClick: function () {},
|
|
|
keys: [27]};
|
|
|
};
|
|
|
|
|
|
// Share link tab
|
|
|
var linkContent = [
|
|
|
UI.dialog.selectableArea(getLinkValue(), { id: 'cp-share-link-preview', tabindex: 1, rows:2 })
|
|
|
];
|
|
|
|
|
|
// Show alert if the pad is password protected
|
|
|
if (hasPassword) {
|
|
|
linkContent.push(h('div.alert.alert-primary', [
|
|
|
h('i.fa.fa-lock'),
|
|
|
Messages.share_linkPasswordAlert, h('br'),
|
|
|
makeFaqLink()
|
|
|
]));
|
|
|
}
|
|
|
|
|
|
// warning about sharing links
|
|
|
var localStore = window.cryptpadStore;
|
|
|
var dismissButton = h('span.fa.fa-times');
|
|
|
var shareLinkWarning = h('div.alert.alert-warning.dismissable',
|
|
|
{ style: 'display: none;' },
|
|
|
[
|
|
|
h('span.cp-inline-alert-text', Messages.share_linkWarning),
|
|
|
dismissButton
|
|
|
]);
|
|
|
linkContent.push(shareLinkWarning);
|
|
|
|
|
|
localStore.get('hide-alert-shareLinkWarning', function (val) {
|
|
|
if (val === '1') { return; }
|
|
|
$(shareLinkWarning).show();
|
|
|
|
|
|
$(dismissButton).on('click', function () {
|
|
|
localStore.put('hide-alert-shareLinkWarning', '1');
|
|
|
$(shareLinkWarning).remove();
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
var link = h('div.cp-share-modal', linkContent);
|
|
|
|
|
|
var linkButtons = [
|
|
|
makeCancelButton(),
|
|
|
{
|
|
|
className: 'primary',
|
|
|
name: Messages.share_linkCopy,
|
|
|
onClick: function () {
|
|
|
var v = getLinkValue();
|
|
|
var success = Clipboard.copy(v);
|
|
|
if (success) { UI.log(Messages.shareSuccess);
|
|
|
}
|
|
|
},
|
|
|
keys: [13]
|
|
|
}
|
|
|
];
|
|
|
|
|
|
var frameLink = UI.dialog.customModal(link, {
|
|
|
buttons: linkButtons,
|
|
|
onClose: config.onClose,
|
|
|
});
|
|
|
|
|
|
// share with contacts tab
|
|
|
var hasFriends = Object.keys(config.friends || {}).length !== 0;
|
|
|
|
|
|
var friendsObject = hasFriends ? createShareWithFriends(config, null, getLinkValue) : noContactsMessage(common);
|
|
|
var friendsList = friendsObject.content;
|
|
|
|
|
|
var contactsContent = h('div.cp-share-modal');
|
|
|
var $contactsContent = $(contactsContent);
|
|
|
$contactsContent.append(friendsList);
|
|
|
|
|
|
// Show alert if the pad is password protected
|
|
|
if (hasPassword) {
|
|
|
$contactsContent.append(h('div.alert.alert-primary', [
|
|
|
h('i.fa.fa-unlock'),
|
|
|
Messages.share_contactPasswordAlert, h('br'),
|
|
|
makeFaqLink()
|
|
|
]));
|
|
|
}
|
|
|
|
|
|
var contactButtons = friendsObject.buttons;
|
|
|
contactButtons.unshift(makeCancelButton());
|
|
|
|
|
|
var frameContacts = UI.dialog.customModal(contactsContent, {
|
|
|
buttons: contactButtons,
|
|
|
onClose: config.onClose,
|
|
|
});
|
|
|
|
|
|
|
|
|
// Embed tab
|
|
|
var embed = h('div.cp-share-modal', [
|
|
|
h('p', Messages.fileEmbedScript),
|
|
|
UI.dialog.selectable(common.getMediatagScript()),
|
|
|
h('p', Messages.fileEmbedTag),
|
|
|
UI.dialog.selectable(common.getMediatagFromHref(fileData)),
|
|
|
]);
|
|
|
|
|
|
// Show alert if the pad is password protected
|
|
|
if (hasPassword) {
|
|
|
embed.append(h('div.alert.alert-primary', [
|
|
|
h('i.fa.fa-lock'), ' ',
|
|
|
Messages.share_embedPasswordAlert, h('br'),
|
|
|
makeFaqLink()
|
|
|
]));
|
|
|
}
|
|
|
|
|
|
var embedButtons = [{
|
|
|
className: 'cancel',
|
|
|
name: Messages.cancel,
|
|
|
onClick: function () {},
|
|
|
keys: [27]
|
|
|
}, {
|
|
|
className: 'primary',
|
|
|
name: Messages.share_mediatagCopy,
|
|
|
onClick: function () {
|
|
|
var v = common.getMediatagFromHref(fileData);
|
|
|
var success = Clipboard.copy(v);
|
|
|
if (success) { UI.log(Messages.shareSuccess); }
|
|
|
},
|
|
|
keys: [13]
|
|
|
}];
|
|
|
var frameEmbed = UI.dialog.customModal(embed, {
|
|
|
buttons: embedButtons,
|
|
|
onClose: config.onClose,
|
|
|
});
|
|
|
|
|
|
// Create modal
|
|
|
var tabs = [{
|
|
|
title: Messages.share_contactCategory,
|
|
|
icon: "fa fa-address-book",
|
|
|
content: frameContacts,
|
|
|
active: hasFriends,
|
|
|
}, {
|
|
|
title: Messages.share_linkCategory,
|
|
|
icon: "fa fa-link",
|
|
|
content: frameLink,
|
|
|
active: !hasFriends
|
|
|
}, {
|
|
|
title: Messages.share_embedCategory,
|
|
|
icon: "fa fa-code",
|
|
|
content: frameEmbed
|
|
|
}];
|
|
|
if (typeof(AppConfig.customizeShareOptions) === 'function') {
|
|
|
AppConfig.customizeShareOptions(hashes, tabs, {
|
|
|
type: 'FILE',
|
|
|
origin: origin,
|
|
|
pathname: pathname
|
|
|
});
|
|
|
}
|
|
|
var modal = UI.dialog.tabs(tabs);
|
|
|
return modal;
|
|
|
};
|
|
|
|
|
|
UIElements.createInviteTeamModal = function (config) {
|
|
|
var common = config.common;
|
|
|
var hasFriends = Object.keys(config.friends || {}).length !== 0;
|
|
|
|
|
|
var privateData = common.getMetadataMgr().getPrivateData();
|
|
|
var team = privateData.teams[config.teamId];
|
|
|
if (!team) { return void UI.warn(Messages.error); }
|
|
|
|
|
|
var origin = privateData.origin;
|
|
|
|
|
|
var module = config.module || common.makeUniversal('team');
|
|
|
|
|
|
// Invite contacts
|
|
|
var $div;
|
|
|
var refreshButton = function () {
|
|
|
if (!$div) { return; }
|
|
|
var $modal = $div.closest('.alertify');
|
|
|
var $nav = $modal.find('nav');
|
|
|
var $btn = $nav.find('button.primary');
|
|
|
var selected = $div.find('.cp-usergrid-user.cp-selected').length;
|
|
|
if (selected) {
|
|
|
$btn.prop('disabled', '');
|
|
|
} else {
|
|
|
$btn.prop('disabled', 'disabled');
|
|
|
}
|
|
|
};
|
|
|
var getContacts = function () {
|
|
|
var list = UIElements.getUserGrid(Messages.team_pickFriends, {
|
|
|
common: common,
|
|
|
data: config.friends,
|
|
|
large: true
|
|
|
}, refreshButton);
|
|
|
var div = h('div.contains-nav');
|
|
|
var $div = $(div);
|
|
|
$div.append(list.div);
|
|
|
var contactsButtons = [{
|
|
|
className: 'primary',
|
|
|
name: Messages.team_inviteModalButton,
|
|
|
onClick: function () {
|
|
|
var $sel = $div.find('.cp-usergrid-user.cp-selected');
|
|
|
var sel = $sel.toArray();
|
|
|
if (!sel.length) { return; }
|
|
|
|
|
|
sel.forEach(function (el) {
|
|
|
var curve = $(el).attr('data-curve');
|
|
|
module.execCommand('INVITE_TO_TEAM', {
|
|
|
teamId: config.teamId,
|
|
|
user: config.friends[curve]
|
|
|
}, function (obj) {
|
|
|
if (obj && obj.error) {
|
|
|
console.error(obj.error);
|
|
|
return UI.warn(Messages.error);
|
|
|
}
|
|
|
});
|
|
|
});
|
|
|
},
|
|
|
keys: [13]
|
|
|
}];
|
|
|
|
|
|
return {
|
|
|
content: div,
|
|
|
buttons: contactsButtons
|
|
|
};
|
|
|
};
|
|
|
var friendsObject = hasFriends ? getContacts() : noContactsMessage(common);
|
|
|
var friendsList = friendsObject.content;
|
|
|
var contactsButtons = friendsObject.buttons;
|
|
|
contactsButtons.unshift({
|
|
|
className: 'cancel',
|
|
|
name: Messages.cancel,
|
|
|
onClick: function () {},
|
|
|
keys: [27]
|
|
|
});
|
|
|
|
|
|
var contactsContent = h('div.cp-share-modal', [
|
|
|
friendsList
|
|
|
]);
|
|
|
|
|
|
var frameContacts = UI.dialog.customModal(contactsContent, {
|
|
|
buttons: contactsButtons,
|
|
|
});
|
|
|
|
|
|
var linkName, linkPassword, linkMessage, linkError, linkSpinText;
|
|
|
var linkForm, linkSpin, linkResult;
|
|
|
var linkWarning;
|
|
|
// Invite from link
|
|
|
var dismissButton = h('span.fa.fa-times');
|
|
|
var linkContent = h('div.cp-share-modal', [
|
|
|
h('p', Messages.team_inviteLinkTitle ),
|
|
|
linkError = h('div.alert.alert-danger.cp-teams-invite-alert', {style : 'display: none;'}),
|
|
|
linkForm = h('div.cp-teams-invite-form', [
|
|
|
// autofill: 'off' was insufficient
|
|
|
// adding these two fake inputs confuses firefox and prevents unwanted form autofill
|
|
|
h('input', { type: 'text', style: 'display: none'}),
|
|
|
h('input', { type: 'password', style: 'display: none'}),
|
|
|
|
|
|
linkName = h('input', {
|
|
|
placeholder: Messages.team_inviteLinkTempName
|
|
|
}),
|
|
|
h('br'),
|
|
|
h('div.cp-teams-invite-block', [
|
|
|
h('span', Messages.team_inviteLinkSetPassword),
|
|
|
h('a.cp-teams-help.fa.fa-question-circle', {
|
|
|
href: origin + '/faq.html#security-pad_password',
|
|
|
target: "_blank",
|
|
|
'data-tippy-placement': "right"
|
|
|
})
|
|
|
]),
|
|
|
linkPassword = UI.passwordInput({
|
|
|
id: 'cp-teams-invite-password',
|
|
|
placeholder: Messages.login_password
|
|
|
}),
|
|
|
h('div.cp-teams-invite-block',
|
|
|
h('span', Messages.team_inviteLinkNote)
|
|
|
),
|
|
|
linkMessage = h('textarea.cp-teams-invite-message', {
|
|
|
placeholder: Messages.team_inviteLinkNoteMsg,
|
|
|
rows: 3
|
|
|
})
|
|
|
]),
|
|
|
linkSpin = h('div.cp-teams-invite-spinner', {
|
|
|
style: 'display: none;'
|
|
|
}, [
|
|
|
h('i.fa.fa-spinner.fa-spin'),
|
|
|
linkSpinText = h('span', Messages.team_inviteLinkLoading)
|
|
|
]),
|
|
|
linkResult = h('div', {
|
|
|
style: 'display: none;'
|
|
|
}, h('textarea', {
|
|
|
readonly: 'readonly'
|
|
|
})),
|
|
|
linkWarning = h('div.cp-teams-invite-alert.alert.alert-warning.dismissable', {
|
|
|
style: "display: none;"
|
|
|
}, [
|
|
|
h('span.cp-inline-alert-text', Messages.team_inviteLinkWarning),
|
|
|
dismissButton
|
|
|
])
|
|
|
]);
|
|
|
$(linkMessage).keydown(function (e) {
|
|
|
if (e.which === 13) {
|
|
|
e.stopPropagation();
|
|
|
}
|
|
|
});
|
|
|
var localStore = window.cryptpadStore;
|
|
|
localStore.get('hide-alert-teamInvite', function (val) {
|
|
|
if (val === '1') { return; }
|
|
|
$(linkWarning).show();
|
|
|
|
|
|
$(dismissButton).on('click', function () {
|
|
|
localStore.put('hide-alert-teamInvite', '1');
|
|
|
$(linkWarning).remove();
|
|
|
});
|
|
|
});
|
|
|
var $linkContent = $(linkContent);
|
|
|
var href;
|
|
|
var process = function () {
|
|
|
var $nav = $linkContent.closest('.alertify').find('nav');
|
|
|
$(linkError).text('').hide();
|
|
|
var name = $(linkName).val();
|
|
|
var pw = $(linkPassword).find('input').val();
|
|
|
var msg = $(linkMessage).val();
|
|
|
var hash = Hash.createRandomHash('invite', pw);
|
|
|
var hashData = Hash.parseTypeHash('invite', hash);
|
|
|
href = origin + '/teams/#' + hash;
|
|
|
if (!name || !name.trim()) {
|
|
|
$(linkError).text(Messages.team_inviteLinkErrorName).show();
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
var seeds = InviteInner.deriveSeeds(hashData.key);
|
|
|
var salt = InviteInner.deriveSalt(pw, AppConfig.loginSalt);
|
|
|
|
|
|
var bytes64;
|
|
|
NThen(function (waitFor) {
|
|
|
$(linkForm).hide();
|
|
|
$(linkSpin).show();
|
|
|
$nav.find('button.cp-teams-invite-create').hide();
|
|
|
$nav.find('button.cp-teams-invite-copy').show();
|
|
|
setTimeout(waitFor(), 150);
|
|
|
}).nThen(function (waitFor) {
|
|
|
InviteInner.deriveBytes(seeds.scrypt, salt, waitFor(function (_bytes) {
|
|
|
bytes64 = _bytes;
|
|
|
}));
|
|
|
}).nThen(function (waitFor) {
|
|
|
module.execCommand('CREATE_INVITE_LINK', {
|
|
|
name: name,
|
|
|
password: pw,
|
|
|
message: msg,
|
|
|
bytes64: bytes64,
|
|
|
hash: hash,
|
|
|
teamId: config.teamId,
|
|
|
seeds: seeds,
|
|
|
}, waitFor(function (obj) {
|
|
|
if (obj && obj.error) {
|
|
|
waitFor.abort();
|
|
|
$(linkSpin).hide();
|
|
|
$(linkForm).show();
|
|
|
$nav.find('button.cp-teams-invite-create').show();
|
|
|
$nav.find('button.cp-teams-invite-copy').hide();
|
|
|
return void $(linkError).text(Messages.team_inviteLinkError).show();
|
|
|
}
|
|
|
// Display result here
|
|
|
$(linkSpin).hide();
|
|
|
$(linkResult).show().find('textarea').text(href);
|
|
|
$nav.find('button.cp-teams-invite-copy').prop('disabled', '');
|
|
|
}));
|
|
|
});
|
|
|
return true;
|
|
|
};
|
|
|
var linkButtons = [{
|
|
|
className: 'cancel',
|
|
|
name: Messages.cancel,
|
|
|
onClick: function () {},
|
|
|
keys: [27]
|
|
|
}, {
|
|
|
className: 'primary cp-teams-invite-create',
|
|
|
name: Messages.team_inviteLinkCreate,
|
|
|
onClick: function () {
|
|
|
return process();
|
|
|
},
|
|
|
keys: []
|
|
|
}, {
|
|
|
className: 'primary cp-teams-invite-copy',
|
|
|
name: Messages.team_inviteLinkCopy,
|
|
|
onClick: function () {
|
|
|
if (!href) { return; }
|
|
|
var success = Clipboard.copy(href);
|
|
|
if (success) { UI.log(Messages.shareSuccess); }
|
|
|
},
|
|
|
keys: []
|
|
|
}];
|
|
|
|
|
|
var frameLink = UI.dialog.customModal(linkContent, {
|
|
|
buttons: linkButtons,
|
|
|
});
|
|
|
$(frameLink).find('.cp-teams-invite-copy').prop('disabled', 'disabled').hide();
|
|
|
|
|
|
// Create modal
|
|
|
var tabs = [{
|
|
|
title: Messages.share_contactCategory,
|
|
|
icon: "fa fa-address-book",
|
|
|
content: frameContacts,
|
|
|
active: hasFriends
|
|
|
}, {
|
|
|
title: Messages.share_linkCategory,
|
|
|
icon: "fa fa-link",
|
|
|
content: frameLink,
|
|
|
active: !hasFriends
|
|
|
}];
|
|
|
|
|
|
var modal = UI.dialog.tabs(tabs);
|
|
|
UI.openCustomModal(modal);
|
|
|
};
|
|
|
|
|
|
UIElements.createButton = function (common, type, rightside, data, callback) {
|
|
|
var AppConfig = common.getAppConfig();
|
|
|
var button;
|
|
|
var sframeChan = common.getSframeChannel();
|
|
|
var appType = (common.getMetadataMgr().getMetadata().type || 'pad').toUpperCase();
|
|
|
switch (type) {
|
|
|
case 'export':
|
|
|
button = $('<button>', {
|
|
|
'class': 'fa fa-download cp-toolbar-icon-export',
|
|
|
title: Messages.exportButtonTitle,
|
|
|
}).append($('<span>', {'class': 'cp-toolbar-drawer-element'}).text(Messages.exportButton));
|
|
|
|
|
|
button.click(common.prepareFeedback(type));
|
|
|
if (callback) {
|
|
|
button.click(callback);
|
|
|
}
|
|
|
break;
|
|
|
case 'import':
|
|
|
button = $('<button>', {
|
|
|
'class': 'fa fa-upload cp-toolbar-icon-import',
|
|
|
title: Messages.importButtonTitle,
|
|
|
}).append($('<span>', {'class': 'cp-toolbar-drawer-element'}).text(Messages.importButton));
|
|
|
/*if (data.types) {
|
|
|
// New import button in the toolbar
|
|
|
var importFunction = {
|
|
|
template: function () {
|
|
|
UIElements.openTemplatePicker(common, true);
|
|
|
},
|
|
|
file: function (cb) {
|
|
|
importContent('text/plain', function (content, file) {
|
|
|
cb(content, file);
|
|
|
}, {accept: data ? data.accept : undefined})
|
|
|
}
|
|
|
};
|
|
|
var toImport = [];
|
|
|
Object.keys(data.types).forEach(function (importType) {
|
|
|
if (!importFunction[importType] || !data.types[importType]) { return; }
|
|
|
var option = h('button', importType);
|
|
|
$(option).click(function () {
|
|
|
importFunction[importType](data.types[importType]);
|
|
|
});
|
|
|
toImport.push(options);
|
|
|
});
|
|
|
|
|
|
button.click(common.prepareFeedback(type));
|
|
|
|
|
|
if (toImport.length === 1) {
|
|
|
button.click(function () { $(toImport[0]).click(); });
|
|
|
} else {
|
|
|
Cryptpad.alert(h('p.cp-import-container', toImport));
|
|
|
}
|
|
|
}
|
|
|
else if (callback) {*/
|
|
|
// Old import button, used in settings
|
|
|
button
|
|
|
.click(common.prepareFeedback(type))
|
|
|
.click(importContent('text/plain', function (content, file) {
|
|
|
callback(content, file);
|
|
|
}, {accept: data ? data.accept : undefined}));
|
|
|
//}
|
|
|
break;
|
|
|
case 'upload':
|
|
|
button = $('<button>', {
|
|
|
'class': 'btn btn-primary new',
|
|
|
title: Messages.uploadButtonTitle,
|
|
|
}).append($('<span>', {'class':'fa fa-upload'})).append(' '+Messages.uploadButton);
|
|
|
if (!data.FM) { return; }
|
|
|
var $input = $('<input>', {
|
|
|
'type': 'file',
|
|
|
'style': 'display: none;',
|
|
|
'multiple': 'multiple'
|
|
|
}).on('change', function (e) {
|
|
|
var files = Util.slice(e.target.files);
|
|
|
files.forEach(function (file) {
|
|
|
var ev = {
|
|
|
target: data.target
|
|
|
};
|
|
|
if (data.filter && !data.filter(file)) {
|
|
|
return;
|
|
|
}
|
|
|
if (data.transformer) {
|
|
|
data.transformer(file, function (newFile) {
|
|
|
data.FM.handleFile(newFile, ev);
|
|
|
});
|
|
|
return;
|
|
|
}
|
|
|
data.FM.handleFile(file, ev);
|
|
|
});
|
|
|
if (callback) { callback(); }
|
|
|
});
|
|
|
if (data.accept) { $input.attr('accept', data.accept); }
|
|
|
button.click(function () { $input.click(); });
|
|
|
break;
|
|
|
case 'importtemplate':
|
|
|
if (!AppConfig.enableTemplates) { return; }
|
|
|
if (!common.isLoggedIn()) { return; }
|
|
|
button = $('<button>', {
|
|
|
'class': 'fa fa-upload cp-toolbar-icon-import',
|
|
|
title: Messages.template_import,
|
|
|
}).append($('<span>', {'class': 'cp-toolbar-drawer-element'}).text(Messages.template_import));
|
|
|
button
|
|
|
.click(common.prepareFeedback(type))
|
|
|
.click(function () {
|
|
|
UIElements.openTemplatePicker(common, true);
|
|
|
});
|
|
|
break;
|
|
|
case 'template':
|
|
|
if (!AppConfig.enableTemplates) { return; }
|
|
|
if (!common.isLoggedIn()) { return; }
|
|
|
button = $('<button>', {
|
|
|
title: Messages.saveTemplateButton,
|
|
|
class: 'fa fa-bookmark cp-toolbar-icon-template'
|
|
|
});
|
|
|
if (data.rt) {
|
|
|
button
|
|
|
.click(function () {
|
|
|
var title = data.getTitle() || document.title;
|
|
|
var todo = function (val) {
|
|
|
if (typeof(val) !== "string") { return; }
|
|
|
var toSave = data.rt.getUserDoc();
|
|
|
if (val.trim()) {
|
|
|
val = val.trim();
|
|
|
title = val;
|
|
|
try {
|
|
|
var parsed = JSON.parse(toSave);
|
|
|
var meta;
|
|
|
if (Array.isArray(parsed) && typeof(parsed[3]) === "object") {
|
|
|
meta = parsed[3].metadata; // pad
|
|
|
} else if (parsed.info) {
|
|
|
meta = parsed.info; // poll
|
|
|
} else {
|
|
|
meta = parsed.metadata;
|
|
|
}
|
|
|
if (typeof(meta) === "object") {
|
|
|
meta.title = val;
|
|
|
meta.defaultTitle = val;
|
|
|
delete meta.users;
|
|
|
}
|
|
|
toSave = JSON.stringify(parsed);
|
|
|
} catch(e) {
|
|
|
console.error("Parse error while setting the title", e);
|
|
|
}
|
|
|
}
|
|
|
sframeChan.query('Q_SAVE_AS_TEMPLATE', {
|
|
|
toSave: toSave,
|
|
|
title: title
|
|
|
}, function () {
|
|
|
UI.alert(Messages.templateSaved);
|
|
|
Feedback.send('TEMPLATE_CREATED');
|
|
|
});
|
|
|
};
|
|
|
UI.prompt(Messages.saveTemplatePrompt, title, todo);
|
|
|
});
|
|
|
}
|
|
|
break;
|
|
|
case 'forget':
|
|
|
button = $('<button>', {
|
|
|
title: Messages.forgetButtonTitle,
|
|
|
'class': "fa fa-trash cp-toolbar-icon-forget"
|
|
|
});
|
|
|
callback = typeof callback === "function" ? callback : function () {};
|
|
|
button
|
|
|
.click(common.prepareFeedback(type))
|
|
|
.click(function() {
|
|
|
common.isPadStored(function (err, data) {
|
|
|
if (!data) {
|
|
|
return void UI.alert(Messages.autostore_notAvailable);
|
|
|
}
|
|
|
sframeChan.query('Q_IS_ONLY_IN_SHARED_FOLDER', null, function (err, res) {
|
|
|
if (err || res.error) { return void console.log(err || res.error); }
|
|
|
var msg = Messages.forgetPrompt;
|
|
|
if (res) {
|
|
|
UI.alert(Messages.sharedFolders_forget);
|
|
|
return;
|
|
|
} else if (!common.isLoggedIn()) {
|
|
|
msg = Messages.fm_removePermanentlyDialog;
|
|
|
}
|
|
|
UI.confirm(msg, function (yes) {
|
|
|
if (!yes) { return; }
|
|
|
sframeChan.query('Q_MOVE_TO_TRASH', null, function (err, obj) {
|
|
|
err = err || (obj && obj.error);
|
|
|
if (err) {
|
|
|
callback(err);
|
|
|
return void UI.warn(Messages.fm_forbidden);
|
|
|
}
|
|
|
var cMsg = common.isLoggedIn() ? Messages.movedToTrash : Messages.deleted;
|
|
|
var msg = common.fixLinks($('<div>').html(cMsg));
|
|
|
UI.alert(msg);
|
|
|
callback();
|
|
|
return;
|
|
|
});
|
|
|
});
|
|
|
|
|
|
});
|
|
|
});
|
|
|
});
|
|
|
break;
|
|
|
case 'present':
|
|
|
button = $('<button>', {
|
|
|
title: Messages.presentButtonTitle,
|
|
|
'class': "fa fa-play-circle cp-toolbar-icon-present", // used in slide.js
|
|
|
});
|
|
|
break;
|
|
|
case 'preview':
|
|
|
button = $('<button>', {
|
|
|
title: Messages.previewButtonTitle,
|
|
|
'class': "fa fa-eye cp-toolbar-icon-preview",
|
|
|
});
|
|
|
break;
|
|
|
case 'print':
|
|
|
button = $('<button>', {
|
|
|
title: Messages.printButtonTitle2,
|
|
|
'class': "fa fa-print cp-toolbar-icon-print",
|
|
|
}).append($('<span>', {'class': 'cp-toolbar-drawer-element'}).text(Messages.printText));
|
|
|
break;
|
|
|
case 'history':
|
|
|
if (!AppConfig.enableHistory) {
|
|
|
button = $('<span>');
|
|
|
break;
|
|
|
}
|
|
|
var active = $(".cp-toolbar-history:visible").length !== 0;
|
|
|
button = $('<button>', {
|
|
|
title: active ? Messages.history_closeTitle : Messages.historyButton,
|
|
|
'class': "fa fa-history cp-toolbar-icon-history",
|
|
|
}).append($('<span>', {'class': 'cp-toolbar-drawer-element'}).text(Messages.historyText));
|
|
|
button.toggleClass("active", active);
|
|
|
if (data.histConfig) {
|
|
|
if (active) {
|
|
|
button.click(function () { $(".cp-toolbar-history-close").trigger("click"); });
|
|
|
}
|
|
|
else {
|
|
|
button
|
|
|
.click(common.prepareFeedback(type))
|
|
|
.on('click', function () {
|
|
|
common.getHistory(data.histConfig);
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
break;
|
|
|
case 'more':
|
|
|
button = $('<button>', {
|
|
|
title: Messages.moreActions,
|
|
|
'class': "cp-toolbar-drawer-button fa fa-ellipsis-h",
|
|
|
});
|
|
|
break;
|
|
|
case 'mediatag':
|
|
|
button = $('<button>', {
|
|
|
'class': 'fa fa-picture-o cp-toolbar-icon-mediatag',
|
|
|
title: Messages.filePickerButton,
|
|
|
})
|
|
|
.click(common.prepareFeedback(type));
|
|
|
break;
|
|
|
case 'savetodrive':
|
|
|
button = $('<button>', {
|
|
|
'class': 'fa fa-cloud-upload cp-toolbar-icon-savetodrive',
|
|
|
title: Messages.canvas_saveToDrive,
|
|
|
})
|
|
|
.click(common.prepareFeedback(type));
|
|
|
break;
|
|
|
case 'hashtag':
|
|
|
button = $('<button>', {
|
|
|
'class': 'fa fa-hashtag cp-toolbar-icon-hashtag',
|
|
|
title: Messages.tags_title,
|
|
|
})
|
|
|
.click(common.prepareFeedback(type))
|
|
|
.click(function () {
|
|
|
common.isPadStored(function (err, data) {
|
|
|
if (!data) {
|
|
|
return void UI.alert(Messages.autostore_notAvailable);
|
|
|
}
|
|
|
UIElements.updateTags(common, null);
|
|
|
});
|
|
|
});
|
|
|
break;
|
|
|
case 'toggle':
|
|
|
button = $('<button>', {
|
|
|
'class': 'fa fa-caret-down cp-toolbar-icon-toggle',
|
|
|
});
|
|
|
window.setTimeout(function () {
|
|
|
button.attr('title', data.title);
|
|
|
});
|
|
|
var updateIcon = function (isVisible) {
|
|
|
button.removeClass('fa-caret-down').removeClass('fa-caret-up');
|
|
|
if (!isVisible) { button.addClass('fa-caret-down'); }
|
|
|
else { button.addClass('fa-caret-up'); }
|
|
|
};
|
|
|
button.click(function (e) {
|
|
|
data.element.toggle();
|
|
|
var isVisible = data.element.is(':visible');
|
|
|
if (callback) { callback(isVisible); }
|
|
|
if (isVisible) {
|
|
|
button.addClass('cp-toolbar-button-active');
|
|
|
if (e.originalEvent) { Feedback.send('TOGGLE_SHOW_' + appType); }
|
|
|
} else {
|
|
|
button.removeClass('cp-toolbar-button-active');
|
|
|
if (e.originalEvent) { Feedback.send('TOGGLE_HIDE_' + appType); }
|
|
|
}
|
|
|
updateIcon(isVisible);
|
|
|
});
|
|
|
updateIcon(data.element.is(':visible'));
|
|
|
break;
|
|
|
case 'properties':
|
|
|
button = $('<button>', {
|
|
|
'class': 'fa fa-info-circle cp-toolbar-icon-properties',
|
|
|
title: Messages.propertiesButtonTitle,
|
|
|
}).append($('<span>', {'class': 'cp-toolbar-drawer-element'})
|
|
|
.text(Messages.propertiesButton))
|
|
|
.click(common.prepareFeedback(type))
|
|
|
.click(function () {
|
|
|
common.isPadStored(function (err, data) {
|
|
|
if (!data) {
|
|
|
return void UI.alert(Messages.autostore_notAvailable);
|
|
|
}
|
|
|
getPropertiesData(common, function (e, data) {
|
|
|
if (e) { return void console.error(e); }
|
|
|
UIElements.getProperties(common, data, function (e, $prop) {
|
|
|
if (e) { return void console.error(e); }
|
|
|
UI.openCustomModal($prop[0]);
|
|
|
});
|
|
|
});
|
|
|
});
|
|
|
});
|
|
|
break;
|
|
|
case 'save': // OnlyOffice save
|
|
|
button = $('<button>', {
|
|
|
'class': 'fa fa-save',
|
|
|
title: Messages.settings_save,
|
|
|
}).append($('<span>', {'class': 'cp-toolbar-drawer-element'})
|
|
|
.text(Messages.settings_save))
|
|
|
.click(common.prepareFeedback(type));
|
|
|
if (callback) { button.click(callback); }
|
|
|
break;
|
|
|
default:
|
|
|
data = data || {};
|
|
|
var icon = data.icon || "fa-question";
|
|
|
button = $('<button>', {
|
|
|
'class': "fa " + icon,
|
|
|
})
|
|
|
.click(common.prepareFeedback(data.name || 'DEFAULT'));
|
|
|
//.click(common.prepareFeedback(type));
|
|
|
if (callback) {
|
|
|
button.click(callback);
|
|
|
}
|
|
|
if (data.title) { button.attr('title', data.title); }
|
|
|
if (data.style) { button.attr('style', data.style); }
|
|
|
if (data.id) { button.attr('id', data.id); }
|
|
|
if (data.hiddenReadOnly) { button.addClass('cp-hidden-if-readonly'); }
|
|
|
if (data.name) {
|
|
|
button.addClass('cp-toolbar-icon-'+data.name);
|
|
|
button.click(common.prepareFeedback(data.name));
|
|
|
}
|
|
|
if (data.text) {
|
|
|
$('<span>', {'class': 'cp-toolbar-drawer-element'}).text(data.text)
|
|
|
.appendTo(button);
|
|
|
}
|
|
|
}
|
|
|
if (rightside) {
|
|
|
button.addClass('cp-toolbar-rightside-button');
|
|
|
}
|
|
|
return button;
|
|
|
};
|
|
|
|
|
|
var createMdToolbar = function (common, editor) {
|
|
|
var $toolbar = $('<div>', {
|
|
|
'class': 'cp-markdown-toolbar'
|
|
|
});
|
|
|
var clean = function (str) {
|
|
|
return str.replace(/^(\n)+/, '').replace(/(\n)+$/, '');
|
|
|
};
|
|
|
var actions = {
|
|
|
'bold': {
|
|
|
expr: '**{0}**',
|
|
|
icon: 'fa-bold'
|
|
|
},
|
|
|
'italic': {
|
|
|
expr: '_{0}_',
|
|
|
icon: 'fa-italic'
|
|
|
},
|
|
|
'strikethrough': {
|
|
|
expr: '~~{0}~~',
|
|
|
icon: 'fa-strikethrough'
|
|
|
},
|
|
|
'heading': {
|
|
|
apply: function (str) {
|
|
|
return '\n'+clean(str).split('\n').map(function (line) {
|
|
|
return '# '+line;
|
|
|
}).join('\n')+'\n';
|
|
|
},
|
|
|
icon: 'fa-header'
|
|
|
},
|
|
|
'link': {
|
|
|
expr: '[{0}](http://)',
|
|
|
icon: 'fa-link'
|
|
|
},
|
|
|
'quote': {
|
|
|
apply: function (str) {
|
|
|
return '\n\n'+str.split('\n').map(function (line) {
|
|
|
return '> '+line;
|
|
|
}).join('\n')+'\n\n';
|
|
|
},
|
|
|
icon: 'fa-quote-right'
|
|
|
},
|
|
|
'nlist': {
|
|
|
apply: function (str) {
|
|
|
return '\n'+clean(str).split('\n').map(function (line) {
|
|
|
return '1. '+line;
|
|
|
}).join('\n')+'\n';
|
|
|
},
|
|
|
icon: 'fa-list-ol'
|
|
|
},
|
|
|
'list': {
|
|
|
apply: function (str) {
|
|
|
return '\n'+clean(str).split('\n').map(function (line) {
|
|
|
return '* '+line;
|
|
|
}).join('\n')+'\n';
|
|
|
},
|
|
|
icon: 'fa-list-ul'
|
|
|
},
|
|
|
'check': {
|
|
|
apply: function (str) {
|
|
|
return '\n' + clean(str).split('\n').map(function (line) {
|
|
|
return '* [ ] ' + line;
|
|
|
}).join('\n') + '\n';
|
|
|
},
|
|
|
icon: 'fa-check-square-o'
|
|
|
},
|
|
|
'code': {
|
|
|
apply: function (str) {
|
|
|
if (str.indexOf('\n') !== -1) {
|
|
|
return '\n```\n' + clean(str) + '\n```\n';
|
|
|
}
|
|
|
return '`' + str + '`';
|
|
|
},
|
|
|
icon: 'fa-code'
|
|
|
},
|
|
|
'toc': {
|
|
|
expr: '[TOC]',
|
|
|
icon: 'fa-newspaper-o'
|
|
|
}
|
|
|
};
|
|
|
var onClick = function () {
|
|
|
var type = $(this).attr('data-type');
|
|
|
var texts = editor.getSelections();
|
|
|
var newTexts = texts.map(function (str) {
|
|
|
str = str || Messages.mdToolbar_defaultText;
|
|
|
if (actions[type].apply) {
|
|
|
return actions[type].apply(str);
|
|
|
}
|
|
|
return actions[type].expr.replace('{0}', str);
|
|
|
});
|
|
|
editor.replaceSelections(newTexts, 'around');
|
|
|
editor.focus();
|
|
|
};
|
|
|
for (var k in actions) {
|
|
|
$('<button>', {
|
|
|
'data-type': k,
|
|
|
'class': 'pure-button fa ' + actions[k].icon,
|
|
|
title: Messages['mdToolbar_' + k] || k
|
|
|
}).click(onClick).appendTo($toolbar);
|
|
|
}
|
|
|
$('<button>', {
|
|
|
'class': 'pure-button fa fa-question cp-markdown-help',
|
|
|
title: Messages.mdToolbar_help
|
|
|
}).click(function () {
|
|
|
var href = Messages.mdToolbar_tutorial;
|
|
|
common.openUnsafeURL(href);
|
|
|
}).appendTo($toolbar);
|
|
|
return $toolbar;
|
|
|
};
|
|
|
UIElements.createMarkdownToolbar = function (common, editor) {
|
|
|
var readOnly = common.getMetadataMgr().getPrivateData().readOnly;
|
|
|
if (readOnly) {
|
|
|
return {
|
|
|
toolbar: $(),
|
|
|
button: $(),
|
|
|
setState: function () {}
|
|
|
};
|
|
|
}
|
|
|
|
|
|
var $toolbar = createMdToolbar(common, editor);
|
|
|
var cfg = {
|
|
|
title: Messages.mdToolbar_button,
|
|
|
element: $toolbar
|
|
|
};
|
|
|
var onClick = function (visible) {
|
|
|
common.setAttribute(['general', 'markdown-help'], visible, function (e) {
|
|
|
if (e) { return void console.error(e); }
|
|
|
});
|
|
|
};
|
|
|
|
|
|
var $toolbarButton = common.createButton('toggle', true, cfg, onClick);
|
|
|
var tbState = true;
|
|
|
common.getAttribute(['general', 'markdown-help'], function (e, data) {
|
|
|
if (e) { return void console.error(e); }
|
|
|
if ($(window).height() < 800 && $(window).width() < 800) { return; }
|
|
|
if (data === true && $toolbarButton.length && tbState) {
|
|
|
$toolbarButton.click();
|
|
|
}
|
|
|
});
|
|
|
|
|
|
// setState provides the ability to disable the toolbar and the button in case we don't
|
|
|
// have the markdown editor available (in code we can switch mode, in poll we can publish)
|
|
|
var setState = function (state) {
|
|
|
tbState = state;
|
|
|
if (!state) {
|
|
|
$toolbar.hide();
|
|
|
$toolbarButton.hide();
|
|
|
return;
|
|
|
}
|
|
|
common.getAttribute(['general', 'markdown-help'], function (e, data) {
|
|
|
if (e) { return void console.error(e); }
|
|
|
if ($(window).height() < 800 && $(window).width() < 800) { return; }
|
|
|
if (data === true && $toolbarButton) {
|
|
|
// Show the toolbar using the button to make sure the icon in the button is
|
|
|
// correct (caret-down / caret-up)
|
|
|
$toolbar.hide();
|
|
|
$toolbarButton.click();
|
|
|
return;
|
|
|
}
|
|
|
$toolbar.show();
|
|
|
$toolbarButton.click();
|
|
|
});
|
|
|
$toolbarButton.show();
|
|
|
};
|
|
|
|
|
|
return {
|
|
|
toolbar: $toolbar,
|
|
|
button: $toolbarButton,
|
|
|
setState: setState
|
|
|
};
|
|
|
};
|
|
|
|
|
|
var setHTML = UIElements.setHTML = function (e, html) {
|
|
|
e.innerHTML = html;
|
|
|
return e;
|
|
|
};
|
|
|
|
|
|
UIElements.createHelpMenu = function (common, categories) {
|
|
|
var type = common.getMetadataMgr().getMetadata().type || 'pad';
|
|
|
|
|
|
var elements = [];
|
|
|
if (Messages.help && Messages.help.generic) {
|
|
|
Object.keys(Messages.help.generic).forEach(function (el) {
|
|
|
elements.push(setHTML(h('li'), Messages.help.generic[el]));
|
|
|
});
|
|
|
}
|
|
|
if (categories) {
|
|
|
categories.forEach(function (cat) {
|
|
|
var msgs = Messages.help[cat];
|
|
|
if (msgs) {
|
|
|
Object.keys(msgs).forEach(function (el) {
|
|
|
elements.push(setHTML(h('li'), msgs[el]));
|
|
|
});
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
|
|
|
var text = h('p.cp-help-text', [
|
|
|
h('h1', Messages.help.title),
|
|
|
h('ul', elements)
|
|
|
]);
|
|
|
|
|
|
common.fixLinks(text);
|
|
|
|
|
|
var closeButton = h('span.cp-help-close.fa.fa-window-close');
|
|
|
var $toolbarButton = common.createButton('', true, {
|
|
|
title: Messages.hide_help_button,
|
|
|
text: Messages.help_button,
|
|
|
name: 'help'
|
|
|
}).addClass('cp-toolbar-button-active');
|
|
|
var help = h('div.cp-help-container', [
|
|
|
closeButton,
|
|
|
text
|
|
|
]);
|
|
|
|
|
|
var toggleHelp = function (forceClose) {
|
|
|
if ($(help).hasClass('cp-help-hidden')) {
|
|
|
if (forceClose) { return; }
|
|
|
common.setAttribute(['hideHelp', type], false);
|
|
|
$toolbarButton.addClass('cp-toolbar-button-active');
|
|
|
$toolbarButton.attr('title', Messages.hide_help_button);
|
|
|
return void $(help).removeClass('cp-help-hidden');
|
|
|
}
|
|
|
$toolbarButton.removeClass('cp-toolbar-button-active');
|
|
|
$toolbarButton.attr('title', Messages.show_help_button);
|
|
|
$(help).addClass('cp-help-hidden');
|
|
|
common.setAttribute(['hideHelp', type], true);
|
|
|
};
|
|
|
|
|
|
var showMore = function () {
|
|
|
$(text).addClass("cp-help-small");
|
|
|
var $dot = $('<span>').text('...').appendTo($(text).find('h1'));
|
|
|
$(text).click(function () {
|
|
|
$(text).removeClass('cp-help-small');
|
|
|
$(text).off('click');
|
|
|
$dot.remove();
|
|
|
});
|
|
|
};
|
|
|
|
|
|
$(closeButton).click(function (e) {
|
|
|
e.stopPropagation();
|
|
|
toggleHelp(true);
|
|
|
});
|
|
|
$toolbarButton.click(function () {
|
|
|
toggleHelp();
|
|
|
});
|
|
|
|
|
|
common.getAttribute(['hideHelp', type], function (err, val) {
|
|
|
//if ($(window).height() < 800 || $(window).width() < 800) { return void toggleHelp(true); }
|
|
|
if (val === true) { return void toggleHelp(true); }
|
|
|
// Note: Help is always hidden by default now, to avoid displaying to many things in the UI
|
|
|
// This is why we have (true || ...)
|
|
|
if (!val && (true || $(window).height() < 800 || $(window).width() < 800)) {
|
|
|
return void showMore();
|
|
|
}
|
|
|
});
|
|
|
|
|
|
return {
|
|
|
menu: help,
|
|
|
button: $toolbarButton,
|
|
|
text: text
|
|
|
};
|
|
|
};
|
|
|
|
|
|
// Avatars
|
|
|
|
|
|
UIElements.displayMediatagImage = function (Common, $tag, cb) {
|
|
|
if (!$tag.length || !$tag.is('media-tag')) { return void cb('NOT_MEDIATAG'); }
|
|
|
var observer = new MutationObserver(function(mutations) {
|
|
|
mutations.forEach(function(mutation) {
|
|
|
if (mutation.addedNodes.length) {
|
|
|
if (mutation.addedNodes.length > 1 ||
|
|
|
mutation.addedNodes[0].nodeName !== 'IMG') {
|
|
|
return void cb('NOT_IMAGE');
|
|
|
}
|
|
|
var $image = $tag.find('img');
|
|
|
var onLoad = function () {
|
|
|
var img = new Image();
|
|
|
img.onload = function () {
|
|
|
var _cb = cb;
|
|
|
cb = $.noop;
|
|
|
_cb(null, $image, img);
|
|
|
};
|
|
|
img.src = $image.attr('src');
|
|
|
};
|
|
|
if ($image[0].complete) { onLoad(); }
|
|
|
$image.on('load', onLoad);
|
|
|
}
|
|
|
});
|
|
|
});
|
|
|
observer.observe($tag[0], {
|
|
|
attributes: false,
|
|
|
childList: true,
|
|
|
characterData: false
|
|
|
});
|
|
|
MediaTag($tag[0]).on('error', function (data) {
|
|
|
console.error(data);
|
|
|
});
|
|
|
};
|
|
|
|
|
|
var emoji_patt = /([\uD800-\uDBFF][\uDC00-\uDFFF])/;
|
|
|
var isEmoji = function (str) {
|
|
|
return emoji_patt.test(str);
|
|
|
};
|
|
|
var emojiStringToArray = function (str) {
|
|
|
var split = str.split(emoji_patt);
|
|
|
var arr = [];
|
|
|
for (var i=0; i<split.length; i++) {
|
|
|
var char = split[i];
|
|
|
if (char !== "") {
|
|
|
arr.push(char);
|
|
|
}
|
|
|
}
|
|
|
return arr;
|
|
|
};
|
|
|
var getFirstEmojiOrCharacter = function (str) {
|
|
|
if (!str || !str.trim()) { return '?'; }
|
|
|
var emojis = emojiStringToArray(str);
|
|
|
return isEmoji(emojis[0])? emojis[0]: str[0];
|
|
|
};
|
|
|
var avatars = {};
|
|
|
UIElements.setAvatar = function (hash, data) {
|
|
|
avatars[hash] = data;
|
|
|
};
|
|
|
UIElements.getAvatar = function (hash) {
|
|
|
return avatars[hash];
|
|
|
};
|
|
|
UIElements.displayAvatar = function (common, $container, href, name, cb) {
|
|
|
var displayDefault = function () {
|
|
|
var text = getFirstEmojiOrCharacter(name);
|
|
|
var $avatar = $('<span>', {'class': 'cp-avatar-default'}).text(text);
|
|
|
$container.append($avatar);
|
|
|
if (cb) { cb(); }
|
|
|
};
|
|
|
if (!window.Symbol) { return void displayDefault(); } // IE doesn't have Symbol
|
|
|
if (!href) { return void displayDefault(); }
|
|
|
|
|
|
var centerImage = function ($img, $image, img) {
|
|
|
var w = img.width;
|
|
|
var h = img.height;
|
|
|
if (w>h) {
|
|
|
$image.css('max-height', '100%');
|
|
|
$img.css('flex-direction', 'column');
|
|
|
if (cb) { cb($img); }
|
|
|
return;
|
|
|
}
|
|
|
$image.css('max-width', '100%');
|
|
|
$img.css('flex-direction', 'row');
|
|
|
if (cb) { cb($img); }
|
|
|
};
|
|
|
|
|
|
var parsed = Hash.parsePadUrl(href);
|
|
|
if (parsed.type !== "file" || parsed.hashData.type !== "file") {
|
|
|
var $img = $('<media-tag>').appendTo($container);
|
|
|
var img = new Image();
|
|
|
$(img).attr('src', href);
|
|
|
img.onload = function () {
|
|
|
centerImage($img, $(img), img);
|
|
|
$(img).appendTo($img);
|
|
|
};
|
|
|
return;
|
|
|
}
|
|
|
// No password for avatars
|
|
|
var privateData = common.getMetadataMgr().getPrivateData();
|
|
|
var origin = privateData.fileHost || privateData.origin;
|
|
|
var secret = Hash.getSecrets('file', parsed.hash);
|
|
|
if (secret.keys && secret.channel) {
|
|
|
var hexFileName = secret.channel;
|
|
|
var cryptKey = Hash.encodeBase64(secret.keys && secret.keys.cryptKey);
|
|
|
var src = origin + Hash.getBlobPathFromHex(hexFileName);
|
|
|
common.getFileSize(hexFileName, function (e, data) {
|
|
|
if (e || !data) { return void displayDefault(); }
|
|
|
if (typeof data !== "number") { return void displayDefault(); }
|
|
|
if (Util.bytesToMegabytes(data) > 0.5) { return void displayDefault(); }
|
|
|
var $img = $('<media-tag>').appendTo($container);
|
|
|
$img.attr('src', src);
|
|
|
$img.attr('data-crypto-key', 'cryptpad:' + cryptKey);
|
|
|
UIElements.displayMediatagImage(common, $img, function (err, $image, img) {
|
|
|
if (err) { return void console.error(err); }
|
|
|
centerImage($img, $image, img);
|
|
|
});
|
|
|
});
|
|
|
}
|
|
|
};
|
|
|
var transformAvatar = function (file, cb) {
|
|
|
if (file.type === 'image/gif') { return void cb(file); }
|
|
|
var $croppie = $('<div>', {
|
|
|
'class': 'cp-app-profile-resizer'
|
|
|
});
|
|
|
|
|
|
if (typeof ($croppie.croppie) !== "function") {
|
|
|
console.warn('fuck');
|
|
|
return void cb(file);
|
|
|
}
|
|
|
|
|
|
var todo = function () {
|
|
|
UI.confirm($croppie[0], function (yes) {
|
|
|
if (!yes) { return; }
|
|
|
$croppie.croppie('result', {
|
|
|
type: 'blob',
|
|
|
size: {width: 300, height: 300}
|
|
|
}).then(function(blob) {
|
|
|
blob.lastModifiedDate = new Date();
|
|
|
blob.name = 'avatar';
|
|
|
cb(blob);
|
|
|
});
|
|
|
});
|
|
|
};
|
|
|
|
|
|
var reader = new FileReader();
|
|
|
reader.onload = function(e) {
|
|
|
$croppie.croppie({
|
|
|
url: e.target.result,
|
|
|
viewport: { width: 100, height: 100 },
|
|
|
boundary: { width: 400, height: 300 },
|
|
|
});
|
|
|
todo();
|
|
|
};
|
|
|
reader.readAsDataURL(file);
|
|
|
};
|
|
|
UIElements.addAvatar = function (common, cb) {
|
|
|
var AVATAR_SIZE_LIMIT = 0.5;
|
|
|
var allowedMediaTypes = [
|
|
|
'image/png',
|
|
|
'image/jpeg',
|
|
|
'image/jpg',
|
|
|
'image/gif',
|
|
|
];
|
|
|
var fmConfig = {
|
|
|
noHandlers: true,
|
|
|
noStore: true,
|
|
|
body: $('body'),
|
|
|
onUploaded: cb
|
|
|
};
|
|
|
var FM = common.createFileManager(fmConfig);
|
|
|
var accepted = ".gif,.jpg,.jpeg,.png";
|
|
|
var data = {
|
|
|
FM: FM,
|
|
|
filter: function (file) {
|
|
|
var sizeMB = Util.bytesToMegabytes(file.size);
|
|
|
var type = file.type;
|
|
|
// We can't resize .gif so we have to display an error if it is too big
|
|
|
if (sizeMB > AVATAR_SIZE_LIMIT && type === 'image/gif') {
|
|
|
UI.log(Messages._getKey('profile_uploadSizeError', [
|
|
|
Messages._getKey('formattedMB', [AVATAR_SIZE_LIMIT])
|
|
|
]));
|
|
|
return false;
|
|
|
}
|
|
|
// Display an error if the image type is not allowed
|
|
|
if (allowedMediaTypes.indexOf(type) === -1) {
|
|
|
UI.log(Messages._getKey('profile_uploadTypeError', [
|
|
|
accepted.split(',').join(', ')
|
|
|
]));
|
|
|
return false;
|
|
|
}
|
|
|
return true;
|
|
|
},
|
|
|
transformer: transformAvatar,
|
|
|
accept: accepted
|
|
|
};
|
|
|
return data;
|
|
|
};
|
|
|
|
|
|
/* Create a usage bar which keeps track of how much storage space is used
|
|
|
by your CryptDrive. The getPinnedUsage RPC is one of the heavier calls,
|
|
|
so we throttle its usage. Clients will not update more than once per
|
|
|
LIMIT_REFRESH_RATE. It will be update at least once every three such intervals
|
|
|
If changes are made to your drive in the interim, they will trigger an
|
|
|
update.
|
|
|
*/
|
|
|
// NOTE: The callback must stay SYNCHRONOUS
|
|
|
var LIMIT_REFRESH_RATE = 30000; // milliseconds
|
|
|
UIElements.createUsageBar = function (common, teamId, cb) {
|
|
|
if (AppConfig.hideUsageBar) { return cb('USAGE_BAR_HIDDEN'); }
|
|
|
if (!common.isLoggedIn()) { return cb("NOT_LOGGED_IN"); }
|
|
|
// getPinnedUsage updates common.account.usage, and other values
|
|
|
// so we can just use those and only check for errors
|
|
|
var $container = $('<span>', {'class':'cp-limit-container'});
|
|
|
var todo = function (err, data) {
|
|
|
if (err || !data) { return void console.error(err || 'No data'); }
|
|
|
|
|
|
var usage = data.usage;
|
|
|
var limit = data.limit;
|
|
|
var plan = data.plan;
|
|
|
$container.html('');
|
|
|
var unit = Util.magnitudeOfBytes(limit);
|
|
|
|
|
|
usage = unit === 'GB'? Util.bytesToGigabytes(usage):
|
|
|
Util.bytesToMegabytes(usage);
|
|
|
limit = unit === 'GB'? Util.bytesToGigabytes(limit):
|
|
|
Util.bytesToMegabytes(limit);
|
|
|
|
|
|
var $limit = $('<span>', {'class': 'cp-limit-bar'}).appendTo($container);
|
|
|
var quota = usage/limit;
|
|
|
var $usage = $('<span>', {'class': 'cp-limit-usage'}).css('width', quota*100+'%');
|
|
|
var $buttons = $(h('span.cp-limit-buttons')).appendTo($container);
|
|
|
|
|
|
var urls = common.getMetadataMgr().getPrivateData().accounts;
|
|
|
var makeDonateButton = function () {
|
|
|
var $a = $('<a>', {
|
|
|
'class': 'cp-limit-upgrade btn btn-primary',
|
|
|
href: urls.donateURL,
|
|
|
rel: "noreferrer noopener",
|
|
|
target: "_blank",
|
|
|
}).text(Messages.crowdfunding_button2).appendTo($buttons);
|
|
|
$a.click(function () {
|
|
|
Feedback.send('SUPPORT_CRYPTPAD');
|
|
|
});
|
|
|
};
|
|
|
|
|
|
var makeUpgradeButton = function () {
|
|
|
var $a = $('<a>', {
|
|
|
'class': 'cp-limit-upgrade btn btn-success',
|
|
|
href: urls.upgradeURL,
|
|
|
rel: "noreferrer noopener",
|
|
|
target: "_blank",
|
|
|
}).text(Messages.upgradeAccount).appendTo($buttons);
|
|
|
$a.click(function () {
|
|
|
Feedback.send('UPGRADE_ACCOUNT');
|
|
|
});
|
|
|
};
|
|
|
|
|
|
if (!Config.removeDonateButton) {
|
|
|
if (!common.isLoggedIn() || !Config.allowSubscriptions) {
|
|
|
// user is not logged in, or subscriptions are disallowed
|
|
|
makeDonateButton();
|
|
|
} else if (!plan) {
|
|
|
// user is logged in and subscriptions are allowed
|
|
|
// and they don't have one. show upgrades
|
|
|
makeDonateButton();
|
|
|
makeUpgradeButton();
|
|
|
} else {
|
|
|
// they have a plan. show nothing
|
|
|
}
|
|
|
}
|
|
|
|
|
|
var prettyUsage;
|
|
|
var prettyLimit;
|
|
|
|
|
|
if (unit === 'GB') {
|
|
|
prettyUsage = Messages._getKey('formattedGB', [usage]);
|
|
|
prettyLimit = Messages._getKey('formattedGB', [limit]);
|
|
|
} else {
|
|
|
prettyUsage = Messages._getKey('formattedMB', [usage]);
|
|
|
prettyLimit = Messages._getKey('formattedMB', [limit]);
|
|
|
}
|
|
|
|
|
|
if (quota < 0.8) { $usage.addClass('cp-limit-usage-normal'); }
|
|
|
else if (quota < 1) { $usage.addClass('cp-limit-usage-warning'); }
|
|
|
else { $usage.addClass('cp-limit-usage-above'); }
|
|
|
var $text = $('<span>', {'class': 'cp-limit-usage-text'});
|
|
|
$text.html(Messages._getKey('storageStatus', [prettyUsage, prettyLimit]));
|
|
|
$container.prepend($text);
|
|
|
$limit.append($usage);
|
|
|
};
|
|
|
|
|
|
var updateUsage = Util.notAgainForAnother(function () {
|
|
|
common.getPinUsage(teamId, todo);
|
|
|
}, LIMIT_REFRESH_RATE);
|
|
|
|
|
|
var interval = setInterval(function () {
|
|
|
updateUsage();
|
|
|
}, LIMIT_REFRESH_RATE * 3);
|
|
|
|
|
|
updateUsage();
|
|
|
cb(null, $container);
|
|
|
return {
|
|
|
stop: function () {
|
|
|
clearInterval(interval);
|
|
|
}
|
|
|
};
|
|
|
};
|
|
|
|
|
|
// Create a button with a dropdown menu
|
|
|
// input is a config object with parameters:
|
|
|
// - container (optional): the dropdown container (span)
|
|
|
// - text (optional): the button text value
|
|
|
// - options: array of {tag: "", attributes: {}, content: "string"}
|
|
|
//
|
|
|
// allowed options tags: ['a', 'hr', 'p']
|
|
|
UIElements.createDropdown = function (config) {
|
|
|
if (typeof config !== "object" || !Array.isArray(config.options)) { return; }
|
|
|
if (config.feedback && !config.common) { return void console.error("feedback in a dropdown requires sframe-common"); }
|
|
|
|
|
|
var isElement = function (o) {
|
|
|
return /HTML/.test(Object.prototype.toString.call(o)) &&
|
|
|
typeof(o.tagName) === 'string';
|
|
|
};
|
|
|
var allowedTags = ['a', 'p', 'hr', 'div'];
|
|
|
var isValidOption = function (o) {
|
|
|
if (typeof o !== "object") { return false; }
|
|
|
if (isElement(o)) { return true; }
|
|
|
if (!o.tag || allowedTags.indexOf(o.tag) === -1) { return false; }
|
|
|
return true;
|
|
|
};
|
|
|
|
|
|
// Container
|
|
|
var $container = $(config.container);
|
|
|
var containerConfig = {
|
|
|
'class': 'cp-dropdown-container'
|
|
|
};
|
|
|
if (config.buttonTitle) {
|
|
|
containerConfig.title = config.buttonTitle;
|
|
|
}
|
|
|
|
|
|
if (!config.container) {
|
|
|
$container = $('<span>', containerConfig);
|
|
|
}
|
|
|
|
|
|
// Button
|
|
|
var $button = $('<button>', {
|
|
|
'class': ''
|
|
|
}).append($('<span>', {'class': 'cp-dropdown-button-title'}).html(config.text || ""));
|
|
|
/*$('<span>', {
|
|
|
'class': 'fa fa-caret-down',
|
|
|
}).appendTo($button);*/
|
|
|
|
|
|
// Menu
|
|
|
var $innerblock = $('<div>', {'class': 'cp-dropdown-content'});
|
|
|
if (config.left) { $innerblock.addClass('cp-dropdown-left'); }
|
|
|
|
|
|
config.options.forEach(function (o) {
|
|
|
if (!isValidOption(o)) { return; }
|
|
|
if (isElement(o)) { return $innerblock.append($(o)); }
|
|
|
$('<' + o.tag + '>', o.attributes || {}).html(o.content || '').appendTo($innerblock);
|
|
|
});
|
|
|
|
|
|
$container.append($button).append($innerblock);
|
|
|
|
|
|
var value = config.initialValue || '';
|
|
|
|
|
|
var setActive = function ($el) {
|
|
|
if ($el.length !== 1) { return; }
|
|
|
$innerblock.find('.cp-dropdown-element-active').removeClass('cp-dropdown-element-active');
|
|
|
$el.addClass('cp-dropdown-element-active');
|
|
|
var scroll = $el.position().top + $innerblock.scrollTop();
|
|
|
if (scroll < $innerblock.scrollTop()) {
|
|
|
$innerblock.scrollTop(scroll);
|
|
|
} else if (scroll > ($innerblock.scrollTop() + 280)) {
|
|
|
$innerblock.scrollTop(scroll-270);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
var hide = function () {
|
|
|
window.setTimeout(function () { $innerblock.hide(); }, 0);
|
|
|
};
|
|
|
|
|
|
var show = function () {
|
|
|
var wh = $(window).height();
|
|
|
var topPos = $container[0].getBoundingClientRect().bottom;
|
|
|
$innerblock.css('max-height', Math.floor(wh - topPos - 1)+'px');
|
|
|
$innerblock.show();
|
|
|
$innerblock.find('.cp-dropdown-element-active').removeClass('cp-dropdown-element-active');
|
|
|
if (config.isSelect && value) {
|
|
|
var $val = $innerblock.find('[data-value="'+value+'"]');
|
|
|
setActive($val);
|
|
|
$innerblock.scrollTop($val.position().top + $innerblock.scrollTop());
|
|
|
}
|
|
|
if (config.feedback) { Feedback.send(config.feedback); }
|
|
|
};
|
|
|
|
|
|
$container.click(function (e) {
|
|
|
e.stopPropagation();
|
|
|
var state = $innerblock.is(':visible');
|
|
|
$('.cp-dropdown-content').hide();
|
|
|
try {
|
|
|
$('iframe').each(function (idx, ifrw) {
|
|
|
$(ifrw).contents().find('.cp-dropdown-content').hide();
|
|
|
});
|
|
|
} catch (er) {
|
|
|
// empty try catch in case this iframe is problematic (cross-origin)
|
|
|
}
|
|
|
if (state) {
|
|
|
hide();
|
|
|
return;
|
|
|
}
|
|
|
show();
|
|
|
});
|
|
|
|
|
|
if (config.isSelect) {
|
|
|
var pressed = '';
|
|
|
var to;
|
|
|
$container.keydown(function (e) {
|
|
|
var $value = $innerblock.find('[data-value].cp-dropdown-element-active:visible');
|
|
|
if (e.which === 38) { // Up
|
|
|
if ($value.length) {
|
|
|
$value.mouseleave();
|
|
|
var $prev = $value.prev();
|
|
|
$prev.mouseenter();
|
|
|
setActive($prev);
|
|
|
}
|
|
|
}
|
|
|
if (e.which === 40) { // Down
|
|
|
if ($value.length) {
|
|
|
$value.mouseleave();
|
|
|
var $next = $value.next();
|
|
|
$next.mouseenter();
|
|
|
setActive($next);
|
|
|
}
|
|
|
}
|
|
|
if (e.which === 13) { //Enter
|
|
|
if ($value.length) {
|
|
|
$value.click();
|
|
|
hide();
|
|
|
}
|
|
|
}
|
|
|
if (e.which === 27) { // Esc
|
|
|
$value.mouseleave();
|
|
|
hide();
|
|
|
}
|
|
|
});
|
|
|
$container.keypress(function (e) {
|
|
|
window.clearTimeout(to);
|
|
|
var c = String.fromCharCode(e.which);
|
|
|
pressed += c;
|
|
|
var $value = $innerblock.find('[data-value^="'+pressed+'"]:first');
|
|
|
if ($value.length) {
|
|
|
setActive($value);
|
|
|
$innerblock.scrollTop($value.position().top + $innerblock.scrollTop());
|
|
|
}
|
|
|
to = window.setTimeout(function () {
|
|
|
pressed = '';
|
|
|
}, 1000);
|
|
|
});
|
|
|
|
|
|
$container.setValue = function (val, name) {
|
|
|
value = val;
|
|
|
var $val = $innerblock.find('[data-value="'+val+'"]');
|
|
|
var textValue = name || $val.html() || val;
|
|
|
$button.find('.cp-dropdown-button-title').html(textValue);
|
|
|
};
|
|
|
$container.getValue = function () {
|
|
|
return value || '';
|
|
|
};
|
|
|
}
|
|
|
|
|
|
return $container;
|
|
|
};
|
|
|
|
|
|
UIElements.createUserAdminMenu = function (Common, config) {
|
|
|
var metadataMgr = Common.getMetadataMgr();
|
|
|
|
|
|
var displayNameCls = config.displayNameCls || 'cp-toolbar-user-name';
|
|
|
var $displayedName = $('<span>', {'class': displayNameCls});
|
|
|
|
|
|
var priv = metadataMgr.getPrivateData();
|
|
|
var accountName = priv.accountName;
|
|
|
var origin = priv.origin;
|
|
|
var padType = metadataMgr.getMetadata().type;
|
|
|
|
|
|
var $userName = $('<span>');
|
|
|
var options = [];
|
|
|
if (config.displayNameCls) {
|
|
|
var $userAdminContent = $('<p>');
|
|
|
if (accountName) {
|
|
|
var $userAccount = $('<span>').append(Messages.user_accountName + ': ');
|
|
|
$userAdminContent.append($userAccount).append(Util.fixHTML(accountName));
|
|
|
$userAdminContent.append($('<br>'));
|
|
|
}
|
|
|
if (config.displayName && !AppConfig.disableProfile) {
|
|
|
// Hide "Display name:" in read only mode
|
|
|
$userName.append(Messages.user_displayName + ': ');
|
|
|
$userName.append($displayedName);
|
|
|
}
|
|
|
$userAdminContent.append($userName);
|
|
|
options.push({
|
|
|
tag: 'p',
|
|
|
attributes: {'class': 'cp-toolbar-account'},
|
|
|
content: $userAdminContent.html()
|
|
|
});
|
|
|
}
|
|
|
options.push({
|
|
|
tag: 'a',
|
|
|
attributes: {
|
|
|
'target': '_blank',
|
|
|
'href': origin+'/index.html',
|
|
|
'class': 'fa fa-home'
|
|
|
},
|
|
|
content: h('span', Messages.homePage)
|
|
|
});
|
|
|
if (padType !== 'drive' || (!accountName && priv.newSharedFolder)) {
|
|
|
options.push({
|
|
|
tag: 'a',
|
|
|
attributes: {
|
|
|
'target': '_blank',
|
|
|
'href': origin+'/drive/',
|
|
|
'class': 'fa fa-hdd-o'
|
|
|
},
|
|
|
content: h('span', Messages.type.drive)
|
|
|
});
|
|
|
}
|
|
|
if (padType !== 'teams' && accountName) {
|
|
|
options.push({
|
|
|
tag: 'a',
|
|
|
attributes: {
|
|
|
'target': '_blank',
|
|
|
'href': origin+'/teams/',
|
|
|
'class': 'fa fa-users'
|
|
|
},
|
|
|
content: h('span', Messages.type.teams)
|
|
|
});
|
|
|
}
|
|
|
options.push({ tag: 'hr' });
|
|
|
// Add the change display name button if not in read only mode
|
|
|
if (config.changeNameButtonCls && config.displayChangeName && !AppConfig.disableProfile) {
|
|
|
options.push({
|
|
|
tag: 'a',
|
|
|
attributes: {'class': config.changeNameButtonCls + ' fa fa-user'},
|
|
|
content: h('span', Messages.user_rename)
|
|
|
});
|
|
|
}
|
|
|
if (accountName && !AppConfig.disableProfile) {
|
|
|
options.push({
|
|
|
tag: 'a',
|
|
|
attributes: {'class': 'cp-toolbar-menu-profile fa fa-user-circle'},
|
|
|
content: h('span', Messages.profileButton)
|
|
|
});
|
|
|
}
|
|
|
if (padType !== 'settings') {
|
|
|
options.push({
|
|
|
tag: 'a',
|
|
|
attributes: {'class': 'cp-toolbar-menu-settings fa fa-cog'},
|
|
|
content: h('span', Messages.settingsButton)
|
|
|
});
|
|
|
}
|
|
|
options.push({ tag: 'hr' });
|
|
|
// Add administration panel link if the user is an admin
|
|
|
if (priv.edPublic && Array.isArray(Config.adminKeys) && Config.adminKeys.indexOf(priv.edPublic) !== -1) {
|
|
|
options.push({
|
|
|
tag: 'a',
|
|
|
attributes: {'class': 'cp-toolbar-menu-admin fa fa-cogs'},
|
|
|
content: h('span', Messages.adminPage || 'Admin')
|
|
|
});
|
|
|
}
|
|
|
if (padType !== 'support' && accountName && Config.supportMailbox) {
|
|
|
options.push({
|
|
|
tag: 'a',
|
|
|
attributes: {'class': 'cp-toolbar-menu-support fa fa-life-ring'},
|
|
|
content: h('span', Messages.supportPage || 'Support')
|
|
|
});
|
|
|
}
|
|
|
options.push({ tag: 'hr' });
|
|
|
if (Config.allowSubscriptions) {
|
|
|
options.push({
|
|
|
tag: 'a',
|
|
|
attributes: {
|
|
|
'target': '_blank',
|
|
|
'href': priv.plan ? priv.accounts.upgradeURL : origin+'/features.html',
|
|
|
'class': 'fa fa-star-o'
|
|
|
},
|
|
|
content: h('span', priv.plan ? Messages.settings_cat_subscription : Messages.pricing)
|
|
|
});
|
|
|
}
|
|
|
if (!priv.plan && !Config.removeDonateButton) {
|
|
|
options.push({
|
|
|
tag: 'a',
|
|
|
attributes: {
|
|
|
'target': '_blank',
|
|
|
'rel': 'noopener',
|
|
|
'href': priv.accounts.donateURL,
|
|
|
'class': 'fa fa-gift'
|
|
|
},
|
|
|
content: h('span', Messages.crowdfunding_button2)
|
|
|
});
|
|
|
}
|
|
|
if (AppConfig.surveyURL) {
|
|
|
options.push({
|
|
|
tag: 'a',
|
|
|
attributes: {
|
|
|
'target': '_blank',
|
|
|
'rel': 'noopener',
|
|
|
'href': AppConfig.surveyURL,
|
|
|
'class': 'cp-toolbar-survey fa fa-graduation-cap'
|
|
|
},
|
|
|
content: h('span', Messages.survey)
|
|
|
});
|
|
|
}
|
|
|
options.push({ tag: 'hr' });
|
|
|
// Add login or logout button depending on the current status
|
|
|
if (accountName) {
|
|
|
options.push({
|
|
|
tag: 'a',
|
|
|
attributes: {'class': 'cp-toolbar-menu-logout fa fa-sign-out'},
|
|
|
content: h('span', Messages.logoutButton)
|
|
|
});
|
|
|
} else {
|
|
|
options.push({
|
|
|
tag: 'a',
|
|
|
attributes: {'class': 'cp-toolbar-menu-login fa fa-sign-in'},
|
|
|
content: h('span', Messages.login_login)
|
|
|
});
|
|
|
options.push({
|
|
|
tag: 'a',
|
|
|
attributes: {'class': 'cp-toolbar-menu-register fa fa-user-plus'},
|
|
|
content: h('span', Messages.login_register)
|
|
|
});
|
|
|
}
|
|
|
var $icon = $('<span>', {'class': 'fa fa-user-secret'});
|
|
|
//var $userbig = $('<span>', {'class': 'big'}).append($displayedName.clone());
|
|
|
var $userButton = $('<div>').append($icon);//.append($userbig);
|
|
|
if (accountName) {
|
|
|
$userButton = $('<div>').append(accountName);
|
|
|
}
|
|
|
/*if (account && config.displayNameCls) {
|
|
|
$userbig.append($('<span>', {'class': 'account-name'}).text('(' + accountName + ')'));
|
|
|
} else if (account) {
|
|
|
// If no display name, do not display the parentheses
|
|
|
$userbig.append($('<span>', {'class': 'account-name'}).text(accountName));
|
|
|
}*/
|
|
|
var dropdownConfigUser = {
|
|
|
text: $userButton.html(), // Button initial text
|
|
|
options: options, // Entries displayed in the menu
|
|
|
left: true, // Open to the left of the button
|
|
|
container: config.$initBlock, // optional
|
|
|
feedback: "USER_ADMIN",
|
|
|
common: Common
|
|
|
};
|
|
|
var $userAdmin = UIElements.createDropdown(dropdownConfigUser);
|
|
|
|
|
|
/*
|
|
|
// Uncomment these lines to have a language selector in the admin menu
|
|
|
// FIXME clicking on the inner menu hides the outer one
|
|
|
var $lang = UIElements.createLanguageSelector(Common);
|
|
|
$userAdmin.find('.cp-dropdown-content').append($lang);
|
|
|
*/
|
|
|
|
|
|
var $displayName = $userAdmin.find('.'+displayNameCls);
|
|
|
|
|
|
var $avatar = $userAdmin.find('> button .cp-dropdown-button-title');
|
|
|
var loadingAvatar;
|
|
|
var to;
|
|
|
var oldUrl = '';
|
|
|
var updateButton = function () {
|
|
|
var myData = metadataMgr.getUserData();
|
|
|
if (!myData) { return; }
|
|
|
if (loadingAvatar) {
|
|
|
// Try again in 200ms
|
|
|
window.clearTimeout(to);
|
|
|
to = window.setTimeout(updateButton, 200);
|
|
|
return;
|
|
|
}
|
|
|
loadingAvatar = true;
|
|
|
var newName = myData.name;
|
|
|
var url = myData.avatar;
|
|
|
$displayName.text(newName || Messages.anonymous);
|
|
|
if (accountName && oldUrl !== url) {
|
|
|
$avatar.html('');
|
|
|
UIElements.displayAvatar(Common, $avatar, url,
|
|
|
newName || Messages.anonymous, function ($img) {
|
|
|
oldUrl = url;
|
|
|
$userAdmin.find('> button').removeClass('cp-avatar');
|
|
|
if ($img) { $userAdmin.find('> button').addClass('cp-avatar'); }
|
|
|
loadingAvatar = false;
|
|
|
});
|
|
|
return;
|
|
|
}
|
|
|
loadingAvatar = false;
|
|
|
};
|
|
|
metadataMgr.onChange(updateButton);
|
|
|
updateButton();
|
|
|
|
|
|
$userAdmin.find('a.cp-toolbar-menu-logout').click(function () {
|
|
|
Common.logout(function () {
|
|
|
window.parent.location = origin+'/';
|
|
|
});
|
|
|
});
|
|
|
$userAdmin.find('a.cp-toolbar-menu-settings').click(function () {
|
|
|
if (padType) {
|
|
|
window.open(origin+'/settings/');
|
|
|
} else {
|
|
|
window.parent.location = origin+'/settings/';
|
|
|
}
|
|
|
});
|
|
|
$userAdmin.find('a.cp-toolbar-menu-support').click(function () {
|
|
|
if (padType) {
|
|
|
window.open(origin+'/support/');
|
|
|
} else {
|
|
|
window.parent.location = origin+'/support/';
|
|
|
}
|
|
|
});
|
|
|
$userAdmin.find('a.cp-toolbar-menu-admin').click(function () {
|
|
|
if (padType) {
|
|
|
window.open(origin+'/admin/');
|
|
|
} else {
|
|
|
window.parent.location = origin+'/admin/';
|
|
|
}
|
|
|
});
|
|
|
$userAdmin.find('a.cp-toolbar-survey').click(function () {
|
|
|
Feedback.send('SURVEY_CLICKED');
|
|
|
});
|
|
|
$userAdmin.find('a.cp-toolbar-menu-profile').click(function () {
|
|
|
if (padType) {
|
|
|
window.open(origin+'/profile/');
|
|
|
} else {
|
|
|
window.parent.location = origin+'/profile/';
|
|
|
}
|
|
|
});
|
|
|
$userAdmin.find('a.cp-toolbar-menu-login').click(function () {
|
|
|
Common.setLoginRedirect(function () {
|
|
|
window.parent.location = origin+'/login/';
|
|
|
});
|
|
|
});
|
|
|
$userAdmin.find('a.cp-toolbar-menu-register').click(function () {
|
|
|
Common.setLoginRedirect(function () {
|
|
|
window.parent.location = origin+'/register/';
|
|
|
});
|
|
|
});
|
|
|
|
|
|
return $userAdmin;
|
|
|
};
|
|
|
|
|
|
// Provide $container if you want to put the generated block in another element
|
|
|
// Provide $initBlock if you already have the menu block and you want the content inserted in it
|
|
|
UIElements.createLanguageSelector = function (common, $container, $initBlock) {
|
|
|
var options = [];
|
|
|
var languages = Messages._languages;
|
|
|
var keys = Object.keys(languages).sort();
|
|
|
keys.forEach(function (l) {
|
|
|
options.push({
|
|
|
tag: 'a',
|
|
|
attributes: {
|
|
|
'class': 'cp-language-value',
|
|
|
'data-value': l,
|
|
|
'href': '#',
|
|
|
},
|
|
|
content: languages[l] // Pretty name of the language value
|
|
|
});
|
|
|
});
|
|
|
var dropdownConfig = {
|
|
|
text: Messages.language, // Button initial text
|
|
|
options: options, // Entries displayed in the menu
|
|
|
//left: true, // Open to the left of the button
|
|
|
container: $initBlock, // optional
|
|
|
isSelect: true,
|
|
|
common: common
|
|
|
};
|
|
|
var $block = UIElements.createDropdown(dropdownConfig);
|
|
|
$block.attr('id', 'cp-language-selector');
|
|
|
|
|
|
if ($container) {
|
|
|
$block.appendTo($container);
|
|
|
}
|
|
|
|
|
|
Language.initSelector($block, common);
|
|
|
|
|
|
return $block;
|
|
|
};
|
|
|
|
|
|
UIElements.createModal = function (cfg) {
|
|
|
var $body = cfg.$body || $('body');
|
|
|
var $blockContainer = $body.find('#'+cfg.id);
|
|
|
if (!$blockContainer.length) {
|
|
|
$blockContainer = $('<div>', {
|
|
|
'class': 'cp-modal-container',
|
|
|
tabindex: 1,
|
|
|
'id': cfg.id
|
|
|
});
|
|
|
}
|
|
|
var hide = function () {
|
|
|
if (cfg.onClose) { return void cfg.onClose(); }
|
|
|
$blockContainer.hide();
|
|
|
};
|
|
|
$blockContainer.html('').appendTo($body);
|
|
|
var $block = $('<div>', {'class': 'cp-modal'}).appendTo($blockContainer);
|
|
|
$('<span>', {
|
|
|
'class': 'cp-modal-close fa fa-times',
|
|
|
'title': Messages.filePicker_close
|
|
|
}).click(hide).appendTo($block);
|
|
|
$body.click(hide);
|
|
|
$block.click(function (e) {
|
|
|
e.stopPropagation();
|
|
|
});
|
|
|
$body.keydown(function (e) {
|
|
|
if (e.which === 27) {
|
|
|
hide();
|
|
|
}
|
|
|
});
|
|
|
return $blockContainer;
|
|
|
};
|
|
|
|
|
|
UIElements.createNewPadModal = function (common) {
|
|
|
// if in drive, show new pad modal instead
|
|
|
if ($(".cp-app-drive-element-row.cp-app-drive-new-ghost").length !== 0) {
|
|
|
return void $(".cp-app-drive-element-row.cp-app-drive-new-ghost").click();
|
|
|
}
|
|
|
|
|
|
var $modal = UIElements.createModal({
|
|
|
id: 'cp-app-toolbar-creation-dialog',
|
|
|
$body: $('body')
|
|
|
});
|
|
|
var $title = $('<h3>').text(Messages.fm_newFile);
|
|
|
var $description = $('<p>').html(Messages.creation_newPadModalDescription);
|
|
|
$modal.find('.cp-modal').append($title);
|
|
|
$modal.find('.cp-modal').append($description);
|
|
|
|
|
|
var $advanced;
|
|
|
|
|
|
var $advancedContainer = $('<div>');
|
|
|
var priv = common.getMetadataMgr().getPrivateData();
|
|
|
var c = (priv.settings.general && priv.settings.general.creation) || {};
|
|
|
if (AppConfig.displayCreationScreen && common.isLoggedIn() && c.skip) {
|
|
|
var $cboxLabel = $(UI.createCheckbox('cp-app-toolbar-creation-advanced',
|
|
|
Messages.creation_newPadModalAdvanced, true))
|
|
|
.appendTo($advancedContainer);
|
|
|
$advanced = $cboxLabel.find('input');
|
|
|
$description.append('<br>');
|
|
|
$description.append(Messages.creation_newPadModalDescriptionAdvanced);
|
|
|
}
|
|
|
|
|
|
var $container = $('<div>');
|
|
|
var i = 0;
|
|
|
var types = AppConfig.availablePadTypes.filter(function (p) {
|
|
|
if (p === 'drive') { return; }
|
|
|
if (p === 'teams') { return; }
|
|
|
if (p === 'contacts') { return; }
|
|
|
if (p === 'todo') { return; }
|
|
|
if (p === 'file') { return; }
|
|
|
if (!common.isLoggedIn() && AppConfig.registeredOnlyTypes &&
|
|
|
AppConfig.registeredOnlyTypes.indexOf(p) !== -1) { return; }
|
|
|
return true;
|
|
|
});
|
|
|
types.forEach(function (p) {
|
|
|
var $element = $('<li>', {
|
|
|
'class': 'cp-icons-element',
|
|
|
'id': 'cp-newpad-icons-'+ (i++)
|
|
|
}).prepend(UI.getIcon(p)).appendTo($container);
|
|
|
$element.append($('<span>', {'class': 'cp-icons-name'})
|
|
|
.text(Messages.type[p]));
|
|
|
$element.attr('data-type', p);
|
|
|
$element.click(function () {
|
|
|
$modal.hide();
|
|
|
if ($advanced && Util.isChecked($advanced)) {
|
|
|
common.sessionStorage.put(Constants.displayPadCreationScreen, true, function (){
|
|
|
common.openURL('/' + p + '/');
|
|
|
});
|
|
|
return;
|
|
|
}
|
|
|
common.sessionStorage.put(Constants.displayPadCreationScreen, "", function () {
|
|
|
common.openURL('/' + p + '/');
|
|
|
});
|
|
|
});
|
|
|
});
|
|
|
|
|
|
var selected = -1;
|
|
|
var next = function () {
|
|
|
selected = ++selected % types.length;
|
|
|
$container.find('.cp-icons-element-selected').removeClass('cp-icons-element-selected');
|
|
|
$container.find('#cp-newpad-icons-'+selected).addClass('cp-icons-element-selected');
|
|
|
};
|
|
|
|
|
|
$modal.off('keydown');
|
|
|
$modal.keydown(function (e) {
|
|
|
if (e.which === 9) {
|
|
|
e.preventDefault();
|
|
|
e.stopPropagation();
|
|
|
next();
|
|
|
return;
|
|
|
}
|
|
|
if (e.which === 13) {
|
|
|
if ($container.find('.cp-icons-element-selected').length === 1) {
|
|
|
$container.find('.cp-icons-element-selected').click();
|
|
|
}
|
|
|
return;
|
|
|
}
|
|
|
if (e.which === 32 && $advanced) {
|
|
|
$advanced.prop('checked', !$advanced.prop('checked'));
|
|
|
$modal.focus();
|
|
|
e.stopPropagation();
|
|
|
e.preventDefault();
|
|
|
}
|
|
|
});
|
|
|
|
|
|
|
|
|
$modal.find('.cp-modal').append($container).append($advancedContainer);
|
|
|
window.setTimeout(function () {
|
|
|
$modal.show();
|
|
|
$modal.focus();
|
|
|
});
|
|
|
};
|
|
|
|
|
|
UIElements.initFilePicker = function (common, cfg) {
|
|
|
var onSelect = cfg.onSelect || $.noop;
|
|
|
var sframeChan = common.getSframeChannel();
|
|
|
sframeChan.on("EV_FILE_PICKED", function (data) {
|
|
|
onSelect(data);
|
|
|
});
|
|
|
};
|
|
|
UIElements.openFilePicker = function (common, types) {
|
|
|
var sframeChan = common.getSframeChannel();
|
|
|
sframeChan.event("EV_FILE_PICKER_OPEN", types);
|
|
|
};
|
|
|
|
|
|
UIElements.openTemplatePicker = function (common, force) {
|
|
|
var metadataMgr = common.getMetadataMgr();
|
|
|
var type = metadataMgr.getMetadataLazy().type;
|
|
|
var sframeChan = common.getSframeChannel();
|
|
|
var focus;
|
|
|
|
|
|
var pickerCfgInit = {
|
|
|
types: [type],
|
|
|
where: ['template'],
|
|
|
hidden: true
|
|
|
};
|
|
|
var pickerCfg = {
|
|
|
types: [type],
|
|
|
where: ['template'],
|
|
|
};
|
|
|
var onConfirm = function (yes) {
|
|
|
if (!yes) {
|
|
|
if (focus) { focus.focus(); }
|
|
|
return;
|
|
|
}
|
|
|
delete pickerCfg.hidden;
|
|
|
common.openFilePicker(pickerCfg);
|
|
|
var first = true; // We can only pick a template once (for a new document)
|
|
|
var fileDialogCfg = {
|
|
|
onSelect: function (data) {
|
|
|
if (data.type === type && first) {
|
|
|
UI.addLoadingScreen({hideTips: true});
|
|
|
var chatChan = common.getPadChat();
|
|
|
var cursorChan = common.getCursorChannel();
|
|
|
sframeChan.query('Q_TEMPLATE_USE', {
|
|
|
href: data.href,
|
|
|
chat: chatChan,
|
|
|
cursor: cursorChan
|
|
|
}, function () {
|
|
|
first = false;
|
|
|
UI.removeLoadingScreen();
|
|
|
Feedback.send('TEMPLATE_USED');
|
|
|
});
|
|
|
if (focus) { focus.focus(); }
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
common.initFilePicker(fileDialogCfg);
|
|
|
};
|
|
|
|
|
|
sframeChan.query("Q_TEMPLATE_EXIST", type, function (err, data) {
|
|
|
if (data) {
|
|
|
common.openFilePicker(pickerCfgInit);
|
|
|
focus = document.activeElement;
|
|
|
if (force) { return void onConfirm(true); }
|
|
|
UI.confirm(Messages.useTemplate, onConfirm, {
|
|
|
ok: Messages.useTemplateOK,
|
|
|
cancel: Messages.useTemplateCancel,
|
|
|
});
|
|
|
} else if (force) {
|
|
|
UI.alert(Messages.template_empty);
|
|
|
}
|
|
|
});
|
|
|
};
|
|
|
|
|
|
UIElements.setExpirationValue = function (val, $expire) {
|
|
|
if (val && typeof (val) === "number") {
|
|
|
$expire.find('#cp-creation-expire').attr('checked', true).trigger('change');
|
|
|
$expire.find('#cp-creation-expire-true').attr('checked', true);
|
|
|
if (val % (3600 * 24 * 30) === 0) {
|
|
|
$expire.find('#cp-creation-expire-unit').val("month");
|
|
|
$expire.find('#cp-creation-expire-val').val(val / (3600 * 24 * 30));
|
|
|
return;
|
|
|
}
|
|
|
if (val % (3600 * 24) === 0) {
|
|
|
$expire.find('#cp-creation-expire-unit').val("day");
|
|
|
$expire.find('#cp-creation-expire-val').val(val / (3600 * 24));
|
|
|
return;
|
|
|
}
|
|
|
if (val % 3600 === 0) {
|
|
|
$expire.find('#cp-creation-expire-unit').val("hour");
|
|
|
$expire.find('#cp-creation-expire-val').val(val / 3600);
|
|
|
return;
|
|
|
}
|
|
|
// if we're here, it means we don't have a valid value so we should check unlimited
|
|
|
$expire.find('#cp-creation-expire-false').attr('checked', true);
|
|
|
}
|
|
|
};
|
|
|
UIElements.getPadCreationScreen = function (common, cfg, appCfg, cb) {
|
|
|
appCfg = appCfg || {};
|
|
|
if (!common.isLoggedIn()) { return void cb(); }
|
|
|
var sframeChan = common.getSframeChannel();
|
|
|
var metadataMgr = common.getMetadataMgr();
|
|
|
var privateData = metadataMgr.getPrivateData();
|
|
|
var type = metadataMgr.getMetadataLazy().type;
|
|
|
var fromFileData = privateData.fromFileData;
|
|
|
|
|
|
var $body = $('body');
|
|
|
var $creationContainer = $('<div>', { id: 'cp-creation-container' }).appendTo($body);
|
|
|
var urlArgs = (Config.requireConf && Config.requireConf.urlArgs) || '';
|
|
|
var l = h('div.cp-creation-logo', h('img', { src: '/customize/loading-logo.png?' + urlArgs }));
|
|
|
$(l).appendTo($creationContainer);
|
|
|
var $creation = $('<div>', { id: 'cp-creation', tabindex: 1 }).appendTo($creationContainer);
|
|
|
|
|
|
// Title
|
|
|
//var colorClass = 'cp-icon-color-'+type;
|
|
|
//$creation.append(h('h2.cp-creation-title', Messages.newButtonTitle));
|
|
|
var newPadH3Title = Messages['button_new' + type];
|
|
|
$creation.append(h('h3.cp-creation-title', newPadH3Title));
|
|
|
//$creation.append(h('h2.cp-creation-title.'+colorClass, Messages.newButtonTitle));
|
|
|
|
|
|
// Deleted pad warning
|
|
|
if (metadataMgr.getPrivateData().isDeleted) {
|
|
|
$creation.append(h('div.cp-creation-deleted-container',
|
|
|
h('div.cp-creation-deleted', Messages.creation_404)
|
|
|
));
|
|
|
}
|
|
|
|
|
|
var origin = privateData.origin;
|
|
|
var createHelper = function (href, text) {
|
|
|
var q = h('a.cp-creation-help.fa.fa-question-circle', {
|
|
|
title: text,
|
|
|
href: origin + href,
|
|
|
target: "_blank",
|
|
|
'data-tippy-placement': "right"
|
|
|
});
|
|
|
return q;
|
|
|
};
|
|
|
|
|
|
// Team pad
|
|
|
var team;
|
|
|
var teamExists = privateData.teams && Object.keys(privateData.teams).length;
|
|
|
var teamValue;
|
|
|
// storeInTeam can be
|
|
|
// * a team ID ==> store in the team drive, and the team will be the owner
|
|
|
// * -1 ==> store in the user drive, and the user will be the owner
|
|
|
// * undefined ==> ask
|
|
|
if (teamExists) {
|
|
|
var teams = Object.keys(privateData.teams).map(function (id) {
|
|
|
var data = privateData.teams[id];
|
|
|
var avatar = h('span.cp-creation-team-avatar.cp-avatar');
|
|
|
UIElements.displayAvatar(common, $(avatar), data.avatar, data.name);
|
|
|
return h('div.cp-creation-team', {
|
|
|
'data-id': id,
|
|
|
title: data.name,
|
|
|
},[
|
|
|
avatar,
|
|
|
h('span.cp-creation-team-name', data.name)
|
|
|
]);
|
|
|
});
|
|
|
teams.unshift(h('div.cp-creation-team', {
|
|
|
'data-id': '-1',
|
|
|
title: Messages.settings_cat_drive
|
|
|
}, [
|
|
|
h('span.cp-creation-team-avatar.fa.fa-hdd-o'),
|
|
|
h('span.cp-creation-team-name', Messages.settings_cat_drive)
|
|
|
]));
|
|
|
team = h('div.cp-creation-teams', [
|
|
|
Messages.team_pcsSelectLabel,
|
|
|
h('div.cp-creation-teams-grid', teams),
|
|
|
createHelper('#', Messages.team_pcsSelectHelp)
|
|
|
]);
|
|
|
var $team = $(team);
|
|
|
$team.find('.cp-creation-team').click(function () {
|
|
|
if ($(this).hasClass('cp-selected')) {
|
|
|
teamValue = undefined;
|
|
|
return void $(this).removeClass('cp-selected');
|
|
|
}
|
|
|
$team.find('.cp-creation-team').removeClass('cp-selected');
|
|
|
$(this).addClass('cp-selected');
|
|
|
teamValue = $(this).attr('data-id');
|
|
|
});
|
|
|
if (privateData.storeInTeam) {
|
|
|
$team.find('[data-id="'+privateData.storeInTeam+'"]').addClass('cp-selected');
|
|
|
teamValue = privateData.storeInTeam;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
// Owned pads
|
|
|
// Default is Owned pad
|
|
|
var owned = h('div.cp-creation-owned', [
|
|
|
UI.createCheckbox('cp-creation-owned', Messages.creation_owned, true),
|
|
|
createHelper('/faq.html#keywords-owned', Messages.creation_owned1)
|
|
|
]);
|
|
|
|
|
|
// Life time
|
|
|
var expire = h('div.cp-creation-expire', [
|
|
|
UI.createCheckbox('cp-creation-expire', Messages.creation_expire, false),
|
|
|
h('span.cp-creation-expire-picker.cp-creation-slider', [
|
|
|
h('input#cp-creation-expire-val', {
|
|
|
type: "number",
|
|
|
min: 1,
|
|
|
max: 100,
|
|
|
value: 3
|
|
|
}),
|
|
|
h('select#cp-creation-expire-unit', [
|
|
|
h('option', { value: 'hour' }, Messages.creation_expireHours),
|
|
|
h('option', { value: 'day' }, Messages.creation_expireDays),
|
|
|
h('option', {
|
|
|
value: 'month',
|
|
|
selected: 'selected'
|
|
|
}, Messages.creation_expireMonths)
|
|
|
])
|
|
|
]),
|
|
|
createHelper('/faq.html#keywords-expiring', Messages.creation_expire2),
|
|
|
]);
|
|
|
|
|
|
// Password
|
|
|
var password = h('div.cp-creation-password', [
|
|
|
UI.createCheckbox('cp-creation-password', Messages.creation_password, false),
|
|
|
h('span.cp-creation-password-picker.cp-creation-slider', [
|
|
|
UI.passwordInput({id: 'cp-creation-password-val'})
|
|
|
/*h('input#cp-creation-password-val', {
|
|
|
type: "text" // TODO type password with click to show
|
|
|
}),*/
|
|
|
]),
|
|
|
//createHelper('#', "TODO: password protection adds another layer of security ........") // TODO
|
|
|
]);
|
|
|
|
|
|
var right = h('span.fa.fa-chevron-right.cp-creation-template-more');
|
|
|
var left = h('span.fa.fa-chevron-left.cp-creation-template-more');
|
|
|
var templates = h('div.cp-creation-template', [
|
|
|
left,
|
|
|
h('div.cp-creation-template-container', [
|
|
|
h('span.fa.fa-circle-o-notch.fa-spin.fa-4x.fa-fw')
|
|
|
]),
|
|
|
right
|
|
|
]);
|
|
|
|
|
|
var settings = h('div.cp-creation-remember', [
|
|
|
UI.createCheckbox('cp-creation-remember', Messages.creation_saveSettings, false),
|
|
|
createHelper('/settings/#creation', Messages.creation_settings),
|
|
|
h('div.cp-creation-remember-help.cp-creation-slider', [
|
|
|
h('span.fa.fa-exclamation-circle.cp-creation-warning'),
|
|
|
Messages.creation_rememberHelp
|
|
|
])
|
|
|
]);
|
|
|
|
|
|
var createDiv = h('div.cp-creation-create');
|
|
|
var $create = $(createDiv);
|
|
|
|
|
|
$(h('div#cp-creation-form', [
|
|
|
team,
|
|
|
owned,
|
|
|
expire,
|
|
|
password,
|
|
|
settings,
|
|
|
templates,
|
|
|
createDiv
|
|
|
])).appendTo($creation);
|
|
|
|
|
|
// Display templates
|
|
|
|
|
|
var selected = 0; // Selected template in the list (highlighted)
|
|
|
var TEMPLATES_DISPLAYED = 4; // Max templates displayed per page
|
|
|
var next = function () {}; // Function called when pressing tab to highlight the next template
|
|
|
var i = 0; // Index of the first template displayed in the current page
|
|
|
sframeChan.query("Q_CREATE_TEMPLATES", type, function (err, res) {
|
|
|
if (!res.data || !Array.isArray(res.data)) {
|
|
|
return void console.error("Error: get the templates list");
|
|
|
}
|
|
|
var allData = res.data.slice().sort(function (a, b) {
|
|
|
if (a.used === b.used) {
|
|
|
// Sort by name
|
|
|
if (a.name === b.name) { return 0; }
|
|
|
return a.name < b.name ? -1 : 1;
|
|
|
}
|
|
|
return b.used - a.used;
|
|
|
});
|
|
|
if (!appCfg.noTemplates) {
|
|
|
allData.unshift({
|
|
|
name: Messages.creation_newTemplate,
|
|
|
id: -1,
|
|
|
//icon: h('span.fa.fa-bookmark')
|
|
|
icon: h('span.cptools.cptools-new-template')
|
|
|
});
|
|
|
}
|
|
|
allData.unshift({
|
|
|
name: Messages.creation_noTemplate,
|
|
|
id: 0,
|
|
|
//icon: h('span.fa.fa-file')
|
|
|
icon: UI.getFileIcon({type: type})
|
|
|
});
|
|
|
var redraw = function (index) {
|
|
|
if (index < 0) { i = 0; }
|
|
|
else if (index > allData.length - 1) { return; }
|
|
|
else { i = index; }
|
|
|
var data = allData.slice(i, i + TEMPLATES_DISPLAYED);
|
|
|
var $container = $(templates).find('.cp-creation-template-container').html('');
|
|
|
data.forEach(function (obj, idx) {
|
|
|
var name = obj.name;
|
|
|
var $span = $('<span>', {
|
|
|
'class': 'cp-creation-template-element',
|
|
|
'title': name,
|
|
|
}).appendTo($container);
|
|
|
$span.data('id', obj.id);
|
|
|
if (idx === selected) { $span.addClass('cp-creation-template-selected'); }
|
|
|
if (!obj.thumbnail) {
|
|
|
$span.append(obj.icon || h('span.cptools.cptools-template'));
|
|
|
}
|
|
|
$('<span>', {'class': 'cp-creation-template-element-name'}).text(name)
|
|
|
.appendTo($span);
|
|
|
$span.click(function () {
|
|
|
$container.find('.cp-creation-template-selected')
|
|
|
.removeClass('cp-creation-template-selected');
|
|
|
$span.addClass('cp-creation-template-selected');
|
|
|
selected = idx;
|
|
|
});
|
|
|
|
|
|
// Add thumbnail if it exists
|
|
|
if (obj.thumbnail) {
|
|
|
common.addThumbnail(obj.thumbnail, $span, function () {});
|
|
|
}
|
|
|
});
|
|
|
$(right).off('click').removeClass('hidden').click(function () {
|
|
|
selected = 0;
|
|
|
redraw(i + TEMPLATES_DISPLAYED);
|
|
|
});
|
|
|
if (i >= allData.length - TEMPLATES_DISPLAYED ) { $(right).addClass('hidden'); }
|
|
|
$(left).off('click').removeClass('hidden').click(function () {
|
|
|
selected = TEMPLATES_DISPLAYED - 1;
|
|
|
redraw(i - TEMPLATES_DISPLAYED);
|
|
|
});
|
|
|
if (i < TEMPLATES_DISPLAYED) { $(left).addClass('hidden'); }
|
|
|
};
|
|
|
if (fromFileData) {
|
|
|
var todo = function (thumbnail) {
|
|
|
allData = [{
|
|
|
name: fromFileData.title,
|
|
|
id: 0,
|
|
|
thumbnail: thumbnail,
|
|
|
icon: h('span.cptools.cptools-file'),
|
|
|
}];
|
|
|
redraw(0);
|
|
|
};
|
|
|
todo();
|
|
|
sframeChan.query("Q_GET_FILE_THUMBNAIL", null, function (err, res) {
|
|
|
if (err || (res && res.error)) { return; }
|
|
|
todo(res.data);
|
|
|
});
|
|
|
}
|
|
|
else {
|
|
|
redraw(0);
|
|
|
}
|
|
|
|
|
|
|
|
|
// Change template selection when Tab is pressed
|
|
|
next = function (revert) {
|
|
|
var max = $creation.find('.cp-creation-template-element').length;
|
|
|
if (selected + 1 === max && !revert) {
|
|
|
selected = i + TEMPLATES_DISPLAYED < allData.length ? 0 : max;
|
|
|
return void redraw(i + TEMPLATES_DISPLAYED);
|
|
|
}
|
|
|
if (selected === 0 && revert) {
|
|
|
selected = i - TEMPLATES_DISPLAYED >= 0 ? TEMPLATES_DISPLAYED - 1 : 0;
|
|
|
return void redraw(i - TEMPLATES_DISPLAYED);
|
|
|
}
|
|
|
selected = revert ?
|
|
|
(--selected < 0 ? 0 : selected) :
|
|
|
++selected >= max ? max-1 : selected;
|
|
|
$creation.find('.cp-creation-template-element')
|
|
|
.removeClass('cp-creation-template-selected');
|
|
|
$($creation.find('.cp-creation-template-element').get(selected))
|
|
|
.addClass('cp-creation-template-selected');
|
|
|
};
|
|
|
|
|
|
});
|
|
|
|
|
|
// Display expiration form when checkbox checked
|
|
|
$creation.find('#cp-creation-expire').on('change', function () {
|
|
|
if ($(this).is(':checked')) {
|
|
|
$creation.find('.cp-creation-expire-picker:not(.active)').addClass('active');
|
|
|
$creation.find('.cp-creation-expire:not(.active)').addClass('active');
|
|
|
$creation.find('#cp-creation-expire-val').focus();
|
|
|
return;
|
|
|
}
|
|
|
$creation.find('.cp-creation-expire-picker').removeClass('active');
|
|
|
$creation.find('.cp-creation-expire').removeClass('active');
|
|
|
$creation.focus();
|
|
|
});
|
|
|
|
|
|
// Display password form when checkbox checked
|
|
|
$creation.find('#cp-creation-password').on('change', function () {
|
|
|
if ($(this).is(':checked')) {
|
|
|
$creation.find('.cp-creation-password-picker:not(.active)').addClass('active');
|
|
|
$creation.find('.cp-creation-password:not(.active)').addClass('active');
|
|
|
$creation.find('#cp-creation-password-val').focus();
|
|
|
return;
|
|
|
}
|
|
|
$creation.find('.cp-creation-password-picker').removeClass('active');
|
|
|
$creation.find('.cp-creation-password').removeClass('active');
|
|
|
$creation.focus();
|
|
|
});
|
|
|
|
|
|
// Display settings help when checkbox checked
|
|
|
$creation.find('#cp-creation-remember').on('change', function () {
|
|
|
if ($(this).is(':checked')) {
|
|
|
$creation.find('.cp-creation-remember-help:not(.active)').addClass('active');
|
|
|
return;
|
|
|
}
|
|
|
$creation.find('.cp-creation-remember-help').removeClass('active');
|
|
|
$creation.focus();
|
|
|
});
|
|
|
|
|
|
// Keyboard shortcuts
|
|
|
$creation.find('#cp-creation-expire-val').keydown(function (e) {
|
|
|
if (e.which === 9) {
|
|
|
e.stopPropagation();
|
|
|
}
|
|
|
});
|
|
|
$creation.find('#cp-creation-expire-unit').keydown(function (e) {
|
|
|
if (e.which === 9 && e.shiftKey) {
|
|
|
e.stopPropagation();
|
|
|
}
|
|
|
});
|
|
|
|
|
|
|
|
|
// Initial values
|
|
|
if (!cfg.owned && typeof cfg.owned !== "undefined") {
|
|
|
$creation.find('#cp-creation-owned').prop('checked', false);
|
|
|
}
|
|
|
if (cfg.skip) {
|
|
|
$creation.find('#cp-creation-remember').prop('checked', true).trigger('change');
|
|
|
}
|
|
|
UIElements.setExpirationValue(cfg.expire, $creation);
|
|
|
|
|
|
// Create the pad
|
|
|
var getFormValues = function () {
|
|
|
// Type of pad
|
|
|
var ownedVal = $('#cp-creation-owned').is(':checked') ? 1 : 0;
|
|
|
// Life time
|
|
|
var expireVal = 0;
|
|
|
if($('#cp-creation-expire').is(':checked')) {
|
|
|
var unit = 0;
|
|
|
switch ($('#cp-creation-expire-unit').val()) {
|
|
|
case "hour" : unit = 3600; break;
|
|
|
case "day" : unit = 3600 * 24; break;
|
|
|
case "month": unit = 3600 * 24 * 30; break;
|
|
|
default: unit = 0;
|
|
|
}
|
|
|
expireVal = ($('#cp-creation-expire-val').val() || 0) * unit;
|
|
|
}
|
|
|
// Password
|
|
|
var passwordVal = $('#cp-creation-password').is(':checked') ?
|
|
|
$('#cp-creation-password-val').val() : undefined;
|
|
|
|
|
|
var $template = $creation.find('.cp-creation-template-selected');
|
|
|
var templateId = $template.data('id') || undefined;
|
|
|
// Team
|
|
|
var team;
|
|
|
if (teamValue) {
|
|
|
team = privateData.teams[teamValue] || {};
|
|
|
team.id = Number(teamValue);
|
|
|
}
|
|
|
|
|
|
return {
|
|
|
owned: ownedVal,
|
|
|
password: passwordVal,
|
|
|
expire: expireVal,
|
|
|
templateId: templateId,
|
|
|
team: team
|
|
|
};
|
|
|
};
|
|
|
var create = function () {
|
|
|
var val = getFormValues();
|
|
|
|
|
|
var skip = $('#cp-creation-remember').is(':checked');
|
|
|
common.setAttribute(['general', 'creation', 'skip'], skip, function (e) {
|
|
|
if (e) { return void console.error(e); }
|
|
|
});
|
|
|
common.setAttribute(['general', 'creation', 'noTemplate'], skip, function (e) {
|
|
|
if (e) { return void console.error(e); }
|
|
|
});
|
|
|
|
|
|
common.setAttribute(['general', 'creation', 'owned'], val.owned, function (e) {
|
|
|
if (e) { return void console.error(e); }
|
|
|
});
|
|
|
common.setAttribute(['general', 'creation', 'expire'], val.expire, function (e) {
|
|
|
if (e) { return void console.error(e); }
|
|
|
});
|
|
|
|
|
|
if (val.expire) {
|
|
|
Feedback.send('EXPIRING_PAD-'+val.expire);
|
|
|
}
|
|
|
|
|
|
$creationContainer.remove();
|
|
|
common.createPad(val, function () {
|
|
|
cb();
|
|
|
});
|
|
|
};
|
|
|
|
|
|
|
|
|
var $button = $('<button>').text(Messages.creation_create).appendTo($create);
|
|
|
$button.addClass('cp-creation-button-selected');
|
|
|
$button.click(function () {
|
|
|
create();
|
|
|
});
|
|
|
|
|
|
$creation.keydown(function (e) {
|
|
|
if (e.which === 9) {
|
|
|
e.preventDefault();
|
|
|
e.stopPropagation();
|
|
|
next(e.shiftKey);
|
|
|
return;
|
|
|
}
|
|
|
if (e.which === 13) {
|
|
|
$button.click();
|
|
|
return;
|
|
|
}
|
|
|
});
|
|
|
$creation.focus();
|
|
|
};
|
|
|
|
|
|
UIElements.onServerError = function (common, err, toolbar, cb) {
|
|
|
if (["EDELETED", "EEXPIRED"].indexOf(err.type) === -1) { return; }
|
|
|
var priv = common.getMetadataMgr().getPrivateData();
|
|
|
var msg = err.type;
|
|
|
if (err.type === 'EEXPIRED') {
|
|
|
msg = Messages.expiredError;
|
|
|
if (err.loaded) {
|
|
|
msg += Messages.errorCopy;
|
|
|
}
|
|
|
} else if (err.type === 'EDELETED') {
|
|
|
if (priv.burnAfterReading) { return void cb(); }
|
|
|
msg = Messages.deletedError;
|
|
|
if (err.loaded) {
|
|
|
msg += Messages.errorCopy;
|
|
|
}
|
|
|
}
|
|
|
if (toolbar && typeof toolbar.deleted === "function") { toolbar.deleted(); }
|
|
|
UI.errorLoadingScreen(msg, true, true);
|
|
|
(cb || function () {})();
|
|
|
};
|
|
|
|
|
|
UIElements.displayPasswordPrompt = function (common, cfg, isError) {
|
|
|
var error;
|
|
|
if (isError) { error = setHTML(h('p.cp-password-error'), Messages.password_error); }
|
|
|
var info = h('p.cp-password-info', Messages.password_info);
|
|
|
var password = UI.passwordInput({placeholder: Messages.password_placeholder});
|
|
|
var $password = $(password);
|
|
|
var button = h('button', Messages.password_submit);
|
|
|
cfg = cfg || {};
|
|
|
|
|
|
if (cfg.value && !isError) {
|
|
|
$password.find('.cp-password-input').val(cfg.value);
|
|
|
}
|
|
|
|
|
|
var submit = function () {
|
|
|
var value = $password.find('.cp-password-input').val();
|
|
|
UI.addLoadingScreen();
|
|
|
common.getSframeChannel().query('Q_PAD_PASSWORD_VALUE', value, function (err, data) {
|
|
|
if (!data) {
|
|
|
UIElements.displayPasswordPrompt(common, cfg, true);
|
|
|
}
|
|
|
});
|
|
|
};
|
|
|
$password.find('.cp-password-input').on('keydown', function (e) { if (e.which === 13) { submit(); } });
|
|
|
$(button).on('click', function () { submit(); });
|
|
|
|
|
|
|
|
|
var block = h('div#cp-loading-password-prompt', [
|
|
|
error,
|
|
|
info,
|
|
|
h('p.cp-password-form', [
|
|
|
password,
|
|
|
button
|
|
|
])
|
|
|
]);
|
|
|
UI.errorLoadingScreen(block);
|
|
|
|
|
|
$password.find('.cp-password-input').focus();
|
|
|
};
|
|
|
|
|
|
UIElements.displayBurnAfterReadingPage = function (common, cb) {
|
|
|
var info = h('p.cp-password-info', 'This document will self-destruct as soon as you open it. It will be removed form the server, once you close this window you will not be able to access it again. If you are not ready to proceed you can close this window and come back later. '); // XXX KEY
|
|
|
var button = h('button.primary', 'view and delete'); // XXX KEY
|
|
|
|
|
|
$(button).on('click', function () {
|
|
|
cb();
|
|
|
});
|
|
|
|
|
|
var block = h('div#cp-loading-burn-after-reading', [
|
|
|
info,
|
|
|
button
|
|
|
]);
|
|
|
UI.errorLoadingScreen(block);
|
|
|
};
|
|
|
UIElements.getBurnAfterReadingWarning = function (common) {
|
|
|
var priv = common.getMetadataMgr().getPrivateData();
|
|
|
if (!priv.burnAfterReading) { return; }
|
|
|
return h('div.alert.alert-danger.cp-burn-after-reading', 'This pad has been deleted from the server, once you close this window you will not be able to access it again.'); // XXX KEY
|
|
|
};
|
|
|
|
|
|
var crowdfundingState = false;
|
|
|
UIElements.displayCrowdfunding = function (common) {
|
|
|
if (crowdfundingState) { return; }
|
|
|
if (AppConfig.disableCrowdfundingMessages) { return; }
|
|
|
var priv = common.getMetadataMgr().getPrivateData();
|
|
|
if (priv.plan) { return; }
|
|
|
|
|
|
crowdfundingState = true;
|
|
|
setTimeout(function () {
|
|
|
common.getAttribute(['general', 'crowdfunding'], function (err, val) {
|
|
|
if (err || val === false) { return; }
|
|
|
common.getSframeChannel().query('Q_GET_PINNED_USAGE', null, function (err, obj) {
|
|
|
var quotaMb = obj.quota / (1024 * 1024);
|
|
|
if (quotaMb < 10) { return; }
|
|
|
// Display the popup
|
|
|
var text = Messages.crowdfunding_popup_text;
|
|
|
var yes = h('button.cp-corner-primary', Messages.crowdfunding_popup_yes);
|
|
|
var no = h('button.cp-corner-primary', Messages.crowdfunding_popup_no);
|
|
|
var never = h('button.cp-corner-cancel', Messages.crowdfunding_popup_never);
|
|
|
var actions = h('div', [yes, no, never]);
|
|
|
|
|
|
var modal = UI.cornerPopup(text, actions, null, {big: true});
|
|
|
|
|
|
$(yes).click(function () {
|
|
|
modal.delete();
|
|
|
common.openURL(priv.accounts.donateURL);
|
|
|
Feedback.send('CROWDFUNDING_YES');
|
|
|
});
|
|
|
$(modal.popup).find('a').click(function (e) {
|
|
|
e.stopPropagation();
|
|
|
e.preventDefault();
|
|
|
modal.delete();
|
|
|
common.openURL(priv.accounts.donateURL);
|
|
|
Feedback.send('CROWDFUNDING_LINK');
|
|
|
});
|
|
|
$(no).click(function () {
|
|
|
modal.delete();
|
|
|
Feedback.send('CROWDFUNDING_NO');
|
|
|
});
|
|
|
$(never).click(function () {
|
|
|
modal.delete();
|
|
|
common.setAttribute(['general', 'crowdfunding'], false);
|
|
|
Feedback.send('CROWDFUNDING_NEVER');
|
|
|
});
|
|
|
});
|
|
|
});
|
|
|
}, 5000);
|
|
|
};
|
|
|
|
|
|
var storePopupState = false;
|
|
|
var autoStoreModal = {};
|
|
|
UIElements.displayStorePadPopup = function (common, data) {
|
|
|
if (storePopupState) { return; }
|
|
|
storePopupState = true;
|
|
|
if (data && data.stored) { return; } // We won't display the popup for dropped files
|
|
|
var priv = common.getMetadataMgr().getPrivateData();
|
|
|
|
|
|
// This pad will be deleted automatically, it shouldn't be stored
|
|
|
if (priv.burnAfterReading) { return; }
|
|
|
|
|
|
var typeMsg = priv.pathname.indexOf('/file/') !== -1 ? Messages.autostore_file :
|
|
|
priv.pathname.indexOf('/drive/') !== -1 ? Messages.autostore_sf :
|
|
|
Messages.autostore_pad;
|
|
|
var text = Messages._getKey('autostore_notstored', [typeMsg]);
|
|
|
var footer = Messages.autostore_settings;
|
|
|
|
|
|
var hide = h('button.cp-corner-cancel', Messages.autostore_hide);
|
|
|
var store = h('button.cp-corner-primary', Messages.autostore_store);
|
|
|
var actions = h('div', [store, hide]);
|
|
|
|
|
|
var initialHide = data && data.autoStore && data.autoStore === -1;
|
|
|
var modal = UI.cornerPopup(text, actions, footer, {hidden: initialHide});
|
|
|
|
|
|
autoStoreModal[priv.channel] = modal;
|
|
|
|
|
|
$(modal.popup).find('.cp-corner-footer a').click(function (e) {
|
|
|
e.preventDefault();
|
|
|
common.openURL('/settings/');
|
|
|
});
|
|
|
|
|
|
$(hide).click(function () {
|
|
|
UIElements.displayCrowdfunding(common);
|
|
|
delete autoStoreModal[priv.channel];
|
|
|
modal.delete();
|
|
|
});
|
|
|
var waitingForStoringCb = false;
|
|
|
$(store).click(function () {
|
|
|
if (waitingForStoringCb) { return; }
|
|
|
waitingForStoringCb = true;
|
|
|
common.getSframeChannel().query("Q_AUTOSTORE_STORE", null, function (err, obj) {
|
|
|
waitingForStoringCb = false;
|
|
|
var error = err || (obj && obj.error);
|
|
|
if (error) {
|
|
|
if (error === 'E_OVER_LIMIT') {
|
|
|
return void UI.warn(Messages.pinLimitReached);
|
|
|
}
|
|
|
return void UI.warn(Messages.autostore_error);
|
|
|
}
|
|
|
$(document).trigger('cpPadStored');
|
|
|
delete autoStoreModal[priv.channel];
|
|
|
modal.delete();
|
|
|
UIElements.displayCrowdfunding(common);
|
|
|
UI.log(Messages.autostore_saved);
|
|
|
});
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
var createContextMenu = function (menu) {
|
|
|
var $menu = $(menu).appendTo($('body'));
|
|
|
|
|
|
var display = function (e) {
|
|
|
$menu.css({ display: "block" });
|
|
|
var h = $menu.outerHeight();
|
|
|
var w = $menu.outerWidth();
|
|
|
var wH = window.innerHeight;
|
|
|
var wW = window.innerWidth;
|
|
|
if (h > wH) {
|
|
|
$menu.css({
|
|
|
top: '0px',
|
|
|
bottom: ''
|
|
|
});
|
|
|
} else if (e.pageY + h <= wH) {
|
|
|
$menu.css({
|
|
|
top: e.pageY+'px',
|
|
|
bottom: ''
|
|
|
});
|
|
|
} else {
|
|
|
$menu.css({
|
|
|
bottom: '0px',
|
|
|
top: ''
|
|
|
});
|
|
|
}
|
|
|
if(w > wW) {
|
|
|
$menu.css({
|
|
|
left: '0px',
|
|
|
right: ''
|
|
|
});
|
|
|
} else if (e.pageX + w <= wW) {
|
|
|
$menu.css({
|
|
|
left: e.pageX+'px',
|
|
|
right: ''
|
|
|
});
|
|
|
} else {
|
|
|
$menu.css({
|
|
|
left: '',
|
|
|
right: '0px',
|
|
|
});
|
|
|
}
|
|
|
};
|
|
|
|
|
|
var hide = function () {
|
|
|
$menu.hide();
|
|
|
};
|
|
|
var remove = function () {
|
|
|
$menu.remove();
|
|
|
};
|
|
|
|
|
|
$('body').click(hide);
|
|
|
|
|
|
return {
|
|
|
menu: menu,
|
|
|
show: display,
|
|
|
hide: hide,
|
|
|
remove: remove
|
|
|
};
|
|
|
};
|
|
|
|
|
|
var mediatagContextMenu;
|
|
|
UIElements.importMediaTagMenu = function (common) {
|
|
|
if (mediatagContextMenu) { return mediatagContextMenu; }
|
|
|
|
|
|
// Create context menu
|
|
|
var menu = h('div.cp-contextmenu.dropdown.cp-unselectable', [
|
|
|
h('ul.dropdown-menu', {
|
|
|
'role': 'menu',
|
|
|
'aria-labelledBy': 'dropdownMenu',
|
|
|
'style': 'display:block;position:static;margin-bottom:5px;'
|
|
|
}, [
|
|
|
h('li', h('a.cp-app-code-context-saveindrive.dropdown-item', {
|
|
|
'tabindex': '-1',
|
|
|
'data-icon': "fa-cloud-upload",
|
|
|
}, Messages.pad_mediatagImport)),
|
|
|
h('li', h('a.cp-app-code-context-download.dropdown-item', {
|
|
|
'tabindex': '-1',
|
|
|
'data-icon': "fa-download",
|
|
|
}, Messages.download_mt_button)),
|
|
|
])
|
|
|
]);
|
|
|
// create the icon for each contextmenu option
|
|
|
$(menu).find("li a.dropdown-item").each(function (i, el) {
|
|
|
var $icon = $("<span>");
|
|
|
if ($(el).attr('data-icon')) {
|
|
|
var font = $(el).attr('data-icon').indexOf('cptools') === 0 ? 'cptools' : 'fa';
|
|
|
$icon.addClass(font).addClass($(el).attr('data-icon'));
|
|
|
} else {
|
|
|
$icon.text($(el).text());
|
|
|
}
|
|
|
$(el).prepend($icon);
|
|
|
});
|
|
|
var m = createContextMenu(menu);
|
|
|
|
|
|
mediatagContextMenu = m;
|
|
|
|
|
|
var $menu = $(m.menu);
|
|
|
$menu.on('click', 'a', function (e) {
|
|
|
e.stopPropagation();
|
|
|
m.hide();
|
|
|
var $mt = $menu.data('mediatag');
|
|
|
if ($(this).hasClass("cp-app-code-context-saveindrive")) {
|
|
|
common.importMediaTag($mt);
|
|
|
}
|
|
|
else if ($(this).hasClass("cp-app-code-context-download")) {
|
|
|
var media = $mt[0]._mediaObject;
|
|
|
window.saveAs(media._blob.content, media.name);
|
|
|
}
|
|
|
});
|
|
|
|
|
|
return m;
|
|
|
};
|
|
|
|
|
|
UIElements.displayFriendRequestModal = function (common, data) {
|
|
|
var msg = data.content.msg;
|
|
|
var text = Messages._getKey('contacts_request', [Util.fixHTML(msg.content.displayName)]);
|
|
|
|
|
|
var todo = function (yes) {
|
|
|
common.getSframeChannel().query("Q_ANSWER_FRIEND_REQUEST", {
|
|
|
data: data,
|
|
|
value: yes
|
|
|
}, function (err, obj) {
|
|
|
var error = err || (obj && obj.error);
|
|
|
if (error) {
|
|
|
return void UI.warn(error);
|
|
|
}
|
|
|
if (yes) {
|
|
|
UI.log(Messages.contacts_added);
|
|
|
} else {
|
|
|
UI.log(Messages.contacts_rejected);
|
|
|
}
|
|
|
});
|
|
|
};
|
|
|
|
|
|
var content = h('div.cp-share-modal', [
|
|
|
setHTML(h('p'), text),
|
|
|
]);
|
|
|
UI.proposal(content, todo);
|
|
|
};
|
|
|
|
|
|
UIElements.displayAddOwnerModal = function (common, data) {
|
|
|
var priv = common.getMetadataMgr().getPrivateData();
|
|
|
var user = common.getMetadataMgr().getUserData();
|
|
|
var sframeChan = common.getSframeChannel();
|
|
|
var msg = data.content.msg;
|
|
|
|
|
|
var name = Util.fixHTML(msg.content.user.displayName) || Messages.anonymous;
|
|
|
var title = Util.fixHTML(msg.content.title);
|
|
|
|
|
|
var text = Messages._getKey('owner_add', [name, title]);
|
|
|
|
|
|
var link = h('a', {
|
|
|
href: '#'
|
|
|
}, Messages.requestEdit_viewPad);
|
|
|
$(link).click(function (e) {
|
|
|
e.preventDefault();
|
|
|
e.stopPropagation();
|
|
|
if (msg.content.password) {
|
|
|
common.sessionStorage.put('newPadPassword', msg.content.password, function () {
|
|
|
common.openURL(msg.content.href);
|
|
|
});
|
|
|
return;
|
|
|
}
|
|
|
common.openURL(msg.content.href);
|
|
|
});
|
|
|
|
|
|
var div = h('div', [
|
|
|
UI.setHTML(h('p'), text),
|
|
|
link
|
|
|
]);
|
|
|
|
|
|
var answer = function (yes) {
|
|
|
common.mailbox.sendTo("ADD_OWNER_ANSWER", {
|
|
|
channel: msg.content.channel,
|
|
|
href: msg.content.href,
|
|
|
password: msg.content.password,
|
|
|
title: msg.content.title,
|
|
|
answer: yes,
|
|
|
user: {
|
|
|
displayName: user.name,
|
|
|
avatar: user.avatar,
|
|
|
profile: user.profile,
|
|
|
notifications: user.notifications,
|
|
|
curvePublic: user.curvePublic,
|
|
|
edPublic: priv.edPublic
|
|
|
}
|
|
|
}, {
|
|
|
channel: msg.content.user.notifications,
|
|
|
curvePublic: msg.content.user.curvePublic
|
|
|
});
|
|
|
common.mailbox.dismiss(data, function (err) {
|
|
|
console.log(err);
|
|
|
});
|
|
|
};
|
|
|
|
|
|
var todo = function (yes) {
|
|
|
if (yes) {
|
|
|
// ACCEPT
|
|
|
sframeChan.query('Q_SET_PAD_METADATA', {
|
|
|
channel: msg.content.channel,
|
|
|
command: 'ADD_OWNERS',
|
|
|
value: [priv.edPublic]
|
|
|
}, function (err, res) {
|
|
|
err = err || (res && res.error);
|
|
|
if (err) {
|
|
|
var text = err === "INSUFFICIENT_PERMISSIONS" ? Messages.fm_forbidden
|
|
|
: Messages.error;
|
|
|
return void UI.warn(text);
|
|
|
}
|
|
|
UI.log(Messages.saved);
|
|
|
|
|
|
// Send notification to the sender
|
|
|
answer(true);
|
|
|
|
|
|
var data = JSON.parse(JSON.stringify(msg.content));
|
|
|
data.metadata = res;
|
|
|
|
|
|
// Add the pad to your drive
|
|
|
// This command will also add your mailbox to the metadata log
|
|
|
// The callback is called when the pad is stored, independantly of the metadata command
|
|
|
sframeChan.query('Q_ACCEPT_OWNERSHIP', data, function (err, res) {
|
|
|
if (err || (res && res.error)) {
|
|
|
return void console.error(err | res.error);
|
|
|
}
|
|
|
UI.log(Messages.saved);
|
|
|
if (autoStoreModal[data.channel]) {
|
|
|
autoStoreModal[data.channel].delete();
|
|
|
delete autoStoreModal[data.channel];
|
|
|
}
|
|
|
});
|
|
|
|
|
|
// Remove yourself from the pending owners
|
|
|
sframeChan.query('Q_SET_PAD_METADATA', {
|
|
|
channel: msg.content.channel,
|
|
|
command: 'RM_PENDING_OWNERS',
|
|
|
value: [priv.edPublic]
|
|
|
}, function (err, res) {
|
|
|
err = err || (res && res.error);
|
|
|
if (err) {
|
|
|
console.error(err);
|
|
|
}
|
|
|
});
|
|
|
});
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// DECLINE
|
|
|
// Remove yourself from the pending owners
|
|
|
sframeChan.query('Q_SET_PAD_METADATA', {
|
|
|
channel: msg.content.channel,
|
|
|
command: 'RM_PENDING_OWNERS',
|
|
|
value: [priv.edPublic]
|
|
|
}, function (err, res) {
|
|
|
err = err || (res && res.error);
|
|
|
if (err) {
|
|
|
console.error(err);
|
|
|
}
|
|
|
// Send notification to the sender
|
|
|
answer(false);
|
|
|
});
|
|
|
};
|
|
|
|
|
|
UI.proposal(div, todo);
|
|
|
};
|
|
|
UIElements.displayAddTeamOwnerModal = function (common, data) {
|
|
|
var priv = common.getMetadataMgr().getPrivateData();
|
|
|
var user = common.getMetadataMgr().getUserData();
|
|
|
var sframeChan = common.getSframeChannel();
|
|
|
var msg = data.content.msg;
|
|
|
|
|
|
var name = Util.fixHTML(msg.content.user.displayName) || Messages.anonymous;
|
|
|
var title = Util.fixHTML(msg.content.title);
|
|
|
|
|
|
var text = Messages._getKey('owner_team_add', [name, title]);
|
|
|
|
|
|
var div = h('div', [
|
|
|
UI.setHTML(h('p'), text),
|
|
|
]);
|
|
|
|
|
|
var answer = function (yes) {
|
|
|
common.mailbox.sendTo("ADD_OWNER_ANSWER", {
|
|
|
teamChannel: msg.content.teamChannel,
|
|
|
title: msg.content.title,
|
|
|
answer: yes,
|
|
|
user: {
|
|
|
displayName: user.name,
|
|
|
avatar: user.avatar,
|
|
|
profile: user.profile,
|
|
|
notifications: user.notifications,
|
|
|
curvePublic: user.curvePublic,
|
|
|
edPublic: priv.edPublic
|
|
|
}
|
|
|
}, {
|
|
|
channel: msg.content.user.notifications,
|
|
|
curvePublic: msg.content.user.curvePublic
|
|
|
});
|
|
|
common.mailbox.dismiss(data, function (err) {
|
|
|
if (err) { console.log(err); }
|
|
|
});
|
|
|
};
|
|
|
var module = common.makeUniversal('team');
|
|
|
|
|
|
var addOwner = function (chan, waitFor, cb) {
|
|
|
// Remove yourself from the pending owners
|
|
|
sframeChan.query('Q_SET_PAD_METADATA', {
|
|
|
channel: chan,
|
|
|
command: 'ADD_OWNERS',
|
|
|
value: [priv.edPublic]
|
|
|
}, function (err, res) {
|
|
|
err = err || (res && res.error);
|
|
|
if (!err) { return; }
|
|
|
waitFor.abort();
|
|
|
cb(err);
|
|
|
});
|
|
|
};
|
|
|
var removePending = function (chan, waitFor, cb) {
|
|
|
// Remove yourself from the pending owners
|
|
|
sframeChan.query('Q_SET_PAD_METADATA', {
|
|
|
channel: chan,
|
|
|
command: 'RM_PENDING_OWNERS',
|
|
|
value: [priv.edPublic]
|
|
|
}, waitFor(function (err, res) {
|
|
|
err = err || (res && res.error);
|
|
|
if (!err) { return; }
|
|
|
waitFor.abort();
|
|
|
cb(err);
|
|
|
}));
|
|
|
};
|
|
|
var changeAll = function (add, _cb) {
|
|
|
var f = add ? addOwner : removePending;
|
|
|
var cb = Util.once(_cb);
|
|
|
NThen(function (waitFor) {
|
|
|
f(msg.content.teamChannel, waitFor, cb);
|
|
|
f(msg.content.chatChannel, waitFor, cb);
|
|
|
f(msg.content.rosterChannel, waitFor, cb);
|
|
|
}).nThen(function () { cb(); });
|
|
|
};
|
|
|
|
|
|
var todo = function (yes) {
|
|
|
if (yes) {
|
|
|
// ACCEPT
|
|
|
changeAll(true, function (err) {
|
|
|
if (err) {
|
|
|
console.error(err);
|
|
|
var text = err === "INSUFFICIENT_PERMISSIONS" ? Messages.fm_forbidden
|
|
|
: Messages.error;
|
|
|
return void UI.warn(text);
|
|
|
}
|
|
|
UI.log(Messages.saved);
|
|
|
|
|
|
// Send notification to the sender
|
|
|
answer(true);
|
|
|
|
|
|
// Mark ourselves as "owner" in our local team data
|
|
|
module.execCommand("ANSWER_OWNERSHIP", {
|
|
|
teamChannel: msg.content.teamChannel,
|
|
|
answer: true
|
|
|
}, function (obj) {
|
|
|
if (obj && obj.error) { console.error(obj.error); }
|
|
|
});
|
|
|
|
|
|
// Remove yourself from the pending owners
|
|
|
changeAll(false, function (err) {
|
|
|
if (err) { console.error(err); }
|
|
|
});
|
|
|
});
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// DECLINE
|
|
|
// Remove yourself from the pending owners
|
|
|
changeAll(false, function (err) {
|
|
|
if (err) { console.error(err); }
|
|
|
// Send notification to the sender
|
|
|
answer(false);
|
|
|
// Set our role back to ADMIN
|
|
|
module.execCommand("ANSWER_OWNERSHIP", {
|
|
|
teamChannel: msg.content.teamChannel,
|
|
|
answer: false
|
|
|
}, function (obj) {
|
|
|
if (obj && obj.error) { console.error(obj.error); }
|
|
|
});
|
|
|
});
|
|
|
};
|
|
|
|
|
|
UI.proposal(div, todo);
|
|
|
};
|
|
|
|
|
|
UIElements.getVerifiedFriend = function (common, curve, name) {
|
|
|
var priv = common.getMetadataMgr().getPrivateData();
|
|
|
var verified = h('p');
|
|
|
var $verified = $(verified);
|
|
|
|
|
|
if (priv.friends && priv.friends[curve]) {
|
|
|
$verified.addClass('cp-notifications-requestedit-verified');
|
|
|
var f = priv.friends[curve];
|
|
|
$verified.append(h('span.fa.fa-certificate'));
|
|
|
var $avatar = $(h('span.cp-avatar')).appendTo($verified);
|
|
|
$verified.append(h('p', Messages._getKey('requestEdit_fromFriend', [f.displayName])));
|
|
|
common.displayAvatar($avatar, f.avatar, f.displayName);
|
|
|
} else {
|
|
|
$verified.append(Messages._getKey('requestEdit_fromStranger', [name]));
|
|
|
}
|
|
|
return verified;
|
|
|
};
|
|
|
|
|
|
UIElements.displayInviteTeamModal = function (common, data) {
|
|
|
var priv = common.getMetadataMgr().getPrivateData();
|
|
|
var user = common.getMetadataMgr().getUserData();
|
|
|
var msg = data.content.msg;
|
|
|
|
|
|
var name = Util.fixHTML(msg.content.user.displayName) || Messages.anonymous;
|
|
|
var teamName = Util.fixHTML(Util.find(msg, ['content', 'team', 'metadata', 'name']) || '');
|
|
|
|
|
|
var verified = UIElements.getVerifiedFriend(common, msg.author, name);
|
|
|
|
|
|
var text = Messages._getKey('team_invitedToTeam', [name, teamName]);
|
|
|
|
|
|
var div = h('div', [
|
|
|
UI.setHTML(h('p'), text),
|
|
|
verified
|
|
|
]);
|
|
|
|
|
|
var module = common.makeUniversal('team');
|
|
|
|
|
|
var answer = function (yes) {
|
|
|
common.mailbox.sendTo("INVITE_TO_TEAM_ANSWER", {
|
|
|
answer: yes,
|
|
|
teamChannel: msg.content.team.channel,
|
|
|
teamName: teamName,
|
|
|
user: {
|
|
|
displayName: user.name,
|
|
|
avatar: user.avatar,
|
|
|
profile: user.profile,
|
|
|
notifications: user.notifications,
|
|
|
curvePublic: user.curvePublic,
|
|
|
edPublic: priv.edPublic
|
|
|
}
|
|
|
}, {
|
|
|
channel: msg.content.user.notifications,
|
|
|
curvePublic: msg.content.user.curvePublic
|
|
|
});
|
|
|
common.mailbox.dismiss(data, function (err) {
|
|
|
console.log(err);
|
|
|
});
|
|
|
};
|
|
|
|
|
|
var MAX_TEAMS_SLOTS = Constants.MAX_TEAMS_SLOTS;
|
|
|
var todo = function (yes) {
|
|
|
var priv = common.getMetadataMgr().getPrivateData();
|
|
|
var numberOfTeams = Object.keys(priv.teams || {}).length;
|
|
|
if (yes) {
|
|
|
if (numberOfTeams >= MAX_TEAMS_SLOTS) {
|
|
|
return void UI.alert(Messages._getKey('team_maxTeams', [MAX_TEAMS_SLOTS]));
|
|
|
}
|
|
|
// ACCEPT
|
|
|
module.execCommand('JOIN_TEAM', {
|
|
|
team: msg.content.team
|
|
|
}, function (obj) {
|
|
|
if (obj && obj.error) {
|
|
|
if (obj.error === 'ENOENT') {
|
|
|
common.mailbox.dismiss(data, function () {});
|
|
|
return void UI.alert(Messages.deletedError);
|
|
|
}
|
|
|
return void UI.warn(Messages.error);
|
|
|
}
|
|
|
answer(true);
|
|
|
if (priv.app !== 'teams') { common.openURL('/teams/'); }
|
|
|
});
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// DECLINE
|
|
|
answer(false);
|
|
|
};
|
|
|
|
|
|
UI.proposal(div, todo);
|
|
|
};
|
|
|
|
|
|
return UIElements;
|
|
|
});
|