Initial work on the 'pad will expire' logic

This commit is contained in:
Caleb James DeLisle 2017-12-05 17:48:30 +01:00
parent 7544bb1ced
commit c702a23c77
18 changed files with 263 additions and 21 deletions

View File

@ -42,42 +42,54 @@
@colortheme_pad-bg: #1c4fa0; @colortheme_pad-bg: #1c4fa0;
@colortheme_pad-color: #fff; @colortheme_pad-color: #fff;
@colortheme_pad-toolbar-bg: #c1e7ff; @colortheme_pad-toolbar-bg: #c1e7ff;
@colortheme_pad-warn: #F83A3A;
@colortheme_slide-bg: #e57614; @colortheme_slide-bg: #e57614;
@colortheme_slide-color: #fff; @colortheme_slide-color: #fff;
@colortheme_slide-warn: #7bccd1;
@colortheme_code-bg: #ffae00; @colortheme_code-bg: #ffae00;
@colortheme_code-color: #000; @colortheme_code-color: #000;
@colortheme_code-warn: #005bef;
@colortheme_poll-bg: #006304; @colortheme_poll-bg: #006304;
@colortheme_poll-color: #fff; @colortheme_poll-color: #fff;
@colortheme_poll-help-bg: #bbffbb; @colortheme_poll-help-bg: #bbffbb;
@colortheme_poll-th-bg: #005bef; @colortheme_poll-th-bg: #005bef;
@colortheme_poll-th-fg: #fff; @colortheme_poll-th-fg: #fff;
@colortheme_poll-warn: #cd2532;
@colortheme_whiteboard-bg: #800080; @colortheme_whiteboard-bg: #800080;
@colortheme_whiteboard-color: #fff; @colortheme_whiteboard-color: #fff;
@colortheme_whiteboard-warn: #ffae00;
@colortheme_drive-bg: #0087ff; @colortheme_drive-bg: #0087ff;
@colortheme_drive-color: #fff; @colortheme_drive-color: #fff;
@colortheme_drive-warn: #cd2532;
@colortheme_file-bg: #cd2532; @colortheme_file-bg: #cd2532;
@colortheme_file-color: #fff; @colortheme_file-color: #fff;
@colortheme_file-warn: #ffae00;
@colortheme_friends-bg: #607b8d; @colortheme_friends-bg: #607b8d;
@colortheme_friends-color: #fff; @colortheme_friends-color: #fff;
@colortheme_friends-warn: #cd2532;
@colortheme_default-bg: #ddd; @colortheme_default-bg: #ddd;
@colortheme_default-color: #000; @colortheme_default-color: #000;
@colortheme_default-warn: #cd2532;
@colortheme_settings-bg: #0087ff; @colortheme_settings-bg: #0087ff;
@colortheme_settings-color: #fff; @colortheme_settings-color: #fff;
@colortheme_settings-warn: #cd2532;
@colortheme_profile-bg: #0087ff; @colortheme_profile-bg: #0087ff;
@colortheme_profile-color: #fff; @colortheme_profile-color: #fff;
@colortheme_profile-warn: #cd2532;
@colortheme_todo-bg: #7bccd1; @colortheme_todo-bg: #7bccd1;
@colortheme_todo-color: #000; @colortheme_todo-color: #000;
@colortheme_todo-warn: #cd2532;
// Sidebar layout (profile / settings) // Sidebar layout (profile / settings)
@colortheme_sidebar-active: #fff; @colortheme_sidebar-active: #fff;

View File

