/** * Toolbar module for wikiEditor */ ( function ( mw, $ ) { $.wikiEditor.modules.toolbar = { /** * API accessible functions */ api : { addToToolbar : function( context, data ) { var smooth = true, type, i; for ( type in data ) { switch ( type ) { case 'sections': var $sections = context.modules.toolbar.$toolbar.find( 'div.sections' ), $tabs = context.modules.toolbar.$toolbar.find( 'div.tabs' ); for ( var section in data[type] ) { if ( section == 'main' ) { // Section context.modules.toolbar.$toolbar.prepend( $.wikiEditor.modules.toolbar.fn.buildSection( context, section, data[type][section] ) ); continue; } // Section $sections.append( $.wikiEditor.modules.toolbar.fn.buildSection( context, section, data[type][section] ) ); // Tab $tabs.append( $.wikiEditor.modules.toolbar.fn.buildTab( context, section, data[type][section] ) ); } break; case 'groups': if ( ! ( 'section' in data ) ) { continue; } var $section = context.modules.toolbar.$toolbar.find( 'div[rel="' + data.section + '"].section' ); for ( var group in data[type] ) { // Group $section.append( $.wikiEditor.modules.toolbar.fn.buildGroup( context, group, data[type][group] ) ); } smooth = false; break; case 'tools': if ( ! ( 'section' in data && 'group' in data ) ) { continue; } var $group = context.modules.toolbar.$toolbar.find( 'div[rel="' + data.section + '"].section ' + 'div[rel="' + data.group + '"].group' ); for ( var tool in data[type] ) { // Tool $group.append( $.wikiEditor.modules.toolbar.fn.buildTool( context, tool, data[type][tool] ) ); } if ( $group.children().length ) { $group.show(); } smooth = false; break; case 'pages': if ( ! ( 'section' in data ) ) { continue; } var $pages = context.modules.toolbar.$toolbar.find( 'div[rel="' + data.section + '"].section .pages' ); var $index = context.modules.toolbar.$toolbar.find( 'div[rel="' + data.section + '"].section .index' ); for ( var page in data[type] ) { // Page $pages.append( $.wikiEditor.modules.toolbar.fn.buildPage( context, page, data[type][page] ) ); // Index $index.append( $.wikiEditor.modules.toolbar.fn.buildBookmark( context, page, data[type][page] ) ); } $.wikiEditor.modules.toolbar.fn.updateBookletSelection( context, page, $pages, $index ); smooth = false; break; case 'rows': if ( ! ( 'section' in data && 'page' in data ) ) { continue; } var $table = context.modules.toolbar.$toolbar.find( 'div[rel="' + data.section + '"].section ' + 'div[rel="' + data.page + '"].page table' ); for ( i = 0; i < data.rows.length; i++ ) { // Row $table.append( $.wikiEditor.modules.toolbar.fn.buildRow( context, data.rows[i] ) ); } smooth = false; break; case 'characters': if ( ! ( 'section' in data && 'page' in data ) ) { continue; } var $characters = context.modules.toolbar.$toolbar.find( 'div[rel="' + data.section + '"].section ' + 'div[rel="' + data.page + '"].page div' ); var actions = $characters.data( 'actions' ); for ( i = 0; i < data.characters.length; i++ ) { // Character $characters .append( $( $.wikiEditor.modules.toolbar.fn.buildCharacter( data.characters[i], actions ) ) .mousedown( function( e ) { context.fn.saveCursorAndScrollTop(); // No dragging! e.preventDefault(); return false; } ) .click( function( e ) { $.wikiEditor.modules.toolbar.fn.doAction( $(this).parent().data( 'context' ), $(this).parent().data( 'actions' )[$(this).attr( 'rel' )] ); e.preventDefault(); return false; } ) ); } smooth = false; break; default: break; } } // Fix div.section size after adding things; if smooth is true uses a smooth // animation, otherwise just change height (breaking any ongoing animation) var $divSections = context.modules.toolbar.$toolbar.find( 'div.sections' ); var $visibleSection = $divSections.find( '.section:visible' ); if ( $visibleSection.size() ) { if ( smooth ) { $divSections.animate( { 'height': $visibleSection.outerHeight() }, 'fast' ); } else { $divSections.height( $visibleSection.outerHeight() ); } } }, removeFromToolbar : function( context, data ) { if ( typeof data.section == 'string' ) { // Section var tab = 'div.tabs span[rel="' + data.section + '"].tab'; var target = 'div[rel="' + data.section + '"].section'; var group = null; if ( typeof data.group == 'string' ) { // Toolbar group target += ' div[rel="' + data.group + '"].group'; if ( typeof data.tool == 'string' ) { // Save for later checking if empty group = target; // Tool target += ' a[rel="' + data.tool + '"].tool'; } } else if ( typeof data.page == 'string' ) { // Booklet page var index = target + ' div.index div[rel="' + data.page + '"]'; target += ' div.pages div[rel="' + data.page + '"].page'; if ( typeof data.character == 'string' ) { // Character target += ' span[rel="' + data.character + '"]'; } else if ( typeof data.row == 'number' ) { // Table row target += ' table tr:not(:has(th)):eq(' + data.row + ')'; } else { // Just a page, remove the index too! context.modules.toolbar.$toolbar.find( index ).remove(); $.wikiEditor.modules.toolbar.fn.updateBookletSelection( context, null, context.modules.toolbar.$toolbar.find( target ), context.modules.toolbar.$toolbar.find( index ) ); } } else { // Just a section, remove the tab too! context.modules.toolbar.$toolbar.find( tab ).remove(); } context.modules.toolbar.$toolbar.find( target ).remove(); // Hide empty groups if ( group ) { var $group = context.modules.toolbar.$toolbar.find( group ); if ( $group.children().length === 0 ) { $group.hide(); } } } } }, /** * Event handlers */ evt: { resize: function( context, event ) { context.$ui.find( '.sections' ).height( context.$ui.find( '.sections .section-visible' ).outerHeight() ); }, tocCollapse: function( context, event ) { $.wikiEditor.modules.toolbar.evt.resize( context, event ); }, tocExpand: function( context, event ) { $.wikiEditor.modules.toolbar.evt.resize( context, event ); } }, /** * Internally used functions */ fn: { /** * Creates a toolbar module within a wikiEditor * * @param {Object} context Context object of editor to create module in * @param {Object} config Configuration object to create module from */ create : function( context, config ) { if ( '$toolbar' in context.modules.toolbar ) { return; } context.modules.toolbar.$toolbar = $( '
' ) .addClass( 'wikiEditor-ui-toolbar' ) .attr( 'id', 'wikiEditor-ui-toolbar' ); $.wikiEditor.modules.toolbar.fn.build( context, config ); context.$ui.find( '.wikiEditor-ui-top' ).append( context.modules.toolbar.$toolbar ); }, /** * Performs an operation based on parameters * * @param {Object} context * @param {Object} action * @param {Object} source */ doAction : function( context, action, source ) { switch ( action.type ) { case 'replace': case 'encapsulate': var parts = { 'pre' : $.wikiEditor.autoMsg( action.options, 'pre' ), 'peri' : $.wikiEditor.autoMsg( action.options, 'peri' ), 'post' : $.wikiEditor.autoMsg( action.options, 'post' ) }; var replace = action.type == 'replace'; if ( 'regex' in action.options && 'regexReplace' in action.options ) { var selection = context.$textarea.textSelection( 'getSelection' ); if ( selection !== '' && selection.match( action.options.regex ) ) { parts.peri = selection.replace( action.options.regex, action.options.regexReplace ); parts.pre = parts.post = ''; replace = true; } } context.$textarea.textSelection( 'encapsulateSelection', $.extend( {}, action.options, parts, { 'replace': replace } ) ); if ( context.$iframe !== undefined ) { context.$iframe[0].contentWindow.focus(); } break; case 'callback': if ( typeof action.execute == 'function' ) { action.execute( context ); } break; case 'dialog': context.fn.saveSelection(); context.$textarea.wikiEditor( 'openDialog', action.module ); break; default: break; } }, buildGroup : function( context, id, group ) { var $group = $( '' ).attr( { 'class' : 'group group-' + id, 'rel' : id } ); var label = $.wikiEditor.autoMsg( group, 'label' ); if ( label ) { $group.append( '' + label + '' ); } var empty = true; if ( 'tools' in group ) { for ( var tool in group.tools ) { tool = $.wikiEditor.modules.toolbar.fn.buildTool( context, tool, group.tools[tool] ); if ( tool ) { // Consider a group with only hidden tools empty as well // .is( ':visible' ) always returns false because tool is not attached to the DOM yet empty = empty && tool.css( 'display' ) == 'none'; $group.append( tool ); } } } if ( empty ) { $group.hide(); } return $group; }, buildTool : function( context, id, tool ) { if ( 'filters' in tool ) { for ( var i = 0; i < tool.filters.length; i++ ) { if ( $( tool.filters[i] ).size() === 0 ) { return null; } } } var label = $.wikiEditor.autoMsg( tool, 'label' ); switch ( tool.type ) { case 'button': var src = $.wikiEditor.autoIcon( tool.icon, $.wikiEditor.imgPath + 'toolbar/' ); var $button = null; if ( 'offset' in tool ) { var offsetOrIcon = $.wikiEditor.autoIconOrOffset( tool.icon, tool.offset, $.wikiEditor.imgPath + 'toolbar/' ); if ( typeof offsetOrIcon == 'object' ) { $button = $( '' ) .attr( { 'href' : '#', 'alt' : label, 'title' : label, 'rel' : id, 'class' : 'tool tool-button wikiEditor-toolbar-spritedButton' } ) .text( label ) .css( 'backgroundPosition', offsetOrIcon[0] + 'px ' + offsetOrIcon[1] + 'px' ); } } if ( !$button ) { $button = $( '' ) .attr( { 'src' : src, 'width' : 22, 'height' : 22, 'alt' : label, 'title' : label, 'rel' : id, 'class' : 'tool tool-button' } ); } if ( 'action' in tool ) { $button .data( 'action', tool.action ) .data( 'context', context ) .mousedown( function( e ) { context.fn.saveCursorAndScrollTop(); // No dragging! e.preventDefault(); return false; } ) .click( function( e ) { $.wikiEditor.modules.toolbar.fn.doAction( $(this).data( 'context' ), $(this).data( 'action' ), $(this) ); e.preventDefault(); return false; } ); } return $button; case 'select': var $select = $( '' ) .attr( { 'rel' : id, 'class' : 'tool tool-select' } ); var $options = $( '' ).addClass( 'options' ); if ( 'list' in tool ) { for ( var option in tool.list ) { var optionLabel = $.wikiEditor.autoMsg( tool.list[option], 'label' ); $options.append( $( '' ) .data( 'action', tool.list[option].action ) .data( 'context', context ) .mousedown( function( e ) { context.fn.saveCursorAndScrollTop(); // No dragging! e.preventDefault(); return false; } ) .click( function( e ) { $.wikiEditor.modules.toolbar.fn.doAction( $(this).data( 'context' ), $(this).data( 'action' ), $(this) ); // Hide the dropdown // Sanity check: if this somehow gets called while the dropdown // is hidden, don't show it if ( $(this).parent().is( ':visible' ) ) { $(this).parent().animate( { 'opacity': 'toggle' }, 'fast' ); } e.preventDefault(); return false; } ) .text( optionLabel ) .addClass( 'option' ) .attr( { 'rel': option, 'href': '#' } ) ); } } $select.append( $( '' ).addClass( 'menu' ).append( $options ) ); $select.append( $( '' ) .addClass( 'label' ) .text( label ) .data( 'options', $options ) .attr( 'href', '#' ) .mousedown( function( e ) { // No dragging! e.preventDefault(); return false; } ) .click( function( e ) { $(this).data( 'options' ).animate( { 'opacity': 'toggle' }, 'fast' ); e.preventDefault(); return false; } ) ); return $select; default: return null; } }, buildBookmark : function( context, id, page ) { var label = $.wikiEditor.autoMsg( page, 'label' ); return $( '' ) .text( label ) .attr( 'rel', id ) .data( 'context', context ) .mousedown( function( e ) { context.fn.saveCursorAndScrollTop(); // No dragging! e.preventDefault(); return false; } ) .click( function( event ) { $(this).parent().parent().find( '.page' ).hide(); $(this).parent().parent().find( '.page-' + $(this).attr( 'rel' ) ).show(); $(this).siblings().removeClass( 'current' ); $(this).addClass( 'current' ); var section = $(this).parent().parent().attr( 'rel' ); $.cookie( 'wikiEditor-' + $(this).data( 'context' ).instance + '-booklet-' + section + '-page', $(this).attr( 'rel' ), { expires: 30, path: '/' } ); context.fn.restoreCursorAndScrollTop(); // No dragging! event.preventDefault(); return false; } ); }, buildPage : function( context, id, page ) { var html; var $page = $( '' ).attr( { 'class' : 'page page-' + id, 'rel' : id } ); switch ( page.layout ) { case 'table': $page.addClass( 'page-table' ); html = '