[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/media/vendor/codemirror/addon/hint/ -> show-hint.js (source)

   1  // CodeMirror, copyright (c) by Marijn Haverbeke and others
   2  // Distributed under an MIT license: https://codemirror.net/5/LICENSE
   3  
   4  // declare global: DOMRect
   5  
   6  (function(mod) {
   7    if (typeof exports == "object" && typeof module == "object") // CommonJS
   8      mod(require("../../lib/codemirror"));
   9    else if (typeof define == "function" && define.amd) // AMD
  10      define(["../../lib/codemirror"], mod);
  11    else // Plain browser env
  12      mod(CodeMirror);
  13  })(function(CodeMirror) {
  14    "use strict";
  15  
  16    var HINT_ELEMENT_CLASS        = "CodeMirror-hint";
  17    var ACTIVE_HINT_ELEMENT_CLASS = "CodeMirror-hint-active";
  18  
  19    // This is the old interface, kept around for now to stay
  20    // backwards-compatible.
  21    CodeMirror.showHint = function(cm, getHints, options) {
  22      if (!getHints) return cm.showHint(options);
  23      if (options && options.async) getHints.async = true;
  24      var newOpts = {hint: getHints};
  25      if (options) for (var prop in options) newOpts[prop] = options[prop];
  26      return cm.showHint(newOpts);
  27    };
  28  
  29    CodeMirror.defineExtension("showHint", function(options) {
  30      options = parseOptions(this, this.getCursor("start"), options);
  31      var selections = this.listSelections()
  32      if (selections.length > 1) return;
  33      // By default, don't allow completion when something is selected.
  34      // A hint function can have a `supportsSelection` property to
  35      // indicate that it can handle selections.
  36      if (this.somethingSelected()) {
  37        if (!options.hint.supportsSelection) return;
  38        // Don't try with cross-line selections
  39        for (var i = 0; i < selections.length; i++)
  40          if (selections[i].head.line != selections[i].anchor.line) return;
  41      }
  42  
  43      if (this.state.completionActive) this.state.completionActive.close();
  44      var completion = this.state.completionActive = new Completion(this, options);
  45      if (!completion.options.hint) return;
  46  
  47      CodeMirror.signal(this, "startCompletion", this);
  48      completion.update(true);
  49    });
  50  
  51    CodeMirror.defineExtension("closeHint", function() {
  52      if (this.state.completionActive) this.state.completionActive.close()
  53    })
  54  
  55    function Completion(cm, options) {
  56      this.cm = cm;
  57      this.options = options;
  58      this.widget = null;
  59      this.debounce = 0;
  60      this.tick = 0;
  61      this.startPos = this.cm.getCursor("start");
  62      this.startLen = this.cm.getLine(this.startPos.line).length - this.cm.getSelection().length;
  63  
  64      if (this.options.updateOnCursorActivity) {
  65        var self = this;
  66        cm.on("cursorActivity", this.activityFunc = function() { self.cursorActivity(); });
  67      }
  68    }
  69  
  70    var requestAnimationFrame = window.requestAnimationFrame || function(fn) {
  71      return setTimeout(fn, 1000/60);
  72    };
  73    var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout;
  74  
  75    Completion.prototype = {
  76      close: function() {
  77        if (!this.active()) return;
  78        this.cm.state.completionActive = null;
  79        this.tick = null;
  80        if (this.options.updateOnCursorActivity) {
  81          this.cm.off("cursorActivity", this.activityFunc);
  82        }
  83  
  84        if (this.widget && this.data) CodeMirror.signal(this.data, "close");
  85        if (this.widget) this.widget.close();
  86        CodeMirror.signal(this.cm, "endCompletion", this.cm);
  87      },
  88  
  89      active: function() {
  90        return this.cm.state.completionActive == this;
  91      },
  92  
  93      pick: function(data, i) {
  94        var completion = data.list[i], self = this;
  95        this.cm.operation(function() {
  96          if (completion.hint)
  97            completion.hint(self.cm, data, completion);
  98          else
  99            self.cm.replaceRange(getText(completion), completion.from || data.from,
 100                                 completion.to || data.to, "complete");
 101          CodeMirror.signal(data, "pick", completion);
 102          self.cm.scrollIntoView();
 103        });
 104        if (this.options.closeOnPick) {
 105          this.close();
 106        }
 107      },
 108  
 109      cursorActivity: function() {
 110        if (this.debounce) {
 111          cancelAnimationFrame(this.debounce);
 112          this.debounce = 0;
 113        }
 114  
 115        var identStart = this.startPos;
 116        if(this.data) {
 117          identStart = this.data.from;
 118        }
 119  
 120        var pos = this.cm.getCursor(), line = this.cm.getLine(pos.line);
 121        if (pos.line != this.startPos.line || line.length - pos.ch != this.startLen - this.startPos.ch ||
 122            pos.ch < identStart.ch || this.cm.somethingSelected() ||
 123            (!pos.ch || this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) {
 124          this.close();
 125        } else {
 126          var self = this;
 127          this.debounce = requestAnimationFrame(function() {self.update();});
 128          if (this.widget) this.widget.disable();
 129        }
 130      },
 131  
 132      update: function(first) {
 133        if (this.tick == null) return
 134        var self = this, myTick = ++this.tick
 135        fetchHints(this.options.hint, this.cm, this.options, function(data) {
 136          if (self.tick == myTick) self.finishUpdate(data, first)
 137        })
 138      },
 139  
 140      finishUpdate: function(data, first) {
 141        if (this.data) CodeMirror.signal(this.data, "update");
 142  
 143        var picked = (this.widget && this.widget.picked) || (first && this.options.completeSingle);
 144        if (this.widget) this.widget.close();
 145  
 146        this.data = data;
 147  
 148        if (data && data.list.length) {
 149          if (picked && data.list.length == 1) {
 150            this.pick(data, 0);
 151          } else {
 152            this.widget = new Widget(this, data);
 153            CodeMirror.signal(data, "shown");
 154          }
 155        }
 156      }
 157    };
 158  
 159    function parseOptions(cm, pos, options) {
 160      var editor = cm.options.hintOptions;
 161      var out = {};
 162      for (var prop in defaultOptions) out[prop] = defaultOptions[prop];
 163      if (editor) for (var prop in editor)
 164        if (editor[prop] !== undefined) out[prop] = editor[prop];
 165      if (options) for (var prop in options)
 166        if (options[prop] !== undefined) out[prop] = options[prop];
 167      if (out.hint.resolve) out.hint = out.hint.resolve(cm, pos)
 168      return out;
 169    }
 170  
 171    function getText(completion) {
 172      if (typeof completion == "string") return completion;
 173      else return completion.text;
 174    }
 175  
 176    function buildKeyMap(completion, handle) {
 177      var baseMap = {
 178        Up: function() {handle.moveFocus(-1);},
 179        Down: function() {handle.moveFocus(1);},
 180        PageUp: function() {handle.moveFocus(-handle.menuSize() + 1, true);},
 181        PageDown: function() {handle.moveFocus(handle.menuSize() - 1, true);},
 182        Home: function() {handle.setFocus(0);},
 183        End: function() {handle.setFocus(handle.length - 1);},
 184        Enter: handle.pick,
 185        Tab: handle.pick,
 186        Esc: handle.close
 187      };
 188  
 189      var mac = /Mac/.test(navigator.platform);
 190  
 191      if (mac) {
 192        baseMap["Ctrl-P"] = function() {handle.moveFocus(-1);};
 193        baseMap["Ctrl-N"] = function() {handle.moveFocus(1);};
 194      }
 195  
 196      var custom = completion.options.customKeys;
 197      var ourMap = custom ? {} : baseMap;
 198      function addBinding(key, val) {
 199        var bound;
 200        if (typeof val != "string")
 201          bound = function(cm) { return val(cm, handle); };
 202        // This mechanism is deprecated
 203        else if (baseMap.hasOwnProperty(val))
 204          bound = baseMap[val];
 205        else
 206          bound = val;
 207        ourMap[key] = bound;
 208      }
 209      if (custom)
 210        for (var key in custom) if (custom.hasOwnProperty(key))
 211          addBinding(key, custom[key]);
 212      var extra = completion.options.extraKeys;
 213      if (extra)
 214        for (var key in extra) if (extra.hasOwnProperty(key))
 215          addBinding(key, extra[key]);
 216      return ourMap;
 217    }
 218  
 219    function getHintElement(hintsElement, el) {
 220      while (el && el != hintsElement) {
 221        if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el;
 222        el = el.parentNode;
 223      }
 224    }
 225  
 226    function Widget(completion, data) {
 227      this.id = "cm-complete-" + Math.floor(Math.random(1e6))
 228      this.completion = completion;
 229      this.data = data;
 230      this.picked = false;
 231      var widget = this, cm = completion.cm;
 232      var ownerDocument = cm.getInputField().ownerDocument;
 233      var parentWindow = ownerDocument.defaultView || ownerDocument.parentWindow;
 234  
 235      var hints = this.hints = ownerDocument.createElement("ul");
 236      hints.setAttribute("role", "listbox")
 237      hints.setAttribute("aria-expanded", "true")
 238      hints.id = this.id
 239      var theme = completion.cm.options.theme;
 240      hints.className = "CodeMirror-hints " + theme;
 241      this.selectedHint = data.selectedHint || 0;
 242  
 243      var completions = data.list;
 244      for (var i = 0; i < completions.length; ++i) {
 245        var elt = hints.appendChild(ownerDocument.createElement("li")), cur = completions[i];
 246        var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS);
 247        if (cur.className != null) className = cur.className + " " + className;
 248        elt.className = className;
 249        if (i == this.selectedHint) elt.setAttribute("aria-selected", "true")
 250        elt.id = this.id + "-" + i
 251        elt.setAttribute("role", "option")
 252        if (cur.render) cur.render(elt, data, cur);
 253        else elt.appendChild(ownerDocument.createTextNode(cur.displayText || getText(cur)));
 254        elt.hintId = i;
 255      }
 256  
 257      var container = completion.options.container || ownerDocument.body;
 258      var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null);
 259      var left = pos.left, top = pos.bottom, below = true;
 260      var offsetLeft = 0, offsetTop = 0;
 261      if (container !== ownerDocument.body) {
 262        // We offset the cursor position because left and top are relative to the offsetParent's top left corner.
 263        var isContainerPositioned = ['absolute', 'relative', 'fixed'].indexOf(parentWindow.getComputedStyle(container).position) !== -1;
 264        var offsetParent = isContainerPositioned ? container : container.offsetParent;
 265        var offsetParentPosition = offsetParent.getBoundingClientRect();
 266        var bodyPosition = ownerDocument.body.getBoundingClientRect();
 267        offsetLeft = (offsetParentPosition.left - bodyPosition.left - offsetParent.scrollLeft);
 268        offsetTop = (offsetParentPosition.top - bodyPosition.top - offsetParent.scrollTop);
 269      }
 270      hints.style.left = (left - offsetLeft) + "px";
 271      hints.style.top = (top - offsetTop) + "px";
 272  
 273      // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor.
 274      var winW = parentWindow.innerWidth || Math.max(ownerDocument.body.offsetWidth, ownerDocument.documentElement.offsetWidth);
 275      var winH = parentWindow.innerHeight || Math.max(ownerDocument.body.offsetHeight, ownerDocument.documentElement.offsetHeight);
 276      container.appendChild(hints);
 277      cm.getInputField().setAttribute("aria-autocomplete", "list")
 278      cm.getInputField().setAttribute("aria-owns", this.id)
 279      cm.getInputField().setAttribute("aria-activedescendant", this.id + "-" + this.selectedHint)
 280  
 281      var box = completion.options.moveOnOverlap ? hints.getBoundingClientRect() : new DOMRect();
 282      var scrolls = completion.options.paddingForScrollbar ? hints.scrollHeight > hints.clientHeight + 1 : false;
 283  
 284      // Compute in the timeout to avoid reflow on init
 285      var startScroll;
 286      setTimeout(function() { startScroll = cm.getScrollInfo(); });
 287  
 288      var overlapY = box.bottom - winH;
 289      if (overlapY > 0) {
 290        var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top);
 291        if (curTop - height > 0) { // Fits above cursor
 292          hints.style.top = (top = pos.top - height - offsetTop) + "px";
 293          below = false;
 294        } else if (height > winH) {
 295          hints.style.height = (winH - 5) + "px";
 296          hints.style.top = (top = pos.bottom - box.top - offsetTop) + "px";
 297          var cursor = cm.getCursor();
 298          if (data.from.ch != cursor.ch) {
 299            pos = cm.cursorCoords(cursor);
 300            hints.style.left = (left = pos.left - offsetLeft) + "px";
 301            box = hints.getBoundingClientRect();
 302          }
 303        }
 304      }
 305      var overlapX = box.right - winW;
 306      if (scrolls) overlapX += cm.display.nativeBarWidth;
 307      if (overlapX > 0) {
 308        if (box.right - box.left > winW) {
 309          hints.style.width = (winW - 5) + "px";
 310          overlapX -= (box.right - box.left) - winW;
 311        }
 312        hints.style.left = (left = Math.max(pos.left - overlapX - offsetLeft, 0)) + "px";
 313      }
 314      if (scrolls) for (var node = hints.firstChild; node; node = node.nextSibling)
 315        node.style.paddingRight = cm.display.nativeBarWidth + "px"
 316  
 317      cm.addKeyMap(this.keyMap = buildKeyMap(completion, {
 318        moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); },
 319        setFocus: function(n) { widget.changeActive(n); },
 320        menuSize: function() { return widget.screenAmount(); },
 321        length: completions.length,
 322        close: function() { completion.close(); },
 323        pick: function() { widget.pick(); },
 324        data: data
 325      }));
 326  
 327      if (completion.options.closeOnUnfocus) {
 328        var closingOnBlur;
 329        cm.on("blur", this.onBlur = function() { closingOnBlur = setTimeout(function() { completion.close(); }, 100); });
 330        cm.on("focus", this.onFocus = function() { clearTimeout(closingOnBlur); });
 331      }
 332  
 333      cm.on("scroll", this.onScroll = function() {
 334        var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect();
 335        if (!startScroll) startScroll = cm.getScrollInfo();
 336        var newTop = top + startScroll.top - curScroll.top;
 337        var point = newTop - (parentWindow.pageYOffset || (ownerDocument.documentElement || ownerDocument.body).scrollTop);
 338        if (!below) point += hints.offsetHeight;
 339        if (point <= editor.top || point >= editor.bottom) return completion.close();
 340        hints.style.top = newTop + "px";
 341        hints.style.left = (left + startScroll.left - curScroll.left) + "px";
 342      });
 343  
 344      CodeMirror.on(hints, "dblclick", function(e) {
 345        var t = getHintElement(hints, e.target || e.srcElement);
 346        if (t && t.hintId != null) {widget.changeActive(t.hintId); widget.pick();}
 347      });
 348  
 349      CodeMirror.on(hints, "click", function(e) {
 350        var t = getHintElement(hints, e.target || e.srcElement);
 351        if (t && t.hintId != null) {
 352          widget.changeActive(t.hintId);
 353          if (completion.options.completeOnSingleClick) widget.pick();
 354        }
 355      });
 356  
 357      CodeMirror.on(hints, "mousedown", function() {
 358        setTimeout(function(){cm.focus();}, 20);
 359      });
 360  
 361      // The first hint doesn't need to be scrolled to on init
 362      var selectedHintRange = this.getSelectedHintRange();
 363      if (selectedHintRange.from !== 0 || selectedHintRange.to !== 0) {
 364        this.scrollToActive();
 365      }
 366  
 367      CodeMirror.signal(data, "select", completions[this.selectedHint], hints.childNodes[this.selectedHint]);
 368      return true;
 369    }
 370  
 371    Widget.prototype = {
 372      close: function() {
 373        if (this.completion.widget != this) return;
 374        this.completion.widget = null;
 375        if (this.hints.parentNode) this.hints.parentNode.removeChild(this.hints);
 376        this.completion.cm.removeKeyMap(this.keyMap);
 377        var input = this.completion.cm.getInputField()
 378        input.removeAttribute("aria-activedescendant")
 379        input.removeAttribute("aria-owns")
 380  
 381        var cm = this.completion.cm;
 382        if (this.completion.options.closeOnUnfocus) {
 383          cm.off("blur", this.onBlur);
 384          cm.off("focus", this.onFocus);
 385        }
 386        cm.off("scroll", this.onScroll);
 387      },
 388  
 389      disable: function() {
 390        this.completion.cm.removeKeyMap(this.keyMap);
 391        var widget = this;
 392        this.keyMap = {Enter: function() { widget.picked = true; }};
 393        this.completion.cm.addKeyMap(this.keyMap);
 394      },
 395  
 396      pick: function() {
 397        this.completion.pick(this.data, this.selectedHint);
 398      },
 399  
 400      changeActive: function(i, avoidWrap) {
 401        if (i >= this.data.list.length)
 402          i = avoidWrap ? this.data.list.length - 1 : 0;
 403        else if (i < 0)
 404          i = avoidWrap ? 0  : this.data.list.length - 1;
 405        if (this.selectedHint == i) return;
 406        var node = this.hints.childNodes[this.selectedHint];
 407        if (node) {
 408          node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, "");
 409          node.removeAttribute("aria-selected")
 410        }
 411        node = this.hints.childNodes[this.selectedHint = i];
 412        node.className += " " + ACTIVE_HINT_ELEMENT_CLASS;
 413        node.setAttribute("aria-selected", "true")
 414        this.completion.cm.getInputField().setAttribute("aria-activedescendant", node.id)
 415        this.scrollToActive()
 416        CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node);
 417      },
 418  
 419      scrollToActive: function() {
 420        var selectedHintRange = this.getSelectedHintRange();
 421        var node1 = this.hints.childNodes[selectedHintRange.from];
 422        var node2 = this.hints.childNodes[selectedHintRange.to];
 423        var firstNode = this.hints.firstChild;
 424        if (node1.offsetTop < this.hints.scrollTop)
 425          this.hints.scrollTop = node1.offsetTop - firstNode.offsetTop;
 426        else if (node2.offsetTop + node2.offsetHeight > this.hints.scrollTop + this.hints.clientHeight)
 427          this.hints.scrollTop = node2.offsetTop + node2.offsetHeight - this.hints.clientHeight + firstNode.offsetTop;
 428      },
 429  
 430      screenAmount: function() {
 431        return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1;
 432      },
 433  
 434      getSelectedHintRange: function() {
 435        var margin = this.completion.options.scrollMargin || 0;
 436        return {
 437          from: Math.max(0, this.selectedHint - margin),
 438          to: Math.min(this.data.list.length - 1, this.selectedHint + margin),
 439        };
 440      }
 441    };
 442  
 443    function applicableHelpers(cm, helpers) {
 444      if (!cm.somethingSelected()) return helpers
 445      var result = []
 446      for (var i = 0; i < helpers.length; i++)
 447        if (helpers[i].supportsSelection) result.push(helpers[i])
 448      return result
 449    }
 450  
 451    function fetchHints(hint, cm, options, callback) {
 452      if (hint.async) {
 453        hint(cm, callback, options)
 454      } else {
 455        var result = hint(cm, options)
 456        if (result && result.then) result.then(callback)
 457        else callback(result)
 458      }
 459    }
 460  
 461    function resolveAutoHints(cm, pos) {
 462      var helpers = cm.getHelpers(pos, "hint"), words
 463      if (helpers.length) {
 464        var resolved = function(cm, callback, options) {
 465          var app = applicableHelpers(cm, helpers);
 466          function run(i) {
 467            if (i == app.length) return callback(null)
 468            fetchHints(app[i], cm, options, function(result) {
 469              if (result && result.list.length > 0) callback(result)
 470              else run(i + 1)
 471            })
 472          }
 473          run(0)
 474        }
 475        resolved.async = true
 476        resolved.supportsSelection = true
 477        return resolved
 478      } else if (words = cm.getHelper(cm.getCursor(), "hintWords")) {
 479        return function(cm) { return CodeMirror.hint.fromList(cm, {words: words}) }
 480      } else if (CodeMirror.hint.anyword) {
 481        return function(cm, options) { return CodeMirror.hint.anyword(cm, options) }
 482      } else {
 483        return function() {}
 484      }
 485    }
 486  
 487    CodeMirror.registerHelper("hint", "auto", {
 488      resolve: resolveAutoHints
 489    });
 490  
 491    CodeMirror.registerHelper("hint", "fromList", function(cm, options) {
 492      var cur = cm.getCursor(), token = cm.getTokenAt(cur)
 493      var term, from = CodeMirror.Pos(cur.line, token.start), to = cur
 494      if (token.start < cur.ch && /\w/.test(token.string.charAt(cur.ch - token.start - 1))) {
 495        term = token.string.substr(0, cur.ch - token.start)
 496      } else {
 497        term = ""
 498        from = cur
 499      }
 500      var found = [];
 501      for (var i = 0; i < options.words.length; i++) {
 502        var word = options.words[i];
 503        if (word.slice(0, term.length) == term)
 504          found.push(word);
 505      }
 506  
 507      if (found.length) return {list: found, from: from, to: to};
 508    });
 509  
 510    CodeMirror.commands.autocomplete = CodeMirror.showHint;
 511  
 512    var defaultOptions = {
 513      hint: CodeMirror.hint.auto,
 514      completeSingle: true,
 515      alignWithWord: true,
 516      closeCharacters: /[\s()\[\]{};:>,]/,
 517      closeOnPick: true,
 518      closeOnUnfocus: true,
 519      updateOnCursorActivity: true,
 520      completeOnSingleClick: true,
 521      container: null,
 522      customKeys: null,
 523      extraKeys: null,
 524      paddingForScrollbar: true,
 525      moveOnOverlap: true,
 526    };
 527  
 528    CodeMirror.defineOption("hintOptions", null);
 529  });


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer