Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Moved placeholder logic out of Javascript and the DOM and into CSS #45

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
17 changes: 11 additions & 6 deletions cnx/aloha-config.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
#
Expand Down
42 changes: 35 additions & 7 deletions cnx/aloha-config.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

165 changes: 105 additions & 60 deletions src/plugins/oer/note/lib/note-plugin.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -8,95 +8,140 @@ define [
'semanticblock/semanticblock-plugin'
'css!note/css/note-plugin.css'], (Aloha, Plugin, jQuery, Ephemera, UI, Button, semanticBlock) ->

TITLE_CONTAINER = '''
<div class="type-container dropdown">
<a class="type" data-toggle="dropdown"></a>
<span class="title" placeholder="Add a title (optional)"></span>
<ul class="dropdown-menu">
<li><a href="">Note</a></li>
<li><a href="">Aside</a></li>
<li><a href="">Warning</a></li>
<li><a href="">Tip</a></li>
<li><a href="">Important</a></li>
</ul>
</div>
TYPE_CONTAINER = jQuery '''
<span class="type-container dropdown aloha-ephemera">
<a class="type" data-toggle="dropdown"></a>
<ul class="dropdown-menu">
</ul>
</span>
'''

# 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'
newTemplate = jQuery("<#{tagName}></#{tagName}")
newTemplate.addClass(className)
newTemplate.attr('data-type', className)
if hasTitle
newTemplate.append("<#{titleTagName} class='title'></#{titleTagName}")
tagName = type.tagName or 'div'
titleTagName = type.titleTagName or 'div'

semanticBlock.activateHandler(className, (element) ->
if hasTitle
titleElement = element.children('.title')
selector = ".#{className}:not([data-type])"
selector = ".#{className}[data-type='#{typeName}']" if typeName

if titleElement.length
title = titleElement.html()
titleElement.remove()
else
title = ''
notishClasses[className] = true

type = element.attr('data-type') or className

body = element.children()
element.children().remove()
newTemplate = jQuery("<#{tagName}></#{tagName}")
newTemplate.addClass(className)
newTemplate.attr('data-type', typeName) if typeName
if hasTitle
newTemplate.append("<#{titleTagName} class='title'></#{titleTagName}")

if hasTitle
titleContainer = jQuery(TITLE_CONTAINER)
titleContainer.find('.title').text(title)
titleContainer.find('.type').text(type.charAt(0).toUpperCase() + type.slice(1) )
titleContainer.prependTo(element)
titleContainer.children('.title').aloha()
semanticBlock.activateHandler(selector, ($element) =>
type = $element.attr('data-type') or className

$title = $element.children('.title')
$title.attr('placeholder', 'Add a title (optional)')
$title.aloha()

$body = $element.contents().not($title)

typeContainer = TYPE_CONTAINER.clone()
# Add dropdown elements for each possible type
jQuery.each @settings, (i, foo) =>
$option = jQuery('<li><a href=""></a></li>')
$option.appendTo(typeContainer.find('.dropdown-menu'))
$option = $option.children('a')
$option.text(foo.label)
$option.on 'click', =>
# Remove the title if this type does not have one
if foo.hasTitle
# If there is no `.title` element then add one in and enable it as an Aloha block
if not $element.children('.title')[0]
$newTitle = jQuery("<#{foo.titleTagName or 'span'} class='title'></#{foo.titleTagName or 'span'}")
$element.append($newTitle)
$newTitle.aloha()

else
$element.children('.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)


typeContainer.find('.type').text(label)
typeContainer.prependTo($element)

# Create the body and add some placeholder text
$('<div>').addClass('body')
.attr('placeholder', "Type the text of your #{className} here.")
.append(body)
.appendTo(element)
.append($body)
.appendTo($element)
.aloha()
)
semanticBlock.deactivateHandler(className, (element) ->
bodyElement = element.children('.body')
body = bodyElement.children()

if body == bodyElement.attr('placeholder')
body = ''
semanticBlock.deactivateHandler(selector, ($element) ->
$body = $element.children('.body')
$body = $body.children()

element.children('.body').remove()
$element.children('.body').remove()

if hasTitle
titleElement = element.children('.type-container').children('.title')
title = titleElement.text()

if title == titleElement.attr('placeholder')
title = ''
$title = $element.children('.title')
if not $title[0]
$title = jQuery("<#{titleTagName}></#{titleTagName}>")
$title.addClass 'title'

element.children('.type-container').remove()
jQuery("<div>").addClass('title').text(title).prependTo(element)
$title.prependTo($element)

element.append(body)
$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())
Loading