Added es.MenuView

This commit is contained in:
Trevor Parscal 2011-12-02 00:30:50 +00:00
parent 874e8aa40a
commit 8a58fb5189
6 changed files with 196 additions and 83 deletions

View file

@ -93,6 +93,7 @@ $wgResourceModules += array(
'es/views/es.HeadingView.js',
'es/views/es.ListItemView.js',
'es/views/es.ListView.js',
'es/views/es.MenuView.js',
'es/views/es.ParagraphView.js',
'es/views/es.PreView.js',
'es/views/es.SurfaceView.js',
@ -115,6 +116,7 @@ $wgResourceModules += array(
'es/styles/es.ContentView.css',
'es/styles/es.DocumentView.css',
'es/styles/es.ToolbarView.css',
'es/styles/es.MenuView.css',
),
'dependencies' => array(
'jquery',

View file

@ -8,6 +8,7 @@
<link rel="stylesheet" href="../modules/es/styles/es.ContentView.css">
<link rel="stylesheet" href="../modules/es/styles/es.DocumentView.css">
<link rel="stylesheet" href="../modules/es/styles/es.ToolbarView.css">
<link rel="stylesheet" href="../modules/es/styles/es.MenuView.css">
<link rel="stylesheet" href="../modules/sandbox/sandbox.css">
<style>
body {
@ -126,6 +127,7 @@
<script src="../modules/es/views/es.ParagraphView.js"></script>
<script src="../modules/es/views/es.PreView.js"></script>
<script src="../modules/es/views/es.ListView.js"></script>
<script src="../modules/es/views/es.MenuView.js"></script>
<script src="../modules/es/views/es.ListItemView.js"></script>
<script src="../modules/es/views/es.TableView.js"></script>
<script src="../modules/es/views/es.TableRowView.js"></script>

View file

@ -45,7 +45,23 @@
border-color: #b3d6f6;
}
.es-contextView-container {
.es-contextView-position-above .es-contextView-menu {
bottom: -4px;
}
.es-contextView-position-below .es-contextView-menu {
top: 3px;
}
.es-contextView-position-left .es-contextView-menu {
left: -1px;
}
.es-contextView-position-right .es-contextView-menu {
right: -1px;
}
.es-contextView-panels {
position: absolute;
border: solid 1px #cccccc;
-webkit-border-radius: 0.25em;
@ -59,50 +75,12 @@
padding: 0.33em 0;
}
.es-contextView-container {
display: none;
}
.es-contextView-position-above .es-contextView-container {
bottom: -4px;
}
.es-contextView-position-below .es-contextView-container {
top: 3px;
}
.es-contextView-position-left .es-contextView-container {
left: -1px;
}
.es-contextView-position-right .es-contextView-container {
right: -1px;
}
.es-contextView-menuItem {
padding: 0.33em 1em;
cursor: pointer;
white-space: nowrap;
}
.es-contextView-menuSection {
padding: 0.33em 0.66em;
white-space: nowrap;
}
.es-contextView-menuItem-break {
margin: 0.33em 0;
border-top: solid 1px #dddddd;
}
.es-contextView-menuItem:hover {
background-color: #b3d6f6;
}
.es-contextView-panels {
}
.es-contextView-panel {
display: none;
padding: 1em;
}
.es-contextView-toolbar {
padding: 0.33em 0.66em;
white-space: nowrap;
}

View file

@ -0,0 +1,29 @@
.es-menuView {
display: none;
position: absolute;
border: solid 1px #cccccc;
-webkit-border-radius: 0.25em;
-moz-border-radius: 0.25em;
-o-border-radius: 0.25em;
border-radius: 0.25em;
background-color: rgba(255,255,255,0.95);
-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);
padding: 0.33em 0;
}
.es-menuView-item {
padding: 0.33em 1em;
cursor: pointer;
white-space: nowrap;
}
.es-menuView-item:hover {
background-color: #b3d6f6;
}
.es-menuView-break {
margin: 0.33em 0;
border-top: solid 1px #dddddd;
}

View file

@ -6,65 +6,55 @@
* @param {jQuery} $overlay DOM selection to add nodes to
*/
es.ContextView = function( surfaceView, $overlay ) {
var _this = this;
// Properties
this.surfaceView = surfaceView;
this.$ = $( '<div class="es-contextView"></div>' ).appendTo( $overlay || $( 'body' ) );
this.$toolbar = $( '<div class="es-contextView-menuSection"></div>' );
this.$container = $( '<div class="es-contextView-container"></div>' )
.appendTo( this.$ );
this.$menu = $( '<div class="es-contextView-menu"></div>' )
.append( this.$toolbar )
.appendTo( this.$container );
this.$panels = $( '<div class="es-contextView-panels"></div>' )
.appendTo( this.$container );
this.$icon = $( '<div class="es-contextView-icon"></div>' )
.appendTo( this.$ );
this.$panels = $( '<div class="es-contextView-panels"></div>' ).appendTo( this.$ );
this.$toolbar = $( '<div class="es-contextView-toolbar"></div>' );
this.toolbarView = new es.ToolbarView(
this.$toolbar,
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.find( '[rel="link"]' ).show();
_this.$panels.find( '[rel="link"] input:first' ).focus();
} },
'-',
{ 'name': 'copy', 'label': 'Copy' },
{ 'name': 'cut', 'label': 'Cut' },
{ 'name': 'paste', 'label': 'Paste' }
] );
this.$.append( this.menu.$ );
this.$icon = $( '<div class="es-contextView-icon"></div>' ).appendTo( this.$ );
// Example menu items
this.$menu.append(
'<div class="es-contextView-menuItem-break"></div>' +
'<div class="es-contextView-menuItem" rel="link">Link to...</div>' +
'<div class="es-contextView-menuItem-break"></div>' +
'<div class="es-contextView-menuItem">Copy</div>' +
'<div class="es-contextView-menuItem">Cut</div>' +
'<div class="es-contextView-menuItem">Paste</div>'
);
// Example panel
this.$panels.append(
'<div class="es-contextView-panel" rel="link">' +
'<div><label>Page title or URL <input type="text"></label></div>' +
'<div><a href="#cancel">Cancel</a> <button>Change</button></div>' +
'</div>'
);
this.$panels.find( '[href="#cancel"]' ).click( function() {
_this.$panels.children().hide();
} );
// Events
var _this = this;
this.$icon.click( function() {
_this.$container.toggle();
} );
this.$menu.find( '[rel="link"]' ).click( function() {
_this.$menu.hide();
_this.$panels.find( '[rel="link"]' ).show();
_this.$panels.find( '[rel="link"] input:first' ).focus();
} );
this.$panels.find( 'button, [href="#cancel"]' ).click( function() {
_this.$menu.show();
_this.$panels.children().hide();
_this.$container.toggle();
_this.surfaceView.$input.focus();
return false;
_this.menu.toggle();
} );
};
/* Methods */
es.ContextView.prototype.set = function() {
this.$.removeClass(
'es-contextView-position-below es-contextView-position-above ' +
'es-contextView-position-left es-contextView-position-right ' +
@ -91,12 +81,12 @@ es.ContextView.prototype.set = function() {
}
}
if ( position ) {
if ( position.left + this.$container.width() < $( 'body' ).width() ) {
if ( position.left + this.menu.$.width() < $( 'body' ).width() ) {
this.$.addClass( 'es-contextView-position-left' );
} else {
this.$.addClass( 'es-contextView-position-right' );
}
if ( position.top + this.$container.height() < $( window ).height() + $( window ).scrollTop() ) {
if ( position.top + this.menu.$.height() < $( window ).height() + $( window ).scrollTop() ) {
this.$.addClass( 'es-contextView-position-below' );
} else {
this.$.addClass( 'es-contextView-position-above' );
@ -107,6 +97,7 @@ es.ContextView.prototype.set = function() {
};
es.ContextView.prototype.clear = function() {
this.$panels.hide().children().hide();
this.$icon.hide();
this.$container.hide();
this.menu.hide();
};

View file

@ -0,0 +1,111 @@
/**
* Creates an es.MenuView object.
*
* @class
* @constructor
* @param {jQuery} $overlay DOM selection to add nodes to
*/
es.MenuView = function( items, $overlay ) {
// Properties
this.$ = $( '<div class="es-menuView"></div>' ).appendTo( $overlay || $( 'body' ) );
this.items = [];
this.autoNamedBreaks = 0;
// Items
if ( es.isArray( items ) ) {
for ( var i = 0; i < items.length; i++ ) {
this.addItem( items[i] );
}
}
// Events
var _this = this;
this.$.bind( {
'mousedown': function( e ) {
if ( e.button === 0 ) {
e.preventDefault();
return false;
}
},
'mouseup': function( e ) {
if ( e.button === 0 ) {
var $item = $( e.target ).closest( '.es-menuView-item' );
if ( $item.length ) {
var name = $item.attr( 'rel' );
for ( var i = 0; i < _this.items.length; i++ ) {
if ( _this.items[i].name === name ) {
_this.onSelect( _this.items[i], e );
return true;
}
}
}
}
}
} );
};
/* Methods */
es.MenuView.prototype.addItem = function( item, before ) {
if ( item === '-' ) {
item = {
'name': 'break-' + this.autoNamedBreaks++
};
}
// Items that don't have custom DOM elements will be auto-created
if ( !item.$ ) {
if ( !item.name ) {
throw 'Invalid menu item error. Items must have a name property.';
}
if ( item.label ) {
item.$ = $( '<div class="es-menuView-item"></div>' )
.attr( 'rel', item.name )
// TODO: i18n time!
.text( item.label );
} else {
// No label, must be a break
item.$ = $( '<div class="es-menuView-break"></div>' )
.attr( 'rel', item.name );
}
// TODO: Keyboard shortcut (and icons for them), support for keyboard accelerators, etc.
}
if ( before ) {
for ( var i = 0; i < this.items.length; i++ ) {
if ( this.items[i].name === before ) {
this.items.splice( i, 0, item );
this.items[i].$.before( item.$ );
return;
}
}
}
this.items.push( item );
this.$.append( item.$ );
};
es.MenuView.prototype.removeItem = function( name ) {
for ( var i = 0; i < this.items.length; i++ ) {
if ( this.items[i].name === name ) {
this.items.splice( i, 1 );
i--;
}
}
};
es.MenuView.prototype.show = function() {
this.$.show();
};
es.MenuView.prototype.toggle = function() {
this.$.toggle();
};
es.MenuView.prototype.hide = function() {
this.$.hide();
};
es.MenuView.prototype.onSelect = function( item, event ) {
if ( typeof item.callback === 'function' ) {
item.callback();
}
this.hide();
};