diff --git a/cnx/aloha-config.coffee b/cnx/aloha-config.coffee index 135bef555a..9a0212b9b5 100644 --- a/cnx/aloha-config.coffee +++ b/cnx/aloha-config.coffee @@ -8,7 +8,7 @@ @Aloha.settings = jQuery: @jQuery # Use the same version of jQuery logLevels: - error: true + error: false warn: true info: false debug: false @@ -47,11 +47,16 @@ 'oer/note' ] - note: - types: - 'note': true - 'noteish': true - 'noteish-notitle': false + note: [ + { label: 'Note', cls: 'note', hasTitle: true } + { label: 'Aside', cls: 'note', hasTitle: true, type: 'aside' } + { label: 'Warning', cls: 'note', hasTitle: true, type: 'warning' } + { label: 'Tip', cls: 'note', hasTitle: true, type: 'tip' } + { label: 'Important', cls: 'note', hasTitle: true, type: 'important' } + + { label: 'Noteish', cls: 'noteish', hasTitle: true } + { label: 'Noteish (no Title)', cls: 'noteish-notitle', hasTitle: false } + ] # This whole thing is what's needed to: # diff --git a/cnx/aloha-config.js b/cnx/aloha-config.js index 0b81d1c371..4e2f583720 100644 --- a/cnx/aloha-config.js +++ b/cnx/aloha-config.js @@ -6,7 +6,7 @@ this.Aloha.settings = { jQuery: this.jQuery, logLevels: { - error: true, + error: false, warn: true, info: false, debug: false @@ -18,14 +18,42 @@ }, errorhandling: true, plugins: { - load: ['common/ui', 'oer/toolbar', 'oer/popover', 'oer/format', 'common/contenthandler', 'common/paste', 'common/block', 'common/list', 'oer/table', 'oer/popover', 'oer/math', 'extra/draganddropfiles', 'common/image', 'oer/assorted', 'oer/title', 'common/undo', 'oer/undobutton', 'oer/genericbutton', 'oer/semanticblock', 'oer/exercise', 'oer/note'], - note: { - types: { - 'note': true, - 'noteish': true, - 'noteish-notitle': false + load: ['common/ui', 'oer/toolbar', 'oer/popover', 'oer/format', 'common/contenthandler', 'common/paste', 'common/block', 'common/list', 'oer/table', 'oer/popover', 'oer/math', 'extra/draganddropfiles', 'common/image', 'oer/assorted', 'oer/title', 'common/undo', 'oer/undobutton', 'oer/genericbutton', 'oer/semanticblock', 'oer/exercise', 'oer/note', 'oer/cnxmlplus-handler'], + note: [ + { + label: 'Note', + cls: 'note', + hasTitle: true + }, { + label: 'Aside', + cls: 'note', + hasTitle: true, + type: 'aside' + }, { + label: 'Warning', + cls: 'note', + hasTitle: true, + type: 'warning' + }, { + label: 'Tip', + cls: 'note', + hasTitle: true, + type: 'tip' + }, { + label: 'Important', + cls: 'note', + hasTitle: true, + type: 'important' + }, { + label: 'Noteish', + cls: 'noteish', + hasTitle: true + }, { + label: 'Noteish (no Title)', + cls: 'noteish-notitle', + hasTitle: false } - }, + ], draganddropfiles: { upload: { config: { diff --git a/src/plugins/oer/note/lib/note-plugin.coffee b/src/plugins/oer/note/lib/note-plugin.coffee index 00a0460134..55242600ba 100644 --- a/src/plugins/oer/note/lib/note-plugin.coffee +++ b/src/plugins/oer/note/lib/note-plugin.coffee @@ -8,41 +8,71 @@ define [ 'semanticblock/semanticblock-plugin' 'css!note/css/note-plugin.css'], (Aloha, Plugin, jQuery, Ephemera, UI, Button, semanticBlock) -> - TITLE_CONTAINER = ''' + TITLE_CONTAINER = jQuery(''' - ''' + ''') + + # Find all classes that could mean something is "notish" + # so they can be removed when the type is changed from the dropdown. + notishClasses = {} Plugin.create 'note', + # Default Settings + # ------- + # The plugin can listen to various classes that should "behave" like a note. + # For each notish element provide a: + # - `label`: **Required** Shows up in dropdown + # - `cls` : **Required** The classname to enable this plugin on + # - `hasTitle`: **Required** `true` if the element allows optional titles + # - `type`: value in the `data-type` attribute. + # - `tagName`: Default: `div`. The HTML element name to use when creating a new note + # - `titleTagName`: Default: `div`. The HTML element name to use when creating a new title + # + # For example, a Warning could look like this: + # + # { label:'Warning', cls:'note', hasTitle:false, type:'warning'} + # + # Then, when the user selects "Warning" from the dropdown the element's + # class and type will be changed and its `> .title` will be removed. + defaults: [ + { label: 'Note', cls: 'note', hasTitle: true } + ] init: () -> # Load up specific classes to listen to or use the default - types = @settings.types or {note: true} - jQuery.map types, (hasTitle, className) -> - - # These 2 variables should be moved into the config so other note-ish classes - # can define what the element name is that is generated for the note and + types = @settings + jQuery.each types, (i, type) => + className = type.cls or throw 'BUG Invalid configuration of not plugin. cls required!' + typeName = type.type + hasTitle = !!type.hasTitle + label = type.label or throw 'BUG Invalid configuration of not plugin. label required!' + + # These 2 variables allow other note-ish classes + # to define what the element name is that is generated for the note and # for the title. # # Maybe they could eventually be functions so titles for inline notes generate # a `span` instead of a `div` for example. - tagName = 'div' - titleTagName = 'div' + tagName = type.tagName or 'div' + titleTagName = type.titleTagName or 'div' + + selector = ".#{className}:not([data-type])" + selector = ".#{className}[data-type='#{typeName}']" if typeName + + notishClasses[className] = true + + newTemplate = jQuery("<#{tagName}> + semanticBlock.activateHandler(selector, (element) => if hasTitle titleElement = element.children('.title') @@ -58,9 +88,40 @@ define [ element.children().remove() if hasTitle - titleContainer = jQuery(TITLE_CONTAINER) + titleContainer = TITLE_CONTAINER.clone() + # Add dropdown elements for each possible type + jQuery.each @settings, (i, foo) => + $option = jQuery('
  • ') + $option.appendTo(titleContainer.find('.dropdown-menu')) + $option = $option.children('a') + $option.text(foo.label) + $option.on 'click', => + # Remove the title if this type does not have one + # The title was moved into `.type-container` for some reason + if foo.hasTitle + # If there is no `.title` element then add one in and enable it as an Aloha block + if not element.find('> .type-container > .title')[0] + $newTitle = jQuery("<#{foo.titleTagName or 'span'} class='title'> .type-container > .title').remove() + + # Remove the `data-type` if this type does not have one + if foo.type + element.attr('data-type', foo.type) + else + element.removeAttr('data-type') + + # Remove all notish class names and then add this one in + for key of notishClasses + element.removeClass key + element.addClass(foo.cls) + + titleContainer.find('.title').text(title) - titleContainer.find('.type').text(type.charAt(0).toUpperCase() + type.slice(1) ) + titleContainer.find('.type').text(label) titleContainer.prependTo(element) titleContainer.children('.title').aloha() @@ -71,7 +132,7 @@ define [ .appendTo(element) .aloha() ) - semanticBlock.deactivateHandler(className, (element) -> + semanticBlock.deactivateHandler(selector, (element) -> bodyElement = element.children('.body') body = bodyElement.children() @@ -93,10 +154,10 @@ define [ element.append(body) ) # Add a listener - UI.adopt "insert-#{className}", Button, + UI.adopt "insert-#{className}#{typeName}", Button, click: -> semanticBlock.insertAtCursor(newTemplate.clone()) # For legacy toolbars listen to 'insertNote' - if 'note' == className + if 'note' == className and not typeName UI.adopt "insertNote", Button, click: -> semanticBlock.insertAtCursor(newTemplate.clone()) diff --git a/src/plugins/oer/note/lib/note-plugin.js b/src/plugins/oer/note/lib/note-plugin.js index b2d57bb351..3d6313ecfc 100644 --- a/src/plugins/oer/note/lib/note-plugin.js +++ b/src/plugins/oer/note/lib/note-plugin.js @@ -2,26 +2,48 @@ (function() { define(['aloha', 'aloha/plugin', 'jquery', 'aloha/ephemera', 'ui/ui', 'ui/button', 'semanticblock/semanticblock-plugin', 'css!note/css/note-plugin.css'], function(Aloha, Plugin, jQuery, Ephemera, UI, Button, semanticBlock) { - var TITLE_CONTAINER; - TITLE_CONTAINER = ''; + var TITLE_CONTAINER, notishClasses; + TITLE_CONTAINER = jQuery(''); + notishClasses = {}; return Plugin.create('note', { + defaults: [ + { + label: 'Note', + cls: 'note', + hasTitle: true + } + ], init: function() { - var types; - types = this.settings.types || { - note: true - }; - return jQuery.map(types, function(hasTitle, className) { - var newTemplate, tagName, titleTagName; - tagName = 'div'; - titleTagName = 'div'; + var types, + _this = this; + types = this.settings; + return jQuery.each(types, function(i, type) { + var className, hasTitle, label, newTemplate, selector, tagName, titleTagName, typeName; + className = type.cls || (function() { + throw 'BUG Invalid configuration of not plugin. cls required!'; + })(); + typeName = type.type; + hasTitle = !!type.hasTitle; + label = type.label || (function() { + throw 'BUG Invalid configuration of not plugin. label required!'; + })(); + tagName = type.tagName || 'div'; + titleTagName = type.titleTagName || 'div'; + selector = "." + className + ":not([data-type])"; + if (typeName) { + selector = "." + className + "[data-type='" + typeName + "']"; + } + notishClasses[className] = true; newTemplate = jQuery("<" + tagName + ">'); + $option.appendTo(titleContainer.find('.dropdown-menu')); + $option = $option.children('a'); + $option.text(foo.label); + return $option.on('click', function() { + var $newTitle, key; + if (foo.hasTitle) { + if (!element.find('> .type-container > .title')[0]) { + $newTitle = jQuery("<" + (foo.titleTagName || 'span') + " class='title'> .type-container > .title').remove(); + } + if (foo.type) { + element.attr('data-type', foo.type); + } else { + element.removeAttr('data-type'); + } + for (key in notishClasses) { + element.removeClass(key); + } + return element.addClass(foo.cls); + }); + }); titleContainer.find('.title').text(title); - titleContainer.find('.type').text(type.charAt(0).toUpperCase() + type.slice(1)); + titleContainer.find('.type').text(label); titleContainer.prependTo(element); titleContainer.children('.title').aloha(); } return $('
    ').addClass('body').attr('placeholder', "Type the text of your " + className + " here.").append(body).appendTo(element).aloha(); }); - semanticBlock.deactivateHandler(className, function(element) { + semanticBlock.deactivateHandler(selector, function(element) { var body, bodyElement, title, titleElement; bodyElement = element.children('.body'); body = bodyElement.children(); @@ -62,12 +112,12 @@ } return element.append(body); }); - UI.adopt("insert-" + className, Button, { + UI.adopt("insert-" + className + typeName, Button, { click: function() { return semanticBlock.insertAtCursor(newTemplate.clone()); } }); - if ('note' === className) { + if ('note' === className && !typeName) { return UI.adopt("insertNote", Button, { click: function() { return semanticBlock.insertAtCursor(newTemplate.clone()); diff --git a/src/plugins/oer/semanticblock/lib/semanticblock-plugin.coffee b/src/plugins/oer/semanticblock/lib/semanticblock-plugin.coffee index 9a930709a9..8f0cf3fc45 100644 --- a/src/plugins/oer/semanticblock/lib/semanticblock-plugin.coffee +++ b/src/plugins/oer/semanticblock/lib/semanticblock-plugin.coffee @@ -60,10 +60,9 @@ define ['aloha', 'block/blockmanager', 'aloha/plugin', 'aloha/pluginmanager', 'j unless element.parent('.semantic-container').length or element.is('.semantic-container') element.addClass 'aloha-oer-block' element.wrap(blockTemplate).parent().append(blockControls.clone()).alohaBlock() - type = undefined - for type of activateHandlers - if element.hasClass(type) - activateHandlers[type] element + for selector of activateHandlers + if element.is(selector) + activateHandlers[selector] element break deactivate = (element) -> @@ -71,10 +70,9 @@ define ['aloha', 'block/blockmanager', 'aloha/plugin', 'aloha/pluginmanager', 'j element.removeClass 'aloha-oer-block ui-draggable' element.removeAttr 'style' - type = undefined - for type of deactivateHandlers - if element.hasClass(type) - deactivateHandlers[type] element + for selector of deactivateHandlers + if element.is(selector) + deactivateHandlers[selector] element break element.siblings('.semantic-controls').remove() element.unwrap() @@ -96,8 +94,8 @@ define ['aloha', 'block/blockmanager', 'aloha/plugin', 'aloha/pluginmanager', 'j Plugin.create 'semanticblock', makeClean: (content) -> - for type of deactivateHandlers - content.find('.aloha-oer-block.'+type).each -> + for selector of deactivateHandlers + content.find(".aloha-oer-block#{selector}").each -> deactivate jQuery(this) init: -> @@ -116,7 +114,7 @@ define ['aloha', 'block/blockmanager', 'aloha/plugin', 'aloha/pluginmanager', 'j $root = params.obj # Add a `.aloha-oer-block` to all registered classes classes = [] - classes.push ".#{cls}" for cls of activateHandlers + classes.push selector for selector of activateHandlers $root.find(classes.join()).each (i, el) -> $el = jQuery(el) $el.addClass 'aloha-oer-block' if not $el.parents('.semantic-drag-source')[0] @@ -159,11 +157,11 @@ define ['aloha', 'block/blockmanager', 'aloha/plugin', 'aloha/pluginmanager', 'j $element = Aloha.jQuery('.semantic-temp').removeClass('semantic-temp') activate $element - activateHandler: (type, handler) -> - activateHandlers[type] = handler + activateHandler: (selector, handler) -> + activateHandlers[selector] = handler - deactivateHandler: (type, handler) -> - deactivateHandlers[type] = handler + deactivateHandler: (selector, handler) -> + deactivateHandlers[selector] = handler registerEvent: (name, selector, callback) -> pluginEvents.push diff --git a/src/plugins/oer/semanticblock/lib/semanticblock-plugin.js b/src/plugins/oer/semanticblock/lib/semanticblock-plugin.js index 8de9baafe7..a1c5a4f7ee 100644 --- a/src/plugins/oer/semanticblock/lib/semanticblock-plugin.js +++ b/src/plugins/oer/semanticblock/lib/semanticblock-plugin.js @@ -75,15 +75,14 @@ ]; insertElement = function(element) {}; activate = function(element) { - var type, _results; + var selector, _results; if (!(element.parent('.semantic-container').length || element.is('.semantic-container'))) { element.addClass('aloha-oer-block'); element.wrap(blockTemplate).parent().append(blockControls.clone()).alohaBlock(); - type = void 0; _results = []; - for (type in activateHandlers) { - if (element.hasClass(type)) { - activateHandlers[type](element); + for (selector in activateHandlers) { + if (element.is(selector)) { + activateHandlers[selector](element); break; } else { _results.push(void 0); @@ -93,14 +92,13 @@ } }; deactivate = function(element) { - var type; + var selector; if (element.parent('.semantic-container').length || element.is('.semantic-container')) { element.removeClass('aloha-oer-block ui-draggable'); element.removeAttr('style'); - type = void 0; - for (type in deactivateHandlers) { - if (element.hasClass(type)) { - deactivateHandlers[type](element); + for (selector in deactivateHandlers) { + if (element.is(selector)) { + deactivateHandlers[selector](element); break; } } @@ -130,10 +128,10 @@ }); return Plugin.create('semanticblock', { makeClean: function(content) { - var type, _results; + var selector, _results; _results = []; - for (type in deactivateHandlers) { - _results.push(content.find('.aloha-oer-block.' + type).each(function() { + for (selector in deactivateHandlers) { + _results.push(content.find(".aloha-oer-block" + selector).each(function() { return deactivate(jQuery(this)); })); } @@ -160,11 +158,11 @@ } }); return Aloha.bind('aloha-editable-created', function(e, params) { - var $root, classes, cls; + var $root, classes, selector; $root = params.obj; classes = []; - for (cls in activateHandlers) { - classes.push("." + cls); + for (selector in activateHandlers) { + classes.push(selector); } $root.find(classes.join()).each(function(i, el) { var $el; @@ -217,11 +215,11 @@ $element = Aloha.jQuery('.semantic-temp').removeClass('semantic-temp'); return activate($element); }, - activateHandler: function(type, handler) { - return activateHandlers[type] = handler; + activateHandler: function(selector, handler) { + return activateHandlers[selector] = handler; }, - deactivateHandler: function(type, handler) { - return deactivateHandlers[type] = handler; + deactivateHandler: function(selector, handler) { + return deactivateHandlers[selector] = handler; }, registerEvent: function(name, selector, callback) { return pluginEvents.push({