| | 1 | /* global tinymce */ |
| | 2 | tinymce.PluginManager.add( 'wpaudiovideo', function( editor ) { |
| | 3 | |
| | 4 | function parseMediaShortcode( content ) { |
| | 5 | return content.replace( /\[(audio|video)[^\]]*\][\s\S]*?\[\/\1\]/g, function( match, type ) { |
| | 6 | var data = window.encodeURIComponent( match ), |
| | 7 | cls = 'dashicons-format-' + type; |
| | 8 | |
| | 9 | return '<div class="wp-control" data-wp-control="' + data + '" contenteditable="false" tabindex="0"><p class="' + cls + '"><br></p></div>'; |
| | 10 | }); |
| | 11 | } |
| | 12 | |
| | 13 | function getMediaShortcode( content ) { |
| | 14 | function getAttr( str, name ) { |
| | 15 | name = new RegExp( name + '=\"([^\"]+)\"', 'g' ).exec( str ); |
| | 16 | return name ? window.decodeURIComponent( name[1] ) : ''; |
| | 17 | } |
| | 18 | |
| | 19 | return content.replace( /<div ([^>]+)>(?:\u00a0| | )*<\/div>/g, function( match, attr ) { |
| | 20 | var data = getAttr( attr, 'data-wp-control' ); |
| | 21 | |
| | 22 | if ( data ) { |
| | 23 | return data; |
| | 24 | } |
| | 25 | |
| | 26 | return match; |
| | 27 | }); |
| | 28 | } |
| | 29 | |
| | 30 | editor.on( 'BeforeSetContent', function( e ) { |
| | 31 | e.content = parseMediaShortcode( e.content ); |
| | 32 | }); |
| | 33 | |
| | 34 | editor.on( 'PostProcess', function( e ) { |
| | 35 | if ( e.get ) { |
| | 36 | e.content = getMediaShortcode( e.content ); |
| | 37 | } |
| | 38 | }); |
| | 39 | |
| | 40 | // Add padding <p> if the noneditable node is last |
| | 41 | editor.on( 'SetContent', function( event ) { |
| | 42 | var node, body, p, |
| | 43 | dom = editor.dom; |
| | 44 | |
| | 45 | if ( event.load || ! event.set ) { |
| | 46 | body = editor.getBody(); |
| | 47 | |
| | 48 | if ( dom.hasClass( body.lastChild, 'wp-control' ) ) { |
| | 49 | p = dom.create( 'p', { 'data-wp-control-after': '1' }, tinymce.Env.ie && tinymce.Env.ie < 11 ? '' : '<br data-mce-bogus="1" />' ); |
| | 50 | dom.insertAfter( p, body.lastChild ); |
| | 51 | |
| | 52 | if ( ! event.set ) { |
| | 53 | editor.nodeChanged(); |
| | 54 | editor.selection.select( p ); |
| | 55 | editor.selection.collapse( true ); |
| | 56 | } |
| | 57 | } |
| | 58 | } |
| | 59 | }); |
| | 60 | |
| | 61 | editor.on( 'PreProcess', function( event ) { |
| | 62 | var dom = editor.dom; |
| | 63 | |
| | 64 | // Remove empty padding nodes |
| | 65 | tinymce.each( dom.select( '[data-wp-control-after]', event.node ), function( node ) { |
| | 66 | if ( dom.isEmpty( node ) ) { |
| | 67 | dom.remove( node ); |
| | 68 | } else { |
| | 69 | dom.setAttrib( node, 'data-wp-control-after', null ); |
| | 70 | } |
| | 71 | }); |
| | 72 | |
| | 73 | // Empty the control nodes |
| | 74 | tinymce.each( dom.select( '.wp-control', event.node ), function( node ) { |
| | 75 | tinymce.each( node.childNodes, function( child ) { |
| | 76 | dom.remove( child ); |
| | 77 | }); |
| | 78 | }); |
| | 79 | }); |
| | 80 | |
| | 81 | editor.on( 'init', function() { |
| | 82 | var dom = editor.dom, |
| | 83 | selection = editor.selection; |
| | 84 | |
| | 85 | function moveCaret( node ) { |
| | 86 | selection.select( node.nextSibling || node.previousSibling || node.parentNode ); |
| | 87 | selection.collapse( true ); |
| | 88 | editor.nodeChanged(); |
| | 89 | } |
| | 90 | |
| | 91 | function getWrapper( event ) { |
| | 92 | if ( dom.hasClass( event.target, 'wp-control' ) ) { |
| | 93 | return event.target; |
| | 94 | } else { |
| | 95 | return dom.getParent( event.target, 'div.wp-control' ) || dom.getParent( selection.getNode(), 'div.wp-control' ); |
| | 96 | } |
| | 97 | } |
| | 98 | |
| | 99 | editor.on( 'click contextmenu', function( event ) { |
| | 100 | var wrapper = getWrapper( event ); |
| | 101 | |
| | 102 | if ( wrapper ) { |
| | 103 | // Don't follow links in the non-editable wrapper |
| | 104 | if ( dom.is( event.target, 'a' ) || dom.getParent( event.target, 'a' ) ) { |
| | 105 | event.preventDefault(); |
| | 106 | } |
| | 107 | |
| | 108 | if ( tinymce.Env.ie ) { |
| | 109 | // Move the caret out of the wrapper |
| | 110 | moveCaret( wrapper ); |
| | 111 | } |
| | 112 | } |
| | 113 | }); |
| | 114 | |
| | 115 | editor.on( 'mousedown', function( event ) { |
| | 116 | var wrapper = getWrapper( event ); |
| | 117 | |
| | 118 | if ( wrapper ) { |
| | 119 | dom.addClass( wrapper, 'wp-selected' ) |
| | 120 | event.preventDefault(); |
| | 121 | |
| | 122 | if ( tinymce.Env.ie && tinymce.Env.ie < 9 ) { |
| | 123 | // Move the caret out of the wrapper |
| | 124 | setTimeout( function() { |
| | 125 | moveCaret( wrapper ); |
| | 126 | }, 0 ); |
| | 127 | |
| | 128 | |
| | 129 | // Prevent IE < 9 from making the div resizable. |
| | 130 | // Without this the tick border and resize handles show for a moment. |
| | 131 | // oncontrolselect and unselectable="on" don't seem to work here :( |
| | 132 | // throw new Error('(ignore me)'); |
| | 133 | } |
| | 134 | } else { |
| | 135 | dom.removeClass( dom.select( 'div.wp-selected' ), 'wp-selected' ); |
| | 136 | } |
| | 137 | }); |
| | 138 | |
| | 139 | editor.on( 'keydown', function( event ) { |
| | 140 | var element, p, |
| | 141 | key = event.keyCode; |
| | 142 | |
| | 143 | if ( key === tinymce.util.VK.DELETE || key === tinymce.util.VK.BACKSPACE ) { |
| | 144 | element = dom.select( 'div.wp-selected' ); |
| | 145 | |
| | 146 | if ( element.length ) { |
| | 147 | dom.events.cancel( event ); |
| | 148 | dom.remove( element[0] ); |
| | 149 | editor.nodeChanged(); |
| | 150 | } |
| | 151 | } |
| | 152 | }); |
| | 153 | }); |
| | 154 | |
| | 155 | return { |
| | 156 | parseMediaShortcode: parseMediaShortcode, |
| | 157 | getMediaShortcode: getMediaShortcode |
| | 158 | }; |
| | 159 | }); |