Integrated menuView into format drop down tool

This commit is contained in:
Trevor Parscal 2011-12-02 21:25:19 +00:00
parent 01180e4f8f
commit 3d678ea3bd
7 changed files with 161 additions and 91 deletions

View file

@ -19,6 +19,7 @@
-webkit-box-shadow: 0 0.25em 1em 0 rgba(0,0,0,0.25);
-moz-box-shadow: 0 0.25em 1em 0 rgba(0,0,0,0.25);
box-shadow: 0 0.25em 1em 0 rgba(0,0,0,0.25);
z-index: 4;
}
.es-contextView-position-start .es-contextView-icon {

View file

@ -11,6 +11,7 @@
-moz-box-shadow: 0 0.25em 1em 0 rgba(0,0,0,0.25);
box-shadow: 0 0.25em 1em 0 rgba(0,0,0,0.25);
padding: 0.33em 0;
z-index: 3;
}
.es-menuView-item {

View file

@ -88,6 +88,19 @@
background-image: url(../images/clear.png);
}
.es-toolbarDropdownTool {
border-color: #dddddd;
-webkit-border-radius: 0.25em;
-moz-border-radius: 0.25em;
-o-border-radius: 0.25em;
background-color: white;
font-size: 0.8em;
line-height: 24px;
padding-left: 0.75em;
padding-right: 24px;
background-image: url(../images/arrow-down.png);
background-position: 9em center;
background-repeat: no-repeat;
}
.es-toolbarDropdownTool-format {
width: 8em;
}
.es-toolbarDropdownTool-formatting {
}

View file