@ -7,6 +7,7 @@
@import (once) "./icon-colors.less"; @import (once) "./icon-colors.less";
@import (once) "./tools.less"; @import (once) "./tools.less";
@_cp-toolbar-color-warn: black;
.toolbar_main () { .toolbar_main () {
@ -224,6 +225,7 @@
} }
.cp-toolbar-limit { .cp-toolbar-limit {
text-shadow: -1px 0 @color, 0 1px @color, 1px 0 @color, 0 -1px @color; text-shadow: -1px 0 @color, 0 1px @color, 1px 0 @color, 0 -1px @color;
color: @_cp-toolbar-color-warn;
} }
.cp-toolbar-leftside, .cp-toolbar-rightside { .cp-toolbar-leftside, .cp-toolbar-rightside {
background-color: lighten(@bgcolor, 8%); background-color: lighten(@bgcolor, 8%);
@ -238,6 +240,19 @@
width: 100%; width: 100%;
} }
} }
.cp-pad-not-pinned {
padding-left: 20px;
font-size: @colortheme_app-font-size;
color: @_cp-toolbar-color-warn;
a {
font-size: @colortheme_app-font-size;
font-weight: bold;
color: @_cp-toolbar-color-warn;
&:hover {
text-decoration: underline;
}
}
}
.cp-toolbar-title-hoverable:hover { .cp-toolbar-title-hoverable:hover {
.cp-toolbar-title-editable, .cp-toolbar-title-edit { .cp-toolbar-title-editable, .cp-toolbar-title-edit {
cursor: text; cursor: text;
@ -383,7 +398,6 @@
vertical-align: middle; vertical-align: middle;
line-height: @toolbar_top-height; line-height: @toolbar_top-height;
span { span {
color: red;
cursor: pointer; cursor: pointer;
margin: auto; margin: auto;
font-size: 20px; font-size: 20px;

View File

@ -31,6 +31,7 @@ define(function () {
out.typeError = "This pad is not compatible with the selected application"; out.typeError = "This pad is not compatible with the selected application";
out.onLogout = 'You are logged out, <a href="/" target="_blank">click here</a> to log in<br>or press <em>Escape</em> to access your pad in read-only mode.'; out.onLogout = 'You are logged out, <a href="/" target="_blank">click here</a> to log in<br>or press <em>Escape</em> to access your pad in read-only mode.';
out.wrongApp = "Unable to display the content of that realtime session in your browser. Please try to reload that page."; out.wrongApp = "Unable to display the content of that realtime session in your browser. Please try to reload that page.";
out.padNotPinned = 'This pad will expire in 3 months, <a href="{0}" target="blank">login</a> or <a href="{1}" target="blank">register</a> to preserve it.';
out.loading = "Loading..."; out.loading = "Loading...";
out.error = "Error"; out.error = "Error";

74
pinned.js Normal file
View File

@ -0,0 +1,74 @@
/* jshint esversion: 6, node: true */
const Fs = require('fs');
const Semaphore = require('saferphore');
const nThen = require('nthen');
const sema = Semaphore.create(20);
let dirList;
const fileList = [];
const pinned = {};
const hashesFromPinFile = (pinFile, fileName) => {
var pins = {};
pinFile.split('\n').filter((x)=>(x)).map((l) => JSON.parse(l)).forEach((l) => {
switch (l[0]) {
case 'RESET': {
pins = {};
//jshint -W086
// fallthrough
}
case 'PIN': {
l[1].forEach((x) => { pins[x] = 1; });
break;
}
case 'UNPIN': {
l[1].forEach((x) => { delete pins[x]; });
break;
}
default: throw new Error(JSON.stringify(l) + ' ' + fileName);
}
});
return Object.keys(pins);
};
module.exports.load = function (cb) {
nThen((waitFor) => {
Fs.readdir('./pins', waitFor((err, list) => {
if (err) { throw err; }
dirList = list;
}));
}).nThen((waitFor) => {
fileList.splice(0, fileList.length);
dirList.forEach((f) => {
sema.take((returnAfter) => {
Fs.readdir('./pins/' + f, waitFor(returnAfter((err, list2) => {
if (err) { throw err; }
list2.forEach((ff) => { fileList.push('./pins/' + f + '/' + ff); });
})));
});
});
}).nThen((waitFor) => {
fileList.forEach((f) => {
sema.take((returnAfter) => {
Fs.readFile(f, waitFor(returnAfter((err, content) => {
if (err) { throw err; }
const hashes = hashesFromPinFile(content.toString('utf8'), f);
hashes.forEach((x) => {
(pinned[x] = pinned[x] || {})[f.replace(/.*\/([^/]*).ndjson$/, (x, y)=>y)] = 1;
});
})));
});
});
}).nThen(() => {
cb(pinned);
});
};
if (!module.parent) {
module.exports.load(function (data) {
Object.keys(data).forEach(function (x) {
console.log(x + ' ' + JSON.stringify(data[x]));
});
});
}

118
rpc.js
View File

@ -10,6 +10,7 @@ var Fs = require("fs");
var Path = require("path"); var Path = require("path");
var Https = require("https"); var Https = require("https");
const Package = require('./package.json'); const Package = require('./package.json');
const Pinned = require('./pinned');
var RPC = module.exports; var RPC = module.exports;
@ -212,7 +213,6 @@ var checkSignature = function (signedMsg, signature, publicKey) {
}; };
var loadUserPins = function (Env, publicKey, cb) { var loadUserPins = function (Env, publicKey, cb) {
var pinStore = Env.pinStore;
var session = beginSession(Env.Sessions, publicKey); var session = beginSession(Env.Sessions, publicKey);
if (session.channels) { if (session.channels) {
@ -230,7 +230,7 @@ var loadUserPins = function (Env, publicKey, cb) {
pins[channel] = false; pins[channel] = false;
}; };
pinStore.getMessages(publicKey, function (msg) { Env.pinStore.getMessages(publicKey, function (msg) {
// handle messages... // handle messages...
var parsed; var parsed;
try { try {
@ -325,9 +325,8 @@ var getFileSize = function (Env, channel, cb) {
}; };
var getMultipleFileSize = function (Env, channels, cb) { var getMultipleFileSize = function (Env, channels, cb) {
var msgStore = Env.msgStore;
if (!Array.isArray(channels)) { return cb('INVALID_PIN_LIST'); } if (!Array.isArray(channels)) { return cb('INVALID_PIN_LIST'); }
if (typeof(msgStore.getChannelSize) !== 'function') { if (typeof(Env.msgStore.getChannelSize) !== 'function') {
return cb('GET_CHANNEL_SIZE_UNSUPPORTED'); return cb('GET_CHANNEL_SIZE_UNSUPPORTED');
} }
@ -499,6 +498,54 @@ var sumChannelSizes = function (sizes) {
.reduce(function (a, b) { return a + b; }, 0); .reduce(function (a, b) { return a + b; }, 0);
}; };
// inform that the
var loadChannelPins = function (Env) {
Pinned.load(function (data) {
Env.pinnedPads = data;
Env.evPinnedPadsReady.fire();
});
};
var addPinned = function (
Env,
publicKey /*:string*/,
channelList /*Array<string>*/,
cb /*:()=>void*/)
{
Env.evPinnedPadsReady.reg(() => {
channelList.forEach((c) => {
const x = Env.pinnedPads[c];
if (!x) { return; }
delete x[publicKey];
});
cb();
});
};
var removePinned = function (
Env,
publicKey /*:string*/,
channelList /*Array<string>*/,
cb /*:()=>void*/)
{
Env.evPinnedPadsReady.reg(() => {
channelList.forEach((c) => {
const x = Env.pinnedPads[c];
if (!x) { return; }
delete x[publicKey];
});
cb();
});
};
var isChannelPinned = function (Env, channel, cb) {
Env.evPinnedPadsReady.reg(() => {
if (Env.pinnedPads[channel] && Object.keys(Env.pinnedPads[channel]).length) {
cb(true);
} else {
delete Env.pinnedPads[channel];
cb(false);
}
});
};
var pinChannel = function (Env, publicKey, channels, cb) { var pinChannel = function (Env, publicKey, channels, cb) {
if (!channels && channels.filter) { if (!channels && channels.filter) {
return void cb('INVALID_PIN_LIST'); return void cb('INVALID_PIN_LIST');
@ -534,6 +581,7 @@ var pinChannel = function (Env, publicKey, channels, cb) {
toStore.forEach(function (channel) { toStore.forEach(function (channel) {
session.channels[channel] = true; session.channels[channel] = true;
}); });
addPinned(Env, publicKey, toStore, () => {});
getHash(Env, publicKey, cb); getHash(Env, publicKey, cb);
}); });
}); });
@ -542,7 +590,6 @@ var pinChannel = function (Env, publicKey, channels, cb) {
}; };
var unpinChannel = function (Env, publicKey, channels, cb) { var unpinChannel = function (Env, publicKey, channels, cb) {
var pinStore = Env.pinStore;
if (!channels && channels.filter) { if (!channels && channels.filter) {
// expected array // expected array
return void cb('INVALID_PIN_LIST'); return void cb('INVALID_PIN_LIST');
@ -560,13 +607,13 @@ var unpinChannel = function (Env, publicKey, channels, cb) {
return void getHash(Env, publicKey, cb); return void getHash(Env, publicKey, cb);
} }
pinStore.message(publicKey, JSON.stringify(['UNPIN', toStore]), Env.pinStore.message(publicKey, JSON.stringify(['UNPIN', toStore]),
function (e) { function (e) {
if (e) { return void cb(e); } if (e) { return void cb(e); }
toStore.forEach(function (channel) { toStore.forEach(function (channel) {
delete session.channels[channel]; delete session.channels[channel];
}); });
removePinned(Env, publicKey, toStore, () => {});
getHash(Env, publicKey, cb); getHash(Env, publicKey, cb);
}); });
}); });
@ -574,7 +621,6 @@ var unpinChannel = function (Env, publicKey, channels, cb) {
var resetUserPins = function (Env, publicKey, channelList, cb) { var resetUserPins = function (Env, publicKey, channelList, cb) {
if (!Array.isArray(channelList)) { return void cb('INVALID_PIN_LIST'); } if (!Array.isArray(channelList)) { return void cb('INVALID_PIN_LIST'); }
var pinStore = Env.pinStore;
var session = beginSession(Env.Sessions, publicKey); var session = beginSession(Env.Sessions, publicKey);
if (!channelList.length) { if (!channelList.length) {
@ -605,13 +651,18 @@ var resetUserPins = function (Env, publicKey, channelList, cb) {
They will not be able to pin additional pads until they upgrade They will not be able to pin additional pads until they upgrade
or delete enough files to go back under their limit. */ or delete enough files to go back under their limit. */
if (pinSize > limit[0] && session.hasPinned) { return void(cb('E_OVER_LIMIT')); } if (pinSize > limit[0] && session.hasPinned) { return void(cb('E_OVER_LIMIT')); }
pinStore.message(publicKey, JSON.stringify(['RESET', channelList]), Env.pinStore.message(publicKey, JSON.stringify(['RESET', channelList]),
function (e) { function (e) {
if (e) { return void cb(e); } if (e) { return void cb(e); }
channelList.forEach(function (channel) { channelList.forEach(function (channel) {
pins[channel] = true; pins[channel] = true;
}); });
var oldChannels = Object.keys(session.channels);
removePinned(Env, publicKey, oldChannels, () => {
addPinned(Env, publicKey, channelList, ()=>{});
});
// update in-memory cache IFF the reset was allowed. // update in-memory cache IFF the reset was allowed.
session.channels = pins; session.channels = pins;
getHash(Env, publicKey, function (e, hash) { getHash(Env, publicKey, function (e, hash) {
@ -879,6 +930,7 @@ var isUnauthenticatedCall = function (call) {
return [ return [
'GET_FILE_SIZE', 'GET_FILE_SIZE',
'GET_MULTIPLE_FILE_SIZE', 'GET_MULTIPLE_FILE_SIZE',
'IS_CHANNEL_PINNED',
].indexOf(call) !== -1; ].indexOf(call) !== -1;
}; };
@ -894,10 +946,31 @@ var isAuthenticatedCall = function (call) {
'GET_LIMIT', 'GET_LIMIT',
'UPLOAD_COMPLETE', 'UPLOAD_COMPLETE',
'UPLOAD_CANCEL', 'UPLOAD_CANCEL',
'EXPIRE_SESSION', 'EXPIRE_SESSION'
].indexOf(call) !== -1; ].indexOf(call) !== -1;
}; };
const mkEvent = function (once) {
var handlers = [];
var fired = false;
return {
reg: function (cb) {
if (once && fired) { return void setTimeout(cb); }
handlers.push(cb);
},
unreg: function (cb) {
if (handlers.indexOf(cb) === -1) { throw new Error("Not registered"); }
handlers.splice(handlers.indexOf(cb), 1);
},
fire: function () {
if (once && fired) { return; }
fired = true;
var args = Array.prototype.slice.call(arguments);
handlers.forEach(function (h) { h.apply(null, args); });
}
};
};
/*::const ConfigType = require('./config.example.js');*/ /*::const ConfigType = require('./config.example.js');*/
RPC.create = function (config /*:typeof(ConfigType)*/, cb /*:(?Error, ?Function)=>void*/) { RPC.create = function (config /*:typeof(ConfigType)*/, cb /*:(?Error, ?Function)=>void*/) {
// load pin-store... // load pin-store...
@ -909,14 +982,19 @@ RPC.create = function (config /*:typeof(ConfigType)*/, cb /*:(?Error, ?Function)
return typeof(config[key]) === 'string'? config[key]: def; return typeof(config[key]) === 'string'? config[key]: def;
}; };
var Env = {}; var Env = {
Env.defaultStorageLimit = config.defaultStorageLimit; defaultStorageLimit: config.defaultStorageLimit,
maxUploadSize: config.maxUploadSize || (20 * 1024 * 1024),
Sessions: {},
paths: {},
msgStore: (undefined /*:any*/),
pinStore: (undefined /*:any*/),
pinnedPads: {},
evPinnedPadsReady: mkEvent(true)
};
Env.maxUploadSize = config.maxUploadSize || (20 * 1024 * 1024); var Sessions = Env.Sessions;
var paths = Env.paths;
var Sessions = Env.Sessions = {};
var paths = Env.paths = {};
var pinPath = paths.pin = keyOrDefaultString('pinPath', './pins'); var pinPath = paths.pin = keyOrDefaultString('pinPath', './pins');
var blobPath = paths.blob = keyOrDefaultString('blobPath', './blob'); var blobPath = paths.blob = keyOrDefaultString('blobPath', './blob');
var blobStagingPath = paths.staging = keyOrDefaultString('blobStagingPath', './blobstage'); var blobStagingPath = paths.staging = keyOrDefaultString('blobStagingPath', './blobstage');
@ -943,6 +1021,10 @@ RPC.create = function (config /*:typeof(ConfigType)*/, cb /*:(?Error, ?Function)
} }
respond(e, [null, dict, null]); respond(e, [null, dict, null]);
}); });
case 'IS_CHANNEL_PINNED':
return void isChannelPinned(Env, msg[1], function (isPinned) {
respond(null, [null, isPinned, null]);
});
default: default:
console.error("unsupported!"); console.error("unsupported!");
return respond('UNSUPPORTED_RPC_CALL', msg); return respond('UNSUPPORTED_RPC_CALL', msg);
@ -1174,6 +1256,8 @@ RPC.create = function (config /*:typeof(ConfigType)*/, cb /*:(?Error, ?Function)
updateLimitDaily(); updateLimitDaily();
setInterval(updateLimitDaily, 24*3600*1000); setInterval(updateLimitDaily, 24*3600*1000);
loadChannelPins(Env);
Store.create({ Store.create({
filePath: pinPath, filePath: pinPath,
}, function (s) { }, function (s) {

View File

@ -102,6 +102,7 @@ app.use("/blob", Express.static(Path.join(__dirname, (config.blobPath || './blob
app.use("/customize", Express.static(__dirname + '/customize')); app.use("/customize", Express.static(__dirname + '/customize'));
app.use("/customize", Express.static(__dirname + '/customize.dist')); app.use("/customize", Express.static(__dirname + '/customize.dist'));
app.use("/customize.dist", Express.static(__dirname + '/customize.dist'));
app.use(/^\/[^\/]*$/, Express.static('customize')); app.use(/^\/[^\/]*$/, Express.static('customize'));
app.use(/^\/[^\/]*$/, Express.static('customize.dist')); app.use(/^\/[^\/]*$/, Express.static('customize.dist'));

View File

@ -5,6 +5,8 @@
@import (once) '../../customize/src/less2/include/alertify.less'; @import (once) '../../customize/src/less2/include/alertify.less';
@import (once) '../../customize/src/less2/include/tokenfield.less'; @import (once) '../../customize/src/less2/include/tokenfield.less';
@_cp-toolbar-color-warn: @colortheme_code-warn;
.toolbar_main(); .toolbar_main();
.fileupload_main(); .fileupload_main();
.alertify_main(); .alertify_main();

View File

@ -461,7 +461,16 @@ define([
getHeadingText: function () { return titleRecommender(); } getHeadingText: function () { return titleRecommender(); }
}, onLocal); }, onLocal);
var configTb = { var configTb = {
displayed: ['userlist', 'title', 'useradmin', 'spinner', 'newpad', 'share', 'limit'], displayed: [
'userlist',
'title',
'useradmin',
'spinner',
'newpad',
'share',
'limit',
'unpinnedWarning'
],
title: title.getTitleConfig(), title: title.getTitleConfig(),
metadataMgr: cpNfInner.metadataMgr, metadataMgr: cpNfInner.metadataMgr,
readOnly: readOnly, readOnly: readOnly,

View File

@ -719,6 +719,26 @@ define([
return $titleContainer; return $titleContainer;
}; };
var createUnpinnedWarning = function (toolbar, config) {
if (Common.isLoggedIn()) { return; }
var pd = config.metadataMgr.getPrivateData();
var o = pd.origin;
var hashes = pd.availableHashes;
var url = pd.origin + pd.pathname + '#' + (hashes.editHash || hashes.viewHash);
var cid = Hash.hrefToHexChannelId(url);
Common.sendAnonRpcMsg('IS_CHANNEL_PINNED', cid, function (x) {
if (x.error || !Array.isArray(x.response)) { return void console.log(x); }
if (x.response[0] === true) { return; }
var msg = $('<span>', {
'class': 'cp-pad-not-pinned',
}).append(
Messages._getKey('padNotPinned', [o + '/login', o + '/register'])
);
$('.cp-toolbar-title').append(msg);
console.log("This pad is not pinned");
});
};
var createPageTitle = function (toolbar, config) { var createPageTitle = function (toolbar, config) {
if (config.title || !config.pageTitle) { return; } if (config.title || !config.pageTitle) { return; }
var $titleContainer = $('<span>', { var $titleContainer = $('<span>', {
@ -1087,6 +1107,7 @@ define([
tb['upgrade'] = $.noop; tb['upgrade'] = $.noop;
tb['newpad'] = createNewPad; tb['newpad'] = createNewPad;
tb['useradmin'] = createUserAdmin; tb['useradmin'] = createUserAdmin;
tb['unpinnedWarning'] = createUnpinnedWarning;
var addElement = toolbar.addElement = function (arr, additionnalCfg, init) { var addElement = toolbar.addElement = function (arr, additionnalCfg, init) {
if (typeof additionnalCfg === "object") { $.extend(true, config, additionnalCfg); } if (typeof additionnalCfg === "object") { $.extend(true, config, additionnalCfg); }

View File

@ -8,6 +8,7 @@
@import (once) '../../customize/src/less2/include/avatar.less'; @import (once) '../../customize/src/less2/include/avatar.less';
@_cp-toolbar-color-warn: @colortheme_friends-warn;;
.toolbar_main(); .toolbar_main();
.fileupload_main(); .fileupload_main();

View File

@ -8,6 +8,8 @@
@import (once) "../../customize/src/less2/include/limit-bar.less"; @import (once) "../../customize/src/less2/include/limit-bar.less";
@import (once) "../../customize/src/less2/include/tokenfield.less"; @import (once) "../../customize/src/less2/include/tokenfield.less";
@_cp-toolbar-color-warn: @colortheme_drive-warn;
.toolbar_main(); .toolbar_main();
.fileupload_main(); .fileupload_main();
.alertify_main(); .alertify_main();

View File

@ -5,6 +5,8 @@
@import (once) '../../customize/src/less2/include/alertify.less'; @import (once) '../../customize/src/less2/include/alertify.less';
@import (once) '../../customize/src/less2/include/tokenfield.less'; @import (once) '../../customize/src/less2/include/tokenfield.less';
@_cp-toolbar-color-warn: @colortheme_file-warn;
.toolbar_main(); .toolbar_main();
.fileupload_main(); .fileupload_main();
.alertify_main(); .alertify_main();

View File

@ -6,6 +6,8 @@
@import (once) '../../customize/src/less2/include/alertify.less'; @import (once) '../../customize/src/less2/include/alertify.less';
@import (once) '../../customize/src/less2/include/tokenfield.less'; @import (once) '../../customize/src/less2/include/tokenfield.less';
@_cp-toolbar-color-warn: @colortheme_pad-warn;
.toolbar_main(); .toolbar_main();
.alertify_main(); .alertify_main();

View File

@ -13,6 +13,8 @@
@import (once) '../../customize/src/less2/include/tools.less'; @import (once) '../../customize/src/less2/include/tools.less';
@import (once) '../../customize/src/less2/include/avatar.less'; @import (once) '../../customize/src/less2/include/avatar.less';
@_cp-toolbar-color-warn: @colortheme_poll-warn;
.toolbar_main(); .toolbar_main();
.fileupload_main(); .fileupload_main();
.alertify_main(); .alertify_main();

View File

@ -4,7 +4,9 @@
@import (once) "../../customize/src/less2/include/markdown.less"; @import (once) "../../customize/src/less2/include/markdown.less";
@import (once) '../../customize/src/less2/include/alertify.less'; @import (once) '../../customize/src/less2/include/alertify.less';
@import (once) '../../customize/src/less2/include/sidebar-layout.less'; @import (once) '../../customize/src/less2/include/sidebar-layout.less';
@import (once) "../../customize/src/less2/include/limit-bar.less"; @import (once) "../../customize/src/less2/include/limit-bar.less";
@_cp-toolbar-color-warn: @colortheme_settings-warn;
.toolbar_main(); .toolbar_main();
.alertify_main(); .alertify_main();

View File

@ -6,6 +6,8 @@
@import (once) "../../customize/src/less2/include/mediatag.less"; @import (once) "../../customize/src/less2/include/mediatag.less";
@import (once) '../../customize/src/less2/include/tokenfield.less'; @import (once) '../../customize/src/less2/include/tokenfield.less';
@_cp-toolbar-color-warn: @colortheme_slide-warn;
.mediatag_base(); .mediatag_base();
.toolbar_main(); .toolbar_main();
.fileupload_main(); .fileupload_main();

View File

@ -6,6 +6,8 @@
@import (once) '../../customize/src/less2/include/tools.less'; @import (once) '../../customize/src/less2/include/tools.less';
@import (once) '../../customize/src/less2/include/tokenfield.less'; @import (once) '../../customize/src/less2/include/tokenfield.less';
@_cp-toolbar-color-warn: @colortheme_whiteboard-warn;
.toolbar_main(); .toolbar_main();
.fileupload_main(); .fileupload_main();
.alertify_main(); .alertify_main();

View File

@ -393,7 +393,16 @@ define([
Title = common.createTitle({}); Title = common.createTitle({});
var configTb = { var configTb = {
displayed: ['title', 'useradmin', 'spinner', 'share', 'userlist', 'newpad', 'limit'], displayed: [
'userlist',
'title',
'useradmin',
'spinner',
'newpad',
'share',
'limit',
'unpinnedWarning'
],
title: Title.getTitleConfig(), title: Title.getTitleConfig(),
metadataMgr: metadataMgr, metadataMgr: metadataMgr,
readOnly: readOnly, readOnly: readOnly,