diff --git a/askbot b/askbot new file mode 160000 index 0000000000..e56ae38084 --- /dev/null +++ b/askbot @@ -0,0 +1 @@ +Subproject commit e56ae380846f7c6cdaeacfc58880fab103540491 diff --git a/cms/static/coffee/src/views/unit.coffee b/cms/static/coffee/src/views/unit.coffee index fe8f928746..dbeffa2738 100644 --- a/cms/static/coffee/src/views/unit.coffee +++ b/cms/static/coffee/src/views/unit.coffee @@ -1,6 +1,7 @@ class CMS.Views.UnitEdit extends Backbone.View events: - 'click .new-component .new-component-type a': 'showComponentTemplates' + # 'click .new-component .new-component-type a': 'showComponentTemplates' + 'click .new-component .new-component-type a': 'addNewComponent' 'click .new-component .cancel-button': 'closeNewComponent' 'click .new-component-templates .new-component-template a': 'saveNewComponent' 'click .new-component-templates .cancel-button': 'closeNewComponent' @@ -68,6 +69,52 @@ class CMS.Views.UnitEdit extends Backbone.View @$newComponentItem.removeClass('adding') @$newComponentItem.find('.rendered-component').remove() + addNewComponent: (event) => + event.preventDefault() + + @$componentItem = $('
  • ').addClass('editing') + type = $(event.currentTarget).data('type') + + switch type + when 'video' + @$editor = $($('#video-editor').html()) + $preview = $($('#video-preview').html()) + when 'problem' + @$editor = $($('#problem-editor').html()) + $preview = $($('#problem-preview').html()) + initProblemEditors(@$editor, $preview) + when 'html' + @$editor = $($('#html-editor').html()) + $preview = $('
    ') + initHTMLEditor(@$editor, $preview) + when 'discussion' + @$editor = $($('#discussion-editor').html()) + $preview = $($('#discussion-preview').html()) + + @$editor.find('.save-button, .cancel-button').bind('click', => + @$componentItem.removeClass('editing') + @closeEditor() + ) + + $componentActions = $($('#component-actions').html()) + + @$componentItem.append(@$editor) + @$componentItem.append($preview) + + @$componentItem.append($componentActions) + @$componentItem.hide() + @$newComponentItem.before(@$componentItem) + @$componentItem.show() + $modalCover.fadeIn(200) + $modalCover.bind('click', @closeEditor) + + closeEditor: (event) => + @$editor.slideUp(150) + $modalCover.fadeOut(150) + $modalCover.unbind('click', @closeEditor) + @$editor.slideUp(150) + @$componentItem.removeClass('editing') + saveNewComponent: (event) => event.preventDefault() diff --git a/cms/static/css/html-editor.css b/cms/static/css/html-editor.css new file mode 100644 index 0000000000..e8ccbb11d0 --- /dev/null +++ b/cms/static/css/html-editor.css @@ -0,0 +1,45 @@ +body { + background-color: #fff; + font-family: 'Open Sans', Verdana, Arial, Helvetica, sans-serif; + font-size: 16px; + line-height: 1.6; + color: #3c3c3c; + scrollbar-3dlight-color: #F0F0EE; + scrollbar-arrow-color: #676662; + scrollbar-base-color: #F0F0EE; + scrollbar-darkshadow-color: #DDDDDD; + scrollbar-face-color: #E0E0DD; + scrollbar-highlight-color: #F0F0EE; + scrollbar-shadow-color: #F0F0EE; + scrollbar-track-color: #F5F5F5; +} + +a { + color: #1d9dd9; + text-decoration: none; +} + +p { + font-size: 16px; + line-height: 1.6; +} + +h2 { + color: #646464; + font-size: 19px; + font-weight: 300; + letter-spacing: 1px; + margin-bottom: 15px; + text-transform: uppercase; +} + +code { + margin: 0 2px; + padding: 0px 5px; + border-radius: 3px; + border: 1px solid #eaeaea; + white-space: nowrap; + font-family: Monaco, monospace; + font-size: 14px; + background-color: #f8f8f8; +} \ No newline at end of file diff --git a/cms/static/img/choice-example.png b/cms/static/img/choice-example.png new file mode 100644 index 0000000000..ee136577a9 Binary files /dev/null and b/cms/static/img/choice-example.png differ diff --git a/cms/static/img/multi-example.png b/cms/static/img/multi-example.png new file mode 100644 index 0000000000..abe729a94b Binary files /dev/null and b/cms/static/img/multi-example.png differ diff --git a/cms/static/img/new-post-icon.png b/cms/static/img/new-post-icon.png new file mode 100644 index 0000000000..bf16b9da89 Binary files /dev/null and b/cms/static/img/new-post-icon.png differ diff --git a/cms/static/img/number-example.png b/cms/static/img/number-example.png new file mode 100644 index 0000000000..7cd050cb5e Binary files /dev/null and b/cms/static/img/number-example.png differ diff --git a/cms/static/img/problem-editor-icons.png b/cms/static/img/problem-editor-icons.png new file mode 100644 index 0000000000..62f078560f Binary files /dev/null and b/cms/static/img/problem-editor-icons.png differ diff --git a/cms/static/img/problem-settings-icon.png b/cms/static/img/problem-settings-icon.png new file mode 100644 index 0000000000..f99082a1e7 Binary files /dev/null and b/cms/static/img/problem-settings-icon.png differ diff --git a/cms/static/img/select-example.png b/cms/static/img/select-example.png new file mode 100644 index 0000000000..ef80e629de Binary files /dev/null and b/cms/static/img/select-example.png differ diff --git a/cms/static/img/show-hide-discussion-icon.png b/cms/static/img/show-hide-discussion-icon.png new file mode 100644 index 0000000000..17d3193780 Binary files /dev/null and b/cms/static/img/show-hide-discussion-icon.png differ diff --git a/cms/static/img/string-example.png b/cms/static/img/string-example.png new file mode 100644 index 0000000000..6f628b20d4 Binary files /dev/null and b/cms/static/img/string-example.png differ diff --git a/cms/static/img/visual-editor-image-icon.png b/cms/static/img/visual-editor-image-icon.png new file mode 100644 index 0000000000..17f8a5bfb4 Binary files /dev/null and b/cms/static/img/visual-editor-image-icon.png differ diff --git a/cms/static/js/html-editor.js b/cms/static/js/html-editor.js new file mode 100644 index 0000000000..3a4ab47172 --- /dev/null +++ b/cms/static/js/html-editor.js @@ -0,0 +1,84 @@ +var $body; +var $htmlPreview; +var $htmlEditor; +var $visualEditor; +var $assetWidget; +var visualEditor; +var htmlEditor; + +function initHTMLEditor($editor, $prev) { + $htmlEditor = $editor; + $htmlPreview = $prev; + + // there's a race condition here. wait a bit, then init tiny + setTimeout(function() { + $visualEditor = $editor.find('.edit-box.tinymce').tinymce({ + script_url : '/static/js/tiny_mce/tiny_mce.js', + theme : "advanced", + skin: 'studio', + + // we may want to add "styleselect" when we collect all styles used throught the lms + theme_advanced_buttons1 : "formatselect,bold,italic,underline,bullist,numlist,outdent,indent,blockquote,studio.asset,link,unlink", + theme_advanced_toolbar_location : "top", + theme_advanced_toolbar_align : "left", + theme_advanced_statusbar_location : "none", + theme_advanced_resizing : true, + theme_advanced_blockformats : "p,code,h2,h3,h4,h5,h6,blockquote", + content_css : "/static/css/html-editor.css", + width: '100%', + height: '400px', + setup : function(ed) { + ed.addButton('studio.asset', { + title : 'Add Asset', + image : '/static/img/visual-editor-image-icon.png', + onclick : function() { + $assetWidget = $($('#asset-library-widget').html()); + $assetWidget.find('.close-button').bind('click', closeAssetWidget); + $modalCover.unbind('click'); + $modalCover.bind('click', closeAssetWidget); + $modalCover.css('z-index', '99999'); + $('.insert-asset-button', $assetWidget).bind('click', { editor: ed }, insertAsset); + $body.append($assetWidget); + } + }); + } + }); + }, 100); + + htmlEditor = CodeMirror.fromTextArea($editor.find('.html-box')[0], { + lineWrapping: true, + mode: 'text/html', + lineNumbers: true + }); + + $editor.find('.save-button, .cancel-button').bind('click', updateHTMLPreview); +} + +function insertAsset(e) { + closeAssetWidget(); + var editor = e.data.editor; + editor.focus(); + editor.selection.setContent($(this).attr('data-markup')); +} + +function closeAssetWidget(e) { + $assetWidget.remove(); + $modalCover.css('z-index', '1000'); +} + +function convertVisualToHTML() { + console.log('convert'); + htmlEditor.setValue($visualEditor.html()); +} + +function convertHTMLToVisual() { + $visualEditor.html(htmlEditor.getValue()); +} + +function updateHTMLPreview() { + if(currentEditor == htmlEditor) { + $htmlPreview.html(htmlEditor.getValue()); + } else { + $htmlPreview.html($visualEditor.html()); + } +} \ No newline at end of file diff --git a/cms/static/js/speed-editor.js b/cms/static/js/speed-editor.js new file mode 100644 index 0000000000..f310e86cac --- /dev/null +++ b/cms/static/js/speed-editor.js @@ -0,0 +1,431 @@ +var $body; +var $preview; +var $tooltip; +var $cheatsheet; +var $currentEditor; +var simpleEditor; +var xmlEditor; +var currentEditor; +var controlDown; +var commandDown; + + +(function() { + $body.on('click', '.editor-bar a', onEditorButton); + $body.on('click', '.cheatsheet-toggle', toggleCheatsheet); + $body.on('click', '.problem-settings-button', toggleProblemSettings); + $(document).bind('keyup', onKeyboard); +})(); + +function initProblemEditors($editor, $prev) { + $currentEditor = $editor; + simpleEditor = CodeMirror.fromTextArea($editor.find('.edit-box')[0], { + lineWrapping: true, + extraKeys: { + 'Ctrl-N': newUnit, + 'Ctrl-H': makeHeader, + 'Ctrl-V': makeVideo, + 'Ctrl-M': makeMultipleChoice, + 'Ctrl-C': makeCheckboxes, + 'Ctrl-S': makeStringInput, + 'Shift-Ctrl-3': makeNumberInput, + 'Shift-Ctrl-S': makeSelect + }, + mode: null, + onChange: onSimpleEditorUpdate + }); + + xmlEditor = CodeMirror.fromTextArea($editor.find('.xml-box')[0], { + lineWrapping: true, + mode: 'xml', + lineNumbers: true + }); + + currentEditor = simpleEditor; + + $(simpleEditor.getWrapperElement()).css('background', '#fff'); + $(xmlEditor.getWrapperElement()).css({ + 'background': '#fff' + }).hide(); + + $(simpleEditor.getWrapperElement()).bind('click', setFocus); + $preview = $prev.find('.problem'); +} + +function toggleProblemSettings(e) { + e.preventDefault(); + + $(this).toggleClass('is-open'); + + if($(this).hasClass('is-open')) { + $(this).find('.button-label').html('Hide Advanced Settings'); + $('.problem-settings').slideDown(150); + } else { + $(this).find('.button-label').html('Show Advanced Settings'); + $('.problem-settings').slideUp(150); + } +} + +function toggleCheatsheet(e) { + e.preventDefault(); + + if(!$currentEditor.find('.simple-editor-cheatsheet')[0]) { + $cheatsheet = $($('#simple-editor-cheatsheet').html()); + $currentEditor.append($cheatsheet); + } + + setTimeout(function() { + $cheatsheet.toggleClass('shown'); + }, 10); +} + +function setFocus(e) { + $(simpleEditor).focus(); +} + +function onSimpleEditorUpdate() { + console.log('update'); + updatePreview(); + updateXML(); +} + +function updateXML() { + var val = simpleEditor.getValue(); + var xml = val; + + // replace headers + xml = xml.replace(/(^.*)\n(?=\=\=+)/g, '

    $1

    '); + xml = xml.replace(/\=\=+/g, ''); + + // group multiple choice answers + xml = xml.replace(/(\(.?\).*\n*)+/g, function(match, p) { + var groupString = '\n'; + groupString += ' \n'; + var options = match.split('\n'); + for(var i = 0; i < options.length; i++) { + if(options[i].length > 0) { + var value = options[i].split(/\)\s*/)[1]; + var correct = /\(x\)/i.test(options[i]); + groupString += ' ' + value + '\n'; + } + } + groupString += ' \n'; + groupString += '\n\n'; + return groupString; + }); + + // group check answers + xml = xml.replace(/(\[.?\].*\n*)+/g, function(match, p) { + var groupString = '\n'; + groupString += ' \n'; + var options = match.split('\n'); + for(var i = 0; i < options.length; i++) { + if(options[i].length > 0) { + var value = options[i].split(/\]\s*/)[1]; + var correct = /\[x\]/i.test(options[i]); + groupString += ' ' + value + '\n'; + } + } + groupString += ' \n'; + groupString += '\n\n'; + return groupString; + }); + + // replace videos + xml = xml.replace(/\{\{video\s(.*)\}\}/g, '