לדלג לתוכן

מדיה ויקי:Gadget-autocomplete.js: הבדלים בין גרסאות בדף

מתוך חב"דפדיה, אנציקלופדיה חב"דית חופשית
יצירת דף עם התוכן "Autocomplete for links and templates Written by [[משתמש:ערן]]: mw.loader.using(['jquery.ui', 'jquery.textSelection'], function() { //extends jquery with autoCompleteWikiText functionality for autocomplete of links and templates $.fn.autoCompleteWikiText = function(options) { var mode = "none", templateDataCache = {}, ctrl = $(this), settings = $.extend(true, { positionMy: $('body')..."
 
אין תקציר עריכה
 
(4 גרסאות ביניים של אותו משתמש אינן מוצגות)
שורה 1: שורה 1:
"use strict";
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
/*
/*
Autocomplete for links and templates
Autocomplete for links and templates
Written by [[משתמש:ערן]]
Written by [[משתמש:ערן]]
*/
*/
mw.loader.using(['jquery.ui', 'jquery.textSelection'], function() {
mw.loader.using(['jquery.ui', 'jquery.textSelection'], function () {
    //extends jquery with autoCompleteWikiText functionality for autocomplete of links and templates
  //extends jquery with autoCompleteWikiText functionality for autocomplete of links and templates
    $.fn.autoCompleteWikiText = function(options) {
  $.fn.autoCompleteWikiText = function (options) {
        var mode = "none",
    var mode = "none",
            templateDataCache = {},
      templateDataCache = {},
            ctrl = $(this),
      ctrl = $(this),
            settings = $.extend(true, {
      settings = $.extend(true, {
            positionMy: $('body').is('.rtl') ? "left top" : "right top", // be default, open below the control
        positionMy: $('body').is('.rtl') ? "left top" : "right top",
            positionAt: $('body').is('.rtl') ? "left bottom" : "right bottom",
        // be default, open below the control
            positionOf: ctrl,
        positionAt: $('body').is('.rtl') ? "left bottom" : "right bottom",
            positionOffset: "0",
        positionOf: ctrl,
            filterResponse: function(a) {
        positionOffset: "0",
                return a;
        filterResponse: function filterResponse(a) {
            }, // function that expects array of string and returns array of strings
          return a;
            menuCSS: {
        },
                width: 'auto',
        // function that expects array of string and returns array of strings
                maxHeight: '30em',
        menuCSS: {
                'overflow-y': 'auto'
          width: 'auto',
            },
          maxHeight: '30em',
            itemCSS: {
          'overflow-y': 'auto'
                right: 'inherit'
        },
            },
        itemCSS: {
            onselected: function(item) {
          right: 'inherit'
                var pos = ctrl.textSelection('getCaretPosition') - 1,
        },
                    txt = ctrl.val(),
        onselected: function onselected(item) {
                open, close, caretBackwards;
          var pos = ctrl.textSelection('getCaretPosition') - 1,
 
            txt = ctrl.val(),
                switch (mode) {
            open,
                    case "none":
            close,
                        return;
            caretBackwards;
                    case "templateValue":
          switch (mode) {
                        open = "|";
            case "none":
                        close = "";
              return;
                        caretBackwards = 0;
            case "templateValue":
                        break;
              open = "|";
                    case "templateParams":
              close = "";
                        open = "|";
              caretBackwards = 0;
                        close = "=";
              break;
                        caretBackwards = 0;
            case "templateParams":
                        break;
              open = "|";
                    case "template":
              close = "=";
                        item = item.substr(mw.config.get('wgFormattedNamespaces')[10].length + 1);
              caretBackwards = 0;
                        caretBackwards = 2;
              break;
                        open = "{{";
            case "template":
                        close = "|}}";
              item = item.substr(mw.config.get('wgFormattedNamespaces')[10].length + 1);
                        break;
              caretBackwards = 2;
                    case "link":
              open = "{{";
                        open = "[[";
              close = "|}}";
                        close = "]]";
              break;
                        caretBackwards = 0;
            case "link":
                        if (item[item.length - 1] == ')') item += '|';
              open = "[[";
                        break;
              close = "]]";
              caretBackwards = 0;
              if (item[item.length - 1] == ')') item += '|';
              break;
          }
          var lastbegin = txt.lastIndexOf(open, pos);
          if (txt[lastbegin + 2] == ':') item = ':' + item;
          var newTxt = txt.substr(0, lastbegin) + open + item + close + txt.substr(pos + 1);
          var orgScroll = ctrl.scrollTop();
          ctrl.val(newTxt);
          ctrl.textSelection('setSelection', {
            start: lastbegin + (open + item + close).length - caretBackwards
          });
          ctrl.scrollTop(orgScroll);
        }
      }, options);
    function findLinks(res) {
      var pos = ctrl.textSelection('getCaretPosition') - 1;
      var txt = ctrl.val();
      var lastbegin = txt.lastIndexOf("[[", pos);
      var lastend = txt.lastIndexOf("]]", pos);
      var isLink = lastbegin > lastend;
      if (isLink) {
        mode = 'link';
        fillLinksList(res, txt.substr(lastbegin + 2, pos - lastbegin));
      } else {
        lastbegin = txt.lastIndexOf("{{", pos);
        lastend = txt.lastIndexOf("}}", pos);
        var isTemplate = lastbegin > lastend;
        if (isTemplate) {
          var prefixName = mw.config.get('wgFormattedNamespaces')[10] + ':' + txt.substr(lastbegin + 2, pos - lastbegin - 1);
          mode = prefixName.indexOf('|') > -1 ? 'templateParams' : 'template';
          fillLinksList(res, prefixName);
        } else {
          mode = "none";
          res([]);
        }
      }
    }
    function resolveTempalte(templateName) {
      var dfd = new jQuery.Deferred();
      if (!templateName) return dfd.reject().promise();
      if (templateDataCache[templateName]) return dfd.resolve(templateDataCache[templateName]).promise();
      var api = new mw.Api();
      api.get({
        action: 'templatedata',
        titles: templateName,
        redirects: 1
      }).done(function (data) {
        if (!data.pages) return dfd.reject();
        for (var pageid in data.pages) {
          templateDataCache[templateName] = data.pages[pageid];
          dfd.resolve(templateDataCache[templateName]);
        }
        if (!templateDataCache[templateName]) dfd.reject();
      });
      return dfd.promise();
    }
    function resolveApi(queryType, queryValue) {
      var dfd = new jQuery.Deferred(),
        api = new mw.Api();
      switch (queryType) {
        case 'users':
          api.get({
            action: 'query',
            list: 'allusers',
            auactiveusers: 1,
            auprefix: queryValue
          }).done(function (data) {
            if (data && data.query && data.query.allusers) dfd.resolve($.map(data.query.allusers, function (e) {
              return e.name;
            }));else dfd.reject();
          });
          break;
        case 'pages':
          api.get({
            action: 'opensearch',
            search: queryValue
          }).done(function (data) {
            if (data[1]) dfd.resolve(settings.filterResponse(data[1]));else dfd.reject();
          });
          break;
        default:
          throw 'unexpected queryType';
      }
      return dfd.promise();
    }
    function fillLinksList(res, txt) {
      txt = $.trim(txt);
      if (txt.length <= 1 || mode != 'templateParams' && txt.indexOf('|') > -1 || txt.indexOf('#') > -1 && mw.config.get('wgNamespaceNumber') === 0) res([]);else if (mode === 'templateParams') {
        var templateMatch = /(.+?)\|(?:.*\|)?([^=]+$)/.exec(txt);
        var templateParamMatch = /(.+?)\|(?:.*\|)?([^=]+=[^=]+$)/.exec(txt);
        $.when(resolveTempalte(templateMatch && templateMatch[1] || templateParamMatch && templateParamMatch[1])).done(function (td) {
          var curTemplateData = td,
            suggestions = [],
            curParamIndex = txt.split('|').length - 1;
          if (templateParamMatch && !templateMatch) {
            var paramNameVal = templateParamMatch[2].split('=');
            if (paramNameVal[0] in curTemplateData.params && 'suggestedvalues' in curTemplateData.params[paramNameVal[0]]) {
              mode = 'templateValue';
              var _iterator = _createForOfIteratorHelper(curTemplateData.params[paramNameVal[0]].suggestedvalues),
                _step;
              try {
                for (_iterator.s(); !(_step = _iterator.n()).done;) {
                  var suggestedVal = _step.value;
                  if (suggestedVal.indexOf(paramNameVal[1]) == 0) suggestions.push(paramNameVal[0] + '=' + suggestedVal);
                 }
                 }
                var lastbegin = txt.lastIndexOf(open, pos);
              } catch (err) {
                if (txt[lastbegin + 2] == ':')
                 _iterator.e(err);
                    item = ':' + item;
              } finally {
 
                 _iterator.f();
                 var newTxt = txt.substr(0, lastbegin) + open + item + close + txt.substr(pos + 1);
              }
                var orgScroll = ctrl.scrollTop();
                 ctrl.val(newTxt);
                ctrl.textSelection('setSelection', {
                    start: lastbegin + (open + item + close).length - caretBackwards
                });
                ctrl.scrollTop(orgScroll);
             }
             }
        }, options);
          } else {
 
             for (var paramName in curTemplateData.params) {
        function findLinks(res) {
              if (paramName == curParamIndex) {
             var pos = ctrl.textSelection('getCaretPosition') - 1;
                var paramValue = templateMatch[2];
            var txt = ctrl.val();
                var dfd;
 
                switch (curTemplateData.params[paramName].type) {
            var lastbegin = txt.lastIndexOf("[[", pos);
                  case 'wiki-page-name':
            var lastend = txt.lastIndexOf("]]", pos);
                    dfd = $.when(resolveApi('pages', paramValue));
            var isLink = lastbegin > lastend;
                    mode = 'templateValue';
            if (isLink) {
                    break;
                mode = 'link';
                  case 'wiki-file-name':
                fillLinksList(res, txt.substr(lastbegin + 2, pos - lastbegin));
                    dfd = $.when(resolveApi('pages', 'File:' + paramValue));
            } else {
                    mode = 'templateValue';
                lastbegin = txt.lastIndexOf("{{", pos);
                    break;
                lastend = txt.lastIndexOf("}}", pos);
                  case 'wiki-template-name':
                var isTemplate = lastbegin > lastend;
                     dfd = $.when(resolveApi('pages', 'Template:' + paramValue));
                if (isTemplate) {
                     mode = 'templateValue';
                     var prefixName = mw.config.get('wgFormattedNamespaces')[10] + ':' + txt.substr(lastbegin + 2, pos - lastbegin - 1);
                    break;
                     mode = (prefixName.indexOf('|') > -1) ? 'templateParams' : 'template';
                  case 'wiki-user-name':
                     fillLinksList(res, prefixName);
                    dfd = $.when(resolveApi('users', paramValue));
                } else {
                    mode = 'templateValue';
                    mode = "none";
                    break;
                    res([]);
                  case 'string':
                }
                     if ('suggestedvalues' in curTemplateData.params[paramName]) {
            }
                      mode = 'templateValue';
        }
                      var _iterator2 = _createForOfIteratorHelper(curTemplateData.params[paramName].suggestedvalues),
 
                        _step2;
 
                      try {
        function resolveTempalte(templateName) {
                        for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
            var dfd = new jQuery.Deferred();
                          var _suggestedVal = _step2.value;
            if (!templateName) return dfd.reject().promise();
                          if (_suggestedVal.indexOf(paramValue) == 0) suggestions.push(_suggestedVal);
            if (templateDataCache[templateName]) return dfd.resolve(templateDataCache[templateName]).promise();
                        }
            var api = new mw.Api();
                      } catch (err) {
            api.get({
                        _iterator2.e(err);
                action: 'templatedata',
                      } finally {
                titles: templateName,
                        _iterator2.f();
                redirects: 1
                      }
            }).done(function(data) {
                      return res(suggestions);
                if (!data.pages) return dfd.reject();
                     } else return res([]);
                for (var pageid in data.pages) {
                  default:
                     templateDataCache[templateName] = data.pages[pageid];
                     return res([]);
                     dfd.resolve(templateDataCache[templateName]);
                  // dont suggest for this indexed param
                 }
                 }
                if (!templateDataCache[templateName]) dfd.reject();
            });
            return dfd.promise();
        }


        function resolveApi(queryType, queryValue) {
                return dfd.done(res).fail(function () {
            var dfd = new jQuery.Deferred(),
                  res([]);
                api = new mw.Api();
                });
 
              }
            switch (queryType) {
              if (paramName === '1' || txt.indexOf(paramName) > -1) continue; //dont suggest used params
                case 'users':
              suggestions.push(paramName);
                    api.get({
                        action: 'query',
                        list: 'allusers',
                        auactiveusers: 1,
                        auprefix: queryValue
                    }).done(function(data) {
                        if (data && data.query && data.query.allusers) dfd.resolve($.map(data.query.allusers, function(e) {
                            return e.name;
                        }));
                        else dfd.reject();
                    });
                    break;
                case 'pages':
                    api.get({
                        action: 'opensearch',
                        search: queryValue
                    }).done(function(data) {
                        if (data[1]) dfd.resolve(settings.filterResponse(data[1]));
                        else dfd.reject();
                    });
                    break;
                default:
                    throw 'unexpected queryType';
             }
             }
          }
          res(suggestions);
        }).fail(res);
      } else if (txt.indexOf('#') > -1) {
        var pageTitle = txt.substr(0, txt.indexOf('#'));
        var sectionPrefix = txt.substr(txt.indexOf('#') + 1);
        var api = new mw.Api();
        api.get({
          action: 'parse',
          page: pageTitle,
          prop: 'sections'
        }).done(function (data) {
          if (data && data.parse && data.parse.sections) res($(data.parse.sections).map(function () {
            return this.line.indexOf(sectionPrefix) == 0 ? pageTitle + '#' + this.line.replace(/[|\[\]\{\}]/g, escape) : null;
          }));
        });
      } else {
        $.when(resolveApi('pages', txt)).done(res).fail(function () {
          res([]);
        });
      }
    }
    ctrl.autocomplete({
      source: function source(request, response) {
        if (fixArrowsBug(this)) response([]);else findLinks(response);
      },
      focus: function focus() {
        return false;
      },
      select: function select(e, ui) {
        settings.onselected(ui.item.value);
        return false;
      },
      open: function open() {
        $(".ui-autocomplete").css(settings.menuCSS).position({
          my: settings.positionMy,
          at: settings.positionAt,
          of: settings.positionOf,
          offset: settings.positionOffset,
          collision: 'none fit'
        }).find('li').css(settings.itemCSS);
      }
    });
    var fixed,
      stfu,
      escapes = 0;
    //this is hack to prevent known serious bug in autocomplete.js that prevent default of the up and down key which may drive you crazy....
    function fixArrowsBug(self) {
      if (fixed) return false;
      fixed = true;


            return dfd.promise();
      // on click selection may change. close the menu
      ctrl.on("click.autocomplete", function (e) {
        clearTimeout(self.searching);
        self.close();
      });
      ctrl.off("keydown.autocomplete");
      ctrl.off("keydown.autocomplete0");
      ctrl.on("keydown.autocomplete", function (event) {
        var keyCode = $.ui.keyCode;
        // hack to allow cancelling the gadget: mostly useful when editing templates.
        escapes = event.keyCode == keyCode.ESCAPE ? escapes + 1 : 0;
        if (stfu || (stfu = escapes >= 3)) {
          self.close(event);
          return;
         }
         }
 
         switch (event.keyCode) {
         function fillLinksList(res, txt) {
          case keyCode.PAGE_UP:
            txt = $.trim(txt);
             self._move("previousPage", event);
             if (txt.length <= 1 || (mode != 'templateParams' && txt.indexOf('|') > -1) || (txt.indexOf('#') > -1 && mw.config.get('wgNamespaceNumber') === 0)) res([]);
             break;
             else if (mode === 'templateParams') {
          case keyCode.PAGE_DOWN:
                var templateMatch = /(.+?)\|(?:.*\|)?([^=]+$)/.exec(txt);
            self._move("nextPage", event);
                var templateParamMatch = /(.+?)\|(?:.*\|)?([^=]+=[^=]+$)/.exec(txt);
            break;
 
          case keyCode.UP:
                $.when(resolveTempalte((templateMatch && templateMatch[1]) || (templateParamMatch && templateParamMatch[1]))).done(function(td) {
            if (!self.menu.element.is(":visible")) return;
 
            self._move("previous", event);
                    var curTemplateData = td,
            // prevent moving cursor to beginning of text field in some browsers
                    suggestions = [],
            event.preventDefault();
                    curParamIndex = txt.split('|').length - 1;
            break;
if (templateParamMatch && !templateMatch) {
          case keyCode.DOWN:
var paramNameVal = templateParamMatch[2].split('=');
            if (!self.menu.element.is(":visible")) return;
if (paramNameVal[0] in curTemplateData.params && 'suggestedvalues' in curTemplateData.params[paramNameVal[0]]) {
            self._move("next", event);
                                mode = 'templateValue';
            // prevent moving cursor to end of text field in some browsers
                                for (const suggestedVal of curTemplateData.params[paramNameVal[0]].suggestedvalues) {
            event.preventDefault();
                                if (suggestedVal.indexOf(paramNameVal[1])==0) suggestions.push(paramNameVal[0] + '=' + suggestedVal);
             break;
                                }
          case keyCode.ENTER:
}
          case keyCode.NUMPAD_ENTER:
} else {
            // when menu is open or has focus
                    for (var paramName in curTemplateData.params) {
             if (self.menu.active) {
                        if (paramName == curParamIndex) {
              event.preventDefault();
                            var paramValue = templateMatch[2];
                            var dfd;
                            switch (curTemplateData.params[paramName].type) {
                                case 'wiki-page-name':
                                    dfd = $.when(resolveApi('pages', paramValue));
                                    mode = 'templateValue';
                                    break;
                                case 'wiki-file-name':
                                    dfd = $.when(resolveApi('pages', 'File:' + paramValue));
                                    mode = 'templateValue';
                                    break;
                                case 'wiki-template-name':
                                    dfd = $.when(resolveApi('pages', 'Template:' + paramValue));
                                    mode = 'templateValue';
                                    break;                                  
                                case 'wiki-user-name':
                                    dfd = $.when(resolveApi('users', paramValue));
                                    mode = 'templateValue';
                                    break;
case 'string':
 
if ('suggestedvalues' in curTemplateData.params[paramName]){
        mode = 'templateValue';
                        for (const suggestedVal of curTemplateData.params[paramName].suggestedvalues) {
                        if (suggestedVal.indexOf(paramValue)==0) suggestions.push(suggestedVal);
                        }        
return res(suggestions);
} else
return res([]);
                                default:
                                    return res([]); // dont suggest for this indexed param
                            }
                            return dfd.done(res).fail(function() {
                                res([]);
                            });
                        }
                        if (paramName === '1' || txt.indexOf(paramName) > -1) continue; //dont suggest used params
                        suggestions.push(paramName);
                    }
                  }
                  res(suggestions);
                }).fail(res);
             } else if (txt.indexOf('#') > -1) {
                var pageTitle = txt.substr(0, txt.indexOf('#'));
                var sectionPrefix = txt.substr(txt.indexOf('#') + 1);
                var api = new mw.Api();
                api.get({
                    action: 'parse',
                    page: pageTitle,
                    prop: 'sections'
                }).done(function(data) {
                    if (data && data.parse && data.parse.sections) res($(data.parse.sections).map(function() {
                        return this.line.indexOf(sectionPrefix) == 0 ? (pageTitle + '#' + this.line.replace(/[|\[\]\{\}]/g, escape)) : null;
                    }));
                });
             } else {
                $.when(resolveApi('pages', txt)).done(res).fail(function() {
                    res([])
                });
             }
             }
        }
          //passthrough - ENTER and TAB both select the current element
 
          case keyCode.TAB:
        ctrl.autocomplete({
             if (!self.menu.active) {
             source: function(request, response) {
              return;
                if (fixArrowsBug(this))
                    response([]);
                else
                    findLinks(response);
            },
            focus: function() {
                return false;
            },
            select: function(e, ui) {
                settings.onselected(ui.item.value);
                return false;
            },
            open: function() {
                $(".ui-autocomplete")
                    .css(settings.menuCSS)
                    .position({
                        my: settings.positionMy,
                        at: settings.positionAt,
                        of: settings.positionOf,
                        offset: settings.positionOffset,
                        collision: 'none fit'
                    })
                    .find('li').css(settings.itemCSS);
             }
             }
        });
             self.menu.select(event);
        var fixed, stfu, escapes = 0;
            break;
        //this is hack to prevent known serious bug in autocomplete.js that prevent default of the up and down key which may drive you crazy....
          case keyCode.ESCAPE:
        function fixArrowsBug(self) {
            self.element.val(self.term);
             if (fixed) return false;
            self.close(event);
            fixed = true;
            break;
 
          case keyCode.SHIFT:
  // on click selection may change. close the menu
          case keyCode.CONTROL:
            ctrl.on("click.autocomplete", function(e){
          case keyCode.ALT:
clearTimeout(self.searching);
          case keyCode.COMMAND:
self.close();
          case keyCode.COMMAND_RIGHT:
  });
          case keyCode.INSERT:
            ctrl.off("keydown.autocomplete");
          case keyCode.CAPS_LOCK:
            ctrl.off("keydown.autocomplete0");
          case keyCode.END:
            ctrl.on("keydown.autocomplete",
          case keyCode.HOME:
                function(event) {
          case keyCode.LEFT:
                    var keyCode = $.ui.keyCode;
          case keyCode.RIGHT:
                    // hack to allow cancelling the gadget: mostly useful when editing templates.
            // ignore metakeys (shift, ctrl, alt)
                    escapes = event.keyCode == keyCode.ESCAPE ? escapes + 1 : 0;
            break;
                    if ( stfu || ( stfu = escapes >= 3 ) ) {
          default:
                        self.close(event);
            // keypress is triggered before the input value is changed
                    return;
            clearTimeout(self.searching);
                    }
            self.searching = setTimeout(function () {
                    switch (event.keyCode) {
              self.search(null, event);
                        case keyCode.PAGE_UP:
            }, self.options.delay);
                            self._move("previousPage", event);
            break;
                            break;
                        case keyCode.PAGE_DOWN:
                            self._move("nextPage", event);
                            break;
                        case keyCode.UP:
                            if (!self.menu.element.is(":visible")) return;
                            self._move("previous", event);
                            // prevent moving cursor to beginning of text field in some browsers
                            event.preventDefault();
                            break;
                        case keyCode.DOWN:
                            if (!self.menu.element.is(":visible")) return;
                            self._move("next", event);
                            // prevent moving cursor to end of text field in some browsers
                            event.preventDefault();
                            break;
                        case keyCode.ENTER:
                        case keyCode.NUMPAD_ENTER:
                            // when menu is open or has focus
                            if (self.menu.active) {
                                event.preventDefault();
                            }
                            //passthrough - ENTER and TAB both select the current element
                        case keyCode.TAB:
                            if (!self.menu.active) {
                                return;
                            }
                            self.menu.select(event);
                            break;
                        case keyCode.ESCAPE:
                            self.element.val(self.term);
                            self.close(event);
                            break;
 
                        case keyCode.SHIFT:
                        case keyCode.CONTROL:
                        case keyCode.ALT:
                        case keyCode.COMMAND:
                        case keyCode.COMMAND_RIGHT:
                        case keyCode.INSERT:
                        case keyCode.CAPS_LOCK:
                        case keyCode.END:
                        case keyCode.HOME:
                        case keyCode.LEFT:
                        case keyCode.RIGHT:                      
                            // ignore metakeys (shift, ctrl, alt)
                            break;
                        default:
                            // keypress is triggered before the input value is changed
                            clearTimeout(self.searching);
                            self.searching = setTimeout(function() {
                                self.search(null, event);
                            }, self.options.delay);
                            break;
                    }
                });
            return true;
         }
         }
      });
      return true;
    }
  };
});
if ($.inArray(mw.config.get('wgAction'), ['edit', 'submit']) + 1) mw.loader.using(['jquery.ui', 'jquery.textSelection'], function () {
  //enable autocomplete for editbox, relative to editform in an offset of -80 vertical
  $("#wpTextbox1").autoCompleteWikiText({
    positionAt: $('#wpTextbox1').prop('dir') == 'rtl' ? "left top" : "right top",
    positionOf: '#editform',
    positionOffset: "0 0",
    menuCSS: {
      background: '#E0EEF7',
      opacity: 0.8
    },
    itemCSS: {
      padding: 0,
      margin: 0
     }
     }
  });
});
});
if ($.inArray(mw.config.get('wgAction'), ['edit', 'submit']) + 1)
    mw.loader.using(['jquery.ui', 'jquery.textSelection'], function() {
        //enable autocomplete for editbox, relative to editform in an offset of -80 vertical
        $("#wpTextbox1").autoCompleteWikiText({
            positionAt: $('#wpTextbox1').prop('dir') == 'rtl' ? "left top" : "right top",
            positionOf: '#editform',
            positionOffset: "0 0",
            menuCSS: {
                background: '#E0EEF7',
                opacity: 0.8
            },
            itemCSS: {
                padding: 0,
                margin: 0
            }
        });
    });