@ -1,28 +1,35 @@
es.DropdownTool = function( toolbar, name ) {
es.DropdownTool = function( toolbar, name, items ) {
// Inheritance
es.Tool.call( this, toolbar, name );
// for es.extendClass
// Early exit when extending via es.extendClass
if ( !name ) {
return;
}
this.$.addClass( 'es-toolbarDropdownTool' ).addClass( 'es-toolbarDropdownTool-' + name );
this.$select = $( '<select>' );
this.$.append( this.$select );
// Properties
var _this = this;
this.menuView = new es.MenuView( items, function( item ) {
_this.onSelect( item );
_this.$.text( item.label );
} );
this.$.bind( {
'change': function( e ) {
_this.onChange( e );
$( document ).add( this.toolbar.surfaceView.$ ).mousedown( function( e ) {
if ( e.button === 0 ) {
_this.menuView.hide();
}
} );
// DOM Changes
this.$.addClass( 'es-toolbarDropdownTool' ).addClass( 'es-toolbarDropdownTool-' + name );
};
es.DropdownTool.prototype.onChange = function() {
throw 'DropdownTool.onChange not implemented in this subclass:' + this.constructor;
/* Methods */
es.DropdownTool.prototype.onSelect = function( item ) {
throw 'DropdownTool.onSelect not implemented in this subclass:' + this.constructor;
};
es.extendClass( es.DropdownTool, es.Tool );
/* Inheritance */
es.extendClass( es.DropdownTool, es.Tool );

View file

@ -1,101 +1,123 @@
es.FormatDropdownTool = function( toolbar, name ) {
es.DropdownTool.call( this, toolbar, name );
this.formats = [
// Inheritance
es.DropdownTool.call( this, toolbar, name, [
{
'name': 'Paragraph',
'name': 'paragraph',
'label': 'Paragraph',
'type' : 'paragraph'
},
{
'name': 'Heading Level 1',
'name': 'heading-1',
'label': 'Heading Level 1',
'type' : 'heading',
'attributes': { 'level': 1 }
},
{
'name': 'Heading Level 2',
'name': 'heading-2',
'label': 'Heading Level 2',
'type' : 'heading',
'attributes': { 'level': 2 }
},
{
'name': 'Heading Level 3',
'name': 'heading-3',
'label': 'Heading Level 3',
'type' : 'heading',
'attributes': { 'level': 3 }
},
{
'name': 'Heading Level 4',
'name': 'heading-4',
'label': 'Heading Level 4',
'type' : 'heading',
'attributes': { 'level': 4 }
},
{
'name': 'Heading Level 5',
'name': 'heading-5',
'label': 'Heading Level 5',
'type' : 'heading',
'attributes': { 'level': 5 }
},
{
'name': 'Heading Level 6',
'name': 'heading-6',
'label': 'Heading Level 6',
'type' : 'heading',
'attributes': { 'level': 6 }
},
{
'name': 'Preformatted',
'name': 'pre',
'label': 'Preformatted',
'type' : 'pre'
}
];
this.$select.append( '<option>' );
] );
for ( var i = 0; i < this.formats.length; i++ ) {
$( '<option>' )
.val( i )
.html( this.formats[i].name )
.appendTo( this.$select );
}
var _this = this;
this.$.bind( {
'mousedown': function( e ) {
if ( e.button === 0 ) {
e.preventDefault();
return false;
}
},
'mouseup': function( e ) {
if ( e.button === 0 ) {
_this.menuView.setPosition( es.Position.newFromElementPagePosition( _this.$ ) );
_this.menuView.toggle();
}
}
} );
};
es.FormatDropdownTool.prototype.onChange = function() {
var index = this.$select.val();
if ( index in this.formats ) {
var txs = this.toolbar.surfaceView.model.getDocument().prepareLeafConversion(
this.toolbar.surfaceView.currentSelection,
this.formats[index].type,
this.formats[index].attributes
)
for ( var i = 0; i < txs.length; i++ ) {
this.toolbar.surfaceView.model.transact( txs[i] );
}
/* Methods */
es.FormatDropdownTool.prototype.onSelect = function( item ) {
var txs = this.toolbar.surfaceView.model.getDocument().prepareLeafConversion(
this.toolbar.surfaceView.currentSelection,
item.type,
item.attributes
);
for ( var i = 0; i < txs.length; i++ ) {
this.toolbar.surfaceView.model.transact( txs[i] );
}
};
es.FormatDropdownTool.prototype.updateState = function( annotations, nodes ) {
var format = {
'type': nodes[0].getElementType(),
'attributes': nodes[0].getElement().attributes
};
for( var i = 1; i < nodes.length; i++ ) {
if ( format.type != nodes[i].getElementType()
|| !es.compareObjects( format.attributes, nodes[i].element.attributes ) ) {
// Get type and attributes of the first node
var i,
format = {
'type': nodes[0].getElementType(),
'attributes': nodes[0].getElement().attributes
};
// Look for mismatches, in which case format should be null
for ( i = 1; i < nodes.length; i++ ) {
if ( format.type != nodes[i].getElementType() ||
!es.compareObjects( format.attributes, nodes[i].element.attributes ) ) {
format = null;
break;
}
}
if ( format === null ) {
this.$select.val( null );
this.$.text( '' );
} else {
for ( var i = 0; i < this.formats.length; i++ ) {
if ( format.type === this.formats[i].type
&& es.compareObjects( format.attributes, this.formats[i].attributes ) ) {
this.$select.val( i );
break;
var items = this.menuView.getItems();
for ( i = 0; i < items.length; i++ ) {
if (
format.type === items[i].type &&
es.compareObjects( format.attributes, items[i].attributes )
) {
this.$.text( items[i].label );
break;
}
}
}
};
/* Registration */
es.Tool.tools.format = {
constructor: es.FormatDropdownTool,
name: 'format'
'constructor': es.FormatDropdownTool,
'name': 'format'
};
es.extendClass( es.FormatDropdownTool, es.DropdownTool );
/* Inheritance */
es.extendClass( es.FormatDropdownTool, es.DropdownTool );

View file

@ -18,28 +18,30 @@ es.ContextView = function( surfaceView, $overlay ) {
this.surfaceView,
[{ 'name': 'textStyle', 'items' : [ 'bold', 'italic', 'formatting', 'clear' ] }]
);
this.menu = new es.MenuView( [
// Example menu items
{ 'name': 'tools', '$': this.$toolbar },
'-',
{ 'name': 'link', 'label': 'Link to...', 'callback': function() {
_this.menu.hide();
_this.$panels
.show()
.find( '[rel="link"]' )
this.menuView = new es.MenuView( [
// Example menu items
{ 'name': 'tools', '$': this.$toolbar },
'-',
{ 'name': 'link', 'label': 'Link to...', 'callback': function( item ) {
_this.menuView.hide();
_this.$panels
.show()
.end()
.find( '[rel="link"] input:first' )
.focus();
} },
'-',
{ 'name': 'copy', 'label': 'Copy' },
{ 'name': 'cut', 'label': 'Cut' },
{ 'name': 'paste', 'label': 'Paste' }
] );
this.$.append( this.menu.$ );
.find( '[rel="link"]' )
.show()
.end()
.find( '[rel="link"] input:first' )
.focus();
} },
'-',
{ 'name': 'copy', 'label': 'Copy' },
{ 'name': 'cut', 'label': 'Cut' },
{ 'name': 'paste', 'label': 'Paste' }
],
null,
this.$
);
this.$icon = $( '<div class="es-contextView-icon"></div>' ).appendTo( this.$ );
// Example panel
this.$panels.append(
'<div class="es-contextView-panel" rel="link">' +
@ -52,8 +54,18 @@ es.ContextView = function( surfaceView, $overlay ) {
} );
// Events
this.$icon.click( function() {
_this.menu.toggle();
this.$icon.bind( {
'mousedown': function( e ) {
if ( e.button === 0 ) {
e.preventDefault();
return false;
}
},
'mouseup': function( e ) {
if ( e.button === 0 ) {
_this.menuView.toggle();
}
}
} );
};
@ -86,12 +98,13 @@ es.ContextView.prototype.set = function() {
}
}
if ( position ) {
if ( position.left + this.menu.$.width() < $( 'body' ).width() ) {
if ( position.left + this.menuView.$.width() < $( 'body' ).width() ) {
this.$.addClass( 'es-contextView-position-left' );
} else {
this.$.addClass( 'es-contextView-position-right' );
}
if ( position.top + this.menu.$.height() < $( window ).height() + $( window ).scrollTop() ) {
var $window = $( window );
if ( position.top + this.menuView.$.height() < $window.height() + $window.scrollTop() ) {
this.$.addClass( 'es-contextView-position-below' );
} else {
this.$.addClass( 'es-contextView-position-above' );
@ -104,5 +117,5 @@ es.ContextView.prototype.set = function() {
es.ContextView.prototype.clear = function() {
this.$panels.hide().children().hide();
this.$icon.hide();
this.menu.hide();
this.menuView.hide();
};

View file

@ -3,13 +3,16 @@
*
* @class
* @constructor
* @param {jQuery} $overlay DOM selection to add nodes to
* @param {Object[]} items List of items to append initially
* @param {Function} callback Function to call if an item doesn't have it's own callback
* @param {jQuery} [$overlay=$( 'body' )] DOM selection to add nodes to
*/
es.MenuView = function( items, $overlay ) {
es.MenuView = function( items, callback, $overlay ) {
// Properties
this.$ = $( '<div class="es-menuView"></div>' ).appendTo( $overlay || $( 'body' ) );
this.items = [];
this.autoNamedBreaks = 0;
this.callback = callback;
// Items
if ( es.isArray( items ) ) {
@ -91,6 +94,14 @@ es.MenuView.prototype.removeItem = function( name ) {
}
};
es.MenuView.prototype.getItems = function() {
return this.items;
};
es.MenuView.prototype.setPosition = function( position ) {
return this.$.css( { 'top': position.top, 'left': position.left } );
};
es.MenuView.prototype.show = function() {
this.$.show();
};
@ -105,7 +116,9 @@ es.MenuView.prototype.hide = function() {
es.MenuView.prototype.onSelect = function( item, event ) {
if ( typeof item.callback === 'function' ) {
item.callback();
item.callback( item );
} else if ( typeof this.callback === 'function' ) {
this.callback( item );
}
this.hide();
};