Initial work on the 'pad will expire' logic

pull/1/head
Caleb James DeLisle 7 years ago
parent 7544bb1ced
commit c702a23c77

@ -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;

@ -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;

@ -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";

@ -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

@ -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),
Env.maxUploadSize = config.maxUploadSize || (20 * 1024 * 1024); Sessions: {},
paths: {},
var Sessions = Env.Sessions = {}; msgStore: (undefined /*:any*/),
pinStore: (undefined /*:any*/),
pinnedPads: {},
evPinnedPadsReady: mkEvent(true)
};
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) {

@ -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'));

@ -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();

@ -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,

@ -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); }

@ -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();

@ -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();

@ -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();

@ -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();

@ -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();

@ -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();

@ -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();

@ -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();

@ -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,

Loading…
Cancel
Save