define([ 'jquery', '/bower_components/chainpad-crypto/crypto.js', '/bower_components/chainpad-netflux/chainpad-netflux.js', '/bower_components/textpatcher/TextPatcher.js', '/common/toolbar2.js', 'json.sortify', '/bower_components/chainpad-json-validator/json-ot.js', '/common/cryptpad-common.js', '/common/cryptget.js', '/common/modes.js', '/common/themes.js', '/common/visible.js', '/common/notify.js', '/slide/slide.js', '/bower_components/file-saver/FileSaver.min.js' ], function ($, Crypto, Realtime, TextPatcher, Toolbar, JSONSortify, JsonOT, Cryptpad, Cryptget, Modes, Themes, Visible, Notify, Slide) { var saveAs = window.saveAs; var Messages = Cryptpad.Messages; var module = window.APP = { Cryptpad: Cryptpad, TextPatcher: TextPatcher, Slide: Slide, }; var APP = window.APP; var SLIDE_BACKCOLOR_ID = "cryptpad-backcolor"; var SLIDE_COLOR_ID = "cryptpad-color"; var stringify = function (obj) { return JSONSortify(obj); }; var setTabTitle = function () { var slideNumber = ''; if (Slide.index && Slide.content.length) { slideNumber = ' (' + Slide.index + '/' + Slide.content.length + ')'; } document.title = APP.title + slideNumber; }; $(function () { Cryptpad.addLoadingScreen(); var ifrw = module.ifrw = $('#pad-iframe')[0].contentWindow; var toolbar; var secret = Cryptpad.getSecrets(); var readOnly = secret.keys && !secret.keys.editKeyStr; Slide.readOnly = readOnly; if (!secret.keys) { secret.keys = secret.key; } var presentMode = Slide.isPresentURL(); var onConnectError = function () { Cryptpad.errorLoadingScreen(Messages.websocketError); }; var andThen = function (CMeditor) { var CodeMirror = module.CodeMirror = CMeditor; CodeMirror.modeURL = "/bower_components/codemirror/mode/%N/%N.js"; var $pad = $('#pad-iframe'); var $textarea = $pad.contents().find('#editor1'); var $bar = $('#pad-iframe')[0].contentWindow.$('#cme_toolbox'); var parsedHash = Cryptpad.parsePadUrl(window.location.href); var defaultName = Cryptpad.getDefaultName(parsedHash); var initialState = Messages.slideInitialState; var isHistoryMode = false; var editor = module.editor = CMeditor.fromTextArea($textarea[0], { lineNumbers: true, lineWrapping: true, autoCloseBrackets: true, matchBrackets : true, showTrailingSpace : true, styleActiveLine : true, search: true, highlightSelectionMatches: {showToken: /\w+/}, extraKeys: {"Shift-Ctrl-R": undefined}, foldGutter: true, gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"], mode: "javascript", readOnly: true }); editor.setValue(initialState); var setMode = module.setMode = function (mode, $select) { module.highlightMode = mode; if (mode === 'text') { editor.setOption('mode', 'text'); return; } CodeMirror.autoLoadMode(editor, mode); editor.setOption('mode', mode); if ($select && $select.val) { $select.val(mode); } }; setMode('markdown'); var setTheme = module.setTheme = (function () { var path = '/common/theme/'; var $head = $(ifrw.document.head); var themeLoaded = module.themeLoaded = function (theme) { return $head.find('link[href*="'+theme+'"]').length; }; var loadTheme = module.loadTheme = function (theme) { $head.append($('', { rel: 'stylesheet', href: path + theme + '.css', })); }; return function (theme, $select) { if (!theme) { editor.setOption('theme', 'default'); } else { if (!themeLoaded(theme)) { loadTheme(theme); } editor.setOption('theme', theme); } if ($select) { $select.setValue(theme || 'Theme'); } }; }()); var $modal = $pad.contents().find('#modal'); var $content = $pad.contents().find('#content'); var $print = $pad.contents().find('#print'); var slideOptions = {}; Slide.setModal(APP, $modal, $content, $pad, ifrw, slideOptions, initialState); var setStyleState = function (state) { $pad.contents().find('#print, #content').find('style').each(function (i, el) { el.disabled = !state; }); }; var enterPresentationMode = function (shouldLog) { Slide.show(true, editor.getValue()); if (shouldLog) { Cryptpad.log(Messages.presentSuccess); } }; var leavePresentationMode = function () { setStyleState(false); Slide.show(false); }; if (presentMode) { enterPresentationMode(true); } var setEditable = module.setEditable = function (bool) { if (readOnly && bool) { return; } editor.setOption('readOnly', !bool); }; var UserList; var textColor; var backColor; var config = { //initialState: Messages.codeInitialState, initialState: '{}', websocketURL: Cryptpad.getWebsocketURL(), channel: secret.channel, // our public key validateKey: secret.keys.validateKey || undefined, readOnly: readOnly, crypto: Crypto.createEncryptor(secret.keys), transformFunction: JsonOT.validate, network: Cryptpad.getNetwork() }; var canonicalize = function (t) { return t.replace(/\r\n/g, '\n'); }; var setHistory = function (bool, update) { isHistoryMode = bool; setEditable(!bool); if (!bool && update) { config.onRemote(); } }; var initializing = true; var stringifyInner = function (textValue) { var obj = { content: textValue, metadata: { users: UserList.userData, defaultTitle: defaultName, slideOptions: slideOptions } }; if (!initializing) { obj.metadata.title = APP.title; } if (textColor) { obj.metadata.color = textColor; } if (backColor) { obj.metadata.backColor = backColor; } // stringify the json and send it into chainpad return stringify(obj); }; var onLocal = config.onLocal = function () { if (initializing) { return; } if (isHistoryMode) { return; } if (readOnly) { return; } editor.save(); var textValue = canonicalize($textarea.val()); var shjson = stringifyInner(textValue); module.patchText(shjson); Slide.update(textValue); if (module.realtime.getUserDoc() !== shjson) { console.error("realtime.getUserDoc() !== shjson"); } }; var getHeadingText = function () { var lines = editor.getValue().split(/\n/); var text = ''; lines.some(function (line) { // lines beginning with a hash are potentially valuable // works for markdown, python, bash, etc. var hash = /^#(.*?)$/; if (hash.test(line)) { line.replace(hash, function (a, one) { text = one; }); return true; } }); return text.trim(); }; var suggestName = function () { if (APP.title === defaultName) { return getHeadingText() || ""; } else { return APP.title || getHeadingText() || defaultName; } }; var exportText = module.exportText = function () { var text = editor.getValue(); var ext = Modes.extensionOf(module.highlightMode); var title = Cryptpad.fixFileName(suggestName()) + ext; Cryptpad.prompt(Messages.exportPrompt, title, function (filename) { if (filename === null) { return; } var blob = new Blob([text], { type: 'text/plain;charset=utf-8' }); saveAs(blob, filename); }); }; var importText = function (content, file) { var $bar = $('#pad-iframe')[0].contentWindow.$('#cme_toolbox'); var mode; var mime = CodeMirror.findModeByMIME(file.type); if (!mime) { var ext = /.+\.([^.]+)$/.exec(file.name); if (ext[1]) { mode = CodeMirror.findModeByExtension(ext[1]); } } else { mode = mime && mime.mode || null; } if (mode && Modes.list.some(function (o) { return o.mode === mode; })) { setMode(mode); $bar.find('#language-mode').val(mode); } else { console.log("Couldn't find a suitable highlighting mode: %s", mode); setMode('text'); $bar.find('#language-mode').val('text'); } editor.setValue(content); onLocal(); }; var updateTitle = function (newTitle) { if (newTitle === APP.title) { return; } // Change the title now, and set it back to the old value if there is an error var oldTitle = APP.title; APP.title = newTitle; setTabTitle(); Cryptpad.renamePad(newTitle, function (err, data) { if (err) { console.log("Couldn't set pad title"); console.error(err); APP.title = oldTitle; setTabTitle(); return; } APP.title = data; setTabTitle(); $bar.find('.' + Toolbar.constants.title).find('span.title').text(data); $bar.find('.' + Toolbar.constants.title).find('input').val(data); if (slideOptions.title) { Slide.updateOptions(); } }); }; var updateColors = function (text, back) { if (text) { textColor = text; $modal.css('color', text); $modal.css('border-color', text); $pad.contents().find('#' + SLIDE_COLOR_ID).css('color', text); } if (back) { backColor = back; $modal.css('background-color', back); $pad.contents().find('#' + SLIDE_COLOR_ID).css('background', back); $pad.contents().find('#' + SLIDE_BACKCOLOR_ID).css('color', back); } }; var updateOptions = function (newOpt) { if (stringify(newOpt) !== stringify(slideOptions)) { $.extend(slideOptions, newOpt); // TODO: manage realtime + cursor in the "options" modal ?? Slide.updateOptions(); } }; var updateDefaultTitle = function (defaultTitle) { defaultName = defaultTitle; $bar.find('.' + Toolbar.constants.title).find('input').attr("placeholder", defaultName); }; var updateMetadata = function(shjson) { // Extract the user list (metadata) from the hyperjson var json = (shjson === "") ? "" : JSON.parse(shjson); var titleUpdated = false; if (json && json.metadata) { if (json.metadata.users) { var userData = json.metadata.users; // Update the local user data UserList.addToUserData(userData); } if (json.metadata.defaultTitle) { updateDefaultTitle(json.metadata.defaultTitle); } if (typeof json.metadata.title !== "undefined") { updateTitle(json.metadata.title || defaultName); titleUpdated = true; } updateOptions(json.metadata.slideOptions); updateColors(json.metadata.color, json.metadata.backColor); } if (!titleUpdated) { updateTitle(defaultName); } }; var renameCb = function (err, title) { if (err) { return; } APP.title = title; setTabTitle(); onLocal(); }; var createPrintDialog = function () { var slideOptionsTmp = { title: false, slide: false, date: false, style: '' }; $.extend(slideOptionsTmp, slideOptions); var $container = $('
'); var $container2 = $('
').appendTo($container); var $div = $('
').appendTo($container2); var $p = $('

', {'class': 'msg'}).appendTo($div); $('').text(Messages.printOptions).appendTo($p); $p.append($('
')); // Slide number $('', {type: 'checkbox', id: 'checkNumber', checked: slideOptionsTmp.slide}).on('change', function () { var c = this.checked; console.log(c); slideOptionsTmp.slide = c; }).appendTo($p).css('width', 'auto'); $('