PageSourceSearch

https://www.o-p-i.fr/aupays/wp-content/plugins/civicrm/civicrm/js/crm.ajax.js?r=Cx6ZOfr_FR

js o-p-i.fr collected 2026-09-24 21:12:16 UTC 24,708 bytes, 664 lines download raw bytes

1// https://civicrm.org/licensing
2/**
3 * @see https://docs.civicrm.org/dev/en/latest/api/interfaces/#ajax
4 * @see https://docs.civicrm.org/dev/en/latest/framework/ajax/
5 */
6(function($, CRM, _, undefined) {
7  /**
8   * @param string path
9   * @param string|object query
10   * @param string mode - optionally specify "front" or "back"
11   */
12  var tplURL;
13  CRM.url = function (path, query, mode) {
14    if (typeof path === 'object') {
15      tplURL = path;
16      return path;
17    }
18    if (!tplURL) {
19      CRM.console('error', 'Error: CRM.url called before initialization');
20    }
21    if (!mode) {
22      mode = CRM.config && CRM.config.isFrontend ? 'front' : 'back';
23    }
24    query = query || '';
25    var url, frag, hash = '';
26    if (path.indexOf('#') > -1) {
27      hash = '#' + path.split('#')[1];
28      path = path.split('#')[0];
29    }
30    frag = path.split('?');
31    // Remove basepage as it can be changed on some CMS eg. WordPress frontend.
32    frag[0] = frag[0].replace('civicrm/', '/');
33    // Encode url path only if slashes in placeholder were also encoded
34    if (tplURL[mode].indexOf('/crmajax-placeholder-url-path') >= 0) {
35      url = tplURL[mode].replace('/crmajax-placeholder-url-path', frag[0]);
36    } else {
37      url = tplURL[mode].replace('%2Fcrmajax-placeholder-url-path', encodeURIComponent(frag[0]));
38    }
39
40    if (_.isEmpty(query)) {
41      url = url.replace(/[?&]civicrm-placeholder-url-query=1/, '');
42    } else {
43      url = url.replace('civicrm-placeholder-url-query=1', typeof query === 'string' ? query : $.param(query));
44    }
45    if (frag[1]) {
46      url += (url.indexOf('?') < 0 ? '?' : '&') + frag[1];
47    }
48    return url + hash;
49  };
50
51  $.fn.crmURL = function () {
52    return this.each(function() {
53      if (this.href) {
54        this.href = CRM.url(this.href);
55      }
56    });
57  };
58
59  // result is an array, but in js, an array is also an object
60  // Assign all the metadata properties to it, mirroring the results arrayObject in php
61  function arrayObject(data) {
62    var result = data.values || [];
63    if (_.isArray(result)) {
64      delete(data.values);
65      _.assign(result, data);
66    }
67    return result;
68  }
69
70  // https://docs.civicrm.org/dev/en/latest/api/interfaces/#ajax
71  CRM.api4 = function(entity, action, params, index) {
72    return new Promise(function(resolve, reject) {
73      if (typeof entity === 'string') {
74        $.post(CRM.url('civicrm/ajax/api4/' + entity + '/' + action), {
75          params: JSON.stringify(params),
76          index: index
77        })
78          .done(function (data) {
79            resolve(arrayObject(data));
80          })
81          .fail(function (data) {
82            reject(data.responseJSON);
83          });
84      } else {
85        $.post(CRM.url('civicrm/ajax/api4'), {
86          calls: JSON.stringify(entity)
87        })
88          .done(function(data) {
89            _.each(data, function(item, key) {
90              data[key] = arrayObject(item);
91            });
92            resolve(data);
93          })
94          .fail(function (data) {
95            reject(data.responseJSON);
96          });
97      }
98    });
99  };
100
101  /**
102   * AJAX api
103   * @link https://docs.civicrm.org/dev/en/latest/api/interfaces/#ajax
104   */
105  CRM.api3 = function(entity, action, params, status) {
106    if (typeof(entity) === 'string') {
107      params = {
108        entity: entity,
109        action: action.toLowerCase(),
110        json: JSON.stringify(params || {})
111      };
112    } else {
113      params = {
114        entity: 'api3',
115        action: 'call',
116        json: JSON.stringify(entity)
117      };
118      status = action;
119    }
120    var ajax = $.ajax({
121      url: CRM.url('civicrm/ajax/rest'),
122      dataType: 'json',
123      data: params,
124      type: params.action.indexOf('get') === 0 ? 'GET' : 'POST'
125    });
126    if (status) {
127      // Default status messages
128      if (status === true) {
129        status = {success: params.action === 'delete' ? ts('Removed') : ts('Saved')};
130        if (params.action.indexOf('get') === 0) {
131          status.start = ts('Loading...');
132          status.success = null;
133        }
134      }
135      var messages = status === true ? {} : status;
136      CRM.status(status, ajax);
137    }
138    return ajax;
139  };
140
141  /**
142   * @deprecated
143   * AJAX api
144   */
145  CRM.api = function(entity, action, params, options) {
146    // Default settings
147    var settings = {
148      context: null,
149      success: function(result, settings) {
150        return true;
151      },
152      error: function(result, settings) {
153        $().crmError(result.error_message, ts('Error'));
154        return false;
155      },
156      callBack: function(result, settings) {
157        if (result.is_error == 1) {
158          return settings.error.call(this, result, settings);
159        }
160        return settings.success.call(this, result, settings);
161      },
162      ajaxURL: 'civicrm/ajax/rest'
163    };
164    action = action.toLowerCase();
165    // Default success handler
166    switch (action) {
167      case "update":
168      case "create":
169      case "setvalue":
170      case "replace":
171        settings.success = function() {
172          CRM.status(ts('Saved'));
173          return true;
174        };
175        break;
176      case "delete":
177        settings.success = function() {
178          CRM.status(ts('Removed'));
179          return true;
180        };
181    }
182    params = {
183      entity: entity,
184      action: action,
185      json: JSON.stringify(params)
186    };
187    // Pass copy of settings into closure to preserve its value during multiple requests
188    (function(stg) {
189      $.ajax({
190        url: stg.ajaxURL.indexOf('http') === 0 ? stg.ajaxURL : CRM.url(stg.ajaxURL),
191        dataType: 'json',
192        data: params,
193        type: action.indexOf('get') < 0 ? 'POST' : 'GET',
194        success: function(result) {
195          stg.callBack.call(stg.context, result, stg);
196        }
197      });
198    })($.extend({}, settings, options));
199  };
200
201  $.widget('civi.crmSnippet', {
202    options: {
203      url: null,
204      block: true,
205      post: null,
206      crmForm: null
207    },
208    _originalContent: null,
209    _originalUrl: null,
210    isOriginalUrl: function() {
211      var
212        args = {},
213        same = true,
214        newUrl = this._formatUrl(this.options.url),
215        oldUrl = this._formatUrl(this._originalUrl);
216      // Compare path
217      if (newUrl.split('?')[0] !== oldUrl.split('?')[0]) {
218        return false;
219      }
220      // Compare arguments
221      $.each((newUrl.split('?')[1] || '').split('&'), function(k, v) {
222        var arg = v.split('=');
223        args[arg[0]] = arg[1];
224      });
225      $.each((oldUrl.split('?')[1] || '').split('&'), function(k, v) {
226        var arg = v.split('=');
227        if (args[arg[0]] !== undefined && arg[1] !== args[arg[0]]) {
228          same = false;
229        }
230      });
231      return same;
232    },
233    resetUrl: function() {
234      this.options.url = this._originalUrl;
235    },
236    _create: function() {
237      this.element.addClass('crm-ajax-container');
238      if (!this.element.is('.crm-container *')) {
239        this.element.addClass('crm-container');
240      }
241      this._handleOrderLinks();
242      // Set default if not supplied
243      this.options.url = this.options.url || document.location.href;
244      this._originalUrl = this.options.url;
245    },
246    _onFailure: function(data, status) {
247      var msg, title = ts('Network Error');
248      if (this.options.block) this.element.unblock();
249      this.element.trigger('crmAjaxFail', data);
250      switch (status) {
251        case 'Forbidden':
252          title = ts('Access Denied');
253          msg = ts('Ensure you are still logged in and have permission to access this feature.');
254          break;
255        default:
256          msg = ts('Unable to reach the server. Please refresh this page in your browser and try again.');
257      }
258      CRM.alert(msg, title, 'error');
259    },
260    _onError: function(data) {
261      this.element.attr('data-unsaved-changes', 'false').trigger('crmAjaxError', data);
262      if (this.options.crmForm && this.options.crmForm.autoClose && this.element.data('uiDialog')) {
263        this.element.dialog('close');
264      }
265    },
266    _formatUrl: function(url, snippetType) {
267      // Strip hash
268      url = url.split('#')[0];
269      // Add snippet argument to url
270      if (snippetType) {
271        if (url.search(/[&?]snippet=/) < 0) {
272          url += (url.indexOf('?') < 0 ? '?' : '&') + 'snippet=' + snippetType;
273        } else {
274          url = url.replace(/([&?])snippet=[^&]*/, '$1snippet=' + snippetType);
275        }
276        // See Civi\Angular\AngularLoader
277        if (snippetType === 'json' && CRM.angular) {
278          url += '&crmAngularModules=' + CRM.angular.modules.join();
279        }
280      }
281      return url;
282    },
283    // Hack to deal with civicrm legacy sort functionality
284    _handleOrderLinks: function() {
285      var that = this;
286      $('a.crm-weight-arrow', that.element).click(function(e) {
287        if (that.options.block) that.element.block();
288        $.getJSON(that._formatUrl(this.href, 'json')).done(function() {
289          that.refresh();
290        });
291        e.stopImmediatePropagation();
292        return false;
293      });
294    },
295    _ajax: function(url) {
296      if (!this.options.post || !this.isOriginalUrl()) {
297        return $.getJSON(url);
298      }
299      return $.post({
300        url: url,
301        dataType: 'json',
302        data: this.options.post
303      });
304    },
305    refresh: function() {
306      var that = this,
307        hash = this.options.url.split('#')[1],
308        url = this._formatUrl(this.options.url, 'json');
309      $(this.element).data('urlHash', hash);
310      if (this.options.crmForm) $('form', this.element).ajaxFormUnbind();
311      if (this.options.block) this.element.block();
312      this._ajax(url).then(function(data) {
313        if (data.status === 'redirect') {
314          that.options.url = data.userContext;
315          return that.refresh();
316        }
317        if (that.options.block) that.element.unblock();
318        if (!$.isPlainObject(data)) {
319          that._onFailure(data);
320          return;
321        }
322        if (data.status === 'error') {
323          that._onError(data);
324          return;
325        }
326        data.url = url;
327        that.element.trigger('crmUnload').trigger('crmBeforeLoad', data);
328        that._beforeRemovingContent();
329        that.element.html(data.content);
330        that._handleOrderLinks();
331        that.element.trigger('crmLoad', data);
332        if (that.options.crmForm) that.element.trigger('crmFormLoad', data);
333        // This is only needed by forms that load via ajax but submit without ajax, e.g. configure contribution page tabs
334        // TODO: remove this when those forms have been converted to use ajax submit
335        if (data.status === 'form_error' && $.isPlainObject(data.errors)) {
336          that.element.trigger('crmFormError', data);
337          $.each(data.errors, function(formElement, msg) {
338            $('[name="'+formElement+'"]', that.element).crmError(msg);
339          });
340        }
341      }, function(data, msg, status) {
342        that._onFailure(data, status);
343      });
344    },
345    // Perform any cleanup needed before removing/replacing content
346    _beforeRemovingContent: function() {
347      var that = this;
348      // Save original content to be restored if widget is destroyed
349      if (this._originalContent === null) {
350        $('.blockUI', this.element).remove();
351        this._originalContent = this.element.contents().detach();
352      }
353      if (this.options.crmForm) $('form', this.element).ajaxFormUnbind();
354    },
355    _destroy: function() {
356      this.element.removeClass('crm-ajax-container').trigger('crmUnload');
357      this._beforeRemovingContent();
358      if (this._originalContent !== null) {
359        this.element.empty().append(this._originalContent);
360      }
361    }
362  });
363
364  var dialogCount = 0,
365    exclude = '[href^="#"], [href^=javascript], [onclick], .no-popup, .cancel';
366
367  CRM.loadPage = function(url, options) {
368    var settings = {
369      target: '#crm-ajax-dialog-' + (dialogCount++),
370      dialog: (options && options.target) ? false : {}
371    };
372    if (options) $.extend(true, settings, options);
373    settings.url = url;
374    // Create new dialog
375    if (settings.dialog) {
376      settings.dialog = CRM.utils.adjustDialogDefaults(settings.dialog);
377      $('<div id="' + settings.target.substring(1) + '"></div>')
378        .dialog(settings.dialog)
379        .parent().find('.ui-dialog-titlebar')
380        .append($('<a class="crm-dialog-titlebar-print ui-dialog-titlebar-close" title="'+ts('Print window')+'" target="_blank" style="right:3.8em;"/>')
381          .button({icons: {primary: 'fa-print'}, text: false}));
382    }
383    // Add handlers to new or existing dialog
384    if ($(settings.target).data('uiDialog')) {
385      $(settings.target)
386        .on('dialogclose', function() {
387          if (settings.dialog && $(this).attr('data-unsaved-changes') !== 'true') {
388            $(this).crmSnippet('destroy').dialog('destroy').remove();
389          }
390        })
391        .on('crmLoad', function(e, data) {
392          // Set title
393          if (e.target === $(settings.target)[0] && data && !settings.dialog.title && data.title) {
394            $(this).dialog('option', 'title', data.title);
395          }
396          // Update print url
397          $(this).parent().find('a.crm-dialog-titlebar-print').attr('href', $(this).data('civiCrmSnippet')._formatUrl($(this).crmSnippet('option', 'url'), '1'));
398        });
399    }
400    $(settings.target).crmSnippet(settings).crmSnippet('refresh');
401    return $(settings.target);
402  };
403  CRM.loadForm = function(url, options) {
404    var formErrors = [], settings = {
405      crmForm: {
406        ajaxForm: {},
407        autoClose: true,
408        validate: true,
409        refreshAction: ['next_new', 'upload_new'],
410        cancelButton: '.cancel',
411        openInline: 'a.open-inline, a.button, a.action-item, a.open-inline-noreturn',
412        onCancel: function(event) {}
413      }
414    };
415    // Move options that belong to crmForm. Others will be passed through to crmSnippet
416    if (options) $.each(options, function(key, value) {
417      if (typeof(settings.crmForm[key]) !== 'undefined') {
418        settings.crmForm[key] = value;
419      }
420      else {
421        settings[key] = value;
422      }
423    });
424
425    var widget = CRM.loadPage(url, settings).off('.crmForm');
426
427    // CRM-14353 - Warn of unsaved changes for all forms except those which have opted out
428    function cancelAction() {
429      var dirty = CRM.utils.initialValueChanged($('form:not([data-warn-changes=false])', widget));
430      widget.attr('data-unsaved-changes', dirty ? 'true' : 'false');
431      if (dirty) {
432        var id = widget.attr('id') + '-unsaved-alert',
433          title = widget.dialog('option', 'title'),
434          alert = CRM.alert('<p>' + ts('%1 has not been saved.', {1: title}) + '</p><p><a href="#" id="' + id + '">' + ts('Restore') + '</a></p>', ts('Unsaved Changes'), 'alert unsaved-dialog', {expires: 60000});
435        $('#' + id).button({icons: {primary: 'fa-undo'}}).click(function(e) {
436          widget.attr('data-unsaved-changes', 'false').dialog('open');
437          e.preventDefault();
438        });
439      }
440    }
441
442    if (widget.data('uiDialog')) widget.on('dialogbeforeclose', function(e) {
443      // CRM-14353 - Warn unsaved changes if user clicks close button or presses "esc"
444      if (e.originalEvent) {
445        cancelAction();
446      }
447    });
448
449    widget.on('crmFormLoad.crmForm', function(event, data) {
450      var $el = $(this).attr('data-unsaved-changes', 'false'),
451        settings = $el.crmSnippet('option', 'crmForm');
452      if (settings.cancelButton) $(settings.cancelButton, this).click(function(e) {
453        e.preventDefault();
454        var returnVal = settings.onCancel.call($el, e);
455        if (returnVal !== false) {
456          $el.trigger('crmFormCancel', e);
457          if ($el.data('uiDialog') && settings.autoClose) {
458            cancelAction();
459            $el.dialog('close');
460          }
461          else if (!settings.autoClose) {
462            $el.crmSnippet('resetUrl').crmSnippet('refresh');
463          }
464        }
465      });
466      if (settings.validate) {
467        // Validate all forms that are not angular-based
468        $("form", this).not('crm-angular-js *').crmValidate();
469      }
470      $("form:not('[data-no-ajax-submit=true]')", this).ajaxForm($.extend({
471        url: data.url.replace(/reset=1[&]?/, ''),
472        dataType: 'json',
473        success: function(response) {
474          if (response.content === undefined) {
475            $el.trigger('crmFormSuccess', response);
476            // Reset form for e.g. "save and new"
477            if (response.userContext && (response.status === 'redirect' || (settings.refreshAction && $.inArray(response.buttonName, settings.refreshAction) >= 0))) {
478              // Force reset of original url
479              $el.data('civiCrmSnippet')._originalUrl = response.userContext;
480              $el.crmSnippet('resetUrl').crmSnippet('refresh');
481            }
482            // Close if we are on the original url or the action was "delete" (in which case returning to view may be inappropriate)
483            else if ($el.data('uiDialog') && (settings.autoClose || response.action === 8)) {
484              $el.dialog('close');
485            }
486            else if (settings.autoClose === false) {
487              $el.crmSnippet('resetUrl').crmSnippet('refresh');
488            }
489          }
490          else {
491            if ($el.crmSnippet('option', 'block')) $el.unblock();
492            response.url = data.url;
493            $el.html(response.content).trigger('crmLoad', response).trigger('crmFormLoad', response);
494            if (response.status === 'form_error') {
495              formErrors = [];
496              $el.trigger('crmFormError', response);
497              $.each(response.errors || [], function(formElement, msg) {
498                formErrors.push($('[name="'+formElement+'"]', $el).crmError(msg));
499              });
500            }
501          }
502        },
503        beforeSubmit: function(submission) {
504          $.each(formErrors, function() {
505            if (this && this.close) this.close();
506          });
507          if ($el.crmSnippet('option', 'block')) $el.block();
508          $el.trigger('crmFormSubmit', submission);
509        }
510      }, settings.ajaxForm));
511      if (settings.openInline) {
512        settings.autoClose = $el.crmSnippet('isOriginalUrl');
513        $(this).off('.openInline').on('click.openInline', settings.openInline, function(e) {
514          if ($(this).is(exclude + ', .crm-popup, [target=crm-popup]')) {
515            return;
516          }
517          if ($(this).hasClass('open-inline-noreturn')) {
518            // Force reset of original url
519            $el.data('civiCrmSnippet')._originalUrl = $(this).attr('href');
520          }
521          $el.crmSnippet('option', 'url', $(this).attr('href')).crmSnippet('refresh');
522          e.preventDefault();
523        });
524      }
525      if ($el.data('uiDialog')) {
526        // Show form buttons as part of the dialog
527        var buttonContainers = '.crm-submit-buttons, .action-link',
528          buttons = [],
529          added = [];
530        $(buttonContainers, $el).find('.crm-form-submit, .crm-form-xbutton, a.button, button').each(function() {
531          var $el = $(this),
532            label = $el.is('input') ? $el.attr('value') : $el.text(),
533            identifier = $el.attr('name') || $el.attr('href');
534          $el.attr('tabindex', '-1');
535          if (!identifier || identifier === '#' || $.inArray(identifier, added) < 0) {
536            var $icon = $el.find('.icon, .crm-i'),
537              button = {'data-identifier': identifier, text: label, click: function() {
538                $el[0].click();
539              }};
540            if ($icon.length) {
541              button.icons = {primary: $icon.attr('class')};
542            } else {
543              var action = $el.attr('crm-icon') || ($el.hasClass('cancel') ? 'fa-times' : 'fa-check');
544              button.icons = {primary: action};
545            }
546            buttons.push(button);
547            added.push(identifier);
548          }
549          // display:none causes the form to not submit when pressing "enter"
550          $el.parents(buttonContainers).css({height: 0, padding: 0, margin: 0, overflow: 'hidden'}).attr('aria-hidden', 'true');
551        });
552        $el.dialog('option', 'buttons', buttons);
553      }
554      // Allow a button to prevent ajax submit
555      $('input[data-no-ajax-submit=true], button[data-no-ajax-submit=true]').click(function() {
556        $(this).closest('form').ajaxFormUnbind();
557      });
558      // For convenience, focus the first field
559      $('input[type=text], textarea, select', this).filter(':visible').first().not('.dateplugin').focus();
560    });
561    return widget;
562  };
563  /**
564   * Handler for jQuery click event e.g. $('a').click(CRM.popup);
565   */
566  CRM.popup = function(e) {
567    var $el = $(this).first(),
568      url = $el.attr('href'),
569      popup = $el.data('popup-type') === 'page' ? CRM.loadPage : CRM.loadForm,
570      settings = $el.data('popup-settings') || {},
571      formData = false;
572    settings.dialog = settings.dialog || {};
573    if (e.isDefaultPrevented() || !CRM.config.ajaxPopupsEnabled || !url || $el.is(exclude + ', .open-inline, .open-inline-noreturn')) {
574      return;
575    }
576    // Sized based on css class
577    if ($el.hasClass('small-popup')) {
578      settings.dialog.width = 400;
579      settings.dialog.height = 300;
580    }
581    else if ($el.hasClass('medium-popup')) {
582      settings.dialog.width = '50%';
583      settings.dialog.height = '30%';
584    }
585    var dialog = popup(url, settings);
586    // Trigger events from the dialog on the original link element
587    $el.trigger('crmPopupOpen', [dialog]);
588    // Listen for success events and buffer them so we only trigger once
589    dialog.on('crmFormSuccess.crmPopup crmPopupFormSuccess.crmPopup', function(e, data) {
590      formData = data;
591    });
592    dialog.on('dialogclose.crmPopup', function(e, data) {
593      if (formData) {
594        $el.trigger('crmPopupFormSuccess', [dialog, formData]);
595      }
596      $el.trigger('crmPopupClose', [dialog, data]);
597    });
598    e.preventDefault();
599  };
600  /**
601   * An event callback for CRM.popup or a standalone function to refresh the content around a given element
602   * @param e {event|selector}
603   */
604  CRM.refreshParent = function(e) {
605    // Use e.target if input smells like an event, otherwise assume it's a jQuery selector
606    var $el = (e.stopPropagation && e.target) ? $(e.target) : $(e),
607      $table = $el.closest('.dataTable');
608    // Call native refresh method on ajax datatables
609    if ($table.length && $.fn.DataTable.fnIsDataTable($table[0]) && $table.dataTable().fnSettings().sAjaxSource) {
610      // Refresh ALL datatables - needed for contact relationship tab
611      $.each($.fn.dataTable.fnTables(), function() {
612        if ($(this).dataTable().fnSettings().sAjaxSource) $(this).unblock().dataTable().fnDraw();
613      });
614    }
615    // Otherwise refresh the nearest crmSnippet
616    else {
617      $el.closest('.crm-ajax-container, #crm-main-content-wrapper').crmSnippet().crmSnippet('refresh');
618    }
619  };
620
621  $(function($) {
622    $('body')
623      .on('click', 'a.crm-popup, a[target=crm-popup]', CRM.popup)
624      // Close unsaved dialog messages
625      .on('dialogopen', function(e) {
626        $('.alert.unsaved-dialog .ui-notify-cross', '#crm-notification-container').click();
627      })
628      // Destroy old unsaved dialog
629      .on('dialogcreate', function(e) {
630        $('.ui-dialog-content.crm-ajax-container:hidden[data-unsaved-changes=true]').crmSnippet('destroy').dialog('destroy').remove();
631      })
632      // Ensure wysiwyg content is updated prior to ajax submit
633      .on('form-pre-serialize', function(e) {
634        $('.crm-wysiwyg-enabled', e.target).each(function() {
635          CRM.wysiwyg.updateElement(this);
636        });
637      })
638      // Auto-resize dialogs when loading content
639      .on('crmLoad dialogopen', 'div.ui-dialog.ui-resizable.crm-container', function(e) {
640        var
641          $wrapper = $(this),
642          $dialog = $wrapper.children('.ui-dialog-content');
643        // small delay to allow contents to render
644        window.setTimeout(function() {
645          var currentHeight = $wrapper.outerHeight(),
646            padding = currentHeight - $dialog.height(),
647            newHeight = $dialog.prop('scrollHeight') + padding,
648            menuHeight = $('#civicrm-menu').outerHeight();
649          if ($('body').hasClass('crm-menubar-below-cms-menu')) {
650            menuHeight += $('#civicrm-menu').offset().top;
651          }
652          var maxHeight = $(window).height() - menuHeight;
653          newHeight = newHeight > maxHeight ? maxHeight : newHeight;
654          if (newHeight > (currentHeight + 15)) {
655            $dialog.dialog('option', {
656              position: {my: 'center', at: 'center center+' + (menuHe
656ight / 2), of: window},
657              height: newHeight
658            });
659          }
660        }, 500);
661      });
662  });
663
664}(jQuery, CRM, _));

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.