[ Index ]

PHP Cross Reference of BuddyPress

title

Body

[close]

/src/bp-activity/js/ -> mentions.js (source)

   1  /* global bp */
   2  
   3  window.bp = window.bp || {};
   4  
   5  ( function( bp, $, undefined ) {
   6      var mentionsQueryCache = [],
   7          mentionsItem;
   8  
   9      bp.mentions       = bp.mentions || {};
  10      bp.mentions.users = window.bp.mentions.users || [];
  11  
  12      if ( typeof window.BP_Suggestions === 'object' ) {
  13          bp.mentions.users = window.BP_Suggestions.friends || bp.mentions.users;
  14      }
  15  
  16      /**
  17       * Adds BuddyPress @mentions to form inputs.
  18       *
  19       * @param {array|object} options If array, becomes the suggestions' data source. If object, passed as config to $.atwho().
  20       * @since 2.1.0
  21       */
  22      $.fn.bp_mentions = function( options ) {
  23          if ( Array.isArray( options ) ) {
  24              options = { data: options };
  25          }
  26  
  27          /**
  28           * Default options for at.js; see https://github.com/ichord/At.js/.
  29           */
  30          var suggestionsDefaults = {
  31              delay:             200,
  32              hideWithoutSuffix: true,
  33              insertTpl:         '@$ID}',
  34              limit:             10,
  35              startWithSpace:    false,
  36              suffix:            '',
  37  
  38              callbacks: {
  39                  /**
  40                   * Custom filter to only match the start of spaced words.
  41                   * Based on the core/default one.
  42                   *
  43                   * @param {string} query
  44                   * @param {array} data
  45                   * @param {string} search_key
  46                   * @return {array}
  47                   * @since 2.1.0
  48                   */
  49                  filter: function( query, data, search_key ) {
  50                      var item, _i, _len, _results = [],
  51                      regxp = new RegExp( '^' + query + '| ' + query, 'ig' ); // start of string, or preceded by a space.
  52  
  53                      for ( _i = 0, _len = data.length; _i < _len; _i++ ) {
  54                          item = data[ _i ];
  55                          if ( item[ search_key ].toLowerCase().match( regxp ) ) {
  56                              _results.push( item );
  57                          }
  58                      }
  59  
  60                      return _results;
  61                  },
  62  
  63                  /**
  64                   * Removes some spaces around highlighted string and tweaks regex to allow spaces
  65                   * (to match display_name). Based on the core default.
  66                   *
  67                   * @param {unknown} li
  68                   * @param {string} query
  69                   * @return {string}
  70                   * @since 2.1.0
  71                   */
  72                  highlighter: function( li, query ) {
  73                      if ( ! query ) {
  74                          return li;
  75                      }
  76  
  77                      var regexp = new RegExp( '>(\\s*|[\\w\\s]*)(' + this.at.replace( '+', '\\+') + '?' + query.replace( '+', '\\+' ) + ')([\\w ]*)\\s*<', 'ig' );
  78                      return li.replace( regexp, function( str, $1, $2, $3 ) {
  79                          return '>' + $1 + '<strong>' + $2 + '</strong>' + $3 + '<';
  80                      });
  81                  },
  82  
  83                  /**
  84                   * Reposition the suggestion list dynamically.
  85                   *
  86                   * @param {unknown} offset
  87                   * @since 2.1.0
  88                   */
  89                  before_reposition: function( offset ) {
  90                      // get the iframe, if any, already applied with atwho.js library.
  91                      var caret,
  92                              line,
  93                              iframeOffset,
  94                              move,
  95                              $view = $( '#atwho-ground-' + this.id + ' .atwho-view' ),
  96                              $body = $( 'body' ),
  97                              atwhoDataValue = this.$inputor.data( 'atwho' );
  98  
  99                      if ( 'undefined' !== atwhoDataValue && 'undefined' !== atwhoDataValue.iframe && null !== atwhoDataValue.iframe ) {
 100                          caret = this.$inputor.caret( 'offset', { iframe: atwhoDataValue.iframe } );
 101                          // Caret.js no longer calculates iframe caret position from the window (it's now just within the iframe).
 102                          // We need to get the iframe offset from the window and merge that into our object.
 103                          iframeOffset = $( atwhoDataValue.iframe ).offset();
 104                          if ( 'undefined' !== iframeOffset ) {
 105                              caret.left += iframeOffset.left;
 106                              caret.top  += iframeOffset.top;
 107                          }
 108                      } else {
 109                          caret = this.$inputor.caret( 'offset' );
 110                      }
 111  
 112                      // If the caret is past horizontal half, then flip it, yo.
 113                      if ( caret.left > ( $body.width() / 2 ) ) {
 114                          $view.addClass( 'right' );
 115                          move = caret.left - offset.left - this.view.$el.width();
 116                      } else {
 117                          $view.removeClass( 'right' );
 118                          move = caret.left - offset.left + 1;
 119                      }
 120  
 121                      // If we're on a small screen, scroll to caret.
 122                      if ( $body.width() <= 400 ) {
 123                          $( document ).scrollTop( caret.top - 6 );
 124                      }
 125  
 126                      // New position is under the caret (never above) and positioned to follow.
 127                      // Dynamic sizing based on the input area (remove 'px' from end).
 128                      line = parseInt( this.$inputor.css( 'line-height' ).substr( 0, this.$inputor.css( 'line-height' ).length - 2 ), 10 );
 129                      if ( !line || line < 5 ) { // Sanity check, and catch no line-height.
 130                          line = 19;
 131                      }
 132  
 133                      offset.top   = caret.top + line;
 134                      offset.left += move;
 135                  },
 136  
 137                  /**
 138                   * Override default behavior which inserts junk tags in the WordPress Visual editor.
 139                   *
 140                   * @param {unknown} $inputor Element which we're inserting content into.
 141                   * @param {string} content The content that will be inserted.
 142                   * @param {string} suffix Applied to the end of the content string.
 143                   * @return {string}
 144                   * @since 2.1.0
 145                   */
 146                  inserting_wrapper: function( $inputor, content, suffix ) {
 147                      return '' + content + suffix;
 148                  }
 149              }
 150          },
 151  
 152          /**
 153           * Default options for our @mentions; see https://github.com/ichord/At.js/.
 154           */
 155          mentionsDefaults = {
 156              callbacks: {
 157                  /**
 158                   * If there are no matches for the query in this.data, then query BuddyPress.
 159                   *
 160                   * @param {string} query Partial @mention to search for.
 161                   * @param {function} render_view Render page callback function.
 162                   * @since 2.1.0
 163                   * @since 3.0.0. Renamed from "remote_filter" for at.js v1.5.4 support.
 164                   */
 165                  remoteFilter: function( query, render_view ) {
 166                      var self = $( this ),
 167                          params = {};
 168  
 169                      mentionsItem = mentionsQueryCache[ query ];
 170                      if ( typeof mentionsItem === 'object' ) {
 171                          render_view( mentionsItem );
 172                          return;
 173                      }
 174  
 175                      if ( self.xhr ) {
 176                          self.xhr.abort();
 177                      }
 178  
 179                      params = { 'action': 'bp_get_suggestions', 'term': query, 'type': 'members' };
 180  
 181                      var groupId = this.$inputor.data( 'suggestions-group-id' );
 182                      if ( ( 'number' === typeof groupId || 'string' === typeof groupId ) && ! isNaN( groupId - parseFloat( groupId ) ) ) {
 183                          params['group-id'] = parseInt( this.$inputor.data( 'suggestions-group-id' ), 10 );
 184                      }
 185  
 186                      self.xhr = $.getJSON( ajaxurl, params )
 187                          /**
 188                           * Success callback for the @suggestions lookup.
 189                           *
 190                           * @param {object} response Details of users matching the query.
 191                           * @since 2.1.0
 192                           */
 193                          .done(function( response ) {
 194                              if ( ! response.success ) {
 195                                  return;
 196                              }
 197  
 198                              var data = $.map( response.data,
 199                                  /**
 200                                   * Create a composite index to determine ordering of results;
 201                                   * nicename matches will appear on top.
 202                                   *
 203                                   * @param {array} suggestion A suggestion's original data.
 204                                   * @return {array} A suggestion's new data.
 205                                   * @since 2.1.0
 206                                   */
 207                                  function( suggestion ) {
 208                                      suggestion.search = suggestion.search || suggestion.ID + ' ' + suggestion.name;
 209                                      return suggestion;
 210                                  }
 211                              );
 212  
 213                              mentionsQueryCache[ query ] = data;
 214                              render_view( data );
 215                          });
 216                  }
 217              },
 218  
 219              data: $.map( options.data,
 220                  /**
 221                   * Create a composite index to search against of nicename + display name.
 222                   * This will also determine ordering of results, so nicename matches will appear on top.
 223                   *
 224                   * @param {array} suggestion A suggestion's original data.
 225                   * @return {array} A suggestion's new data.
 226                   * @since 2.1.0
 227                   */
 228                  function( suggestion ) {
 229                      suggestion.search = suggestion.search || suggestion.ID + ' ' + suggestion.name;
 230                      return suggestion;
 231                  }
 232              ),
 233  
 234              at:         '@',
 235              searchKey:  'search',
 236              displayTpl: '<li data-value="@$ID}"><img src="$image}" alt="" /><span class="username">@$ID}</span><small>$name}</small></li>'
 237          },
 238  
 239          opts = $.extend( true, {}, suggestionsDefaults, mentionsDefaults, options );
 240          return $.fn.atwho.call( this, opts );
 241      };
 242  
 243      $( document ).ready(function() {
 244          // Activity/reply, post comments, dashboard post 'text' editor.
 245          $( '.bp-suggestions, #comments form textarea, .wp-editor-area' ).bp_mentions( bp.mentions.users );
 246      });
 247  
 248      bp.mentions.tinyMCEinit = function() {
 249          if ( typeof window.tinyMCE === 'undefined' || window.tinyMCE.activeEditor === null || typeof window.tinyMCE.activeEditor === 'undefined' ) {
 250              return;
 251          } else {
 252              $( window.tinyMCE.activeEditor.contentDocument.activeElement )
 253                  .atwho( 'setIframe', $( '.wp-editor-wrap iframe' )[0] )
 254                  .bp_mentions( bp.mentions.users );
 255          }
 256      };
 257  })( bp, jQuery );


Generated: Fri Mar 29 01:01:02 2024 Cross-referenced by PHPXref 0.7.1