[ Index ]

WordPress Cross Reference

title

Body

[close]

/wp-includes/js/ -> mce-view.js (source)

   1  // Ensure the global `wp` object exists.
   2  window.wp = window.wp || {};
   3  
   4  (function($){
   5      var views = {},
   6          instances = {};
   7  
   8      // Create the `wp.mce` object if necessary.
   9      wp.mce = wp.mce || {};
  10  
  11      // wp.mce.view
  12      // -----------
  13      // A set of utilities that simplifies adding custom UI within a TinyMCE editor.
  14      // At its core, it serves as a series of converters, transforming text to a
  15      // custom UI, and back again.
  16      wp.mce.view = {
  17          // ### defaults
  18          defaults: {
  19              // The default properties used for objects with the `pattern` key in
  20              // `wp.mce.view.add()`.
  21              pattern: {
  22                  view: Backbone.View,
  23                  text: function( instance ) {
  24                      return instance.options.original;
  25                  },
  26  
  27                  toView: function( content ) {
  28                      if ( ! this.pattern )
  29                          return;
  30  
  31                      this.pattern.lastIndex = 0;
  32                      var match = this.pattern.exec( content );
  33  
  34                      if ( ! match )
  35                          return;
  36  
  37                      return {
  38                          index:   match.index,
  39                          content: match[0],
  40                          options: {
  41                              original: match[0],
  42                              results:  match
  43                          }
  44                      };
  45                  }
  46              },
  47  
  48              // The default properties used for objects with the `shortcode` key in
  49              // `wp.mce.view.add()`.
  50              shortcode: {
  51                  view: Backbone.View,
  52                  text: function( instance ) {
  53                      return instance.options.shortcode.string();
  54                  },
  55  
  56                  toView: function( content ) {
  57                      var match = wp.shortcode.next( this.shortcode, content );
  58  
  59                      if ( ! match )
  60                          return;
  61  
  62                      return {
  63                          index:   match.index,
  64                          content: match.content,
  65                          options: {
  66                              shortcode: match.shortcode
  67                          }
  68                      };
  69                  }
  70              }
  71          },
  72  
  73          // ### add( id, options )
  74          // Registers a new TinyMCE view.
  75          //
  76          // Accepts a unique `id` and an `options` object.
  77          //
  78          // `options` accepts the following properties:
  79          //
  80          // * `pattern` is the regular expression used to scan the content and
  81          // detect matching views.
  82          //
  83          // * `view` is a `Backbone.View` constructor. If a plain object is
  84          // provided, it will automatically extend the parent constructor
  85          // (usually `Backbone.View`). Views are instantiated when the `pattern`
  86          // is successfully matched. The instance's `options` object is provided
  87          // with the `original` matched value, the match `results` including
  88          // capture groups, and the `viewType`, which is the constructor's `id`.
  89          //
  90          // * `extend` an existing view by passing in its `id`. The current
  91          // view will inherit all properties from the parent view, and if
  92          // `view` is set to a plain object, it will extend the parent `view`
  93          // constructor.
  94          //
  95          // * `text` is a method that accepts an instance of the `view`
  96          // constructor and transforms it into a text representation.
  97          add: function( id, options ) {
  98              var parent, remove, base, properties;
  99  
 100              // Fetch the parent view or the default options.
 101              if ( options.extend )
 102                  parent = wp.mce.view.get( options.extend );
 103              else if ( options.shortcode )
 104                  parent = wp.mce.view.defaults.shortcode;
 105              else
 106                  parent = wp.mce.view.defaults.pattern;
 107  
 108              // Extend the `options` object with the parent's properties.
 109              _.defaults( options, parent );
 110              options.id = id;
 111  
 112              // Create properties used to enhance the view for use in TinyMCE.
 113              properties = {
 114                  // Ensure the wrapper element and references to the view are
 115                  // removed. Otherwise, removed views could randomly restore.
 116                  remove: function() {
 117                      delete instances[ this.el.id ];
 118                      this.$el.parent().remove();
 119  
 120                      // Trigger the inherited `remove` method.
 121                      if ( remove )
 122                          remove.apply( this, arguments );
 123  
 124                      return this;
 125                  }
 126              };
 127  
 128              // If the `view` provided was an object, use the parent's
 129              // `view` constructor as a base. If a `view` constructor
 130              // was provided, treat that as the base.
 131              if ( _.isFunction( options.view ) ) {
 132                  base = options.view;
 133              } else {
 134                  base   = parent.view;
 135                  remove = options.view.remove;
 136                  _.defaults( properties, options.view );
 137              }
 138  
 139              // If there's a `remove` method on the `base` view that wasn't
 140              // created by this method, inherit it.
 141              if ( ! remove && ! base._mceview )
 142                  remove = base.prototype.remove;
 143  
 144              // Automatically create the new `Backbone.View` constructor.
 145              options.view = base.extend( properties, {
 146                  // Flag that the new view has been created by `wp.mce.view`.
 147                  _mceview: true
 148              });
 149  
 150              views[ id ] = options;
 151          },
 152  
 153          // ### get( id )
 154          // Returns a TinyMCE view options object.
 155          get: function( id ) {
 156              return views[ id ];
 157          },
 158  
 159          // ### remove( id )
 160          // Unregisters a TinyMCE view.
 161          remove: function( id ) {
 162              delete views[ id ];
 163          },
 164  
 165          // ### toViews( content )
 166          // Scans a `content` string for each view's pattern, replacing any
 167          // matches with wrapper elements, and creates a new view instance for
 168          // every match.
 169          //
 170          // To render the views, call `wp.mce.view.render( scope )`.
 171          toViews: function( content ) {
 172              var pieces = [ { content: content } ],
 173                  current;
 174  
 175              _.each( views, function( view, viewType ) {
 176                  current = pieces.slice();
 177                  pieces  = [];
 178  
 179                  _.each( current, function( piece ) {
 180                      var remaining = piece.content,
 181                          result;
 182  
 183                      // Ignore processed pieces, but retain their location.
 184                      if ( piece.processed ) {
 185                          pieces.push( piece );
 186                          return;
 187                      }
 188  
 189                      // Iterate through the string progressively matching views
 190                      // and slicing the string as we go.
 191                      while ( remaining && (result = view.toView( remaining )) ) {
 192                          // Any text before the match becomes an unprocessed piece.
 193                          if ( result.index )
 194                              pieces.push({ content: remaining.substring( 0, result.index ) });
 195  
 196                          // Add the processed piece for the match.
 197                          pieces.push({
 198                              content:   wp.mce.view.toView( viewType, result.options ),
 199                              processed: true
 200                          });
 201  
 202                          // Update the remaining content.
 203                          remaining = remaining.slice( result.index + result.content.length );
 204                      }
 205  
 206                      // There are no additional matches. If any content remains,
 207                      // add it as an unprocessed piece.
 208                      if ( remaining )
 209                          pieces.push({ content: remaining });
 210                  });
 211              });
 212  
 213              return _.pluck( pieces, 'content' ).join('');
 214          },
 215  
 216          toView: function( viewType, options ) {
 217              var view = wp.mce.view.get( viewType ),
 218                  instance, id;
 219  
 220              if ( ! view )
 221                  return '';
 222  
 223              // Create a new view instance.
 224              instance = new view.view( _.extend( options || {}, {
 225                  viewType: viewType
 226              }) );
 227  
 228              // Use the view's `id` if it already exists. Otherwise,
 229              // create a new `id`.
 230              id = instance.el.id = instance.el.id || _.uniqueId('__wpmce-');
 231              instances[ id ] = instance;
 232  
 233              // Create a dummy `$wrapper` property to allow `$wrapper` to be
 234              // called in the view's `render` method without a conditional.
 235              instance.$wrapper = $();
 236  
 237              return wp.html.string({
 238                  // If the view is a span, wrap it in a span.
 239                  tag: 'span' === instance.tagName ? 'span' : 'div',
 240  
 241                  attrs: {
 242                      'class':           'wp-view-wrap wp-view-type-' + viewType,
 243                      'data-wp-view':    id,
 244                      'contenteditable': false
 245                  }
 246              });
 247          },
 248  
 249          // ### render( scope )
 250          // Renders any view instances inside a DOM node `scope`.
 251          //
 252          // View instances are detected by the presence of wrapper elements.
 253          // To generate wrapper elements, pass your content through
 254          // `wp.mce.view.toViews( content )`.
 255          render: function( scope ) {
 256              $( '.wp-view-wrap', scope ).each( function() {
 257                  var wrapper = $(this),
 258                      view = wp.mce.view.instance( this );
 259  
 260                  if ( ! view )
 261                      return;
 262  
 263                  // Link the real wrapper to the view.
 264                  view.$wrapper = wrapper;
 265                  // Render the view.
 266                  view.render();
 267                  // Detach the view element to ensure events are not unbound.
 268                  view.$el.detach();
 269  
 270                  // Empty the wrapper, attach the view element to the wrapper,
 271                  // and add an ending marker to the wrapper to help regexes
 272                  // scan the HTML string.
 273                  wrapper.empty().append( view.el ).append('<span data-wp-view-end class="wp-view-end"></span>');
 274              });
 275          },
 276  
 277          // ### toText( content )
 278          // Scans an HTML `content` string and replaces any view instances with
 279          // their respective text representations.
 280          toText: function( content ) {
 281              return content.replace( /<(?:div|span)[^>]+data-wp-view="([^"]+)"[^>]*>.*?<span[^>]+data-wp-view-end[^>]*><\/span><\/(?:div|span)>/g, function( match, id ) {
 282                  var instance = instances[ id ],
 283                      view;
 284  
 285                  if ( instance )
 286                      view = wp.mce.view.get( instance.options.viewType );
 287  
 288                  return instance && view ? view.text( instance ) : '';
 289              });
 290          },
 291  
 292          // ### Remove internal TinyMCE attributes.
 293          removeInternalAttrs: function( attrs ) {
 294              var result = {};
 295              _.each( attrs, function( value, attr ) {
 296                  if ( -1 === attr.indexOf('data-mce') )
 297                      result[ attr ] = value;
 298              });
 299              return result;
 300          },
 301  
 302          // ### Parse an attribute string and removes internal TinyMCE attributes.
 303          attrs: function( content ) {
 304              return wp.mce.view.removeInternalAttrs( wp.html.attrs( content ) );
 305          },
 306  
 307          // ### instance( scope )
 308          //
 309          // Accepts a MCE view wrapper `node` (i.e. a node with the
 310          // `wp-view-wrap` class).
 311          instance: function( node ) {
 312              var id = $( node ).data('wp-view');
 313  
 314              if ( id )
 315                  return instances[ id ];
 316          },
 317  
 318          // ### Select a view.
 319          //
 320          // Accepts a MCE view wrapper `node` (i.e. a node with the
 321          // `wp-view-wrap` class).
 322          select: function( node ) {
 323              var $node = $(node);
 324  
 325              // Bail if node is already selected.
 326              if ( $node.hasClass('selected') )
 327                  return;
 328  
 329              $node.addClass('selected');
 330              $( node.firstChild ).trigger('select');
 331          },
 332  
 333          // ### Deselect a view.
 334          //
 335          // Accepts a MCE view wrapper `node` (i.e. a node with the
 336          // `wp-view-wrap` class).
 337          deselect: function( node ) {
 338              var $node = $(node);
 339  
 340              // Bail if node is already selected.
 341              if ( ! $node.hasClass('selected') )
 342                  return;
 343  
 344              $node.removeClass('selected');
 345              $( node.firstChild ).trigger('deselect');
 346          }
 347      };
 348  
 349  }(jQuery));


Generated: Tue Mar 25 01:41:18 2014 WordPress honlapkészítés: online1.hu