[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

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

   1  // CodeMirror, copyright (c) by Marijn Haverbeke and others
   2  // Distributed under an MIT license: https://codemirror.net/5/LICENSE
   3  
   4  // Glue code between CodeMirror and Tern.
   5  //
   6  // Create a CodeMirror.TernServer to wrap an actual Tern server,
   7  // register open documents (CodeMirror.Doc instances) with it, and
   8  // call its methods to activate the assisting functions that Tern
   9  // provides.
  10  //
  11  // Options supported (all optional):
  12  // * defs: An array of JSON definition data structures.
  13  // * plugins: An object mapping plugin names to configuration
  14  //   options.
  15  // * getFile: A function(name, c) that can be used to access files in
  16  //   the project that haven't been loaded yet. Simply do c(null) to
  17  //   indicate that a file is not available.
  18  // * fileFilter: A function(value, docName, doc) that will be applied
  19  //   to documents before passing them on to Tern.
  20  // * switchToDoc: A function(name, doc) that should, when providing a
  21  //   multi-file view, switch the view or focus to the named file.
  22  // * showError: A function(editor, message) that can be used to
  23  //   override the way errors are displayed.
  24  // * completionTip: Customize the content in tooltips for completions.
  25  //   Is passed a single argument—the completion's data as returned by
  26  //   Tern—and may return a string, DOM node, or null to indicate that
  27  //   no tip should be shown. By default the docstring is shown.
  28  // * typeTip: Like completionTip, but for the tooltips shown for type
  29  //   queries.
  30  // * responseFilter: A function(doc, query, request, error, data) that
  31  //   will be applied to the Tern responses before treating them
  32  //
  33  //
  34  // It is possible to run the Tern server in a web worker by specifying
  35  // these additional options:
  36  // * useWorker: Set to true to enable web worker mode. You'll probably
  37  //   want to feature detect the actual value you use here, for example
  38  //   !!window.Worker.
  39  // * workerScript: The main script of the worker. Point this to
  40  //   wherever you are hosting worker.js from this directory.
  41  // * workerDeps: An array of paths pointing (relative to workerScript)
  42  //   to the Acorn and Tern libraries and any Tern plugins you want to
  43  //   load. Or, if you minified those into a single script and included
  44  //   them in the workerScript, simply leave this undefined.
  45  
  46  (function(mod) {
  47    if (typeof exports == "object" && typeof module == "object") // CommonJS
  48      mod(require("../../lib/codemirror"));
  49    else if (typeof define == "function" && define.amd) // AMD
  50      define(["../../lib/codemirror"], mod);
  51    else // Plain browser env
  52      mod(CodeMirror);
  53  })(function(CodeMirror) {
  54    "use strict";
  55    // declare global: tern
  56  
  57    CodeMirror.TernServer = function(options) {
  58      var self = this;
  59      this.options = options || {};
  60      var plugins = this.options.plugins || (this.options.plugins = {});
  61      if (!plugins.doc_comment) plugins.doc_comment = true;
  62      this.docs = Object.create(null);
  63      if (this.options.useWorker) {
  64        this.server = new WorkerServer(this);
  65      } else {
  66        this.server = new tern.Server({
  67          getFile: function(name, c) { return getFile(self, name, c); },
  68          async: true,
  69          defs: this.options.defs || [],
  70          plugins: plugins
  71        });
  72      }
  73      this.trackChange = function(doc, change) { trackChange(self, doc, change); };
  74  
  75      this.cachedArgHints = null;
  76      this.activeArgHints = null;
  77      this.jumpStack = [];
  78  
  79      this.getHint = function(cm, c) { return hint(self, cm, c); };
  80      this.getHint.async = true;
  81    };
  82  
  83    CodeMirror.TernServer.prototype = {
  84      addDoc: function(name, doc) {
  85        var data = {doc: doc, name: name, changed: null};
  86        this.server.addFile(name, docValue(this, data));
  87        CodeMirror.on(doc, "change", this.trackChange);
  88        return this.docs[name] = data;
  89      },
  90  
  91      delDoc: function(id) {
  92        var found = resolveDoc(this, id);
  93        if (!found) return;
  94        CodeMirror.off(found.doc, "change", this.trackChange);
  95        delete this.docs[found.name];
  96        this.server.delFile(found.name);
  97      },
  98  
  99      hideDoc: function(id) {
 100        closeArgHints(this);
 101        var found = resolveDoc(this, id);
 102        if (found && found.changed) sendDoc(this, found);
 103      },
 104  
 105      complete: function(cm) {
 106        cm.showHint({hint: this.getHint});
 107      },
 108  
 109      showType: function(cm, pos, c) { showContextInfo(this, cm, pos, "type", c); },
 110  
 111      showDocs: function(cm, pos, c) { showContextInfo(this, cm, pos, "documentation", c); },
 112  
 113      updateArgHints: function(cm) { updateArgHints(this, cm); },
 114  
 115      jumpToDef: function(cm) { jumpToDef(this, cm); },
 116  
 117      jumpBack: function(cm) { jumpBack(this, cm); },
 118  
 119      rename: function(cm) { rename(this, cm); },
 120  
 121      selectName: function(cm) { selectName(this, cm); },
 122  
 123      request: function (cm, query, c, pos) {
 124        var self = this;
 125        var doc = findDoc(this, cm.getDoc());
 126        var request = buildRequest(this, doc, query, pos);
 127        var extraOptions = request.query && this.options.queryOptions && this.options.queryOptions[request.query.type]
 128        if (extraOptions) for (var prop in extraOptions) request.query[prop] = extraOptions[prop];
 129  
 130        this.server.request(request, function (error, data) {
 131          if (!error && self.options.responseFilter)
 132            data = self.options.responseFilter(doc, query, request, error, data);
 133          c(error, data);
 134        });
 135      },
 136  
 137      destroy: function () {
 138        closeArgHints(this)
 139        if (this.worker) {
 140          this.worker.terminate();
 141          this.worker = null;
 142        }
 143      }
 144    };
 145  
 146    var Pos = CodeMirror.Pos;
 147    var cls = "CodeMirror-Tern-";
 148    var bigDoc = 250;
 149  
 150    function getFile(ts, name, c) {
 151      var buf = ts.docs[name];
 152      if (buf)
 153        c(docValue(ts, buf));
 154      else if (ts.options.getFile)
 155        ts.options.getFile(name, c);
 156      else
 157        c(null);
 158    }
 159  
 160    function findDoc(ts, doc, name) {
 161      for (var n in ts.docs) {
 162        var cur = ts.docs[n];
 163        if (cur.doc == doc) return cur;
 164      }
 165      if (!name) for (var i = 0;; ++i) {
 166        n = "[doc" + (i || "") + "]";
 167        if (!ts.docs[n]) { name = n; break; }
 168      }
 169      return ts.addDoc(name, doc);
 170    }
 171  
 172    function resolveDoc(ts, id) {
 173      if (typeof id == "string") return ts.docs[id];
 174      if (id instanceof CodeMirror) id = id.getDoc();
 175      if (id instanceof CodeMirror.Doc) return findDoc(ts, id);
 176    }
 177  
 178    function trackChange(ts, doc, change) {
 179      var data = findDoc(ts, doc);
 180  
 181      var argHints = ts.cachedArgHints;
 182      if (argHints && argHints.doc == doc && cmpPos(argHints.start, change.to) >= 0)
 183        ts.cachedArgHints = null;
 184  
 185      var changed = data.changed;
 186      if (changed == null)
 187        data.changed = changed = {from: change.from.line, to: change.from.line};
 188      var end = change.from.line + (change.text.length - 1);
 189      if (change.from.line < changed.to) changed.to = changed.to - (change.to.line - end);
 190      if (end >= changed.to) changed.to = end + 1;
 191      if (changed.from > change.from.line) changed.from = change.from.line;
 192  
 193      if (doc.lineCount() > bigDoc && change.to - changed.from > 100) setTimeout(function() {
 194        if (data.changed && data.changed.to - data.changed.from > 100) sendDoc(ts, data);
 195      }, 200);
 196    }
 197  
 198    function sendDoc(ts, doc) {
 199      ts.server.request({files: [{type: "full", name: doc.name, text: docValue(ts, doc)}]}, function(error) {
 200        if (error) window.console.error(error);
 201        else doc.changed = null;
 202      });
 203    }
 204  
 205    // Completion
 206  
 207    function hint(ts, cm, c) {
 208      ts.request(cm, {type: "completions", types: true, docs: true, urls: true}, function(error, data) {
 209        if (error) return showError(ts, cm, error);
 210        var completions = [], after = "";
 211        var from = data.start, to = data.end;
 212        if (cm.getRange(Pos(from.line, from.ch - 2), from) == "[\"" &&
 213            cm.getRange(to, Pos(to.line, to.ch + 2)) != "\"]")
 214          after = "\"]";
 215  
 216        for (var i = 0; i < data.completions.length; ++i) {
 217          var completion = data.completions[i], className = typeToIcon(completion.type);
 218          if (data.guess) className += " " + cls + "guess";
 219          completions.push({text: completion.name + after,
 220                            displayText: completion.displayName || completion.name,
 221                            className: className,
 222                            data: completion});
 223        }
 224  
 225        var obj = {from: from, to: to, list: completions};
 226        var tooltip = null;
 227        CodeMirror.on(obj, "close", function() { remove(tooltip); });
 228        CodeMirror.on(obj, "update", function() { remove(tooltip); });
 229        CodeMirror.on(obj, "select", function(cur, node) {
 230          remove(tooltip);
 231          var content = ts.options.completionTip ? ts.options.completionTip(cur.data) : cur.data.doc;
 232          if (content) {
 233            tooltip = makeTooltip(node.parentNode.getBoundingClientRect().right + window.pageXOffset,
 234                                  node.getBoundingClientRect().top + window.pageYOffset, content, cm, cls + "hint-doc");
 235          }
 236        });
 237        c(obj);
 238      });
 239    }
 240  
 241    function typeToIcon(type) {
 242      var suffix;
 243      if (type == "?") suffix = "unknown";
 244      else if (type == "number" || type == "string" || type == "bool") suffix = type;
 245      else if (/^fn\(/.test(type)) suffix = "fn";
 246      else if (/^\[/.test(type)) suffix = "array";
 247      else suffix = "object";
 248      return cls + "completion " + cls + "completion-" + suffix;
 249    }
 250  
 251    // Type queries
 252  
 253    function showContextInfo(ts, cm, pos, queryName, c) {
 254      ts.request(cm, queryName, function(error, data) {
 255        if (error) return showError(ts, cm, error);
 256        if (ts.options.typeTip) {
 257          var tip = ts.options.typeTip(data);
 258        } else {
 259          var tip = elt("span", null, elt("strong", null, data.type || "not found"));
 260          if (data.doc)
 261            tip.appendChild(document.createTextNode(" — " + data.doc));
 262          if (data.url) {
 263            tip.appendChild(document.createTextNode(" "));
 264            var child = tip.appendChild(elt("a", null, "[docs]"));
 265            child.href = data.url;
 266            child.target = "_blank";
 267          }
 268        }
 269        tempTooltip(cm, tip, ts);
 270        if (c) c();
 271      }, pos);
 272    }
 273  
 274    // Maintaining argument hints
 275  
 276    function updateArgHints(ts, cm) {
 277      closeArgHints(ts);
 278  
 279      if (cm.somethingSelected()) return;
 280      var state = cm.getTokenAt(cm.getCursor()).state;
 281      var inner = CodeMirror.innerMode(cm.getMode(), state);
 282      if (inner.mode.name != "javascript") return;
 283      var lex = inner.state.lexical;
 284      if (lex.info != "call") return;
 285  
 286      var ch, argPos = lex.pos || 0, tabSize = cm.getOption("tabSize");
 287      for (var line = cm.getCursor().line, e = Math.max(0, line - 9), found = false; line >= e; --line) {
 288        var str = cm.getLine(line), extra = 0;
 289        for (var pos = 0;;) {
 290          var tab = str.indexOf("\t", pos);
 291          if (tab == -1) break;
 292          extra += tabSize - (tab + extra) % tabSize - 1;
 293          pos = tab + 1;
 294        }
 295        ch = lex.column - extra;
 296        if (str.charAt(ch) == "(") {found = true; break;}
 297      }
 298      if (!found) return;
 299  
 300      var start = Pos(line, ch);
 301      var cache = ts.cachedArgHints;
 302      if (cache && cache.doc == cm.getDoc() && cmpPos(start, cache.start) == 0)
 303        return showArgHints(ts, cm, argPos);
 304  
 305      ts.request(cm, {type: "type", preferFunction: true, end: start}, function(error, data) {
 306        if (error || !data.type || !(/^fn\(/).test(data.type)) return;
 307        ts.cachedArgHints = {
 308          start: start,
 309          type: parseFnType(data.type),
 310          name: data.exprName || data.name || "fn",
 311          guess: data.guess,
 312          doc: cm.getDoc()
 313        };
 314        showArgHints(ts, cm, argPos);
 315      });
 316    }
 317  
 318    function showArgHints(ts, cm, pos) {
 319      closeArgHints(ts);
 320  
 321      var cache = ts.cachedArgHints, tp = cache.type;
 322      var tip = elt("span", cache.guess ? cls + "fhint-guess" : null,
 323                    elt("span", cls + "fname", cache.name), "(");
 324      for (var i = 0; i < tp.args.length; ++i) {
 325        if (i) tip.appendChild(document.createTextNode(", "));
 326        var arg = tp.args[i];
 327        tip.appendChild(elt("span", cls + "farg" + (i == pos ? " " + cls + "farg-current" : ""), arg.name || "?"));
 328        if (arg.type != "?") {
 329          tip.appendChild(document.createTextNode(":\u00a0"));
 330          tip.appendChild(elt("span", cls + "type", arg.type));
 331        }
 332      }
 333      tip.appendChild(document.createTextNode(tp.rettype ? ") ->\u00a0" : ")"));
 334      if (tp.rettype) tip.appendChild(elt("span", cls + "type", tp.rettype));
 335      var place = cm.cursorCoords(null, "page");
 336      var tooltip = ts.activeArgHints = makeTooltip(place.right + 1, place.bottom, tip, cm)
 337      setTimeout(function() {
 338        tooltip.clear = onEditorActivity(cm, function() {
 339          if (ts.activeArgHints == tooltip) closeArgHints(ts) })
 340      }, 20)
 341    }
 342  
 343    function parseFnType(text) {
 344      var args = [], pos = 3;
 345  
 346      function skipMatching(upto) {
 347        var depth = 0, start = pos;
 348        for (;;) {
 349          var next = text.charAt(pos);
 350          if (upto.test(next) && !depth) return text.slice(start, pos);
 351          if (/[{\[\(]/.test(next)) ++depth;
 352          else if (/[}\]\)]/.test(next)) --depth;
 353          ++pos;
 354        }
 355      }
 356  
 357      // Parse arguments
 358      if (text.charAt(pos) != ")") for (;;) {
 359        var name = text.slice(pos).match(/^([^, \(\[\{]+): /);
 360        if (name) {
 361          pos += name[0].length;
 362          name = name[1];
 363        }
 364        args.push({name: name, type: skipMatching(/[\),]/)});
 365        if (text.charAt(pos) == ")") break;
 366        pos += 2;
 367      }
 368  
 369      var rettype = text.slice(pos).match(/^\) -> (.*)$/);
 370  
 371      return {args: args, rettype: rettype && rettype[1]};
 372    }
 373  
 374    // Moving to the definition of something
 375  
 376    function jumpToDef(ts, cm) {
 377      function inner(varName) {
 378        var req = {type: "definition", variable: varName || null};
 379        var doc = findDoc(ts, cm.getDoc());
 380        ts.server.request(buildRequest(ts, doc, req), function(error, data) {
 381          if (error) return showError(ts, cm, error);
 382          if (!data.file && data.url) { window.open(data.url); return; }
 383  
 384          if (data.file) {
 385            var localDoc = ts.docs[data.file], found;
 386            if (localDoc && (found = findContext(localDoc.doc, data))) {
 387              ts.jumpStack.push({file: doc.name,
 388                                 start: cm.getCursor("from"),
 389                                 end: cm.getCursor("to")});
 390              moveTo(ts, doc, localDoc, found.start, found.end);
 391              return;
 392            }
 393          }
 394          showError(ts, cm, "Could not find a definition.");
 395        });
 396      }
 397  
 398      if (!atInterestingExpression(cm))
 399        dialog(cm, "Jump to variable", function(name) { if (name) inner(name); });
 400      else
 401        inner();
 402    }
 403  
 404    function jumpBack(ts, cm) {
 405      var pos = ts.jumpStack.pop(), doc = pos && ts.docs[pos.file];
 406      if (!doc) return;
 407      moveTo(ts, findDoc(ts, cm.getDoc()), doc, pos.start, pos.end);
 408    }
 409  
 410    function moveTo(ts, curDoc, doc, start, end) {
 411      doc.doc.setSelection(start, end);
 412      if (curDoc != doc && ts.options.switchToDoc) {
 413        closeArgHints(ts);
 414        ts.options.switchToDoc(doc.name, doc.doc);
 415      }
 416    }
 417  
 418    // The {line,ch} representation of positions makes this rather awkward.
 419    function findContext(doc, data) {
 420      var before = data.context.slice(0, data.contextOffset).split("\n");
 421      var startLine = data.start.line - (before.length - 1);
 422      var start = Pos(startLine, (before.length == 1 ? data.start.ch : doc.getLine(startLine).length) - before[0].length);
 423  
 424      var text = doc.getLine(startLine).slice(start.ch);
 425      for (var cur = startLine + 1; cur < doc.lineCount() && text.length < data.context.length; ++cur)
 426        text += "\n" + doc.getLine(cur);
 427      if (text.slice(0, data.context.length) == data.context) return data;
 428  
 429      var cursor = doc.getSearchCursor(data.context, 0, false);
 430      var nearest, nearestDist = Infinity;
 431      while (cursor.findNext()) {
 432        var from = cursor.from(), dist = Math.abs(from.line - start.line) * 10000;
 433        if (!dist) dist = Math.abs(from.ch - start.ch);
 434        if (dist < nearestDist) { nearest = from; nearestDist = dist; }
 435      }
 436      if (!nearest) return null;
 437  
 438      if (before.length == 1)
 439        nearest.ch += before[0].length;
 440      else
 441        nearest = Pos(nearest.line + (before.length - 1), before[before.length - 1].length);
 442      if (data.start.line == data.end.line)
 443        var end = Pos(nearest.line, nearest.ch + (data.end.ch - data.start.ch));
 444      else
 445        var end = Pos(nearest.line + (data.end.line - data.start.line), data.end.ch);
 446      return {start: nearest, end: end};
 447    }
 448  
 449    function atInterestingExpression(cm) {
 450      var pos = cm.getCursor("end"), tok = cm.getTokenAt(pos);
 451      if (tok.start < pos.ch && tok.type == "comment") return false;
 452      return /[\w)\]]/.test(cm.getLine(pos.line).slice(Math.max(pos.ch - 1, 0), pos.ch + 1));
 453    }
 454  
 455    // Variable renaming
 456  
 457    function rename(ts, cm) {
 458      var token = cm.getTokenAt(cm.getCursor());
 459      if (!/\w/.test(token.string)) return showError(ts, cm, "Not at a variable");
 460      dialog(cm, "New name for " + token.string, function(newName) {
 461        ts.request(cm, {type: "rename", newName: newName, fullDocs: true}, function(error, data) {
 462          if (error) return showError(ts, cm, error);
 463          applyChanges(ts, data.changes);
 464        });
 465      });
 466    }
 467  
 468    function selectName(ts, cm) {
 469      var name = findDoc(ts, cm.doc).name;
 470      ts.request(cm, {type: "refs"}, function(error, data) {
 471        if (error) return showError(ts, cm, error);
 472        var ranges = [], cur = 0;
 473        var curPos = cm.getCursor();
 474        for (var i = 0; i < data.refs.length; i++) {
 475          var ref = data.refs[i];
 476          if (ref.file == name) {
 477            ranges.push({anchor: ref.start, head: ref.end});
 478            if (cmpPos(curPos, ref.start) >= 0 && cmpPos(curPos, ref.end) <= 0)
 479              cur = ranges.length - 1;
 480          }
 481        }
 482        cm.setSelections(ranges, cur);
 483      });
 484    }
 485  
 486    var nextChangeOrig = 0;
 487    function applyChanges(ts, changes) {
 488      var perFile = Object.create(null);
 489      for (var i = 0; i < changes.length; ++i) {
 490        var ch = changes[i];
 491        (perFile[ch.file] || (perFile[ch.file] = [])).push(ch);
 492      }
 493      for (var file in perFile) {
 494        var known = ts.docs[file], chs = perFile[file];;
 495        if (!known) continue;
 496        chs.sort(function(a, b) { return cmpPos(b.start, a.start); });
 497        var origin = "*rename" + (++nextChangeOrig);
 498        for (var i = 0; i < chs.length; ++i) {
 499          var ch = chs[i];
 500          known.doc.replaceRange(ch.text, ch.start, ch.end, origin);
 501        }
 502      }
 503    }
 504  
 505    // Generic request-building helper
 506  
 507    function buildRequest(ts, doc, query, pos) {
 508      var files = [], offsetLines = 0, allowFragments = !query.fullDocs;
 509      if (!allowFragments) delete query.fullDocs;
 510      if (typeof query == "string") query = {type: query};
 511      query.lineCharPositions = true;
 512      if (query.end == null) {
 513        query.end = pos || doc.doc.getCursor("end");
 514        if (doc.doc.somethingSelected())
 515          query.start = doc.doc.getCursor("start");
 516      }
 517      var startPos = query.start || query.end;
 518  
 519      if (doc.changed) {
 520        if (doc.doc.lineCount() > bigDoc && allowFragments !== false &&
 521            doc.changed.to - doc.changed.from < 100 &&
 522            doc.changed.from <= startPos.line && doc.changed.to > query.end.line) {
 523          files.push(getFragmentAround(doc, startPos, query.end));
 524          query.file = "#0";
 525          var offsetLines = files[0].offsetLines;
 526          if (query.start != null) query.start = Pos(query.start.line - -offsetLines, query.start.ch);
 527          query.end = Pos(query.end.line - offsetLines, query.end.ch);
 528        } else {
 529          files.push({type: "full",
 530                      name: doc.name,
 531                      text: docValue(ts, doc)});
 532          query.file = doc.name;
 533          doc.changed = null;
 534        }
 535      } else {
 536        query.file = doc.name;
 537      }
 538      for (var name in ts.docs) {
 539        var cur = ts.docs[name];
 540        if (cur.changed && cur != doc) {
 541          files.push({type: "full", name: cur.name, text: docValue(ts, cur)});
 542          cur.changed = null;
 543        }
 544      }
 545  
 546      return {query: query, files: files};
 547    }
 548  
 549    function getFragmentAround(data, start, end) {
 550      var doc = data.doc;
 551      var minIndent = null, minLine = null, endLine, tabSize = 4;
 552      for (var p = start.line - 1, min = Math.max(0, p - 50); p >= min; --p) {
 553        var line = doc.getLine(p), fn = line.search(/\bfunction\b/);
 554        if (fn < 0) continue;
 555        var indent = CodeMirror.countColumn(line, null, tabSize);
 556        if (minIndent != null && minIndent <= indent) continue;
 557        minIndent = indent;
 558        minLine = p;
 559      }
 560      if (minLine == null) minLine = min;
 561      var max = Math.min(doc.lastLine(), end.line + 20);
 562      if (minIndent == null || minIndent == CodeMirror.countColumn(doc.getLine(start.line), null, tabSize))
 563        endLine = max;
 564      else for (endLine = end.line + 1; endLine < max; ++endLine) {
 565        var indent = CodeMirror.countColumn(doc.getLine(endLine), null, tabSize);
 566        if (indent <= minIndent) break;
 567      }
 568      var from = Pos(minLine, 0);
 569  
 570      return {type: "part",
 571              name: data.name,
 572              offsetLines: from.line,
 573              text: doc.getRange(from, Pos(endLine, end.line == endLine ? null : 0))};
 574    }
 575  
 576    // Generic utilities
 577  
 578    var cmpPos = CodeMirror.cmpPos;
 579  
 580    function elt(tagname, cls /*, ... elts*/) {
 581      var e = document.createElement(tagname);
 582      if (cls) e.className = cls;
 583      for (var i = 2; i < arguments.length; ++i) {
 584        var elt = arguments[i];
 585        if (typeof elt == "string") elt = document.createTextNode(elt);
 586        e.appendChild(elt);
 587      }
 588      return e;
 589    }
 590  
 591    function dialog(cm, text, f) {
 592      if (cm.openDialog)
 593        cm.openDialog(text + ": <input type=text>", f);
 594      else
 595        f(prompt(text, ""));
 596    }
 597  
 598    // Tooltips
 599  
 600    function tempTooltip(cm, content, ts) {
 601      if (cm.state.ternTooltip) remove(cm.state.ternTooltip);
 602      var where = cm.cursorCoords();
 603      var tip = cm.state.ternTooltip = makeTooltip(where.right + 1, where.bottom, content, cm);
 604      function maybeClear() {
 605        old = true;
 606        if (!mouseOnTip) clear();
 607      }
 608      function clear() {
 609        cm.state.ternTooltip = null;
 610        if (tip.parentNode) fadeOut(tip)
 611        clearActivity()
 612      }
 613      var mouseOnTip = false, old = false;
 614      CodeMirror.on(tip, "mousemove", function() { mouseOnTip = true; });
 615      CodeMirror.on(tip, "mouseout", function(e) {
 616        var related = e.relatedTarget || e.toElement
 617        if (!related || !CodeMirror.contains(tip, related)) {
 618          if (old) clear();
 619          else mouseOnTip = false;
 620        }
 621      });
 622      setTimeout(maybeClear, ts.options.hintDelay ? ts.options.hintDelay : 1700);
 623      var clearActivity = onEditorActivity(cm, clear)
 624    }
 625  
 626    function onEditorActivity(cm, f) {
 627      cm.on("cursorActivity", f)
 628      cm.on("blur", f)
 629      cm.on("scroll", f)
 630      cm.on("setDoc", f)
 631      return function() {
 632        cm.off("cursorActivity", f)
 633        cm.off("blur", f)
 634        cm.off("scroll", f)
 635        cm.off("setDoc", f)
 636      }
 637    }
 638  
 639    function makeTooltip(x, y, content, cm, className) {
 640      var node = elt("div", cls + "tooltip" + " " + (className || ""), content);
 641      node.style.left = x + "px";
 642      node.style.top = y + "px";
 643      var container = ((cm.options || {}).hintOptions || {}).container || document.body;
 644      container.appendChild(node);
 645  
 646      var pos = cm.cursorCoords();
 647      var winW = window.innerWidth;
 648      var winH = window.innerHeight;
 649      var box = node.getBoundingClientRect();
 650      var hints = document.querySelector(".CodeMirror-hints");
 651      var overlapY = box.bottom - winH;
 652      var overlapX = box.right - winW;
 653  
 654      if (hints && overlapX > 0) {
 655        node.style.left = 0;
 656        var box = node.getBoundingClientRect();
 657        node.style.left = (x = x - hints.offsetWidth - box.width) + "px";
 658        overlapX = box.right - winW;
 659      }
 660      if (overlapY > 0) {
 661        var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top);
 662        if (curTop - height > 0) { // Fits above cursor
 663          node.style.top = (pos.top - height) + "px";
 664        } else if (height > winH) {
 665          node.style.height = (winH - 5) + "px";
 666          node.style.top = (pos.bottom - box.top) + "px";
 667        }
 668      }
 669      if (overlapX > 0) {
 670        if (box.right - box.left > winW) {
 671          node.style.width = (winW - 5) + "px";
 672          overlapX -= (box.right - box.left) - winW;
 673        }
 674        node.style.left = (x - overlapX) + "px";
 675      }
 676  
 677      return node;
 678    }
 679  
 680    function remove(node) {
 681      var p = node && node.parentNode;
 682      if (p) p.removeChild(node);
 683    }
 684  
 685    function fadeOut(tooltip) {
 686      tooltip.style.opacity = "0";
 687      setTimeout(function() { remove(tooltip); }, 1100);
 688    }
 689  
 690    function showError(ts, cm, msg) {
 691      if (ts.options.showError)
 692        ts.options.showError(cm, msg);
 693      else
 694        tempTooltip(cm, String(msg), ts);
 695    }
 696  
 697    function closeArgHints(ts) {
 698      if (ts.activeArgHints) {
 699        if (ts.activeArgHints.clear) ts.activeArgHints.clear()
 700        remove(ts.activeArgHints)
 701        ts.activeArgHints = null
 702      }
 703    }
 704  
 705    function docValue(ts, doc) {
 706      var val = doc.doc.getValue();
 707      if (ts.options.fileFilter) val = ts.options.fileFilter(val, doc.name, doc.doc);
 708      return val;
 709    }
 710  
 711    // Worker wrapper
 712  
 713    function WorkerServer(ts) {
 714      var worker = ts.worker = new Worker(ts.options.workerScript);
 715      worker.postMessage({type: "init",
 716                          defs: ts.options.defs,
 717                          plugins: ts.options.plugins,
 718                          scripts: ts.options.workerDeps});
 719      var msgId = 0, pending = {};
 720  
 721      function send(data, c) {
 722        if (c) {
 723          data.id = ++msgId;
 724          pending[msgId] = c;
 725        }
 726        worker.postMessage(data);
 727      }
 728      worker.onmessage = function(e) {
 729        var data = e.data;
 730        if (data.type == "getFile") {
 731          getFile(ts, data.name, function(err, text) {
 732            send({type: "getFile", err: String(err), text: text, id: data.id});
 733          });
 734        } else if (data.type == "debug") {
 735          window.console.log(data.message);
 736        } else if (data.id && pending[data.id]) {
 737          pending[data.id](data.err, data.body);
 738          delete pending[data.id];
 739        }
 740      };
 741      worker.onerror = function(e) {
 742        for (var id in pending) pending[id](e);
 743        pending = {};
 744      };
 745  
 746      this.addFile = function(name, text) { send({type: "add", name: name, text: text}); };
 747      this.delFile = function(name) { send({type: "del", name: name}); };
 748      this.request = function(body, c) { send({type: "req", body: body}, c); };
 749    }
 750  });


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