גרסה אחרונה מ־17:02, 13 במאי 2025

"use strict";

function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
/*
Autocomplete for links and templates
Written by [[משתמש:ערן]]
*/
mw.loader.using(['jquery.ui', 'jquery.textSelection'], function () {
  //extends jquery with autoCompleteWikiText functionality for autocomplete of links and templates
  $.fn.autoCompleteWikiText = function (options) {
    var mode = "none",
      templateDataCache = {},
      ctrl = $(this),
      settings = $.extend(true, {
        positionMy: $('body').is('.rtl') ? "left top" : "right top",
        // be default, open below the control
        positionAt: $('body').is('.rtl') ? "left bottom" : "right bottom",
        positionOf: ctrl,
        positionOffset: "0",
        filterResponse: function filterResponse(a) {
          return a;
        },
        // function that expects array of string and returns array of strings
        menuCSS: {
          width: 'auto',
          maxHeight: '30em',
          'overflow-y': 'auto'
        },
        itemCSS: {
          right: 'inherit'
        },
        onselected: function onselected(item) {
          var pos = ctrl.textSelection('getCaretPosition') - 1,
            txt = ctrl.val(),
            open,
            close,
            caretBackwards;
          switch (mode) {
            case "none":
              return;
            case "templateValue":
              open = "|";
              close = "";
              caretBackwards = 0;
              break;
            case "templateParams":
              open = "|";
              close = "=";
              caretBackwards = 0;
              break;
            case "template":
              item = item.substr(mw.config.get('wgFormattedNamespaces')[10].length + 1);
              caretBackwards = 2;
              open = "{{";
              close = "|}}";
              break;
            case "link":
              open = "[[";
              close = "]]";
              caretBackwards = 0;
              if (item[item.length - 1] == ')') item += '|';
              break;
          }
          var lastbegin = txt.lastIndexOf(open, pos);
          if (txt[lastbegin + 2] == ':') item = ':' + item;
          var newTxt = txt.substr(0, lastbegin) + open + item + close + txt.substr(pos + 1);
          var orgScroll = ctrl.scrollTop();
          ctrl.val(newTxt);
          ctrl.textSelection('setSelection', {
            start: lastbegin + (open + item + close).length - caretBackwards
          });
          ctrl.scrollTop(orgScroll);
        }
      }, options);
    function findLinks(res) {
      var pos = ctrl.textSelection('getCaretPosition') - 1;
      var txt = ctrl.val();
      var lastbegin = txt.lastIndexOf("[[", pos);
      var lastend = txt.lastIndexOf("]]", pos);
      var isLink = lastbegin > lastend;
      if (isLink) {
        mode = 'link';
        fillLinksList(res, txt.substr(lastbegin + 2, pos - lastbegin));
      } else {
        lastbegin = txt.lastIndexOf("{{", pos);
        lastend = txt.lastIndexOf("}}", pos);
        var isTemplate = lastbegin > lastend;
        if (isTemplate) {
          var prefixName = mw.config.get('wgFormattedNamespaces')[10] + ':' + txt.substr(lastbegin + 2, pos - lastbegin - 1);
          mode = prefixName.indexOf('|') > -1 ? 'templateParams' : 'template';
          fillLinksList(res, prefixName);
        } else {
          mode = "none";
          res([]);
        }
      }
    }
    function resolveTempalte(templateName) {
      var dfd = new jQuery.Deferred();
      if (!templateName) return dfd.reject().promise();
      if (templateDataCache[templateName]) return dfd.resolve(templateDataCache[templateName]).promise();
      var api = new mw.Api();
      api.get({
        action: 'templatedata',
        titles: templateName,
        redirects: 1
      }).done(function (data) {
        if (!data.pages) return dfd.reject();
        for (var pageid in data.pages) {
          templateDataCache[templateName] = data.pages[pageid];
          dfd.resolve(templateDataCache[templateName]);
        }
        if (!templateDataCache[templateName]) dfd.reject();
      });
      return dfd.promise();
    }
    function resolveApi(queryType, queryValue) {
      var dfd = new jQuery.Deferred(),
        api = new mw.Api();
      switch (queryType) {
        case 'users':
          api.get({
            action: 'query',
            list: 'allusers',
            auactiveusers: 1,
            auprefix: queryValue
          }).done(function (data) {
            if (data && data.query && data.query.allusers) dfd.resolve($.map(data.query.allusers, function (e) {
              return e.name;
            }));else dfd.reject();
          });
          break;
        case 'pages':
          api.get({
            action: 'opensearch',
            search: queryValue
          }).done(function (data) {
            if (data[1]) dfd.resolve(settings.filterResponse(data[1]));else dfd.reject();
          });
          break;
        default:
          throw 'unexpected queryType';
      }
      return dfd.promise();
    }
    function fillLinksList(res, txt) {
      txt = $.trim(txt);
      if (txt.length <= 1 || mode != 'templateParams' && txt.indexOf('|') > -1 || txt.indexOf('#') > -1 && mw.config.get('wgNamespaceNumber') === 0) res([]);else if (mode === 'templateParams') {
        var templateMatch = /(.+?)\|(?:.*\|)?([^=]+$)/.exec(txt);
        var templateParamMatch = /(.+?)\|(?:.*\|)?([^=]+=[^=]+$)/.exec(txt);
        $.when(resolveTempalte(templateMatch && templateMatch[1] || templateParamMatch && templateParamMatch[1])).done(function (td) {
          var curTemplateData = td,
            suggestions = [],
            curParamIndex = txt.split('|').length - 1;
          if (templateParamMatch && !templateMatch) {
            var paramNameVal = templateParamMatch[2].split('=');
            if (paramNameVal[0] in curTemplateData.params && 'suggestedvalues' in curTemplateData.params[paramNameVal[0]]) {
              mode = 'templateValue';
              var _iterator = _createForOfIteratorHelper(curTemplateData.params[paramNameVal[0]].suggestedvalues),
                _step;
              try {
                for (_iterator.s(); !(_step = _iterator.n()).done;) {
                  var suggestedVal = _step.value;
                  if (suggestedVal.indexOf(paramNameVal[1]) == 0) suggestions.push(paramNameVal[0] + '=' + suggestedVal);
                }
              } catch (err) {
                _iterator.e(err);
              } finally {
                _iterator.f();
              }
            }
          } else {
            for (var paramName in curTemplateData.params) {
              if (paramName == curParamIndex) {
                var paramValue = templateMatch[2];
                var dfd;
                switch (curTemplateData.params[paramName].type) {
                  case 'wiki-page-name':
                    dfd = $.when(resolveApi('pages', paramValue));
                    mode = 'templateValue';
                    break;
                  case 'wiki-file-name':
                    dfd = $.when(resolveApi('pages', 'File:' + paramValue));
                    mode = 'templateValue';
                    break;
                  case 'wiki-template-name':
                    dfd = $.when(resolveApi('pages', 'Template:' + paramValue));
                    mode = 'templateValue';
                    break;
                  case 'wiki-user-name':
                    dfd = $.when(resolveApi('users', paramValue));
                    mode = 'templateValue';
                    break;
                  case 'string':
                    if ('suggestedvalues' in curTemplateData.params[paramName]) {
                      mode = 'templateValue';
                      var _iterator2 = _createForOfIteratorHelper(curTemplateData.params[paramName].suggestedvalues),
                        _step2;
                      try {
                        for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
                          var _suggestedVal = _step2.value;
                          if (_suggestedVal.indexOf(paramValue) == 0) suggestions.push(_suggestedVal);
                        }
                      } catch (err) {
                        _iterator2.e(err);
                      } finally {
                        _iterator2.f();
                      }
                      return res(suggestions);
                    } else return res([]);
                  default:
                    return res([]);
                  // dont suggest for this indexed param
                }

                return dfd.done(res).fail(function () {
                  res([]);
                });
              }
              if (paramName === '1' || txt.indexOf(paramName) > -1) continue; //dont suggest used params
              suggestions.push(paramName);
            }
          }
          res(suggestions);
        }).fail(res);
      } else if (txt.indexOf('#') > -1) {
        var pageTitle = txt.substr(0, txt.indexOf('#'));
        var sectionPrefix = txt.substr(txt.indexOf('#') + 1);
        var api = new mw.Api();
        api.get({
          action: 'parse',
          page: pageTitle,
          prop: 'sections'
        }).done(function (data) {
          if (data && data.parse && data.parse.sections) res($(data.parse.sections).map(function () {
            return this.line.indexOf(sectionPrefix) == 0 ? pageTitle + '#' + this.line.replace(/[|\[\]\{\}]/g, escape) : null;
          }));
        });
      } else {
        $.when(resolveApi('pages', txt)).done(res).fail(function () {
          res([]);
        });
      }
    }
    ctrl.autocomplete({
      source: function source(request, response) {
        if (fixArrowsBug(this)) response([]);else findLinks(response);
      },
      focus: function focus() {
        return false;
      },
      select: function select(e, ui) {
        settings.onselected(ui.item.value);
        return false;
      },
      open: function open() {
        $(".ui-autocomplete").css(settings.menuCSS).position({
          my: settings.positionMy,
          at: settings.positionAt,
          of: settings.positionOf,
          offset: settings.positionOffset,
          collision: 'none fit'
        }).find('li').css(settings.itemCSS);
      }
    });
    var fixed,
      stfu,
      escapes = 0;
    //this is hack to prevent known serious bug in autocomplete.js that prevent default of the up and down key which may drive you crazy....
    function fixArrowsBug(self) {
      if (fixed) return false;
      fixed = true;

      // on click selection may change. close the menu
      ctrl.on("click.autocomplete", function (e) {
        clearTimeout(self.searching);
        self.close();
      });
      ctrl.off("keydown.autocomplete");
      ctrl.off("keydown.autocomplete0");
      ctrl.on("keydown.autocomplete", function (event) {
        var keyCode = $.ui.keyCode;
        // hack to allow cancelling the gadget: mostly useful when editing templates.
        escapes = event.keyCode == keyCode.ESCAPE ? escapes + 1 : 0;
        if (stfu || (stfu = escapes >= 3)) {
          self.close(event);
          return;
        }
        switch (event.keyCode) {
          case keyCode.PAGE_UP:
            self._move("previousPage", event);
            break;
          case keyCode.PAGE_DOWN:
            self._move("nextPage", event);
            break;
          case keyCode.UP:
            if (!self.menu.element.is(":visible")) return;
            self._move("previous", event);
            // prevent moving cursor to beginning of text field in some browsers
            event.preventDefault();
            break;
          case keyCode.DOWN:
            if (!self.menu.element.is(":visible")) return;
            self._move("next", event);
            // prevent moving cursor to end of text field in some browsers
            event.preventDefault();
            break;
          case keyCode.ENTER:
          case keyCode.NUMPAD_ENTER:
            // when menu is open or has focus
            if (self.menu.active) {
              event.preventDefault();
            }
          //passthrough - ENTER and TAB both select the current element
          case keyCode.TAB:
            if (!self.menu.active) {
              return;
            }
            self.menu.select(event);
            break;
          case keyCode.ESCAPE:
            self.element.val(self.term);
            self.close(event);
            break;
          case keyCode.SHIFT:
          case keyCode.CONTROL:
          case keyCode.ALT:
          case keyCode.COMMAND:
          case keyCode.COMMAND_RIGHT:
          case keyCode.INSERT:
          case keyCode.CAPS_LOCK:
          case keyCode.END:
          case keyCode.HOME:
          case keyCode.LEFT:
          case keyCode.RIGHT:
            // ignore metakeys (shift, ctrl, alt)
            break;
          default:
            // keypress is triggered before the input value is changed
            clearTimeout(self.searching);
            self.searching = setTimeout(function () {
              self.search(null, event);
            }, self.options.delay);
            break;
        }
      });
      return true;
    }
  };
});
if ($.inArray(mw.config.get('wgAction'), ['edit', 'submit']) + 1) mw.loader.using(['jquery.ui', 'jquery.textSelection'], function () {
  //enable autocomplete for editbox, relative to editform in an offset of -80 vertical
  $("#wpTextbox1").autoCompleteWikiText({
    positionAt: $('#wpTextbox1').prop('dir') == 'rtl' ? "left top" : "right top",
    positionOf: '#editform',
    positionOffset: "0 0",
    menuCSS: {
      background: '#E0EEF7',
      opacity: 0.8
    },
    itemCSS: {
      padding: 0,
      margin: 0
    }
  });
});