MediaWiki:ConvenientDiscussions.js.map.json

From Fallen London Wiki (Staging)

Note: After saving, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Go to Menu → Settings (Opera → Preferences on a Mac) and then to Privacy & security → Clear browsing data → Cached images and files.
version3
sources
"webpack:///webpack/bootstrap"
"webpack:///./node_modules/@babel/runtime/helpers/asyncToGenerator.js"
"webpack:///./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js"
"webpack:///./node_modules/css-loader/dist/runtime/api.js"
"webpack:///./node_modules/lz-string/libs/lz-string.js"
"webpack:///./node_modules/nano-css/index.js"
"webpack:///./src/less/global.less?98b0"
"webpack:///./node_modules/locutus/php/strings/html_entity_decode.js"
"webpack:///./src/js/worker-gate.js"
"webpack:///./dist/convenientDiscussions-i18n/en.js"
"webpack:///./node_modules/locutus/php/strings/get_html_translation_table.js"
"webpack:///./src/tribute/tribute.less?2f00"
"webpack:///./src/tribute/tribute.less"
"webpack:///./node_modules/worker-loader/dist/workers/InlineWorker.js"
"webpack:///./src/less/global.less"
"webpack:///./src/less/Comment.less?37c7"
"webpack:///./src/less/Comment.less"
"webpack:///./src/less/CommentForm.less?1f2b"
"webpack:///./src/less/CommentForm.less"
"webpack:///./src/less/Section.less?2b8c"
"webpack:///./src/less/Section.less"
"webpack:///./src/less/commentLayers.less?c551"
"webpack:///./src/less/commentLayers.less"
"webpack:///./src/less/navPanel.less?dd40"
"webpack:///./src/less/navPanel.less"
"webpack:///./src/less/skin.less?117c"
"webpack:///./src/less/skin.less"
"webpack:///./src/less/talkPage.less?e28e"
"webpack:///./src/less/talkPage.less"
"webpack:///./src/less/logPages.less?e8c5"
"webpack:///./src/less/logPages.less"
"webpack:///./src/js/cd.js"
"webpack:///./src/js/CdError.js"
"webpack:///./src/tribute/TributeEvents.js"
"webpack:///./src/tribute/TributeMenuEvents.js"
"webpack:///./src/tribute/TributeRange.js"
"webpack:///./src/tribute/TributeSearch.js"
"webpack:///./src/tribute/Tribute.js"
"webpack:///./src/js/util.js"
"webpack:///./src/js/userRegistry.js"
"webpack:///./src/js/options.js"
"webpack:///./src/js/apiWrappers.js"
"webpack:///./src/js/Autocomplete.js"
"webpack:///./src/js/CommentFormStatic.js"
"webpack:///./src/js/timestamp.js"
"webpack:///./src/js/wikitext.js"
"webpack:///./src/js/Page.js"
"webpack:///./src/js/treeWalker.js"
"webpack:///./src/js/commentLayers.js"
"webpack:///./src/js/currentSection.js"
"webpack:///./src/js/jqueryExtensions.js"
"webpack:///./src/js/Parser.js"
"webpack:///./src/js/processPage.js"
"webpack:///./src/js/siteData.js"
"webpack:///./src/js/boot.js"
"webpack:///./src/js/toc.js"
"webpack:///./src/js/updateChecker.js"
"webpack:///./src/js/navPanel.js"
"webpack:///./src/js/eventHandlers.js"
"webpack:///./src/js/ooui.js"
"webpack:///./src/js/modal.js"
"webpack:///./src/js/SectionStatic.js"
"webpack:///./src/js/Section.js"
"webpack:///./src/js/SectionSkeleton.js"
"webpack:///./src/js/CommentForm.js"
"webpack:///./src/js/CommentStatic.js"
"webpack:///./src/js/Comment.js"
"webpack:///./src/js/commentLinks.js"
"webpack:///./src/js/CommentSkeleton.js"
"webpack:///./src/js/debug.js"
"webpack:///./src/js/defaultConfig.js"
"webpack:///./src/js/staticGlobals.js"
"webpack:///./src/js/globalUtil.js"
"webpack:///./src/js/app.js"
names
"installedModules"
"__webpack_require__"
"moduleId"
"exports"
"module"
"i"
"l"
"modules"
"call"
"m"
"c"
"d"
"name"
"getter"
"o"
"Object"
"defineProperty"
"enumerable"
"get"
"r"
"Symbol"
"toStringTag"
"value"
"t"
"mode"
"__esModule"
"ns"
"create"
"key"
"bind"
"n"
"object"
"property"
"prototype"
"hasOwnProperty"
"p"
"s"
"asyncGeneratorStep"
"gen"
"resolve"
"reject"
"_next"
"_throw"
"arg"
"info"
"error"
"done"
"Promise"
"then"
"fn"
"self"
"this"
"args"
"arguments"
"apply"
"err"
"undefined"
"memo"
"isOldIE"
"Boolean"
"window"
"document"
"all"
"atob"
"getTarget"
"target"
"styleTarget"
"querySelector"
"HTMLIFrameElement"
"contentDocument"
"head"
"e"
"stylesInDom"
"getIndexByIdentifier"
"identifier"
"result"
"length"
"modulesToDom"
"list"
"options"
"idCountMap"
"identifiers"
"item"
"id"
"base"
"count"
"concat"
"index"
"obj"
"css"
"media"
"sourceMap"
"references"
"updater"
"push"
"addStyle"
"insertStyleElement"
"style"
"createElement"
"attributes"
"nonce"
"keys"
"forEach"
"setAttribute"
"insert"
"Error"
"appendChild"
"textStore"
"replaceText"
"replacement"
"filter"
"join"
"applyToSingletonTag"
"remove"
"styleSheet"
"cssText"
"cssNode"
"createTextNode"
"childNodes"
"removeChild"
"insertBefore"
"applyToTag"
"removeAttribute"
"btoa"
"unescape"
"encodeURIComponent"
"JSON"
"stringify"
"firstChild"
"singleton"
"singletonCounter"
"update"
"styleIndex"
"parentNode"
"removeStyleElement"
"newObj"
"lastIdentifiers"
"newList"
"toString"
"newLastIdentifiers"
"_i"
"_index"
"splice"
"useSourceMap"
"map"
"content"
"cssMapping"
"sourceMapping"
"base64"
"data"
"sourceURLs"
"sources"
"source"
"sourceRoot"
"cssWithMappingToString"
"mediaQuery"
"dedupe"
"alreadyImportedModules"
"LZString"
"f"
"String"
"fromCharCode"
"keyStrBase64"
"keyStrUriSafe"
"baseReverseDic"
"getBaseValue"
"alphabet"
"character"
"charAt"
"compressToBase64"
"input"
"res"
"_compress"
"a"
"decompressFromBase64"
"_decompress"
"compressToUTF16"
"decompressFromUTF16"
"compressed"
"charCodeAt"
"compressToUint8Array"
"uncompressed"
"compress"
"buf"
"Uint8Array"
"TotalLen"
"current_value"
"decompressFromUint8Array"
"decompress"
"Array"
"compressToEncodedURIComponent"
"decompressFromEncodedURIComponent"
"replace"
"bitsPerChar"
"getCharFromInt"
"ii"
"context_dictionary"
"context_dictionaryToCreate"
"context_c"
"context_wc"
"context_w"
"context_enlargeIn"
"context_dictSize"
"context_numBits"
"context_data"
"context_data_val"
"context_data_position"
"Math"
"pow"
"resetValue"
"getNextValue"
"w"
"bits"
"resb"
"maxpower"
"power"
"dictionary"
"enlargeIn"
"dictSize"
"numBits"
"entry"
"val"
"position"
"KEBAB_REGEX"
"config"
"assign"
"renderer"
"raw"
"pfx"
"client"
"kebab"
"prop"
"toLowerCase"
"decl"
"hash"
"str"
"selector"
"parent"
"putRaw"
"rawCssRule"
"sh"
"sheet"
"insertRule"
"cssRules"
"put"
"decls"
"atrule"
"postponed"
"putAt"
"api"
"default"
"locals"
"string"
"quoteStyle"
"getHtmlTranslationTable"
"tmpStr"
"entity"
"symbol"
"hashMap"
"split"
"require"
"convenientDiscussions"
"i18n"
"table"
"decimal"
"useTable"
"useQuoteStyle"
"entities"
"constMappingTable"
"constMappingQuoteStyle"
"isNaN"
"toUpperCase"
"___CSS_LOADER_API_IMPORT___"
"URL"
"webkitURL"
"url"
"blob"
"BlobBuilder"
"WebKitBlobBuilder"
"MozBlobBuilder"
"MSBlobBuilder"
"append"
"getBlob"
"Blob"
"Worker"
"createObjectURL"
"context"
"CdError"
"constructor"
"message"
"type"
"code"
"apiData"
"super"
"TributeEvents"
"tribute"
"events"
"element"
"boundKeydown"
"keydown"
"boundKeyup"
"keyup"
"boundInput"
"addEventListener"
"unbind"
"removeEventListener"
"instance"
"event"
"commandEvent"
"keyCode"
"callbacks"
"inputEvent"
"click"
"which"
"menu"
"contains"
"li"
"preventDefault"
"stopPropagation"
"nodeName"
"selectItemAtIndex"
"getAttribute"
"hideMenu"
"current"
"externalTrigger"
"setTimeout"
"isActive"
"updateSelection"
"triggerPos"
"lastCanceledTriggerPos"
"triggerChar"
"lastCanceledTriggerChar"
"allowSpaces"
"hasTrailingSpace"
"dropMenu"
"mentionText"
"trigger"
"collection"
"menuShowMinLength"
"showMenuFor"
"shouldDeactivate"
"eventKeyPressed"
"el"
"range"
"getTriggerInfo"
"selectedPath"
"mentionSelectedPath"
"selectedOffset"
"mentionSelectedOffset"
"mentionTriggerChar"
"pre"
"slice"
"selectionStart"
"lastIndexOf"
"collectionItem"
"find"
"enter"
"filteredItems"
"menuSelected"
"escape"
"tab"
"up"
"selected"
"setActiveLi"
"scrollTop"
"scrollHeight"
"down"
"lis"
"querySelectorAll"
"parseInt"
"classList"
"add"
"selectClass"
"liClientRect"
"getBoundingClientRect"
"menuClientRect"
"bottom"
"scrollDistance"
"top"
"getFullHeight"
"elem"
"includeMargin"
"height"
"currentStyle"
"getComputedStyle"
"parseFloat"
"marginTop"
"marginBottom"
"TributeMenuEvents"
"menuEvents"
"menuClickEvent"
"menuContainerScrollEvent"
"debounce"
"windowResizeEvent"
"positionMenuAtCaret"
"menuContainer"
"func"
"wait"
"immediate"
"timeout"
"callNow"
"clearTimeout"
"punctuationRegexp"
"TributeRange"
"scrollTo"
"coordinates"
"positionMenu"
"getTextAreaOrInputUnderlinePosition"
"mentionPosition"
"left"
"right"
"additionalStyles"
"scrollIntoView"
"body"
"selectElement"
"targetElement"
"path"
"offset"
"nextSibling"
"previousSibling"
"sel"
"getSelection"
"createRange"
"setStart"
"setEnd"
"collapse"
"removeAllRanges"
"console"
"warn"
"addRange"
"focus"
"replaceTriggerText"
"requireLeadingSpace"
"originalEvent"
"replaceEvent"
"CustomEvent"
"detail"
"start"
"end"
"ctrlKey"
"ctrlModify"
"myField"
"endPos"
"ending"
"substring"
"shiftKey"
"altKey"
"shiftModify"
"startPos"
"selectionEnd"
"keepAsEnd"
"match"
"text"
"replaceTextSuffix"
"execCommand"
"typeContent"
"dispatchEvent"
"bubbles"
"getNodePositionInParent"
"getTextPrecedingCurrentSelection"
"textComponent"
"menuAlreadyActive"
"effectiveRange"
"currentTriggerSnippet"
"originalCurrentTriggerSnippet"
"leadingSpace"
"regex"
"mostRecentTriggerCharPos"
"mostRecentTriggerCharLength"
"idx"
"lastIndexWithLeadingSpace"
"inputOk"
"test"
"firstSnippetChar"
"trim"
"includes"
"mentionSelectedElement"
"reversedStr"
"reverse"
"cidx"
"len"
"firstChar"
"triggerIdx"
"isMenuOffScreen"
"menuDimensions"
"windowWidth"
"innerWidth"
"windowHeight"
"innerHeight"
"doc"
"documentElement"
"windowLeft"
"pageXOffset"
"scrollLeft"
"clientLeft"
"windowTop"
"pageYOffset"
"clientTop"
"menuTop"
"menuRight"
"width"
"menuBottom"
"menuLeft"
"floor"
"ceil"
"getMenuDimensions"
"dimensions"
"offsetWidth"
"offsetHeight"
"isFirefox"
"mozInnerScreenX"
"div"
"computed"
"whiteSpace"
"wordWrap"
"visibility"
"overflowY"
"overflow"
"textContent"
"triggerSpan"
"span"
"clientWidth"
"clientHeight"
"rect"
"menuContainerIsBody"
"offsetTop"
"borderTopWidth"
"fontSize"
"isRtl"
"offsetLeft"
"menuIsOffScreen"
"paddingTop"
"clientRect"
"elemTop"
"elemBottom"
"maxY"
"targetY"
"TributeSearch"
"search"
"pattern"
"opts"
"post"
"compareString"
"caseSensitive"
"skip"
"rendered"
"score"
"patternCache"
"traverse"
"render"
"cache"
"stringIndex"
"patternIndex"
"calculateScore"
"best"
"temp"
"indexOf"
"pop"
"indices"
"arr"
"reduce"
"prev"
"extract"
"original"
"sort"
"b"
"compare"
"Tribute"
"values"
"containerClass"
"itemClass"
"selectTemplate"
"menuItemTemplate"
"lookup"
"fillAttr"
"noMatchTemplate"
"searchOpts"
"menuItemLimit"
"defaultSelectTemplate"
"defaultMenuItemTemplate"
"_isActive"
"noMatchEvent"
"matchItem"
"triggers"
"attach"
"jQuery"
"NodeList"
"HTMLCollection"
"_attach"
"hasAttribute"
"createMenu"
"wrapper"
"ul"
"className"
"processValues"
"items"
"innerHTML"
"fragment"
"createDocumentFragment"
"_findLiTarget"
"movementY"
"snapshot"
"tributeMenu"
"showMenuForCollection"
"collectionIndex"
"activeElement"
"placeCaretAtEnd"
"insertAtCaret"
"selectNodeContents"
"createTextRange"
"textRange"
"moveToElementText"
"select"
"textarea"
"scrollPos"
"caretPos"
"hasInsertedViaCommand"
"front"
"back"
"_append"
"newValues"
"appendCurrent"
"detach"
"_detach"
"keptScrollPosition"
"keptTocHeight"
"unique"
"transparentize"
"color"
"dummyElement"
"isInline"
"node"
"countTextNodesAsInline"
"nodeType"
"Node"
"TEXT_NODE"
"ELEMENT_NODE"
"cd"
"g"
"POPULAR_INLINE_ELEMENTS"
"tagName"
"POPULAR_NOT_INLINE_ELEMENTS"
"display"
"startsWith"
"caseInsensitiveFirstCharPattern"
"mw"
"util"
"escapeRegExp"
"isProbablyTalkPage"
"pageName"
"namespaceNumber"
"PAGE_WHITELIST_REGEXP"
"customTalkNamespaces"
"PAGE_BLACKLIST_REGEXP"
"isCommentEdit"
"summary"
"isUndo"
"undoTexts"
"some"
"defined"
"reorderArray"
"startIndex"
"handleApiReject"
"underlinesToSpaces"
"spacesToUnderlines"
"removeDoubleSpaces"
"firstCharToUpperCase"
"char"
"PHP_CHAR_TO_UPPER_JSON"
"phpCharToUpper"
"getMessages"
"messages"
"msg"
"isInputFocused"
"$"
"mergeRegexps"
"regexpOrString"
"RegExp"
"hideText"
"regexp"
"hidden"
"useAlternativeMarker"
"preText"
"textToHide"
"unhideText"
"num"
"saveScrollPosition"
"saveTocHeight"
"$toc"
"isTocFloating"
"outerHeight"
"restoreScrollPosition"
"resetTocHeight"
"promise"
"race"
"dealWithLoadingBug"
"moduleName"
"loader"
"getState"
"$body"
"wrap"
"sParse"
"location"
"reload"
"notify"
"getExtendedRect"
"convenientDiscussionsMarginTop"
"convenientDiscussionsMarginBottom"
"outerTop"
"outerBottom"
"areObjectsEqual"
"object1"
"object2"
"doesInclude"
"isMultipartObject"
"Date"
"toPrimitiveValue"
"keys1"
"keys2"
"every"
"getFromLocalStorage"
"json"
"localStorage"
"getItem"
"parse"
"saveToLocalStorage"
"setItem"
"removeDirMarks"
"insertText"
"insertContent"
"keepWorkerSafeValues"
"allowedFuncNames"
"disallowedNames"
"calculateWordsOverlap"
"s1"
"s2"
"LETTER_PATTERN"
"words1"
"words2"
"total"
"overlap"
"word1"
"word2"
"users"
"getUser"
"isIPv6Address"
"CURRENT_USER_NAME"
"gender"
"CURRENT_USER_GENDER"
"User"
"Map"
"isRegistered"
"cachedIsRegistered"
"isIPAddress"
"setGender"
"set"
"getGender"
"packVisits"
"visits"
"packWatchedSections"
"watchedSections"
"pageId"
"getSettings"
"omitLocal"
"reuse"
"getUserInfo"
"globalSettings"
"localSettings"
"SETTINGS_OPTION_NAME"
"LOCAL_SETTINGS_OPTION_NAME"
"settings"
"defaultSettings"
"settingAliases"
"alias"
"getLocalOverridingSettings"
"varLocalAlias"
"setSettings"
"localSettingNames"
"setLocalOption"
"setGlobalOption"
"getVisits"
"isFirstRun"
"user"
"VISITS_OPTION_NAME"
"articleId"
"thisPageVisits"
"cleanUpVisits"
"originalVisits"
"timestamps"
"acc"
"boundary"
"visit"
"setVisits"
"visitsString"
"visitsStringCompressed"
"lzString"
"getWatchedSections"
"keptData"
"WATCHED_SECTIONS_OPTION_NAME"
"thisPageWatchedSections"
"justWatchedSection"
"justUnwatchedSection"
"setWatchedSections"
"watchedSectionsString"
"watchedSectionsStringCompressed"
"cachedUserInfoRequest"
"currentAutocompletePromise"
"makeBackgroundRequest"
"params"
"method"
"success"
"resp"
"jqXHR"
"textStatus"
"parseCode"
"customOptions"
"defaultOptions"
"action"
"contentmodel"
"pst"
"disablelimitreport"
"formatversion"
"html"
"load"
"modulestyles"
"parsedSummary"
"parsedsummary"
"Api"
"meta"
"uiprop"
"userinfo"
"query"
"rights"
"visitsCompressed"
"exec"
"unpackVisits"
"watchedSectionsCompressed"
"pages"
"isPageId"
"unpackWatchedSections"
"CURRENT_USER_RIGHTS"
"unknownApiErrorText"
"errorCode"
"errorInfo"
"getPageTitles"
"pageIds"
"limit"
"nextPageIds"
"pageids"
"catch"
"thisPages"
"getPageIds"
"pageTitles"
"normalized"
"redirects"
"nextPageTitles"
"titles"
"setOption"
"details"
"assertCurrentUser"
"optionname"
"optionvalue"
"getUserGenders"
"requestInBackground"
"usersToRequest"
"nextUsers"
"ususers"
"usprop"
"userRegistry"
"Autocomplete"
"types"
"inputs"
"comments"
"defaultUserNames"
"autocompleteTypes"
"collections"
"getCollections"
"SITE_DIR"
"$input"
"cdInput"
"activeAutocompleteMenu"
"OO"
"ui"
"MultilineTextInputWidget"
"on"
"transform"
"prepareValues"
"isArray"
"spacesRegexp"
"mws"
"collectionsByType"
"mentions"
"mentionCharacter"
"mentionRequiresLeadingSpace"
"callback"
"byText"
"matches"
"makeRequest"
"namespace"
"USER_NAMESPACES_REGEXP"
"getRelevantUserNames"
"removeSelf"
"wikilinks"
"valid"
"ALL_NAMESPACES_REGEXP"
"colonPrefix"
"COLON_NAMESPACES_PREFIX_REGEXP"
"getRelevantPageNames"
"templates"
"useTemplateData"
"setDisabled"
"pushPending"
"paramsString"
"firstValueIndex"
"template"
"paramOrder"
"param"
"required"
"suggested"
"format"
"caretIndex"
"getRange"
"to"
"selectRange"
"always"
"popPending"
"endsWith"
"getRelevantTemplateNames"
"tags"
"tag"
"commentLinks"
"comment"
"snippet"
"anchor"
"author"
"timestamp"
"getText"
"spacePos"
"authortimestamp"
"getConfig"
"userNamespace"
"userNamespacesByGender"
"containsRegexp"
"startsWithRegexp"
"item1"
"item2"
"item1StartsWith"
"item2StartsWith"
"lastFocused"
"commentForm1"
"commentForm2"
"lastFocused1"
"lastFocused2"
"getDefaultPreloadConfig"
"editIntro"
"commentTemplate"
"headline"
"noHeadline"
"omitSignature"
"modeToProperty"
"getLastActive"
"commentForms"
"getLastActiveAltered"
"commentForm"
"isAltered"
"createAddSectionForm"
"preloadConfig"
"CommentForm"
"isNewTopicOnTop"
"addSectionForm"
"$element"
"cdScrollIntoView"
"headlineInput"
"CURRENT_PAGE"
"parseTimestampRegexp"
"parseTimestampRegexpNoTimezone"
"parseTimestamp"
"timezoneOffset"
"TIMESTAMP_REGEXP"
"TIMESTAMP_REGEXP_NO_TIMEZONE"
"date"
"TIMESTAMP_PARSER"
"zeroPad"
"number"
"formatDate"
"DATE_FORMAT"
"getUTCMonth"
"getUTCDate"
"getUTCDay"
"getDay"
"getUTCFullYear"
"getUTCHours"
"getUTCMinutes"
"endQuote"
"substr"
"generateCommentAnchor"
"resolveCollisions"
"year"
"month"
"day"
"hours"
"minutes"
"commentAnchors"
"anchorNum"
"registerCommentAnchor"
"resetCommentAnchors"
"parseCommentAnchor"
"commentAnchor"
"Number"
"UTC"
"hideDistractingCode"
"replaceMarks"
"newCode"
"before"
"after"
"repeat"
"newline"
"findFirstTimestamp"
"signatures"
"extractSignatures"
"removeWikiMarkup"
"FILE_LINK_REGEXP"
"normalizeCode"
"decodeHtmlEntities"
"encodeWikilink"
"link"
"generateCommentAnchors"
"adjustedCode"
"QUOTE_REGEXP"
"beginning"
"COMMENT_ANTIPATTERNS_REGEXP"
"adjustedCodeForUnsigneds"
"timestampRegexp"
"signatureRegexp"
"CAPTURE_USER_NAME_PATTERN"
"authorLinkRegexp"
"timestampMatch"
"line"
"lastIndex"
"authorTimestampMatch"
"endIndex"
"nextCommentStartIndex"
"dirtyCode"
"authorLinkMatch"
"commentEndingStartIndex"
"max"
"commentEnding"
"extractRegularSignatures"
"unsigneds"
"UNSIGNED_TEMPLATES_REGEXP"
"relevantSignatureIndex"
"findIndex"
"sig"
"extractUnsigneds"
"sig1"
"sig2"
"commentStartIndex"
"html_entity_decode"
"hideTemplatesRecursively"
"concealFirstMarkerLength"
"pos"
"stack"
"hideSensitiveCode"
"hide"
"isTable"
"hideTags"
"hideTemplates"
"endWithTwoNewlines"
"Page"
"nameOrMwTitle"
"title"
"Title"
"newFromText"
"getMainText"
"getPrefixedText"
"getNamespaceId"
"getUrl"
"parameters"
"realName"
"isArchivePage"
"cachedIsArchivePage"
"iterator"
"SOURCE_PAGES_MAP"
"sourceRegexp"
"canHaveArchives"
"PAGES_WITHOUT_ARCHIVES_REGEXP"
"getArchivePrefix"
"ARCHIVE_PAGES_MAP"
"entries"
"getArchivedPage"
"archiveRegexp"
"getCode"
"tolerateMissing"
"rvslots"
"rvprop"
"curtimestamp"
"page"
"revision"
"revisions"
"slots"
"main"
"missing"
"queryTimestamp"
"invalid"
"redirectTarget"
"pageid"
"revisionId"
"revid"
"markAsRead"
"oldid"
"request"
"getRevisions"
"modifyCode"
"pageCode"
"commentCode"
"commentTextToCode"
"newPageCode"
"codeBeforeInsertion"
"firstSectionStartIndex"
"trimLeft"
"edit"
"postWithEditToken"
"logMessage"
"isRawMessage"
"spamblacklist"
"loadMessagesIfMissing"
"description"
"abusefilter"
"plain"
"newtimestamp"
"analyzeNewTopicPlacement"
"areNewTopicsOnTop"
"sectionHeadingRegexp"
"sectionHeadingMatch"
"previousDate"
"difference"
"purge"
"newerthanrevid"
"TreeWalker"
"root"
"acceptNode"
"onlyElementNodes"
"startNode"
"currentNode"
"firstChildProperty"
"lastChildProperty"
"previousSiblingProperty"
"nextSiblingProperty"
"tryMove"
"lastChild"
"nextNode"
"previousNode"
"ElementsTreeWalker"
"rootElement"
"ElementsAndTextTreeWalker"
"underlays"
"layersContainers"
"redrawIfNecessary"
"removeUnhighlighted"
"redrawAll"
"container"
"cdCouldHaveMoved"
"rootBottom"
"$root"
"floatingRects"
"notMovedCount"
"shouldBeHighlighted"
"isNew"
"isOwn"
"highlightOwnComments"
"isTarget"
"isFocused"
"isDeleted"
"isUnderBottom"
"positions"
"$underlay"
"removeLayers"
"editForm"
"floatingElements"
"isMoved"
"configureLayers"
"getLayersContainer"
"closest"
"updateLayersPositions"
"reset"
"currentSection"
"mount"
"attr"
"appendTo"
"sections"
"$heading"
"section"
"extendedRect"
"empty"
"getParentTree"
"sectionInTree"
"level"
"addClass"
"cdScrollTo"
"cdRemoveNonElementNodes"
"alignment"
"smooth"
"autoScrollInProgress"
"$elements"
"first"
"offsetTopLast"
"last"
"offsetBottom"
"min"
"onComplete"
"handleScroll"
"navPanel"
"updateCommentFormButton"
"animate"
"complete"
"cdIsInViewport"
"partially"
"wasHidden"
"show"
"elementTop"
"elementBottom"
"viewportTop"
"viewportBottom"
"cdGetText"
"from"
"cloneNode"
"innerText"
"cdAddCloseButton"
"$closeButton"
"prepend"
"foreignComponentClasses"
"timezoneRegexp"
"signatureEndingRegexp"
"elementsToExclude"
"getUserNameFromLink"
"href"
"userName"
"decodeURIComponent"
"uri"
"Uri"
"ARTICLE_PATH_REGEXP"
"getPageNameFromUrl"
"CONTRIBS_PAGE"
"CONTRIBS_PAGE_LINK_REGEXP"
"IS_IPv6_ADDRESS"
"CURRENT_NAMESPACE_NUMBER"
"CURRENT_PAGE_TITLE"
"isCellOfMultiCommentTable"
"getElementsByClassName"
"Parser"
"closedDiscussionClasses"
"pageHasOutdents"
"TIMEZONE_REGEXP"
"createComment"
"signature"
"CommentClass"
"createSection"
"headingElement"
"watchedSectionsRequest"
"SectionClass"
"findTimestamps"
"getElementsByTagName"
"elementsToExcludeClasses"
"getAllTextNodes"
"finding"
"textNode"
"remainedText"
"afterNode"
"findSignatures"
"timestampElement"
"timestampText"
"unsignedElement"
"closestNotInlineAncestor"
"unsignedClass"
"isUnsigned"
"cniaChildren"
"childElementsProperty"
"treeWalker"
"startElement"
"authorName"
"firstSignatureElement"
"signatureNodes"
"hasAuthorLinks"
"signatureScanLimit"
"firstSignatureElementIndex"
"signatureContainer"
"startElementNextSibling"
"getElementByClassName"
"follows"
"collectParts"
"signatureElement"
"firstForeignComponentAfter"
"parts"
"isTextNode"
"isHeading"
"hasCurrentSignature"
"hasForeignComponents"
"lastStep"
"previousPart"
"haveDived"
"previousElementSibling"
"checkForCustomForeignComponents"
"removeNestedParts"
"part"
"nextDiveElementIndex"
"j"
"encloseInlineParts"
"sequencesToBeEnclosed"
"encloseThis"
"sequence"
"newNode"
"filterParts"
"replaceListsWithItems"
"lastPart"
"partTextNoSpaces"
"children"
"child"
"newParts"
"getLevelsUpTree"
"initialElement"
"levelElements"
"unshift"
"findHeadings"
"headings"
"heading1"
"heading2"
"prepare"
"messagesRequest"
"$content"
"toc"
"init"
"commentLayers"
"getFirstElementInViewportData"
"firstElementChild"
"evaluate"
"XPathResult"
"ANY_TYPE"
"textNodes"
"iterateNext"
"findSpecialElements"
"floatingElementsSelector"
"FLOATING_ELEMENT_SELECTORS"
"customFloatingElementSelectors"
"closedDiscussionsSelector"
"closedDiscussionElements"
"changeElementType"
"newType"
"feivData"
"newElement"
"attribute"
"commentId"
"replaceElement"
"replaceChild"
"mergeAdjacentCommentLevels"
"levels"
"isOrHasCommentLevel"
"bottomElement"
"topElement"
"currentTopElement"
"currentBottomElement"
"topTag"
"bottomInnerTags"
"DD"
"LI"
"firstMoved"
"newChild"
"processComments"
"parser"
"highlightables"
"has"
"each"
"adjustDom"
"hook"
"fire"
"processSections"
"heading"
"Section"
"adjust"
"cleanUpWatched"
"highlightWatchedSections"
"addAddTopicButton"
"addSectionButton"
"ButtonWidget"
"label"
"framed"
"classes"
"$addSectionButtonContainer"
"connectToAddTopicButtons"
"ADD_TOPIC_SELECTORS"
"$button"
"is"
"off"
"metaKey"
"editintro"
"preload"
"preloadtitle"
"nosummary"
"cdomitsignature"
"$form"
"connectToCommentLinks"
"Comment"
"getByAnchor"
"scrollToAndHighlightTarget"
"configureAndAddLayers"
"highlightMentions"
"USER_NAMESPACE_ALIASES_REGEXP"
"processFragment"
"decodedFragment"
"escapedFragment"
"escapedDecodedFragment"
"escapeSelector"
"commentAnchorToCheck"
"gap"
"getTime"
"MILLISECONDS_IN_A_MINUTE"
"pushState"
"sectionAnchor"
"history"
"state"
"fragmentHasNoTarget"
"idleFragments"
"isPageActive"
"notFound"
"processVisits"
"visitsRequest"
"previousVisitUnixTime"
"currentUnixTime"
"now"
"HIGHLIGHT_NEW_COMMENTS_INTERVAL"
"haveMatchedTimeWithComment"
"isSeen"
"commentUnixTime"
"unseenCommentAnchors"
"unseenComments"
"addNewComments"
"groupBySection"
"fill"
"confirmDesktopNotifications"
"desktopNotifications"
"Notification"
"permission"
"actions"
"flags"
"confirmDialog"
"size"
"alert"
"requestPermission"
"debugLog"
"timePerComment"
"debug"
"timerTotal"
"logAndResetTimer"
"toFixed"
"logAndResetEverything"
"processPage"
"stopTimer"
"startTimer"
"editWatchedSections"
"settingsDialog"
"el1"
"el2"
"compareDocumentPosition"
"DOCUMENT_POSITION_PRECEDING"
"y"
"wasPageCreated"
"updateChecker"
"isMounted"
"unmount"
"restoreCommentForms"
"highlightFocused"
"handleWindowResize"
"addPreventUnloadCondition"
"saveSession"
"alwaysConfirmLeavingPage"
"setInterval"
"MutationObserver"
"records"
"record"
"observe"
"childList"
"subtree"
"handleGlobalKeyDown"
"using"
"removeLoadingOverlay"
"DATE_FORMATS"
"DIGITS"
"TIMEZONES"
"loadData"
"requests"
"contribsPage"
"LOCAL_TIMEZONE_OFFSET"
"localTimezoneOffset"
"messageNames"
"messagesRequests"
"nextNames"
"amlang"
"loadMessages"
"amincludelocal"
"amfilter"
"siprop"
"specialpagealiases"
"realname"
"aliases"
"general"
"timeoffset"
"setLocalTimestampRegexps"
"mainPartPattern"
"digits"
"regexpAlternateGroup"
"getTimestampMainPartPattern"
"timezones"
"timezonePattern"
"abbr"
"exists"
"initTimestampParsingTools"
"langCode"
"setFormats"
"matchingGroups"
"untransformDigits"
"monthIdx"
"hour"
"minute"
"TIMESTAMP_MATCHING_GROUPS"
"setLocalTimestampParser"
"saveSessionTimeout"
"saveSessionLastTime"
"$loadingPopup"
"tocItems"
"notificationsData"
"isPageBeingReloaded"
"initSettings"
"allowEditOthersComments"
"alwaysExpandAdvanced"
"haveInsertButtonsBeenAltered"
"autopreview"
"defaultCommentLinkType"
"defaultSectionLinkType"
"insertButtons"
"defaultInsertButtons"
"notifications"
"notificationsBlacklist"
"showLoadingOverlay"
"showToolbar"
"signaturePrefix"
"defaultSignaturePrefix"
"modifyToc"
"watchOnReply"
"watchSectionOnReply"
"varAlias"
"remoteSettings"
"initGlobals"
"moduleRegistry"
"script"
"files"
"CURRENT_PAGE_NAME"
"GENDER_AFFECTS_USER_STRING"
"sPlain"
"QQX_MODE"
"getParamValue"
"SUMMARY_POSTFIX"
"SUMMARY_LENGTH_LIMIT"
"scriptPageWikilink"
"NOTIFICATION_AREA"
"dontHandleScroll"
"hasPageBeenReloaded"
"processPageInBackground"
"getCommentByAnchor"
"getSectionByAnchor"
"getSectionsByHeadline"
"getByHeadline"
"getLastActiveCommentForm"
"getLastActiveAlteredCommentForm"
"initPatterns"
"anySpace"
"namespaceIds"
"userNamespacesPattern"
"allNamespacesPattern"
"contribsPagePattern"
"userNamespaceAliasesPattern"
"unsignedTemplates"
"unsignedTemplatesPattern"
"UNSIGNED_TEMPLATES_PATTERN"
"CURRENT_USER_SIGNATURE"
"SIGN_CODE"
"signatureContent"
"authorInSignatureMatch"
"signaturePrefixPattern"
"signatureBeginning"
"CURRENT_USER_SIGNATURE_PREFIX_REGEXP"
"pieJoined"
"PIE_PATTERN"
"pnieJoined"
"PNIE_PATTERN"
"commentAntipatternsPatternParts"
"templatesToExclude"
"commentAntipatterns"
"elementsToExcludeClassesPattern"
"templatesToExcludePattern"
"commentAntipatternPattern"
"quoteTemplateToPattern"
"tpl"
"quoteBeginningsPattern"
"pairQuoteTemplates"
"quoteEndingsPattern"
"closedDiscussionBeginningsPattern"
"closedDiscussionTemplates"
"closedDiscussionEndingsPattern"
"CLOSED_DISCUSSION_PAIR_REGEXP"
"CLOSED_DISCUSSION_SINGLE_REGEXP"
"UNHIGHLIGHTABLE_ELEMENT_CLASSES"
"customUnhighlightableElementClasses"
"fileNamespacesPattern"
"FILE_PREFIX_PATTERN"
"colonNamespacesPattern"
"BAD_COMMENT_BEGINNINGS"
"customBadCommentBeginnings"
"customAddTopicLinkSelectors"
"pagesWithoutArchives"
"pathToRegexp"
"replacements"
"isArchivePath"
"archivePaths"
"archive"
"initOouiAndElementPrototypes"
"createWindowManager"
"COMMENT_ELEMENT_PROTOTYPES"
"goToParentButton"
"icon"
"invisibleLabel"
"linkButton"
"pendingLinkButton"
"disabled"
"thankButton"
"pendingThankButton"
"thankedButton"
"editButton"
"replyButton"
"underlay"
"overlay"
"overlayInnerWrapper"
"overlayGradient"
"overlayContent"
"SECTION_ELEMENT_PROTOTYPES"
"addSubsectionButton"
"worker"
"extend"
"jqueryExtensions"
"getUnseenCommentAnchors"
"updatePageContent"
"isShowLoadingOverlaySettingOff"
"cdShowLoadingOverlay"
"setLoadingOverlay"
"$logoContainer"
"isLoadingOverlayOn"
"reloadPage"
"closeNotifications"
"closeNotificationsSmoothly"
"parseData"
"didSubmitCommentForm"
"$outermostElement"
"wgRevisionId"
"wgCurRevisionId"
"jsconfigvars"
"replaceState"
"pathname"
"updatePageTitle"
"possiblyHide"
"timeSinceLastSave"
"targetData"
"firstCommentAnchor"
"getValue"
"commentInput"
"summaryInput"
"minor"
"minorCheckbox"
"isSelected"
"watch"
"watchCheckbox"
"watchSection"
"watchSectionCheckbox"
"omitSignatureCheckbox"
"delete"
"deleteCheckbox"
"originalHeadline"
"originalComment"
"isSummaryAltered"
"saveUnixTime"
"commentFormsData"
"dataAllPages"
"newData"
"forms"
"SECONDS_IN_A_DAY"
"cleanUpSessions"
"haveRestored"
"rescue"
"isActionable"
"dataToRestore"
"notification"
"$notification"
"goToNextCommentForm"
"rescueCommentFormsContent"
"restoreCommentFormsFromData"
"addToRescue"
"checkCodeRequest"
"setTargets"
"addToPage"
"addNotification"
"close"
"TocItem"
"textSpan"
"$link"
"$text"
"$headline"
"clone"
"cookie"
"$closestFloating"
"isWatched"
"updateTocLink"
"addNewSections"
"otherSection"
"tocLevel"
"currentTree"
"$topUl"
"getTocItem"
"currentLevelMatch"
"upperLevelMatch"
"onclick"
"numberSpan"
"commentsBySection"
"firstComment"
"next"
"areCommentsRendered"
"sectionOrAnchor"
"$sectionLink"
"$target"
"$next"
"moreTooltipText"
"getParent"
"names"
"bulletSpan"
"lastCheckedRevisionId"
"commentsNotifiedAbout"
"isBackgroundCheckArranged"
"previousVisitRevisionId"
"submittedCommentAnchor"
"resolverCount"
"revisionData"
"resolvers"
"setAlarmViaWorker"
"interval"
"postMessage"
"removeAlarmViaWorker"
"checkForUpdates"
"documentHidden"
"rvlimit"
"currentRevisionId"
"isPageStillAtRevision"
"currentComments"
"mapSections"
"mappedCurrentComments"
"mapComments"
"checkForNewEdits"
"BACKGROUND_UPDATE_CHECK_INTERVAL"
"UPDATE_CHECK_INTERVAL"
"onDocumentVisible"
"abs"
"rvstart"
"toISOString"
"oldComments"
"checkForEditsSincePreviousVisit"
"matchedSection"
"matchScore"
"otherComments"
"otherComment"
"currentCommentsFiltered"
"currentComment"
"found"
"hasParentAnchorMatched"
"parentAnchor"
"hasHeadlineMatched"
"hasIdMatched"
"partsMatchedProportion"
"elementHtmls"
"match1"
"match2"
"hasPoorMatch"
"isCommentEdited"
"olderComment"
"newerComment"
"textInnerHtml"
"headingInnerHtml"
"seenRenderedEdits"
"seenUnixTime"
"cleanUpSeenRenderedEdits"
"oldComment"
"seenInnerHtml"
"innerHtml"
"commentsData"
"markAsEdited"
"isOpeningSection"
"getSection"
"elementTagNames"
"hiddenElementData"
"oldSection"
"headlineElement"
"parseHeadline"
"newHeadline"
"originalThisPageWatchedSections"
"isEditMarkUpdated"
"newComment"
"unmarkAsEdited"
"comparedHtml"
"isEdited"
"showOrdinaryNotification"
"filteredComments"
"toMe"
"openNotification"
"isOpen"
"formsDataWillNotBeLost"
"reloadHtml"
"where"
"watchedSectionHeadline"
"mayBeInterestingString"
"mayBeInteresting"
"showDesktopNotification"
"hasFocus"
"parentAuthorName"
"newComments"
"interestingNewComments"
"interesting"
"closestWatchedSection"
"getClosestWatchedSection"
"authors"
"relevantNewCommentAnchor"
"newCommentsBySection"
"areThereInteresting"
"updateRefreshButton"
"addNewCommentsNotifications"
"commentsToNotifyAbout"
"cna"
"onMessageFromWorker"
"resolverId"
"onmessage"
"processRevisionsIfNeeded"
"revisionToParseId"
"payload"
"newCommentsCount"
"interestingMark"
"newCount"
"lastFirstUnseenCommentId"
"$refreshButton"
"refreshClick"
"$previousButton"
"goToPreviousNewComment"
"$nextButton"
"goToNextNewComment"
"$firstUnseenButton"
"goToFirstUnseenComment"
"$commentFormButton"
"updateFirstUnseenButton"
"unseenCount"
"commentInViewport"
"findInViewport"
"isInViewport"
"registerSeen"
"top1"
"top2"
"commentCount"
"commentsCount"
"tooltipText"
"bullet"
"generateTooltipText"
"removeClass"
"beforeUnloadHandlers"
"adjustLabels"
"condition"
"returnValue"
"removePreventUnloadCondition"
"isPageOverlayOn"
"quote"
"checkboxField"
"help"
"tabIndex"
"checkbox"
"CheckboxInputWidget"
"FieldLayout"
"align"
"helpInline"
"radioField"
"RadioOptionWidget"
"RadioSelectWidget"
"field"
"selectItemByData"
"copyActionField"
"copyCallback"
"TextInputWidget"
"button"
"ActionFieldLayout"
"windowManager"
"WindowManager"
"win"
"closed"
"clearWindows"
"deferMsg"
"dialog"
"MessageDialog"
"addWindows"
"windowInstance"
"openWindow"
"confirmDestructive"
"messageName"
"confirm"
"isUnsaved"
"saveButton"
"isDisabled"
"confirmCloseDialog"
"dialogCode"
"handleError"
"recoverable"
"showErrors"
"$errors"
"setAbilities"
"updateWindowSize"
"SettingsDialog"
"inheritClass"
"ProcessDialog"
"static"
"modes"
"getBodyHeight"
"initialize"
"$loading"
"loadingPanel"
"PanelLayout"
"padded"
"expanded"
"settingsPanel"
"$settingsSaved"
"reloadPanel"
"$dataRemoved"
"dataRemovedPanel"
"stackLayout"
"StackLayout"
"getSetupProcess"
"setMode"
"getReadyProcess"
"preparationRequests"
"settingsForm"
"renderForm"
"bookletLayout"
"setPage"
"getActionProcess"
"Process"
"collectSettings"
"currentPageName"
"getCurrentPageName"
"allowEditOthersCommentsField"
"allowEditOthersCommentsCheckbox"
"alwaysExpandAdvancedField"
"alwaysExpandAdvancedCheckbox"
"autocompleteMentionsOption"
"CheckboxMultioptionWidget"
"autocompleteCommentLinksOption"
"autocompleteWikilinksOption"
"autocompleteTemplatesOption"
"autocompleteTagsOption"
"autocompleteTypesMultiselect"
"CheckboxMultiselectWidget"
"autocompleteTypesField"
"autopreviewField"
"autopreviewCheckbox"
"desktopNotificationsField"
"desktopNotificationsSelect"
"desktopNotificationsRadioAll"
"desktopNotificationsRadioNone"
"desktopNotificationsRadioToMe"
"hostname"
"highlightOwnCommentsField"
"highlightOwnCommentsCheckbox"
"insertButtonsSelected"
"insertButtonsMultiselect"
"TagMultiselectWidget"
"placeholder"
"allowArbitrary"
"inputPosition"
"tagLimit"
"insertButtonsField"
"modifyTocField"
"modifyTocCheckbox"
"notificationsField"
"notificationsSelect"
"notificationsRadioAll"
"notificationsRadioNone"
"notificationsRadioToMe"
"notificationsBlacklistMultiselect"
"widgets"
"UsersMultiselectWidget"
"notificationsBlacklistField"
"showToolbarField"
"showToolbarCheckbox"
"signaturePrefixInput"
"maxlength"
"signaturePrefixField"
"useTemplateDataField"
"useTemplateDataCheckbox"
"watchOnReplyField"
"watchOnReplyCheckbox"
"watchSectionOnReplyField"
"watchSectionOnReplyCheckbox"
"connect"
"change"
"choose"
"removeDataButton"
"removeDataField"
"targetBlank"
"GeneralPageLayout"
"PageLayout"
"setupOutlineItem"
"outlineItem"
"setLabel"
"CommentFormPageLayout"
"NotificationsPageLayout"
"RemoveDataPageLayout"
"generalPage"
"commentFormPage"
"notificationsPage"
"removeDataPage"
"BookletLayout"
"outlined"
"addPages"
"updateStates"
"findSelectedItemsData"
"findSelectedItem"
"getData"
"processInsertButtons"
"displayedText"
"findItemFromData"
"save"
"changeDesktopNotifications"
"option"
"removeData"
"removeItem"
"EditWatchedSectionsDialog"
"$errorItems"
"sectionsPanel"
"$watchedSectionsSaved"
"savedPanel"
"page1"
"page2"
"rows"
"newValue"
"pageTitle"
"sectionTitle"
"titleToId"
"copyLinkToClipboardAndNotify"
"$textarea"
"successful"
"copyLink"
"isLinkBeingCopied"
"isComment"
"wikilink"
"decodedCurrentPageUrl"
"decodeURI"
"anchorWithUnderlines"
"diffField"
"shortDiffField"
"$diff"
"onlyCdWarning"
"diffLink"
"shortDiffLink"
"errorText"
"getDiffLink"
"generateDiffView"
"wikilinkField"
"currentPageWikilinkField"
"linkField"
"$dummyInput"
"$message"
"archivePrefix"
"searchQuery"
"profile"
"fulltext"
"cdcomment"
"watchPromise"
"unwatchHeadline"
"autoHideSeconds"
"unwatch"
"parentTree"
"returnScore"
"hasAnchorMatched"
"hasParentTreeMatched"
"bestMatch"
"isLastSection"
"nextSameLevelSection"
"elements"
"headingNestingLevel"
"addAddSubsectionButton"
"isFirstChunkClosed"
"lastElementInFirstChunk"
"firstContentElement"
"addReplyButton"
"subsections"
"getChildren"
"targetSection"
"$replyButtonLink"
"replyButtonHoverHandler"
"replyButtonUnhoverHandler"
"genders"
"commonGender"
"userList"
"$lastElement"
"$addSubsectionButtonContainer"
"$replyButton"
"insertAfter"
"initialSectionCount"
"levelMatch"
"levelRegexp"
"firstCommentPart"
"lastCommentPart"
"hasSubsections"
"lastNode"
"firstCommentPartId"
"lastCommentPartId"
"commentsInFirstChunk"
"followsHeading"
"classesToFilter"
"foreignElementsInHeadlinesClasses"
"nodes"
"ignoreFirstLevel"
"cachedParentTree"
"elementPrototypes"
"sourcePage"
"editSectionElement"
"closingBracketElement"
"lastElementChild"
"editLink"
"editUrl"
"extendSectionMenu"
"addReply"
"isVotePlaceholder"
"childElementCount"
"createUl"
"replyWrapper"
"replyContainer"
"nextElementSibling"
"$replyWrapper"
"$replyContainer"
"labelContainer"
"addSubsection"
"buttonContainer"
"lastElement"
"hideAddSubsectionButtonTimeout"
"deferButtonHide"
"onmouseenter"
"onmouseleave"
"addSubsectionForm"
"showAddSubsectionButtonTimeout"
"$addSubsectionButton"
"openingSectionOfLevel"
"addMenuItem"
"tooltip"
"class"
"move"
"visible"
"finally"
"addReplyForm"
"baseSection"
"getBase"
"MoveSectionDialog"
"onTitleInputChange"
"titleInput"
"getValidity"
"loadSourcePage"
"getSourcePage"
"locateInCode"
"sectionInCode"
"inCode"
"sectionWikilink"
"loadTargetPage"
"targetPage"
"editTargetPage"
"codeBeginning"
"codeEnding"
"getMoveTargetPageCode"
"keepLinkCheckbox"
"newSectionCode"
"relativeContentStartIndex"
"summaryEnding"
"summaryEndingInput"
"buildEditSummary"
"baserevid"
"starttimestamp"
"editSourcePage"
"getMoveSourcePageCode"
"abort"
"movePanel"
"sectionCode"
"TitleInputWidget"
"$overlay"
"excludeCurrentPage"
"showMissing"
"validate"
"getMWTitle"
"titleField"
"executeAction"
"keepLinkField"
"$sectionCodeNote"
"maxLength"
"summaryEndingAutocomplete"
"summaryEndingField"
"blur"
"updateWatchMenuItems"
"silent"
"renamedFrom"
"$links"
"hasClass"
"watchedAncestorHeadline"
"searchInCode"
"replyPlaceholder"
"firstChunkCode"
"lastCommentIndentationChars"
"lastComment"
"containerListType"
"indentationCharMode"
"indentationChars"
"firstChunkContentEndIndex"
"contentEndIndex"
"includeCurrent"
"cached$elements"
"adjustedPageCode"
"headlines"
"sectionIndex"
"thisHeadline"
"numberOfPreviousHeadlinesToCheck"
"previousHeadlinesInCode"
"havePreviousHeadlinesMatched"
"hasSectionIndexMatched"
"fullHeadingMatch"
"equalSigns"
"equalSignsPattern"
"codeFromSection"
"adjustedCodeFromSection"
"sectionMatch"
"firstChunkMatch"
"log"
"hasFirstCommentMatched"
"contentStartIndex"
"firstChunkEndIndex"
"keepInSectionEnding"
"codeMatch"
"indirect"
"haveMetDirect"
"tocItem"
"removeAttr"
"SectionStatic"
"commentFormsCounter"
"sectionHeadline"
"mediaWikiNamespace"
"$messageArea"
"$el"
"encapsulateSelection"
"createContents"
"addEvents"
"initAutocomplete"
"operations"
"currentOperation"
"registerOperation"
"commentText"
"codeToText"
"inSmallFont"
"headlineCode"
"setValue"
"closeOperation"
"preview"
"cancel"
"affectHeadline"
"preloadPage"
"onlyInclude"
"setSelected"
"checkCode"
"targetComment"
"addToolbar"
"moduleNames"
"$toolbarPlaceholder"
"wikiEditor"
"packageExports"
"dialogsConfig"
"replaceIcons"
"getDefaultConfig"
"textSelection"
"setContents"
"lang"
"group"
"tools"
"smaller"
"peri"
"execute"
"codeBlock"
"underline"
"strikethrough"
"groups"
"mention"
"addInsertButton"
"$a"
"$insertButtons"
"editingSectionOpeningComment"
"headlineInputPurpose"
"commentInputPlaceholder"
"rowNumber"
"requestAuthorGenderIfNeeded"
"autosize"
"maxRows"
"$advanced"
"codePointLimit"
"visibleCodePointLimit"
"updateAutoSummary"
"$summaryPreview"
"minorField"
"watchCheckboxSelected"
"watchField"
"callItTopic"
"watchSectionField"
"omitSignatureField"
"deleteField"
"settingsButton"
"checkboxesLayout"
"HorizontalLayout"
"$buttonsContainer"
"$leftButtonsContainer"
"$rightButtonsContainer"
"submitButtonLabelStandard"
"submitButtonLabelShort"
"advancedButton"
"$popupsOverlay"
"helpPopupButton"
"PopupButtonWidget"
"popup"
"cancelButton"
"viewChangesButton"
"previewButton"
"submitButton"
"updateFormOnDeleteCheckboxChange"
"$previewArea"
"prependTo"
"layout"
"customCommentFormModules"
"checkFunc"
"outerWrapperTag"
"$lastOfTarget"
"$other"
"createList"
"$nextToTargetFirstChild"
"$outerWrapper"
"$wrappingList"
"$wrappingItem"
"headingLevelRegexp"
"$tested"
"saveSessionEventHandler"
"textReactions"
"customTextReactions"
"submit"
"showMessage"
"hideMessage"
"dontAutopreviewOnSummaryChange"
"toggleAdvanced"
"viewChanges"
"commentsInSection"
"usersInSection"
"autocomplete"
"headlineAutocomplete"
"summaryAutocomplete"
"formWidth"
"buttonsTotalWidthStandard"
"outerWidth"
"setEnabled"
"htmlOrJquery"
"isRaw"
"isDestroyed"
"appendable"
"$label"
"MessageWidget"
"inline"
"$info"
"messageType"
"isAuto"
"navigateToEditUrl"
"confirmClose"
"forget"
"addIndentationChars"
"spaceAfterIndentationChars"
"willCommentBeIndented"
"replyIndentationChars"
"defaultIndentationChar"
"isZeroLevel"
"newLineIndentationChars"
"preTransformCode"
"isWholeCommentInSmall"
"signatureCode"
"chars"
"paragraphTemplates"
"entireLineRegexp"
"thisLineEndingRegexp"
"nextLineBeginningRegexp"
"headingRegexp"
"thisLine"
"nextLine"
"headingLevel"
"spaceOrNot"
"indentation"
"smallDivTemplates"
"imitateList"
"postTransformCode"
"prepareNewPageCode"
"doDelete"
"anchorsRegexp"
"anchors"
"commentInCode"
"anchorCode"
"getAnchorCode"
"commentStart"
"commentTextIndex"
"headingCode"
"signatureDirtyCode"
"thisInCode"
"tryPrepareNewPageCode"
"operation"
"isClosed"
"closeOperationIfNecessary"
"otherOperationIndex"
"findLastIndex"
"op"
"isDelayed"
"unregisterOperation"
"isBeingSubmitted"
"previewEmpty"
"nativePromiseState"
"isTooEarly"
"lastPreviewTimestamp"
"previewTimeout"
"areInputsEmpty"
"$comment"
"$colon"
"$previewLabel"
"toslots"
"fromrev"
"fromslots"
"wrapDiffBody"
"runChecks"
"checks"
"confirmation"
"noConfirmPostEmptyCommentPageRegexp"
"longCommentThreshold"
"check"
"tryEditPage"
"watchlist"
"editTimestamp"
"isHeadlineAltered"
"destroy"
"autoSummary"
"autoText"
"optionalText"
"summaryCommentTextLengthLimit"
"subsection"
"addPostfix"
"updateAutoSummaryBound"
"subject"
"targetParent"
"editOrDeleteText"
"initialMinorCheckboxSelected"
"clearFlags"
"setFlags"
"mentionAddressee"
"lastChar"
"allowEmptySelection"
"selection"
"isCommentInputFocused"
"rangeStart"
"rangeEnd"
"quoteFormatting"
"leadingNewline"
"selectionStartPos"
"leadingNewlineChar"
"periStartPos"
"trailingSpace"
"middleText"
"CommentFormStatic"
"addLayers"
"registerIfInViewport"
"findClosestDirection"
"isVisible"
"getPositions"
"findVisible"
"direction"
"firstVisibleComment"
"lastVisibleComment"
"foundComment"
"searchArea"
"findClosest"
"downplayedBottom"
"higherTop"
"proportion"
"round"
"isObstructingElementHovered"
"layersContainerOffset"
"getLayersContainerOffset"
"pageY"
"layersTop"
"layersHeight"
"pageX"
"layersLeft"
"layersWidth"
"unhighlightFocused"
"thanks"
"colon"
"moveFromBeginning"
"moveToBeginning"
"goToCommentToYou"
"goToCommentWatchedSection"
"currentUserRegexp"
"$wrapperRegularPrototype"
"$wrapperInterestingPrototype"
"switchInterestingButton"
"setLevels"
"shift"
"headingLevelMatch"
"addAttributes"
"cachedSection"
"$signature"
"$timestamp"
"bindEvents"
"isEditedSincePreviousVisit"
"isFlashNewOnSightSet"
"ontouchstart"
"considerFloating"
"rectTop"
"rectBottom"
"intersectsFloatingCount"
"bottomIntersectsFloating"
"floatingTop"
"floatingBottom"
"REGULAR_LINE_HEIGHT"
"initialOverflows"
"calculateLayersPositions"
"firstHighlightableWidth"
"COMMENT_UNDERLAY_SIDE_MARGIN"
"createLayers"
"oncontextmenu"
"mouseUpTimeout"
"onmousedown"
"onmouseup"
"goToParent"
"thankUnixTime"
"cleanUpThanks"
"thank"
"replyForm"
"reply"
"updateLayersStyles"
"$overlayContent"
"$overlayGradient"
"topDifference"
"heightDifference"
"getCurrentBackgroundColor"
"backgroundColor"
"highlightTarget"
"flash"
"delay"
"$elementsToAnimate"
"stop"
"finalColor"
"unhighlightTimeout"
"flashNew"
"flashNewOnSight"
"isNewVersionRendered"
"comparedRevisionId"
"stringName"
"$refreshLink"
"$diffLink"
"showDiff"
"$span"
"$last"
"areThereReferences"
"areStyleTagsKept"
"currentAutonumber"
"eq"
"$headlineNumber"
"$html"
"cachedText"
"replaceButton"
"buttonName"
"goToChildButton"
"goToChild"
"childToScrollBackTo"
"findAddingEdit"
"addingEdit"
"rvend"
"rvdir"
"rvuser"
"compareRequests"
"fromtitle"
"torelative"
"compareResps"
"commentFullText"
"diffBody"
"diffOriginalText"
"diffText"
"bestDiffPartOverlap"
"diffPartText"
"diffPartOverlap"
"thisCommentTimestamp"
"dateProximity"
"short"
"urlEnding"
"diff"
"$nextDiffLink"
"$summaryText"
"parsedcomment"
"$above"
"$diffBody"
"thankFail"
"genderRequest"
"question"
"$question"
"rev"
"scriptCodeName"
"commentData"
"adjustCommentCodeData"
"spacing"
"newChars"
"paragraphTemplatesPattern"
"lineRegexp"
"registerAllInDirection"
"highlight"
"makesSenseToRegister"
"nextComment"
"newElementOrHtml"
"nativeElement"
"outerHTML"
"not"
"cachedParent"
"cleanUp"
"$clone"
"$dummy"
"selectorParts"
"signaturePrefixRegexp"
"adjustCommentBeginning"
"lineStartIndex"
"headingMatch"
"headingStartIndex"
"originalRegexp"
"linesRegexp"
"indent"
"testIndent"
"replaceIndentationChars"
"indentationCharsPattern"
"originalData"
"movePartToSignature"
"tagRegexp"
"regexps"
"movePartsToSignature"
"smallWrappers"
"prefix"
"signatureEndIndex"
"previousComments"
"hasPreviousCommentsDataMatched"
"hasPreviousCommentDataMatched"
"isPreviousCommentsDataEqual"
"currentIndex"
"chunkCodeAfterEndIndex"
"chunkCodeAfter"
"adjustedChunkCodeAfter"
"maxIndentationCharsLength"
"properPlaceRegexp"
"adjustedCodeInBetween"
"changedIndentationChars"
"succeedingText"
"cachedLayersContainer"
"offsetParent"
"conveneintDiscussionsStyle"
"backgroundImage"
"cdCachedLayersContainerTop"
"cdCachedLayersContainerLeft"
"runAlways"
"genderRequestCallbacks"
"errorCallback"
"revisionIdLesser"
"revisionIdGreater"
"revisionsRequest"
"revids"
"compareRequest"
"torev"
"revisionsResp"
"compareResp"
"lineNumbers"
"newlinesBeforeComment"
"newlinesInComment"
"startLineNumber"
"endLineNumber"
"currentLineNumbers"
"cleanDiffBody"
"tr"
"$tr"
"$lineNumbers"
"addToDiff"
"$cleanDiff"
"$historyLink"
"$below"
"CommentStatic"
"processDiffFirstRun"
"dataRequest"
"nanoCss"
"nanoCssCreate"
"$aRegularPrototype"
"$spanRegularPrototype"
"currentUserNamePattern"
"addWatchlistMenu"
"progressive"
"$menu"
"isEnhanced"
"$collapsibles"
"$lines"
"hasFlag"
"switchInteresting"
"editWatchedSectionsButton"
"extractAuthor"
"authorElement"
"isArchiving"
"isInSection"
"processWatchlist"
"nsMatch"
"nsNumber"
"linkElement"
"bytesAddedElement"
"bytesAddedMatch"
"bytesAdded"
"bytesToDeemComment"
"curLink"
"curIdMatch"
"curId"
"destination"
"processContributions"
"timezone"
"timezoneParts"
"dateElement"
"processHistory"
"lines"
"separators"
"processDiff"
"area"
"addCommentLinks"
"IS_DIFF_PAGE"
"timerStartTimestamps"
"timerRunCount"
"timerAllRunsTotal"
"initCounters"
"array"
"counters"
"Proxy"
"resetTimer"
"fullResetTimer"
"timerLabels"
"counterLabels"
"averageTimerTime"
"average"
"incrementCounter"
"pageWhitelist"
"pageBlacklist"
"optionsPrefix"
"transformSummary"
"targetPageWikilink"
"COMMENT_FOCUSED_COLOR"
"COMMENT_TARGET_COLOR"
"COMMENT_NEW_COLOR"
"COMMENT_OWN_COLOR"
"COMMENT_DELETED_COLOR"
"$wrapper"
"parseHTML"
"wrapAll"
"$linkWrapper"
"wrapInner"
"wasOptionalTextAdded"
"projectedText"
"IS_SNIPPET"
"fullName"
"lastParam"
"addFooterLink"
"enable"
"cdtalkpage"
"$li"
"go"
"defaultConfig"
"contentStrings"
"strings"
"en"
"relevantLang"
"contentStringName"
"setStrings"
"wsonEnding"
"enabledInQuery"
"modulesRequest"
"lineHeight"
"focusedColor"
"contentBackgroundColor"
"sidebarColor"
"initTalkPageCss"
"$start"
"$end"
"addCommentLinksToSpecialSearch"
"configUrls"
"rejectWithMsg"
"emptyResponseCallback"
"getScript"
"IS_DEV"
"getStrings"
"isRunning"
"getStringsPromise"
mappings"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AAS,SAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,UAClBA,EAAS,KAAS,SAClBA,EAAS,KAAS,SAClBA,EAAS,KAAS,UAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,UAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,SAClBA,EAAS,KAAS,UAClBA,EAAS,KAAS,UAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,UAClBA,EAAS,KAAS,SAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,UAClBA,EAAS,KAAS,SAClBA,EAAS,KAAS,QAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,UAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,SAClBA,EAAS,KAAS,UAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,UAClBA,EAAS,KAAS,SAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,UAClBA,EAAS,KAAS,UAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,UAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,SAClBA,EAAS,KAAS,UAClBA,EAAS,KAAS,UAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,UAClBA,EAAS,KAAS,SAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,UAClBA,EAAS,KAAS,SAClBA,EAAS,KAAS,QAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,UAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,SAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,WAClBA,EAAS,KAAS,UAClBA,EAAS,KAAS,SAClBA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wBACX,GAAM,wBACN,UAAW,mBACX,GAAM,cACN,GAAM,8DACN,GAAM,aACN,IAAO,cACP,IAAO,aACP,IAAO,aACP,IAAO,yBACP,UAAW,aACX,UAAW,aACX,IAAO,cACP,GAAM,aACN,UAAW,yBACX,UAAW,aACX,IAAO,cACP,GAAM,cACN,GAAM,aACN,GAAM,aACN,IAAO,YACP,GAAM,cACN,IAAO,cACP,GAAM,cACN,IAAO,cACP,IAAO,aACP,GAAM,aACN,IAAO,aACP,GAAM,YACN,IAAO,qBACP,IAAO,4CACP,IAAO,aACP,GAAM,iBACN,GAAM,aACN,IAAO,aACP,IAAO,4CACP,IAAO,+BACP,GAAM,aACN,IAAO,aACP,IAAO,4CACP,GAAM,+BACN,IAAO,qDACP,IAAO,aACP,IAAO,aACP,UAAW,YACX,IAAO,cACP,GAAM,iBACN,IAAO,cACP,GAAM,aACN,IAAO,YACP,GAAM,aACN,GAAM,aACN,IAAO,aACP,GAAM,aACN,IAAO,qBACP,GAAM,YACN,IAAO,cACP,GAAM,aACN,GAAM,aACN,GAAM,aACN,IAAO,4CACP,GAAM,qBACN,IAAO,cACP,IAAO,4CACP,IAAO,YACP,GAAM,aACN,IAAO,iDACP,IAAO,aACP,GAAM,mBACN,IAAO,cACP,SAAU,aACV,GAAM,aACN,IAAO,aACP,IAAO,aACP,cAAe,YACf,GAAM,YACN,GAAM,mBACN,IAAO,aACP,IAAO,aACP,IAAO,iBACP,IAAO,aACP,GAAM,aACN,GAAM,aACN,IAAO,aACP,GAAM,qBACN,IAAO,yBACP,GAAM,aACN,GAAM,aACN,GAAM,cACN,IAAO,aACP,GAAM,aACN,IAAO,aACP,IAAO,aACP,IAAO,iBACP,IAAO,cACP,IAAO,cACP,IAAO,cACP,IAAO,aACP,GAAM,aACN,GAAM,aACN,IAAO,aACP,IAAO,aACP,IAAO,cACP,IAAO,aACP,GAAM,aACN,QAAS,kCACT,GAAM,4CACN,IAAO,aACP,IAAO,YACP,GAAM,YACN,IAAO,aACP,IAAO,aACP,GAAM,aACN,IAAO,YACP,WAAY,aACZ,GAAM,YACN,IAAO,cACP,GAAM,cACN,IAAO,YACP,WAAY,aACZ,WAAY,YACZ,GAAM,aACN,IAAO,cACP,GAAM,aACN,IAAO,aACP,GAAM,aACN,IAAO,aACP,IAAO,aACP,IAAO,aACP,IAAO,4CACP,GAAM,aACN,IAAO,aACP,GAAM,yBACN,IAAO,iBACP,GAAM,iBACN,IAAO,aACP,IAAO,aACP,GAAM,aACN,IAAO,aACP,WAAY,aACZ,GAAM,aACN,GAAM,cACN,WAAY,yBACZ,IAAO,cACP,GAAM,cACN,IAAO,aACP,GAAM,aACN,GAAM,aACN,GAAM,aACN,GAAM,YACN,QAAS,eACT,QAAS,eACT,IAAO,YACP,GAAM,aACN,GAAM,aACN,IAAO,cACP,IAAO,cACP,GAAM,YACN,GAAM,kBACN,GAAM,aACN,IAAO,aACP,GAAM,aACN,IAAO,aACP,IAAO,aACP,GAAM,aACN,IAAO,4CACP,UAAW,cACX,UAAW,aACX,GAAM,eACN,GAAM,aACN,GAAM,aACN,GAAM,aACN,IAAO,aACP,GAAM,aACN,GAAM,aACN,IAAO,aACP,GAAM,aACN,IAAO,aACP,IAAO,aACP,GAAM,aACN,UAAW,aACX,UAAW,aACX,GAAM,aACN,GAAM,iBACN,IAAO,cACP,IAAO,aACP,IAAO,cACP,UAAW,aACX,UAAW,aACX,GAAM,cACN,GAAM,yBACN,GAAM,aACN,IAAO,aACP,GAAM,aACN,IAAO,qBACP,GAAM,6CACN,IAAO,YACP,IAAO,cACP,GAAM,iBACN,IAAO,yBACP,IAAO,qBACP,GAAM,iBACN,IAAO,aACP,GAAM,iBACN,IAAO,gCACP,IAAO,cACP,GAAM,aACN,IAAO,aACP,IAAO,aACP,GAAM,cACN,GAAM,aACN,IAAO,gCACP,GAAM,gCACN,IAAO,YACP,IAAO,aACP,UAAW,gCACX,UAAW,gCACX,QAAS,gCACT,GAAM,gCACN,QAAS,gCACT,QAAS,gCACT,GAAM,cAGFC,GAAS,CACb,WAAY,+DACZ,IAAO,+DACP,GAAM,+DACN,GAAM,+DACN,IAAO,+DACP,IAAO,+DACP,IAAO,+DACP,IAAO,+DACP,GAAM,+DACN,GAAM,+DACN,IAAO,+DACP,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"
file"convenientDiscussions.js"
sourcesContent
" // The module cache var installedModules = {}; // The require function function __webpack_require__(moduleId) { // Check if module is in cache if(installedModules[moduleId]) { return installedModules[moduleId].exports; } // Create a new module (and put it into the cache) var module = installedModules[moduleId] = { i: moduleId, l: false, exports: {} }; // Execute the module function modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); // Flag the module as loaded module.l = true; // Return the exports of the module return module.exports; } // expose the modules object (__webpack_modules__) __webpack_require__.m = modules; // expose the module cache __webpack_require__.c = installedModules; // define getter function for harmony exports __webpack_require__.d = function(exports, name, getter) { if(!__webpack_require__.o(exports, name)) { Object.defineProperty(exports, name, { enumerable: true, get: getter }); } }; // define __esModule on exports __webpack_require__.r = function(exports) { if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); } Object.defineProperty(exports, '__esModule', { value: true }); }; // create a fake namespace object // mode & 1: value is a module id, require it // mode & 2: merge all properties of value into the ns // mode & 4: return value when already ns object // mode & 8|1: behave like require __webpack_require__.t = function(value, mode) { if(mode & 1) value = __webpack_require__(value); if(mode & 8) return value; if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; var ns = Object.create(null); __webpack_require__.r(ns); Object.defineProperty(ns, 'default', { enumerable: true, value: value }); if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); return ns; }; // getDefaultExport function for compatibility with non-harmony modules __webpack_require__.n = function(module) { var getter = module && module.__esModule ? function getDefault() { return module['default']; } : function getModuleExports() { return module; }; __webpack_require__.d(getter, 'a', getter); return getter; }; // Object.prototype.hasOwnProperty.call __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; // __webpack_public_path__ __webpack_require__.p = ""; // Load entry module and return exports return __webpack_require__(__webpack_require__.s = 32); "
"function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } module.exports = _asyncToGenerator;"
""use strict"; var isOldIE = function isOldIE() { var memo; return function memorize() { if (typeof memo === 'undefined') { // Test for IE <= 9 as proposed by Browserhacks // @see http://browserhacks.com/#hack-e71d8692f65334173fee715c222cb805 // Tests for existence of standard globals is to allow style-loader // to operate correctly into non-standard environments // @see https://github.com/webpack-contrib/style-loader/issues/177 memo = Boolean(window && document && document.all && !window.atob); } return memo; }; }(); var getTarget = function getTarget() { var memo = {}; return function memorize(target) { if (typeof memo[target] === 'undefined') { var styleTarget = document.querySelector(target); // Special case to return head of iframe instead of iframe itself if (window.HTMLIFrameElement && styleTarget instanceof window.HTMLIFrameElement) { try { // This will throw an exception if access to iframe is blocked // due to cross-origin restrictions styleTarget = styleTarget.contentDocument.head; } catch (e) { // istanbul ignore next styleTarget = null; } } memo[target] = styleTarget; } return memo[target]; }; }(); var stylesInDom = []; function getIndexByIdentifier(identifier) { var result = -1; for (var i = 0; i < stylesInDom.length; i++) { if (stylesInDom[i].identifier === identifier) { result = i; break; } } return result; } function modulesToDom(list, options) { var idCountMap = {}; var identifiers = []; for (var i = 0; i < list.length; i++) { var item = list[i]; var id = options.base ? item[0] + options.base : item[0]; var count = idCountMap[id] || 0; var identifier = "".concat(id, " ").concat(count); idCountMap[id] = count + 1; var index = getIndexByIdentifier(identifier); var obj = { css: item[1], media: item[2], sourceMap: item[3] }; if (index !== -1) { stylesInDom[index].references++; stylesInDom[index].updater(obj); } else { stylesInDom.push({ identifier: identifier, updater: addStyle(obj, options), references: 1 }); } identifiers.push(identifier); } return identifiers; } function insertStyleElement(options) { var style = document.createElement('style'); var attributes = options.attributes || {}; if (typeof attributes.nonce === 'undefined') { var nonce = typeof __webpack_nonce__ !== 'undefined' ? __webpack_nonce__ : null; if (nonce) { attributes.nonce = nonce; } } Object.keys(attributes).forEach(function (key) { style.setAttribute(key, attributes[key]); }); if (typeof options.insert === 'function') { options.insert(style); } else { var target = getTarget(options.insert || 'head'); if (!target) { throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid."); } target.appendChild(style); } return style; } function removeStyleElement(style) { // istanbul ignore if if (style.parentNode === null) { return false; } style.parentNode.removeChild(style); } /* istanbul ignore next */ var replaceText = function replaceText() { var textStore = []; return function replace(index, replacement) { textStore[index] = replacement; return textStore.filter(Boolean).join('\n'); }; }(); function applyToSingletonTag(style, index, remove, obj) { var css = remove ? '' : obj.media ? "@media ".concat(obj.media, " {").concat(obj.css, "}") : obj.css; // For old IE /* istanbul ignore if */ if (style.styleSheet) { style.styleSheet.cssText = replaceText(index, css); } else { var cssNode = document.createTextNode(css); var childNodes = style.childNodes; if (childNodes[index]) { style.removeChild(childNodes[index]); } if (childNodes.length) { style.insertBefore(cssNode, childNodes[index]); } else { style.appendChild(cssNode); } } } function applyToTag(style, options, obj) { var css = obj.css; var media = obj.media; var sourceMap = obj.sourceMap; if (media) { style.setAttribute('media', media); } else { style.removeAttribute('media'); } if (sourceMap && btoa) { css += "\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))), " */"); } // For old IE /* istanbul ignore if */ if (style.styleSheet) { style.styleSheet.cssText = css; } else { while (style.firstChild) { style.removeChild(style.firstChild); } style.appendChild(document.createTextNode(css)); } } var singleton = null; var singletonCounter = 0; function addStyle(obj, options) { var style; var update; var remove; if (options.singleton) { var styleIndex = singletonCounter++; style = singleton || (singleton = insertStyleElement(options)); update = applyToSingletonTag.bind(null, style, styleIndex, false); remove = applyToSingletonTag.bind(null, style, styleIndex, true); } else { style = insertStyleElement(options); update = applyToTag.bind(null, style, options); remove = function remove() { removeStyleElement(style); }; } update(obj); return function updateStyle(newObj) { if (newObj) { if (newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap) { return; } update(obj = newObj); } else { remove(); } }; } module.exports = function (list, options) { options = options || {}; // Force single-tag solution on IE6-9, which has a hard limit on the # of <style> // tags it will allow on a page if (!options.singleton && typeof options.singleton !== 'boolean') { options.singleton = isOldIE(); } list = list || []; var lastIdentifiers = modulesToDom(list, options); return function update(newList) { newList = newList || []; if (Object.prototype.toString.call(newList) !== '[object Array]') { return; } for (var i = 0; i < lastIdentifiers.length; i++) { var identifier = lastIdentifiers[i]; var index = getIndexByIdentifier(identifier); stylesInDom[index].references--; } var newLastIdentifiers = modulesToDom(newList, options); for (var _i = 0; _i < lastIdentifiers.length; _i++) { var _identifier = lastIdentifiers[_i]; var _index = getIndexByIdentifier(_identifier); if (stylesInDom[_index].references === 0) { stylesInDom[_index].updater(); stylesInDom.splice(_index, 1); } } lastIdentifiers = newLastIdentifiers; }; };"
""use strict"; /* MIT License http://www.opensource.org/licenses/mit-license.php Author Tobias Koppers @sokra */ // css base code, injected by the css-loader // eslint-disable-next-line func-names module.exports = function (useSourceMap) { var list = []; // return the list of modules as css string list.toString = function toString() { return this.map(function (item) { var content = cssWithMappingToString(item, useSourceMap); if (item[2]) { return "@media ".concat(item[2], " {").concat(content, "}"); } return content; }).join(''); }; // import a list of modules into the list // eslint-disable-next-line func-names list.i = function (modules, mediaQuery, dedupe) { if (typeof modules === 'string') { // eslint-disable-next-line no-param-reassign modules = [[null, modules, '']]; } var alreadyImportedModules = {}; if (dedupe) { for (var i = 0; i < this.length; i++) { // eslint-disable-next-line prefer-destructuring var id = this[i][0]; if (id != null) { alreadyImportedModules[id] = true; } } } for (var _i = 0; _i < modules.length; _i++) { var item = [].concat(modules[_i]); if (dedupe && alreadyImportedModules[item[0]]) { // eslint-disable-next-line no-continue continue; } if (mediaQuery) { if (!item[2]) { item[2] = mediaQuery; } else { item[2] = "".concat(mediaQuery, " and ").concat(item[2]); } } list.push(item); } }; return list; }; function cssWithMappingToString(item, useSourceMap) { var content = item[1] || ''; // eslint-disable-next-line prefer-destructuring var cssMapping = item[3]; if (!cssMapping) { return content; } if (useSourceMap && typeof btoa === 'function') { var sourceMapping = toComment(cssMapping); var sourceURLs = cssMapping.sources.map(function (source) { return "/*# sourceURL=".concat(cssMapping.sourceRoot || '').concat(source, " */"); }); return [content].concat(sourceURLs).concat([sourceMapping]).join('\n'); } return [content].join('\n'); } // Adapted from convert-source-map (MIT) function toComment(sourceMap) { // eslint-disable-next-line no-undef var base64 = btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))); var data = "sourceMappingURL=data:application/json;charset=utf-8;base64,".concat(base64); return "/*# ".concat(data, " */"); }"
"// Copyright (c) 2013 Pieroxy <pieroxy@pieroxy.net> // This work is free. You can redistribute it and/or modify it // under the terms of the WTFPL, Version 2 // For more information see LICENSE.txt or http://www.wtfpl.net/ // // For more information, the home page: // http://pieroxy.net/blog/pages/lz-string/testing.html // // LZ-based compression algorithm, version 1.4.4 var LZString = (function() { // private property var f = String.fromCharCode; var keyStrBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; var keyStrUriSafe = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$"; var baseReverseDic = {}; function getBaseValue(alphabet, character) { if (!baseReverseDic[alphabet]) { baseReverseDic[alphabet] = {}; for (var i=0 ; i<alphabet.length ; i++) { baseReverseDic[alphabet][alphabet.charAt(i)] = i; } } return baseReverseDic[alphabet][character]; } var LZString = { compressToBase64 : function (input) { if (input == null) return ""; var res = LZString._compress(input, 6, function(a){return keyStrBase64.charAt(a);}); switch (res.length % 4) { // To produce valid Base64 default: // When could this happen ? case 0 : return res; case 1 : return res+"==="; case 2 : return res+"=="; case 3 : return res+"="; } }, decompressFromBase64 : function (input) { if (input == null) return ""; if (input == "") return null; return LZString._decompress(input.length, 32, function(index) { return getBaseValue(keyStrBase64, input.charAt(index)); }); }, compressToUTF16 : function (input) { if (input == null) return ""; return LZString._compress(input, 15, function(a){return f(a+32);}) + " "; }, decompressFromUTF16: function (compressed) { if (compressed == null) return ""; if (compressed == "") return null; return LZString._decompress(compressed.length, 16384, function(index) { return compressed.charCodeAt(index) - 32; }); }, //compress into uint8array (UCS-2 big endian format) compressToUint8Array: function (uncompressed) { var compressed = LZString.compress(uncompressed); var buf=new Uint8Array(compressed.length*2); // 2 bytes per character for (var i=0, TotalLen=compressed.length; i<TotalLen; i++) { var current_value = compressed.charCodeAt(i); buf[i*2] = current_value >>> 8; buf[i*2+1] = current_value % 256; } return buf; }, //decompress from uint8array (UCS-2 big endian format) decompressFromUint8Array:function (compressed) { if (compressed===null || compressed===undefined){ return LZString.decompress(compressed); } else { var buf=new Array(compressed.length/2); // 2 bytes per character for (var i=0, TotalLen=buf.length; i<TotalLen; i++) { buf[i]=compressed[i*2]*256+compressed[i*2+1]; } var result = []; buf.forEach(function (c) { result.push(f(c)); }); return LZString.decompress(result.join('')); } }, //compress into a string that is already URI encoded compressToEncodedURIComponent: function (input) { if (input == null) return ""; return LZString._compress(input, 6, function(a){return keyStrUriSafe.charAt(a);}); }, //decompress from an output of compressToEncodedURIComponent decompressFromEncodedURIComponent:function (input) { if (input == null) return ""; if (input == "") return null; input = input.replace(/ /g, "+"); return LZString._decompress(input.length, 32, function(index) { return getBaseValue(keyStrUriSafe, input.charAt(index)); }); }, compress: function (uncompressed) { return LZString._compress(uncompressed, 16, function(a){return f(a);}); }, _compress: function (uncompressed, bitsPerChar, getCharFromInt) { if (uncompressed == null) return ""; var i, value, context_dictionary= {}, context_dictionaryToCreate= {}, context_c="", context_wc="", context_w="", context_enlargeIn= 2, // Compensate for the first entry which should not count context_dictSize= 3, context_numBits= 2, context_data=[], context_data_val=0, context_data_position=0, ii; for (ii = 0; ii < uncompressed.length; ii += 1) { context_c = uncompressed.charAt(ii); if (!Object.prototype.hasOwnProperty.call(context_dictionary,context_c)) { context_dictionary[context_c] = context_dictSize++; context_dictionaryToCreate[context_c] = true; } context_wc = context_w + context_c; if (Object.prototype.hasOwnProperty.call(context_dictionary,context_wc)) { context_w = context_wc; } else { if (Object.prototype.hasOwnProperty.call(context_dictionaryToCreate,context_w)) { if (context_w.charCodeAt(0)<256) { for (i=0 ; i<context_numBits ; i++) { context_data_val = (context_data_val << 1); if (context_data_position == bitsPerChar-1) { context_data_position = 0; context_data.push(getCharFromInt(context_data_val)); context_data_val = 0; } else { context_data_position++; } } value = context_w.charCodeAt(0); for (i=0 ; i<8 ; i++) { context_data_val = (context_data_val << 1) | (value&1); if (context_data_position == bitsPerChar-1) { context_data_position = 0; context_data.push(getCharFromInt(context_data_val)); context_data_val = 0; } else { context_data_position++; } value = value >> 1; } } else { value = 1; for (i=0 ; i<context_numBits ; i++) { context_data_val = (context_data_val << 1) | value; if (context_data_position ==bitsPerChar-1) { context_data_position = 0; context_data.push(getCharFromInt(context_data_val)); context_data_val = 0; } else { context_data_position++; } value = 0; } value = context_w.charCodeAt(0); for (i=0 ; i<16 ; i++) { context_data_val = (context_data_val << 1) | (value&1); if (context_data_position == bitsPerChar-1) { context_data_position = 0; context_data.push(getCharFromInt(context_data_val)); context_data_val = 0; } else { context_data_position++; } value = value >> 1; } } context_enlargeIn--; if (context_enlargeIn == 0) { context_enlargeIn = Math.pow(2, context_numBits); context_numBits++; } delete context_dictionaryToCreate[context_w]; } else { value = context_dictionary[context_w]; for (i=0 ; i<context_numBits ; i++) { context_data_val = (context_data_val << 1) | (value&1); if (context_data_position == bitsPerChar-1) { context_data_position = 0; context_data.push(getCharFromInt(context_data_val)); context_data_val = 0; } else { context_data_position++; } value = value >> 1; } } context_enlargeIn--; if (context_enlargeIn == 0) { context_enlargeIn = Math.pow(2, context_numBits); context_numBits++; } // Add wc to the dictionary. context_dictionary[context_wc] = context_dictSize++; context_w = String(context_c); } } // Output the code for w. if (context_w !== "") { if (Object.prototype.hasOwnProperty.call(context_dictionaryToCreate,context_w)) { if (context_w.charCodeAt(0)<256) { for (i=0 ; i<context_numBits ; i++) { context_data_val = (context_data_val << 1); if (context_data_position == bitsPerChar-1) { context_data_position = 0; context_data.push(getCharFromInt(context_data_val)); context_data_val = 0; } else { context_data_position++; } } value = context_w.charCodeAt(0); for (i=0 ; i<8 ; i++) { context_data_val = (context_data_val << 1) | (value&1); if (context_data_position == bitsPerChar-1) { context_data_position = 0; context_data.push(getCharFromInt(context_data_val)); context_data_val = 0; } else { context_data_position++; } value = value >> 1; } } else { value = 1; for (i=0 ; i<context_numBits ; i++) { context_data_val = (context_data_val << 1) | value; if (context_data_position == bitsPerChar-1) { context_data_position = 0; context_data.push(getCharFromInt(context_data_val)); context_data_val = 0; } else { context_data_position++; } value = 0; } value = context_w.charCodeAt(0); for (i=0 ; i<16 ; i++) { context_data_val = (context_data_val << 1) | (value&1); if (context_data_position == bitsPerChar-1) { context_data_position = 0; context_data.push(getCharFromInt(context_data_val)); context_data_val = 0; } else { context_data_position++; } value = value >> 1; } } context_enlargeIn--; if (context_enlargeIn == 0) { context_enlargeIn = Math.pow(2, context_numBits); context_numBits++; } delete context_dictionaryToCreate[context_w]; } else { value = context_dictionary[context_w]; for (i=0 ; i<context_numBits ; i++) { context_data_val = (context_data_val << 1) | (value&1); if (context_data_position == bitsPerChar-1) { context_data_position = 0; context_data.push(getCharFromInt(context_data_val)); context_data_val = 0; } else { context_data_position++; } value = value >> 1; } } context_enlargeIn--; if (context_enlargeIn == 0) { context_enlargeIn = Math.pow(2, context_numBits); context_numBits++; } } // Mark the end of the stream value = 2; for (i=0 ; i<context_numBits ; i++) { context_data_val = (context_data_val << 1) | (value&1); if (context_data_position == bitsPerChar-1) { context_data_position = 0; context_data.push(getCharFromInt(context_data_val)); context_data_val = 0; } else { context_data_position++; } value = value >> 1; } // Flush the last char while (true) { context_data_val = (context_data_val << 1); if (context_data_position == bitsPerChar-1) { context_data.push(getCharFromInt(context_data_val)); break; } else context_data_position++; } return context_data.join(''); }, decompress: function (compressed) { if (compressed == null) return ""; if (compressed == "") return null; return LZString._decompress(compressed.length, 32768, function(index) { return compressed.charCodeAt(index); }); }, _decompress: function (length, resetValue, getNextValue) { var dictionary = [], next, enlargeIn = 4, dictSize = 4, numBits = 3, entry = "", result = [], i, w, bits, resb, maxpower, power, c, data = {val:getNextValue(0), position:resetValue, index:1}; for (i = 0; i < 3; i += 1) { dictionary[i] = i; } bits = 0; maxpower = Math.pow(2,2); power=1; while (power!=maxpower) { resb = data.val & data.position; data.position >>= 1; if (data.position == 0) { data.position = resetValue; data.val = getNextValue(data.index++); } bits |= (resb>0 ? 1 : 0) * power; power <<= 1; } switch (next = bits) { case 0: bits = 0; maxpower = Math.pow(2,8); power=1; while (power!=maxpower) { resb = data.val & data.position; data.position >>= 1; if (data.position == 0) { data.position = resetValue; data.val = getNextValue(data.index++); } bits |= (resb>0 ? 1 : 0) * power; power <<= 1; } c = f(bits); break; case 1: bits = 0; maxpower = Math.pow(2,16); power=1; while (power!=maxpower) { resb = data.val & data.position; data.position >>= 1; if (data.position == 0) { data.position = resetValue; data.val = getNextValue(data.index++); } bits |= (resb>0 ? 1 : 0) * power; power <<= 1; } c = f(bits); break; case 2: return ""; } dictionary[3] = c; w = c; result.push(c); while (true) { if (data.index > length) { return ""; } bits = 0; maxpower = Math.pow(2,numBits); power=1; while (power!=maxpower) { resb = data.val & data.position; data.position >>= 1; if (data.position == 0) { data.position = resetValue; data.val = getNextValue(data.index++); } bits |= (resb>0 ? 1 : 0) * power; power <<= 1; } switch (c = bits) { case 0: bits = 0; maxpower = Math.pow(2,8); power=1; while (power!=maxpower) { resb = data.val & data.position; data.position >>= 1; if (data.position == 0) { data.position = resetValue; data.val = getNextValue(data.index++); } bits |= (resb>0 ? 1 : 0) * power; power <<= 1; } dictionary[dictSize++] = f(bits); c = dictSize-1; enlargeIn--; break; case 1: bits = 0; maxpower = Math.pow(2,16); power=1; while (power!=maxpower) { resb = data.val & data.position; data.position >>= 1; if (data.position == 0) { data.position = resetValue; data.val = getNextValue(data.index++); } bits |= (resb>0 ? 1 : 0) * power; power <<= 1; } dictionary[dictSize++] = f(bits); c = dictSize-1; enlargeIn--; break; case 2: return result.join(''); } if (enlargeIn == 0) { enlargeIn = Math.pow(2, numBits); numBits++; } if (dictionary[c]) { entry = dictionary[c]; } else { if (c === dictSize) { entry = w + w.charAt(0); } else { return null; } } result.push(entry); // Add w+entry[0] to the dictionary. dictionary[dictSize++] = w + entry.charAt(0); enlargeIn--; w = entry; if (enlargeIn == 0) { enlargeIn = Math.pow(2, numBits); numBits++; } } } }; return LZString; })(); if (typeof define === 'function' && define.amd) { define(function () { return LZString; }); } else if( typeof module !== 'undefined' && module != null ) { module.exports = LZString } "
"'use strict'; var KEBAB_REGEX = /[A-Z]/g; var hash = function (str) { var hash = 5381, i = str.length; while (i) hash = (hash * 33) ^ str.charCodeAt(--i); return '_' + (hash >>> 0).toString(36); }; exports.create = function (config) { config = config || {}; var assign = config.assign || Object.assign; var client = typeof window === 'object'; // Check if we are really in browser environment. if (process.env.NODE_ENV !== 'production') { if (client) { if ((typeof document !== 'object') || !document.getElementsByTagName('HTML')) { console.error( 'nano-css detected browser environment because of "window" global, but ' + '"document" global seems to be defective.' ); } } } var renderer = assign({ raw: '', pfx: '_', client: client, assign: assign, stringify: JSON.stringify, kebab: function (prop) { return prop.replace(KEBAB_REGEX, '-$&').toLowerCase(); }, decl: function (key, value) { key = renderer.kebab(key); return key + ':' + value + ';'; }, hash: function (obj) { return hash(renderer.stringify(obj)); }, selector: function (parent, selector) { return parent + (selector[0] === ':' ? '' : ' ') + selector; }, putRaw: function (rawCssRule) { renderer.raw += rawCssRule; }, }, config); if (renderer.client) { if (!renderer.sh) document.head.appendChild(renderer.sh = document.createElement('style')); if (process.env.NODE_ENV !== 'production') { renderer.sh.setAttribute('data-nano-css-dev', ''); // Test style sheet used in DEV mode to test if .insetRule() would throw. renderer.shTest = document.createElement('style'); renderer.shTest.setAttribute('data-nano-css-dev-tests', ''); document.head.appendChild(renderer.shTest); } renderer.putRaw = function (rawCssRule) { // .insertRule() is faster than .appendChild(), that's why we use it in PROD. // But CSS injected using .insertRule() is not displayed in Chrome Devtools, // that's why we use .appendChild in DEV. if (process.env.NODE_ENV === 'production') { var sheet = renderer.sh.sheet; // Unknown pseudo-selectors will throw, this try/catch swallows all errors. try { sheet.insertRule(rawCssRule, sheet.cssRules.length); // eslint-disable-next-line no-empty } catch (error) {} } else { // Test if .insertRule() works in dev mode. Unknown pseudo-selectors will throw when // .insertRule() is used, but .appendChild() will not throw. try { renderer.shTest.sheet.insertRule(rawCssRule, renderer.shTest.sheet.cssRules.length); } catch (error) { if (config.verbose) { console.error(error); } } // Insert pretty-printed CSS for dev mode. renderer.sh.appendChild(document.createTextNode(rawCssRule)); } }; } renderer.put = function (selector, decls, atrule) { var str = ''; var prop, value; var postponed = []; for (prop in decls) { value = decls[prop]; if ((value instanceof Object) && !(value instanceof Array)) { postponed.push(prop); } else { if ((process.env.NODE_ENV !== 'production') && !renderer.sourcemaps) { str += ' ' + renderer.decl(prop, value, selector, atrule) + '\n'; } else { str += renderer.decl(prop, value, selector, atrule); } } } if (str) { if ((process.env.NODE_ENV !== 'production') && !renderer.sourcemaps) { str = '\n' + selector + ' {\n' + str + '}\n'; } else { str = selector + '{' + str + '}'; } renderer.putRaw(atrule ? atrule + '{' + str + '}' : str); } for (var i = 0; i < postponed.length; i++) { prop = postponed[i]; if (prop[0] === "@" && prop !== "@font-face") { renderer.putAt(selector, decls[prop], prop); } else { renderer.put(renderer.selector(selector, prop), decls[prop], atrule); } } }; renderer.putAt = renderer.put; return renderer; }; "
"var api = require("!../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js"); var content = require("!!../../node_modules/css-loader/dist/cjs.js!../../node_modules/postcss-loader/src/index.js??ref--5-2!../../node_modules/less-loader/dist/cjs.js!./global.less"); content = content.__esModule ? content.default : content; if (typeof content === 'string') { content = [[module.id, content, '']]; } var options = {}; options.insert = "head"; options.singleton = false; var update = api(content, options); module.exports = content.locals || {};"
"'use strict'; module.exports = function html_entity_decode(string, quoteStyle) { // eslint-disable-line camelcase // discuss at: http://locutus.io/php/html_entity_decode/ // original by: john (http://www.jd-tech.net) // input by: ger // input by: Ratheous // input by: Nick Kolosov (http://sammy.ru) // improved by: Kevin van Zonneveld (http://kvz.io) // improved by: marc andreu // revised by: Kevin van Zonneveld (http://kvz.io) // revised by: Kevin van Zonneveld (http://kvz.io) // bugfixed by: Onno Marsman (https://twitter.com/onnomarsman) // bugfixed by: Brett Zamir (http://brett-zamir.me) // bugfixed by: Fox // example 1: html_entity_decode('Kevin &amp; van Zonneveld') // returns 1: 'Kevin & van Zonneveld' // example 2: html_entity_decode('&amp;lt;') // returns 2: '&lt;' var getHtmlTranslationTable = require('../strings/get_html_translation_table'); var tmpStr = ''; var entity = ''; var symbol = ''; tmpStr = string.toString(); var hashMap = getHtmlTranslationTable('HTML_ENTITIES', quoteStyle); if (hashMap === false) { return false; } // @todo: &amp; problem // http://locutus.io/php/get_html_translation_table:416#comment_97660 delete hashMap['&']; hashMap['&'] = '&amp;'; for (symbol in hashMap) { entity = hashMap[symbol]; tmpStr = tmpStr.split(entity).join(symbol); } tmpStr = tmpStr.split('&#039;').join("'"); return tmpStr; }; //# sourceMappingURL=html_entity_decode.js.map"
"module.exports = function() { return require("!!./node_modules/worker-loader/dist/workers/InlineWorker.js")("!function(t){var e={};function r(i){if(e[i])return e[i].exports;var n=e[i]={i:i,l:!1,exports:{}};t[i].call(n.exports,n,n.exports,r);n.l=!0;return n.exports}r.m=t;r.c=e;r.d=function(t,e,i){if(!r.o(t,e))Object.defineProperty(t,e,{enumerable:!0,get:i})};r.r=function(t){if(\"undefined\"!=typeof Symbol&&Symbol.toStringTag)Object.defineProperty(t,Symbol.toStringTag,{value:\"Module\"});Object.defineProperty(t,\"__esModule\",{value:!0})};r.t=function(t,e){if(1&e)t=r(t);if(8&e)return t;if(4&e&&\"object\"==typeof t&&t&&t.__esModule)return t;var i=Object.create(null);r.r(i);Object.defineProperty(i,\"default\",{enumerable:!0,value:t});if(2&e&&\"string\"!=typeof t)for(var n in t)r.d(i,n,function(e){return t[e]}.bind(null,n));return i};r.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};r.d(e,\"a\",e);return e};r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)};r.p=\"\";r(r.s=28)}([function(t,e,r){\"use strict\";const i=\"undefined\"==typeof window?self:window;i.convenientDiscussions=i.convenientDiscussions||{};if(\"object\"!=typeof i.convenientDiscussions)i.convenientDiscussions={};e.a=i.convenientDiscussions},function(t,e,r){\"use strict\";r.d(e,\"f\",(function(){return n}));r.d(e,\"a\",(function(){return s}));r.d(e,\"c\",(function(){return o}));r.d(e,\"i\",(function(){return a}));r.d(e,\"h\",(function(){return u}));r.d(e,\"b\",(function(){return c}));r.d(e,\"d\",(function(){return l}));r.d(e,\"e\",(function(){return f}));r.d(e,\"g\",(function(){return h}));r(23),r(4);var i=r(0);function n(t,e){if(e&&t.nodeType===Node.TEXT_NODE)return!0;if(t.nodeType!==Node.ELEMENT_NODE)return null;if(i.a.g.POPULAR_INLINE_ELEMENTS.includes(t.tagName))return!0;else if(i.a.g.POPULAR_NOT_INLINE_ELEMENTS.includes(t.tagName))return!1;else if(\"undefined\"!=typeof window){console.warn(\"Expensive operation: isInline() called for:\",t);return window.getComputedStyle(t).display.startsWith(\"inline\")}else return null}function s(t){return void 0!==t}function o(t){return[].concat(...t)}function a(t){return t.replace(/_/g,\" \")}function u(t){return t.replace(/ /g,\"_\")}function c(t){return t.length?function(t){if(\"\"===i.a.g.PHP_CHAR_TO_UPPER_JSON[t])return t;else return i.a.g.PHP_CHAR_TO_UPPER_JSON[t]||t.toUpperCase()}(t[0])+t.slice(1):\"\"}function l(t){return t.map(mw.msg)}function f(t,e,r,i){return t.replace(e,(t,e,n)=>{if(\"number\"==typeof e){e=null;n=null}return(e||\"\")+(i?\"\\x03\":\"\\x01\")+r.push(n||t)+(i?\"\\x04\":\"\\x02\")})}function h(t){return t.replace(/[\\u200E\\u200F]/g,\"\")}},function(t,e,r){\"use strict\";r.d(e,\"b\",(function(){return a}));r.d(e,\"a\",(function(){return c}));r.d(e,\"c\",(function(){return f}));r.d(e,\"d\",(function(){return h}));var i=r(0),n=r(1);let s,o;function a(t,e){t=Object(n.g)(t);if(!s){s=new RegExp(\"^([^]*)(\".concat(i.a.g.TIMESTAMP_REGEXP.source,\")(?![\\\"'\\xbb])\"));o=new RegExp(\"^([^]*)(\".concat(i.a.g.TIMESTAMP_REGEXP_NO_TIMEZONE.source,\")\"))}const r=void 0===e?s:o,a=t.match(r);if(!a)return null;else return{date:i.a.g.TIMESTAMP_PARSER(a,i.a,e),match:a}}function u(t,e){return(\"0000\"+t).slice(-e)}function c(t,e,r=!1){let i=t.getUTCFullYear(),s=t.getUTCMonth(),o=t.getUTCDate(),a=t.getUTCHours(),c=t.getUTCMinutes(),f=u(i,4)+u(s+1,2)+u(o,2)+u(a,2)+u(c,2)+(e?\"_\"+Object(n.h)(e):\"\");if(r&&l.includes(f)){let t=2;const e=f;do{f=\"\".concat(e,\"_\").concat(t);t++}while(l.includes(f))}return f}let l=[];function f(t){if(t)l.push(t)}function h(){l=[]}},function(t,e,r){\"use strict\";function i(t){for(var r in t)if(!e.hasOwnProperty(r))e[r]=t[r]}var n=this&&this.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var r in t)if(Object.hasOwnProperty.call(t,r))e[r]=t[r];e.default=t;return e};Object.defineProperty(e,\"__esModule\",{value:!0});var s=r(10);e.Parser=s.Parser;var o=r(14);e.DomHandler=o.DomHandler;e.DefaultHandler=o.DomHandler;e.parseDOM=function(t,e){var r=new o.DomHandler(void 0,e);new s.Parser(r,e).end(t);return r.dom};e.createDomStream=function(t,e,r){var i=new o.DomHandler(t,e,r);return new s.Parser(i,e)};var a=r(11);e.Tokenizer=a.default;var u=n(r(9));e.ElementType=u;e.EVENTS={attribute:2,cdatastart:0,cdataend:0,text:1,processinginstruction:2,comment:1,commentend:0,closetag:1,opentag:2,opentagname:1,error:1,end:0};i(r(15));i(r(41));i(r(42));var c=n(r(16));e.DomUtils=c;var l=r(15);e.RssHandler=l.FeedHandler},function(t,e,r){\"use strict\";r.d(e,\"a\",(function(){return CdError}));class CdError extends Error{constructor(t){let e;if(t){var r,i;e=t.type;if(t.code)e+=\"/\".concat(t.code);if(null==t?void 0:null===(r=t.apiData)||void 0===r?void 0:null===(i=r.error)||void 0===i?void 0:i.code)e+=\"/\".concat(t.apiData.error.code)}else e=\"\";super(e);this.name=\"CdError\";this.data=t}}},function(t,e,r){\"use strict\";r.d(e,\"c\",(function(){return TreeWalker}));r.d(e,\"b\",(function(){return ElementsTreeWalker}));r.d(e,\"a\",(function(){return ElementsAndTextTreeWalker}));var i=r(0);class TreeWalker{constructor(t,e,r=!1,i=t){this.acceptNode=e;this.root=t;this.currentNode=i;if(r){this.firstChildProperty=\"firstElementChild\";this.lastChildProperty=\"lastElementChild\";this.previousSiblingProperty=\"previousElementSibling\";this.nextSiblingProperty=\"nextElementSibling\"}else{this.firstChildProperty=\"firstChild\";this.lastChildProperty=\"lastChild\";this.previousSiblingProperty=\"previousSibling\";this.nextSiblingProperty=\"nextSibling\"}}tryMove(t){let e=this.currentNode;if(e===this.root&&!t.includes(\"Child\"))return null;do{e=e[t]}while(e&&this.acceptNode&&!this.acceptNode(e));if(e)this.currentNode=e;return e||null}parentNode(){return this.tryMove(\"parentNode\")}firstChild(){return this.tryMove(this.firstChildProperty)}lastChild(){return this.tryMove(this.lastChildProperty)}previousSibling(){return this.tryMove(this.previousSiblingProperty)}nextSibling(){return this.tryMove(this.nextSiblingProperty)}nextNode(){let t=this.currentNode;do{if(t[this.firstChildProperty])t=t[this.firstChildProperty];else{for(;t&&!t[this.nextSiblingProperty]&&t.parentNode!==this.root;)t=t.parentNode;if(t)t=t[this.nextSiblingProperty]}}while(t&&this.acceptNode&&!this.acceptNode(t));if(t)this.currentNode=t;return t}previousNode(){let t=this.currentNode;if(t!==this.root){do{if(t[this.previousSiblingProperty]){t=t[this.previousSiblingProperty];for(;t[this.lastChildProperty];)t=t[this.lastChildProperty]}else t=t.parentNode}while(t&&this.acceptNode&&!this.acceptNode(t));if(t)this.currentNode=t;return t}}}class ElementsTreeWalker extends TreeWalker{constructor(t){super(i.a.g.rootElement,null,!0);if(t)this.currentNode=t}}class ElementsAndTextTreeWalker extends TreeWalker{constructor(t){super(i.a.g.rootElement,t=>t.nodeType===Node.TEXT_NODE||t.nodeType===Node.ELEMENT_NODE);if(t)this.currentNode=t}}},function(t,e,r){\"use strict\";Object.defineProperty(e,\"__esModule\",{value:!0});var i=r(9);e.isTag=function(t){return i.isTag(t)};e.isCDATA=function(t){return\"cdata\"===t.type};e.isText=function(t){return\"text\"===t.type};e.isComment=function(t){return\"comment\"===t.type};e.hasChildren=function(t){return Object.prototype.hasOwnProperty.call(t,\"children\")}},function(t){t.exports=JSON.parse('{\"Aacute\":\"\\xc1\",\"aacute\":\"\\xe1\",\"Abreve\":\"\\u0102\",\"abreve\":\"\\u0103\",\"ac\":\"\\u223e\",\"acd\":\"\\u223f\",\"acE\":\"\\u223e\\u0333\",\"Acirc\":\"\\xc2\",\"acirc\":\"\\xe2\",\"acute\":\"\\xb4\",\"Acy\":\"\\u0410\",\"acy\":\"\\u0430\",\"AElig\":\"\\xc6\",\"aelig\":\"\\xe6\",\"af\":\"\\u2061\",\"Afr\":\"\\ud835\\udd04\",\"afr\":\"\\ud835\\udd1e\",\"Agrave\":\"\\xc0\",\"agrave\":\"\\xe0\",\"alefsym\":\"\\u2135\",\"aleph\":\"\\u2135\",\"Alpha\":\"\\u0391\",\"alpha\":\"\\u03b1\",\"Amacr\":\"\\u0100\",\"amacr\":\"\\u0101\",\"amalg\":\"\\u2a3f\",\"amp\":\"&\",\"AMP\":\"&\",\"andand\":\"\\u2a55\",\"And\":\"\\u2a53\",\"and\":\"\\u2227\",\"andd\":\"\\u2a5c\",\"andslope\":\"\\u2a58\",\"andv\":\"\\u2a5a\",\"ang\":\"\\u2220\",\"ange\":\"\\u29a4\",\"angle\":\"\\u2220\",\"angmsdaa\":\"\\u29a8\",\"angmsdab\":\"\\u29a9\",\"angmsdac\":\"\\u29aa\",\"angmsdad\":\"\\u29ab\",\"angmsdae\":\"\\u29ac\",\"angmsdaf\":\"\\u29ad\",\"angmsdag\":\"\\u29ae\",\"angmsdah\":\"\\u29af\",\"angmsd\":\"\\u2221\",\"angrt\":\"\\u221f\",\"angrtvb\":\"\\u22be\",\"angrtvbd\":\"\\u299d\",\"angsph\":\"\\u2222\",\"angst\":\"\\xc5\",\"angzarr\":\"\\u237c\",\"Aogon\":\"\\u0104\",\"aogon\":\"\\u0105\",\"Aopf\":\"\\ud835\\udd38\",\"aopf\":\"\\ud835\\udd52\",\"apacir\":\"\\u2a6f\",\"ap\":\"\\u2248\",\"apE\":\"\\u2a70\",\"ape\":\"\\u224a\",\"apid\":\"\\u224b\",\"apos\":\"\\'\",\"ApplyFunction\":\"\\u2061\",\"approx\":\"\\u2248\",\"approxeq\":\"\\u224a\",\"Aring\":\"\\xc5\",\"aring\":\"\\xe5\",\"Ascr\":\"\\ud835\\udc9c\",\"ascr\":\"\\ud835\\udcb6\",\"Assign\":\"\\u2254\",\"ast\":\"*\",\"asymp\":\"\\u2248\",\"asympeq\":\"\\u224d\",\"Atilde\":\"\\xc3\",\"atilde\":\"\\xe3\",\"Auml\":\"\\xc4\",\"auml\":\"\\xe4\",\"awconint\":\"\\u2233\",\"awint\":\"\\u2a11\",\"backcong\":\"\\u224c\",\"backepsilon\":\"\\u03f6\",\"backprime\":\"\\u2035\",\"backsim\":\"\\u223d\",\"backsimeq\":\"\\u22cd\",\"Backslash\":\"\\u2216\",\"Barv\":\"\\u2ae7\",\"barvee\":\"\\u22bd\",\"barwed\":\"\\u2305\",\"Barwed\":\"\\u2306\",\"barwedge\":\"\\u2305\",\"bbrk\":\"\\u23b5\",\"bbrktbrk\":\"\\u23b6\",\"bcong\":\"\\u224c\",\"Bcy\":\"\\u0411\",\"bcy\":\"\\u0431\",\"bdquo\":\"\\u201e\",\"becaus\":\"\\u2235\",\"because\":\"\\u2235\",\"Because\":\"\\u2235\",\"bemptyv\":\"\\u29b0\",\"bepsi\":\"\\u03f6\",\"bernou\":\"\\u212c\",\"Bernoullis\":\"\\u212c\",\"Beta\":\"\\u0392\",\"beta\":\"\\u03b2\",\"beth\":\"\\u2136\",\"between\":\"\\u226c\",\"Bfr\":\"\\ud835\\udd05\",\"bfr\":\"\\ud835\\udd1f\",\"bigcap\":\"\\u22c2\",\"bigcirc\":\"\\u25ef\",\"bigcup\":\"\\u22c3\",\"bigodot\":\"\\u2a00\",\"bigoplus\":\"\\u2a01\",\"bigotimes\":\"\\u2a02\",\"bigsqcup\":\"\\u2a06\",\"bigstar\":\"\\u2605\",\"bigtriangledown\":\"\\u25bd\",\"bigtriangleup\":\"\\u25b3\",\"biguplus\":\"\\u2a04\",\"bigvee\":\"\\u22c1\",\"bigwedge\":\"\\u22c0\",\"bkarow\":\"\\u290d\",\"blacklozenge\":\"\\u29eb\",\"blacksquare\":\"\\u25aa\",\"blacktriangle\":\"\\u25b4\",\"blacktriangledown\":\"\\u25be\",\"blacktriangleleft\":\"\\u25c2\",\"blacktriangleright\":\"\\u25b8\",\"blank\":\"\\u2423\",\"blk12\":\"\\u2592\",\"blk14\":\"\\u2591\",\"blk34\":\"\\u2593\",\"block\":\"\\u2588\",\"bne\":\"=\\u20e5\",\"bnequiv\":\"\\u2261\\u20e5\",\"bNot\":\"\\u2aed\",\"bnot\":\"\\u2310\",\"Bopf\":\"\\ud835\\udd39\",\"bopf\":\"\\ud835\\udd53\",\"bot\":\"\\u22a5\",\"bottom\":\"\\u22a5\",\"bowtie\":\"\\u22c8\",\"boxbox\":\"\\u29c9\",\"boxdl\":\"\\u2510\",\"boxdL\":\"\\u2555\",\"boxDl\":\"\\u2556\",\"boxDL\":\"\\u2557\",\"boxdr\":\"\\u250c\",\"boxdR\":\"\\u2552\",\"boxDr\":\"\\u2553\",\"boxDR\":\"\\u2554\",\"boxh\":\"\\u2500\",\"boxH\":\"\\u2550\",\"boxhd\":\"\\u252c\",\"boxHd\":\"\\u2564\",\"boxhD\":\"\\u2565\",\"boxHD\":\"\\u2566\",\"boxhu\":\"\\u2534\",\"boxHu\":\"\\u2567\",\"boxhU\":\"\\u2568\",\"boxHU\":\"\\u2569\",\"boxminus\":\"\\u229f\",\"boxplus\":\"\\u229e\",\"boxtimes\":\"\\u22a0\",\"boxul\":\"\\u2518\",\"boxuL\":\"\\u255b\",\"boxUl\":\"\\u255c\",\"boxUL\":\"\\u255d\",\"boxur\":\"\\u2514\",\"boxuR\":\"\\u2558\",\"boxUr\":\"\\u2559\",\"boxUR\":\"\\u255a\",\"boxv\":\"\\u2502\",\"boxV\":\"\\u2551\",\"boxvh\":\"\\u253c\",\"boxvH\":\"\\u256a\",\"boxVh\":\"\\u256b\",\"boxVH\":\"\\u256c\",\"boxvl\":\"\\u2524\",\"boxvL\":\"\\u2561\",\"boxVl\":\"\\u2562\",\"boxVL\":\"\\u2563\",\"boxvr\":\"\\u251c\",\"boxvR\":\"\\u255e\",\"boxVr\":\"\\u255f\",\"boxVR\":\"\\u2560\",\"bprime\":\"\\u2035\",\"breve\":\"\\u02d8\",\"Breve\":\"\\u02d8\",\"brvbar\":\"\\xa6\",\"bscr\":\"\\ud835\\udcb7\",\"Bscr\":\"\\u212c\",\"bsemi\":\"\\u204f\",\"bsim\":\"\\u223d\",\"bsime\":\"\\u22cd\",\"bsolb\":\"\\u29c5\",\"bsol\":\"\\\\\\\\\",\"bsolhsub\":\"\\u27c8\",\"bull\":\"\\u2022\",\"bullet\":\"\\u2022\",\"bump\":\"\\u224e\",\"bumpE\":\"\\u2aae\",\"bumpe\":\"\\u224f\",\"Bumpeq\":\"\\u224e\",\"bumpeq\":\"\\u224f\",\"Cacute\":\"\\u0106\",\"cacute\":\"\\u0107\",\"capand\":\"\\u2a44\",\"capbrcup\":\"\\u2a49\",\"capcap\":\"\\u2a4b\",\"cap\":\"\\u2229\",\"Cap\":\"\\u22d2\",\"capcup\":\"\\u2a47\",\"capdot\":\"\\u2a40\",\"CapitalDifferentialD\":\"\\u2145\",\"caps\":\"\\u2229\\ufe00\",\"caret\":\"\\u2041\",\"caron\":\"\\u02c7\",\"Cayleys\":\"\\u212d\",\"ccaps\":\"\\u2a4d\",\"Ccaron\":\"\\u010c\",\"ccaron\":\"\\u010d\",\"Ccedil\":\"\\xc7\",\"ccedil\":\"\\xe7\",\"Ccirc\":\"\\u0108\",\"ccirc\":\"\\u0109\",\"Cconint\":\"\\u2230\",\"ccups\":\"\\u2a4c\",\"ccupssm\":\"\\u2a50\",\"Cdot\":\"\\u010a\",\"cdot\":\"\\u010b\",\"cedil\":\"\\xb8\",\"Cedilla\":\"\\xb8\",\"cemptyv\":\"\\u29b2\",\"cent\":\"\\xa2\",\"centerdot\":\"\\xb7\",\"CenterDot\":\"\\xb7\",\"cfr\":\"\\ud835\\udd20\",\"Cfr\":\"\\u212d\",\"CHcy\":\"\\u0427\",\"chcy\":\"\\u0447\",\"check\":\"\\u2713\",\"checkmark\":\"\\u2713\",\"Chi\":\"\\u03a7\",\"chi\":\"\\u03c7\",\"circ\":\"\\u02c6\",\"circeq\":\"\\u2257\",\"circlearrowleft\":\"\\u21ba\",\"circlearrowright\":\"\\u21bb\",\"circledast\":\"\\u229b\",\"circledcirc\":\"\\u229a\",\"circleddash\":\"\\u229d\",\"CircleDot\":\"\\u2299\",\"circledR\":\"\\xae\",\"circledS\":\"\\u24c8\",\"CircleMinus\":\"\\u2296\",\"CirclePlus\":\"\\u2295\",\"CircleTimes\":\"\\u2297\",\"cir\":\"\\u25cb\",\"cirE\":\"\\u29c3\",\"cire\":\"\\u2257\",\"cirfnint\":\"\\u2a10\",\"cirmid\":\"\\u2aef\",\"cirscir\":\"\\u29c2\",\"ClockwiseContourIntegral\":\"\\u2232\",\"CloseCurlyDoubleQuote\":\"\\u201d\",\"CloseCurlyQuote\":\"\\u2019\",\"clubs\":\"\\u2663\",\"clubsuit\":\"\\u2663\",\"colon\":\":\",\"Colon\":\"\\u2237\",\"Colone\":\"\\u2a74\",\"colone\":\"\\u2254\",\"coloneq\":\"\\u2254\",\"comma\":\",\",\"commat\":\"@\",\"comp\":\"\\u2201\",\"compfn\":\"\\u2218\",\"complement\":\"\\u2201\",\"complexes\":\"\\u2102\",\"cong\":\"\\u2245\",\"congdot\":\"\\u2a6d\",\"Congruent\":\"\\u2261\",\"conint\":\"\\u222e\",\"Conint\":\"\\u222f\",\"ContourIntegral\":\"\\u222e\",\"copf\":\"\\ud835\\udd54\",\"Copf\":\"\\u2102\",\"coprod\":\"\\u2210\",\"Coproduct\":\"\\u2210\",\"copy\":\"\\xa9\",\"COPY\":\"\\xa9\",\"copysr\":\"\\u2117\",\"CounterClockwiseContourIntegral\":\"\\u2233\",\"crarr\":\"\\u21b5\",\"cross\":\"\\u2717\",\"Cross\":\"\\u2a2f\",\"Cscr\":\"\\ud835\\udc9e\",\"cscr\":\"\\ud835\\udcb8\",\"csub\":\"\\u2acf\",\"csube\":\"\\u2ad1\",\"csup\":\"\\u2ad0\",\"csupe\":\"\\u2ad2\",\"ctdot\":\"\\u22ef\",\"cudarrl\":\"\\u2938\",\"cudarrr\":\"\\u2935\",\"cuepr\":\"\\u22de\",\"cuesc\":\"\\u22df\",\"cularr\":\"\\u21b6\",\"cularrp\":\"\\u293d\",\"cupbrcap\":\"\\u2a48\",\"cupcap\":\"\\u2a46\",\"CupCap\":\"\\u224d\",\"cup\":\"\\u222a\",\"Cup\":\"\\u22d3\",\"cupcup\":\"\\u2a4a\",\"cupdot\":\"\\u228d\",\"cupor\":\"\\u2a45\",\"cups\":\"\\u222a\\ufe00\",\"curarr\":\"\\u21b7\",\"curarrm\":\"\\u293c\",\"curlyeqprec\":\"\\u22de\",\"curlyeqsucc\":\"\\u22df\",\"curlyvee\":\"\\u22ce\",\"curlywedge\":\"\\u22cf\",\"curren\":\"\\xa4\",\"curvearrowleft\":\"\\u21b6\",\"curvearrowright\":\"\\u21b7\",\"cuvee\":\"\\u22ce\",\"cuwed\":\"\\u22cf\",\"cwconint\":\"\\u2232\",\"cwint\":\"\\u2231\",\"cylcty\":\"\\u232d\",\"dagger\":\"\\u2020\",\"Dagger\":\"\\u2021\",\"daleth\":\"\\u2138\",\"darr\":\"\\u2193\",\"Darr\":\"\\u21a1\",\"dArr\":\"\\u21d3\",\"dash\":\"\\u2010\",\"Dashv\":\"\\u2ae4\",\"dashv\":\"\\u22a3\",\"dbkarow\":\"\\u290f\",\"dblac\":\"\\u02dd\",\"Dcaron\":\"\\u010e\",\"dcaron\":\"\\u010f\",\"Dcy\":\"\\u0414\",\"dcy\":\"\\u0434\",\"ddagger\":\"\\u2021\",\"ddarr\":\"\\u21ca\",\"DD\":\"\\u2145\",\"dd\":\"\\u2146\",\"DDotrahd\":\"\\u2911\",\"ddotseq\":\"\\u2a77\",\"deg\":\"\\xb0\",\"Del\":\"\\u2207\",\"Delta\":\"\\u0394\",\"delta\":\"\\u03b4\",\"demptyv\":\"\\u29b1\",\"dfisht\":\"\\u297f\",\"Dfr\":\"\\ud835\\udd07\",\"dfr\":\"\\ud835\\udd21\",\"dHar\":\"\\u2965\",\"dharl\":\"\\u21c3\",\"dharr\":\"\\u21c2\",\"DiacriticalAcute\":\"\\xb4\",\"DiacriticalDot\":\"\\u02d9\",\"DiacriticalDoubleAcute\":\"\\u02dd\",\"DiacriticalGrave\":\"`\",\"DiacriticalTilde\":\"\\u02dc\",\"diam\":\"\\u22c4\",\"diamond\":\"\\u22c4\",\"Diamond\":\"\\u22c4\",\"diamondsuit\":\"\\u2666\",\"diams\":\"\\u2666\",\"die\":\"\\xa8\",\"DifferentialD\":\"\\u2146\",\"digamma\":\"\\u03dd\",\"disin\":\"\\u22f2\",\"div\":\"\\xf7\",\"divide\":\"\\xf7\",\"divideontimes\":\"\\u22c7\",\"divonx\":\"\\u22c7\",\"DJcy\":\"\\u0402\",\"djcy\":\"\\u0452\",\"dlcorn\":\"\\u231e\",\"dlcrop\":\"\\u230d\",\"dollar\":\"$\",\"Dopf\":\"\\ud835\\udd3b\",\"dopf\":\"\\ud835\\udd55\",\"Dot\":\"\\xa8\",\"dot\":\"\\u02d9\",\"DotDot\":\"\\u20dc\",\"doteq\":\"\\u2250\",\"doteqdot\":\"\\u2251\",\"DotEqual\":\"\\u2250\",\"dotminus\":\"\\u2238\",\"dotplus\":\"\\u2214\",\"dotsquare\":\"\\u22a1\",\"doublebarwedge\":\"\\u2306\",\"DoubleContourIntegral\":\"\\u222f\",\"DoubleDot\":\"\\xa8\",\"DoubleDownArrow\":\"\\u21d3\",\"DoubleLeftArrow\":\"\\u21d0\",\"DoubleLeftRightArrow\":\"\\u21d4\",\"DoubleLeftTee\":\"\\u2ae4\",\"DoubleLongLeftArrow\":\"\\u27f8\",\"DoubleLongLeftRightArrow\":\"\\u27fa\",\"DoubleLongRightArrow\":\"\\u27f9\",\"DoubleRightArrow\":\"\\u21d2\",\"DoubleRightTee\":\"\\u22a8\",\"DoubleUpArrow\":\"\\u21d1\",\"DoubleUpDownArrow\":\"\\u21d5\",\"DoubleVerticalBar\":\"\\u2225\",\"DownArrowBar\":\"\\u2913\",\"downarrow\":\"\\u2193\",\"DownArrow\":\"\\u2193\",\"Downarrow\":\"\\u21d3\",\"DownArrowUpArrow\":\"\\u21f5\",\"DownBreve\":\"\\u0311\",\"downdownarrows\":\"\\u21ca\",\"downharpoonleft\":\"\\u21c3\",\"downharpoonright\":\"\\u21c2\",\"DownLeftRightVector\":\"\\u2950\",\"DownLeftTeeVector\":\"\\u295e\",\"DownLeftVectorBar\":\"\\u2956\",\"DownLeftVector\":\"\\u21bd\",\"DownRightTeeVector\":\"\\u295f\",\"DownRightVectorBar\":\"\\u2957\",\"DownRightVector\":\"\\u21c1\",\"DownTeeArrow\":\"\\u21a7\",\"DownTee\":\"\\u22a4\",\"drbkarow\":\"\\u2910\",\"drcorn\":\"\\u231f\",\"drcrop\":\"\\u230c\",\"Dscr\":\"\\ud835\\udc9f\",\"dscr\":\"\\ud835\\udcb9\",\"DScy\":\"\\u0405\",\"dscy\":\"\\u0455\",\"dsol\":\"\\u29f6\",\"Dstrok\":\"\\u0110\",\"dstrok\":\"\\u0111\",\"dtdot\":\"\\u22f1\",\"dtri\":\"\\u25bf\",\"dtrif\":\"\\u25be\",\"duarr\":\"\\u21f5\",\"duhar\":\"\\u296f\",\"dwangle\":\"\\u29a6\",\"DZcy\":\"\\u040f\",\"dzcy\":\"\\u045f\",\"dzigrarr\":\"\\u27ff\",\"Eacute\":\"\\xc9\",\"eacute\":\"\\xe9\",\"easter\":\"\\u2a6e\",\"Ecaron\":\"\\u011a\",\"ecaron\":\"\\u011b\",\"Ecirc\":\"\\xca\",\"ecirc\":\"\\xea\",\"ecir\":\"\\u2256\",\"ecolon\":\"\\u2255\",\"Ecy\":\"\\u042d\",\"ecy\":\"\\u044d\",\"eDDot\":\"\\u2a77\",\"Edot\":\"\\u0116\",\"edot\":\"\\u0117\",\"eDot\":\"\\u2251\",\"ee\":\"\\u2147\",\"efDot\":\"\\u2252\",\"Efr\":\"\\ud835\\udd08\",\"efr\":\"\\ud835\\udd22\",\"eg\":\"\\u2a9a\",\"Egrave\":\"\\xc8\",\"egrave\":\"\\xe8\",\"egs\":\"\\u2a96\",\"egsdot\":\"\\u2a98\",\"el\":\"\\u2a99\",\"Element\":\"\\u2208\",\"elinters\":\"\\u23e7\",\"ell\":\"\\u2113\",\"els\":\"\\u2a95\",\"elsdot\":\"\\u2a97\",\"Emacr\":\"\\u0112\",\"emacr\":\"\\u0113\",\"empty\":\"\\u2205\",\"emptyset\":\"\\u2205\",\"EmptySmallSquare\":\"\\u25fb\",\"emptyv\":\"\\u2205\",\"EmptyVerySmallSquare\":\"\\u25ab\",\"emsp13\":\"\\u2004\",\"emsp14\":\"\\u2005\",\"emsp\":\"\\u2003\",\"ENG\":\"\\u014a\",\"eng\":\"\\u014b\",\"ensp\":\"\\u2002\",\"Eogon\":\"\\u0118\",\"eogon\":\"\\u0119\",\"Eopf\":\"\\ud835\\udd3c\",\"eopf\":\"\\ud835\\udd56\",\"epar\":\"\\u22d5\",\"eparsl\":\"\\u29e3\",\"eplus\":\"\\u2a71\",\"epsi\":\"\\u03b5\",\"Epsilon\":\"\\u0395\",\"epsilon\":\"\\u03b5\",\"epsiv\":\"\\u03f5\",\"eqcirc\":\"\\u2256\",\"eqcolon\":\"\\u2255\",\"eqsim\":\"\\u2242\",\"eqslantgtr\":\"\\u2a96\",\"eqslantless\":\"\\u2a95\",\"Equal\":\"\\u2a75\",\"equals\":\"=\",\"EqualTilde\":\"\\u2242\",\"equest\":\"\\u225f\",\"Equilibrium\":\"\\u21cc\",\"equiv\":\"\\u2261\",\"equivDD\":\"\\u2a78\",\"eqvparsl\":\"\\u29e5\",\"erarr\":\"\\u2971\",\"erDot\":\"\\u2253\",\"escr\":\"\\u212f\",\"Escr\":\"\\u2130\",\"esdot\":\"\\u2250\",\"Esim\":\"\\u2a73\",\"esim\":\"\\u2242\",\"Eta\":\"\\u0397\",\"eta\":\"\\u03b7\",\"ETH\":\"\\xd0\",\"eth\":\"\\xf0\",\"Euml\":\"\\xcb\",\"euml\":\"\\xeb\",\"euro\":\"\\u20ac\",\"excl\":\"!\",\"exist\":\"\\u2203\",\"Exists\":\"\\u2203\",\"expectation\":\"\\u2130\",\"exponentiale\":\"\\u2147\",\"ExponentialE\":\"\\u2147\",\"fallingdotseq\":\"\\u2252\",\"Fcy\":\"\\u0424\",\"fcy\":\"\\u0444\",\"female\":\"\\u2640\",\"ffilig\":\"\\ufb03\",\"fflig\":\"\\ufb00\",\"ffllig\":\"\\ufb04\",\"Ffr\":\"\\ud835\\udd09\",\"ffr\":\"\\ud835\\udd23\",\"filig\":\"\\ufb01\",\"FilledSmallSquare\":\"\\u25fc\",\"FilledVerySmallSquare\":\"\\u25aa\",\"fjlig\":\"fj\",\"flat\":\"\\u266d\",\"fllig\":\"\\ufb02\",\"fltns\":\"\\u25b1\",\"fnof\":\"\\u0192\",\"Fopf\":\"\\ud835\\udd3d\",\"fopf\":\"\\ud835\\udd57\",\"forall\":\"\\u2200\",\"ForAll\":\"\\u2200\",\"fork\":\"\\u22d4\",\"forkv\":\"\\u2ad9\",\"Fouriertrf\":\"\\u2131\",\"fpartint\":\"\\u2a0d\",\"frac12\":\"\\xbd\",\"frac13\":\"\\u2153\",\"frac14\":\"\\xbc\",\"frac15\":\"\\u2155\",\"frac16\":\"\\u2159\",\"frac18\":\"\\u215b\",\"frac23\":\"\\u2154\",\"frac25\":\"\\u2156\",\"frac34\":\"\\xbe\",\"frac35\":\"\\u2157\",\"frac38\":\"\\u215c\",\"frac45\":\"\\u2158\",\"frac56\":\"\\u215a\",\"frac58\":\"\\u215d\",\"frac78\":\"\\u215e\",\"frasl\":\"\\u2044\",\"frown\":\"\\u2322\",\"fscr\":\"\\ud835\\udcbb\",\"Fscr\":\"\\u2131\",\"gacute\":\"\\u01f5\",\"Gamma\":\"\\u0393\",\"gamma\":\"\\u03b3\",\"Gammad\":\"\\u03dc\",\"gammad\":\"\\u03dd\",\"gap\":\"\\u2a86\",\"Gbreve\":\"\\u011e\",\"gbreve\":\"\\u011f\",\"Gcedil\":\"\\u0122\",\"Gcirc\":\"\\u011c\",\"gcirc\":\"\\u011d\",\"Gcy\":\"\\u0413\",\"gcy\":\"\\u0433\",\"Gdot\":\"\\u0120\",\"gdot\":\"\\u0121\",\"ge\":\"\\u2265\",\"gE\":\"\\u2267\",\"gEl\":\"\\u2a8c\",\"gel\":\"\\u22db\",\"geq\":\"\\u2265\",\"geqq\":\"\\u2267\",\"geqslant\":\"\\u2a7e\",\"gescc\":\"\\u2aa9\",\"ges\":\"\\u2a7e\",\"gesdot\":\"\\u2a80\",\"gesdoto\":\"\\u2a82\",\"gesdotol\":\"\\u2a84\",\"gesl\":\"\\u22db\\ufe00\",\"gesles\":\"\\u2a94\",\"Gfr\":\"\\ud835\\udd0a\",\"gfr\":\"\\ud835\\udd24\",\"gg\":\"\\u226b\",\"Gg\":\"\\u22d9\",\"ggg\":\"\\u22d9\",\"gimel\":\"\\u2137\",\"GJcy\":\"\\u0403\",\"gjcy\":\"\\u0453\",\"gla\":\"\\u2aa5\",\"gl\":\"\\u2277\",\"glE\":\"\\u2a92\",\"glj\":\"\\u2aa4\",\"gnap\":\"\\u2a8a\",\"gnapprox\":\"\\u2a8a\",\"gne\":\"\\u2a88\",\"gnE\":\"\\u2269\",\"gneq\":\"\\u2a88\",\"gneqq\":\"\\u2269\",\"gnsim\":\"\\u22e7\",\"Gopf\":\"\\ud835\\udd3e\",\"gopf\":\"\\ud835\\udd58\",\"grave\":\"`\",\"GreaterEqual\":\"\\u2265\",\"GreaterEqualLess\":\"\\u22db\",\"GreaterFullEqual\":\"\\u2267\",\"GreaterGreater\":\"\\u2aa2\",\"GreaterLess\":\"\\u2277\",\"GreaterSlantEqual\":\"\\u2a7e\",\"GreaterTilde\":\"\\u2273\",\"Gscr\":\"\\ud835\\udca2\",\"gscr\":\"\\u210a\",\"gsim\":\"\\u2273\",\"gsime\":\"\\u2a8e\",\"gsiml\":\"\\u2a90\",\"gtcc\":\"\\u2aa7\",\"gtcir\":\"\\u2a7a\",\"gt\":\">\",\"GT\":\">\",\"Gt\":\"\\u226b\",\"gtdot\":\"\\u22d7\",\"gtlPar\":\"\\u2995\",\"gtquest\":\"\\u2a7c\",\"gtrapprox\":\"\\u2a86\",\"gtrarr\":\"\\u2978\",\"gtrdot\":\"\\u22d7\",\"gtreqless\":\"\\u22db\",\"gtreqqless\":\"\\u2a8c\",\"gtrless\":\"\\u2277\",\"gtrsim\":\"\\u2273\",\"gvertneqq\":\"\\u2269\\ufe00\",\"gvnE\":\"\\u2269\\ufe00\",\"Hacek\":\"\\u02c7\",\"hairsp\":\"\\u200a\",\"half\":\"\\xbd\",\"hamilt\":\"\\u210b\",\"HARDcy\":\"\\u042a\",\"hardcy\":\"\\u044a\",\"harrcir\":\"\\u2948\",\"harr\":\"\\u2194\",\"hArr\":\"\\u21d4\",\"harrw\":\"\\u21ad\",\"Hat\":\"^\",\"hbar\":\"\\u210f\",\"Hcirc\":\"\\u0124\",\"hcirc\":\"\\u0125\",\"hearts\":\"\\u2665\",\"heartsuit\":\"\\u2665\",\"hellip\":\"\\u2026\",\"hercon\":\"\\u22b9\",\"hfr\":\"\\ud835\\udd25\",\"Hfr\":\"\\u210c\",\"HilbertSpace\":\"\\u210b\",\"hksearow\":\"\\u2925\",\"hkswarow\":\"\\u2926\",\"hoarr\":\"\\u21ff\",\"homtht\":\"\\u223b\",\"hookleftarrow\":\"\\u21a9\",\"hookrightarrow\":\"\\u21aa\",\"hopf\":\"\\ud835\\udd59\",\"Hopf\":\"\\u210d\",\"horbar\":\"\\u2015\",\"HorizontalLine\":\"\\u2500\",\"hscr\":\"\\ud835\\udcbd\",\"Hscr\":\"\\u210b\",\"hslash\":\"\\u210f\",\"Hstrok\":\"\\u0126\",\"hstrok\":\"\\u0127\",\"HumpDownHump\":\"\\u224e\",\"HumpEqual\":\"\\u224f\",\"hybull\":\"\\u2043\",\"hyphen\":\"\\u2010\",\"Iacute\":\"\\xcd\",\"iacute\":\"\\xed\",\"ic\":\"\\u2063\",\"Icirc\":\"\\xce\",\"icirc\":\"\\xee\",\"Icy\":\"\\u0418\",\"icy\":\"\\u0438\",\"Idot\":\"\\u0130\",\"IEcy\":\"\\u0415\",\"iecy\":\"\\u0435\",\"iexcl\":\"\\xa1\",\"iff\":\"\\u21d4\",\"ifr\":\"\\ud835\\udd26\",\"Ifr\":\"\\u2111\",\"Igrave\":\"\\xcc\",\"igrave\":\"\\xec\",\"ii\":\"\\u2148\",\"iiiint\":\"\\u2a0c\",\"iiint\":\"\\u222d\",\"iinfin\":\"\\u29dc\",\"iiota\":\"\\u2129\",\"IJlig\":\"\\u0132\",\"ijlig\":\"\\u0133\",\"Imacr\":\"\\u012a\",\"imacr\":\"\\u012b\",\"image\":\"\\u2111\",\"ImaginaryI\":\"\\u2148\",\"imagline\":\"\\u2110\",\"imagpart\":\"\\u2111\",\"imath\":\"\\u0131\",\"Im\":\"\\u2111\",\"imof\":\"\\u22b7\",\"imped\":\"\\u01b5\",\"Implies\":\"\\u21d2\",\"incare\":\"\\u2105\",\"in\":\"\\u2208\",\"infin\":\"\\u221e\",\"infintie\":\"\\u29dd\",\"inodot\":\"\\u0131\",\"intcal\":\"\\u22ba\",\"int\":\"\\u222b\",\"Int\":\"\\u222c\",\"integers\":\"\\u2124\",\"Integral\":\"\\u222b\",\"intercal\":\"\\u22ba\",\"Intersection\":\"\\u22c2\",\"intlarhk\":\"\\u2a17\",\"intprod\":\"\\u2a3c\",\"InvisibleComma\":\"\\u2063\",\"InvisibleTimes\":\"\\u2062\",\"IOcy\":\"\\u0401\",\"iocy\":\"\\u0451\",\"Iogon\":\"\\u012e\",\"iogon\":\"\\u012f\",\"Iopf\":\"\\ud835\\udd40\",\"iopf\":\"\\ud835\\udd5a\",\"Iota\":\"\\u0399\",\"iota\":\"\\u03b9\",\"iprod\":\"\\u2a3c\",\"iquest\":\"\\xbf\",\"iscr\":\"\\ud835\\udcbe\",\"Iscr\":\"\\u2110\",\"isin\":\"\\u2208\",\"isindot\":\"\\u22f5\",\"isinE\":\"\\u22f9\",\"isins\":\"\\u22f4\",\"isinsv\":\"\\u22f3\",\"isinv\":\"\\u2208\",\"it\":\"\\u2062\",\"Itilde\":\"\\u0128\",\"itilde\":\"\\u0129\",\"Iukcy\":\"\\u0406\",\"iukcy\":\"\\u0456\",\"Iuml\":\"\\xcf\",\"iuml\":\"\\xef\",\"Jcirc\":\"\\u0134\",\"jcirc\":\"\\u0135\",\"Jcy\":\"\\u0419\",\"jcy\":\"\\u0439\",\"Jfr\":\"\\ud835\\udd0d\",\"jfr\":\"\\ud835\\udd27\",\"jmath\":\"\\u0237\",\"Jopf\":\"\\ud835\\udd41\",\"jopf\":\"\\ud835\\udd5b\",\"Jscr\":\"\\ud835\\udca5\",\"jscr\":\"\\ud835\\udcbf\",\"Jsercy\":\"\\u0408\",\"jsercy\":\"\\u0458\",\"Jukcy\":\"\\u0404\",\"jukcy\":\"\\u0454\",\"Kappa\":\"\\u039a\",\"kappa\":\"\\u03ba\",\"kappav\":\"\\u03f0\",\"Kcedil\":\"\\u0136\",\"kcedil\":\"\\u0137\",\"Kcy\":\"\\u041a\",\"kcy\":\"\\u043a\",\"Kfr\":\"\\ud835\\udd0e\",\"kfr\":\"\\ud835\\udd28\",\"kgreen\":\"\\u0138\",\"KHcy\":\"\\u0425\",\"khcy\":\"\\u0445\",\"KJcy\":\"\\u040c\",\"kjcy\":\"\\u045c\",\"Kopf\":\"\\ud835\\udd42\",\"kopf\":\"\\ud835\\udd5c\",\"Kscr\":\"\\ud835\\udca6\",\"kscr\":\"\\ud835\\udcc0\",\"lAarr\":\"\\u21da\",\"Lacute\":\"\\u0139\",\"lacute\":\"\\u013a\",\"laemptyv\":\"\\u29b4\",\"lagran\":\"\\u2112\",\"Lambda\":\"\\u039b\",\"lambda\":\"\\u03bb\",\"lang\":\"\\u27e8\",\"Lang\":\"\\u27ea\",\"langd\":\"\\u2991\",\"langle\":\"\\u27e8\",\"lap\":\"\\u2a85\",\"Laplacetrf\":\"\\u2112\",\"laquo\":\"\\xab\",\"larrb\":\"\\u21e4\",\"larrbfs\":\"\\u291f\",\"larr\":\"\\u2190\",\"Larr\":\"\\u219e\",\"lArr\":\"\\u21d0\",\"larrfs\":\"\\u291d\",\"larrhk\":\"\\u21a9\",\"larrlp\":\"\\u21ab\",\"larrpl\":\"\\u2939\",\"larrsim\":\"\\u2973\",\"larrtl\":\"\\u21a2\",\"latail\":\"\\u2919\",\"lAtail\":\"\\u291b\",\"lat\":\"\\u2aab\",\"late\":\"\\u2aad\",\"lates\":\"\\u2aad\\ufe00\",\"lbarr\":\"\\u290c\",\"lBarr\":\"\\u290e\",\"lbbrk\":\"\\u2772\",\"lbrace\":\"{\",\"lbrack\":\"[\",\"lbrke\":\"\\u298b\",\"lbrksld\":\"\\u298f\",\"lbrkslu\":\"\\u298d\",\"Lcaron\":\"\\u013d\",\"lcaron\":\"\\u013e\",\"Lcedil\":\"\\u013b\",\"lcedil\":\"\\u013c\",\"lceil\":\"\\u2308\",\"lcub\":\"{\",\"Lcy\":\"\\u041b\",\"lcy\":\"\\u043b\",\"ldca\":\"\\u2936\",\"ldquo\":\"\\u201c\",\"ldquor\":\"\\u201e\",\"ldrdhar\":\"\\u2967\",\"ldrushar\":\"\\u294b\",\"ldsh\":\"\\u21b2\",\"le\":\"\\u2264\",\"lE\":\"\\u2266\",\"LeftAngleBracket\":\"\\u27e8\",\"LeftArrowBar\":\"\\u21e4\",\"leftarrow\":\"\\u2190\",\"LeftArrow\":\"\\u2190\",\"Leftarrow\":\"\\u21d0\",\"LeftArrowRightArrow\":\"\\u21c6\",\"leftarrowtail\":\"\\u21a2\",\"LeftCeiling\":\"\\u2308\",\"LeftDoubleBracket\":\"\\u27e6\",\"LeftDownTeeVector\":\"\\u2961\",\"LeftDownVectorBar\":\"\\u2959\",\"LeftDownVector\":\"\\u21c3\",\"LeftFloor\":\"\\u230a\",\"leftharpoondown\":\"\\u21bd\",\"leftharpoonup\":\"\\u21bc\",\"leftleftarrows\":\"\\u21c7\",\"leftrightarrow\":\"\\u2194\",\"LeftRightArrow\":\"\\u2194\",\"Leftrightarrow\":\"\\u21d4\",\"leftrightarrows\":\"\\u21c6\",\"leftrightharpoons\":\"\\u21cb\",\"leftrightsquigarrow\":\"\\u21ad\",\"LeftRightVector\":\"\\u294e\",\"LeftTeeArrow\":\"\\u21a4\",\"LeftTee\":\"\\u22a3\",\"LeftTeeVector\":\"\\u295a\",\"leftthreetimes\":\"\\u22cb\",\"LeftTriangleBar\":\"\\u29cf\",\"LeftTriangle\":\"\\u22b2\",\"LeftTriangleEqual\":\"\\u22b4\",\"LeftUpDownVector\":\"\\u2951\",\"LeftUpTeeVector\":\"\\u2960\",\"LeftUpVectorBar\":\"\\u2958\",\"LeftUpVector\":\"\\u21bf\",\"LeftVectorBar\":\"\\u2952\",\"LeftVector\":\"\\u21bc\",\"lEg\":\"\\u2a8b\",\"leg\":\"\\u22da\",\"leq\":\"\\u2264\",\"leqq\":\"\\u2266\",\"leqslant\":\"\\u2a7d\",\"lescc\":\"\\u2aa8\",\"les\":\"\\u2a7d\",\"lesdot\":\"\\u2a7f\",\"lesdoto\":\"\\u2a81\",\"lesdotor\":\"\\u2a83\",\"lesg\":\"\\u22da\\ufe00\",\"lesges\":\"\\u2a93\",\"lessapprox\":\"\\u2a85\",\"lessdot\":\"\\u22d6\",\"lesseqgtr\":\"\\u22da\",\"lesseqqgtr\":\"\\u2a8b\",\"LessEqualGreater\":\"\\u22da\",\"LessFullEqual\":\"\\u2266\",\"LessGreater\":\"\\u2276\",\"lessgtr\":\"\\u2276\",\"LessLess\":\"\\u2aa1\",\"lesssim\":\"\\u2272\",\"LessSlantEqual\":\"\\u2a7d\",\"LessTilde\":\"\\u2272\",\"lfisht\":\"\\u297c\",\"lfloor\":\"\\u230a\",\"Lfr\":\"\\ud835\\udd0f\",\"lfr\":\"\\ud835\\udd29\",\"lg\":\"\\u2276\",\"lgE\":\"\\u2a91\",\"lHar\":\"\\u2962\",\"lhard\":\"\\u21bd\",\"lharu\":\"\\u21bc\",\"lharul\":\"\\u296a\",\"lhblk\":\"\\u2584\",\"LJcy\":\"\\u0409\",\"ljcy\":\"\\u0459\",\"llarr\":\"\\u21c7\",\"ll\":\"\\u226a\",\"Ll\":\"\\u22d8\",\"llcorner\":\"\\u231e\",\"Lleftarrow\":\"\\u21da\",\"llhard\":\"\\u296b\",\"lltri\":\"\\u25fa\",\"Lmidot\":\"\\u013f\",\"lmidot\":\"\\u0140\",\"lmoustache\":\"\\u23b0\",\"lmoust\":\"\\u23b0\",\"lnap\":\"\\u2a89\",\"lnapprox\":\"\\u2a89\",\"lne\":\"\\u2a87\",\"lnE\":\"\\u2268\",\"lneq\":\"\\u2a87\",\"lneqq\":\"\\u2268\",\"lnsim\":\"\\u22e6\",\"loang\":\"\\u27ec\",\"loarr\":\"\\u21fd\",\"lobrk\":\"\\u27e6\",\"longleftarrow\":\"\\u27f5\",\"LongLeftArrow\":\"\\u27f5\",\"Longleftarrow\":\"\\u27f8\",\"longleftrightarrow\":\"\\u27f7\",\"LongLeftRightArrow\":\"\\u27f7\",\"Longleftrightarrow\":\"\\u27fa\",\"longmapsto\":\"\\u27fc\",\"longrightarrow\":\"\\u27f6\",\"LongRightArrow\":\"\\u27f6\",\"Longrightarrow\":\"\\u27f9\",\"looparrowleft\":\"\\u21ab\",\"looparrowright\":\"\\u21ac\",\"lopar\":\"\\u2985\",\"Lopf\":\"\\ud835\\udd43\",\"lopf\":\"\\ud835\\udd5d\",\"loplus\":\"\\u2a2d\",\"lotimes\":\"\\u2a34\",\"lowast\":\"\\u2217\",\"lowbar\":\"_\",\"LowerLeftArrow\":\"\\u2199\",\"LowerRightArrow\":\"\\u2198\",\"loz\":\"\\u25ca\",\"lozenge\":\"\\u25ca\",\"lozf\":\"\\u29eb\",\"lpar\":\"(\",\"lparlt\":\"\\u2993\",\"lrarr\":\"\\u21c6\",\"lrcorner\":\"\\u231f\",\"lrhar\":\"\\u21cb\",\"lrhard\":\"\\u296d\",\"lrm\":\"\\u200e\",\"lrtri\":\"\\u22bf\",\"lsaquo\":\"\\u2039\",\"lscr\":\"\\ud835\\udcc1\",\"Lscr\":\"\\u2112\",\"lsh\":\"\\u21b0\",\"Lsh\":\"\\u21b0\",\"lsim\":\"\\u2272\",\"lsime\":\"\\u2a8d\",\"lsimg\":\"\\u2a8f\",\"lsqb\":\"[\",\"lsquo\":\"\\u2018\",\"lsquor\":\"\\u201a\",\"Lstrok\":\"\\u0141\",\"lstrok\":\"\\u0142\",\"ltcc\":\"\\u2aa6\",\"ltcir\":\"\\u2a79\",\"lt\":\"<\",\"LT\":\"<\",\"Lt\":\"\\u226a\",\"ltdot\":\"\\u22d6\",\"lthree\":\"\\u22cb\",\"ltimes\":\"\\u22c9\",\"ltlarr\":\"\\u2976\",\"ltquest\":\"\\u2a7b\",\"ltri\":\"\\u25c3\",\"ltrie\":\"\\u22b4\",\"ltrif\":\"\\u25c2\",\"ltrPar\":\"\\u2996\",\"lurdshar\":\"\\u294a\",\"luruhar\":\"\\u2966\",\"lvertneqq\":\"\\u2268\\ufe00\",\"lvnE\":\"\\u2268\\ufe00\",\"macr\":\"\\xaf\",\"male\":\"\\u2642\",\"malt\":\"\\u2720\",\"maltese\":\"\\u2720\",\"Map\":\"\\u2905\",\"map\":\"\\u21a6\",\"mapsto\":\"\\u21a6\",\"mapstodown\":\"\\u21a7\",\"mapstoleft\":\"\\u21a4\",\"mapstoup\":\"\\u21a5\",\"marker\":\"\\u25ae\",\"mcomma\":\"\\u2a29\",\"Mcy\":\"\\u041c\",\"mcy\":\"\\u043c\",\"mdash\":\"\\u2014\",\"mDDot\":\"\\u223a\",\"measuredangle\":\"\\u2221\",\"MediumSpace\":\"\\u205f\",\"Mellintrf\":\"\\u2133\",\"Mfr\":\"\\ud835\\udd10\",\"mfr\":\"\\ud835\\udd2a\",\"mho\":\"\\u2127\",\"micro\":\"\\xb5\",\"midast\":\"*\",\"midcir\":\"\\u2af0\",\"mid\":\"\\u2223\",\"middot\":\"\\xb7\",\"minusb\":\"\\u229f\",\"minus\":\"\\u2212\",\"minusd\":\"\\u2238\",\"minusdu\":\"\\u2a2a\",\"MinusPlus\":\"\\u2213\",\"mlcp\":\"\\u2adb\",\"mldr\":\"\\u2026\",\"mnplus\":\"\\u2213\",\"models\":\"\\u22a7\",\"Mopf\":\"\\ud835\\udd44\",\"mopf\":\"\\ud835\\udd5e\",\"mp\":\"\\u2213\",\"mscr\":\"\\ud835\\udcc2\",\"Mscr\":\"\\u2133\",\"mstpos\":\"\\u223e\",\"Mu\":\"\\u039c\",\"mu\":\"\\u03bc\",\"multimap\":\"\\u22b8\",\"mumap\":\"\\u22b8\",\"nabla\":\"\\u2207\",\"Nacute\":\"\\u0143\",\"nacute\":\"\\u0144\",\"nang\":\"\\u2220\\u20d2\",\"nap\":\"\\u2249\",\"napE\":\"\\u2a70\\u0338\",\"napid\":\"\\u224b\\u0338\",\"napos\":\"\\u0149\",\"napprox\":\"\\u2249\",\"natural\":\"\\u266e\",\"naturals\":\"\\u2115\",\"natur\":\"\\u266e\",\"nbsp\":\"\\xa0\",\"nbump\":\"\\u224e\\u0338\",\"nbumpe\":\"\\u224f\\u0338\",\"ncap\":\"\\u2a43\",\"Ncaron\":\"\\u0147\",\"ncaron\":\"\\u0148\",\"Ncedil\":\"\\u0145\",\"ncedil\":\"\\u0146\",\"ncong\":\"\\u2247\",\"ncongdot\":\"\\u2a6d\\u0338\",\"ncup\":\"\\u2a42\",\"Ncy\":\"\\u041d\",\"ncy\":\"\\u043d\",\"ndash\":\"\\u2013\",\"nearhk\":\"\\u2924\",\"nearr\":\"\\u2197\",\"neArr\":\"\\u21d7\",\"nearrow\":\"\\u2197\",\"ne\":\"\\u2260\",\"nedot\":\"\\u2250\\u0338\",\"NegativeMediumSpace\":\"\\u200b\",\"NegativeThickSpace\":\"\\u200b\",\"NegativeThinSpace\":\"\\u200b\",\"NegativeVeryThinSpace\":\"\\u200b\",\"nequiv\":\"\\u2262\",\"nesear\":\"\\u2928\",\"nesim\":\"\\u2242\\u0338\",\"NestedGreaterGreater\":\"\\u226b\",\"NestedLessLess\":\"\\u226a\",\"NewLine\":\"\\\\n\",\"nexist\":\"\\u2204\",\"nexists\":\"\\u2204\",\"Nfr\":\"\\ud835\\udd11\",\"nfr\":\"\\ud835\\udd2b\",\"ngE\":\"\\u2267\\u0338\",\"nge\":\"\\u2271\",\"ngeq\":\"\\u2271\",\"ngeqq\":\"\\u2267\\u0338\",\"ngeqslant\":\"\\u2a7e\\u0338\",\"nges\":\"\\u2a7e\\u0338\",\"nGg\":\"\\u22d9\\u0338\",\"ngsim\":\"\\u2275\",\"nGt\":\"\\u226b\\u20d2\",\"ngt\":\"\\u226f\",\"ngtr\":\"\\u226f\",\"nGtv\":\"\\u226b\\u0338\",\"nharr\":\"\\u21ae\",\"nhArr\":\"\\u21ce\",\"nhpar\":\"\\u2af2\",\"ni\":\"\\u220b\",\"nis\":\"\\u22fc\",\"nisd\":\"\\u22fa\",\"niv\":\"\\u220b\",\"NJcy\":\"\\u040a\",\"njcy\":\"\\u045a\",\"nlarr\":\"\\u219a\",\"nlArr\":\"\\u21cd\",\"nldr\":\"\\u2025\",\"nlE\":\"\\u2266\\u0338\",\"nle\":\"\\u2270\",\"nleftarrow\":\"\\u219a\",\"nLeftarrow\":\"\\u21cd\",\"nleftrightarrow\":\"\\u21ae\",\"nLeftrightarrow\":\"\\u21ce\",\"nleq\":\"\\u2270\",\"nleqq\":\"\\u2266\\u0338\",\"nleqslant\":\"\\u2a7d\\u0338\",\"nles\":\"\\u2a7d\\u0338\",\"nless\":\"\\u226e\",\"nLl\":\"\\u22d8\\u0338\",\"nlsim\":\"\\u2274\",\"nLt\":\"\\u226a\\u20d2\",\"nlt\":\"\\u226e\",\"nltri\":\"\\u22ea\",\"nltrie\":\"\\u22ec\",\"nLtv\":\"\\u226a\\u0338\",\"nmid\":\"\\u2224\",\"NoBreak\":\"\\u2060\",\"NonBreakingSpace\":\"\\xa0\",\"nopf\":\"\\ud835\\udd5f\",\"Nopf\":\"\\u2115\",\"Not\":\"\\u2aec\",\"not\":\"\\xac\",\"NotCongruent\":\"\\u2262\",\"NotCupCap\":\"\\u226d\",\"NotDoubleVerticalBar\":\"\\u2226\",\"NotElement\":\"\\u2209\",\"NotEqual\":\"\\u2260\",\"NotEqualTilde\":\"\\u2242\\u0338\",\"NotExists\":\"\\u2204\",\"NotGreater\":\"\\u226f\",\"NotGreaterEqual\":\"\\u2271\",\"NotGreaterFullEqual\":\"\\u2267\\u0338\",\"NotGreaterGreater\":\"\\u226b\\u0338\",\"NotGreaterLess\":\"\\u2279\",\"NotGreaterSlantEqual\":\"\\u2a7e\\u0338\",\"NotGreaterTilde\":\"\\u2275\",\"NotHumpDownHump\":\"\\u224e\\u0338\",\"NotHumpEqual\":\"\\u224f\\u0338\",\"notin\":\"\\u2209\",\"notindot\":\"\\u22f5\\u0338\",\"notinE\":\"\\u22f9\\u0338\",\"notinva\":\"\\u2209\",\"notinvb\":\"\\u22f7\",\"notinvc\":\"\\u22f6\",\"NotLeftTriangleBar\":\"\\u29cf\\u0338\",\"NotLeftTriangle\":\"\\u22ea\",\"NotLeftTriangleEqual\":\"\\u22ec\",\"NotLess\":\"\\u226e\",\"NotLessEqual\":\"\\u2270\",\"NotLessGreater\":\"\\u2278\",\"NotLessLess\":\"\\u226a\\u0338\",\"NotLessSlantEqual\":\"\\u2a7d\\u0338\",\"NotLessTilde\":\"\\u2274\",\"NotNestedGreaterGreater\":\"\\u2aa2\\u0338\",\"NotNestedLessLess\":\"\\u2aa1\\u0338\",\"notni\":\"\\u220c\",\"notniva\":\"\\u220c\",\"notnivb\":\"\\u22fe\",\"notnivc\":\"\\u22fd\",\"NotPrecedes\":\"\\u2280\",\"NotPrecedesEqual\":\"\\u2aaf\\u0338\",\"NotPrecedesSlantEqual\":\"\\u22e0\",\"NotReverseElement\":\"\\u220c\",\"NotRightTriangleBar\":\"\\u29d0\\u0338\",\"NotRightTriangle\":\"\\u22eb\",\"NotRightTriangleEqual\":\"\\u22ed\",\"NotSquareSubset\":\"\\u228f\\u0338\",\"NotSquareSubsetEqual\":\"\\u22e2\",\"NotSquareSuperset\":\"\\u2290\\u0338\",\"NotSquareSupersetEqual\":\"\\u22e3\",\"NotSubset\":\"\\u2282\\u20d2\",\"NotSubsetEqual\":\"\\u2288\",\"NotSucceeds\":\"\\u2281\",\"NotSucceedsEqual\":\"\\u2ab0\\u0338\",\"NotSucceedsSlantEqual\":\"\\u22e1\",\"NotSucceedsTilde\":\"\\u227f\\u0338\",\"NotSuperset\":\"\\u2283\\u20d2\",\"NotSupersetEqual\":\"\\u2289\",\"NotTilde\":\"\\u2241\",\"NotTildeEqual\":\"\\u2244\",\"NotTildeFullEqual\":\"\\u2247\",\"NotTildeTilde\":\"\\u2249\",\"NotVerticalBar\":\"\\u2224\",\"nparallel\":\"\\u2226\",\"npar\":\"\\u2226\",\"nparsl\":\"\\u2afd\\u20e5\",\"npart\":\"\\u2202\\u0338\",\"npolint\":\"\\u2a14\",\"npr\":\"\\u2280\",\"nprcue\":\"\\u22e0\",\"nprec\":\"\\u2280\",\"npreceq\":\"\\u2aaf\\u0338\",\"npre\":\"\\u2aaf\\u0338\",\"nrarrc\":\"\\u2933\\u0338\",\"nrarr\":\"\\u219b\",\"nrArr\":\"\\u21cf\",\"nrarrw\":\"\\u219d\\u0338\",\"nrightarrow\":\"\\u219b\",\"nRightarrow\":\"\\u21cf\",\"nrtri\":\"\\u22eb\",\"nrtrie\":\"\\u22ed\",\"nsc\":\"\\u2281\",\"nsccue\":\"\\u22e1\",\"nsce\":\"\\u2ab0\\u0338\",\"Nscr\":\"\\ud835\\udca9\",\"nscr\":\"\\ud835\\udcc3\",\"nshortmid\":\"\\u2224\",\"nshortparallel\":\"\\u2226\",\"nsim\":\"\\u2241\",\"nsime\":\"\\u2244\",\"nsimeq\":\"\\u2244\",\"nsmid\":\"\\u2224\",\"nspar\":\"\\u2226\",\"nsqsube\":\"\\u22e2\",\"nsqsupe\":\"\\u22e3\",\"nsub\":\"\\u2284\",\"nsubE\":\"\\u2ac5\\u0338\",\"nsube\":\"\\u2288\",\"nsubset\":\"\\u2282\\u20d2\",\"nsubseteq\":\"\\u2288\",\"nsubseteqq\":\"\\u2ac5\\u0338\",\"nsucc\":\"\\u2281\",\"nsucceq\":\"\\u2ab0\\u0338\",\"nsup\":\"\\u2285\",\"nsupE\":\"\\u2ac6\\u0338\",\"nsupe\":\"\\u2289\",\"nsupset\":\"\\u2283\\u20d2\",\"nsupseteq\":\"\\u2289\",\"nsupseteqq\":\"\\u2ac6\\u0338\",\"ntgl\":\"\\u2279\",\"Ntilde\":\"\\xd1\",\"ntilde\":\"\\xf1\",\"ntlg\":\"\\u2278\",\"ntriangleleft\":\"\\u22ea\",\"ntrianglelefteq\":\"\\u22ec\",\"ntriangleright\":\"\\u22eb\",\"ntrianglerighteq\":\"\\u22ed\",\"Nu\":\"\\u039d\",\"nu\":\"\\u03bd\",\"num\":\"#\",\"numero\":\"\\u2116\",\"numsp\":\"\\u2007\",\"nvap\":\"\\u224d\\u20d2\",\"nvdash\":\"\\u22ac\",\"nvDash\":\"\\u22ad\",\"nVdash\":\"\\u22ae\",\"nVDash\":\"\\u22af\",\"nvge\":\"\\u2265\\u20d2\",\"nvgt\":\">\\u20d2\",\"nvHarr\":\"\\u2904\",\"nvinfin\":\"\\u29de\",\"nvlArr\":\"\\u2902\",\"nvle\":\"\\u2264\\u20d2\",\"nvlt\":\"<\\u20d2\",\"nvltrie\":\"\\u22b4\\u20d2\",\"nvrArr\":\"\\u2903\",\"nvrtrie\":\"\\u22b5\\u20d2\",\"nvsim\":\"\\u223c\\u20d2\",\"nwarhk\":\"\\u2923\",\"nwarr\":\"\\u2196\",\"nwArr\":\"\\u21d6\",\"nwarrow\":\"\\u2196\",\"nwnear\":\"\\u2927\",\"Oacute\":\"\\xd3\",\"oacute\":\"\\xf3\",\"oast\":\"\\u229b\",\"Ocirc\":\"\\xd4\",\"ocirc\":\"\\xf4\",\"ocir\":\"\\u229a\",\"Ocy\":\"\\u041e\",\"ocy\":\"\\u043e\",\"odash\":\"\\u229d\",\"Odblac\":\"\\u0150\",\"odblac\":\"\\u0151\",\"odiv\":\"\\u2a38\",\"odot\":\"\\u2299\",\"odsold\":\"\\u29bc\",\"OElig\":\"\\u0152\",\"oelig\":\"\\u0153\",\"ofcir\":\"\\u29bf\",\"Ofr\":\"\\ud835\\udd12\",\"ofr\":\"\\ud835\\udd2c\",\"ogon\":\"\\u02db\",\"Ograve\":\"\\xd2\",\"ograve\":\"\\xf2\",\"ogt\":\"\\u29c1\",\"ohbar\":\"\\u29b5\",\"ohm\":\"\\u03a9\",\"oint\":\"\\u222e\",\"olarr\":\"\\u21ba\",\"olcir\":\"\\u29be\",\"olcross\":\"\\u29bb\",\"oline\":\"\\u203e\",\"olt\":\"\\u29c0\",\"Omacr\":\"\\u014c\",\"omacr\":\"\\u014d\",\"Omega\":\"\\u03a9\",\"omega\":\"\\u03c9\",\"Omicron\":\"\\u039f\",\"omicron\":\"\\u03bf\",\"omid\":\"\\u29b6\",\"ominus\":\"\\u2296\",\"Oopf\":\"\\ud835\\udd46\",\"oopf\":\"\\ud835\\udd60\",\"opar\":\"\\u29b7\",\"OpenCurlyDoubleQuote\":\"\\u201c\",\"OpenCurlyQuote\":\"\\u2018\",\"operp\":\"\\u29b9\",\"oplus\":\"\\u2295\",\"orarr\":\"\\u21bb\",\"Or\":\"\\u2a54\",\"or\":\"\\u2228\",\"ord\":\"\\u2a5d\",\"order\":\"\\u2134\",\"orderof\":\"\\u2134\",\"ordf\":\"\\xaa\",\"ordm\":\"\\xba\",\"origof\":\"\\u22b6\",\"oror\":\"\\u2a56\",\"orslope\":\"\\u2a57\",\"orv\":\"\\u2a5b\",\"oS\":\"\\u24c8\",\"Oscr\":\"\\ud835\\udcaa\",\"oscr\":\"\\u2134\",\"Oslash\":\"\\xd8\",\"oslash\":\"\\xf8\",\"osol\":\"\\u2298\",\"Otilde\":\"\\xd5\",\"otilde\":\"\\xf5\",\"otimesas\":\"\\u2a36\",\"Otimes\":\"\\u2a37\",\"otimes\":\"\\u2297\",\"Ouml\":\"\\xd6\",\"ouml\":\"\\xf6\",\"ovbar\":\"\\u233d\",\"OverBar\":\"\\u203e\",\"OverBrace\":\"\\u23de\",\"OverBracket\":\"\\u23b4\",\"OverParenthesis\":\"\\u23dc\",\"para\":\"\\xb6\",\"parallel\":\"\\u2225\",\"par\":\"\\u2225\",\"parsim\":\"\\u2af3\",\"parsl\":\"\\u2afd\",\"part\":\"\\u2202\",\"PartialD\":\"\\u2202\",\"Pcy\":\"\\u041f\",\"pcy\":\"\\u043f\",\"percnt\":\"%\",\"period\":\".\",\"permil\":\"\\u2030\",\"perp\":\"\\u22a5\",\"pertenk\":\"\\u2031\",\"Pfr\":\"\\ud835\\udd13\",\"pfr\":\"\\ud835\\udd2d\",\"Phi\":\"\\u03a6\",\"phi\":\"\\u03c6\",\"phiv\":\"\\u03d5\",\"phmmat\":\"\\u2133\",\"phone\":\"\\u260e\",\"Pi\":\"\\u03a0\",\"pi\":\"\\u03c0\",\"pitchfork\":\"\\u22d4\",\"piv\":\"\\u03d6\",\"planck\":\"\\u210f\",\"planckh\":\"\\u210e\",\"plankv\":\"\\u210f\",\"plusacir\":\"\\u2a23\",\"plusb\":\"\\u229e\",\"pluscir\":\"\\u2a22\",\"plus\":\"+\",\"plusdo\":\"\\u2214\",\"plusdu\":\"\\u2a25\",\"pluse\":\"\\u2a72\",\"PlusMinus\":\"\\xb1\",\"plusmn\":\"\\xb1\",\"plussim\":\"\\u2a26\",\"plustwo\":\"\\u2a27\",\"pm\":\"\\xb1\",\"Poincareplane\":\"\\u210c\",\"pointint\":\"\\u2a15\",\"popf\":\"\\ud835\\udd61\",\"Popf\":\"\\u2119\",\"pound\":\"\\xa3\",\"prap\":\"\\u2ab7\",\"Pr\":\"\\u2abb\",\"pr\":\"\\u227a\",\"prcue\":\"\\u227c\",\"precapprox\":\"\\u2ab7\",\"prec\":\"\\u227a\",\"preccurlyeq\":\"\\u227c\",\"Precedes\":\"\\u227a\",\"PrecedesEqual\":\"\\u2aaf\",\"PrecedesSlantEqual\":\"\\u227c\",\"PrecedesTilde\":\"\\u227e\",\"preceq\":\"\\u2aaf\",\"precnapprox\":\"\\u2ab9\",\"precneqq\":\"\\u2ab5\",\"precnsim\":\"\\u22e8\",\"pre\":\"\\u2aaf\",\"prE\":\"\\u2ab3\",\"precsim\":\"\\u227e\",\"prime\":\"\\u2032\",\"Prime\":\"\\u2033\",\"primes\":\"\\u2119\",\"prnap\":\"\\u2ab9\",\"prnE\":\"\\u2ab5\",\"prnsim\":\"\\u22e8\",\"prod\":\"\\u220f\",\"Product\":\"\\u220f\",\"profalar\":\"\\u232e\",\"profline\":\"\\u2312\",\"profsurf\":\"\\u2313\",\"prop\":\"\\u221d\",\"Proportional\":\"\\u221d\",\"Proportion\":\"\\u2237\",\"propto\":\"\\u221d\",\"prsim\":\"\\u227e\",\"prurel\":\"\\u22b0\",\"Pscr\":\"\\ud835\\udcab\",\"pscr\":\"\\ud835\\udcc5\",\"Psi\":\"\\u03a8\",\"psi\":\"\\u03c8\",\"puncsp\":\"\\u2008\",\"Qfr\":\"\\ud835\\udd14\",\"qfr\":\"\\ud835\\udd2e\",\"qint\":\"\\u2a0c\",\"qopf\":\"\\ud835\\udd62\",\"Qopf\":\"\\u211a\",\"qprime\":\"\\u2057\",\"Qscr\":\"\\ud835\\udcac\",\"qscr\":\"\\ud835\\udcc6\",\"quaternions\":\"\\u210d\",\"quatint\":\"\\u2a16\",\"quest\":\"?\",\"questeq\":\"\\u225f\",\"quot\":\"\\\\\"\",\"QUOT\":\"\\\\\"\",\"rAarr\":\"\\u21db\",\"race\":\"\\u223d\\u0331\",\"Racute\":\"\\u0154\",\"racute\":\"\\u0155\",\"radic\":\"\\u221a\",\"raemptyv\":\"\\u29b3\",\"rang\":\"\\u27e9\",\"Rang\":\"\\u27eb\",\"rangd\":\"\\u2992\",\"range\":\"\\u29a5\",\"rangle\":\"\\u27e9\",\"raquo\":\"\\xbb\",\"rarrap\":\"\\u2975\",\"rarrb\":\"\\u21e5\",\"rarrbfs\":\"\\u2920\",\"rarrc\":\"\\u2933\",\"rarr\":\"\\u2192\",\"Rarr\":\"\\u21a0\",\"rArr\":\"\\u21d2\",\"rarrfs\":\"\\u291e\",\"rarrhk\":\"\\u21aa\",\"rarrlp\":\"\\u21ac\",\"rarrpl\":\"\\u2945\",\"rarrsim\":\"\\u2974\",\"Rarrtl\":\"\\u2916\",\"rarrtl\":\"\\u21a3\",\"rarrw\":\"\\u219d\",\"ratail\":\"\\u291a\",\"rAtail\":\"\\u291c\",\"ratio\":\"\\u2236\",\"rationals\":\"\\u211a\",\"rbarr\":\"\\u290d\",\"rBarr\":\"\\u290f\",\"RBarr\":\"\\u2910\",\"rbbrk\":\"\\u2773\",\"rbrace\":\"}\",\"rbrack\":\"]\",\"rbrke\":\"\\u298c\",\"rbrksld\":\"\\u298e\",\"rbrkslu\":\"\\u2990\",\"Rcaron\":\"\\u0158\",\"rcaron\":\"\\u0159\",\"Rcedil\":\"\\u0156\",\"rcedil\":\"\\u0157\",\"rceil\":\"\\u2309\",\"rcub\":\"}\",\"Rcy\":\"\\u0420\",\"rcy\":\"\\u0440\",\"rdca\":\"\\u2937\",\"rdldhar\":\"\\u2969\",\"rdquo\":\"\\u201d\",\"rdquor\":\"\\u201d\",\"rdsh\":\"\\u21b3\",\"real\":\"\\u211c\",\"realine\":\"\\u211b\",\"realpart\":\"\\u211c\",\"reals\":\"\\u211d\",\"Re\":\"\\u211c\",\"rect\":\"\\u25ad\",\"reg\":\"\\xae\",\"REG\":\"\\xae\",\"ReverseElement\":\"\\u220b\",\"ReverseEquilibrium\":\"\\u21cb\",\"ReverseUpEquilibrium\":\"\\u296f\",\"rfisht\":\"\\u297d\",\"rfloor\":\"\\u230b\",\"rfr\":\"\\ud835\\udd2f\",\"Rfr\":\"\\u211c\",\"rHar\":\"\\u2964\",\"rhard\":\"\\u21c1\",\"rharu\":\"\\u21c0\",\"rharul\":\"\\u296c\",\"Rho\":\"\\u03a1\",\"rho\":\"\\u03c1\",\"rhov\":\"\\u03f1\",\"RightAngleBracket\":\"\\u27e9\",\"RightArrowBar\":\"\\u21e5\",\"rightarrow\":\"\\u2192\",\"RightArrow\":\"\\u2192\",\"Rightarrow\":\"\\u21d2\",\"RightArrowLeftArrow\":\"\\u21c4\",\"rightarrowtail\":\"\\u21a3\",\"RightCeiling\":\"\\u2309\",\"RightDoubleBracket\":\"\\u27e7\",\"RightDownTeeVector\":\"\\u295d\",\"RightDownVectorBar\":\"\\u2955\",\"RightDownVector\":\"\\u21c2\",\"RightFloor\":\"\\u230b\",\"rightharpoondown\":\"\\u21c1\",\"rightharpoonup\":\"\\u21c0\",\"rightleftarrows\":\"\\u21c4\",\"rightleftharpoons\":\"\\u21cc\",\"rightrightarrows\":\"\\u21c9\",\"rightsquigarrow\":\"\\u219d\",\"RightTeeArrow\":\"\\u21a6\",\"RightTee\":\"\\u22a2\",\"RightTeeVector\":\"\\u295b\",\"rightthreetimes\":\"\\u22cc\",\"RightTriangleBar\":\"\\u29d0\",\"RightTriangle\":\"\\u22b3\",\"RightTriangleEqual\":\"\\u22b5\",\"RightUpDownVector\":\"\\u294f\",\"RightUpTeeVector\":\"\\u295c\",\"RightUpVectorBar\":\"\\u2954\",\"RightUpVector\":\"\\u21be\",\"RightVectorBar\":\"\\u2953\",\"RightVector\":\"\\u21c0\",\"ring\":\"\\u02da\",\"risingdotseq\":\"\\u2253\",\"rlarr\":\"\\u21c4\",\"rlhar\":\"\\u21cc\",\"rlm\":\"\\u200f\",\"rmoustache\":\"\\u23b1\",\"rmoust\":\"\\u23b1\",\"rnmid\":\"\\u2aee\",\"roang\":\"\\u27ed\",\"roarr\":\"\\u21fe\",\"robrk\":\"\\u27e7\",\"ropar\":\"\\u2986\",\"ropf\":\"\\ud835\\udd63\",\"Ropf\":\"\\u211d\",\"roplus\":\"\\u2a2e\",\"rotimes\":\"\\u2a35\",\"RoundImplies\":\"\\u2970\",\"rpar\":\")\",\"rpargt\":\"\\u2994\",\"rppolint\":\"\\u2a12\",\"rrarr\":\"\\u21c9\",\"Rrightarrow\":\"\\u21db\",\"rsaquo\":\"\\u203a\",\"rscr\":\"\\ud835\\udcc7\",\"Rscr\":\"\\u211b\",\"rsh\":\"\\u21b1\",\"Rsh\":\"\\u21b1\",\"rsqb\":\"]\",\"rsquo\":\"\\u2019\",\"rsquor\":\"\\u2019\",\"rthree\":\"\\u22cc\",\"rtimes\":\"\\u22ca\",\"rtri\":\"\\u25b9\",\"rtrie\":\"\\u22b5\",\"rtrif\":\"\\u25b8\",\"rtriltri\":\"\\u29ce\",\"RuleDelayed\":\"\\u29f4\",\"ruluhar\":\"\\u2968\",\"rx\":\"\\u211e\",\"Sacute\":\"\\u015a\",\"sacute\":\"\\u015b\",\"sbquo\":\"\\u201a\",\"scap\":\"\\u2ab8\",\"Scaron\":\"\\u0160\",\"scaron\":\"\\u0161\",\"Sc\":\"\\u2abc\",\"sc\":\"\\u227b\",\"sccue\":\"\\u227d\",\"sce\":\"\\u2ab0\",\"scE\":\"\\u2ab4\",\"Scedil\":\"\\u015e\",\"scedil\":\"\\u015f\",\"Scirc\":\"\\u015c\",\"scirc\":\"\\u015d\",\"scnap\":\"\\u2aba\",\"scnE\":\"\\u2ab6\",\"scnsim\":\"\\u22e9\",\"scpolint\":\"\\u2a13\",\"scsim\":\"\\u227f\",\"Scy\":\"\\u0421\",\"scy\":\"\\u0441\",\"sdotb\":\"\\u22a1\",\"sdot\":\"\\u22c5\",\"sdote\":\"\\u2a66\",\"searhk\":\"\\u2925\",\"searr\":\"\\u2198\",\"seArr\":\"\\u21d8\",\"searrow\":\"\\u2198\",\"sect\":\"\\xa7\",\"semi\":\";\",\"seswar\":\"\\u2929\",\"setminus\":\"\\u2216\",\"setmn\":\"\\u2216\",\"sext\":\"\\u2736\",\"Sfr\":\"\\ud835\\udd16\",\"sfr\":\"\\ud835\\udd30\",\"sfrown\":\"\\u2322\",\"sharp\":\"\\u266f\",\"SHCHcy\":\"\\u0429\",\"shchcy\":\"\\u0449\",\"SHcy\":\"\\u0428\",\"shcy\":\"\\u0448\",\"ShortDownArrow\":\"\\u2193\",\"ShortLeftArrow\":\"\\u2190\",\"shortmid\":\"\\u2223\",\"shortparallel\":\"\\u2225\",\"ShortRightArrow\":\"\\u2192\",\"ShortUpArrow\":\"\\u2191\",\"shy\":\"\\xad\",\"Sigma\":\"\\u03a3\",\"sigma\":\"\\u03c3\",\"sigmaf\":\"\\u03c2\",\"sigmav\":\"\\u03c2\",\"sim\":\"\\u223c\",\"simdot\":\"\\u2a6a\",\"sime\":\"\\u2243\",\"simeq\":\"\\u2243\",\"simg\":\"\\u2a9e\",\"simgE\":\"\\u2aa0\",\"siml\":\"\\u2a9d\",\"simlE\":\"\\u2a9f\",\"simne\":\"\\u2246\",\"simplus\":\"\\u2a24\",\"simrarr\":\"\\u2972\",\"slarr\":\"\\u2190\",\"SmallCircle\":\"\\u2218\",\"smallsetminus\":\"\\u2216\",\"smashp\":\"\\u2a33\",\"smeparsl\":\"\\u29e4\",\"smid\":\"\\u2223\",\"smile\":\"\\u2323\",\"smt\":\"\\u2aaa\",\"smte\":\"\\u2aac\",\"smtes\":\"\\u2aac\\ufe00\",\"SOFTcy\":\"\\u042c\",\"softcy\":\"\\u044c\",\"solbar\":\"\\u233f\",\"solb\":\"\\u29c4\",\"sol\":\"/\",\"Sopf\":\"\\ud835\\udd4a\",\"sopf\":\"\\ud835\\udd64\",\"spades\":\"\\u2660\",\"spadesuit\":\"\\u2660\",\"spar\":\"\\u2225\",\"sqcap\":\"\\u2293\",\"sqcaps\":\"\\u2293\\ufe00\",\"sqcup\":\"\\u2294\",\"sqcups\":\"\\u2294\\ufe00\",\"Sqrt\":\"\\u221a\",\"sqsub\":\"\\u228f\",\"sqsube\":\"\\u2291\",\"sqsubset\":\"\\u228f\",\"sqsubseteq\":\"\\u2291\",\"sqsup\":\"\\u2290\",\"sqsupe\":\"\\u2292\",\"sqsupset\":\"\\u2290\",\"sqsupseteq\":\"\\u2292\",\"square\":\"\\u25a1\",\"Square\":\"\\u25a1\",\"SquareIntersection\":\"\\u2293\",\"SquareSubset\":\"\\u228f\",\"SquareSubsetEqual\":\"\\u2291\",\"SquareSuperset\":\"\\u2290\",\"SquareSupersetEqual\":\"\\u2292\",\"SquareUnion\":\"\\u2294\",\"squarf\":\"\\u25aa\",\"squ\":\"\\u25a1\",\"squf\":\"\\u25aa\",\"srarr\":\"\\u2192\",\"Sscr\":\"\\ud835\\udcae\",\"sscr\":\"\\ud835\\udcc8\",\"ssetmn\":\"\\u2216\",\"ssmile\":\"\\u2323\",\"sstarf\":\"\\u22c6\",\"Star\":\"\\u22c6\",\"star\":\"\\u2606\",\"starf\":\"\\u2605\",\"straightepsilon\":\"\\u03f5\",\"straightphi\":\"\\u03d5\",\"strns\":\"\\xaf\",\"sub\":\"\\u2282\",\"Sub\":\"\\u22d0\",\"subdot\":\"\\u2abd\",\"subE\":\"\\u2ac5\",\"sube\":\"\\u2286\",\"subedot\":\"\\u2ac3\",\"submult\":\"\\u2ac1\",\"subnE\":\"\\u2acb\",\"subne\":\"\\u228a\",\"subplus\":\"\\u2abf\",\"subrarr\":\"\\u2979\",\"subset\":\"\\u2282\",\"Subset\":\"\\u22d0\",\"subseteq\":\"\\u2286\",\"subseteqq\":\"\\u2ac5\",\"SubsetEqual\":\"\\u2286\",\"subsetneq\":\"\\u228a\",\"subsetneqq\":\"\\u2acb\",\"subsim\":\"\\u2ac7\",\"subsub\":\"\\u2ad5\",\"subsup\":\"\\u2ad3\",\"succapprox\":\"\\u2ab8\",\"succ\":\"\\u227b\",\"succcurlyeq\":\"\\u227d\",\"Succeeds\":\"\\u227b\",\"SucceedsEqual\":\"\\u2ab0\",\"SucceedsSlantEqual\":\"\\u227d\",\"SucceedsTilde\":\"\\u227f\",\"succeq\":\"\\u2ab0\",\"succnapprox\":\"\\u2aba\",\"succneqq\":\"\\u2ab6\",\"succnsim\":\"\\u22e9\",\"succsim\":\"\\u227f\",\"SuchThat\":\"\\u220b\",\"sum\":\"\\u2211\",\"Sum\":\"\\u2211\",\"sung\":\"\\u266a\",\"sup1\":\"\\xb9\",\"sup2\":\"\\xb2\",\"sup3\":\"\\xb3\",\"sup\":\"\\u2283\",\"Sup\":\"\\u22d1\",\"supdot\":\"\\u2abe\",\"supdsub\":\"\\u2ad8\",\"supE\":\"\\u2ac6\",\"supe\":\"\\u2287\",\"supedot\":\"\\u2ac4\",\"Superset\":\"\\u2283\",\"SupersetEqual\":\"\\u2287\",\"suphsol\":\"\\u27c9\",\"suphsub\":\"\\u2ad7\",\"suplarr\":\"\\u297b\",\"supmult\":\"\\u2ac2\",\"supnE\":\"\\u2acc\",\"supne\":\"\\u228b\",\"supplus\":\"\\u2ac0\",\"supset\":\"\\u2283\",\"Supset\":\"\\u22d1\",\"supseteq\":\"\\u2287\",\"supseteqq\":\"\\u2ac6\",\"supsetneq\":\"\\u228b\",\"supsetneqq\":\"\\u2acc\",\"supsim\":\"\\u2ac8\",\"supsub\":\"\\u2ad4\",\"supsup\":\"\\u2ad6\",\"swarhk\":\"\\u2926\",\"swarr\":\"\\u2199\",\"swArr\":\"\\u21d9\",\"swarrow\":\"\\u2199\",\"swnwar\":\"\\u292a\",\"szlig\":\"\\xdf\",\"Tab\":\"\\\\t\",\"target\":\"\\u2316\",\"Tau\":\"\\u03a4\",\"tau\":\"\\u03c4\",\"tbrk\":\"\\u23b4\",\"Tcaron\":\"\\u0164\",\"tcaron\":\"\\u0165\",\"Tcedil\":\"\\u0162\",\"tcedil\":\"\\u0163\",\"Tcy\":\"\\u0422\",\"tcy\":\"\\u0442\",\"tdot\":\"\\u20db\",\"telrec\":\"\\u2315\",\"Tfr\":\"\\ud835\\udd17\",\"tfr\":\"\\ud835\\udd31\",\"there4\":\"\\u2234\",\"therefore\":\"\\u2234\",\"Therefore\":\"\\u2234\",\"Theta\":\"\\u0398\",\"theta\":\"\\u03b8\",\"thetasym\":\"\\u03d1\",\"thetav\":\"\\u03d1\",\"thickapprox\":\"\\u2248\",\"thicksim\":\"\\u223c\",\"ThickSpace\":\"\\u205f\\u200a\",\"ThinSpace\":\"\\u2009\",\"thinsp\":\"\\u2009\",\"thkap\":\"\\u2248\",\"thksim\":\"\\u223c\",\"THORN\":\"\\xde\",\"thorn\":\"\\xfe\",\"tilde\":\"\\u02dc\",\"Tilde\":\"\\u223c\",\"TildeEqual\":\"\\u2243\",\"TildeFullEqual\":\"\\u2245\",\"TildeTilde\":\"\\u2248\",\"timesbar\":\"\\u2a31\",\"timesb\":\"\\u22a0\",\"times\":\"\\xd7\",\"timesd\":\"\\u2a30\",\"tint\":\"\\u222d\",\"toea\":\"\\u2928\",\"topbot\":\"\\u2336\",\"topcir\":\"\\u2af1\",\"top\":\"\\u22a4\",\"Topf\":\"\\ud835\\udd4b\",\"topf\":\"\\ud835\\udd65\",\"topfork\":\"\\u2ada\",\"tosa\":\"\\u2929\",\"tprime\":\"\\u2034\",\"trade\":\"\\u2122\",\"TRADE\":\"\\u2122\",\"triangle\":\"\\u25b5\",\"triangledown\":\"\\u25bf\",\"triangleleft\":\"\\u25c3\",\"trianglelefteq\":\"\\u22b4\",\"triangleq\":\"\\u225c\",\"triangleright\":\"\\u25b9\",\"trianglerighteq\":\"\\u22b5\",\"tridot\":\"\\u25ec\",\"trie\":\"\\u225c\",\"triminus\":\"\\u2a3a\",\"TripleDot\":\"\\u20db\",\"triplus\":\"\\u2a39\",\"trisb\":\"\\u29cd\",\"tritime\":\"\\u2a3b\",\"trpezium\":\"\\u23e2\",\"Tscr\":\"\\ud835\\udcaf\",\"tscr\":\"\\ud835\\udcc9\",\"TScy\":\"\\u0426\",\"tscy\":\"\\u0446\",\"TSHcy\":\"\\u040b\",\"tshcy\":\"\\u045b\",\"Tstrok\":\"\\u0166\",\"tstrok\":\"\\u0167\",\"twixt\":\"\\u226c\",\"twoheadleftarrow\":\"\\u219e\",\"twoheadrightarrow\":\"\\u21a0\",\"Uacute\":\"\\xda\",\"uacute\":\"\\xfa\",\"uarr\":\"\\u2191\",\"Uarr\":\"\\u219f\",\"uArr\":\"\\u21d1\",\"Uarrocir\":\"\\u2949\",\"Ubrcy\":\"\\u040e\",\"ubrcy\":\"\\u045e\",\"Ubreve\":\"\\u016c\",\"ubreve\":\"\\u016d\",\"Ucirc\":\"\\xdb\",\"ucirc\":\"\\xfb\",\"Ucy\":\"\\u0423\",\"ucy\":\"\\u0443\",\"udarr\":\"\\u21c5\",\"Udblac\":\"\\u0170\",\"udblac\":\"\\u0171\",\"udhar\":\"\\u296e\",\"ufisht\":\"\\u297e\",\"Ufr\":\"\\ud835\\udd18\",\"ufr\":\"\\ud835\\udd32\",\"Ugrave\":\"\\xd9\",\"ugrave\":\"\\xf9\",\"uHar\":\"\\u2963\",\"uharl\":\"\\u21bf\",\"uharr\":\"\\u21be\",\"uhblk\":\"\\u2580\",\"ulcorn\":\"\\u231c\",\"ulcorner\":\"\\u231c\",\"ulcrop\":\"\\u230f\",\"ultri\":\"\\u25f8\",\"Umacr\":\"\\u016a\",\"umacr\":\"\\u016b\",\"uml\":\"\\xa8\",\"UnderBar\":\"_\",\"UnderBrace\":\"\\u23df\",\"UnderBracket\":\"\\u23b5\",\"UnderParenthesis\":\"\\u23dd\",\"Union\":\"\\u22c3\",\"UnionPlus\":\"\\u228e\",\"Uogon\":\"\\u0172\",\"uogon\":\"\\u0173\",\"Uopf\":\"\\ud835\\udd4c\",\"uopf\":\"\\ud835\\udd66\",\"UpArrowBar\":\"\\u2912\",\"uparrow\":\"\\u2191\",\"UpArrow\":\"\\u2191\",\"Uparrow\":\"\\u21d1\",\"UpArrowDownArrow\":\"\\u21c5\",\"updownarrow\":\"\\u2195\",\"UpDownArrow\":\"\\u2195\",\"Updownarrow\":\"\\u21d5\",\"UpEquilibrium\":\"\\u296e\",\"upharpoonleft\":\"\\u21bf\",\"upharpoonright\":\"\\u21be\",\"uplus\":\"\\u228e\",\"UpperLeftArrow\":\"\\u2196\",\"UpperRightArrow\":\"\\u2197\",\"upsi\":\"\\u03c5\",\"Upsi\":\"\\u03d2\",\"upsih\":\"\\u03d2\",\"Upsilon\":\"\\u03a5\",\"upsilon\":\"\\u03c5\",\"UpTeeArrow\":\"\\u21a5\",\"UpTee\":\"\\u22a5\",\"upuparrows\":\"\\u21c8\",\"urcorn\":\"\\u231d\",\"urcorner\":\"\\u231d\",\"urcrop\":\"\\u230e\",\"Uring\":\"\\u016e\",\"uring\":\"\\u016f\",\"urtri\":\"\\u25f9\",\"Uscr\":\"\\ud835\\udcb0\",\"uscr\":\"\\ud835\\udcca\",\"utdot\":\"\\u22f0\",\"Utilde\":\"\\u0168\",\"utilde\":\"\\u0169\",\"utri\":\"\\u25b5\",\"utrif\":\"\\u25b4\",\"uuarr\":\"\\u21c8\",\"Uuml\":\"\\xdc\",\"uuml\":\"\\xfc\",\"uwangle\":\"\\u29a7\",\"vangrt\":\"\\u299c\",\"varepsilon\":\"\\u03f5\",\"varkappa\":\"\\u03f0\",\"varnothing\":\"\\u2205\",\"varphi\":\"\\u03d5\",\"varpi\":\"\\u03d6\",\"varpropto\":\"\\u221d\",\"varr\":\"\\u2195\",\"vArr\":\"\\u21d5\",\"varrho\":\"\\u03f1\",\"varsigma\":\"\\u03c2\",\"varsubsetneq\":\"\\u228a\\ufe00\",\"varsubsetneqq\":\"\\u2acb\\ufe00\",\"varsupsetneq\":\"\\u228b\\ufe00\",\"varsupsetneqq\":\"\\u2acc\\ufe00\",\"vartheta\":\"\\u03d1\",\"vartriangleleft\":\"\\u22b2\",\"vartriangleright\":\"\\u22b3\",\"vBar\":\"\\u2ae8\",\"Vbar\":\"\\u2aeb\",\"vBarv\":\"\\u2ae9\",\"Vcy\":\"\\u0412\",\"vcy\":\"\\u0432\",\"vdash\":\"\\u22a2\",\"vDash\":\"\\u22a8\",\"Vdash\":\"\\u22a9\",\"VDash\":\"\\u22ab\",\"Vdashl\":\"\\u2ae6\",\"veebar\":\"\\u22bb\",\"vee\":\"\\u2228\",\"Vee\":\"\\u22c1\",\"veeeq\":\"\\u225a\",\"vellip\":\"\\u22ee\",\"verbar\":\"|\",\"Verbar\":\"\\u2016\",\"vert\":\"|\",\"Vert\":\"\\u2016\",\"VerticalBar\":\"\\u2223\",\"VerticalLine\":\"|\",\"VerticalSeparator\":\"\\u2758\",\"VerticalTilde\":\"\\u2240\",\"VeryThinSpace\":\"\\u200a\",\"Vfr\":\"\\ud835\\udd19\",\"vfr\":\"\\ud835\\udd33\",\"vltri\":\"\\u22b2\",\"vnsub\":\"\\u2282\\u20d2\",\"vnsup\":\"\\u2283\\u20d2\",\"Vopf\":\"\\ud835\\udd4d\",\"vopf\":\"\\ud835\\udd67\",\"vprop\":\"\\u221d\",\"vrtri\":\"\\u22b3\",\"Vscr\":\"\\ud835\\udcb1\",\"vscr\":\"\\ud835\\udccb\",\"vsubnE\":\"\\u2acb\\ufe00\",\"vsubne\":\"\\u228a\\ufe00\",\"vsupnE\":\"\\u2acc\\ufe00\",\"vsupne\":\"\\u228b\\ufe00\",\"Vvdash\":\"\\u22aa\",\"vzigzag\":\"\\u299a\",\"Wcirc\":\"\\u0174\",\"wcirc\":\"\\u0175\",\"wedbar\":\"\\u2a5f\",\"wedge\":\"\\u2227\",\"Wedge\":\"\\u22c0\",\"wedgeq\":\"\\u2259\",\"weierp\":\"\\u2118\",\"Wfr\":\"\\ud835\\udd1a\",\"wfr\":\"\\ud835\\udd34\",\"Wopf\":\"\\ud835\\udd4e\",\"wopf\":\"\\ud835\\udd68\",\"wp\":\"\\u2118\",\"wr\":\"\\u2240\",\"wreath\":\"\\u2240\",\"Wscr\":\"\\ud835\\udcb2\",\"wscr\":\"\\ud835\\udccc\",\"xcap\":\"\\u22c2\",\"xcirc\":\"\\u25ef\",\"xcup\":\"\\u22c3\",\"xdtri\":\"\\u25bd\",\"Xfr\":\"\\ud835\\udd1b\",\"xfr\":\"\\ud835\\udd35\",\"xharr\":\"\\u27f7\",\"xhArr\":\"\\u27fa\",\"Xi\":\"\\u039e\",\"xi\":\"\\u03be\",\"xlarr\":\"\\u27f5\",\"xlArr\":\"\\u27f8\",\"xmap\":\"\\u27fc\",\"xnis\":\"\\u22fb\",\"xodot\":\"\\u2a00\",\"Xopf\":\"\\ud835\\udd4f\",\"xopf\":\"\\ud835\\udd69\",\"xoplus\":\"\\u2a01\",\"xotime\":\"\\u2a02\",\"xrarr\":\"\\u27f6\",\"xrArr\":\"\\u27f9\",\"Xscr\":\"\\ud835\\udcb3\",\"xscr\":\"\\ud835\\udccd\",\"xsqcup\":\"\\u2a06\",\"xuplus\":\"\\u2a04\",\"xutri\":\"\\u25b3\",\"xvee\":\"\\u22c1\",\"xwedge\":\"\\u22c0\",\"Yacute\":\"\\xdd\",\"yacute\":\"\\xfd\",\"YAcy\":\"\\u042f\",\"yacy\":\"\\u044f\",\"Ycirc\":\"\\u0176\",\"ycirc\":\"\\u0177\",\"Ycy\":\"\\u042b\",\"ycy\":\"\\u044b\",\"yen\":\"\\xa5\",\"Yfr\":\"\\ud835\\udd1c\",\"yfr\":\"\\ud835\\udd36\",\"YIcy\":\"\\u0407\",\"yicy\":\"\\u0457\",\"Yopf\":\"\\ud835\\udd50\",\"yopf\":\"\\ud835\\udd6a\",\"Yscr\":\"\\ud835\\udcb4\",\"yscr\":\"\\ud835\\udcce\",\"YUcy\":\"\\u042e\",\"yucy\":\"\\u044e\",\"yuml\":\"\\xff\",\"Yuml\":\"\\u0178\",\"Zacute\":\"\\u0179\",\"zacute\":\"\\u017a\",\"Zcaron\":\"\\u017d\",\"zcaron\":\"\\u017e\",\"Zcy\":\"\\u0417\",\"zcy\":\"\\u0437\",\"Zdot\":\"\\u017b\",\"zdot\":\"\\u017c\",\"zeetrf\":\"\\u2128\",\"ZeroWidthSpace\":\"\\u200b\",\"Zeta\":\"\\u0396\",\"zeta\":\"\\u03b6\",\"zfr\":\"\\ud835\\udd37\",\"Zfr\":\"\\u2128\",\"ZHcy\":\"\\u0416\",\"zhcy\":\"\\u0436\",\"zigrarr\":\"\\u21dd\",\"zopf\":\"\\ud835\\udd6b\",\"Zopf\":\"\\u2124\",\"Zscr\":\"\\ud835\\udcb5\",\"zscr\":\"\\ud835\\udccf\",\"zwj\":\"\\u200d\",\"zwnj\":\"\\u200c\"}')},function(t){t.exports=JSON.parse('{\"amp\":\"&\",\"apos\":\"\\'\",\"gt\":\">\",\"lt\":\"<\",\"quot\":\"\\\\\"\"}')},function(t,e,r){\"use strict\";Object.defineProperty(e,\"__esModule\",{value:!0});e.isTag=function(t){return\"tag\"===t.type||\"script\"===t.type||\"style\"===t.type};e.Text=\"text\";e.Directive=\"directive\";e.Comment=\"comment\";e.Script=\"script\";e.Style=\"style\";e.Tag=\"tag\";e.CDATA=\"cdata\";e.Doctype=\"doctype\"},function(t,e,r){\"use strict\";var i,n=this&&this.__extends||(i=function(t,e){return(i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)if(e.hasOwnProperty(r))t[r]=e[r]})(t,e)},function(t,e){i(t,e);function r(){this.constructor=t}t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),s=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,\"__esModule\",{value:!0});var o=s(r(11)),a=r(31),u=new Set([\"input\",\"option\",\"optgroup\",\"select\",\"button\",\"datalist\",\"textarea\"]),c=new Set([\"p\"]),l={tr:new Set([\"tr\",\"th\",\"td\"]),th:new Set([\"th\"]),td:new Set([\"thead\",\"th\",\"td\"]),body:new Set([\"head\",\"link\",\"script\"]),li:new Set([\"li\"]),p:c,h1:c,h2:c,h3:c,h4:c,h5:c,h6:c,select:u,input:u,output:u,button:u,datalist:u,textarea:u,option:new Set([\"option\"]),optgroup:new Set([\"optgroup\",\"option\"]),dd:new Set([\"dt\",\"dd\"]),dt:new Set([\"dt\",\"dd\"]),address:c,article:c,aside:c,blockquote:c,details:c,div:c,dl:c,fieldset:c,figcaption:c,figure:c,footer:c,form:c,header:c,hr:c,main:c,nav:c,ol:c,pre:c,section:c,table:c,ul:c,rt:new Set([\"rt\",\"rp\"]),rp:new Set([\"rt\",\"rp\"]),tbody:new Set([\"thead\",\"tbody\"]),tfoot:new Set([\"thead\",\"tbody\"])},f=new Set([\"area\",\"base\",\"basefont\",\"br\",\"col\",\"command\",\"embed\",\"frame\",\"hr\",\"img\",\"input\",\"isindex\",\"keygen\",\"link\",\"meta\",\"param\",\"source\",\"track\",\"wbr\"]),h=new Set([\"math\",\"svg\"]),d=new Set([\"mi\",\"mo\",\"mn\",\"ms\",\"mtext\",\"annotation-xml\",\"foreignObject\",\"desc\",\"title\"]),p=/\\s|\\//,_=function(t){n(e,t);function e(r,i){var n=t.call(this)||this;n._tagname=\"\";n._attribname=\"\";n._attribvalue=\"\";n._attribs=null;n._stack=[];n._foreignContext=[];n.startIndex=0;n.endIndex=null;n.parseChunk=e.prototype.write;n.done=e.prototype.end;n._options=i||{};n._cbs=r||{};n._tagname=\"\";n._attribname=\"\";n._attribvalue=\"\";n._attribs=null;n._stack=[];n._foreignContext=[];n.startIndex=0;n.endIndex=null;n._lowerCaseTagNames=\"lowerCaseTags\"in n._options?!!n._options.lowerCaseTags:!n._options.xmlMode;n._lowerCaseAttributeNames=\"lowerCaseAttributeNames\"in n._options?!!n._options.lowerCaseAttributeNames:!n._options.xmlMode;n._tokenizer=new(n._options.Tokenizer||o.default)(n._options,n);if(n._cbs.onparserinit)n._cbs.onparserinit(n);return n}e.prototype._updatePosition=function(t){if(null===this.endIndex)if(this._tokenizer._sectionStart<=t)this.startIndex=0;else this.startIndex=this._tokenizer._sectionStart-t;else this.startIndex=this.endIndex+1;this.endIndex=this._tokenizer.getAbsoluteIndex()};e.prototype.ontext=function(t){this._updatePosition(1);this.endIndex--;if(this._cbs.ontext)this._cbs.ontext(t)};e.prototype.onopentagname=function(t){if(this._lowerCaseTagNames)t=t.toLowerCase();this._tagname=t;if(!this._options.xmlMode&&Object.prototype.hasOwnProperty.call(l,t))for(var e=void 0;l[t].has(e=this._stack[this._stack.length-1]);this.onclosetag(e));if(this._options.xmlMode||!f.has(t)){this._stack.push(t);if(h.has(t))this._foreignContext.push(!0);else if(d.has(t))this._foreignContext.push(!1)}if(this._cbs.onopentagname)this._cbs.onopentagname(t);if(this._cbs.onopentag)this._attribs={}};e.prototype.onopentagend=function(){this._updatePosition(1);if(this._attribs){if(this._cbs.onopentag)this._cbs.onopentag(this._tagname,this._attribs);this._attribs=null}if(!this._options.xmlMode&&this._cbs.onclosetag&&f.has(this._tagname))this._cbs.onclosetag(this._tagname);this._tagname=\"\"};e.prototype.onclosetag=function(t){this._updatePosition(1);if(this._lowerCaseTagNames)t=t.toLowerCase();if(h.has(t)||d.has(t))this._foreignContext.pop();if(this._stack.length&&(this._options.xmlMode||!f.has(t))){var e=this._stack.lastIndexOf(t);if(-1!==e)if(this._cbs.onclosetag){e=this._stack.length-e;for(;e--;)this._cbs.onclosetag(this._stack.pop())}else this._stack.length=e;else if(\"p\"===t&&!this._options.xmlMode){this.onopentagname(t);this._closeCurrentTag()}}else if(!this._options.xmlMode&&(\"br\"===t||\"p\"===t)){this.onopentagname(t);this._closeCurrentTag()}};e.prototype.onselfclosingtag=function(){if(this._options.xmlMode||this._options.recognizeSelfClosing||this._foreignContext[this._foreignContext.length-1])this._closeCurrentTag();else this.onopentagend()};e.prototype._closeCurrentTag=function(){var t=this._tagname;this.onopentagend();if(this._stack[this._stack.length-1]===t){if(this._cbs.onclosetag)this._cbs.onclosetag(t);this._stack.pop()}};e.prototype.onattribname=function(t){if(this._lowerCaseAttributeNames)t=t.toLowerCase();this._attribname=t};e.prototype.onattribdata=function(t){this._attribvalue+=t};e.prototype.onattribend=function(){if(this._cbs.onattribute)this._cbs.onattribute(this._attribname,this._attribvalue);if(this._attribs&&!Object.prototype.hasOwnProperty.call(this._attribs,this._attribname))this._attribs[this._attribname]=this._attribvalue;this._attribname=\"\";this._attribvalue=\"\"};e.prototype._getInstructionName=function(t){var e=t.search(p),r=e<0?t:t.substr(0,e);if(this._lowerCaseTagNames)r=r.toLowerCase();return r};e.prototype.ondeclaration=function(t){if(this._cbs.onprocessinginstruction){var e=this._getInstructionName(t);this._cbs.onprocessinginstruction(\"!\"+e,\"!\"+t)}};e.prototype.onprocessinginstruction=function(t){if(this._cbs.onprocessinginstruction){var e=this._getInstructionName(t);this._cbs.onprocessinginstruction(\"?\"+e,\"?\"+t)}};e.prototype.oncomment=function(t){this._updatePosition(4);if(this._cbs.oncomment)this._cbs.oncomment(t);if(this._cbs.oncommentend)this._cbs.oncommentend()};e.prototype.oncdata=function(t){this._updatePosition(1);if(this._options.xmlMode||this._options.recognizeCDATA){if(this._cbs.oncdatastart)this._cbs.oncdatastart();if(this._cbs.ontext)this._cbs.ontext(t);if(this._cbs.oncdataend)this._cbs.oncdataend()}else this.oncomment(\"[CDATA[\"+t+\"]]\")};e.prototype.onerror=function(t){if(this._cbs.onerror)this._cbs.onerror(t)};e.prototype.onend=function(){if(this._cbs.onclosetag)for(var t=this._stack.length;t>0;this._cbs.onclosetag(this._stack[--t]));if(this._cbs.onend)this._cbs.onend()};e.prototype.reset=function(){if(this._cbs.onreset)this._cbs.onreset();this._tokenizer.reset();this._tagname=\"\";this._attribname=\"\";this._attribs=null;this._stack=[];if(this._cbs.onparserinit)this._cbs.onparserinit(this)};e.prototype.parseComplete=function(t){this.reset();this.end(t)};e.prototype.write=function(t){this._tokenizer.write(t)};e.prototype.end=function(t){this._tokenizer.end(t)};e.prototype.pause=function(){this._tokenizer.pause()};e.prototype.resume=function(){this._tokenizer.resume()};return e}(a.EventEmitter);e.Parser=_},function(t,e,r){\"use strict\";var i=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,\"__esModule\",{value:!0});var n=i(r(12)),s=i(r(7)),o=i(r(13)),a=i(r(8));function u(t){return\" \"===t||\"\\n\"===t||\"\\t\"===t||\"\\f\"===t||\"\\r\"===t}function c(t,e,r){var i=t.toLowerCase();if(t===i)return function(t,n){if(n===i)t._state=e;else{t._state=r;t._index--}};else return function(n,s){if(s===i||s===t)n._state=e;else{n._state=r;n._index--}}}function l(t,e){var r=t.toLowerCase();return function(i,n){if(n===r||n===t)i._state=e;else{i._state=3;i._index--}}}var f=c(\"C\",23,16),h=c(\"D\",24,16),d=c(\"A\",25,16),p=c(\"T\",26,16),_=c(\"A\",27,16),m=l(\"R\",34),g=l(\"I\",35),b=l(\"P\",36),E=l(\"T\",37),y=c(\"R\",39,1),v=c(\"I\",40,1),A=c(\"P\",41,1),C=c(\"T\",42,1),T=l(\"Y\",44),D=l(\"L\",45),x=l(\"E\",46),N=c(\"Y\",48,1),S=c(\"L\",49,1),O=c(\"E\",50,1),L=c(\"#\",52,53),w=c(\"X\",55,54),P=function(){function t(t,e){this._state=1;this._buffer=\"\";this._sectionStart=0;this._index=0;this._bufferOffset=0;this._baseState=1;this._special=1;this._running=!0;this._ended=!1;this._cbs=e;this._xmlMode=!(!t||!t.xmlMode);this._decodeEntities=!(!t||!t.decodeEntities)}t.prototype.reset=function(){this._state=1;this._buffer=\"\";this._sectionStart=0;this._index=0;this._bufferOffset=0;this._baseState=1;this._special=1;this._running=!0;this._ended=!1};t.prototype._stateText=function(t){if(\"<\"===t){if(this._index>this._sectionStart)this._cbs.ontext(this._getSection());this._state=2;this._sectionStart=this._index}else if(this._decodeEntities&&1===this._special&&\"&\"===t){if(this._index>this._sectionStart)this._cbs.ontext(this._getSection());this._baseState=1;this._state=51;this._sectionStart=this._index}};t.prototype._stateBeforeTagName=function(t){if(\"/\"===t)this._state=5;else if(\"<\"===t){this._cbs.ontext(this._getSection());this._sectionStart=this._index}else if(\">\"===t||1!==this._special||u(t))this._state=1;else if(\"!\"===t){this._state=15;this._sectionStart=this._index+1}else if(\"?\"===t){this._state=17;this._sectionStart=this._index+1}else{this._state=!this._xmlMode&&(\"s\"===t||\"S\"===t)?31:3;this._sectionStart=this._index}};t.prototype._stateInTagName=function(t){if(\"/\"===t||\">\"===t||u(t)){this._emitToken(\"onopentagname\");this._state=8;this._index--}};t.prototype._stateBeforeClosingTagName=function(t){if(u(t));else if(\">\"===t)this._state=1;else if(1!==this._special)if(\"s\"===t||\"S\"===t)this._state=32;else{this._state=1;this._index--}else{this._state=6;this._sectionStart=this._index}};t.prototype._stateInClosingTagName=function(t){if(\">\"===t||u(t)){this._emitToken(\"onclosetag\");this._state=7;this._index--}};t.prototype._stateAfterClosingTagName=function(t){if(\">\"===t){this._state=1;this._sectionStart=this._index+1}};t.prototype._stateBeforeAttributeName=function(t){if(\">\"===t){this._cbs.onopentagend();this._state=1;this._sectionStart=this._index+1}else if(\"/\"===t)this._state=4;else if(!u(t)){this._state=9;this._sectionStart=this._index}};t.prototype._stateInSelfClosingTag=function(t){if(\">\"===t){this._cbs.onselfclosingtag();this._state=1;this._sectionStart=this._index+1}else if(!u(t)){this._state=8;this._index--}};t.prototype._stateInAttributeName=function(t){if(\"=\"===t||\"/\"===t||\">\"===t||u(t)){this._cbs.onattribname(this._getSection());this._sectionStart=-1;this._state=10;this._index--}};t.prototype._stateAfterAttributeName=function(t){if(\"=\"===t)this._state=11;else if(\"/\"===t||\">\"===t){this._cbs.onattribend();this._state=8;this._index--}else if(!u(t)){this._cbs.onattribend();this._state=9;this._sectionStart=this._index}};t.prototype._stateBeforeAttributeValue=function(t){if('\"'===t){this._state=12;this._sectionStart=this._index+1}else if(\"'\"===t){this._state=13;this._sectionStart=this._index+1}else if(!u(t)){this._state=14;this._sectionStart=this._index;this._index--}};t.prototype._stateInAttributeValueDoubleQuotes=function(t){if('\"'===t){this._emitToken(\"onattribdata\");this._cbs.onattribend();this._state=8}else if(this._decodeEntities&&\"&\"===t){this._emitToken(\"onattribdata\");this._baseState=this._state;this._state=51;this._sectionStart=this._index}};t.prototype._stateInAttributeValueSingleQuotes=function(t){if(\"'\"===t){this._emitToken(\"onattribdata\");this._cbs.onattribend();this._state=8}else if(this._decodeEntities&&\"&\"===t){this._emitToken(\"onattribdata\");this._baseState=this._state;this._state=51;this._sectionStart=this._index}};t.prototype._stateInAttributeValueNoQuotes=function(t){if(u(t)||\">\"===t){this._emitToken(\"onattribdata\");this._cbs.onattribend();this._state=8;this._index--}else if(this._decodeEntities&&\"&\"===t){this._emitToken(\"onattribdata\");this._baseState=this._state;this._state=51;this._sectionStart=this._index}};t.prototype._stateBeforeDeclaration=function(t){this._state=\"[\"===t?22:\"-\"===t?18:16};t.prototype._stateInDeclaration=function(t){if(\">\"===t){this._cbs.ondeclaration(this._getSection());this._state=1;this._sectionStart=this._index+1}};t.prototype._stateInProcessingInstruction=function(t){if(\">\"===t){this._cbs.onprocessinginstruction(this._getSection());this._state=1;this._sectionStart=this._index+1}};t.prototype._stateBeforeComment=function(t){if(\"-\"===t){this._state=19;this._sectionStart=this._index+1}else this._state=16};t.prototype._stateInComment=function(t){if(\"-\"===t)this._state=20};t.prototype._stateAfterComment1=function(t){if(\"-\"===t)this._state=21;else this._state=19};t.prototype._stateAfterComment2=function(t){if(\">\"===t){this._cbs.oncomment(this._buffer.substring(this._sectionStart,this._index-2));this._state=1;this._sectionStart=this._index+1}else if(\"-\"!==t)this._state=19};t.prototype._stateBeforeCdata6=function(t){if(\"[\"===t){this._state=28;this._sectionStart=this._index+1}else{this._state=16;this._index--}};t.prototype._stateInCdata=function(t){if(\"]\"===t)this._state=29};t.prototype._stateAfterCdata1=function(t){if(\"]\"===t)this._state=30;else this._state=28};t.prototype._stateAfterCdata2=function(t){if(\">\"===t){this._cbs.oncdata(this._buffer.substring(this._sectionStart,this._index-2));this._state=1;this._sectionStart=this._index+1}else if(\"]\"!==t)this._state=28};t.prototype._stateBeforeSpecial=function(t){if(\"c\"===t||\"C\"===t)this._state=33;else if(\"t\"===t||\"T\"===t)this._state=43;else{this._state=3;this._index--}};t.prototype._stateBeforeSpecialEnd=function(t){if(2===this._special&&(\"c\"===t||\"C\"===t))this._state=38;else if(3===this._special&&(\"t\"===t||\"T\"===t))this._state=47;else this._state=1};t.prototype._stateBeforeScript5=function(t){if(\"/\"===t||\">\"===t||u(t))this._special=2;this._state=3;this._index--};t.prototype._stateAfterScript5=function(t){if(\">\"===t||u(t)){this._special=1;this._state=6;this._sectionStart=this._index-6;this._index--}else this._state=1};t.prototype._stateBeforeStyle4=function(t){if(\"/\"===t||\">\"===t||u(t))this._special=3;this._state=3;this._index--};t.prototype._stateAfterStyle4=function(t){if(\">\"===t||u(t)){this._special=1;this._state=6;this._sectionStart=this._index-5;this._index--}else this._state=1};t.prototype._parseNamedEntityStrict=function(){if(this._sectionStart+1<this._index){var t=this._buffer.substring(this._sectionStart+1,this._index),e=this._xmlMode?a.default:s.default;if(Object.prototype.hasOwnProperty.call(e,t)){this._emitPartial(e[t]);this._sectionStart=this._index+1}}};t.prototype._parseLegacyEntity=function(){var t=this._sectionStart+1,e=this._index-t;if(e>6)e=6;for(;e>=2;){var r=this._buffer.substr(t,e);if(Object.prototype.hasOwnProperty.call(o.default,r)){this._emitPartial(o.default[r]);this._sectionStart+=e+1;return}else e--}};t.prototype._stateInNamedEntity=function(t){if(\";\"===t){this._parseNamedEntityStrict();if(this._sectionStart+1<this._index&&!this._xmlMode)this._parseLegacyEntity();this._state=this._baseState}else if((t<\"a\"||t>\"z\")&&(t<\"A\"||t>\"Z\")&&(t<\"0\"||t>\"9\")){if(this._xmlMode||this._sectionStart+1===this._index);else if(1!==this._baseState){if(\"=\"!==t)this._parseNamedEntityStrict()}else this._parseLegacyEntity();this._state=this._baseState;this._index--}};t.prototype._decodeNumericEntity=function(t,e){var r=this._sectionStart+t;if(r!==this._index){var i=this._buffer.substring(r,this._index),s=parseInt(i,e);this._emitPartial(n.default(s));this._sectionStart=this._index}else this._sectionStart--;this._state=this._baseState};t.prototype._stateInNumericEntity=function(t){if(\";\"===t){this._decodeNumericEntity(2,10);this._sectionStart++}else if(t<\"0\"||t>\"9\"){if(!this._xmlMode)this._decodeNumericEntity(2,10);else this._state=this._baseState;this._index--}};t.prototype._stateInHexEntity=function(t){if(\";\"===t){this._decodeNumericEntity(3,16);this._sectionStart++}else if((t<\"a\"||t>\"f\")&&(t<\"A\"||t>\"F\")&&(t<\"0\"||t>\"9\")){if(!this._xmlMode)this._decodeNumericEntity(3,16);else this._state=this._baseState;this._index--}};t.prototype._cleanup=function(){if(this._sectionStart<0){this._buffer=\"\";this._bufferOffset+=this._index;this._index=0}else if(this._running){if(1===this._state){if(this._sectionStart!==this._index)this._cbs.ontext(this._buffer.substr(this._sectionStart));this._buffer=\"\";this._bufferOffset+=this._index;this._index=0}else if(this._sectionStart===this._index){this._buffer=\"\";this._bufferOffset+=this._index;this._index=0}else{this._buffer=this._buffer.substr(this._sectionStart);this._index-=this._sectionStart;this._bufferOffset+=this._sectionStart}this._sectionStart=0}};t.prototype.write=function(t){if(this._ended)this._cbs.onerror(Error(\".write() after done!\"));this._buffer+=t;this._parse()};t.prototype._parse=function(){for(;this._index<this._buffer.length&&this._running;){var t=this._buffer.charAt(this._index);if(1===this._state)this._stateText(t);else if(12===this._state)this._stateInAttributeValueDoubleQuotes(t);else if(9===this._state)this._stateInAttributeName(t);else if(19===this._state)this._stateInComment(t);else if(8===this._state)this._stateBeforeAttributeName(t);else if(3===this._state)this._stateInTagName(t);else if(6===this._state)this._stateInClosingTagName(t);else if(2===this._state)this._stateBeforeTagName(t);else if(10===this._state)this._stateAfterAttributeName(t);else if(13===this._state)this._stateInAttributeValueSingleQuotes(t);else if(11===this._state)this._stateBeforeAttributeValue(t);else if(5===this._state)this._stateBeforeClosingTagName(t);else if(7===this._state)this._stateAfterClosingTagName(t);else if(31===this._state)this._stateBeforeSpecial(t);else if(20===this._state)this._stateAfterComment1(t);else if(14===this._state)this._stateInAttributeValueNoQuotes(t);else if(4===this._state)this._stateInSelfClosingTag(t);else if(16===this._state)this._stateInDeclaration(t);else if(15===this._state)this._stateBeforeDeclaration(t);else if(21===this._state)this._stateAfterComment2(t);else if(18===this._state)this._stateBeforeComment(t);else if(32===this._state)this._stateBeforeSpecialEnd(t);else if(38===this._state)y(this,t);else if(39===this._state)v(this,t);else if(40===this._state)A(this,t);else if(33===this._state)m(this,t);else if(34===this._state)g(this,t);else if(35===this._state)b(this,t);else if(36===this._state)E(this,t);else if(37===this._state)this._stateBeforeScript5(t);else if(41===this._state)C(this,t);else if(42===this._state)this._stateAfterScript5(t);else if(43===this._state)T(this,t);else if(28===this._state)this._stateInCdata(t);else if(44===this._state)D(this,t);else if(45===this._state)x(this,t);else if(46===this._state)this._stateBeforeStyle4(t);else if(47===this._state)N(this,t);else if(48===this._state)S(this,t);else if(49===this._state)O(this,t);else if(50===this._state)this._stateAfterStyle4(t);else if(17===this._state)this._stateInProcessingInstruction(t);else if(53===this._state)this._stateInNamedEntity(t);else if(22===this._state)f(this,t);else if(51===this._state)L(this,t);else if(23===this._state)h(this,t);else if(24===this._state)d(this,t);else if(29===this._state)this._stateAfterCdata1(t);else if(30===this._state)this._stateAfterCdata2(t);else if(25===this._state)p(this,t);else if(26===this._state)_(this,t);else if(27===this._state)this._stateBeforeCdata6(t);else if(55===this._state)this._stateInHexEntity(t);else if(54===this._state)this._stateInNumericEntity(t);else if(52===this._state)w(this,t);else this._cbs.onerror(Error(\"unknown _state\"),this._state);this._index++}this._cleanup()};t.prototype.pause=function(){this._running=!1};t.prototype.resume=function(){this._running=!0;if(this._index<this._buffer.length)this._parse();if(this._ended)this._finish()};t.prototype.end=function(t){if(this._ended)this._cbs.onerror(Error(\".end() after done!\"));if(t)this.write(t);this._ended=!0;if(this._running)this._finish()};t.prototype._finish=function(){if(this._sectionStart<this._index)this._handleTrailingData();this._cbs.onend()};t.prototype._handleTrailingData=function(){var t=this._buffer.substr(this._sectionStart);if(28===this._state||29===this._state||30===this._state)this._cbs.oncdata(t);else if(19===this._state||20===this._state||21===this._state)this._cbs.oncomment(t);else if(53===this._state&&!this._xmlMode){this._parseLegacyEntity();if(this._sectionStart<this._index){this._state=this._baseState;this._handleTrailingData()}}else if(54===this._state&&!this._xmlMode){this._decodeNumericEntity(2,10);if(this._sectionStart<this._index){this._state=this._baseState;this._handleTrailingData()}}else if(55===this._state&&!this._xmlMode){this._decodeNumericEntity(3,16);if(this._sectionStart<this._index){this._state=this._baseState;this._handleTrailingData()}}else if(3!==this._state&&8!==this._state&&11!==this._state&&10!==this._state&&9!==this._state&&13!==this._state&&12!==this._state&&14!==this._state&&6!==this._state)this._cbs.ontext(t)};t.prototype.getAbsoluteIndex=function(){return this._bufferOffset+this._index};t.prototype._getSection=function(){return this._buffer.substring(this._sectionStart,this._index)};t.prototype._emitToken=function(t){this._cbs[t](this._getSection());this._sectionStart=-1};t.prototype._emitPartial=function(t){if(1!==this._baseState)this._cbs.onattribdata(t);else this._cbs.ontext(t)};return t}();e.default=P},function(t,e,r){\"use strict\";var i=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,\"__esModule\",{value:!0});var n=i(r(30));e.default=function(t){if(t>=55296&&t<=57343||t>1114111)return\"\\ufffd\";if(t in n.default)t=n.default[t];var e=\"\";if(t>65535){t-=65536;e+=String.fromCharCode(t>>>10&1023|55296);t=56320|1023&t}return e+=String.fromCharCode(t)}},function(t){t.exports=JSON.parse('{\"Aacute\":\"\\xc1\",\"aacute\":\"\\xe1\",\"Acirc\":\"\\xc2\",\"acirc\":\"\\xe2\",\"acute\":\"\\xb4\",\"AElig\":\"\\xc6\",\"aelig\":\"\\xe6\",\"Agrave\":\"\\xc0\",\"agrave\":\"\\xe0\",\"amp\":\"&\",\"AMP\":\"&\",\"Aring\":\"\\xc5\",\"aring\":\"\\xe5\",\"Atilde\":\"\\xc3\",\"atilde\":\"\\xe3\",\"Auml\":\"\\xc4\",\"auml\":\"\\xe4\",\"brvbar\":\"\\xa6\",\"Ccedil\":\"\\xc7\",\"ccedil\":\"\\xe7\",\"cedil\":\"\\xb8\",\"cent\":\"\\xa2\",\"copy\":\"\\xa9\",\"COPY\":\"\\xa9\",\"curren\":\"\\xa4\",\"deg\":\"\\xb0\",\"divide\":\"\\xf7\",\"Eacute\":\"\\xc9\",\"eacute\":\"\\xe9\",\"Ecirc\":\"\\xca\",\"ecirc\":\"\\xea\",\"Egrave\":\"\\xc8\",\"egrave\":\"\\xe8\",\"ETH\":\"\\xd0\",\"eth\":\"\\xf0\",\"Euml\":\"\\xcb\",\"euml\":\"\\xeb\",\"frac12\":\"\\xbd\",\"frac14\":\"\\xbc\",\"frac34\":\"\\xbe\",\"gt\":\">\",\"GT\":\">\",\"Iacute\":\"\\xcd\",\"iacute\":\"\\xed\",\"Icirc\":\"\\xce\",\"icirc\":\"\\xee\",\"iexcl\":\"\\xa1\",\"Igrave\":\"\\xcc\",\"igrave\":\"\\xec\",\"iquest\":\"\\xbf\",\"Iuml\":\"\\xcf\",\"iuml\":\"\\xef\",\"laquo\":\"\\xab\",\"lt\":\"<\",\"LT\":\"<\",\"macr\":\"\\xaf\",\"micro\":\"\\xb5\",\"middot\":\"\\xb7\",\"nbsp\":\"\\xa0\",\"not\":\"\\xac\",\"Ntilde\":\"\\xd1\",\"ntilde\":\"\\xf1\",\"Oacute\":\"\\xd3\",\"oacute\":\"\\xf3\",\"Ocirc\":\"\\xd4\",\"ocirc\":\"\\xf4\",\"Ograve\":\"\\xd2\",\"ograve\":\"\\xf2\",\"ordf\":\"\\xaa\",\"ordm\":\"\\xba\",\"Oslash\":\"\\xd8\",\"oslash\":\"\\xf8\",\"Otilde\":\"\\xd5\",\"otilde\":\"\\xf5\",\"Ouml\":\"\\xd6\",\"ouml\":\"\\xf6\",\"para\":\"\\xb6\",\"plusmn\":\"\\xb1\",\"pound\":\"\\xa3\",\"quot\":\"\\\\\"\",\"QUOT\":\"\\\\\"\",\"raquo\":\"\\xbb\",\"reg\":\"\\xae\",\"REG\":\"\\xae\",\"sect\":\"\\xa7\",\"shy\":\"\\xad\",\"sup1\":\"\\xb9\",\"sup2\":\"\\xb2\",\"sup3\":\"\\xb3\",\"szlig\":\"\\xdf\",\"THORN\":\"\\xde\",\"thorn\":\"\\xfe\",\"times\":\"\\xd7\",\"Uacute\":\"\\xda\",\"uacute\":\"\\xfa\",\"Ucirc\":\"\\xdb\",\"ucirc\":\"\\xfb\",\"Ugrave\":\"\\xd9\",\"ugrave\":\"\\xf9\",\"uml\":\"\\xa8\",\"Uuml\":\"\\xdc\",\"uuml\":\"\\xfc\",\"Yacute\":\"\\xdd\",\"yacute\":\"\\xfd\",\"yen\":\"\\xa5\",\"yuml\":\"\\xff\"}')},function(t,e,r){\"use strict\";Object.defineProperty(e,\"__esModule\",{value:!0});var i=r(32);e.Node=i.Node;e.Element=i.Element;e.DataNode=i.DataNode;e.NodeWithChildren=i.NodeWithChildren;var n=/\\s+/g,s={normalizeWhitespace:!1,withStartIndices:!1,withEndIndices:!1},o=function(){function t(t,e,r){this.dom=[];this._done=!1;this._tagStack=[];this._lastNode=null;this._parser=null;if(\"function\"==typeof e){r=e;e=s}if(\"object\"==typeof t){e=t;t=void 0}this._callback=t||null;this._options=e||s;this._elementCB=r||null}t.prototype.onparserinit=function(t){this._parser=t};t.prototype.onreset=function(){this.dom=[];this._done=!1;this._tagStack=[];this._lastNode=null;this._parser=this._parser||null};t.prototype.onend=function(){if(!this._done){this._done=!0;this._parser=null;this.handleCallback(null)}};t.prototype.onerror=function(t){this.handleCallback(t)};t.prototype.onclosetag=function(){this._lastNode=null;var t=this._tagStack.pop();if(t&&this._parser){if(this._options.withEndIndices)t.endIndex=this._parser.endIndex;if(this._elementCB)this._elementCB(t)}};t.prototype.onopentag=function(t,e){var r=new i.Element(t,e);this.addNode(r);this._tagStack.push(r)};t.prototype.ontext=function(t){var e=this._options.normalizeWhitespace,r=this._lastNode;if(r&&\"text\"===r.type)if(e)r.data=(r.data+t).replace(n,\" \");else r.data+=t;else{if(e)t=t.replace(n,\" \");var s=new i.DataNode(\"text\",t);this.addNode(s);this._lastNode=s}};t.prototype.oncomment=function(t){if(!this._lastNode||\"comment\"!==this._lastNode.type){var e=new i.DataNode(\"comment\",t);this.addNode(e);this._lastNode=e}else this._lastNode.data+=t};t.prototype.oncommentend=function(){this._lastNode=null};t.prototype.oncdatastart=function(){var t=new i.DataNode(\"text\",\"\"),e=new i.NodeWithChildren(\"cdata\",[t]);this.addNode(e);t.parent=e;this._lastNode=t};t.prototype.oncdataend=function(){this._lastNode=null};t.prototype.onprocessinginstruction=function(t,e){var r=new i.ProcessingInstruction(t,e);this.addNode(r)};t.prototype.handleCallback=function(t){if(\"function\"==typeof this._callback)this._callback(t,this.dom);else if(t)throw t};t.prototype.addNode=function(t){var e=this._tagStack[this._tagStack.length-1],r=e?e.children:this.dom,i=r[r.length-1];if(this._parser){if(this._options.withStartIndices)t.startIndex=this._parser.startIndex;if(this._options.withEndIndices)t.endIndex=this._parser.endIndex}r.push(t);if(i){t.prev=i;i.next=t}if(e)t.parent=e;this._lastNode=null};t.prototype.addDataNode=function(t){this.addNode(t);this._lastNode=t};return t}();e.DomHandler=o;e.default=o},function(t,e,r){\"use strict\";var i,n=this&&this.__extends||(i=function(t,e){return(i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)if(e.hasOwnProperty(r))t[r]=e[r]})(t,e)},function(t,e){i(t,e);function r(){this.constructor=t}t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),s=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}},o=this&&this.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var r in t)if(Object.hasOwnProperty.call(t,r))e[r]=t[r];e.default=t;return e};Object.defineProperty(e,\"__esModule\",{value:!0});var a=s(r(14)),u=o(r(16)),c=r(10),l=function(t){n(e,t);function e(e,r){if(\"object\"==typeof e&&null!==e)r=e=void 0;return t.call(this,e,r)||this}e.prototype.onend=function(){var t={},e=h(m,this.dom);if(e)if(\"feed\"===e.name){var r=e.children;t.type=\"atom\";_(t,\"id\",\"id\",r);_(t,\"title\",\"title\",r);var i=p(\"href\",h(\"link\",r));if(i)t.link=i;_(t,\"description\",\"subtitle\",r);if(n=d(\"updated\",r))t.updated=new Date(n);_(t,\"author\",\"email\",r,!0);t.items=f(\"entry\",r).map((function(t){var e={},r=t.children;_(e,\"id\",\"id\",r);_(e,\"title\",\"title\",r);var i=p(\"href\",h(\"link\",r));if(i)e.link=i;var n=d(\"summary\",r)||d(\"content\",r);if(n)e.description=n;var s=d(\"updated\",r);if(s)e.pubDate=new Date(s);return e}))}else{var n;r=h(\"channel\",e.children).children;t.type=e.name.substr(0,3);t.id=\"\";_(t,\"title\",\"title\",r);_(t,\"link\",\"link\",r);_(t,\"description\",\"description\",r);if(n=d(\"lastBuildDate\",r))t.updated=new Date(n);_(t,\"author\",\"managingEditor\",r,!0);t.items=f(\"item\",e.children).map((function(t){var e={},r=t.children;_(e,\"id\",\"guid\",r);_(e,\"title\",\"title\",r);_(e,\"link\",\"link\",r);_(e,\"description\",\"description\",r);var i=d(\"pubDate\",r);if(i)e.pubDate=new Date(i);return e}))}this.feed=t;this.handleCallback(e?null:Error(\"couldn't find root of feed\"))};return e}(a.default);e.FeedHandler=l;function f(t,e){return u.getElementsByTagName(t,e,!0)}function h(t,e){return u.getElementsByTagName(t,e,!0,1)[0]}function d(t,e,r){if(void 0===r)r=!1;return u.getText(u.getElementsByTagName(t,e,r,1)).trim()}function p(t,e){if(!e)return null;else return e.attribs[t]}function _(t,e,r,i,n){if(void 0===n)n=!1;var s=d(r,i,n);if(s)t[e]=s}function m(t){return\"rss\"===t||\"feed\"===t||\"rdf:RDF\"===t}var g={xmlMode:!0};e.parseFeed=function(t,e){if(void 0===e)e=g;var r=new l(e);new c.Parser(r,e).end(t);return r.feed}},function(t,e,r){\"use strict\";function i(t){for(var r in t)if(!e.hasOwnProperty(r))e[r]=t[r]}Object.defineProperty(e,\"__esModule\",{value:!0});i(r(33));i(r(37));i(r(38));i(r(19));i(r(39));i(r(40));i(r(6))},function(t,e,r){\"use strict\";var i=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,\"__esModule\",{value:!0});var n=i(r(7)),s=i(r(13)),o=i(r(8)),a=i(r(12));e.decodeXML=u(o.default);e.decodeHTMLStrict=u(n.default);function u(t){var e=Object.keys(t).join(\"|\"),r=l(t),i=new RegExp(\"&(?:\"+(e+=\"|#[xX][\\\\da-fA-F]+|#\\\\d+\")+\");\",\"g\");return function(t){return String(t).replace(i,r)}}var c=function(t,e){return t<e?1:-1};e.decodeHTML=function(){for(var t=Object.keys(s.default).sort(c),e=Object.keys(n.default).sort(c),r=0,i=0;r<e.length;r++)if(t[i]===e[r]){e[r]+=\";?\";i++}else e[r]+=\";\";var o=new RegExp(\"&(?:\"+e.join(\"|\")+\"|#[xX][\\\\da-fA-F]+;?|#\\\\d+;?)\",\"g\"),a=l(n.default);function u(t){if(\";\"!==t.substr(-1))t+=\";\";return a(t)}return function(t){return String(t).replace(o,u)}}();function l(t){return function(e){if(\"#\"===e.charAt(1))if(\"X\"===e.charAt(2)||\"x\"===e.charAt(2))return a.default(parseInt(e.substr(3),16));else return a.default(parseInt(e.substr(2),10));return t[e.slice(1,-1)]}}},function(t,e,r){\"use strict\";var i=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,\"__esModule\",{value:!0});var n=u(i(r(8)).default),s=c(n);e.encodeXML=p(n,s);var o=u(i(r(7)).default),a=c(o);e.encodeHTML=p(o,a);function u(t){return Object.keys(t).sort().reduce((function(e,r){e[t[r]]=\"&\"+r+\";\";return e}),{})}function c(t){var e=[],r=[];Object.keys(t).forEach((function(t){return 1===t.length?e.push(\"\\\\\"+t):r.push(t)}));r.unshift(\"[\"+e.join(\"\")+\"]\");return new RegExp(r.join(\"|\"),\"g\")}var l=/[^\\0-\\x7F]/g,f=/[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]/g;function h(t){return\"&#x\"+t.charCodeAt(0).toString(16).toUpperCase()+\";\"}function d(t,e){return\"&#x\"+(1024*(t.charCodeAt(0)-55296)+t.charCodeAt(1)-56320+65536).toString(16).toUpperCase()+\";\"}function p(t,e){return function(r){return r.replace(e,(function(e){return t[e]})).replace(f,d).replace(l,h)}}var _=c(n);e.escape=function(t){return t.replace(_,h).replace(f,d).replace(l,h)}},function(t,e,r){\"use strict\";Object.defineProperty(e,\"__esModule\",{value:!0});var i=r(6);e.filter=function(t,e,r,i){if(void 0===r)r=!0;if(void 0===i)i=1/0;if(!Array.isArray(e))e=[e];return n(t,e,r,i)};function n(t,e,r,s){for(var o=[],a=0;a<e.length;a++){var u=e[a];if(t(u)){o.push(u);if(--s<=0)break}if(r&&i.hasChildren(u)&&u.children.length>0){var c=n(t,u.children,r,s);o=o.concat(c);if((s-=c.length)<=0)break}}return o}e.find=n;e.findOneChild=function(t,e){for(var r=0;r<e.length;r++)if(t(e[r]))return e[r];return null};e.findOne=function t(e,r,n){if(void 0===n)n=!0;for(var s=null,o=0;o<r.length&&!s;o++){var a=r[o];if(i.isTag(a))if(e(a))s=a;else if(n&&a.children.length>0)s=t(e,a.children)}return s};e.existsOne=function t(e,r){for(var n=0;n<r.length;n++){var s=r[n];if(i.isTag(s)&&(e(s)||s.children.length>0&&t(e,s.children)))return!0}return!1};e.findAll=function(t,e){for(var r=[],n=e.slice();n.length;){var s=n.shift();if(s&&i.isTag(s)){if(s.children&&s.children.length>0)n.unshift.apply(n,s.children);if(t(s))r.push(s)}}return r}},function(t,e,r){\"use strict\";r.d(e,\"a\",(function(){return CommentSkeleton}));var i=r(4),n=r(0),s=r(5);class CommentSkeleton{constructor(t,e){this.parser=t;let r=this.parser.collectParts(e.element);r=this.parser.removeNestedParts(r);r=this.parser.encloseInlineParts(r,e.element);r=this.parser.filterParts(r);r.reverse();r=this.parser.replaceListsWithItems(r,e.element);this.id=n.a.comments.length;this.date=e.date||null;this.timestamp=e.timestampText;this.authorName=e.authorName;this.signatureElement=e.element;this.isOwn=this.authorName===n.a.g.CURRENT_USER_NAME;this.anchor=e.anchor;this.isUnsigned=e.isUnsigned;this.parts=r;this.elements=this.parts.map(t=>t.node);this.highlightables=this.elements.filter(t=>!/^(H[1-6]|STYLE|LINK)$/.test(t.tagName)&&!n.a.g.UNHIGHLIGHTABLE_ELEMENT_CLASSES.some(e=>t.classList.contains(e))&&!/float: *(?:left|right)|display: *none/.test(t.getAttribute(\"style\")));if(!this.highlightables.length)throw new i.a;this.setLevels();this.followsHeading=!1;if(this.parts[0].isHeading&&0!==this.level){this.parts.shift();this.elements.shift()}if(this.parts[0].isHeading){this.isOpeningSection=!0;const t=this.parts[0].node.tagName.match(/^H([1-6])$/);this.openingSectionOfLevel=t&&Number(t[1])}else this.isOpeningSection=!1;this.addAttributes()}addAttributes(){if(this.anchor&&!this.elements[0].getAttribute(\"id\"))this.elements[0].setAttribute(\"id\",this.anchor);this.highlightables[0].classList.add(\"cd-commentPart-first\");this.highlightables[this.highlightables.length-1].classList.add(\"cd-commentPart-last\");this.elements.forEach(t=>{t.classList.add(\"cd-commentPart\");t.setAttribute(\"data-comment-id\",String(this.id))})}setLevels(){const t={};t.top=this.parser.getLevelsUpTree(this.highlightables[0]);t.bottom=this.highlightables.length>1?this.parser.getLevelsUpTree(this.highlightables[this.highlightables.length-1]):t.top;this.level=Math.min(t.top.length,t.bottom.length);for(let e=0;e<this.level;e++){if(t.top[e])t.top[e].classList.add(\"cd-commentLevel\",\"cd-commentLevel-\".concat(e+1));if(t.bottom[e]&&t.bottom[e]!==t.top[e])t.bottom[e].classList.add(\"cd-commentLevel\",\"cd-commentLevel-\".concat(e+1))}}getSection(){if(void 0===this.cachedSection)this.cachedSection=n.a.sections.slice().reverse().find(t=>t.comments.includes(this))||null;return this.cachedSection}getChildren(){if(this.id===n.a.comments.length-1)return[];if(n.a.g.pageHasOutdents){const t=new s.b(this.elements[this.elements.length-1]);for(;t.nextNode()&&!t.currentNode.classList.contains(\"cd-commentPart\");)if(t.currentNode.classList.contains(\"outdent-template\"))return[n.a.comments[this.id+1]]}const t=[];n.a.comments.slice(this.id+1).some(e=>{if(e.getSection()===this.getSection()&&e.level>this.level){if(e.level===this.level+1||e.id===this.id+1)t.push(e)}else return!0});return t}}},function(t,e,r){\"use strict\";r.d(e,\"a\",(function(){return SectionSkeleton}));var i=r(4),n=r(0),s=r(5);class SectionSkeleton{constructor(t,e){this.parser=t;this.headlineElement=this.parser.context.getElementByClassName(e,\"mw-headline\");if(!this.headlineElement)throw new i.a;this.anchor=this.headlineElement.getAttribute(\"id\");this.parseHeadline();const r=e.tagName.match(/^H([1-6])$/);this.level=r&&Number(r[1]);const o=new s.c(n.a.g.rootElement,t=>![\"STYLE\",\"LINK\"].includes(t.tagName)&&!t.classList.contains(\"cd-sectionButtonContainer\"),!0,e);this.headingNestingLevel=0;for(;o.parentNode();)this.headingNestingLevel++;o.currentNode=e;const a=[e],u=new RegExp(\"^H[1-\".concat(this.level,\"]$\"));let c,l,f=!1;for(;o.nextSibling()&&!u.test(o.currentNode.tagName);){if(void 0===this.lastElementInFirstChunk&&/^H[2-6]$/.test(o.currentNode.tagName)){f=!0;this.lastElementInFirstChunk=a[a.length-1]}a.push(o.currentNode)}this.lastElementInFirstChunk=this.lastElementInFirstChunk||a[a.length-1];if(a[1]){o.currentNode=a[a.length-1];for(;o.lastChild(););const t=o.currentNode;o.currentNode=a[1];do{if(o.currentNode.classList.contains(\"cd-commentPart\"))c=o.currentNode}while(!c&&o.currentNode!==t&&o.nextNode());o.currentNode=t;do{if(o.currentNode.classList.contains(\"cd-commentPart\"))l=o.currentNode}while(!l&&o.currentNode!==a[1]&&o.previousNode())}if(c){const t=Number(c.getAttribute(\"data-comment-id\")),e=Number(l.getAttribute(\"data-comment-id\"));this.comments=n.a.comments.slice(t,e+1);if(f){const t=this.comments.findIndex(t=>!(this.parser.context.follows(this.lastElementInFirstChunk,t.elements[0])||this.lastElementInFirstChunk.contains(t.elements[0])));this.commentsInFirstChunk=this.comments.slice(0,t||0)}this.comments[0].followsHeading=!0}this.id=n.a.sections.length;this.comments=this.comments||[];this.commentsInFirstChunk=this.commentsInFirstChunk||this.comments;this.elements=a}parseHeadline(){const t=[\"mw-headline-number\",...n.a.config.foreignElementsInHeadlinesClasses],e=Array.from(this.headlineElement.childNodes).filter(e=>e.nodeType!==Node.ELEMENT_NODE||!t.some(t=>e.classList.contains(t)));this.headline=e.map(t=>t.textContent).join(\"\").trim()}getParent(t=!0){if(t&&this.level<=2)return null;else return n.a.sections.slice(0,this.id).reverse().find(t=>t.level<this.level)||null}getParentTree(){if(!this.cachedParentTree){this.cachedParentTree=[];let t=this;for(;t=t.getParent(!1);)this.cachedParentTree.push(t)}return this.cachedParentTree}}},function(t,e,r){\"use strict\";t.exports=function(t,e){var i=r(44),n=\"\",s=\"\",o=\"\";n=t.toString();var a=i(\"HTML_ENTITIES\",e);if(!1===a)return!1;delete a[\"&\"];a[\"&\"]=\"&amp;\";for(o in a){s=a[o];n=n.split(s).join(o)}return n=n.split(\"&#039;\").join(\"'\")}},function(t,e){function r(t,e,r,i,n,s,o){try{var a=t[s](o),u=a.value}catch(t){r(t);return}if(a.done)e(u);else Promise.resolve(u).then(i,n)}t.exports=function(t){return function(){var e=this,i=arguments;return new Promise((function(n,s){var o=t.apply(e,i);function a(t){r(o,n,s,a,u,\"next\",t)}function u(t){r(o,n,s,a,u,\"throw\",t)}a(void 0)}))}}},function(t,e,r){\"use strict\";e.a={LETTER_PATTERN:\"A-Za-z\\\\u00AA\\\\u00B5\\\\u00BA\\\\u00C0-\\\\u00D6\\\\u00D8-\\\\u00F6\\\\u00F8-\\\\u02C1\\\\u02C6-\\\\u02D1\\\\u02E0-\\\\u02E4\\\\u02EC\\\\u02EE\\\\u0370-\\\\u0374\\\\u0376\\\\u0377\\\\u037A-\\\\u037D\\\\u037F\\\\u0386\\\\u0388-\\\\u038A\\\\u038C\\\\u038E-\\\\u03A1\\\\u03A3-\\\\u03F5\\\\u03F7-\\\\u0481\\\\u048A-\\\\u052F\\\\u0531-\\\\u0556\\\\u0559\\\\u0561-\\\\u0587\\\\u05D0-\\\\u05EA\\\\u05F0-\\\\u05F2\\\\u0620-\\\\u064A\\\\u066E\\\\u066F\\\\u0671-\\\\u06D3\\\\u06D5\\\\u06E5\\\\u06E6\\\\u06EE\\\\u06EF\\\\u06FA-\\\\u06FC\\\\u06FF\\\\u0710\\\\u0712-\\\\u072F\\\\u074D-\\\\u07A5\\\\u07B1\\\\u07CA-\\\\u07EA\\\\u07F4\\\\u07F5\\\\u07FA\\\\u0800-\\\\u0815\\\\u081A\\\\u0824\\\\u0828\\\\u0840-\\\\u0858\\\\u08A0-\\\\u08B4\\\\u0904-\\\\u0939\\\\u093D\\\\u0950\\\\u0958-\\\\u0961\\\\u0971-\\\\u0980\\\\u0985-\\\\u098C\\\\u098F\\\\u0990\\\\u0993-\\\\u09A8\\\\u09AA-\\\\u09B0\\\\u09B2\\\\u09B6-\\\\u09B9\\\\u09BD\\\\u09CE\\\\u09DC\\\\u09DD\\\\u09DF-\\\\u09E1\\\\u09F0\\\\u09F1\\\\u0A05-\\\\u0A0A\\\\u0A0F\\\\u0A10\\\\u0A13-\\\\u0A28\\\\u0A2A-\\\\u0A30\\\\u0A32\\\\u0A33\\\\u0A35\\\\u0A36\\\\u0A38\\\\u0A39\\\\u0A59-\\\\u0A5C\\\\u0A5E\\\\u0A72-\\\\u0A74\\\\u0A85-\\\\u0A8D\\\\u0A8F-\\\\u0A91\\\\u0A93-\\\\u0AA8\\\\u0AAA-\\\\u0AB0\\\\u0AB2\\\\u0AB3\\\\u0AB5-\\\\u0AB9\\\\u0ABD\\\\u0AD0\\\\u0AE0\\\\u0AE1\\\\u0AF9\\\\u0B05-\\\\u0B0C\\\\u0B0F\\\\u0B10\\\\u0B13-\\\\u0B28\\\\u0B2A-\\\\u0B30\\\\u0B32\\\\u0B33\\\\u0B35-\\\\u0B39\\\\u0B3D\\\\u0B5C\\\\u0B5D\\\\u0B5F-\\\\u0B61\\\\u0B71\\\\u0B83\\\\u0B85-\\\\u0B8A\\\\u0B8E-\\\\u0B90\\\\u0B92-\\\\u0B95\\\\u0B99\\\\u0B9A\\\\u0B9C\\\\u0B9E\\\\u0B9F\\\\u0BA3\\\\u0BA4\\\\u0BA8-\\\\u0BAA\\\\u0BAE-\\\\u0BB9\\\\u0BD0\\\\u0C05-\\\\u0C0C\\\\u0C0E-\\\\u0C10\\\\u0C12-\\\\u0C28\\\\u0C2A-\\\\u0C39\\\\u0C3D\\\\u0C58-\\\\u0C5A\\\\u0C60\\\\u0C61\\\\u0C85-\\\\u0C8C\\\\u0C8E-\\\\u0C90\\\\u0C92-\\\\u0CA8\\\\u0CAA-\\\\u0CB3\\\\u0CB5-\\\\u0CB9\\\\u0CBD\\\\u0CDE\\\\u0CE0\\\\u0CE1\\\\u0CF1\\\\u0CF2\\\\u0D05-\\\\u0D0C\\\\u0D0E-\\\\u0D10\\\\u0D12-\\\\u0D3A\\\\u0D3D\\\\u0D4E\\\\u0D5F-\\\\u0D61\\\\u0D7A-\\\\u0D7F\\\\u0D85-\\\\u0D96\\\\u0D9A-\\\\u0DB1\\\\u0DB3-\\\\u0DBB\\\\u0DBD\\\\u0DC0-\\\\u0DC6\\\\u0E01-\\\\u0E30\\\\u0E32\\\\u0E33\\\\u0E40-\\\\u0E46\\\\u0E81\\\\u0E82\\\\u0E84\\\\u0E87\\\\u0E88\\\\u0E8A\\\\u0E8D\\\\u0E94-\\\\u0E97\\\\u0E99-\\\\u0E9F\\\\u0EA1-\\\\u0EA3\\\\u0EA5\\\\u0EA7\\\\u0EAA\\\\u0EAB\\\\u0EAD-\\\\u0EB0\\\\u0EB2\\\\u0EB3\\\\u0EBD\\\\u0EC0-\\\\u0EC4\\\\u0EC6\\\\u0EDC-\\\\u0EDF\\\\u0F00\\\\u0F40-\\\\u0F47\\\\u0F49-\\\\u0F6C\\\\u0F88-\\\\u0F8C\\\\u1000-\\\\u102A\\\\u103F\\\\u1050-\\\\u1055\\\\u105A-\\\\u105D\\\\u1061\\\\u1065\\\\u1066\\\\u106E-\\\\u1070\\\\u1075-\\\\u1081\\\\u108E\\\\u10A0-\\\\u10C5\\\\u10C7\\\\u10CD\\\\u10D0-\\\\u10FA\\\\u10FC-\\\\u1248\\\\u124A-\\\\u124D\\\\u1250-\\\\u1256\\\\u1258\\\\u125A-\\\\u125D\\\\u1260-\\\\u1288\\\\u128A-\\\\u128D\\\\u1290-\\\\u12B0\\\\u12B2-\\\\u12B5\\\\u12B8-\\\\u12BE\\\\u12C0\\\\u12C2-\\\\u12C5\\\\u12C8-\\\\u12D6\\\\u12D8-\\\\u1310\\\\u1312-\\\\u1315\\\\u1318-\\\\u135A\\\\u1380-\\\\u138F\\\\u13A0-\\\\u13F5\\\\u13F8-\\\\u13FD\\\\u1401-\\\\u166C\\\\u166F-\\\\u167F\\\\u1681-\\\\u169A\\\\u16A0-\\\\u16EA\\\\u16F1-\\\\u16F8\\\\u1700-\\\\u170C\\\\u170E-\\\\u1711\\\\u1720-\\\\u1731\\\\u1740-\\\\u1751\\\\u1760-\\\\u176C\\\\u176E-\\\\u1770\\\\u1780-\\\\u17B3\\\\u17D7\\\\u17DC\\\\u1820-\\\\u1877\\\\u1880-\\\\u18A8\\\\u18AA\\\\u18B0-\\\\u18F5\\\\u1900-\\\\u191E\\\\u1950-\\\\u196D\\\\u1970-\\\\u1974\\\\u1980-\\\\u19AB\\\\u19B0-\\\\u19C9\\\\u1A00-\\\\u1A16\\\\u1A20-\\\\u1A54\\\\u1AA7\\\\u1B05-\\\\u1B33\\\\u1B45-\\\\u1B4B\\\\u1B83-\\\\u1BA0\\\\u1BAE\\\\u1BAF\\\\u1BBA-\\\\u1BE5\\\\u1C00-\\\\u1C23\\\\u1C4D-\\\\u1C4F\\\\u1C5A-\\\\u1C7D\\\\u1CE9-\\\\u1CEC\\\\u1CEE-\\\\u1CF1\\\\u1CF5\\\\u1CF6\\\\u1D00-\\\\u1DBF\\\\u1E00-\\\\u1F15\\\\u1F18-\\\\u1F1D\\\\u1F20-\\\\u1F45\\\\u1F48-\\\\u1F4D\\\\u1F50-\\\\u1F57\\\\u1F59\\\\u1F5B\\\\u1F5D\\\\u1F5F-\\\\u1F7D\\\\u1F80-\\\\u1FB4\\\\u1FB6-\\\\u1FBC\\\\u1FBE\\\\u1FC2-\\\\u1FC4\\\\u1FC6-\\\\u1FCC\\\\u1FD0-\\\\u1FD3\\\\u1FD6-\\\\u1FDB\\\\u1FE0-\\\\u1FEC\\\\u1FF2-\\\\u1FF4\\\\u1FF6-\\\\u1FFC\\\\u2071\\\\u207F\\\\u2090-\\\\u209C\\\\u2102\\\\u2107\\\\u210A-\\\\u2113\\\\u2115\\\\u2119-\\\\u211D\\\\u2124\\\\u2126\\\\u2128\\\\u212A-\\\\u212D\\\\u212F-\\\\u2139\\\\u213C-\\\\u213F\\\\u2145-\\\\u2149\\\\u214E\\\\u2183\\\\u2184\\\\u2C00-\\\\u2C2E\\\\u2C30-\\\\u2C5E\\\\u2C60-\\\\u2CE4\\\\u2CEB-\\\\u2CEE\\\\u2CF2\\\\u2CF3\\\\u2D00-\\\\u2D25\\\\u2D27\\\\u2D2D\\\\u2D30-\\\\u2D67\\\\u2D6F\\\\u2D80-\\\\u2D96\\\\u2DA0-\\\\u2DA6\\\\u2DA8-\\\\u2DAE\\\\u2DB0-\\\\u2DB6\\\\u2DB8-\\\\u2DBE\\\\u2DC0-\\\\u2DC6\\\\u2DC8-\\\\u2DCE\\\\u2DD0-\\\\u2DD6\\\\u2DD8-\\\\u2DDE\\\\u2E2F\\\\u3005\\\\u3006\\\\u3031-\\\\u3035\\\\u303B\\\\u303C\\\\u3041-\\\\u3096\\\\u309D-\\\\u309F\\\\u30A1-\\\\u30FA\\\\u30FC-\\\\u30FF\\\\u3105-\\\\u312D\\\\u3131-\\\\u318E\\\\u31A0-\\\\u31BA\\\\u31F0-\\\\u31FF\\\\u3400-\\\\u4DB5\\\\u4E00-\\\\u9FD5\\\\uA000-\\\\uA48C\\\\uA4D0-\\\\uA4FD\\\\uA500-\\\\uA60C\\\\uA610-\\\\uA61F\\\\uA62A\\\\uA62B\\\\uA640-\\\\uA66E\\\\uA67F-\\\\uA69D\\\\uA6A0-\\\\uA6E5\\\\uA717-\\\\uA71F\\\\uA722-\\\\uA788\\\\uA78B-\\\\uA7AD\\\\uA7B0-\\\\uA7B7\\\\uA7F7-\\\\uA801\\\\uA803-\\\\uA805\\\\uA807-\\\\uA80A\\\\uA80C-\\\\uA822\\\\uA840-\\\\uA873\\\\uA882-\\\\uA8B3\\\\uA8F2-\\\\uA8F7\\\\uA8FB\\\\uA8FD\\\\uA90A-\\\\uA925\\\\uA930-\\\\uA946\\\\uA960-\\\\uA97C\\\\uA984-\\\\uA9B2\\\\uA9CF\\\\uA9E0-\\\\uA9E4\\\\uA9E6-\\\\uA9EF\\\\uA9FA-\\\\uA9FE\\\\uAA00-\\\\uAA28\\\\uAA40-\\\\uAA42\\\\uAA44-\\\\uAA4B\\\\uAA60-\\\\uAA76\\\\uAA7A\\\\uAA7E-\\\\uAAAF\\\\uAAB1\\\\uAAB5\\\\uAAB6\\\\uAAB9-\\\\uAABD\\\\uAAC0\\\\uAAC2\\\\uAADB-\\\\uAADD\\\\uAAE0-\\\\uAAEA\\\\uAAF2-\\\\uAAF4\\\\uAB01-\\\\uAB06\\\\uAB09-\\\\uAB0E\\\\uAB11-\\\\uAB16\\\\uAB20-\\\\uAB26\\\\uAB28-\\\\uAB2E\\\\uAB30-\\\\uAB5A\\\\uAB5C-\\\\uAB65\\\\uAB70-\\\\uABE2\\\\uAC00-\\\\uD7A3\\\\uD7B0-\\\\uD7C6\\\\uD7CB-\\\\uD7FB\\\\uF900-\\\\uFA6D\\\\uFA70-\\\\uFAD9\\\\uFB00-\\\\uFB06\\\\uFB13-\\\\uFB17\\\\uFB1D\\\\uFB1F-\\\\uFB28\\\\uFB2A-\\\\uFB36\\\\uFB38-\\\\uFB3C\\\\uFB3E\\\\uFB40\\\\uFB41\\\\uFB43\\\\uFB44\\\\uFB46-\\\\uFBB1\\\\uFBD3-\\\\uFD3D\\\\uFD50-\\\\uFD8F\\\\uFD92-\\\\uFDC7\\\\uFDF0-\\\\uFDFB\\\\uFE70-\\\\uFE74\\\\uFE76-\\\\uFEFC\\\\uFF21-\\\\uFF3A\\\\uFF41-\\\\uFF5A\\\\uFF66-\\\\uFFBE\\\\uFFC2-\\\\uFFC7\\\\uFFCA-\\\\uFFCF\\\\uFFD2-\\\\uFFD7\\\\uFFDA-\\\\uFFDC\",COMMENT_FOCUSED_COLOR:\"#eaf3ff\",COMMENT_TARGET_COLOR:\"#ffedb8\",COMMENT_NEW_COLOR:\"#e8ffd1\",COMMENT_OWN_COLOR:\"#f7ebff\",COMMENT_DELETED_COLOR:\"#fee7e6\",COMMENT_UNDERLAY_SIDE_MARGIN:5,HIGHLIGHT_NEW_COMMENTS_INTERVAL:15,UPDATE_CHECK_INTERVAL:15,BACKGROUND_UPDATE_CHECK_INTERVAL:60,SECONDS_IN_A_DAY:86400,MILLISECONDS_IN_A_MINUTE:6e4,POPULAR_NOT_INLINE_ELEMENTS:[\"BLOCKQUOTE\",\"DD\",\"DIV\",\"DL\",\"FORM\",\"H1\",\"H2\",\"H3\",\"H4\",\"H5\",\"H6\",\"HR\",\"INPUT\",\"LI\",\"LINK\",\"OL\",\"P\",\"PRE\",\"STYLE\",\"TABLE\",\"TBODY\",\"TR\",\"TH\",\"TD\",\"UL\"],POPULAR_INLINE_ELEMENTS:[\"A\",\"ABBR\",\"B\",\"BIG\",\"BR\",\"CENTER\",\"CITE\",\"CODE\",\"DEL\",\"EM\",\"FONT\",\"I\",\"IMG\",\"INS\",\"KBD\",\"Q\",\"S\",\"SAMP\",\"SMALL\",\"SPAN\",\"STRIKE\",\"STRONG\",\"SUB\",\"SUP\",\"TT\",\"U\",\"VAR\"],UNHIGHLIGHTABLE_ELEMENT_CLASSES:[\"mw-empty-elt\",\"tleft\",\"tright\",\"floatleft\",\"floatright\"],BAD_COMMENT_BEGINNINGS:[/^<!--[^]*?--> *\\n+/,/^(?:----+|<hr>) *\\n+/,/^\\{\\|.*?\\|\\} *\\n+(?=[*:#])/],FLOATING_ELEMENT_SELECTORS:[\".cd-floating\",\".tright\",\".floatright\",\".tleft\",\".floatleft\",'*[style*=\"float:right\"]','*[style*=\"float: right\"]','*[style*=\"float:left\"]','*[style*=\"float: left\"]'],SIGN_CODE:\"~~\".concat(\"~~\")}},function(t,e,r){\"use strict\";e.a={init(){this.timerTotal={};this.timerStartTimestamps={};this.timerRunCount={};this.timerAllRunsTotal={};this.initCounters();this.array=[];this.object={}},initCounters(){this.counters=\"undefined\"==typeof Proxy?{}:new Proxy({},{get:(t,e)=>e in t?t[e]:0})},startTimer(t){if(void 0===this.timerTotal[t])this.timerTotal[t]=0;this.timerStartTimestamps[t]=Date.now()},stopTimer(t){if(void 0===this.timerStartTimestamps[t])return;const e=Date.now()-this.timerStartTimestamps[t];this.timerTotal[t]+=e;delete this.timerStartTimestamps[t];if(void 0===this.timerAllRunsTotal[t]){this.timerAllRunsTotal[t]=0;this.timerRunCount[t]=0}this.timerAllRunsTotal[t]+=e;this.timerRunCount[t]++},resetTimer(t){if(void 0!==this.timerStartTimestamps[t])this.stopTimer(t);delete this.timerTotal[t]},fullResetTimer(t){this.resetTimer(t);delete this.timerAllRunsTotal[t];delete this.timerRunCount[t]},logAndResetTimer(t){if(void 0!==this.timerStartTimestamps[t])this.stopTimer(t);if(void 0!==this.timerTotal[t]){console.debug(\"\".concat(t,\": \").concat(this.timerTotal[t]));this.resetTimer(t)}},logAndResetEverything(t){const e=Object.keys(this.timerTotal);if(t)e.sort();e.forEach(t=>{this.logAndResetTimer(t)});const r=Object.keys(this.counters);if(t)r.sort();r.forEach(t=>{console.debug(\"counter \".concat(t,\": \").concat(this.counters[t]))});this.initCounters();if(this.array.length){console.debug(\"array: \",this.array);this.array=[]}if(Object.keys(this.object).length){console.debug(\"object: \",this.object);this.object={}}},averageTimerTime(t){if(void 0===this.timerAllRunsTotal[t]){console.error(\"No data for timer \".concat(t));return}const e=this.timerAllRunsTotal[t]/this.timerRunCount[t];console.debug(\"\".concat(t,\": \").concat(e.toFixed(1),\" average for \").concat(this.timerRunCount[t],\" runs\"))},incrementCounter(t){this.counters[t]++}}},function(t,e,r){\"use strict\";r.d(e,\"a\",(function(){return Parser}));var i=r(0),n=r(5),s=r(1),o=r(2);let a,u,c,l;function f(t){const e=t.getAttribute(\"href\");let r;if(e){const t=function(t){if(\"undefined\"==typeof mw||\"/wiki/$1\"===mw.config.get(\"wgArticlePath\")&&\"/w/index.php\"===mw.config.get(\"wgScript\")){let e=t.replace(/^(?:https?:)?\\/\\/[^/]+/,\"\").replace(/^\\/wiki\\//,\"\").replace(/^\\/w\\/index.php\\?title=/,\"\").replace(/&action=edit.*/,\"\").replace(/#.*/,\"\").replace(/_/g,\" \");try{e=decodeURIComponent(e)}catch(t){return null}return e}else{let e;try{e=new mw.Uri(t)}catch(t){return null}const r=e.path.match(i.a.g.ARTICLE_PATH_REGEXP);if(r)try{return decodeURIComponent(r[1])}catch(t){return null}return e.query.title||null}}(e);if(!t)return null;const n=t.match(i.a.g.USER_NAMESPACES_REGEXP);if(n)r=n[1];else if(t.startsWith(i.a.g.CONTRIBS_PAGE+\"/\")){r=t.replace(i.a.g.CONTRIBS_PAGE_LINK_REGEXP,\"\");if(i.a.g.IS_IPv6_ADDRESS(r))r=r.toUpperCase()}if(r)r=Object(s.b)(Object(s.i)(r.replace(/\\/.*/,\"\"))).trim()}else if(t.classList.contains(\"mw-selflink\")&&3===i.a.g.CURRENT_NAMESPACE_NUMBER)r=i.a.g.CURRENT_PAGE_TITLE;else return null;return r}function h(t){if(\"TD\"!==t.tagName)return!1;let e;for(let r=t;!e&&r!==i.a.g.rootElement;r=r.parentNode)if(\"TABLE\"===r.tagName)e=r;return!e||e.getElementsByClassName(\"cd-signature\",2).length>1}class Parser{constructor(t){this.context=t;if(!a){a=[\"cd-commentPart\",...i.a.config.closedDiscussionClasses];if(i.a.g.pageHasOutdents)a.push(\"outdent-template\");u=new RegExp(i.a.g.TIMEZONE_REGEXP.source+\"\\\\s*$\");if(i.a.config.signatureEndingRegexp)c=new RegExp(i.a.config.signatureEndingRegexp.source+\"$\")}}createComment(t){return new this.context.CommentClass(this,t)}createSection(t,e){return new this.context.SectionClass(this,t,e)}findTimestamps(){l=[...Array.from(i.a.g.rootElement.getElementsByTagName(\"blockquote\")),...Object(s.c)(i.a.config.elementsToExcludeClasses.map(t=>Array.from(i.a.g.rootElement.getElementsByClassName(t))))];return this.context.getAllTextNodes().map(t=>{const e=t.textContent,{date:r,match:i}=Object(o.b)(e)||{};if(r&&!l.some(e=>e.contains(t)))return{node:t,date:r,match:i}}).filter(s.a).map(t=>{const{node:e,match:r,date:i}=t,n=this.context.document.createElement(\"span\");n.classList.add(\"cd-timestamp\");const s=this.context.document.createTextNode(r[2]);n.appendChild(s);const o=e.textContent.slice(r.index+r[0].length);let a;if(o)a=this.context.document.createTextNode(o);e.textContent=e.textContent.slice(0,r.index+r[1].length);e.parentNode.insertBefore(n,e.nextSibling);if(a)e.parentNode.insertBefore(a,n.nextSibling);return{element:n,date:i}})}findSignatures(t){const e=t.map(t=>{const e=t.date,r=t.element,a=t.element.textContent;let u,c;for(let e=t.element;!c;e=e.parentNode)if(Object(s.f)(e)){if(e.classList.contains(i.a.config.unsignedClass))u=e}else c=e;const l=Boolean(u);if(c){const e=Array.from(c[this.context.childElementsProperty]),r=new n.b(t.element);for(;r.nextNode()&&c.contains(r.currentNode)&&(!e.includes(r.currentNode)||Object(s.f)(r.currentNode));)if(r.currentNode.classList.contains(\"cd-timestamp\"))return}const h=u||t.element,d=new n.a(h);let p,_,m=0;const g=[];if(u)_=h;else{g.push(h);d.previousSibling()}do{const t=d.currentNode;m+=t.textContent.length;if(t.nodeType===Node.ELEMENT_NODE){if(t.classList.contains(\"cd-timestamp\"))break;let e=!1;if(\"A\"===t.tagName){const r=f(t);if(r){if(!p)p=r;if(p===r)e=!0}}else Array.from(t.getElementsByTagName(\"a\")).reverse().some(t=>{const r=f(t);if(r){if(!p)p=r;if(p===r){e=!0;return!0}}});if(e)_=t}g.push(t)}while(d.previousSibling()&&m<i.a.config.signatureScanLimit);const b=g.indexOf(_);g.splice(-1===b?1:b+1);const E=Object(o.a)(t.date,p,!0);Object(o.c)(E);const y=h.parentNode,v=h.nextSibling,A=this.context.document.createElement(\"span\");A.classList.add(\"cd-signature\");g.reverse().forEach(A.appendChild.bind(A));y.insertBefore(A,v);if(p)return{element:A,timestampElement:r,timestampText:a,date:e,authorName:p,anchor:E,isUnsigned:l}}).filter(s.a);if(i.a.config.unsignedClass)Array.from(i.a.g.rootElement.getElementsByClassName(i.a.config.unsignedClass)).forEach(t=>{if(!this.context.getElementByClassName(t,\"cd-timestamp\"))Array.from(t.getElementsByTagName(\"a\")).some(r=>{const i=f(r);if(i){t.classList.add(\"cd-signature\");const r=!0;e.push({element:t,authorName:i,isUnsigned:r});return!0}})});e.sort((t,e)=>this.context.follows(t.element,e.element)?1:-1);return e}collectParts(t){const e=new n.a(t);let r,o=[];for(;!r;){for(;!e.currentNode.nextSibling&&e.parentNode(););if(!e.nextSibling())break;if(!Object(s.f)(e.currentNode,!0))r=e.currentNode}if(r&&t.parentNode.contains(r)||t.parentNode.getElementsByClassName(\"cd-signature\",2).length>1||h(t.parentNode)){e.currentNode=t;for(;e.nextSibling()&&Object(s.f)(e.currentNode,!0);)o.push({node:e.currentNode,isTextNode:e.currentNode.nodeType===Node.TEXT_NODE,isHeading:!1,hasCurrentSignature:!1,hasForeignComponents:!1,lastStep:\"start\"});o.reverse();e.currentNode=t}else e.currentNode=t.parentNode;o.push({node:e.currentNode,isTextNode:!1,isHeading:!1,hasCurrentSignature:!0,hasForeignComponents:!1,lastStep:\"start\"});for(let n=0;n<500;n++){var f;let n;const m=o[o.length-1];if(!m.isTextNode&&!m.hasCurrentSignature){var d;const t=m.node.textContent;if(!Object(s.f)(m.node,!0)&&(u.test(t)||(null===(d=c)||void 0===d?void 0:d.test(t)))&&!l.some(t=>t.contains(m.node))){m.hasForeignComponents=!0;break}}if(!m.hasCurrentSignature&&m.hasForeignComponents){let t,r=!1;for(;(t=e.currentNode)&&e.lastChild();){if(Object(s.f)(e.currentNode,!0)){e.currentNode=t;break}r=!0}if(r)n=\"dive\";else break}else if(e.previousSibling())n=\"back\";else{if(!e.parentNode())break;n=\"up\"}const g=e.currentNode,b=g.nodeType===Node.TEXT_NODE;if(\"back\"===n&&[\"OL\",\"UL\"].includes(m.node.tagName)&&!([\"DL\",\"OL\",\"UL\"].includes(g.tagName)||b&&g.previousSibling&&[\"DL\",\"OL\",\"UL\"].includes(g.previousSibling.tagName))&&(null===(f=m.node[this.context.childElementsProperty][0])||void 0===f?void 0:f.contains(t)))break;let E=null,y=null,v=null;if(!b){var p,_;if(g===e.root||a.some(t=>g.classList.contains(t))||\"toc\"===g.getAttribute(\"id\")||h(g)||\"HR\"===g.tagName&&g.previousElementSibling&&this.context.getElementByClassName(g.previousElementSibling,\"cd-signature\")||i.a.g.pageHasOutdents&&this.context.getElementByClassName(g,\"outdent-template\")||(null===(p=(_=i.a.config).checkForCustomForeignComponents)||void 0===p?void 0:p.call(_,g,this.context)))break;E=/^H[1-6]$/.test(g.tagName);y=g.contains(t);v=g.getElementsByClassName(\"cd-signature\",Number(y)+1).length-Number(y)>0||r&&g.contains(r)}o.push({node:g,isTextNode:b,isHeading:E,hasCurrentSignature:y,hasForeignComponents:v,lastStep:n});if(E)break}return o}removeNestedParts(t){for(let e=t.length-1;e>=0;e--){const r=t[e];if(\"up\"===r.lastStep&&!r.hasForeignComponents){let r=0;for(let i=e-1;i>0;i--)if(\"dive\"===t[i].lastStep){r=i;break}t.splice(r,e-r);e=r}}return t}encloseInlineParts(t,e){const r=[];let i=null,n=!1;for(let e=0;e<=t.length;e++){const o=t[e];if(o&&(null===i||[\"back\",\"start\"].includes(o.lastStep))&&!o.hasForeignComponents&&!o.isHeading){if(null===i)if(Object(s.f)(o.node.parentNode)){for(let r=e+1;r<t.length;r++)if(\"up\"!==t[r].lastStep);else e=r-1;break}else i=e;if(!n&&(o.isTextNode&&o.node.textContent.trim()||Object(s.f)(o.node)))n=!0}else if(null!==i){if(n){const t=e-1;r.push({start:i,end:t})}i=null;n=!1}}for(let i=r.length-1;i>=0;i--){const n=r[i],s=this.context.document.createElement(\"div\"),o=t[n.start].node.nextSibling,a=t[n.start].node.parentNode;for(let e=n.end;e>=n.start;e--)s.appendChild(t[e].node);a.insertBefore(s,o);const u={node:s,isTextNode:!1,isHeading:!1,hasCurrentSignature:s.contains(e),hasForeignComponents:!1,lastStep:\"replaced\"};t.splice(n.start,n.end-n.start+1,u)}return t}filterParts(t){for(let e=(t=t.filter(t=>!t.hasForeignComponents&&!t.isTextNode)).length-1;e>0;e--){const r=t[e];if(\"P\"===r.node.tagName&&!r.node.textContent.trim())t.splice(e,1);else break}return t}replaceListsWithItems(t,e){const r=t[t.length-1];for(let i=t.length-1;i>=0;i--){const n=t[i];if([\"UL\",\"DL\",\"OL\",\"LI\",\"DD\"].includes(n.node.tagName)&&(\"up\"===n.lastStep&&(!t[i-1]||\"back\"!==t[i-1].lastStep)||(\"DD\"===r.node.tagName||\"DD\"===r.node.parentNode.tagName||\"DL\"===r.node.tagName)&&!t.slice(i+1).some(t=>\"P\"===t.node.tagName))){const r=n.node.textContent.replace(/\\s+/g,\"\");let s,o=[n.node];do{s=o.reduce((t,e)=>t.concat(Array.from(e[this.context.childElementsProperty])),[])}while(s.length&&s.every(t=>[\"UL\",\"DL\",\"OL\",\"LI\",\"DD\"].includes(t.tagName))&&s.map(t=>t.textContent).join(\"\").replace(/\\s+/g,\"\")===r&&(o=s));if(o.length>1){const r=o.map(t=>({node:t,isTextNode:!1,hasCurrentSignature:t.contains(e),hasForeignComponents:!1,lastStep:\"replaced\"}));t.splice(i,1,...r)}else if(o[0]!==n.node)Object.assign(n,{node:o[0],lastStep:\"replaced\"})}}return t}getLevelsUpTree(t){const e=[],r=new n.b(t);for(;r.parentNode();){const t=r.currentNode;if([\"UL\",\"DL\",\"OL\"].includes(t.tagName))if(t.classList.contains(\"cd-commentLevel\")){const r=t.getAttribute(\"class\").match(/cd-commentLevel-(\\d+)/);if(r)e.unshift(...Array(Number(r[1])));return e}else e.unshift(t)}return e}findHeadings(){const t=[...i.a.g.rootElement.getElementsByTagName(\"h1\"),...i.a.g.rootElement.getElementsByTagName(\"h2\"),...i.a.g.rootElement.getElementsByTagName(\"h3\"),...i.a.g.rootElement.getElementsByTagName(\"h4\"),...i.a.g.rootElement.getElementsByTagName(\"h5\"),...i.a.g.rootElement.getElementsByTagName(\"h6\")];t.sort((t,e)=>this.context.follows(t,e)?1:-1);return t}}},function(t,e,r){\"use strict\";r.d(e,\"a\",(function(){return u}));var i=r(3),cd=r(0),n=r(22),s=r.n(n);r(1);r(2);function o(t){if(-1===t.indexOf(\"&\"))return t;else{let e=t;if(-1!==e.indexOf(\"&#38;amp;\"))e=e.replace(/&#38;amp;/g,\"&amp;amp;\");if(-1!==e.indexOf(\"&#\"))e=e.replace(/&#(\\d+);/g,(t,e)=>String.fromCharCode(e));if(-1!==e.indexOf(\"&\"))e=s()(e);return e}}self.Node={TEXT_NODE:3,ELEMENT_NODE:1};function a(t,e,r){if(r&&e(t))return!0;for(let r=t.firstChild;r;r=r.nextSibling)if(a(r,e,!0))return!0}function u(){let t=[];a(cd.a.g.rootElement,e=>{if(e.nodeType===Node.TEXT_NODE)t.push(e)});return t}const c=Object(i.parseDOM)(\"<a>a</a>\"),l=c[0].constructor,f=c[0].childNodes[0].constructor,h=Object.getPrototypeOf(f);Object.defineProperty(l.prototype,\"childElements\",{get:function(){return this.childNodes.filter(t=>t.nodeType===Node.ELEMENT_NODE)}});Object.defineProperty(l.prototype,\"previousElementSibling\",{get:function(){for(let t=this.previousSibling;t;t=t.previousSibling)if(t.nodeType===Node.ELEMENT_NODE)return t;return null}});Object.defineProperty(l.prototype,\"nextElementSibling\",{get:function(){for(let t=this.nextSibling;t;t=t.nextSibling)if(t.nodeType===Node.ELEMENT_NODE)return t;return null}});Object.defineProperty(l.prototype,\"firstElementChild\",{get:function(){let t;for(t=this.firstChild;t&&t.nodeType!==Node.ELEMENT_NODE;t=t.nextSibling);return t||null}});Object.defineProperty(l.prototype,\"lastElementChild\",{get:function(){let t;for(t=this.lastChild;t&&t.nodeType!==Node.ELEMENT_NODE;t=t.previousSibling);return t||null}});Object.defineProperty(l.prototype,\"textContent\",{get:function(){let t=\"\";this.childNodes.forEach(e=>{t+=e.textContent});return t}});Object.defineProperty(l.prototype,\"innerHTML\",{get:function(){return i.DomUtils.getInnerHTML(this)}});Object.defineProperty(l.prototype,\"outerHTML\",{get:function(){return i.DomUtils.getOuterHTML(this)}});l.prototype.getAttribute=function(t){let e=this.attribs[t];if(e&&\"string\"==typeof e&&-1!==e.indexOf(\"&\"))e=e.replace(/&amp;/g,\"&\").replace(/&quot;/g,'\"');return e};l.prototype.setAttribute=function(t,e){if(e&&\"string\"==typeof e){if(-1!==e.indexOf(\"&\"))e=e.replace(/&/g,\"&amp;\");if(-1!==e.indexOf('\"'))e=e.replace(/\"/g,\"&quot;\")}this.attribs[t]=e||\"\"};l.prototype.removeAttribute=function(t){delete this.attribs[t]};l.prototype.appendChild=function(t){if(t.parentNode)t.remove();i.DomUtils.appendChild(this,t)};l.prototype.insertBefore=function(t,e){if(e){if(t.parentNode)t.remove();i.DomUtils.prepend(e,t)}else this.appendChild(t)};l.prototype.removeChild=function(t){if(t.parentNode===this)i.DomUtils.removeElement(t)};l.prototype.contains=function(t){if(t===this)return!0;if(!this.childNodes.length)return!1;for(let e=t;e;e=e.parentNode)if(e===this)return!0;return!1};l.prototype.follows=function(t){if(this.startIndex&&t.startIndex)return this.startIndex>t.startIndex;if(this===t)return!1;const e=[],r=[];let i,n,s;for(let r=this;r;r=r.parentNode){if(r===t)return!0;e.unshift(r)}for(let o=t;o;o=o.parentNode){r.unshift(o);if(e.includes(o)){i=o;n=e[e.indexOf(o)+1];s=r[1];break}}return!i||i.childNodes.indexOf(n)>i.childNodes.indexOf(s)};Object.defineProperty(l.prototype,\"tagName\",{get:function(){return this.name.toUpperCase()}});Object.defineProperty(l.prototype,\"classList\",{get:function(){if(this._classList)return this._classList;else{this._classList={list:[],isMovedFromClassAttr:!1,moveFromClassAttr(t){this.list=(t||\"\").split(\" \");this.isMovedFromClassAttr=!0},add:(...t)=>{t.forEach(t=>{let e=this.getAttribute(\"class\")||\"\";if(e)e+=\" \";e+=t;this.setAttribute(\"class\",e);if(this._classList.isMovedFromClassAttr)this._classList.list.push(t);else this._classList.moveFromClassAttr(e)})},contains:t=>{const e=this.getAttribute(\"class\");if(!e)return!1;if(!this._classList.isMovedFromClassAttr)this._classList.moveFromClassAttr(e);return Boolean(this._classList.list.length)&&-1!==this._classList.list.indexOf(t)}};return this._classList}}});l.prototype.getElementsByClassName=function(t,e,r){let i=[];a(this,n=>{if(n.nodeType===Node.ELEMENT_NODE)if(n.nodeType===Node.ELEMENT_NODE&&n.classList.contains(t,r)){i.push(n);if(e&&i.length===e)return!0}});return i};l.prototype.getElementsByTagName=function(t){return i.DomUtils.getElementsByTagName(t,this)};Object.defineProperty(f.prototype,\"textContent\",{get:function(){return o(this.data)},set:function(t){this.data=t}});h.prototype.remove=function(){i.DomUtils.removeElement(this);this.prev=null;this.next=null};class Document extends l{constructor(t){super(\"body\",{});for(const e of t)this.appendChild(e)}createElement(t){return new l(t,{})}createTextNode(t){return new f(\"text\",t)}}Document.prototype.getElementsByClassName=l.prototype.getElementsByClassName;self.Document=Document},function(t,e,r){\"use strict\";r.r(e);r(29)},function(module,__webpack_exports__,__webpack_require__){\"use strict\";var _CdError__WEBPACK_IMPORTED_MODULE_0__=__webpack_require__(4),_CommentSkeleton__WEBPACK_IMPORTED_MODULE_1__=__webpack_require__(20),_Parser__WEBPACK_IMPORTED_MODULE_2__=__webpack_require__(26),_SectionSkeleton__WEBPACK_IMPORTED_MODULE_3__=__webpack_require__(21),_cd__WEBPACK_IMPORTED_MODULE_4__=__webpack_require__(0),_debug__WEBPACK_IMPORTED_MODULE_5__=__webpack_require__(25),_staticGlobals__WEBPACK_IMPORTED_MODULE_6__=__webpack_require__(24),_htmlparser2Extended__WEBPACK_IMPORTED_MODULE_7__=__webpack_require__(27),_htmlparser2Extended__WEBPACK_IMPORTED_MODULE_8__=__webpack_require__(3),_htmlparser2Extended__WEBPACK_IMPORTED_MODULE_8___default=__webpack_require__.n(_htmlparser2Extended__WEBPACK_IMPORTED_MODULE_8__),_timestamp__WEBPACK_IMPORTED_MODULE_9__=__webpack_require__(2);let firstRun=!0;const context={CommentClass:_CommentSkeleton__WEBPACK_IMPORTED_MODULE_1__.a,SectionClass:_SectionSkeleton__WEBPACK_IMPORTED_MODULE_3__.a,childElementsProperty:\"childElements\",follows:(t,e)=>t.follows(e),getAllTextNodes:_htmlparser2Extended__WEBPACK_IMPORTED_MODULE_7__.a,getElementByClassName:(t,e)=>t.getElementsByClassName(e,1)[0]||null};let alarmTimeout;self.cd=_cd__WEBPACK_IMPORTED_MODULE_4__.a;_cd__WEBPACK_IMPORTED_MODULE_4__.a.g=_staticGlobals__WEBPACK_IMPORTED_MODULE_6__.a;_cd__WEBPACK_IMPORTED_MODULE_4__.a.debug=_debug__WEBPACK_IMPORTED_MODULE_5__.a;_cd__WEBPACK_IMPORTED_MODULE_4__.a.debug.init();function setAlarm(t){clearTimeout(alarmTimeout);alarmTimeout=setTimeout(()=>{postMessage({type:\"wakeUp\"})},t)}function parse(){_cd__WEBPACK_IMPORTED_MODULE_4__.a.comments=[];_cd__WEBPACK_IMPORTED_MODULE_4__.a.sections=[];Object(_timestamp__WEBPACK_IMPORTED_MODULE_9__.d)();_cd__WEBPACK_IMPORTED_MODULE_4__.a.debug.startTimer(\"worker: parse comments\");const t=new _Parser__WEBPACK_IMPORTED_MODULE_2__.a(context),e=t.findTimestamps();t.findSignatures(e).forEach(e=>{try{const r=t.createComment(e);if(void 0!==r.id)_cd__WEBPACK_IMPORTED_MODULE_4__.a.comments.push(r)}catch(t){if(!(t instanceof _CdError__WEBPACK_IMPORTED_MODULE_0__.a))console.error(t)}});_cd__WEBPACK_IMPORTED_MODULE_4__.a.debug.stopTimer(\"worker: parse comments\");_cd__WEBPACK_IMPORTED_MODULE_4__.a.debug.startTimer(\"worker: parse sections\");t.findHeadings().forEach(e=>{try{const r=t.createSection(e);if(void 0!==r.id)_cd__WEBPACK_IMPORTED_MODULE_4__.a.sections.push(r)}catch(t){if(!(t instanceof _CdError__WEBPACK_IMPORTED_MODULE_0__.a))console.error(t)}});_cd__WEBPACK_IMPORTED_MODULE_4__.a.debug.stopTimer(\"worker: parse sections\");_cd__WEBPACK_IMPORTED_MODULE_4__.a.debug.startTimer(\"worker: prepare comments and sections\");_cd__WEBPACK_IMPORTED_MODULE_4__.a.sections.forEach(t=>{var e;t.parentTree=t.getParentTree().map(t=>t.headline);t.firstCommentAnchor=null===(e=t.comments[0])||void 0===e?void 0:e.anchor});let r=[\"cachedSection\",\"elements\",\"highlightables\",\"parent\",\"parser\",\"parts\",\"signatureElement\"],i=[\"cachedParentTree\",\"commentsInFirstChunk\",\"elements\",\"headlineElement\",\"lastElementInFirstChunk\",\"parser\"];const n=(t,e)=>{const r=Object.assign({},t);Object.keys(r).forEach(t=>{if(e.includes(t))delete r[t]});return r};_cd__WEBPACK_IMPORTED_MODULE_4__.a.sections=_cd__WEBPACK_IMPORTED_MODULE_4__.a.sections.map(t=>n(t,i));_cd__WEBPACK_IMPORTED_MODULE_4__.a.comments.forEach(t=>{t.getChildren().forEach(e=>{e.parent=t});const e=t.getSection();t.section=e||null;if(t.parent){t.parentAuthorName=t.parent.authorName;t.parentAnchor=t.parent.anchor;t.toMe=t.parent.isOwn}t.elements[0].removeAttribute(\"id\");t.hiddenElementData=[];t.elementHtmls=t.elements.map(e=>{e.removeAttribute(\"data-comment-id\");if(/^H[1-6]$/.test(e.tagName)){const t=e.getElementsByClassName(\"mw-headline\")[0];if(t){var r;null===(r=t.getElementsByClassName(\"mw-headline-number\")[0])||void 0===r||r.remove();Array.from(e.childNodes).forEach(t=>{t.remove()});Array.from(t.childNodes).forEach(e.appendChild.bind(e))}}[...e.getElementsByClassName(\"autonumber\"),...e.getElementsByClassName(\"reference\"),...e.getElementsByClassName(\"references\"),...e.getElementsByTagName(\"style\"),...e.getElementsByTagName(\"link\")].forEach(e=>{let r;if(e.classList.contains(\"reference\"))r=\"reference\";else if(e.classList.contains(\"references\"))r=\"references\";else if(e.classList.contains(\"autonumber\"))r=\"autonumber\";else r=\"templateStyles\";const i=t.hiddenElementData.push({type:r,tagName:e.tagName,html:e.outerHTML}),n=context.document.createTextNode(\"\\x01\".concat(i,\"_\").concat(r,\"\\x02\"));e.parentNode.insertBefore(n,e);e.remove()});return e.outerHTML});t.innerHtml=\"\";t.textInnerHtml=\"\";t.headingInnerHtml=\"\";t.elements.forEach(e=>{const r=e.innerHTML;t.innerHtml+=r+\"\\n\";if(/^H[1-6]$/.test(e.tagName))t.headingInnerHtml+=r;else t.textInnerHtml+=r+\"\\n\"});t.innerHtml=t.innerHtml.trim();t.textInnerHtml=t.textInnerHtml.trim();t.headingInnerHtml=t.headingInnerHtml.trim();t.signatureElement.remove();t.text=t.elements.map(t=>t.textContent).join(\"\\n\");t.elementTagNames=t.elements.map(t=>t.tagName)});_cd__WEBPACK_IMPORTED_MODULE_4__.a.sections.forEach(t=>{delete t.comments});_cd__WEBPACK_IMPORTED_MODULE_4__.a.comments=_cd__WEBPACK_IMPORTED_MODULE_4__.a.comments.map(t=>n(t,r));_cd__WEBPACK_IMPORTED_MODULE_4__.a.comments.forEach((t,e)=>{t.previousComments=_cd__WEBPACK_IMPORTED_MODULE_4__.a.comments.slice(Math.max(0,e-2),e).reverse()});_cd__WEBPACK_IMPORTED_MODULE_4__.a.debug.stopTimer(\"worker: prepare comments and sections\")}function restoreFunc(code){if(code){if(!/^ *function\\b/.test(code)&&!/^.+=>/.test(code))code=\"function \"+code;if(/^ *function *\\(/.test(code))code=\"(\"+code+\")\"}return eval(code)}function onMessageFromWindow(t){const e=t.data;if(firstRun){console.debug(\"Convenient Discussions' web worker has been successfully loaded. Click the link with the file name and line number to open the source code in your debug tool.\");firstRun=!1}if(\"setAlarm\"===e.type)setAlarm(e.interval);if(\"removeAlarm\"===e.type)clearTimeout(alarmTimeout);if(\"parse\"===e.type){_cd__WEBPACK_IMPORTED_MODULE_4__.a.debug.startTimer(\"worker\");Object.assign(_cd__WEBPACK_IMPORTED_MODULE_4__.a.g,e.g);_cd__WEBPACK_IMPORTED_MODULE_4__.a.config=e.config;_cd__WEBPACK_IMPORTED_MODULE_4__.a.config.checkForCustomForeignComponents=restoreFunc(_cd__WEBPACK_IMPORTED_MODULE_4__.a.config.checkForCustomForeignComponents);_cd__WEBPACK_IMPORTED_MODULE_4__.a.g.TIMESTAMP_PARSER=restoreFunc(_cd__WEBPACK_IMPORTED_MODULE_4__.a.g.TIMESTAMP_PARSER);_cd__WEBPACK_IMPORTED_MODULE_4__.a.g.IS_IPv6_ADDRESS=restoreFunc(_cd__WEBPACK_IMPORTED_MODULE_4__.a.g.IS_IPv6_ADDRESS);const t=Object(_htmlparser2Extended__WEBPACK_IMPORTED_MODULE_8__.parseDOM)(e.text,{withStartIndices:!0,withEndIndices:!0});context.document=new Document(t);_cd__WEBPACK_IMPORTED_MODULE_4__.a.g.rootElement=context.document.childNodes[0];_cd__WEBPACK_IMPORTED_MODULE_4__.a.g.pageHasOutdents=Boolean(_cd__WEBPACK_IMPORTED_MODULE_4__.a.g.rootElement.getElementsByClassName(\"outdent-template\",1).length);parse();postMessage({type:e.type,revisionId:e.revisionId,resolverId:e.resolverId,comments:_cd__WEBPACK_IMPORTED_MODULE_4__.a.comments,sections:_cd__WEBPACK_IMPORTED_MODULE_4__.a.sections});_cd__WEBPACK_IMPORTED_MODULE_4__.a.debug.stopTimer(\"worker\");_cd__WEBPACK_IMPORTED_MODULE_4__.a.debug.logAndResetEverything()}}onmessage=onMessageFromWindow},function(t){t.exports=JSON.parse('{\"0\":65533,\"128\":8364,\"130\":8218,\"131\":402,\"132\":8222,\"133\":8230,\"134\":8224,\"135\":8225,\"136\":710,\"137\":8240,\"138\":352,\"139\":8249,\"140\":338,\"142\":381,\"145\":8216,\"146\":8217,\"147\":8220,\"148\":8221,\"149\":8226,\"150\":8211,\"151\":8212,\"152\":732,\"153\":8482,\"154\":353,\"155\":8250,\"156\":339,\"158\":382,\"159\":376}')},function(t,e,r){\"use strict\";var i,n=\"object\"==typeof Reflect?Reflect:null,s=n&&\"function\"==typeof n.apply?n.apply:function(t,e,r){return Function.prototype.apply.call(t,e,r)};if(n&&\"function\"==typeof n.ownKeys)i=n.ownKeys;else if(Object.getOwnPropertySymbols)i=function(t){return Object.getOwnPropertyNames(t).concat(Object.getOwnPropertySymbols(t))};else i=function(t){return Object.getOwnPropertyNames(t)};var o=Number.isNaN||function(t){return t!=t};function a(){a.init.call(this)}t.exports=a;t.exports.once=function(t,e){return new Promise((function(r,i){function n(){if(void 0!==s)t.removeListener(\"error\",s);r([].slice.call(arguments))}var s;if(\"error\"!==e){s=function(r){t.removeListener(e,n);i(r)};t.once(\"error\",s)}t.once(e,n)}))};a.EventEmitter=a;a.prototype._events=void 0;a.prototype._eventsCount=0;a.prototype._maxListeners=void 0;var u=10;function c(t){if(\"function\"!=typeof t)throw new TypeError('The \"listener\" argument must be of type Function. Received type '+typeof t)}Object.defineProperty(a,\"defaultMaxListeners\",{enumerable:!0,get:function(){return u},set:function(t){if(\"number\"!=typeof t||t<0||o(t))throw new RangeError('The value of \"defaultMaxListeners\" is out of range. It must be a non-negative number. Received '+t+\".\");u=t}});a.init=function(){if(void 0===this._events||this._events===Object.getPrototypeOf(this)._events){this._events=Object.create(null);this._eventsCount=0}this._maxListeners=this._maxListeners||void 0};a.prototype.setMaxListeners=function(t){if(\"number\"!=typeof t||t<0||o(t))throw new RangeError('The value of \"n\" is out of range. It must be a non-negative number. Received '+t+\".\");this._maxListeners=t;return this};function l(t){if(void 0===t._maxListeners)return a.defaultMaxListeners;else return t._maxListeners}a.prototype.getMaxListeners=function(){return l(this)};a.prototype.emit=function(t){for(var e=[],r=1;r<arguments.length;r++)e.push(arguments[r]);var i=\"error\"===t,n=this._events;if(void 0!==n)i=i&&void 0===n.error;else if(!i)return!1;if(i){var o;if(e.length>0)o=e[0];if(o instanceof Error)throw o;var a=new Error(\"Unhandled error.\"+(o?\" (\"+o.message+\")\":\"\"));a.context=o;throw a}var u=n[t];if(void 0===u)return!1;if(\"function\"==typeof u)s(u,this,e);else{var c=u.length,l=m(u,c);for(r=0;r<c;++r)s(l[r],this,e)}return!0};function f(t,e,r,i){var n,s,o;c(r);if(void 0===(s=t._events)){s=t._events=Object.create(null);t._eventsCount=0}else{if(void 0!==s.newListener){t.emit(\"newListener\",e,r.listener?r.listener:r);s=t._events}o=s[e]}if(void 0===o){o=s[e]=r;++t._eventsCount}else{if(\"function\"==typeof o)o=s[e]=i?[r,o]:[o,r];else if(i)o.unshift(r);else o.push(r);if((n=l(t))>0&&o.length>n&&!o.warned){o.warned=!0;var a=new Error(\"Possible EventEmitter memory leak detected. \"+o.length+\" \"+String(e)+\" listeners added. Use emitter.setMaxListeners() to increase limit\");a.name=\"MaxListenersExceededWarning\";a.emitter=t;a.type=e;a.count=o.length;!function(t){if(console&&console.warn)console.warn(t)}(a)}}return t}a.prototype.addListener=function(t,e){return f(this,t,e,!1)};a.prototype.on=a.prototype.addListener;a.prototype.prependListener=function(t,e){return f(this,t,e,!0)};function h(){if(!this.fired){this.target.removeListener(this.type,this.wrapFn);this.fired=!0;if(0===arguments.length)return this.listener.call(this.target);else return this.listener.apply(this.target,arguments)}}function d(t,e,r){var i={fired:!1,wrapFn:void 0,target:t,type:e,listener:r},n=h.bind(i);n.listener=r;i.wrapFn=n;return n}a.prototype.once=function(t,e){c(e);this.on(t,d(this,t,e));return this};a.prototype.prependOnceListener=function(t,e){c(e);this.prependListener(t,d(this,t,e));return this};a.prototype.removeListener=function(t,e){var r,i,n,s,o;c(e);if(void 0===(i=this._events))return this;if(void 0===(r=i[t]))return this;if(r===e||r.listener===e)if(0==--this._eventsCount)this._events=Object.create(null);else{delete i[t];if(i.removeListener)this.emit(\"removeListener\",t,r.listener||e)}else if(\"function\"!=typeof r){n=-1;for(s=r.length-1;s>=0;s--)if(r[s]===e||r[s].listener===e){o=r[s].listener;n=s;break}if(n<0)return this;if(0===n)r.shift();else!function(t,e){for(;e+1<t.length;e++)t[e]=t[e+1];t.pop()}(r,n);if(1===r.length)i[t]=r[0];if(void 0!==i.removeListener)this.emit(\"removeListener\",t,o||e)}return this};a.prototype.off=a.prototype.removeListener;a.prototype.removeAllListeners=function(t){var e,r,i;if(void 0===(r=this._events))return this;if(void 0===r.removeListener){if(0===arguments.length){this._events=Object.create(null);this._eventsCount=0}else if(void 0!==r[t])if(0==--this._eventsCount)this._events=Object.create(null);else delete r[t];return this}if(0===arguments.length){var n,s=Object.keys(r);for(i=0;i<s.length;++i)if(\"removeListener\"!==(n=s[i]))this.removeAllListeners(n);this.removeAllListeners(\"removeListener\");this._events=Object.create(null);this._eventsCount=0;return this}if(\"function\"==typeof(e=r[t]))this.removeListener(t,e);else if(void 0!==e)for(i=e.length-1;i>=0;i--)this.removeListener(t,e[i]);return this};function p(t,e,r){var i=t._events;if(void 0===i)return[];var n=i[e];if(void 0===n)return[];if(\"function\"==typeof n)return r?[n.listener||n]:[n];else return r?function(t){for(var e=new Array(t.length),r=0;r<e.length;++r)e[r]=t[r].listener||t[r];return e}(n):m(n,n.length)}a.prototype.listeners=function(t){return p(this,t,!0)};a.prototype.rawListeners=function(t){return p(this,t,!1)};a.listenerCount=function(t,e){if(\"function\"==typeof t.listenerCount)return t.listenerCount(e);else return _.call(t,e)};a.prototype.listenerCount=_;function _(t){var e=this._events;if(void 0!==e){var r=e[t];if(\"function\"==typeof r)return 1;else if(void 0!==r)return r.length}return 0}a.prototype.eventNames=function(){return this._eventsCount>0?i(this._events):[]};function m(t,e){for(var r=new Array(e),i=0;i<e;++i)r[i]=t[i];return r}},function(t,e,r){\"use strict\";var i,n=this&&this.__extends||(i=function(t,e){return(i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)if(e.hasOwnProperty(r))t[r]=e[r]})(t,e)},function(t,e){i(t,e);function r(){this.constructor=t}t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)});Object.defineProperty(e,\"__esModule\",{value:!0});var s=new Map([[\"tag\",1],[\"script\",1],[\"style\",1],[\"directive\",1],[\"text\",3],[\"cdata\",4],[\"comment\",8]]),o=function(){function t(t){this.type=t;this.parent=null;this.prev=null;this.next=null;this.startIndex=null;this.endIndex=null}Object.defineProperty(t.prototype,\"nodeType\",{get:function(){return s.get(this.type)||1},enumerable:!0,configurable:!0});Object.defineProperty(t.prototype,\"parentNode\",{get:function(){return this.parent||null},set:function(t){this.parent=t},enumerable:!0,configurable:!0});Object.defineProperty(t.prototype,\"previousSibling\",{get:function(){return this.prev||null},set:function(t){this.prev=t},enumerable:!0,configurable:!0});Object.defineProperty(t.prototype,\"nextSibling\",{get:function(){return this.next||null},set:function(t){this.next=t},enumerable:!0,configurable:!0});return t}();e.Node=o;var a=function(t){n(e,t);function e(e,r){var i=t.call(this,e)||this;i.data=r;return i}Object.defineProperty(e.prototype,\"nodeValue\",{get:function(){return this.data},set:function(t){this.data=t},enumerable:!0,configurable:!0});return e}(o);e.DataNode=a;var u=function(t){n(e,t);function e(e,r){var i=t.call(this,\"directive\",r)||this;i.name=e;return i}return e}(a);e.ProcessingInstruction=u;var c=function(t){n(e,t);function e(e,r){var i=t.call(this,e)||this;i.children=r;return i}Object.defineProperty(e.prototype,\"firstChild\",{get:function(){return this.children[0]||null},enumerable:!0,configurable:!0});Object.defineProperty(e.prototype,\"lastChild\",{get:function(){return this.children[this.children.length-1]||null},enumerable:!0,configurable:!0});Object.defineProperty(e.prototype,\"childNodes\",{get:function(){return this.children},set:function(t){this.children=t},enumerable:!0,configurable:!0});return e}(o);e.NodeWithChildren=c;var l=function(t){n(e,t);function e(e,r){var i=t.call(this,\"script\"===e?\"script\":\"style\"===e?\"style\":\"tag\",[])||this;i.name=e;i.attribs=r;i.attribs=r;return i}Object.defineProperty(e.prototype,\"tagName\",{get:function(){return this.name},set:function(t){this.name=t},enumerable:!0,configurable:!0});return e}(c);e.Element=l},function(t,e,r){\"use strict\";var i=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,\"__esModule\",{value:!0});var n=r(6),s=i(r(34));e.getOuterHTML=s.default;e.getInnerHTML=function(t,r){return n.hasChildren(t)?t.children.map((function(t){return e.getOuterHTML(t,r)})).join(\"\"):\"\"};e.getText=function t(e){if(Array.isArray(e))return e.map(t).join(\"\");if(n.isTag(e))return\"br\"===e.name?\"\\n\":t(e.children);if(n.isCDATA(e))return t(e.children);if(n.isText(e))return e.data;else return\"\"}},function(t,e,r){var i=r(9),n=r(35),s=r(36);s.elementNames.__proto__=null;s.attributeNames.__proto__=null;var o={__proto__:null,style:!0,script:!0,xmp:!0,iframe:!0,noembed:!0,noframes:!0,plaintext:!0,noscript:!0};var a={__proto__:null,area:!0,base:!0,basefont:!0,br:!0,col:!0,command:!0,embed:!0,frame:!0,hr:!0,img:!0,input:!0,isindex:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0},u=t.exports=function(t,e){if(!Array.isArray(t)&&!t.cheerio)t=[t];e=e||{};for(var r=\"\",n=0;n<t.length;n++){var s=t[n];if(\"root\"===s.type)r+=u(s.children,e);else if(i.isTag(s))r+=l(s,e);else if(s.type===i.Directive)r+=f(s);else if(s.type===i.Comment)r+=p(s);else if(s.type===i.CDATA)r+=d(s);else r+=h(s,e)}return r},c=[\"mi\",\"mo\",\"mn\",\"ms\",\"mtext\",\"annotation-xml\",\"foreignObject\",\"desc\",\"title\"];function l(t,e){if(\"foreign\"===e.xmlMode){t.name=s.elementNames[t.name]||t.name;if(t.parent&&c.indexOf(t.parent.name)>=0)e=Object.assign({},e,{xmlMode:!1})}if(!e.xmlMode&&[\"svg\",\"math\"].indexOf(t.name)>=0)e=Object.assign({},e,{xmlMode:\"foreign\"});var r=\"<\"+t.name,i=function(t,e){if(t){var r,i=\"\";for(var o in t){r=t[o];if(i)i+=\" \";if(\"foreign\"===e.xmlMode)o=s.attributeNames[o]||o;i+=o;if(null!==r&&\"\"!==r||e.xmlMode)i+='=\"'+(e.decodeEntities?n.encodeXML(r):r.replace(/\\\"/g,\"&quot;\"))+'\"'}return i}}(t.attribs,e);if(i)r+=\" \"+i;if(e.xmlMode&&(!t.children||0===t.children.length))r+=\"/>\";else{r+=\">\";if(t.children)r+=u(t.children,e);if(!a[t.name]||e.xmlMode)r+=\"</\"+t.name+\">\"}return r}function f(t){return\"<\"+t.data+\">\"}function h(t,e){var r=t.data||\"\";if(e.decodeEntities&&(!t.parent||!(t.parent.name in o)))r=n.encodeXML(r);return r}function d(t){return\"<![CDATA[\"+t.children[0].data+\"]]>\"}function p(t){return\"\\x3c!--\"+t.data+\"--\\x3e\"}},function(t,e,r){\"use strict\";Object.defineProperty(e,\"__esModule\",{value:!0});var i=r(17),n=r(18);e.decode=function(t,e){return(!e||e<=0?i.decodeXML:i.decodeHTML)(t)};e.decodeStrict=function(t,e){return(!e||e<=0?i.decodeXML:i.decodeHTMLStrict)(t)};e.encode=function(t,e){return(!e||e<=0?n.encodeXML:n.encodeHTML)(t)};var s=r(18);e.encodeXML=s.encodeXML;e.encodeHTML=s.encodeHTML;e.escape=s.escape;e.encodeHTML4=s.encodeHTML;e.encodeHTML5=s.encodeHTML;var o=r(17);e.decodeXML=o.decodeXML;e.decodeHTML=o.decodeHTML;e.decodeHTMLStrict=o.decodeHTMLStrict;e.decodeHTML4=o.decodeHTML;e.decodeHTML5=o.decodeHTML;e.decodeHTML4Strict=o.decodeHTMLStrict;e.decodeHTML5Strict=o.decodeHTMLStrict;e.decodeXMLStrict=o.decodeXML},function(t){t.exports=JSON.parse('{\"elementNames\":{\"altglyph\":\"altGlyph\",\"altglyphdef\":\"altGlyphDef\",\"altglyphitem\":\"altGlyphItem\",\"animatecolor\":\"animateColor\",\"animatemotion\":\"animateMotion\",\"animatetransform\":\"animateTransform\",\"clippath\":\"clipPath\",\"feblend\":\"feBlend\",\"fecolormatrix\":\"feColorMatrix\",\"fecomponenttransfer\":\"feComponentTransfer\",\"fecomposite\":\"feComposite\",\"feconvolvematrix\":\"feConvolveMatrix\",\"fediffuselighting\":\"feDiffuseLighting\",\"fedisplacementmap\":\"feDisplacementMap\",\"fedistantlight\":\"feDistantLight\",\"fedropshadow\":\"feDropShadow\",\"feflood\":\"feFlood\",\"fefunca\":\"feFuncA\",\"fefuncb\":\"feFuncB\",\"fefuncg\":\"feFuncG\",\"fefuncr\":\"feFuncR\",\"fegaussianblur\":\"feGaussianBlur\",\"feimage\":\"feImage\",\"femerge\":\"feMerge\",\"femergenode\":\"feMergeNode\",\"femorphology\":\"feMorphology\",\"feoffset\":\"feOffset\",\"fepointlight\":\"fePointLight\",\"fespecularlighting\":\"feSpecularLighting\",\"fespotlight\":\"feSpotLight\",\"fetile\":\"feTile\",\"feturbulence\":\"feTurbulence\",\"foreignobject\":\"foreignObject\",\"glyphref\":\"glyphRef\",\"lineargradient\":\"linearGradient\",\"radialgradient\":\"radialGradient\",\"textpath\":\"textPath\"},\"attributeNames\":{\"definitionurl\":\"definitionURL\",\"attributename\":\"attributeName\",\"attributetype\":\"attributeType\",\"basefrequency\":\"baseFrequency\",\"baseprofile\":\"baseProfile\",\"calcmode\":\"calcMode\",\"clippathunits\":\"clipPathUnits\",\"diffuseconstant\":\"diffuseConstant\",\"edgemode\":\"edgeMode\",\"filterunits\":\"filterUnits\",\"glyphref\":\"glyphRef\",\"gradienttransform\":\"gradientTransform\",\"gradientunits\":\"gradientUnits\",\"kernelmatrix\":\"kernelMatrix\",\"kernelunitlength\":\"kernelUnitLength\",\"keypoints\":\"keyPoints\",\"keysplines\":\"keySplines\",\"keytimes\":\"keyTimes\",\"lengthadjust\":\"lengthAdjust\",\"limitingconeangle\":\"limitingConeAngle\",\"markerheight\":\"markerHeight\",\"markerunits\":\"markerUnits\",\"markerwidth\":\"markerWidth\",\"maskcontentunits\":\"maskContentUnits\",\"maskunits\":\"maskUnits\",\"numoctaves\":\"numOctaves\",\"pathlength\":\"pathLength\",\"patterncontentunits\":\"patternContentUnits\",\"patterntransform\":\"patternTransform\",\"patternunits\":\"patternUnits\",\"pointsatx\":\"pointsAtX\",\"pointsaty\":\"pointsAtY\",\"pointsatz\":\"pointsAtZ\",\"preservealpha\":\"preserveAlpha\",\"preserveaspectratio\":\"preserveAspectRatio\",\"primitiveunits\":\"primitiveUnits\",\"refx\":\"refX\",\"refy\":\"refY\",\"repeatcount\":\"repeatCount\",\"repeatdur\":\"repeatDur\",\"requiredextensions\":\"requiredExtensions\",\"requiredfeatures\":\"requiredFeatures\",\"specularconstant\":\"specularConstant\",\"specularexponent\":\"specularExponent\",\"spreadmethod\":\"spreadMethod\",\"startoffset\":\"startOffset\",\"stddeviation\":\"stdDeviation\",\"stitchtiles\":\"stitchTiles\",\"surfacescale\":\"surfaceScale\",\"systemlanguage\":\"systemLanguage\",\"tablevalues\":\"tableValues\",\"targetx\":\"targetX\",\"targety\":\"targetY\",\"textlength\":\"textLength\",\"viewbox\":\"viewBox\",\"viewtarget\":\"viewTarget\",\"xchannelselector\":\"xChannelSelector\",\"ychannelselector\":\"yChannelSelector\",\"zoomandpan\":\"zoomAndPan\"}}')},function(t,e,r){\"use strict\";Object.defineProperty(e,\"__esModule\",{value:!0});function i(t){return t.children||null}e.getChildren=i;function n(t){return t.parent||null}e.getParent=n;e.getSiblings=function(t){var e=n(t);return e?i(e):[t]};function s(t,e){return t.attribs&&t.attribs[e]}e.getAttributeValue=s;e.hasAttrib=function(t,e){return!!s(t,e)};e.getName=function(t){return t.name}},function(t,e,r){\"use strict\";Object.defineProperty(e,\"__esModule\",{value:!0});e.removeElement=function(t){if(t.prev)t.prev.next=t.next;if(t.next)t.next.prev=t.prev;if(t.parent){var e=t.parent.children;e.splice(e.lastIndexOf(t),1)}};e.replaceElement=function(t,e){var r=e.prev=t.prev;if(r)r.next=e;var i=e.next=t.next;if(i)i.prev=e;var n=e.parent=t.parent;if(n){var s=n.children;s[s.lastIndexOf(t)]=e}};e.appendChild=function(t,e){e.parent=t;if(1!==t.children.push(e)){var r=t.children[t.children.length-2];r.next=e;e.prev=r;e.next=null}};e.append=function(t,e){var r=t.parent,i=t.next;e.next=i;e.prev=t;t.next=e;e.parent=r;if(i){i.prev=e;if(r){var n=r.children;n.splice(n.lastIndexOf(i),0,e)}}else if(r)r.children.push(e)};e.prepend=function(t,e){var r=t.parent;if(r){var i=r.children;i.splice(i.lastIndexOf(t),0,e)}if(t.prev)t.prev.next=e;e.parent=r;e.prev=t.prev;e.next=t;t.prev=e}},function(t,e,r){\"use strict\";Object.defineProperty(e,\"__esModule\",{value:!0});var i=r(19),n=r(6);function s(t){return\"text\"===t.type}var o={tag_name:function(t){if(\"function\"==typeof t)return function(e){return n.isTag(e)&&t(e.name)};else if(\"*\"===t)return n.isTag;else return function(e){return n.isTag(e)&&e.name===t}},tag_type:function(t){if(\"function\"==typeof t)return function(e){return t(e.type)};else return function(e){return e.type===t}},tag_contains:function(t){if(\"function\"==typeof t)return function(e){return s(e)&&t(e.data)};else return function(e){return s(e)&&e.data===t}}};function a(t,e){if(\"function\"==typeof e)return function(r){return n.isTag(r)&&e(r.attribs[t])};else return function(r){return n.isTag(r)&&r.attribs[t]===e}}function u(t,e){return function(r){return t(r)||e(r)}}function c(t){var e=Object.keys(t).map((function(e){var r=t[e];return e in o?o[e](r):a(e,r)}));return 0===e.length?null:e.reduce(u)}e.testElement=function(t,e){var r=c(t);return r?r(e):!0};e.getElements=function(t,e,r,n){if(void 0===n)n=1/0;var s=c(t);return s?i.filter(s,e,r,n):[]};e.getElementById=function(t,e,r){if(void 0===r)r=!0;if(!Array.isArray(e))e=[e];return i.findOne(a(\"id\",t),e,r)};e.getElementsByTagName=function(t,e,r,n){if(void 0===n)n=1/0;return i.filter(o.tag_name(t),e,r,n)};e.getElementsByTagType=function(t,e,r,n){if(void 0===r)r=!0;if(void 0===n)n=1/0;return i.filter(o.tag_type(t),e,r,n)}},function(t,e,r){\"use strict\";Object.defineProperty(e,\"__esModule\",{value:!0});var i=r(6);e.removeSubsets=function(t){for(var e=t.length;--e>=0;){var r=t[e];if(!(e>0&&t.lastIndexOf(r,e-1)>=0)){for(var i=r.parent;i;i=i.parent)if(t.indexOf(i)>-1){t.splice(e,1);break}}else t.splice(e,1)}return t};function n(t,e){var r=[],n=[];if(t===e)return 0;for(var s=i.hasChildren(t)?t:t.parent;s;){r.unshift(s);s=s.parent}s=i.hasChildren(e)?e:e.parent;for(;s;){n.unshift(s);s=s.parent}for(var o=0;r[o]===n[o];)o++;if(0===o)return 1;var a=r[o-1],u=a.children,c=r[o],l=n[o];if(u.indexOf(c)>u.indexOf(l))if(a===e)return 20;else return 4;else if(a===t)return 10;else return 2}e.compareDocumentPosition=n;e.uniqueSort=function(t){(t=t.filter((function(t,e,r){return!r.includes(t,e+1)}))).sort((function(t,e){var r=n(t,e);if(2&r)return-1;else if(4&r)return 1;return 0}));return t}},function(t,e){},function(t,e,r){\"use strict\";var i,n=this&&this.__extends||(i=function(t,e){return(i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)if(e.hasOwnProperty(r))t[r]=e[r]})(t,e)},function(t,e){i(t,e);function r(){this.constructor=t}t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),s=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,\"__esModule\",{value:!0});var o=function(t){n(e,t);function e(e){if(void 0===e)e={};var r=t.call(this,(function(t){for(var e,i=[],n=1;n<arguments.length;n++)i[n-1]=arguments[n];r.events.push([t].concat(i));if(r._cbs[t])(e=r._cbs)[t].apply(e,i)}))||this;r._cbs=e;r.events=[];return r}e.prototype.onreset=function(){this.events=[];if(this._cbs.onreset)this._cbs.onreset()};e.prototype.restart=function(){var t;if(this._cbs.onreset)this._cbs.onreset();for(var e=0;e<this.events.length;e++){var r=this.events[e],i=r[0],n=r.slice(1);if(this._cbs[i])(t=this._cbs)[i].apply(t,n)}};return e}(s(r(43)).default);e.CollectingHandler=o},function(t,e,r){\"use strict\";Object.defineProperty(e,\"__esModule\",{value:!0});var i=function(){function t(t){this._func=t}t.prototype.onattribute=function(t,e){this._func(\"onattribute\",t,e)};t.prototype.oncdatastart=function(){this._func(\"oncdatastart\")};t.prototype.oncdataend=function(){this._func(\"oncdataend\")};t.prototype.ontext=function(t){this._func(\"ontext\",t)};t.prototype.onprocessinginstruction=function(t,e){this._func(\"onprocessinginstruction\",t,e)};t.prototype.oncomment=function(t){this._func(\"oncomment\",t)};t.prototype.oncommentend=function(){this._func(\"oncommentend\")};t.prototype.onclosetag=function(t){this._func(\"onclosetag\",t)};t.prototype.onopentag=function(t,e){this._func(\"onopentag\",t,e)};t.prototype.onopentagname=function(t){this._func(\"onopentagname\",t)};t.prototype.onerror=function(t){this._func(\"onerror\",t)};t.prototype.onend=function(){this._func(\"onend\")};t.prototype.onparserinit=function(t){this._func(\"onparserinit\",t)};t.prototype.onreset=function(){this._func(\"onreset\")};return t}();e.default=i},function(t,e,r){\"use strict\";t.exports=function(t,e){var r,i,n,s={},o={},a={},u={};a[0]=\"HTML_SPECIALCHARS\";a[1]=\"HTML_ENTITIES\";u[0]=\"ENT_NOQUOTES\";u[2]=\"ENT_COMPAT\";u[3]=\"ENT_QUOTES\";i=!isNaN(t)?a[t]:t?t.toUpperCase():\"HTML_SPECIALCHARS\";n=!isNaN(e)?u[e]:e?e.toUpperCase():\"ENT_COMPAT\";if(\"HTML_SPECIALCHARS\"!==i&&\"HTML_ENTITIES\"!==i)throw new Error(\"Table: \"+i+\" not supported\");s[38]=\"&amp;\";if(\"HTML_ENTITIES\"===i){s[160]=\"&nbsp;\";s[161]=\"&iexcl;\";s[162]=\"&cent;\";s[163]=\"&pound;\";s[164]=\"&curren;\";s[165]=\"&yen;\";s[166]=\"&brvbar;\";s[167]=\"&sect;\";s[168]=\"&uml;\";s[169]=\"&copy;\";s[170]=\"&ordf;\";s[171]=\"&laquo;\";s[172]=\"&not;\";s[173]=\"&shy;\";s[174]=\"&reg;\";s[175]=\"&macr;\";s[176]=\"&deg;\";s[177]=\"&plusmn;\";s[178]=\"&sup2;\";s[179]=\"&sup3;\";s[180]=\"&acute;\";s[181]=\"&micro;\";s[182]=\"&para;\";s[183]=\"&middot;\";s[184]=\"&cedil;\";s[185]=\"&sup1;\";s[186]=\"&ordm;\";s[187]=\"&raquo;\";s[188]=\"&frac14;\";s[189]=\"&frac12;\";s[190]=\"&frac34;\";s[191]=\"&iquest;\";s[192]=\"&Agrave;\";s[193]=\"&Aacute;\";s[194]=\"&Acirc;\";s[195]=\"&Atilde;\";s[196]=\"&Auml;\";s[197]=\"&Aring;\";s[198]=\"&AElig;\";s[199]=\"&Ccedil;\";s[200]=\"&Egrave;\";s[201]=\"&Eacute;\";s[202]=\"&Ecirc;\";s[203]=\"&Euml;\";s[204]=\"&Igrave;\";s[205]=\"&Iacute;\";s[206]=\"&Icirc;\";s[207]=\"&Iuml;\";s[208]=\"&ETH;\";s[209]=\"&Ntilde;\";s[210]=\"&Ograve;\";s[211]=\"&Oacute;\";s[212]=\"&Ocirc;\";s[213]=\"&Otilde;\";s[214]=\"&Ouml;\";s[215]=\"&times;\";s[216]=\"&Oslash;\";s[217]=\"&Ugrave;\";s[218]=\"&Uacute;\";s[219]=\"&Ucirc;\";s[220]=\"&Uuml;\";s[221]=\"&Yacute;\";s[222]=\"&THORN;\";s[223]=\"&szlig;\";s[224]=\"&agrave;\";s[225]=\"&aacute;\";s[226]=\"&acirc;\";s[227]=\"&atilde;\";s[228]=\"&auml;\";s[229]=\"&aring;\";s[230]=\"&aelig;\";s[231]=\"&ccedil;\";s[232]=\"&egrave;\";s[233]=\"&eacute;\";s[234]=\"&ecirc;\";s[235]=\"&euml;\";s[236]=\"&igrave;\";s[237]=\"&iacute;\";s[238]=\"&icirc;\";s[239]=\"&iuml;\";s[240]=\"&eth;\";s[241]=\"&ntilde;\";s[242]=\"&ograve;\";s[243]=\"&oacute;\";s[244]=\"&ocirc;\";s[245]=\"&otilde;\";s[246]=\"&ouml;\";s[247]=\"&divide;\";s[248]=\"&oslash;\";s[249]=\"&ugrave;\";s[250]=\"&uacute;\";s[251]=\"&ucirc;\";s[252]=\"&uuml;\";s[253]=\"&yacute;\";s[254]=\"&thorn;\";s[255]=\"&yuml;\"}if(\"ENT_NOQUOTES\"!==n)s[34]=\"&quot;\";if(\"ENT_QUOTES\"===n)s[39]=\"&#39;\";s[60]=\"&lt;\";s[62]=\"&gt;\";for(r in s)if(s.hasOwnProperty(r))o[String.fromCharCode(r)]=s[r];return o}}]);\n//# sourceMappingURL=https://commons.wikimedia.org/w/index.php?title=User:Jack_who_built_the_house/convenientDiscussions-worker.js.map.json&action=raw&ctype=application/json", null); };"
"convenientDiscussions.i18n = convenientDiscussions.i18n || {}; convenientDiscussions.i18n['en'] = { "script-name": "Convenient Discussions", "script-name-short": "CD", "cm-gotoparent": "▲", "cm-gotoparent-tooltip": "Go to the parent comment", "cm-gotochild": "▼", "cm-gotochild-tooltip": "Go back to the child comment", "cm-copylink": "#", "cm-copylink-tooltip": "Copy a link", "cm-thank": "Thank", "cm-thank-tooltip": "Thank for the edit that added this comment", "cm-thanked": "Thanked", "cm-thanked-tooltip": "You have already thanked the user for this comment", "cm-edit": "Edit", "cm-reply": "Reply", "sm-editopeningcomment": "edit opening comment", "sm-editopeningcomment-tooltip": "Edit the comment opening the section", "sm-addsubsection": "add subsection", "sm-addsubsection-tooltip": "Add a subsection to this section", "sm-move": "move", "sm-move-tooltip": "Move the topic to another page", "sm-watch": "watch", "sm-watch-tooltip": "Add the section to the watchlist. This affects notifications and bolding in the watchlist", "sm-unwatch": "unwatch", "sm-unwatch-tooltip": "Remove the section from the watchlist", "sm-copylink": "#", "sm-copylink-tooltip": "Copy a link", "comment-edited": "The comment has changed.", "comment-edited-refresh": "Refresh", "comment-edited-diff": "Diff", "comment-edited-diff-error": "Couldn't render the diff.", "comment-edited-diff-empty": "The diff is empty. Probably, the rendering of the comment has changed, but it wasn't edited.", "comment-deleted": "The comment was deleted or re-signed.", "comment-editedsince": "The comment has changed since your last visit.", "comment-edited-history": "Edit history", "section-reply": "Reply to section", "section-addsubsection-to": "Add subsection to \"$1\"", "section-newcomments": "{{plural:$1|There is a new comment|There are new comments}} in this section from {{plural:$2|{{gender:$4|}}|{{gender:$4|}}}} $3. Click to refresh the page.", "section-watch-success": "Section \"$1\" has been added to your watchlist.", "section-unwatch-success": "Section \"$1\" has been removed from your watchlist.", "section-unwatch-stillwatched": "<strong>Note:</strong> you are still watching this section as it is included in the section \"$1\" that you watch.", "section-watch-pagenotwatched": "<strong>Note:</strong> you watch the section but not the page. In order for new comments to be highlighted on your watchlist page, add the page to the watchlist.", "section-watch-error-load": "Couldn't load the settings from the server.", "section-watch-error-save": "Couldn't save the settings to the server.", "section-watch-error-maxsize": "Couldn't update the settings: the size of the watched sections list exceeds the maximum size. <span class=\"cd-notification-editWatchedSections\">Edit the sections list</span> to fix this.", "cld-summary": "Edit summary", "cld-diff": "Diff link", "cld-diff-error": "Couldn't find", "cld-diff-error-network": "Couldn't find (network error)", "cld-diff-error-unknown": "Couldn't find (unknown error)", "cld-shortdiff": "Short diff link", "cld-wikilink": "Wikilink", "cld-help-onlycd": "This link will work only for users that have Convenient Discussions installed.", "cld-currentpagewikilink": "Wikilink from the same page", "cld-link": "Regular link", "cld-close": "Close", "copylink-copied": "The link has been copied to the clipboard.", "copylink-error": "Couldn't copy the link.", "thank-confirm": "Thank {{gender:$2|}} $1 for [$3 this edit]?", "thank-error": "Couldn't send the thank you.", "thank-success": "\"Thank you\" notification has been sent.", "es-reply": "reply", "es-reply-to": "reply to {{gender:$2|}} $1", "es-addition": "addition", "es-edit-reply": "edit the reply", "es-edit-reply-to": "edit the reply to {{gender:$2|}} $1", "es-edit-addition": "edit the addition", "es-edit-topic": "edit the opening comment", "es-edit-subsection": "edit the opening comment", "es-edit-comment": "edit the comment", "es-edit-comment-by": "edit the comment by {{gender:$2|}} $1", "es-delete-reply": "delete the reply", "es-delete-reply-to": "delete the reply to {{gender:$2|}} $1", "es-delete-addition": "delete the addition", "es-delete-topic": "delete the topic", "es-delete-subsection": "delete the subsection", "es-delete-comment": "delete the comment", "es-delete-comment-by": "delete the comment by {{gender:$2|}} $1", "es-new-topic": "new topic", "es-new-subsection": "new subsection", "es-move-from": "move from [[$1]]", "es-move-to": "move to [[$1]]", "cf-headline-topic": "Topic subject/headline", "cf-headline-subsection": "Subject/headline of the subsection of \"$1\"", "cf-comment-placeholder-replytosection": "Reply to \"$1\"", "cf-comment-placeholder-replytocomment": "Reply to {{gender:$2|}} $1", "cf-summary-placeholder": "Edit summary", "cf-summary-preview": "Edit summary preview", "cf-save": "Save", "cf-save-short": "Save", "cf-delete-button": "Delete", "cf-delete-button-short": "Delete", "cf-addtopic": "Add topic", "cf-addtopic-short": "Add", "cf-addsubsection": "Add subsection", "cf-addsubsection-short": "Add", "cf-reply": "Reply", "cf-reply-short": "Reply", "cf-preview": "Preview", "cf-preview-short": "Preview", "cf-viewchanges": "View changes", "cf-viewchanges-short": "Changes", "cf-cancel": "Cancel", "cf-cancel-short": "Cancel", "cf-advanced": "Advanced", "cf-settings-tooltip": "Convenient Discussions settings", "cf-help": "?", "cf-help-short": "?", "cf-help-content": "<ul>\n<li>Type <kbd>$1</kbd> and choose a user to [[mw:Special:MyLanguage/Help:Notifications/Mention|mention]] them.</li>\n<li>Type <kbd><nowiki>[[#</" + String("") + "nowiki></kbd> to link a comment in this section.</li>\n<li>Hold Shift while choosing an autocomplete item to change the displayed text (for example, <code><nowiki>[[Article|</" + String("") + "nowiki><var>text</var><nowiki>]]</" + String("") + "nowiki></code>).</li>\n<li>Hold Alt while choosing an autocomplete item to use the text after the caret as displayed text.</li>\n<li>Hold Ctrl while choosing a user to add punctiation after the name.</li>\n<li>If the comment menu obstructs a link behind it, make a long click/tap on it—it will disappear.</li>\n</ul>\n<p>Hotkeys:</p>\n<ul>\n<li><b>Ctrl+Enter</b> — post</li>\n<li><b>Esc</b> — cancel</li>\n<li><b>Q</b> (<b>Ctrl+Alt+Q</b>) — quote the selected text</li>\n</ul>\n<p>[[c:Special:MyLanguage/User:Jack who built the house/Convenient Discussions|Script documentation]]</p>", "cf-strikethrough-tooltip": "Strikethrough", "cf-strikethrough-placeholder": "Struckthrough text", "cf-code-tooltip": "Code", "cf-code-placeholder": "Code", "cf-codeblock-tooltip": "Code block", "cf-codeblock-placeholder": "Code block", "cf-quote-tooltip": "Quote the selected text", "cf-quote-placeholder": "Quoted text", "cf-mention-tooltip": "Mention a user. Hold Ctrl to mention the comment's addressee if available", "cf-underline-tooltip": "Underline", "cf-underline-placeholder": "Underlined text", "cf-minor": "Minor edit", "cf-watch": "Watch this page", "cf-watchsection-topic": "Watch this topic", "cf-watchsection-subsection": "Watch this subsection", "cf-watchsection-tooltip": "Add this section to the watchlist. This affects notifications and bolding in the watchlist", "cf-omitsignature": "Omit signature", "cf-delete": "Delete", "cf-block-preview": "Preview", "cf-block-viewchanges": "Changes", "cf-block-close": "Close", "cf-reaction-templateinheadline": "Don't use templates in headlines: this breaks section links.", "cf-reaction-signature": "No need to enter <kbd>$1</kbd>: the signature will be added automatically.", "cf-reaction-pre": "<code><nowiki><pre></" + String("") + "nowiki></code> tags can break the layout—better use <code><nowiki><syntaxhighlight></" + String("") + "nowiki></code>.", "cf-reaction-mention-edit": "Since you are <em>editing</em> a comment, a [[mw:Special:MyLanguage/Help:Notifications/Mention#How to mention another editor and trigger a notification|mention notification]] will not be sent. To send a notification, you may link the user in the edit summary.", "cf-reaction-mention-nosignature": "Since you've opted not to include a signature in your comment, a [[mw:Special:MyLanguage/Help:Notifications/Mention#How to mention another editor and trigger a notification|mention notification]] will not be sent. To send a notification, you may link the user in the edit summary.", "cf-notice-nochanges": "No changes.", "cf-notice-editconflict-retrying": "Trying again…", "cf-error-getpagecode": "Couldn't get the page code.", "cf-error-findplace": "Couldn't find the proper place in the code to insert the comment into.", "cf-error-commentlinks-commentnotfound": "Couldn't find the comment with ID $1, linked from your comment, on the page.", "cf-error-numberedlist": "It's impossible to form the comment correctly without distorting the numbered list markup.", "cf-error-numberedlist-list": "Remove lists from the comment.", "cf-error-numberedlist-table": "Remove tables from the comment.", "cf-error-delete-repliestocomment": "Can't delete the comment because it has replies.", "cf-error-delete-repliesinsection": "Can't delete the section because it has replies.", "cf-error-preview": "Couldn't preview the comment.", "cf-error-viewchanges": "Couldn't get the changes.", "cf-error-couldntedit": "The page may not have been edited.", "cf-error-pagedoesntexist": "The page doesn't exist.", "cf-error-formconflict": "There already is an \"Add topic\" form of a different type open on the page. Close that form to open this one.", "cf-error-othersubmitted": "Can't submit the form because another form is being submitted right now.", "cf-confirm-noheadline-topic": "You didn't enter the topic subject/headline.", "cf-confirm-noheadline-subsection": "You didn't enter the section subject/headline.", "cf-confirm-noheadline-question": "Are you sure you want to post the comment?", "cf-confirm-empty": "Are you sure you want to post an empty comment?", "cf-confirm-long": "This comment is longer than $1 characters. Are you sure you want to post it?", "cf-confirm-secondlevelheading": "The comment contains the code of the second level section. If you are moving the source code, it's better to use the standard edit source function, otherwise it could be altered unpredictably. Are you sure you want to post the comment?", "cf-confirm-delete": "Are you sure you want to delete the comment?", "cf-confirm-delete-yes": "Delete", "cf-confirm-delete-no": "Cancel", "cf-confirm-close": "Are you sure you want to close the form? The input will be lost.", "cf-confirm-close-yes": "Close", "cf-confirm-close-no": "Cancel", "cf-autocomplete-notemplatedata": "Couldn't load TemplateData for this template.", "cf-autocomplete-commentlinktext": "$1 @ $2", "dn-confirm": "Do you want Convenient Discussions to send you desktop notifications about new comments on currently open pages if they are addressed to you or posted in sections that you watch? You can disable this feature in the settings.", "dn-confirm-yes": "Yes", "dn-confirm-no": "No", "dn-grantpermission": "Grant a permission to the site.", "dn-grantpermission-again": "You have desktop notifications switched on, but the site is not allowed to send them. Grant a permission to the site to receive notifications or deny to prevent this message from showing up again.", "deadanchor-section-title": "Section not found", "deadanchor-section-text": "It could be moved or archived.", "deadanchor-comment-title": "Comment not found", "deadanchor-comment-text": "It could be moved or archived.", "deadanchor-searchinarchive": "Do you want to search in the archive?", "deadanchor-search-gotocomment": "jump to comment", "restore-restored-title": "Session restored", "restore-restored-text": "The unsent comment forms have been automatically recovered.", "rd-intro": "Couldn't find the comments or sections on the page that some of the opened forms were related to. Below is the restored content of these forms. Copy it if you need.", "rd-headline": "Subject/headline", "rd-comment": "Comment", "rd-summary": "Edit summary", "rd-close": "Close", "navpanel-refresh": "Refresh page", "navpanel-previous": "Go to the previous new comment", "navpanel-next": "Go to the next new comment", "navpanel-firstunseen": "Go to the first unseen comment", "navpanel-commentform": "Go to the next comment form out of sight", "navpanel-newcomments-count": "$1 new {{plural:$1|comment|comments}}.", "navpanel-newcomments-names": "$1 → $2", "navpanel-newcomments-unknowndate": "unknown date", "navpanel-newcomments-refresh": "Click to refresh the page", "toc-more": "…$1 more", "toc-watched": "You watch this section", "notification-toyou": "$1 {{gender:$2|replied}} to your comment$3.", "notification-toyou-desktop": "$1 {{gender:$2|replied}} to your comment$3 on page \"$4\".", "notification-insection": "$1 {{gender:$2|replied}} in section \"$3\".", "notification-insection-desktop": "$1 {{gender:$2|replied}} in section \"$3\" on page \"$4\".", "notification-newcomments": "$1 new {{plural:$1|comment|comments}}$2$3.", "notification-newcomments-desktop": "$1 new {{plural:$1|comment|comments}}$2 on page \"$3\"$4.", "notification-newcomments-maybeinteresting": "that may be interesting to you", "notification-reload": "Click to reload the page$1.", "notification-formdata": "form data will not be lost", "notification-part-insection": "in section \"$1\"", "notification-part-onthispage": "on this page", "footer-runcd": "Run Convenient Discussions on this page once", "footer-dontruncd": "Don't run Convenient Discussions on this page once", "sd-title": "Convenient Discussions settings", "sd-save": "Save", "sd-reload": "Reload", "sd-page-talkpage": "Talk page", "sd-page-commentform": "Comment form", "sd-page-notifications": "Notifications", "sd-page-dataremoval": "Data removal", "sd-close-confirm": "The settings were not saved. Are you sure you want to close the window?", "sd-close-confirm-yes": "Close", "sd-close-confirm-no": "Cancel", "sd-saved": "The settings have been saved successfully. Reload the page to apply them.", "sd-reset": "Reset settings (in all sections)", "sd-reset-confirm": "Are you sure you want to reset the settings? (Click \"{{int:convenient-discussions-sd-save}}\" after resetting.)", "sd-removedata": "Remove all script data", "sd-removedata-description": "Delete the data that Convenient Discussions has collected: your settings, talk page last visits, watched sections, and drafts of unsent comments", "sd-removedata-help": "Note that everything except the global settings is removed for the current wiki only. If you have used Convenient Discussions on other wikis and you want to remove the data on them, you will have to remove it on those wikis. See [[c:Special:MyLanguage/User:Jack who built the house/Convenient Discussions#Data|the script's homepage]] for the details on what, why, and how the script stores and instructions on how to delete each piece of data individually.", "sd-removedata-confirm": "This will permanently delete your settings, talk page last visits, watched sections, and drafts of unsent comments. Do you want to proceed?", "sd-removedata-confirm-yes": "Yes", "sd-removedata-confirm-no": "No", "sd-dataremoved": "Your data has been successfully removed.", "sd-error-removedata": "Couldn't remove the data on the server.", "sd-localsetting": "<i>This setting is individual for each wiki.</i>", "sd-alloweditotherscomments": "Show a link to edit other users' comments", "sd-alwaysexpandadvanced": "Expand the \"{{int:convenient-discussions-cf-advanced}}\" section when replying", "sd-autocompletetypes": "Enable autocomplete for", "sd-autocompletetypes-mentions": "mentions", "sd-autocompletetypes-commentlinks": "comment links", "sd-autocompletetypes-wikilinks": "wikilinks", "sd-autocompletetypes-templates": "templates", "sd-autocompletetypes-tags": "tags", "sd-autopreview": "Preview the comment as I type", "sd-desktopnotifications": "Desktop notifications", "sd-desktopnotifications-radio-all": "Notify me about replies to my comments and comments in sections that I watch", "sd-desktopnotifications-radio-tome": "Notify me about replies to my comments only", "sd-desktopnotifications-radio-none": "Don't notify me", "sd-desktopnotifications-help": "Desktop notifications inform about events on pages that are open but hidden. To receive them, you must grant a premission to $1.", "sd-highlightowncomments": "Highlight my comments", "sd-insertbuttons": "Text insert buttons", "sd-insertbuttons-multiselect-placeholder": "Add a button", "sd-insertbuttons-help": "Use <code>+</code> to specify a place where the caret should be put after inserting the text; for example, <code><nowiki>{{+}}</" + String("") + "nowiki></code>. Use <code>;</code> to specify displayed text if you want it to be different from the one inserted; for example, <code><nowiki><code>+</code>;<code /></" + String("") + "nowiki></code>. Use <code><nowiki>\\</" + String("") + "nowiki></code> before the aforementioned characters to insert them as is; for example, <code><nowiki>2\\+2</" + String("") + "nowiki></code>. The buttons can be dragged and dropped.", "sd-notifications": "Ordinary notifications", "sd-notifications-radio-all": "Notify me about replies to my comments and comments in sections that I watch", "sd-notifications-radio-tome": "Notify me about replies to my comments only", "sd-notifications-radio-none": "Don't notify me", "sd-notifications-help": "Notifications are small popups in the top right corner of the page.", "sd-notificationsblacklist": "Don't notify about comments of these users", "sd-notificationsblacklist-multiselect-placeholder": "Add a user", "sd-showtoolbar": "Show the editing toolbar", "sd-signatureprefix": "Signature prefix", "sd-signatureprefix-help": "Text that is added before the signature, <em>including</em> a space at the beginning if needed.", "sd-modifytoc": "Modify the table of contents", "sd-modifytoc-help": "Show new comments and sections and highlight watched sections.", "sd-usetemplatedata": "Use TemplateData in templates autocomplete", "sd-usetemplatedata-help": "Hold Shift while choosing a template from the autocomplete menu to insert the template's required and suggested parameters as well.", "sd-watchonreply": "Watch the page that I comment on", "sd-watchsectiononreply": "Watch the section that I comment in", "sd-watchsectiononreply-help": "This affects notifications and bolding in the watchlist.", "ewsd-title": "Edit watched sections list", "ewsd-save": "Save", "ewsd-saved": "The watched sections list has been successfully saved.", "ewsd-error-maxsize": "Couldn't update the settings: the size of the watched sections list exceeds the maximum size. Reduce the size of the list to fix this.", "ewsd-error-processing": "An error occurred while processing the watched sections list.", "ewsd-close-confirm": "The watched sections list wasn't saved. Are you sure you want to close the window?", "ewsd-close-confirm-yes": "Close", "ewsd-close-confirm-no": "Cancel", "msd-title": "Move topic", "msd-move": "Move", "msd-reload": "Reload", "msd-targetpage": "Enter the name of the discussion page to move the topic to:", "msd-keeplink": "Keep a link to the new location", "msd-summaryending": "Edit summary (will be added to the standard one)", "msd-error-wrongpage": "Wrong page.", "msd-error-sourcepagedeleted": "The current page was deleted.", "msd-error-invalidpagename": "Invalid page name.", "msd-error-editconflict-retry": "Just click \"{{int:ooui-dialog-process-retry}}\".", "msd-error-editingtargetpage": "Couldn't edit the target page.", "msd-error-editingsourcepage": "Couldn't edit the source page. You will have to edit it manually.", "msd-moved": "The topic has been successfully moved. You may reload the page or go to [[$1|the page where the topic was moved to]].", "msd-bottom": "The code may be different if the page would be updated while the window is idle.", "move-sourcepagecode": "''Moved to [[$1]]. $2''", "move-targetpagecode": "''Moved from [[$1]]. $2''", "error-loaddata": "{{int:convenient-discussions-script-name}}: Couldn't load the data required by the script.", "error-needreloadpage": "API error. Please <span class=\"cd-notification-reloadPage\">reload the page</span> and try again.", "error-processpage": "{{int:convenient-discussions-script-name}}: Couldn't process the page.", "error-settings-load": "Couldn't load the settings from the server.", "error-settings-save": "Couldn't save the settings to the server.", "error-reloadpage": "Couldn't reload the page.", "error-reloadpage-saved": "The page was saved, but couldn't reload the page.", "error-api": "API error: $1.", "error-network": "Network error.", "error-nodata": "The server response lacks the requested data.", "error-unknown": "Unknown error.", "error-javascript": "A JavaScript error occurred. See the details in the JavaScript console (F12 → Console).", "error-locatecomment": "Couldn't locate the comment in the code. This may be caused by the complexity of the comment code, the script flaw of the fact that the comment was deleted or heavily edited. You can try to <span class=\"cd-message-editSection\">[$1 edit the source the standard way]</span> or <span class=\"cd-message-reloadPage\">reload the page</span>.", "error-locatesection": "Couldn't locate the section in the code. This may be caused by the complexity of the section's first comment code, the script flaw of the fact that the section was deleted. You can try to <span class=\"cd-message-editPage\">[$1 edit the page source the standard way]</span> or <span class=\"cd-message-reloadPage\">reload the page</span>.", "error-spamblacklist": "You are trying to add a URL with the domain name $1 that is blacklisted. The page was not edited.", "error-titleblacklist": "The page name is blacklisted. The page was not edited.", "error-abusefilter": "Your edit was automatically rejected by abuse filter \"$1\".", "error-editconflict": "Edit conflict.", "error-blocked": "You or your IP address is blocked from editing. The page was not edited.", "error-pagedeleted": "The page was deleted.", "error-pagenotedited": "The page was not edited.", "error-diffnotfound": "Couldn't find the edit that added this comment.", "error-diffnotfound-history": "You can look for it in the [$1 revision history] for yourself.", "error-elementhidden": "The element is hidden. Can't scroll to it.", "error-purgecache": "Couldn't purge the cache of this page.", "wl-button-switchinteresting-tooltip": "Show only comments in sections that I watch and comments addressed to me. (Note: detection is based on edit summaries, so some edits may be missing)", "wl-button-editwatchedsections-tooltip": "Edit the list of sections that I watch", "wl-button-settings-tooltip": "Convenient Discussions settings", "lp-comment": "comment", "lp-comment-tooltip": "Go to comment", "lp-comment-toyou": "the comment is addressed to you", "lp-comment-watchedsection": "you are watching this section", "bullet": "<b>•</b>", "loading-ellipsis": "Loading…", "addtopic": "Add topic", "addtopicbutton-tooltip": "Open in a new tab to create a new topic on the standard page, not in Convenient Discussions", "copy": "Copy" }; "
"'use strict'; module.exports = function get_html_translation_table(table, quoteStyle) { // eslint-disable-line camelcase // discuss at: http://locutus.io/php/get_html_translation_table/ // original by: Philip Peterson // revised by: Kevin van Zonneveld (http://kvz.io) // bugfixed by: noname // bugfixed by: Alex // bugfixed by: Marco // bugfixed by: madipta // bugfixed by: Brett Zamir (http://brett-zamir.me) // bugfixed by: T.Wild // improved by: KELAN // improved by: Brett Zamir (http://brett-zamir.me) // input by: Frank Forte // input by: Ratheous // note 1: It has been decided that we're not going to add global // note 1: dependencies to Locutus, meaning the constants are not // note 1: real constants, but strings instead. Integers are also supported if someone // note 1: chooses to create the constants themselves. // example 1: get_html_translation_table('HTML_SPECIALCHARS') // returns 1: {'"': '&quot;', '&': '&amp;', '<': '&lt;', '>': '&gt;'} var entities = {}; var hashMap = {}; var decimal; var constMappingTable = {}; var constMappingQuoteStyle = {}; var useTable = {}; var useQuoteStyle = {}; // Translate arguments constMappingTable[0] = 'HTML_SPECIALCHARS'; constMappingTable[1] = 'HTML_ENTITIES'; constMappingQuoteStyle[0] = 'ENT_NOQUOTES'; constMappingQuoteStyle[2] = 'ENT_COMPAT'; constMappingQuoteStyle[3] = 'ENT_QUOTES'; useTable = !isNaN(table) ? constMappingTable[table] : table ? table.toUpperCase() : 'HTML_SPECIALCHARS'; useQuoteStyle = !isNaN(quoteStyle) ? constMappingQuoteStyle[quoteStyle] : quoteStyle ? quoteStyle.toUpperCase() : 'ENT_COMPAT'; if (useTable !== 'HTML_SPECIALCHARS' && useTable !== 'HTML_ENTITIES') { throw new Error('Table: ' + useTable + ' not supported'); } entities['38'] = '&amp;'; if (useTable === 'HTML_ENTITIES') { entities['160'] = '&nbsp;'; entities['161'] = '&iexcl;'; entities['162'] = '&cent;'; entities['163'] = '&pound;'; entities['164'] = '&curren;'; entities['165'] = '&yen;'; entities['166'] = '&brvbar;'; entities['167'] = '&sect;'; entities['168'] = '&uml;'; entities['169'] = '&copy;'; entities['170'] = '&ordf;'; entities['171'] = '&laquo;'; entities['172'] = '&not;'; entities['173'] = '&shy;'; entities['174'] = '&reg;'; entities['175'] = '&macr;'; entities['176'] = '&deg;'; entities['177'] = '&plusmn;'; entities['178'] = '&sup2;'; entities['179'] = '&sup3;'; entities['180'] = '&acute;'; entities['181'] = '&micro;'; entities['182'] = '&para;'; entities['183'] = '&middot;'; entities['184'] = '&cedil;'; entities['185'] = '&sup1;'; entities['186'] = '&ordm;'; entities['187'] = '&raquo;'; entities['188'] = '&frac14;'; entities['189'] = '&frac12;'; entities['190'] = '&frac34;'; entities['191'] = '&iquest;'; entities['192'] = '&Agrave;'; entities['193'] = '&Aacute;'; entities['194'] = '&Acirc;'; entities['195'] = '&Atilde;'; entities['196'] = '&Auml;'; entities['197'] = '&Aring;'; entities['198'] = '&AElig;'; entities['199'] = '&Ccedil;'; entities['200'] = '&Egrave;'; entities['201'] = '&Eacute;'; entities['202'] = '&Ecirc;'; entities['203'] = '&Euml;'; entities['204'] = '&Igrave;'; entities['205'] = '&Iacute;'; entities['206'] = '&Icirc;'; entities['207'] = '&Iuml;'; entities['208'] = '&ETH;'; entities['209'] = '&Ntilde;'; entities['210'] = '&Ograve;'; entities['211'] = '&Oacute;'; entities['212'] = '&Ocirc;'; entities['213'] = '&Otilde;'; entities['214'] = '&Ouml;'; entities['215'] = '&times;'; entities['216'] = '&Oslash;'; entities['217'] = '&Ugrave;'; entities['218'] = '&Uacute;'; entities['219'] = '&Ucirc;'; entities['220'] = '&Uuml;'; entities['221'] = '&Yacute;'; entities['222'] = '&THORN;'; entities['223'] = '&szlig;'; entities['224'] = '&agrave;'; entities['225'] = '&aacute;'; entities['226'] = '&acirc;'; entities['227'] = '&atilde;'; entities['228'] = '&auml;'; entities['229'] = '&aring;'; entities['230'] = '&aelig;'; entities['231'] = '&ccedil;'; entities['232'] = '&egrave;'; entities['233'] = '&eacute;'; entities['234'] = '&ecirc;'; entities['235'] = '&euml;'; entities['236'] = '&igrave;'; entities['237'] = '&iacute;'; entities['238'] = '&icirc;'; entities['239'] = '&iuml;'; entities['240'] = '&eth;'; entities['241'] = '&ntilde;'; entities['242'] = '&ograve;'; entities['243'] = '&oacute;'; entities['244'] = '&ocirc;'; entities['245'] = '&otilde;'; entities['246'] = '&ouml;'; entities['247'] = '&divide;'; entities['248'] = '&oslash;'; entities['249'] = '&ugrave;'; entities['250'] = '&uacute;'; entities['251'] = '&ucirc;'; entities['252'] = '&uuml;'; entities['253'] = '&yacute;'; entities['254'] = '&thorn;'; entities['255'] = '&yuml;'; } if (useQuoteStyle !== 'ENT_NOQUOTES') { entities['34'] = '&quot;'; } if (useQuoteStyle === 'ENT_QUOTES') { entities['39'] = '&#39;'; } entities['60'] = '&lt;'; entities['62'] = '&gt;'; // ascii decimals to real symbols for (decimal in entities) { if (entities.hasOwnProperty(decimal)) { hashMap[String.fromCharCode(decimal)] = entities[decimal]; } } return hashMap; }; //# sourceMappingURL=get_html_translation_table.js.map"
"var api = require("!../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js"); var content = require("!!../../node_modules/css-loader/dist/cjs.js!../../node_modules/postcss-loader/src/index.js??ref--5-2!../../node_modules/less-loader/dist/cjs.js!./tribute.less"); content = content.__esModule ? content.default : content; if (typeof content === 'string') { content = [[module.id, content, '']]; } var options = {}; options.insert = "head"; options.singleton = false; var update = api(content, options); module.exports = content.locals || {};"
"// Imports var ___CSS_LOADER_API_IMPORT___ = require("../../node_modules/css-loader/dist/runtime/api.js"); exports = ___CSS_LOADER_API_IMPORT___(false); // Module exports.push([module.id, ".tribute-container{position:absolute;top:0;left:0;height:auto;max-height:500px;max-width:500px;overflow:auto;display:block;z-index:999999;font-size:14px;margin-top:3px;line-height:20px;background-color:#fff;box-shadow:0 2px 2px 0 rgba(0,0,0,.25);border:1px solid #a2a9b1}.tribute-container.tribute-rtl{left:auto;right:0}.tribute-container ul{margin:0;padding:0;list-style:none}.tribute-container li{padding:5px 7px;cursor:pointer;margin:0}.tribute-container li.highlight{background-color:rgba(0,23,70,.086)}.tribute-container li.no-match{cursor:default}", ""]); // Exports module.exports = exports; "
"'use strict'; // http://stackoverflow.com/questions/10343913/how-to-create-a-web-worker-from-a-string var URL = window.URL || window.webkitURL; module.exports = function (content, url) { try { try { var blob; try { // BlobBuilder = Deprecated, but widely implemented var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder; blob = new BlobBuilder(); blob.append(content); blob = blob.getBlob(); } catch (e) { // The proposed API blob = new Blob([content]); } return new Worker(URL.createObjectURL(blob)); } catch (e) { return new Worker('data:application/javascript,' + encodeURIComponent(content)); } } catch (e) { if (!url) { throw Error('Inline worker is not supported'); } return new Worker(url); } };"
"// Imports var ___CSS_LOADER_API_IMPORT___ = require("../../node_modules/css-loader/dist/runtime/api.js"); exports = ___CSS_LOADER_API_IMPORT___(false); // Module exports.push([module.id, "a:not([href]){cursor:pointer}.cd-autocompleteTypesMultiselect .oo-ui-multioptionWidget.oo-ui-widget-enabled{cursor:default}.cd-autocompleteTypesMultiselect .oo-ui-checkboxMultioptionWidget,.cd-autocompleteTypesMultiselect .oo-ui-checkboxMultioptionWidget .oo-ui-checkboxInputWidget,.cd-autocompleteTypesMultiselect .oo-ui-checkboxMultioptionWidget.oo-ui-labelElement>.oo-ui-labelElement-label{display:inline-block}.cd-autocompleteTypesMultiselect .oo-ui-checkboxMultioptionWidget .oo-ui-checkboxInputWidget{width:auto}.cd-autocompleteTypesMultiselect .oo-ui-checkboxMultioptionWidget:not(:last-child){margin-right:1em}", ""]); // Exports module.exports = exports; "
"var api = require("!../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js"); var content = require("!!../../node_modules/css-loader/dist/cjs.js!../../node_modules/postcss-loader/src/index.js??ref--5-2!../../node_modules/less-loader/dist/cjs.js!./Comment.less"); content = content.__esModule ? content.default : content; if (typeof content === 'string') { content = [[module.id, content, '']]; } var options = {}; options.insert = "head"; options.singleton = false; var update = api(content, options); module.exports = content.locals || {};"
"// Imports var ___CSS_LOADER_API_IMPORT___ = require("../../node_modules/css-loader/dist/runtime/api.js"); exports = ___CSS_LOADER_API_IMPORT___(false); // Module exports.push([module.id, ".cd-commentPart-first{margin-top:.5em}.cd-commentPart-last{margin-bottom:.5em}ol>li.cd-commentPart-first{margin-top:0}ol>li.cd-commentPart-last{margin-bottom:.1em}.cd-commentLevel.cd-commentLevel:not(ol){list-style-type:none;list-style-image:none;margin:0}.mw-content-ltr .cd-commentLevel:not(ol),.mw-content-rtl .mw-content-ltr .cd-commentLevel:not(ol){padding-left:1em;padding-right:0;margin-left:1em;margin-right:0;border-left:1px solid #c8ccd1;border-right:0}.mw-content-ltr .mw-content-rtl .cd-commentLevel:not(ol),.mw-content-rtl .cd-commentLevel:not(ol){padding-left:0;padding-right:1em;margin-left:0;margin-right:1em;border-left:0;border-right:1px solid #c8ccd1}.mw-content-ltr dl.cd-commentLevel>dd,.mw-content-rtl .mw-content-ltr dl.cd-commentLevel>dd,dl.cd-commentLevel>dd{margin-left:0}.mw-content-ltr .mw-content-rtl dl.cd-commentLevel>dd,.mw-content-rtl dl.cd-commentLevel>dd{margin-right:0}.cd-button-pending.cd-button-pending.cd-button-pending .oo-ui-buttonElement-button{cursor:wait}", ""]); // Exports module.exports = exports; "
"var api = require("!../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js"); var content = require("!!../../node_modules/css-loader/dist/cjs.js!../../node_modules/postcss-loader/src/index.js??ref--5-2!../../node_modules/less-loader/dist/cjs.js!./CommentForm.less"); content = content.__esModule ? content.default : content; if (typeof content === 'string') { content = [[module.id, content, '']]; } var options = {}; options.insert = "head"; options.singleton = false; var update = api(content, options); module.exports = content.locals || {};"
"// Imports var ___CSS_LOADER_API_IMPORT___ = require("../../node_modules/css-loader/dist/runtime/api.js"); exports = ___CSS_LOADER_API_IMPORT___(false); // Module exports.push([module.id, ".cd-commentForm{display:flow-root;-ms-display:grid;margin:.5em 0;font-size:14px}.cd-commentForm .cd-headlineInput{margin-bottom:.214286em}.cd-commentForm .oo-ui-textInputWidget{max-width:none}.cd-commentForm .cd-summaryInput{margin-top:.214286em}.cd-commentForm .cd-checkboxesContainer{margin-top:.5em}.cd-commentForm .cd-checkboxesContainer .oo-ui-fieldLayout{margin-right:1em}.cd-commentForm .cd-checkboxesContainer .oo-ui-fieldLayout:last-child{margin-right:0}.cd-commentForm .cd-buttonsContainer{margin-top:.5em;display:flow-root;-ms-display:grid}.cd-commentForm .cd-leftButtonsContainer{float:left}.cd-commentForm .cd-rightButtonsContainer{float:right}.cd-commentForm .oo-ui-buttonElement-framed>.oo-ui-buttonElement-button{vertical-align:middle}.cd-commentForm .cd-settingsButton{margin:-1em 0 0}.cd-commentForm table.diff{margin-bottom:.5em}.cd-commentForm .wikiEditor-ui-left{float:none}.cd-commentForm .wikiEditor-ui-toolbar{z-index:1}.cd-commentForm-signature{opacity:.67}.cd-commentForm-dummyElement{height:0}.cd-commentForm .oo-ui-textInputWidget .oo-ui-inputWidget-input{border-radius:0}.cd-commentForm-addSection,.cd-commentForm-addSubsection,.cd-commentForm-sectionOpeningComment{margin-top:1em}.ltr .cd-commentForm .cd-checkboxesContainer{direction:ltr;text-align:left}.ltr .cd-commentForm .cd-checkboxesContainer .oo-ui-fieldLayout{margin-right:1em;margin-left:0}.ltr .cd-commentForm .cd-checkboxesContainer .oo-ui-fieldLayout:last-child{margin-right:0}.ltr .cd-commentForm .cd-buttonsContainer{direction:ltr}.ltr .cd-commentForm .cd-leftButtonsContainer{float:left}.ltr .cd-commentForm .cd-rightButtonsContainer{float:right}.rtl .cd-commentForm .cd-checkboxesContainer{direction:rtl;text-align:right}.rtl .cd-commentForm .cd-checkboxesContainer .oo-ui-fieldLayout{margin-left:1em;margin-right:0}.rtl .cd-commentForm .cd-checkboxesContainer .oo-ui-fieldLayout:last-child{margin-left:0}.rtl .cd-commentForm .cd-buttonsContainer{direction:rtl}.rtl .cd-commentForm .cd-leftButtonsContainer{float:right}.rtl .cd-commentForm .cd-rightButtonsContainer{float:left}ol>li.cd-commentForm{display:list-item;-ms-display:list-item}.cd-replyWrapper{margin-top:.5em}.cd-commentInput{margin-top:1px;border:1px solid #a2a9b1}.cd-commentInput .wikiEditor-ui .wikiEditor-ui-view{border:0}.cd-commentInput .oo-ui-inputWidget-input.oo-ui-inputWidget-input{width:calc(100% + 2px);margin:-1px;position:relative}.cd-commentInput.oo-ui-widget-disabled+.cd-insertButtons,.cd-commentInput.oo-ui-widget-disabled .wikiEditor-ui-top{pointer-events:none}body:not(.skin-monobook) .cd-commentInput.oo-ui-textInputWidget.oo-ui-widget-disabled,body:not(.skin-monobook) .cd-commentInput.oo-ui-textInputWidget.oo-ui-widget-disabled+.cd-insertButtons,body:not(.skin-monobook) .cd-commentInput.oo-ui-textInputWidget.oo-ui-widget-disabled .oo-ui-inputWidget-input,body:not(.skin-monobook) .cd-commentInput.oo-ui-textInputWidget.oo-ui-widget-disabled .wikiEditor-ui-top{border-color:#c8ccd1}.cd-previewArea{margin-top:.5em;padding:.5em .75em;background-color:#f8f9fa;display:flow-root;-ms-display:grid}.cd-previewArea>.mw-parser-output>:first-child{margin-top:0}.cd-previewArea>.mw-parser-output>:last-child{margin-bottom:0}.cd-previewArea .mw-editsection,.cd-previewArea .mw-headline-number{display:none}.cd-previewArea:empty{margin:0;padding:0}.cd-previewArea-above{margin-top:0;margin-bottom:.5em;width:calc(100% - 1.5em)}.cd-previewArea-indentedComment>.mw-parser-output>dl>dd{margin-left:0;margin-bottom:0}.cd-previewArea-label{color:#72777d;margin-bottom:.5em}.cd-messageArea{width:100%}.cd-messageArea,.cd-previewArea{position:relative;clear:both}.cd-messageArea .cd-closeButton,.cd-previewArea .cd-closeButton{background-color:#f8f9fa}.cd-messageArea:hover .cd-closeButton,.cd-previewArea:hover .cd-closeButton{opacity:1}.cd-messageArea,.cd-previewArea-above{float:left}.cd-messageArea+*,.cd-previewArea-above+*{clear:both}.cd-closeButton{position:absolute;z-index:1;top:0;right:0;width:20px;height:20px;background-image:url(https://upload.wikimedia.org/wikipedia/commons/1/18/OOjs_UI_icon_close-ltr.svg);background-position:50%;background-repeat:no-repeat;opacity:0;transition:opacity .2s ease-in}.cd-message{margin-bottom:.5em}.cd-popupsOverlay{position:absolute;top:0;left:0;z-index:5;font-size:14px}.cd-insertButtons{background-color:#f8f9fa;border:1px solid #a2a9b1;border-top:0 solid #a2a9b1;font-size:.928571em;line-height:1.384616em}.cd-insertButtons:after{display:block;content:\"\";clear:both}.cd-insertButtons:empty{border:0}.cd-insertButtons-item{color:#222;padding:2px .5em 3px;white-space:nowrap;display:block}.cd-insertButtons-item:focus,.cd-insertButtons-item:hover{text-decoration:none;color:#222;background-color:rgba(0,23,70,.086)}.ltr .cd-insertButtons-item{float:left}.rtl .cd-insertButtons-item{float:right}.cd-toolbarPlaceholder{background-color:#f8f9fa;border:solid #a2a9b1;border-width:1px 1px 0;height:32px;margin:1px 0 -1px}.cd-commentForm-edit .cd-toolbarPlaceholder{border-color:#c8ccd1}.tribute-container.cd-autocompleteContainer li.highlight{font-weight:400}", ""]); // Exports module.exports = exports; "
"var api = require("!../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js"); var content = require("!!../../node_modules/css-loader/dist/cjs.js!../../node_modules/postcss-loader/src/index.js??ref--5-2!../../node_modules/less-loader/dist/cjs.js!./Section.less"); content = content.__esModule ? content.default : content; if (typeof content === 'string') { content = [[module.id, content, '']]; } var options = {}; options.insert = "head"; options.singleton = false; var update = api(content, options); module.exports = content.locals || {};"
"// Imports var ___CSS_LOADER_API_IMPORT___ = require("../../node_modules/css-loader/dist/runtime/api.js"); exports = ___CSS_LOADER_API_IMPORT___(false); // Module exports.push([module.id, ".cd-sectionLinkWrapper:before{content:\" | \";color:#54595d}.cd-sectionButtonContainer{margin-top:.5em}.cd-replyWrapper:not(.cd-commentForm){margin-left:-1px}.mw-content-ltr .cd-replyWrapper:not(.cd-commentForm){margin-left:-1px;margin-right:0}.mw-content-rtl .cd-replyWrapper:not(.cd-commentForm){margin-right:-1px;margin-left:0}ol .cd-sectionButton{margin-top:-2px}.cd-refreshButtonContainer .oo-ui-labelElement-label{white-space:normal}.ltr .mw-content-rtl .mw-editsection:before{content:\"\\200B\\200E\"}.rtl .mw-content-ltr .mw-editsection:before{content:\"\\200B\\200F\"}.client-js .ltr .mw-content-rtl .mw-editsection-bracket:first-of-type,.client-js .rtl .mw-content-ltr .mw-editsection-bracket:last-of-type{margin-right:.25em;margin-left:0}.client-js .ltr .mw-content-rtl .mw-editsection-bracket:last-of-type,.client-js .rtl .mw-content-ltr .mw-editsection-bracket:first-of-type{margin-left:.25em;margin-right:0}.cd-moveSectionDialog-code{margin:1em 0}.cd-moveSectionDialog-codeNote{font-size:95%}", ""]); // Exports module.exports = exports; "
"var api = require("!../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js"); var content = require("!!../../node_modules/css-loader/dist/cjs.js!../../node_modules/postcss-loader/src/index.js??ref--5-2!../../node_modules/less-loader/dist/cjs.js!./commentLayers.less"); content = content.__esModule ? content.default : content; if (typeof content === 'string') { content = [[module.id, content, '']]; } var options = {}; options.insert = "head"; options.singleton = false; var update = api(content, options); module.exports = content.locals || {};"
"// Imports var ___CSS_LOADER_API_IMPORT___ = require("../../node_modules/css-loader/dist/runtime/api.js"); exports = ___CSS_LOADER_API_IMPORT___(false); // Module exports.push([module.id, ".cd-commentUnderlay{position:absolute;z-index:-1}.cd-commentUnderlay-new{background-color:var(--cd-comment-new-color)}.cd-commentUnderlay-own{background-color:var(--cd-comment-own-color)}.cd-commentUnderlay-deleted{background-color:var(--cd-comment-deleted-color)}.cd-commentUnderlay-focused{background-color:var(--cd-comment-focused-color)}.cd-commentOverlay{position:absolute;display:none;pointer-events:none;justify-content:flex-end;line-height:1.4285714em}.cd-commentOverlay-focused{display:flex}.cd-commentOverlay-innerWrapper{position:absolute;z-index:1;bottom:0;font-size:14px;pointer-events:all;display:flex;flex-direction:row}.cd-commentOverlay-gradient{width:1.4em;display:inline-block;padding:1px 1px 2px;-moz-user-select:none;-webkit-user-select:none;user-select:none}.cd-commentOverlay-content{display:inline-flex;padding:0 .5em 1px;background-color:var(--cd-comment-focused-color);flex-direction:row}.cd-commentOverlay .cd-button.oo-ui-buttonElement-frameless.oo-ui-widget-enabled>.oo-ui-buttonElement-button:active,.cd-commentOverlay .cd-button.oo-ui-buttonElement-frameless.oo-ui-widget-enabled>.oo-ui-buttonElement-button:hover{background-color:initial}.cd-commentOverlay .oo-ui-buttonElement-frameless.oo-ui-iconElement:first-child{margin-left:0}.ltr .cd-commentOverlay .oo-ui-buttonWidget{margin-right:0}.ltr .cd-commentOverlay .cd-commentButton:not(:first-child){margin-left:1em}.rtl .cd-commentOverlay .oo-ui-buttonWidget{margin-left:0}.rtl .cd-commentOverlay .cd-commentButton:not(:first-child){margin-right:1em}body:not(.skin-monobook) .cd-commentButton-icon.oo-ui-buttonElement-frameless.oo-ui-iconElement>.oo-ui-buttonElement-button{padding-top:1.4285714em;padding-left:1.4285714em;min-width:unset}body:not(.skin-monobook) .cd-commentButton-icon.oo-ui-buttonElement-frameless.oo-ui-iconElement>.oo-ui-buttonElement-button>.oo-ui-iconElement-icon{left:0}.cd-commentLayersContainerParent-relative{position:relative;z-index:0;overflow:hidden!important}", ""]); // Exports module.exports = exports; "
"var api = require("!../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js"); var content = require("!!../../node_modules/css-loader/dist/cjs.js!../../node_modules/postcss-loader/src/index.js??ref--5-2!../../node_modules/less-loader/dist/cjs.js!./navPanel.less"); content = content.__esModule ? content.default : content; if (typeof content === 'string') { content = [[module.id, content, '']]; } var options = {}; options.insert = "head"; options.singleton = false; var update = api(content, options); module.exports = content.locals || {};"
"// Imports var ___CSS_LOADER_API_IMPORT___ = require("../../node_modules/css-loader/dist/runtime/api.js"); exports = ___CSS_LOADER_API_IMPORT___(false); // Module exports.push([module.id, "#cd-navPanel{position:fixed;top:41.5%;left:0;z-index:5;width:34px;background-color:#fff;border:1px solid #a2a9b1;border-left-width:0;opacity:.695;font-size:14px;line-height:1.2;color:#000;-moz-user-select:none;-webkit-user-select:none;user-select:none}#cd-navPanel:hover{opacity:1}#cd-navPanel-refreshButton{padding:4px;width:26px;height:26px;background-image:url(https://upload.wikimedia.org/wikipedia/commons/1/17/OOjs_UI_icon_reload.svg);background-size:20px 20px}#cd-navPanel-refreshButton:not(:empty){background-image:none;display:flex;justify-content:center;align-items:center;font-weight:700}#cd-navPanel-previousButton{background-image:url(https://upload.wikimedia.org/wikipedia/commons/1/10/OOjs_UI_icon_collapse.svg);background-size:16px 16px}#cd-navPanel-nextButton{background-image:url(https://upload.wikimedia.org/wikipedia/commons/9/90/OOjs_UI_icon_expand.svg);background-size:16px 16px}#cd-navPanel-firstUnseenButton{height:17px;padding:7px 0}#cd-navPanel-commentFormButton{background-image:url(https://upload.wikimedia.org/wikipedia/commons/a/ac/OOjs_UI_icon_ongoingConversation-ltr.svg);background-size:16px 16px;background-position-y:54%}.sitedir-ltr #cd-navPanel{left:0;right:unset;border-left-width:0;border-right-width:1px}.sitedir-ltr.rtl #cd-navPanel,.sitedir-rtl #cd-navPanel{right:0;left:unset;border-left-width:1px;border-right-width:0}.cd-navPanel-button{display:block;text-align:center;background-position:50%;background-repeat:no-repeat;cursor:pointer}.cd-navPanel-button:hover{background-color:#eaecf0}.cd-navPanel-button:not(:first-child){position:relative;height:31px;margin-top:1px}.cd-navPanel-button:not(:first-child):before{position:absolute;top:-1px;left:4px;margin:0 auto 1px;width:26px;height:0;border-top:1px solid #a2a9b1;content:\"\"}.cd-navPanel-refreshButton-interesting{color:#7d00cc}", ""]); // Exports module.exports = exports; "
"var api = require("!../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js"); var content = require("!!../../node_modules/css-loader/dist/cjs.js!../../node_modules/postcss-loader/src/index.js??ref--5-2!../../node_modules/less-loader/dist/cjs.js!./skin.less"); content = content.__esModule ? content.default : content; if (typeof content === 'string') { content = [[module.id, content, '']]; } var options = {}; options.insert = "head"; options.singleton = false; var update = api(content, options); module.exports = content.locals || {};"
"// Imports var ___CSS_LOADER_API_IMPORT___ = require("../../node_modules/css-loader/dist/runtime/api.js"); exports = ___CSS_LOADER_API_IMPORT___(false); // Module exports.push([module.id, ".skin-monobook .cd-commentUnderlay{z-index:-1}.skin-monobook .cd-commentOverlay-innerWrapper{z-index:2}.skin-monobook .cd-commentButton.oo-ui-buttonElement.oo-ui-labelElement>.oo-ui-buttonElement-button>.oo-ui-labelElement-label{line-height:1.172em}.skin-monobook .cd-commentButton-icon.oo-ui-buttonElement-frameless.oo-ui-iconElement>.oo-ui-buttonElement-button{padding:0}.skin-monobook .cd-commentButton-icon.oo-ui-buttonElement-frameless.oo-ui-iconElement>.oo-ui-buttonElement-button>.oo-ui-iconElement-icon{margin:0;width:20px;height:20px}.skin-monobook .cd-commentInput{border:1px solid #ccc}.skin-monobook .cd-commentInput .wikiEditor-ui-toolbar{z-index:auto}.skin-monobook .cd-commentInput.oo-ui-textInputWidget.oo-ui-widget-disabled,.skin-monobook .cd-commentInput.oo-ui-textInputWidget.oo-ui-widget-disabled .oo-ui-inputWidget-input,.skin-monobook .cd-commentInput.oo-ui-textInputWidget.oo-ui-widget-disabled .wikiEditor-ui-top,.skin-monobook .cd-insertButtons,.skin-monobook .cd-toolbarPlaceholder{border-color:#ccc}.skin-monobook .cd-loadingPopup{width:15.5em}.skin-timeless .mw-body-content{position:relative}.skin-timeless .cd-loadingPopup{width:15em}.skin-timeless .cd-loadingPopup-logo-partBackground{background-color:#eaecf0!important}.skin-modern #mw-content-text{position:relative}.skin-modern .cd-loadingPopup{width:18.2em}", ""]); // Exports module.exports = exports; "
"var api = require("!../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js"); var content = require("!!../../node_modules/css-loader/dist/cjs.js!../../node_modules/postcss-loader/src/index.js??ref--5-2!../../node_modules/less-loader/dist/cjs.js!./talkPage.less"); content = content.__esModule ? content.default : content; if (typeof content === 'string') { content = [[module.id, content, '']]; } var options = {}; options.insert = "head"; options.singleton = false; var update = api(content, options); module.exports = content.locals || {};"
"// Imports var ___CSS_LOADER_API_IMPORT___ = require("../../node_modules/css-loader/dist/runtime/api.js"); exports = ___CSS_LOADER_API_IMPORT___(false); // Module exports.push([module.id, ".cd-commentButton.oo-ui-buttonElement-frameless.oo-ui-labelElement>.oo-ui-buttonElement-button,.cd-sectionButton.oo-ui-buttonElement-frameless.oo-ui-labelElement>.oo-ui-buttonElement-button{padding:0}.cd-commentButton.oo-ui-buttonElement-frameless.oo-ui-labelElement:first-child,.cd-sectionButton.oo-ui-buttonElement-frameless.oo-ui-labelElement:first-child{margin-left:0;margin-right:0}.cd-button.oo-ui-buttonElement>.oo-ui-buttonElement-button{min-height:unset}ol>.cd-replyWrapper:not(.cd-replyWrapper-hasCommentForm){list-style-type:none}.action-view .cd-hide,.cd-hidden:not(#cd-notExistingClass){display:none}div.cd-show,p.cd-show{display:block!important}span.cd-show{display:inline!important}.cd-destructiveText{color:#d33}.cd-loadingPopup{position:fixed;bottom:0;width:10em;z-index:111}.cd-loadingPopup-logo{display:block;margin:0 auto 2em;width:55px;position:relative}.cd-loadingPopup-logo-partBackground{position:absolute;left:8px;top:6px;width:27px;height:21px;z-index:-1}.ltr .cd-loadingPopup{left:0}.rtl .cd-loadingPopup{right:0}@media screen and (min-width:982px){.cd-loadingPopup{width:11em}}.skin-vector:not(.skin-vector-legacy) .cd-loadingPopup{width:0}.sitedir-ltr.skin-vector:not(.skin-vector-legacy) .cd-loadingPopup{margin-left:2em}.sitedir-rtl.skin-vector:not(.skin-vector-legacy) .cd-loadingPopup{margin-right:2em}.cd-toc-watched{font-weight:700}.cd-toc-notRenderedCommentList .cd-toc-bullet,.cd-toc-notRenderedCommentList .cd-toc-more,.cd-toc-notRenderedCommentList a,.cd-toc-notRenderedSection a{color:#72777d}.cd-toc-more{cursor:help}.cd-toc-hiddenTocNumber{visibility:hidden}.cd-editMark{margin-left:1em;font-size:85%;color:#72777d}.cd-link-pending.cd-link-pending{opacity:.5;cursor:wait;text-decoration:none}.cd-copyLinkDialog .oo-ui-actionFieldLayout.oo-ui-fieldLayout-align-top,.cd-copyLinkDialog .oo-ui-fieldLayout.oo-ui-labelElement.oo-ui-fieldLayout-align-top>.oo-ui-fieldLayout-body>.oo-ui-fieldLayout-header,.cd-copyLinkDialog .oo-ui-textInputWidget{max-width:60em}.cd-copyLinkDialog .oo-ui-textInputWidget input{height:2.20779221em}.cd-diffView-diff{margin:1em 0}.cd-diffView-nextDiffLink{float:right;margin-left:1em}.cd-commentDiffView-below{margin:.5em 0 0}#cd-currentSection{position:fixed;top:0;left:0;z-index:5;font-size:12px;padding:7px 9px;line-height:1.2;list-style-type:none;list-style-image:none;margin:0;color:#202122;overflow-wrap:break-word}#cd-currentSection:empty{padding:0}.cd-currentSection-level{margin:0 0 .25em;cursor:pointer}.cd-currentSection-level:last-child{margin-bottom:0}.cd-currentSection-level-1{margin-left:.75em}.cd-currentSection-level-2{margin-left:1.5em}.cd-currentSection-level-3{margin-left:2.25em}.cd-currentSection-level-4{margin-left:3em}.cd-currentSection-level-5{margin-left:3.75em}.cd-currentUserLink{background-color:#efd7ff}", ""]); // Exports module.exports = exports; "
"var api = require("!../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js"); var content = require("!!../../node_modules/css-loader/dist/cjs.js!../../node_modules/postcss-loader/src/index.js??ref--5-2!../../node_modules/less-loader/dist/cjs.js!./logPages.less"); content = content.__esModule ? content.default : content; if (typeof content === 'string') { content = [[module.id, content, '']]; } var options = {}; options.insert = "head"; options.singleton = false; var update = api(content, options); module.exports = content.locals || {};"
"// Imports var ___CSS_LOADER_API_IMPORT___ = require("../../node_modules/css-loader/dist/runtime/api.js"); exports = ___CSS_LOADER_API_IMPORT___(false); // Module exports.push([module.id, ".cd-commentLink-interesting a{font-weight:700}.cd-watchlistMenu{display:inline-block;border:1px solid #a2a9b1;border-radius:2px;padding:0 .5em;vertical-align:top}.cd-watchlistMenu-scriptPageLink{vertical-align:middle;margin:0 .25em}.ltr .cd-watchlistMenu{margin:0 1em 0 .5em}.rtl .cd-watchlistMenu{margin:0 .5em 0 1em}#mw-watchlist-options .cd-watchlistMenu{float:right}.cd-watchlistMenu-button{margin:-1px 0}.cd-watchlistMenu-button-switchInteresting .oo-ui-iconElement-icon{background-position-y:7px}.cd-editWatchedSections-input{padding:1px 0}.cd-editWatchedSections-input .oo-ui-inputWidget-input{resize:none;border-radius:0}", ""]); // Exports module.exports = exports; "
"/** * @module cd */ // Window or worker context const context = typeof window === 'undefined' ? self : window; /** * @namespace convenientDiscussions */ context.convenientDiscussions = context.convenientDiscussions || {}; if (typeof context.convenientDiscussions !== 'object') { context.convenientDiscussions = {}; } export default context.convenientDiscussions; "
"/** * Custom error class. * * @module CdError */ export default class CdError extends Error { constructor(data) { let message; if (data) { message = data.type; if (data.code) { message += `/${data.code}`; } if (data?.apiData?.error?.code) { message += `/${data.apiData.error.code}`; } } else { message = ''; } super(message); this.name = 'CdError'; this.data = data; } } "
"class TributeEvents { constructor(tribute) { this.tribute = tribute; this.tribute.events = this; } /* jwbth: Removed: - "space" - it causes the menu not to change or hide when a space was typed; - "delete" - it causes the menu not to appear when backspace is pressed and a character preventing the menu to appear is removed (for example, ">" in "<small>"). */ static keys() { return [ { key: 9, value: "TAB" }, { key: 13, value: "ENTER" }, { key: 27, value: "ESCAPE" }, { key: 38, value: "UP" }, { key: 40, value: "DOWN" } ]; } bind(element) { element.boundKeydown = this.keydown.bind(element, this); element.boundKeyup = this.keyup.bind(element, this); element.boundInput = this.input.bind(element, this); element.addEventListener("keydown", element.boundKeydown, false); element.addEventListener("keyup", element.boundKeyup, false); element.addEventListener("input", element.boundInput, false); } unbind(element) { element.removeEventListener("keydown", element.boundKeydown, false); element.removeEventListener("keyup", element.boundKeyup, false); element.removeEventListener("input", element.boundInput, false); delete element.boundKeydown; delete element.boundKeyup; delete element.boundInput; } keydown(instance, event) { // jwbth: Removed shouldDeactivate() fixing the disappearing of the menu when a part of a // mention is typed and the user presses any command key. let element = this; instance.commandEvent = false; TributeEvents.keys().forEach(o => { if (o.key === event.keyCode) { instance.commandEvent = true; instance.callbacks()[o.value.toLowerCase()](event, element); } }); } input(instance, event) { instance.inputEvent = true; instance.keyup.call(this, instance, event); } click(instance, event) { // jwbth: Ignore other than left button clicks. if (event.which !== 1) return; let tribute = instance.tribute; if (tribute.menu && tribute.menu.contains(event.target)) { let li = event.target; event.preventDefault(); event.stopPropagation(); while (li.nodeName.toLowerCase() !== "li") { li = li.parentNode; if (!li || li === tribute.menu) { // jwbth: Replaced the error throw with return, as there is nothing wrong when a user // clicks the scroll bar. return; } } tribute.selectItemAtIndex(li.getAttribute("data-index"), event); tribute.hideMenu(); // TODO: should fire with externalTrigger and target is outside of menu } else if (tribute.current.element && !tribute.current.externalTrigger) { tribute.current.externalTrigger = false; setTimeout(() => tribute.hideMenu()); } } keyup(instance, event) { // jwbth: Added this and replaces the usages below. const tribute = instance.tribute; // jwbth: Added this to avoid appearing-disappearing of the menu when moving the caret. if (!instance.inputEvent && !tribute.isActive) return; if (instance.inputEvent) { instance.inputEvent = false; } instance.updateSelection(this); if (event.keyCode === 27) return; // jwbth: Added this. if ( tribute.current.triggerPos === tribute.lastCanceledTriggerPos && tribute.current.triggerChar === tribute.lastCanceledTriggerChar ) { return; } tribute.lastCanceledTriggerPos = null; tribute.lastCanceledTriggerChar = null; if (!tribute.allowSpaces && tribute.hasTrailingSpace) { tribute.hasTrailingSpace = false; instance.commandEvent = true; return; } // jwbth: Added this block (search for `dropMenu` for the explanation). if (tribute.dropMenu || tribute.current.mentionText === undefined) { tribute.isActive = false; tribute.hideMenu(); tribute.dropMenu = false; return; } if (!tribute.isActive) { // jwbth: Removed the block and made `trigger` be filled from `tribute.current.triggerChar` // to account for triggers with the same first character. let trigger = tribute.current.triggerChar; if (typeof trigger !== "undefined") { instance.callbacks().triggerChar(event, this, trigger); } } if (tribute.current.mentionText.length < tribute.current.collection.menuShowMinLength) return; if ( /* jwbth: "=== false" is replaced with "!== true" to fix the issue with the autocomplete menu not appearing. This issue appears because of the check "triggerChar !== this.tribute.current.trigger" I added to TributeRange.js to fix another issue. Steps to reproduce in Convenient Discussions: open a reply form, paste a wikilink using the context menu, press "@". Expected: An autocomplete menu appears. Actual: Does not. This is because "instance.commandEvent = false" is executed only on keydown event that lacks when pasting from the context menu. */ (tribute.current.trigger && instance.commandEvent !== true) || (tribute.isActive && event.keyCode === 8) ) { tribute.showMenuFor(this, true); } } shouldDeactivate(event) { if (!this.tribute.isActive) return false; if (this.tribute.current.mentionText.length === 0) { let eventKeyPressed = false; TributeEvents.keys().forEach(o => { if (event.keyCode === o.key) eventKeyPressed = true; }); return !eventKeyPressed; } return false; } // jwbth: Removed `getKeyCode` as it is redundant. updateSelection(el) { this.tribute.current.element = el; let info = this.tribute.range.getTriggerInfo(false, this.tribute.hasTrailingSpace, true, this.tribute.allowSpaces); if (info) { this.tribute.current.selectedPath = info.mentionSelectedPath; this.tribute.current.mentionText = info.mentionText; this.tribute.current.selectedOffset = info.mentionSelectedOffset; // jwbth: Added this line to use this property in `keyup()`. this.tribute.current.triggerChar = info.mentionTriggerChar; const current = this.tribute.current; const pre = current.element.value.slice(0, current.element.selectionStart); current.triggerPos = pre.lastIndexOf(current.triggerChar); } else { // jwbth: Added this block. const current = this.tribute.current; delete current.selectedPath; delete current.mentionText; delete current.selectedOffset; delete current.triggerChar; delete current.triggerPos; } } callbacks() { // jwbth: Removed `delete` and `space` keys from here, see `keys()`. return { triggerChar: (e, el, trigger) => { let tribute = this.tribute; tribute.current.trigger = trigger; let collectionItem = tribute.collection.find(item => { return item.trigger === trigger; }); tribute.current.collection = collectionItem; if ( tribute.current.mentionText.length >= tribute.current.collection.menuShowMinLength && tribute.inputEvent ) { tribute.showMenuFor(el, true); } }, enter: (e) => { // choose selection if (this.tribute.isActive && this.tribute.current.filteredItems) { e.preventDefault(); e.stopPropagation(); setTimeout(() => { this.tribute.selectItemAtIndex(this.tribute.menuSelected, e); this.tribute.hideMenu(); }, 0); } }, escape: (e) => { if (this.tribute.isActive) { e.preventDefault(); e.stopPropagation(); // jwbth: Added this block. this.tribute.lastCanceledTriggerPos = this.tribute.current.triggerPos; this.tribute.lastCanceledTriggerChar = this.tribute.current.triggerChar; this.tribute.isActive = false; this.tribute.hideMenu(); } }, tab: (e, el) => { // choose first match this.callbacks().enter(e, el); }, up: (e) => { // navigate up ul if (this.tribute.isActive && this.tribute.current.filteredItems) { e.preventDefault(); e.stopPropagation(); let count = this.tribute.current.filteredItems.length, selected = this.tribute.menuSelected; if (count > selected && selected > 0) { this.tribute.menuSelected--; this.setActiveLi(); } else if (selected === 0) { this.tribute.menuSelected = count - 1; this.setActiveLi(); this.tribute.menu.scrollTop = this.tribute.menu.scrollHeight; } } }, down: (e) => { // navigate down ul if (this.tribute.isActive && this.tribute.current.filteredItems) { e.preventDefault(); e.stopPropagation(); let count = this.tribute.current.filteredItems.length - 1, selected = this.tribute.menuSelected; if (count > selected) { this.tribute.menuSelected++; this.setActiveLi(); } else if (count === selected) { this.tribute.menuSelected = 0; this.setActiveLi(); this.tribute.menu.scrollTop = 0; } } }, }; } setActiveLi(index) { let lis = this.tribute.menu.querySelectorAll("li"), length = lis.length >>> 0; if (index) this.tribute.menuSelected = parseInt(index); for (let i = 0; i < length; i++) { let li = lis[i]; if (i === this.tribute.menuSelected) { li.classList.add(this.tribute.current.collection.selectClass); let liClientRect = li.getBoundingClientRect(); let menuClientRect = this.tribute.menu.getBoundingClientRect(); if (liClientRect.bottom > menuClientRect.bottom) { let scrollDistance = liClientRect.bottom - menuClientRect.bottom; this.tribute.menu.scrollTop += scrollDistance; } else if (liClientRect.top < menuClientRect.top) { let scrollDistance = menuClientRect.top - liClientRect.top; this.tribute.menu.scrollTop -= scrollDistance; } } else { li.classList.remove(this.tribute.current.collection.selectClass); } } } getFullHeight(elem, includeMargin) { let height = elem.getBoundingClientRect().height; if (includeMargin) { let style = elem.currentStyle || window.getComputedStyle(elem); return ( height + parseFloat(style.marginTop) + parseFloat(style.marginBottom) ); } return height; } } export default TributeEvents; "
"class TributeMenuEvents { constructor(tribute) { this.tribute = tribute; this.tribute.menuEvents = this; this.menu = this.tribute.menu; } bind() { this.menuClickEvent = this.tribute.events.click.bind(null, this); this.menuContainerScrollEvent = this.debounce( () => { if (this.tribute.isActive) { this.tribute.showMenuFor(this.tribute.current.element, false); } }, 300, false ); this.windowResizeEvent = this.debounce( () => { if (this.tribute.isActive) { this.tribute.range.positionMenuAtCaret(true); } }, 300, false ); // fixes IE11 issues with mousedown document.addEventListener("MSPointerDown", this.menuClickEvent, false); document.addEventListener("mousedown", this.menuClickEvent, false); window.addEventListener("resize", this.windowResizeEvent); // jwbth: Added this line to make the menu change its height if its lower border is off screen. window.addEventListener("scroll", this.windowResizeEvent); if (this.menuContainer) { this.menuContainer.addEventListener( "scroll", this.menuContainerScrollEvent, false ); } else { window.addEventListener("scroll", this.menuContainerScrollEvent); } } unbind() { document.removeEventListener("mousedown", this.menuClickEvent, false); document.removeEventListener("MSPointerDown", this.menuClickEvent, false); window.removeEventListener("resize", this.windowResizeEvent); // jwbth: Added this line, see above. window.removeEventListener("scroll", this.windowResizeEvent); if (this.menuContainer) { this.menuContainer.removeEventListener( "scroll", this.menuContainerScrollEvent, false ); } else { window.removeEventListener("scroll", this.menuContainerScrollEvent); } } debounce(func, wait, immediate) { var timeout; return () => { var context = this, args = arguments; var later = () => { timeout = null; if (!immediate) func.apply(context, args); }; var callNow = immediate && !timeout; clearTimeout(timeout); timeout = setTimeout(later, wait); if (callNow) func.apply(context, args); }; } } export default TributeMenuEvents; "
"// Thanks to https://github.com/jeff-collins/ment.io import "./utils"; const punctuationRegexp = /[\s!-#%-\x2A,-/:;\x3F@\x5B-\x5D_\x7B}\u00A1\u00A7\u00AB\u00B6\u00B7\u00BB\u00BF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u0AF0\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E3B\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]/; class TributeRange { constructor(tribute) { this.tribute = tribute this.tribute.range = this } positionMenuAtCaret(scrollTo) { let coordinates let info = this.getTriggerInfo(false, this.tribute.hasTrailingSpace, true, this.tribute.allowSpaces) if (typeof info !== 'undefined') { if(!this.tribute.positionMenu){ this.tribute.menu.style.cssText = `display: block;` return } coordinates = this.getTextAreaOrInputUnderlinePosition(this.tribute.current.element, info.mentionPosition) this.tribute.menu.style.cssText = ( `top: ${coordinates.top}${typeof coordinates.top === 'number' ? 'px' : ''}; ` + `left:${coordinates.left}${typeof coordinates.left === 'number' ? 'px' : ''}; ` + `right: ${coordinates.right}${typeof coordinates.right === 'number' ? 'px' : ''}; ` + `bottom: ${coordinates.bottom}${typeof coordinates.bottom === 'number' ? 'px' : ''}; ` + `position: absolute; ` + `display: block;` ) // jwbth: Added this block. if (coordinates.additionalStyles) { this.tribute.menu.style.cssText += ' ' + coordinates.additionalStyles } if (scrollTo) this.scrollIntoView() // jwbth: Removed `setTimeout` part entirely as it seems to have no effect after other // changes. } else { this.tribute.menu.style.cssText = 'display: none' } } get menuContainerIsBody() { return this.tribute.menuContainer === document.body || !this.tribute.menuContainer } selectElement(targetElement, path, offset) { let range let elem = targetElement if (path) { for (var i = 0; i < path.length; i++) { elem = elem.childNodes[path[i]] if (elem === undefined) { return } while (elem.length < offset) { offset -= elem.length elem = elem.nextSibling } if (elem.childNodes.length === 0 && !elem.length) { elem = elem.previousSibling } } } let sel = window.getSelection() range = document.createRange() range.setStart(elem, offset) range.setEnd(elem, offset) range.collapse(true) try { sel.removeAllRanges() } catch (error) { console.warn(error) } sel.addRange(range) targetElement.focus() } replaceTriggerText(data, requireLeadingSpace, hasTrailingSpace, originalEvent, item) { let info = this.getTriggerInfo(true, hasTrailingSpace, requireLeadingSpace, this.tribute.allowSpaces) if (info !== undefined) { let context = this.tribute.current let replaceEvent = new CustomEvent('tribute-replaced', { detail: { item: item, instance: context, context: info, event: originalEvent, } }) // jwbth: We use the `data` object instead of a string, to store the start/end/content // data. The code processing these properties is added below. if (typeof data !== 'object') { data = { start: data } } data.content = data.content || '' data.end = data.end || '' if (originalEvent.ctrlKey && data.ctrlModify) { data = data.ctrlModify(data) } let myField = this.tribute.current.element // jwbth: Fixed this line to make it work with `replaceTextSuffix`es of length other // than 1. let endPos = info.mentionPosition + info.mentionText.length + info.mentionTriggerChar.length let ending = myField.value.substring(endPos, myField.value.length) if ((originalEvent.shiftKey || originalEvent.altKey) && data.shiftModify) { data = data.shiftModify(data) } if (originalEvent.altKey) { data.content = ending endPos += ending.length ending = '' } let startPos = info.mentionPosition myField.selectionStart = startPos myField.selectionEnd = endPos // jwbth: Made alterations to make the `keepAsEnd` config value work. if (context.collection.keepAsEnd && !originalEvent.shiftKey) { const [end] = ending.match(context.collection.keepAsEnd) || [] if (end) { ending = ending.slice(end.length) myField.selectionEnd += end.length data.end = end } } let text = data.start + data.content + data.end let textSuffix = typeof this.tribute.replaceTextSuffix == 'string' ? this.tribute.replaceTextSuffix : ' ' text += textSuffix // jwbth: Preserve the undo/redo functionality in browsers that support it. myField.focus() if (!document.execCommand('insertText', false, text)) { myField.value = myField.value.substring(0, startPos) + text + ending } // jwbth: Start offset is calculated from the start position of the inserted text. // Absent value means the selection start position should match with the end position // (i.e., no text should be selected). if (originalEvent.shiftKey || (data.typeContent && !data.content)) { myField.selectionEnd = startPos + text.length - data.end.length myField.selectionStart = startPos + data.start.length } else { myField.selectionEnd = startPos + text.length myField.selectionStart = myField.selectionEnd } context.element.dispatchEvent(new CustomEvent('input', { bubbles: true })) context.element.dispatchEvent(replaceEvent) } } getNodePositionInParent(element) { if (element.parentNode === null) { return 0 } for (var i = 0; i < element.parentNode.childNodes.length; i++) { let node = element.parentNode.childNodes[i] if (node === element) { return i } } } getTextPrecedingCurrentSelection() { let text = '' let textComponent = this.tribute.current.element if (textComponent) { let startPos = textComponent.selectionStart if (textComponent.value && startPos >= 0) { text = textComponent.value.substring(0, startPos) } } return text } getTriggerInfo(menuAlreadyActive, hasTrailingSpace, requireLeadingSpace, allowSpaces) { let selected, path, offset selected = this.tribute.current.element let effectiveRange = this.getTextPrecedingCurrentSelection() if (effectiveRange !== undefined && effectiveRange !== null) { let mostRecentTriggerCharPos = -1 let mostRecentTriggerCharLength = 0 let triggerChar this.tribute.collection.forEach(config => { let c = config.trigger let idx = config.requireLeadingSpace ? this.lastIndexWithLeadingSpace(effectiveRange, c) : effectiveRange.lastIndexOf(c) if ( idx > mostRecentTriggerCharPos || // jwbth: Added this lines, as well as the `mostRecentTriggerCharLength` // variable and operations with it, to have triggers like "[[#" be used instead // of triggers like "[[" if both are present. ( idx > -1 && idx === mostRecentTriggerCharPos && c.length > mostRecentTriggerCharLength ) ) { mostRecentTriggerCharPos = idx mostRecentTriggerCharLength = c.length triggerChar = c requireLeadingSpace = config.requireLeadingSpace } }) let currentTriggerSnippet let originalCurrentTriggerSnippet let leadingSpace let regex let inputOk = (mostRecentTriggerCharPos >= 0 && ( mostRecentTriggerCharPos === 0 || !requireLeadingSpace || // jwbth: Use punctuation instead of just whitespace characters. punctuationRegexp.test( effectiveRange.substring( mostRecentTriggerCharPos - 1, mostRecentTriggerCharPos) ) ) ) if (inputOk) { currentTriggerSnippet = effectiveRange.substring(mostRecentTriggerCharPos + triggerChar.length, effectiveRange.length) // jwbth: Added this line and the declaration above. originalCurrentTriggerSnippet = currentTriggerSnippet triggerChar = effectiveRange.substring(mostRecentTriggerCharPos, mostRecentTriggerCharPos + triggerChar.length) let firstSnippetChar = currentTriggerSnippet.substring(0, 1) leadingSpace = currentTriggerSnippet.length > 0 && ( firstSnippetChar === ' ' || firstSnippetChar === '\xA0' ) if (hasTrailingSpace) { currentTriggerSnippet = currentTriggerSnippet.trim() } regex = allowSpaces ? /[^\S ]/g : /[\xA0\s]/g this.tribute.hasTrailingSpace = regex.test(currentTriggerSnippet) } /* jwbth: Added this block, breaking the block starting with `inputOk` check into two parts, as we need to have the menu removed when: - there is no valid trigger before the caret position, - typing a space after "@" or "##", - there are newlines before the caret position and the trigger position, - there is a selection. */ if ( mostRecentTriggerCharPos === -1 || (originalCurrentTriggerSnippet && !originalCurrentTriggerSnippet[0].trim()) || originalCurrentTriggerSnippet.includes('\n') || selected.selectionStart !== selected.selectionEnd || // When pressed backspace in "[[#" and faced the trigger "[[" (this.tribute.current.trigger && triggerChar !== this.tribute.current.trigger) ) { this.tribute.dropMenu = true return } if (inputOk && !leadingSpace && (menuAlreadyActive || !regex.test(currentTriggerSnippet))) { return { mentionPosition: mostRecentTriggerCharPos, mentionText: currentTriggerSnippet, mentionSelectedElement: selected, mentionSelectedPath: path, mentionSelectedOffset: offset, mentionTriggerChar: triggerChar } } } } lastIndexWithLeadingSpace(str, trigger) { let reversedStr = str.split('').reverse().join('') let index = -1 for (let cidx = 0, len = str.length; cidx < len; cidx++) { let firstChar = cidx === str.length - 1 let leadingSpace = punctuationRegexp.test(reversedStr[cidx + 1]) let match = true for (let triggerIdx = trigger.length - 1; triggerIdx >= 0; triggerIdx--) { if (trigger[triggerIdx] !== reversedStr[cidx-triggerIdx]) { match = false break } } if (match && (firstChar || leadingSpace)) { index = str.length - 1 - cidx break } } return index } isMenuOffScreen(coordinates, menuDimensions) { let windowWidth = window.innerWidth let windowHeight = window.innerHeight let doc = document.documentElement let windowLeft = (window.pageXOffset || doc.scrollLeft) - (doc.clientLeft || 0) let windowTop = (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0) let menuTop = typeof coordinates.top === 'number' ? coordinates.top : windowTop + windowHeight - coordinates.bottom - menuDimensions.height let menuRight = typeof coordinates.right === 'number' ? coordinates.right : coordinates.left + menuDimensions.width let menuBottom = typeof coordinates.bottom === 'number' ? coordinates.bottom : coordinates.top + menuDimensions.height let menuLeft = typeof coordinates.left === 'number' ? coordinates.left : windowLeft + windowWidth - coordinates.right - menuDimensions.width return { top: menuTop < Math.floor(windowTop), right: menuRight > Math.ceil(windowLeft + windowWidth), bottom: menuBottom > Math.ceil(windowTop + windowHeight) - 3, left: menuLeft < Math.floor(windowLeft) } } getMenuDimensions() { // Width of the menu depends of its contents and position // We must check what its width would be without any obstruction // This way, we can achieve good positioning for flipping the menu let dimensions = { width: null, height: null } // jwbth: Fixed "visibility(;) hidden;". this.tribute.menu.style.cssText = `top: 0px;` + `left: 0px;` + `right: auto;` + `position: fixed;` + `display: block;` + `visibility: hidden;` dimensions.width = this.tribute.menu.offsetWidth dimensions.height = this.tribute.menu.offsetHeight this.tribute.menu.style.cssText = `display: none;` return dimensions } // jwbth: Added RTL support. getTextAreaOrInputUnderlinePosition(element, position) { let properties = [ 'borderBottomStyle', 'borderBottomWidth', 'borderLeftStyle', 'borderLeftWidth', 'borderRightStyle', 'borderRightWidth', 'borderTopStyle', 'borderTopWidth', 'boxSizing', 'direction', 'fontFamily', 'fontSize', 'fontSizeAdjust', 'fontStretch', 'fontStyle', 'fontVariant', 'fontWeight', 'height', 'letterSpacing', 'lineHeight', 'overflowX', 'overflowY', 'paddingBottom', 'paddingLeft', 'paddingRight', 'paddingTop', 'tabSize', 'textAlign', 'textDecoration', 'textIndent', 'textTransform', 'width', 'wordSpacing' ] let isFirefox = (window.mozInnerScreenX !== null) let div = document.createElement('div') div.id = 'input-textarea-caret-position-mirror-div' document.body.appendChild(div) let style = div.style let computed = window.getComputedStyle ? getComputedStyle(element) : element.currentStyle style.whiteSpace = 'pre-wrap' if (element.nodeName !== 'INPUT') { style.wordWrap = 'break-word' } // position off-screen style.position = 'absolute' style.visibility = 'hidden' // transfer the element's properties to the div properties.forEach(prop => { style[prop] = computed[prop] }) if (isFirefox) { // jwbth: replaced parseInt with parseFloat: can result in wrongly positioned menu (have // seen an example when edited [[:en:Wikipedia:Village pump (proposals)#Allow fair use // non-freely licensed photos of politicians]]). style.width = `${(parseFloat(computed.width) - 2)}px` if (element.scrollHeight > parseFloat(computed.height)) style.overflowY = 'scroll' } else { style.overflow = 'hidden' } div.textContent = element.value.substring(0, position) // jwbth: Removed replacing "\s" with ' ' as its function is unclear and negative effects // are likely (say, when replacing the tab character with the space that has different // width). let triggerSpan = document.createElement('span') triggerSpan.textContent = this.tribute.current.trigger let span = document.createElement('span') span.append( triggerSpan, element.value.substring(position + this.tribute.current.trigger.length) || '.' ) div.appendChild(span) let doc = document.documentElement // jwbth: Replaced `window.innerWidth` with `document.documentElement.clientWidth` here and // in other places to have the scrollbars counted. let windowWidth = doc.clientWidth let windowHeight = doc.clientHeight let rect = element.getBoundingClientRect() let windowLeft = (window.pageXOffset || doc.scrollLeft) - (doc.clientLeft || 0) let windowTop = (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0) let top = 0 let left = 0 let right = 0 if (this.menuContainerIsBody) { top = rect.top left = rect.left right = rect.right } let coordinates = { top: top + windowTop + span.offsetTop + parseInt(computed.borderTopWidth) + parseInt(computed.fontSize) - element.scrollTop } if (this.tribute.isRtl) { coordinates.right = (windowWidth - right) + (windowWidth - span.getBoundingClientRect().right) + triggerSpan.offsetWidth } else { coordinates.left = windowLeft + left + span.offsetLeft + triggerSpan.offsetWidth + 1 } let menuDimensions = this.getMenuDimensions() let menuIsOffScreen = this.isMenuOffScreen(coordinates, menuDimensions) if (this.tribute.isRtl) { if (menuIsOffScreen.left) { coordinates.left = 0 coordinates.right = 'auto' } } else { if (menuIsOffScreen.right) { // jwbth: Simplified the positioning by putting `right` at 0. coordinates.right = 0 coordinates.left = 'auto' } } if (menuIsOffScreen.bottom) { // jwbth: Removed the block setting `coordinates.bottom` as a reference point as well as // the `parentHeight` variable, added the block setting the height for the menu. const height = windowTop + windowHeight - coordinates.top - parseFloat(getComputedStyle(element).paddingTop) - 3 coordinates.additionalStyles = `height: ${height}px; overflow-y: scroll;` } // jwbth: Removed the second check if the menu is off screen as it seems redundant after we // stopped flipping the menu. document.body.removeChild(div) return coordinates } scrollIntoView() { let reasonableBuffer = 20, clientRect let maxScrollDisplacement = 100 let e = this.menu if (typeof e === 'undefined') return while (clientRect === undefined || clientRect.height === 0) { clientRect = e.getBoundingClientRect() if (clientRect.height === 0) { e = e.childNodes[0] if (e === undefined || !e.getBoundingClientRect) { return } } } let elemTop = clientRect.top let elemBottom = elemTop + clientRect.height if (elemTop < 0) { window.scrollTo(0, window.pageYOffset + clientRect.top - reasonableBuffer) } else if (elemBottom > window.innerHeight) { let maxY = window.pageYOffset + clientRect.top - reasonableBuffer if (maxY - window.pageYOffset > maxScrollDisplacement) { maxY = window.pageYOffset + maxScrollDisplacement } let targetY = window.pageYOffset - (window.innerHeight - elemBottom) if (targetY > maxY) { targetY = maxY } window.scrollTo(0, targetY) } } } export default TributeRange; "
"// Thanks to https://github.com/mattyork/fuzzy class TributeSearch { constructor(tribute) { this.tribute = tribute this.tribute.search = this } match(pattern, string, opts) { opts = opts || {} let pre = opts.pre || '', post = opts.post || '', compareString = opts.caseSensitive && string || string.toLowerCase() if (opts.skip) { return {rendered: string, score: 0} } pattern = opts.caseSensitive && pattern || pattern.toLowerCase() let patternCache = this.traverse(compareString, pattern, 0, 0, []) if (!patternCache) { return null } return { rendered: this.render(string, patternCache.cache, pre, post), score: patternCache.score } } traverse(string, pattern, stringIndex, patternIndex, patternCache) { if (pattern.length === patternIndex) { // calculate score and copy the cache containing the indices where it's found return { score: this.calculateScore(patternCache), cache: patternCache.slice() } } // if string at end or remaining pattern > remaining string if (string.length === stringIndex || pattern.length - patternIndex > string.length - stringIndex) { return undefined } let c = pattern[patternIndex] let index = string.indexOf(c, stringIndex) let best, temp while (index > -1) { patternCache.push(index) temp = this.traverse(string, pattern, index + 1, patternIndex + 1, patternCache) patternCache.pop() // if downstream traversal failed, return best answer so far if (!temp) { return best } if (!best || best.score < temp.score) { best = temp } index = string.indexOf(c, index + 1) } return best } calculateScore(patternCache) { let score = 0 let temp = 1 patternCache.forEach((index, i) => { if (i > 0) { if (patternCache[i - 1] + 1 === index) { temp += temp + 1 } else { temp = 1 } } score += temp }) return score } render(string, indices, pre, post) { var rendered = string.substring(0, indices[0]) indices.forEach((index, i) => { rendered += pre + string[index] + post + string.substring(index + 1, (indices[i + 1]) ? indices[i + 1] : string.length) }) return rendered } filter(pattern, arr, opts) { opts = opts || {} return arr .reduce((prev, element, idx) => { let str = element if (opts.extract) { str = opts.extract(element) if (!str) { // take care of undefineds / nulls / etc. str = '' } } let rendered = this.match(pattern, str, opts) if (rendered != null) { prev[prev.length] = { string: rendered.rendered, score: rendered.score, index: idx, original: element } } return prev }, []) .sort((a, b) => { let compare = b.score - a.score if (compare) return compare return a.index - b.index }) } } export default TributeSearch; "
"/** * Tribute.js * Native ES6 JavaScript @mention Plugin * Improved and adapted for use in the Convenient Discussions script * * @license * The MIT License (MIT) * * Copyright (c) 2020 Jack who built the house * Copyright (c) 2017-2020 ZURB, Inc. * Copyright (c) 2014 Jeff Collins * Copyright (c) 2012 Matt York * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software * and associated documentation files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or * substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. **/ import "./utils"; import TributeEvents from "./TributeEvents"; import TributeMenuEvents from "./TributeMenuEvents"; import TributeRange from "./TributeRange"; import TributeSearch from "./TributeSearch"; class Tribute { constructor({ values = null, selectClass = "highlight", containerClass = "tribute-container", itemClass = "", trigger = "@", selectTemplate = null, menuItemTemplate = null, lookup = "key", fillAttr = "value", collection = null, menuContainer = null, noMatchTemplate = null, requireLeadingSpace = true, allowSpaces = false, replaceTextSuffix = null, positionMenu = true, searchOpts = {}, menuItemLimit = null, menuShowMinLength = 0, isRtl = false }) { this.menuSelected = 0; this.current = {}; this.inputEvent = false; this.isActive = false; this.menuContainer = menuContainer; this.allowSpaces = allowSpaces; this.replaceTextSuffix = replaceTextSuffix; this.positionMenu = positionMenu; this.hasTrailingSpace = false; this.isRtl = isRtl; if (values) { this.collection = [ { // symbol that starts the lookup trigger: trigger, // class applied to selected item selectClass: selectClass, // class applied to the Container containerClass: containerClass, // class applied to each item itemClass: itemClass, // function called on select that retuns the content to insert selectTemplate: ( selectTemplate || Tribute.defaultSelectTemplate ).bind(this), // function called that returns content for an item menuItemTemplate: ( menuItemTemplate || Tribute.defaultMenuItemTemplate ).bind(this), // function called when menu is empty, disables hiding of menu. noMatchTemplate: (t => { if (typeof t === "string") { if (t.trim() === "") return null; return t; } if (typeof t === "function") { return t.bind(this); } return ( noMatchTemplate || function() { return "<li>No Match Found!</li>"; }.bind(this) ); })(noMatchTemplate), // column to search against in the object lookup: lookup, // column that contains the content to insert by default fillAttr: fillAttr, // array of objects or a function returning an array of objects values: values, requireLeadingSpace: requireLeadingSpace, searchOpts: searchOpts, menuItemLimit: menuItemLimit, menuShowMinLength: menuShowMinLength } ]; } else if (collection) { this.collection = collection.map(item => { return { trigger: item.trigger || trigger, keepAsEnd: item.keepAsEnd || null, selectClass: item.selectClass || selectClass, containerClass: item.containerClass || containerClass, itemClass: item.itemClass || itemClass, selectTemplate: ( item.selectTemplate || Tribute.defaultSelectTemplate ).bind(this), menuItemTemplate: ( item.menuItemTemplate || Tribute.defaultMenuItemTemplate ).bind(this), // function called when menu is empty, disables hiding of menu. noMatchTemplate: (t => { if (typeof t === "string") { if (t.trim() === "") return null; return t; } if (typeof t === "function") { return t.bind(this); } return ( noMatchTemplate || function() { return "<li>No Match Found!</li>"; }.bind(this) ); })(noMatchTemplate), lookup: item.lookup || lookup, fillAttr: item.fillAttr || fillAttr, values: item.values, requireLeadingSpace: item.requireLeadingSpace, searchOpts: item.searchOpts || searchOpts, menuItemLimit: item.menuItemLimit || menuItemLimit, menuShowMinLength: item.menuShowMinLength || menuShowMinLength }; }); } else { throw new Error("[Tribute] No collection specified."); } new TributeRange(this); new TributeEvents(this); new TributeMenuEvents(this); new TributeSearch(this); } get isActive() { return this._isActive; } set isActive(val) { if (this._isActive != val) { this._isActive = val; if (this.current.element) { let noMatchEvent = new CustomEvent(`tribute-active-${val}`); this.current.element.dispatchEvent(noMatchEvent); } } } static defaultSelectTemplate(item) { if (typeof item === "undefined") return `${this.current.collection.trigger}${this.current.mentionText}`; return ( this.current.collection.trigger + item.original[this.current.collection.fillAttr] ); } static defaultMenuItemTemplate(matchItem) { return matchItem.string; } static inputTypes() { return ["TEXTAREA", "INPUT"]; } triggers() { return this.collection.map(config => { return config.trigger; }); } attach(el) { if (!el) { throw new Error("[Tribute] Must pass in a DOM node or NodeList."); } // Check if it is a jQuery collection if (typeof jQuery !== "undefined" && el instanceof jQuery) { el = el.get(); } // Is el an Array/Array-like object? if ( el.constructor === NodeList || el.constructor === HTMLCollection || el.constructor === Array ) { let length = el.length; for (var i = 0; i < length; ++i) { this._attach(el[i]); } } else { this._attach(el); } } _attach(el) { if (el.hasAttribute("data-tribute")) { console.warn("Tribute was already bound to " + el.nodeName); } this.events.bind(el); el.setAttribute("data-tribute", true); } createMenu(containerClass) { let wrapper = document.createElement("div"), ul = document.createElement("ul"); wrapper.className = containerClass; if (this.isRtl) { wrapper.className += ' tribute-rtl'; } wrapper.appendChild(ul); if (this.menuContainer) { return this.menuContainer.appendChild(wrapper); } return document.body.appendChild(wrapper); } showMenuFor(element, scrollTo) { const processValues = values => { // Tribute may not be active any more by the time the value callback returns if (!this.isActive) { return; } let items = this.search.filter(this.current.mentionText, values, { // jwbth: Replaced "<span>" and "</span>" as default values with empty strings. Tags are // displayed as plain text currently anyway. pre: this.current.collection.searchOpts.pre || "", post: this.current.collection.searchOpts.post || "", skip: this.current.collection.searchOpts.skip, extract: el => { if (typeof this.current.collection.lookup === "string") { return el[this.current.collection.lookup]; } else if (typeof this.current.collection.lookup === "function") { return this.current.collection.lookup(el, this.current.mentionText); } else { throw new Error( "Invalid lookup attribute, lookup must be string or function." ); } } }); if (this.current.collection.menuItemLimit) { items = items.slice(0, this.current.collection.menuItemLimit); } this.current.filteredItems = items; let ul = this.menu.querySelector("ul"); this.range.positionMenuAtCaret(scrollTo); if (!items.length) { let noMatchEvent = new CustomEvent("tribute-no-match", { detail: this.menu }); this.current.element.dispatchEvent(noMatchEvent); if ( (typeof this.current.collection.noMatchTemplate === "function" && !this.current.collection.noMatchTemplate()) || !this.current.collection.noMatchTemplate ) { this.hideMenu(); } else { typeof this.current.collection.noMatchTemplate === "function" ? (ul.innerHTML = this.current.collection.noMatchTemplate()) : (ul.innerHTML = this.current.collection.noMatchTemplate); } return; } ul.innerHTML = ""; let fragment = document.createDocumentFragment(); items.forEach((item, index) => { let li = document.createElement("li"); li.setAttribute("data-index", index); li.className = this.current.collection.itemClass; li.addEventListener("mousemove", e => { let [, index] = this._findLiTarget(e.target); if (e.movementY !== 0) { this.events.setActiveLi(index); } }); if (this.menuSelected === index) { li.classList.add(this.current.collection.selectClass); } // jwbth: Replaced innerHTML with textContent to prevent XSS injections. li.textContent = this.current.collection.menuItemTemplate(item); fragment.appendChild(li); }); ul.appendChild(fragment); // jwbth: Added this line to make the menu redrawn immediately, not wait the `setTimeout`'s // callback. this.range.positionMenuAtCaret(scrollTo); }; // jwbth: Only proceed if the menu isn't already shown for the current element & mentionText. // This behavior has issues, see // https://github.com/jwbth/convenient-discussions/commit/14dc20cf1b23dff79c2592ff47431513890ab213, // so here we have even more workarounds. But otherwise `values` is called 3 times, Carl. That's // probably a problem of Tribute, but seems non-trivial to refactor it quickly. if ( this.isActive && this.current.element === element && this.current.mentionText === this.snapshot.mentionText ) { if (this.current.element.selectionStart !== this.snapshot.selectionStart) { processValues([]); } return; } this.snapshot = { mentionText: this.current.mentionText, selectionStart: this.current.element?.selectionStart, }; // create the menu if it doesn't exist. if (!this.menu) { this.menu = this.createMenu(this.current.collection.containerClass); element.tributeMenu = this.menu; this.menuEvents.bind(this.menu); } this.isActive = true; this.menuSelected = 0; this.lastCanceledTriggerChar = null; this.lastCanceledTriggerPos = null; if (!this.current.mentionText) { this.current.mentionText = ""; } if (typeof this.current.collection.values === "function") { this.current.collection.values(this.current.mentionText, processValues); } else { processValues(this.current.collection.values); } } _findLiTarget(el) { if (!el) return []; const index = el.getAttribute("data-index"); return !index ? this._findLiTarget(el.parentNode) : [el, index]; } showMenuForCollection(element, collectionIndex) { if (element !== document.activeElement) { this.placeCaretAtEnd(element); } this.current.collection = this.collection[collectionIndex || 0]; // jwbth: Added this to avert a JS error. this.current.trigger = this.current.collection.trigger; this.current.externalTrigger = true; this.current.element = element; // jwbth: Added this. this.current.triggerPos = element.selectionStart; if (!this.insertAtCaret(element, this.current.collection.trigger)) { this.showMenuFor(element); } } // TODO: make sure this works for inputs/textareas placeCaretAtEnd(el) { el.focus(); if ( typeof window.getSelection != "undefined" && typeof document.createRange != "undefined" ) { var range = document.createRange(); range.selectNodeContents(el); range.collapse(false); var sel = window.getSelection(); sel.removeAllRanges(); sel.addRange(range); } else if (typeof document.body.createTextRange != "undefined") { var textRange = document.body.createTextRange(); textRange.moveToElementText(el); textRange.collapse(false); textRange.select(); } } insertAtCaret(textarea, text) { var scrollPos = textarea.scrollTop; var caretPos = textarea.selectionStart; textarea.focus(); // jwbth: Preserve the undo/redo functionality in browsers that support it (Chrome does, Firefox // doesn't: https://bugzilla.mozilla.org/show_bug.cgi?id=1220696). const hasInsertedViaCommand = document.execCommand('insertText', false, text); if (!hasInsertedViaCommand) { var front = textarea.value.substring(0, caretPos); var back = textarea.value.substring( textarea.selectionEnd, textarea.value.length ); textarea.value = front + text + back; caretPos += text.length; textarea.selectionStart = caretPos; textarea.selectionEnd = caretPos; } textarea.scrollTop = scrollPos; return hasInsertedViaCommand; } hideMenu() { if (this.menu) { this.menu.style.cssText = "display: none;"; this.isActive = false; this.menuSelected = 0; this.current = {}; } } selectItemAtIndex(index, originalEvent) { index = parseInt(index); if (typeof index !== "number" || isNaN(index)) return; let item = this.current.filteredItems[index]; let data = this.current.collection.selectTemplate(item, originalEvent); if (data !== null) this.replaceText(data, originalEvent, item); } replaceText(data, originalEvent, item) { this.range.replaceTriggerText(data, true, true, originalEvent, item); } _append(collection, newValues, replace) { if (typeof collection.values === "function") { throw new Error("Unable to append to values, as it is a function."); } else if (!replace) { collection.values = collection.values.concat(newValues); } else { collection.values = newValues; } } append(collectionIndex, newValues, replace) { let index = parseInt(collectionIndex); if (typeof index !== "number") throw new Error("please provide an index for the collection to update."); let collection = this.collection[index]; this._append(collection, newValues, replace); } appendCurrent(newValues, replace) { if (this.isActive) { this._append(this.current.collection, newValues, replace); } else { throw new Error( "No active state. Please use append instead and pass an index." ); } } detach(el) { if (!el) { throw new Error("[Tribute] Must pass in a DOM node or NodeList."); } // Check if it is a jQuery collection if (typeof jQuery !== "undefined" && el instanceof jQuery) { el = el.get(); } // Is el an Array/Array-like object? if ( el.constructor === NodeList || el.constructor === HTMLCollection || el.constructor === Array ) { let length = el.length; for (var i = 0; i < length; ++i) { this._detach(el[i]); } } else { this._detach(el); } } _detach(el) { this.events.unbind(el); if (el.tributeMenu) { this.menuEvents.unbind(el.tributeMenu); } setTimeout(() => { el.removeAttribute("data-tribute"); this.isActive = false; if (el.tributeMenu) { el.tributeMenu.remove(); } }); } } export default Tribute; "
"/** * Utilities module. Utilities that go to the {@link module:cd~convenientDiscussions.util * convenientDiscussions.util} object are in {@link module:globalUtil}. * * @module util */ import CdError from './CdError'; import cd from './cd'; let keptScrollPosition = null; let keptTocHeight = null; /** * Callback for `Array#filter` to remove duplicated elements from an array. * * @param {*} item * @param {number} i * @param {Array} arr * @returns {boolean} */ export function unique(item, i, arr) { return arr.indexOf(item) === i; } /** * Generates a transparent color for the given color to use it in a gradient. * * @param {string} color * @returns {string} */ export function transparentize(color) { const dummyElement = document.createElement('span'); dummyElement.style.color = color; color = dummyElement.style.color; return color.includes('rgba') ? color.replace(/\d+(?=\))/, '0') : color .replace('rgb', 'rgba') .replace(')', ', 0)'); } /** * Check if a node is an element with `display: inline` or `display: inline-block` in the default * browser styles. As an option, it can also treat text nodes as inline elements. * * @param {Node} node * @param {boolean} countTextNodesAsInline * @returns {?boolean} */ export function isInline(node, countTextNodesAsInline) { if (countTextNodesAsInline && node.nodeType === Node.TEXT_NODE) { return true; } if (node.nodeType !== Node.ELEMENT_NODE) { return null; } if (cd.g.POPULAR_INLINE_ELEMENTS.includes(node.tagName)) { return true; } else if (cd.g.POPULAR_NOT_INLINE_ELEMENTS.includes(node.tagName)) { return false; } else { // This can be called from a worker. if (typeof window !== 'undefined') { console.warn('Expensive operation: isInline() called for:', node); // This is very expensive. Avoid by any means. return window.getComputedStyle(node).display.startsWith('inline'); } else { return null; } } } /** * Generate a pattern for use in a regular expression from a string that is case-insensitive for the * first character only. * * @param {string} s * @returns {string} */ export function caseInsensitiveFirstCharPattern(s) { const firstChar = s[0]; return ( ( // Could be issues, probably not very serious, resulting from the difference of PHP's // mb_strtoupper and JavaScript's String#toUpperCase, see firstCharToUpperCase() and // https://phabricator.wikimedia.org/T141723#2513800. firstChar.toUpperCase() !== firstChar.toLowerCase() ? '[' + firstChar.toUpperCase() + firstChar.toLowerCase() + ']' : mw.util.escapeRegExp(firstChar) ) + mw.util.escapeRegExp(s.slice(1)) ); } /** * Check if a page is probably a talk page. The namespace number is required. * * This function exists mostly because we can't be sure the `mediawiki.Title` module is loaded when * the script has started executing (and can't use the {@link module:Page Page} constructor), and we * need to make this check fast. So, in most cases, {@link module:Page#isProbablyTalkPage} should be * used. * * @param {string} pageName * @param {number} namespaceNumber * @returns {boolean} */ export function isProbablyTalkPage(pageName, namespaceNumber) { return ( ( namespaceNumber % 2 === 1 || cd.g.PAGE_WHITELIST_REGEXP?.test(pageName) || (!cd.g.PAGE_WHITELIST_REGEXP && cd.config.customTalkNamespaces?.includes(namespaceNumber)) ) && !cd.g.PAGE_BLACKLIST_REGEXP?.test(pageName) ); } /** * Check by an edit summary if an edit is probably an edit of a comment. * * @param {string} summary * @returns {boolean} */ export function isCommentEdit(summary) { return ( summary && ( summary.includes(`${cd.s('es-edit')} ${cd.s('es-reply-genitive')}`) || summary.includes(`${cd.s('es-edit')} ${cd.s('es-addition-genitive')}`) ) ); } /** * Check by an edit summary if an edit is probably an undo. * * @param {string} summary * @returns {boolean} */ export function isUndo(summary) { return summary && cd.config.undoTexts.some((text) => summary.includes(text)); } /** * Callback for `Array#filter` to keep only defined values in an array. * * @param {*} el * @returns {boolean} */ export function defined(el) { return el !== undefined; } /** * Return an array with a changed start index (`[0, 1, 2, 3]` can be transformed into `[2, 3, 0, * 1]`) and optionally reversed while keeping the start index (`[0, 1, 2, 3]` can be transformed * into `[2, 1, 0, 3]`). * * @param {Array} arr * @param {number} startIndex * @param {boolean} [reverse=false] * @returns {Array} */ export function reorderArray(arr, startIndex, reverse = false) { return reverse ? arr .slice(startIndex + 1) .concat(arr.slice(0, startIndex + 1)) .reverse() : arr .slice(startIndex) .concat(arr.slice(0, startIndex)) } /** * Alternative to `Array#flat(1)`. That method is not yet supported by major browsers. * * @param {Array} arr * @returns {Array} */ export function flat(arr) { return [].concat(...arr); } /** * Callback used in the `.catch()` parts of `mw.Api` requests. * * @param {string} code * @param {object} data * @throws {CdError} */ export function handleApiReject(code, data) { // See the parameters with which mw.Api() rejects: // https://phabricator.wikimedia.org/source/mediawiki/browse/master/resources/src/mediawiki.api/index.js;fbfa8f1a61c5ffba664e817701439affb4f6a388$245 throw code === 'http' ? new CdError({ type: 'network' }) : new CdError({ type: 'api', code: 'error', apiData: data, }); } /** * Transforms underlines to spaces in a string. * * @param {string} s * @returns {string} */ export function underlinesToSpaces(s) { return s.replace(/_/g, ' '); } /** * Transforms spaces to underlines in a string. * * @param {string} s * @returns {string} */ export function spacesToUnderlines(s) { return s.replace(/ /g, '_'); } /** * Replaces sequences of spaces with single spaces. * * @param {string} s * @returns {string} */ export function removeDoubleSpaces(s) { return s.replace(/ {2,}/g, ' '); } /** * Provide `mw.Title.phpCharToUpper` functionality for the web worker context. * * @param {string} char * @returns {string} */ function phpCharToUpper(char) { if (cd.g.PHP_CHAR_TO_UPPER_JSON[char] === '') { return char; } return cd.g.PHP_CHAR_TO_UPPER_JSON[char] || char.toUpperCase(); } /** * Transform the first letter of a string to upper case, for example: `'wikilink'` → `'Wikilink'`. * Do it in PHP, not JavaScript, fashion to match the MediaWiki behavior, see {@link * https://phabricator.wikimedia.org/T141723#2513800}. * * @param {string} s * @returns {string} */ export function firstCharToUpperCase(s) { return s.length ? phpCharToUpper(s[0]) + s.slice(1) : ''; } /** * Get text of the localization messages. * * @param {string[]} messages * @returns {string[]} */ export function getMessages(messages) { return messages.map(mw.msg); } /** * `Array#findIndex` analog that looks for the _last_ index. * * @param {Array} arr * @param {Function} callback * @returns {?number} */ export function findLastIndex(arr, callback) { for (let i = arr.length - 1; i >= 0; i--) { if (callback(arr[i])) { return i; } } return null; } /** * Check if an input or editable element is focused. * * @returns {boolean} */ export function isInputFocused() { return $(':focus:input').length || $(':focus').prop('isContentEditable'); } /** * Turn many regexps into one, putting it in `()` and separating individual expressions by `|`. * * @param {RegExp[]|string[]} arr * @returns {?RegExp} */ export function mergeRegexps(arr) { if (!arr) { return null; } const pattern = arr .map((regexpOrString) => regexpOrString.source || regexpOrString) .join('|'); return pattern ? new RegExp(`(${pattern})`) : null; } /** * Replace text matched by a regexp with placeholders. * * @param {string} text * @param {RegExp} regexp * @param {string[]} hidden * @param {boolean} useAlternativeMarker * @returns {string} */ export function hideText(text, regexp, hidden, useAlternativeMarker) { return text.replace(regexp, (s, preText, textToHide) => { // If there are no groups, the offset is the second argument. if (typeof preText === 'number') { preText = null; textToHide = null; } // Handle tables separately return ( (preText || '') + (useAlternativeMarker ? '\x03' : '\x01') + hidden.push(textToHide || s) + (useAlternativeMarker ? '\x04' : '\x02') ); }); } /** * Replace placeholders created by {@link module:util.hide}. * * @param {string} text * @param {string[]} hidden * @returns {string} */ export function unhideText(text, hidden) { while (/(?:\x01|\x03)\d+(?:\x02|\x04)/.test(text)) { text = text.replace(/(?:\x01|\x03)(\d+)(?:\x02|\x04)/g, (s, num) => hidden[num - 1]); } return text; } /** * Save the scroll position to restore it later with {@link module:util.restoreScrollPosition}. * * @param {boolean} [saveTocHeight=true] Used for more fine control of scroll behavior after page * reloads and when visits are loaded. */ export function saveScrollPosition(saveTocHeight = true) { keptScrollPosition = window.pageYOffset; keptTocHeight = ( (saveTocHeight || keptTocHeight) && cd.g.$toc.length && !cd.g.isTocFloating && window.pageYOffset !== 0 && window.pageYOffset + window.innerHeight > cd.g.$toc.offset().top + cd.g.$toc.outerHeight() ) ? cd.g.$toc.outerHeight() : null; } /** * Restore the scroll position saved in {@link module:util.saveScrollPosition}. * * @param {boolean} [resetTocHeight=true] Used for more fine control of scroll behavior after page * reloads and when visits are loaded. */ export function restoreScrollPosition(resetTocHeight = true) { if (keptScrollPosition === null) return; if (keptTocHeight) { keptScrollPosition += (cd.g.$toc.outerHeight() || 0) - keptTocHeight; } window.scrollTo(0, keptScrollPosition); keptScrollPosition = null; if (resetTocHeight) { keptTocHeight = null; } } /** * Use a {@link * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/race * Promise.race()} workaround to get the state of a native promise. Note that it works _only_ with * native promises: it doesn't work with jQuery promises (for example, ones that `mw.Api()` return). * * @param {Promise} promise * @returns {string} */ export async function nativePromiseState(promise) { const obj = {}; return Promise.race([promise, obj]) .then((value) => value === obj ? 'pending' : 'resolved', () => 'rejected'); } /** * Show a notification suggesting to reload the page if the specified module is in the "loading" * state. Also return `true` in such a case. * * For the details of the bug, see https://phabricator.wikimedia.org/T68598 "mw.loader state of * module stuck at "loading" if request was aborted". * * @param {string} moduleName * @returns {boolean} */ export function dealWithLoadingBug(moduleName) { if (mw.loader.getState(moduleName) === 'loading') { const $body = cd.util.wrap(cd.sParse('error-needreloadpage'), { callbacks: { 'cd-notification-reloadPage': () => { location.reload(); }, }, }); mw.notify($body, { type: 'error' }); return true; } return false; } /** * Get the bounding client rectangle of an element, setting top and bottom values including top and * bottom margins to the `outerTop` and `outerBottom` properties. The top and bottom margins are * cached. * * @param {Element} el * @returns {object} */ export function getExtendedRect(el) { if (el.convenientDiscussionsMarginTop === undefined) { const style = window.getComputedStyle(el); el.convenientDiscussionsMarginTop = parseFloat(style.marginTop); el.convenientDiscussionsMarginBottom = parseFloat(style.marginBottom); } const rect = el.getBoundingClientRect(); return { outerTop: rect.top - el.convenientDiscussionsMarginTop, outerBottom: rect.bottom + el.convenientDiscussionsMarginBottom, top: rect.top, bottom: rect.top, left: rect.left, right: rect.right, width: rect.width, height: rect.height, }; } /** * Whether two objects are the same by value. Doesn't handle complex cases. `undefined` values are * treated as unexistent (this helps to compare values retrieved from the local storage as JSON: * `JSON.stringify()` removes all `undefined` values as well). * * @param {object} object1 First object. * @param {object} object2 Second object. * @param {boolean} [doesInclude=false] Test if all the values of the first object are contained in * the second object. * @returns {boolean} */ export function areObjectsEqual(object1, object2, doesInclude = false) { const isMultipartObject = (val) => ( val !== null && typeof val === 'object' && !( val instanceof RegExp || val instanceof Date || // This can be used in the worker context, where Node is an object and Worker is undefined. (typeof Node === 'function' && val instanceof Node) || (typeof Worker === 'function' && val instanceof Worker) ) ); const toPrimitiveValue = (val) => ( val instanceof RegExp || val instanceof Date ? val.toString() : val ); if (!isMultipartObject(object1) || !isMultipartObject(object2)) { return toPrimitiveValue(object1) === toPrimitiveValue(object2); } const keys1 = Object.keys(object1).filter((key) => object1[key] !== undefined); const keys2 = Object.keys(object2).filter((key) => object2[key] !== undefined); return ( (keys1.length === keys2.length || doesInclude) && keys1.every((key) => areObjectsEqual(object1[key], object2[key])) ); } /** * Helper to get the script's local storage item packed in JSON or an empty object in case of * unexistent/falsy/corrupt values. * * @param {string} name * @returns {object} */ export function getFromLocalStorage(name) { const json = localStorage.getItem(`convenientDiscussions-${name}`); let obj; if (json) { try { // "||" in case of a falsy value. obj = JSON.parse(json) || {}; } catch (e) { console.error(e, json); return {}; } } return obj || {}; } /** * Helper to set a local storage item. * * @param {string} name * @param {object} obj */ export function saveToLocalStorage(name, obj) { localStorage.setItem(`convenientDiscussions-${name}`, JSON.stringify(obj)); } /** * Remove left-to-right and right-to-left marks that sometimes are copied from the edit history to * the timestamp (for example, https://meta.wikimedia.org/w/index.php?diff=20418518) and also appear * after →/← in edit summaries. * * @param {string} text * @returns {string} */ export function removeDirMarks(text) { return text.replace(/[\u200E\u200F]/g, ''); } /** * @typedef {object} OoUiTextInputWidget * @see https://doc.wikimedia.org/oojs-ui/master/js/#!/api/OO.ui.TextInputWidget */ /** * Replace the selected text (if any) in an input (input or textarea) with the provided text and * keep the undo/redo functionality in browsers that support it (Chrome does, Firefox doesn't: * https://bugzilla.mozilla.org/show_bug.cgi?id=1220696). * * @param {OoUiTextInputWidget} input Input to set replace the selection in. * @param {string} text Text to replace the selection with. */ export function insertText(input, text) { input.focus(); if (!document.execCommand('insertText', false, text)) { input.insertContent(text); } } /** * Filter out values of an object that can't be safely passed to worker (see {@link * https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm}). * * @param {object} obj * @param {Array} [allowedFuncNames=[]] Names of the properties that should be passed to the worker * despite their values are functions (they are passed in a stringified form). * @param {Array} [disallowedNames=[]] Names of the properties that should be filtered out without * checking (allows to save time on greedy operations). * @returns {object} * @private */ export function keepWorkerSafeValues(obj, allowedFuncNames = [], disallowedNames = []) { const newObj = Object.assign({}, obj); Object.keys(newObj).forEach((key) => { if (disallowedNames.includes(key)) { delete newObj[key]; return; } const val = newObj[key]; if ( typeof val === 'object' && val !== null && !(val instanceof RegExp || val instanceof Date) ) { try { if (!areObjectsEqual(val, JSON.parse(JSON.stringify(val)))) { delete newObj[key]; } } catch (e) { delete newObj[key]; } } else if (typeof val === 'function') { if (allowedFuncNames.includes(key)) { newObj[key] = val.toString(); } else { delete newObj[key]; } } }); return newObj; } /** * Calculates the proportion of the number of words (minimum 2 characters long) present in both * strings to the total words count. * * @param {string} s1 * @param {string} s2 * @returns {number} * @private */ export function calculateWordsOverlap(s1, s2) { const regexp = new RegExp(`[${cd.g.LETTER_PATTERN}]{2,}`, 'g'); const words1 = (s1.match(regexp) || []).filter(unique); const words2 = (s2.match(regexp) || []).filter(unique); if (!words1.length || !words2.length) { return 0; } let total = words2.length; let overlap = 0; words1.forEach((word1) => { if (words2.some((word2) => word2 === word1)) { overlap++; } else { total++; } }); return overlap / total; } "
"/** * User class and object `userRegistry` used to obtain its instances while avoiding creating * duplicates. * * @module userRegistry */ import cd from './cd'; import { firstCharToUpperCase, underlinesToSpaces } from './util'; export default { /** * Collection of users. * * @type {object} */ users: {}, /** * Get the user object for a user with the specified name (either a new one or already existing). * * @param {string} name * @returns {User} */ getUser(name) { if (name.includes('#')) { name = name.slice(0, name.indexOf('#')); } if (mw.util.isIPv6Address(name)) { name = name.toUpperCase().trim(); } else { name = underlinesToSpaces(firstCharToUpperCase(name)).trim(); } if (!this.users[name]) { const options = name === cd.g.CURRENT_USER_NAME ? { gender: cd.g.CURRENT_USER_GENDER } : {}; this.users[name] = new User(name, options); } return this.users[name]; }, } /** * Class representing a user. Is made similar to `mw.user` so that it is possible to pass it to * `mw.msg` and have `{{gender:}}` replaced. */ class User { /** * Create a user object. * * @param {string} name * @param {object} options */ constructor(name, options = {}) { this.name = name; this.options = new mw.Map(); Object.keys(options).forEach((name) => { this[name] = options[name]; }); } /** * Is the user registered (not an IP user). * * @type {boolean} */ isRegistered() { if (this.cachedIsRegistered === undefined) { this.cachedIsRegistered = !mw.util.isIPAddress(this.name); } return this.cachedIsRegistered; } setGender(value) { this.options.set('gender', value); } /** * User's gender (must be obtained using {@link module:apiWrappers.getUserGenders}). * * @type {string} */ getGender() { return this.options.get('gender'); } } "
"/** * User options handling functions. * * @module options */ import lzString from 'lz-string'; import CdError from './CdError'; import cd from './cd'; import { firstCharToUpperCase } from './util'; import { getUserInfo, setGlobalOption, setLocalOption } from './apiWrappers'; /** * Pack the visits object into a string for further compression. * * @param {object} visits * @returns {string} */ export function packVisits(visits) { return Object.keys(visits) .map((key) => `${key},${visits[key].join(',')}\n`) .join('') .trim(); } /** * Unpack the visits string into a visits object. * * @param {string} visitsString * @returns {object} */ export function unpackVisits(visitsString) { const visits = {}; // " *" fixes a error previously made. Not needed for new sites. const regexp = /^(\d+), *(.+)$/gm; let match; while ((match = regexp.exec(visitsString))) { visits[match[1]] = match[2].split(','); } return visits; } /** * Pack the watched sections object into a string for further compression. * * @param {object} watchedSections * @returns {string} */ export function packWatchedSections(watchedSections) { return Object.keys(watchedSections).filter((pageId) => watchedSections[pageId].length) .map((key) => ` ${key} ${watchedSections[key].join('\n')}\n`) .join('') .trim(); } /** * Unpack the watched sections string into a visits object. * * @param {string} watchedSectionsString * @returns {object} */ export function unpackWatchedSections(watchedSectionsString) { const watchedSections = {}; const pages = watchedSectionsString.split(/(?:^|\n )(\d+) /).slice(1); let pageId; for ( let i = 0, isPageId = true; i < pages.length; i++, isPageId = !isPageId ) { if (isPageId) { pageId = pages[i]; } else { watchedSections[pageId] = pages[i].split('\n'); } } return watchedSections; } /** * Request the settings from the server. * * @param {object} [options={}] * @param {object} [options.options] Options object. * @param {boolean} [options.omitLocal=false] Whether to omit variables set via `cdLocal...` * variables (they shouldn't need to be saved to the server). * @param {boolean} [options.reuse=false] If `options` is not set, reuse the cached user info * request. * @returns {object} */ export async function getSettings({ options, omitLocal = false, reuse = false, } = {}) { if (!options) { ({ options } = await getUserInfo(reuse)); } let globalSettings; try { globalSettings = JSON.parse(options[cd.g.SETTINGS_OPTION_NAME]) || {}; } catch (e) { globalSettings = {}; } let localSettings; try { localSettings = JSON.parse(options[cd.g.LOCAL_SETTINGS_OPTION_NAME]) || {}; } catch (e) { localSettings = {}; } let settings = {}; Object.keys(cd.defaultSettings).forEach((name) => { (cd.settingAliases[name] || []).concat(name).forEach((alias) => { // Global settings override those set via personal JS. if ( globalSettings[alias] !== undefined && typeof globalSettings[alias] === typeof cd.defaultSettings[name] ) { settings[name] = globalSettings[alias]; } // Local settings override global. if ( localSettings[alias] !== undefined && typeof localSettings[alias] === typeof cd.defaultSettings[name] ) { settings[name] = localSettings[alias]; } }); }); if (!omitLocal) { Object.assign(settings, getLocalOverridingSettings()); } return settings; } /** * Get settings set in common.js that are meant to override native settings. * * @returns {object} */ export function getLocalOverridingSettings() { const settings = {}; Object.keys(cd.defaultSettings).forEach((name) => { (cd.settingAliases[name] || []).concat(name).forEach((alias) => { const varLocalAlias = 'cdLocal' + firstCharToUpperCase(alias); if ( varLocalAlias in window && typeof window[varLocalAlias] === typeof cd.defaultSettings[name] ) { settings[name] = window[varLocalAlias]; } }); }); return settings; } /** * Save the settings to the server. This function will split the settings into the global and local * ones and make two respective requests. * * @param {object} [settings] Settings to save. Otherwise, `cd.settings` is used. */ export async function setSettings(settings) { settings = settings || cd.settings; const globalSettings = {}; const localSettings = {}; Object.keys(settings).forEach((key) => { if (cd.localSettingNames.includes(key)) { localSettings[key] = settings[key]; } else { globalSettings[key] = settings[key]; } }); try { await Promise.all([ setLocalOption(cd.g.LOCAL_SETTINGS_OPTION_NAME, JSON.stringify(localSettings)), setGlobalOption(cd.g.SETTINGS_OPTION_NAME, JSON.stringify(globalSettings)) ]); } catch (e) { // The site doesn't support global preferences. if (e instanceof CdError && e.data.apiData && e.data.apiData.error.code === 'badvalue') { setLocalOption(cd.g.SETTINGS_OPTION_NAME, JSON.stringify(globalSettings)); } else { throw e; } } } /** * @typedef {object} GetVisitsReturn * @property {object} visits * @property {object} thisPageVisits */ /** * Request the pages visits data from the server. * * `mw.user.options` is not used even on the first run because the script may not run immediately * after the page has loaded. In fact, when the page is loaded in a background tab, it can be * throttled until it is focused, so an indefinite amount of time can pass. * * @param {boolean} [reuse=false] Whether to reuse a cached userinfo request. * @returns {GetVisitsReturn} */ export async function getVisits(reuse = false) { const visits = await ( cd.g.isFirstRun && mw.user.options.get(cd.g.VISITS_OPTION_NAME) === null ? Promise.resolve({}) : getUserInfo(reuse).then((options) => options.visits) ); const articleId = mw.config.get('wgArticleId'); let thisPageVisits; // This should always true; this check should be performed before. if (articleId) { visits[articleId] = visits[articleId] || []; thisPageVisits = visits[articleId]; } // These variables are not used anywhere in the script but can be helpful for testing purposes. cd.g.visits = visits; cd.g.thisPageVisits = thisPageVisits; return { visits, thisPageVisits }; } /** * Remove the oldest 10% of visits when the size limit is hit. * * @param {object} originalVisits * @returns {object} * @private */ function cleanUpVisits(originalVisits) { const visits = Object.assign({}, originalVisits); const timestamps = Object.keys(visits).reduce((acc, key) => acc.concat(visits[key]), []); timestamps.sort(); const boundary = timestamps[Math.floor(timestamps.length / 10)]; Object.keys(visits).forEach((key) => { visits[key] = visits[key].filter((visit) => visit >= boundary); if (!visits[key].length) { delete visits[key]; } }); return visits; } /** * Save the pages visits data to the server. * * @param {object} visits */ export async function setVisits(visits) { if (!visits) return; const visitsString = packVisits(visits); const visitsStringCompressed = lzString.compressToEncodedURIComponent(visitsString); try { await setLocalOption(cd.g.VISITS_OPTION_NAME, visitsStringCompressed); } catch (e) { if (e instanceof CdError) { const { type, code } = e.data; if (type === 'internal' && code === 'sizeLimit') { setVisits(cleanUpVisits(visits)); } else { console.error(e); } } else { console.error(e); } } } /** * Request the watched sections from the server and assign them to * `convenientDiscussions.g.watchedSections`. * * `mw.user.options` is not used even on first run because it appears to be cached sometimes which * can be critical for determining watched sections. * * @param {boolean} [reuse=false] Whether to reuse a cached userinfo request. * @param {object} [keptData={}] * @param {string} [keptData.justWatchedSection] Name of the section that was watched within seconds * before making this request (it could be not enough time for it to appear in the response). * @param {string} [keptData.justUnwatchedSection] Name of the section that was unwatched within * seconds before making this request (it could be not enough time for it to appear in the * response). */ export async function getWatchedSections(reuse = false, keptData = {}) { const watchedSections = await ( cd.g.isFirstRun && mw.user.options.get(cd.g.WATCHED_SECTIONS_OPTION_NAME) === null ? Promise.resolve({}) : getUserInfo(reuse).then((options) => options.watchedSections) ); const articleId = mw.config.get('wgArticleId'); let thisPageWatchedSections; if (articleId) { watchedSections[articleId] = watchedSections[articleId] || []; thisPageWatchedSections = watchedSections[articleId]; // Manually add/remove a section that was added/removed at the same moment the page was // reloaded the last time, so when we requested watched sections from server, this section // wasn't there yet most probably. if (keptData.justWatchedSection) { if (!thisPageWatchedSections.includes(keptData.justWatchedSection)) { thisPageWatchedSections.push(keptData.justWatchedSection); } } if (keptData.justUnwatchedSection) { if (thisPageWatchedSections.includes(keptData.justUnwatchedSection)) { thisPageWatchedSections .splice(thisPageWatchedSections.indexOf(keptData.justUnwatchedSection), 1); } } } cd.g.watchedSections = watchedSections; cd.g.thisPageWatchedSections = thisPageWatchedSections; } /** * Save the watched sections kept in `convenientDiscussions.g.watchedSections` to the server. */ export async function setWatchedSections() { const watchedSectionsString = packWatchedSections(cd.g.watchedSections); const watchedSectionsStringCompressed = ( lzString.compressToEncodedURIComponent(watchedSectionsString) ); await setLocalOption(cd.g.WATCHED_SECTIONS_OPTION_NAME, watchedSectionsStringCompressed); } "
"/** * Wrappers for MediaWiki action API requests ({@link * https://www.mediawiki.org/wiki/API:Main_page}). See also the {@link module:Page Page class} * methods for functions regarding concrete page names. * * @module apiWrappers */ import lzString from 'lz-string'; import CdError from './CdError'; import cd from './cd'; import userRegistry from './userRegistry'; import { defined, handleApiReject } from './util'; import { unpackVisits, unpackWatchedSections } from './options'; let cachedUserInfoRequest; let currentAutocompletePromise; const autocompleteTimeout = 100; /** * Make a request that won't set the process on hold when the tab is in the background. * * @param {object} params * @param {string} [method='post'] * @returns {Promise} */ export function makeBackgroundRequest(params, method = 'post') { return new Promise((resolve, reject) => { cd.g.api[method](params, { success: (resp) => { if (resp.error) { reject('api', resp); } else { resolve(resp); } }, error: (jqXHR, textStatus) => { reject('http', textStatus); }, }); }); } /** * Make a parse request with arbitrary code. We assume that if something is parsed, it will be * shown, so we automatically load modules. * * @param {string} code * @param {object} [customOptions] * @returns {Promise} * @throws {CdError} */ export async function parseCode(code, customOptions) { const defaultOptions = { action: 'parse', text: code, contentmodel: 'wikitext', prop: ['text', 'modules'], pst: true, disablelimitreport: true, formatversion: 2, }; const options = Object.assign({}, defaultOptions, customOptions); return cd.g.api.post(options).then( (resp) => { const html = resp.parse?.text; if (html) { mw.loader.load(resp.parse.modules); mw.loader.load(resp.parse.modulestyles); } else { throw new CdError({ type: 'api', code: 'noData', }); } const parsedSummary = resp.parse.parsedsummary; if (customOptions?.summary && !parsedSummary) { throw new CdError({ type: 'api', code: 'noData', }); } return { html, parsedSummary }; }, handleApiReject ); } /** * Make a userinfo request (see {@link https://www.mediawiki.org/wiki/API:Userinfo}). * * @param {boolean} [reuse=false] Whether to reuse a cached request. * @returns {Promise} Promise for an object containing the full options object, visits, watched * sections, and rights. * @throws {CdError} */ export function getUserInfo(reuse = false) { if (reuse && cachedUserInfoRequest) { return cachedUserInfoRequest; } cd.g.api = cd.g.api || new mw.Api(); cachedUserInfoRequest = cd.g.api.post({ action: 'query', meta: 'userinfo', uiprop: ['options', 'rights'], formatversion: 2, }).then( (resp) => { const userinfo = resp.query?.userinfo; const options = userinfo?.options; const rights = userinfo?.rights; if (!options || !rights) { throw new CdError({ type: 'api', code: 'noData', }); } const visitsCompressed = options[cd.g.VISITS_OPTION_NAME]; const visitsString = visitsCompressed ? lzString.decompressFromEncodedURIComponent(visitsCompressed) : ''; const visits = unpackVisits(visitsString); const watchedSectionsCompressed = options[cd.g.WATCHED_SECTIONS_OPTION_NAME]; const watchedSectionsString = watchedSectionsCompressed ? lzString.decompressFromEncodedURIComponent(watchedSectionsCompressed) : ''; const watchedSections = unpackWatchedSections(watchedSectionsString); cd.g.CURRENT_USER_RIGHTS = rights; return { options, visits, watchedSections, rights }; }, handleApiReject ); return cachedUserInfoRequest; } /** * Generate an error text for an unknown error. * * @param {string} errorCode * @param {string} [errorInfo] * @returns {string} * @private */ export async function unknownApiErrorText(errorCode, errorInfo) { let text; if (errorCode) { text = cd.sParse('error-api', errorCode) + ' '; if (errorInfo) { try { const { html } = await parseCode(errorInfo); text += html; } catch (e) { text += errorInfo; } } } return text; } /** * Get page titles for an array of page IDs. * * @param {number[]} pageIds * @returns {object[]} * @throws {CdError} */ export async function getPageTitles(pageIds) { const pages = []; const limit = cd.g.CURRENT_USER_RIGHTS?.includes('apihighlimits') ? 500 : 50; let nextPageIds; while ((nextPageIds = pageIds.splice(0, limit).join('|'))) { const resp = await cd.g.api.post({ action: 'query', pageids: nextPageIds, formatversion: 2, }).catch(handleApiReject); if (resp.error) { throw new CdError({ type: 'api', code: 'error', apiData: resp, }); } const query = resp.query; const thisPages = query?.pages; if (!thisPages) { throw new CdError({ type: 'api', code: 'noData', }); } pages.push(...thisPages); } return pages; } /** * Get page IDs for an array of page titles. * * @param {string[]} pageTitles * @returns {object[]} * @throws {CdError} */ export async function getPageIds(pageTitles) { const pages = []; const normalized = []; const redirects = []; const limit = cd.g.CURRENT_USER_RIGHTS?.includes('apihighlimits') ? 500 : 50; let nextPageTitles; while ((nextPageTitles = pageTitles.splice(0, limit).join('|'))) { const resp = await cd.g.api.post({ action: 'query', titles: nextPageTitles, redirects: true, formatversion: 2, }).catch(handleApiReject); if (resp.error) { throw new CdError({ type: 'api', code: 'error', apiData: resp, }); } const query = resp.query; const thisPages = query?.pages; if (!thisPages) { throw new CdError({ type: 'api', code: 'noData', }); } normalized.push(...query.normalized || []); redirects.push(...query.redirects || []); pages.push(...thisPages); } return { pages, normalized, redirects }; } /** * Generic function for setting an option. * * @param {string} name * @param {string} value * @param {string} action * @private */ async function setOption(name, value, action) { if (value && value.length > 65535) { throw new CdError({ type: 'internal', code: 'sizeLimit', details: { action }, }); } const resp = await makeBackgroundRequest(cd.g.api.assertCurrentUser({ action: action, optionname: name, // Global options can't be deleted because of the bug https://phabricator.wikimedia.org/T207448. optionvalue: value === undefined && action === 'globalpreferences' ? '' : value, }), 'postWithEditToken').catch(handleApiReject); if (!resp || resp[action] !== 'success') { throw new CdError({ type: 'api', code: 'noSuccess', details: { action }, }); } } /** * Set an option value. See {@link https://www.mediawiki.org/wiki/API:Options}. * * @param {string} name * @param {string} value * @throws {CdError} */ export async function setLocalOption(name, value) { await setOption(name, value, 'options'); } /** * Set a global preferences' option value. See {@link * https://www.mediawiki.org/wiki/Extension:GlobalPreferences/API}. * * @param {string} name * @param {string} value * @throws {CdError} */ export async function setGlobalOption(name, value) { await setOption(name, value, 'globalpreferences'); } /** * Request genders of a list of users. A gender may be `'male'`, `'female'`, or `'unknown'`. * * @param {User[]} users * @param {boolean} [requestInBackground=false] Make a request that won't set the process on hold * when the tab is in the background. * @throws {CdError} */ export async function getUserGenders(users, requestInBackground = false) { const usersToRequest = users .filter((user) => !user.getGender()) .map((user) => user.name); const limit = cd.g.CURRENT_USER_RIGHTS?.includes('apihighlimits') ? 500 : 50; let nextUsers; while ((nextUsers = usersToRequest.splice(0, limit).join('|'))) { const options = { action: 'query', list: 'users', ususers: nextUsers, usprop: 'gender', formatversion: 2, }; const resp = await (requestInBackground ? makeBackgroundRequest(options) : cd.g.api.post(options)) .catch(handleApiReject); const users = resp.query?.users; if (!users) { throw new CdError({ type: 'api', code: 'noData', }); } users .filter((user) => user.gender) .forEach((user) => { userRegistry.getUser(user.name).setGender(user.gender); }); } } /** * Get a list of 10 user names matching the specified search text. User names are sorted as {@link * https://www.mediawiki.org/wiki/API:Opensearch OpenSearch} sorts them. Only users with a talk page * existent are included. Redirects are resolved. * * Reuses the existing request if available. * * @param {string} text * @returns {Promise} Promise for a string array. * @throws {CdError} */ export function getRelevantUserNames(text) { const promise = new Promise((resolve, reject) => { setTimeout(() => { try { if (promise !== currentAutocompletePromise) { throw new CdError(); } cd.g.api.get({ action: 'opensearch', search: text, namespace: 3, redirects: 'resolve', limit: 10, formatversion: 2, }).then( (resp) => { const users = resp[1] ?.map((name) => (name.match(cd.g.USER_NAMESPACES_REGEXP) || [])[1]) .filter(defined) .filter((name) => !name.includes('/')); if (!users) { throw new CdError({ type: 'api', code: 'noData', }); } resolve(users); }, (e) => { handleApiReject(e); } ); } catch (e) { reject(e); } }, autocompleteTimeout); }); currentAutocompletePromise = promise; return promise; } /** * Get a list of 10 page names matching the specified search text. Page names are sorted as {@link * https://www.mediawiki.org/wiki/API:Opensearch OpenSearch} sorts them. Redirects are not resolved. * * Reuses the existing request if available. * * @param {string} text * @returns {Promise} Promise for a string array. * @throws {CdError} */ export function getRelevantPageNames(text) { let colonPrefix = false; if (cd.g.COLON_NAMESPACES_PREFIX_REGEXP.test(text)) { text = text.slice(1); colonPrefix = true; } const promise = new Promise((resolve, reject) => { setTimeout(() => { try { if (promise !== currentAutocompletePromise) { throw new CdError(); } cd.g.api.get({ action: 'opensearch', search: text, redirects: 'return', limit: 10, formatversion: 2, }).then( (resp) => { const regexp = new RegExp('^' + mw.util.escapeRegExp(text[0]), 'i'); const pages = resp[1]?.map((name) => ( name .replace(regexp, () => text[0]) .replace(/^/, colonPrefix ? ':' : '') )); if (!pages) { throw new CdError({ type: 'api', code: 'noData', }); } resolve(pages); }, (e) => { handleApiReject(e); } ); } catch (e) { reject(e); } }, autocompleteTimeout); }); currentAutocompletePromise = promise; return promise; } /** * Get a list of 10 template names matching the specified search text. Template names are sorted as * {@link https://www.mediawiki.org/wiki/API:Opensearch OpenSearch} sorts them. Redirects are not * resolved. * * Reuses the existing request if available. * * @param {string} text * @returns {Promise} Promise for a string array. * @throws {CdError} */ export function getRelevantTemplateNames(text) { const promise = new Promise((resolve, reject) => { setTimeout(() => { try { if (promise !== currentAutocompletePromise) { throw new CdError(); } cd.g.api.get({ action: 'opensearch', search: text.startsWith(':') ? text.slice(1) : 'Template:' + text, redirects: 'return', limit: 10, formatversion: 2, }).then( (resp) => { const regexp = new RegExp('^' + mw.util.escapeRegExp(text[0]), 'i'); const templates = resp[1] ?.filter((name) => !name.endsWith('/doc')) .map((name) => text.startsWith(':') ? name : name.slice(name.indexOf(':') + 1)) .map((name) => name.replace(regexp, () => text[0])); if (!templates) { throw new CdError({ type: 'api', code: 'noData', }); } resolve(templates); }, (e) => { handleApiReject(e); } ); } catch (e) { reject(e); } }, autocompleteTimeout); }); currentAutocompletePromise = promise; return promise; } "
"/** * Autocomplete mechanism. * * @module Autocomplete */ import Tribute from '../tribute/Tribute'; import cd from './cd'; import userRegistry from './userRegistry'; import { defined, handleApiReject, insertText, removeDoubleSpaces, unique } from './util'; import { getRelevantPageNames, getRelevantTemplateNames, getRelevantUserNames, } from './apiWrappers'; /** * Autocomplete class. */ export default class Autocomplete { /** * @typedef {object} OoUiTextInputWidget * @see https://doc.wikimedia.org/oojs-ui/master/js/#!/api/OO.ui.TextInputWidget */ /** * Create an autocomplete instance. An instance is a set of settings and inputs to which these * settings apply. * * @param {object} options * @param {string[]} options.types Which values should be autocompleted. Can contain `'mentions'`, * `'wikilinks'`, `'templates'`, and `'tags'`. * @param {OoUiTextInputWidget[]} options.inputs Inputs to attach the autocomplete to. * @param {string[]} [options.comments] List of comments in the section for the mentions and * comment links autocomplete. * @param {string[]} [options.defaultUserNames] Default list of user names for the mentions * autocomplete. */ constructor({ types, inputs, comments, defaultUserNames }) { types = types // The "mentions" type is needed in any case, as it can be triggered from the toolbar. When it // is not, we will suppress it specifically. .filter((type) => cd.settings.autocompleteTypes.includes(type) || type === 'mentions') const collections = this.getCollections(types, comments, defaultUserNames); require('../tribute/tribute.less'); /** * {@link https://github.com/zurb/tribute Tribute} object. * * @type {Tribute} */ this.tribute = new Tribute({ collection: collections, allowSpaces: true, menuItemLimit: 10, noMatchTemplate: () => null, containerClass: 'tribute-container cd-autocompleteContainer', replaceTextSuffix: '', isRtl: cd.g.SITE_DIR === 'rtl', }); inputs.forEach((input) => { const element = input.$input.get(0); this.tribute.attach(element); element.cdInput = input; element.addEventListener('tribute-active-true', () => { cd.g.activeAutocompleteMenu = this.tribute.menu; }); element.addEventListener('tribute-active-false', () => { cd.g.activeAutocompleteMenu = null; }); if (input instanceof OO.ui.MultilineTextInputWidget) { input.on('resize', () => { this.tribute.menuEvents.windowResizeEvent?.(); }); } }); } /** * Get a list of collections of specified types. * * @param {string[]} types * @param {string[]} comments * @param {string[]} defaultUserNames * @returns {object[]} * @private */ getCollections(types, comments, defaultUserNames) { const selectTemplate = (item) => { if (item) { return item.original.transform(item.original.item); } else { return ''; } }; const prepareValues = (arr, config) => ( arr .filter(defined) .filter(unique) .map((item) => { let key; if (Array.isArray(item)) { // Tags key = item[0]; } else if (item.key) { // Comment links key = item.key; } else { // The rest key = item; } const transform = config.transform; return { key, item, transform }; }) ); const spacesRegexp = new RegExp(cd.mws('word-separator'), 'g'); const collectionsByType = { mentions: { trigger: cd.config.mentionCharacter, searchOpts: { skip: true }, requireLeadingSpace: cd.config.mentionRequiresLeadingSpace, selectTemplate, values: async (text, callback) => { if ( !cd.settings.autocompleteTypes.includes('mentions') && !this.tribute.current.externalTrigger ) { return; } text = removeDoubleSpaces(text); if (!text.startsWith(this.mentions.snapshot)) { this.mentions.cache = []; } this.mentions.snapshot = text; if (text.includes('[[')) { callback([]); return; } if (this.mentions.byText[text]) { callback(prepareValues(this.mentions.byText[text], this.mentions)); } else { const matches = Autocomplete.search(text, this.mentions.default); let values = matches.slice(); const makeRequest = ( text && text.length <= 85 && !/[#<>[\]|{}/@:]/.test(text) && // 5 spaces in a user name seem too many. "Jack who built the house" has 4 :-) (text.match(spacesRegexp) || []).length <= 4 ); if (makeRequest) { // Logically, either `matched` or `this.mentions.cache` should have a zero length (a // request is made only if there are no matches in the section; if there are, // `this.mentions.cache` is an empty array). if (!matches.length) { values.push(...this.mentions.cache); } values = Autocomplete.search(text, values); // Make the typed text always appear on the last, 10th place. values[9] = text.trim(); } callback(prepareValues(values, this.mentions)); if (makeRequest && !matches.length) { let values; try { values = await getRelevantUserNames(text); } catch (e) { return; } // Type "[[Text", then delete and type "<s" quickly. if (!this.tribute.current || this.tribute.current.trigger !== '@') return; values = this.mentions.removeSelf(values); this.mentions.cache = values.slice(); // Make the typed text always appear on the last, 10th place. values[9] = text.trim(); this.mentions.byText[text] = values; // The text has been updated since the request was made. if (this.mentions.snapshot !== text) return; callback(prepareValues(values, this.mentions)); } } }, }, wikilinks: { trigger: '[[', keepAsEnd: /^(?:\||\]\])/, searchOpts: { skip: true }, selectTemplate, values: async (text, callback) => { text = removeDoubleSpaces(text); if (!text.startsWith(this.wikilinks.snapshot)) { this.wikilinks.cache = []; } this.wikilinks.snapshot = text; if (this.wikilinks.byText[text]) { callback(prepareValues(this.wikilinks.byText[text], this.wikilinks)); } else { let values = []; const valid = ( text && text !== ':' && text.length <= 255 && // 10 spaces in a page name seems too many. (text.match(spacesRegexp) || []).length <= 9 && // Forbidden characters !/[#<>[\]|{}]/.test(text) ); const makeRequest = ( valid && // Interwikis !( (/^:/.test(text) || /^[a-z]\w*:/.test(text)) && !cd.g.ALL_NAMESPACES_REGEXP.test(text) ) ); if (makeRequest) { values.push(...this.wikilinks.cache); values = Autocomplete.search(text, values); } if (valid) { // Make the typed text always appear on the last, 10th place. values[9] = text.trim(); } callback(prepareValues(values, this.wikilinks)); if (makeRequest) { let values; try { values = await getRelevantPageNames(text); } catch (e) { return; } // Type "[[Text", then delete and type "<s" quickly. if (!this.tribute.current || this.tribute.current.trigger !== '[[') return; this.wikilinks.cache = values.slice(); // Make the typed text always appear on the last, 10th place. values[9] = text.trim(); this.wikilinks.byText[text] = values; // The text has been updated since the request was made. if (this.wikilinks.snapshot !== text) return; callback(prepareValues(values, this.wikilinks)); } } }, }, templates: { trigger: '{{', keepAsEnd: /^(?:\||\}\})/, searchOpts: { skip: true }, selectTemplate: (item, event) => { if (item) { if (cd.settings.useTemplateData && event.shiftKey && !event.altKey) { const input = this.tribute.current.element.cdInput; setTimeout(() => { input.setDisabled(true); input.pushPending(); cd.g.api.get({ action: 'templatedata', titles: `Template:${item.original.key}`, redirects: true, }) .then( (resp) => { if (!resp.pages) { throw 'No data.'; } else if (!Object.keys(resp.pages).length) { throw 'Template missing.'; } else { return resp; } }, handleApiReject ) .then( (resp) => { const pages = resp.pages; let paramsString = ''; let firstValueIndex = 0; Object.keys(pages).forEach((key) => { const template = pages[key]; const params = template.params || []; const paramNames = template.paramOrder || Object.keys(params); paramNames .filter((param) => params[param].required || params[param].suggested) .forEach((param) => { if (template.format === 'block') { paramsString += `\n| ${param} = `; } else { if (isNaN(param)) { paramsString += `|${param}=`; } else { paramsString += `|`; } } if (!firstValueIndex) { firstValueIndex = paramsString.length; } }); if (template.format === 'block' && paramsString) { paramsString += '\n'; } }); // Remove leading "|". paramsString = paramsString.slice(1); input.setDisabled(false); const caretIndex = input.getRange().to; insertText(input, paramsString); input.selectRange(caretIndex + firstValueIndex - 1); }, (e) => { input.setDisabled(false); input.focus(); mw.notify(cd.s('cf-autocomplete-notemplatedata'), { type: 'error' }); console.warn(e); } ) .always(() => { input.popPending(); }); }); } return item.original.transform(item.original.item); } else { return ''; } }, values: async (text, callback) => { text = removeDoubleSpaces(text); if (!text.startsWith(this.templates.snapshot)) { this.templates.cache = []; } this.templates.snapshot = text; if (text.includes('{{')) { callback([]); return; } if (this.templates.byText[text]) { callback(prepareValues(this.templates.byText[text], this.templates)); } else { let values = []; const makeRequest = ( text && text.length <= 255 && !/[#<>[\]|{}]/.test(text) && // 10 spaces in a page name seems too many. (text.match(spacesRegexp) || []).length <= 9 ); if (makeRequest) { values.push(...this.templates.cache); values = Autocomplete.search(text, values); // Make the typed text always appear on the last, 10th place. values[9] = text.trim(); } callback(prepareValues(values, this.templates)); if (makeRequest) { let values; try { values = await getRelevantTemplateNames(text); } catch (e) { return; } // Type "[[Text", then delete and type "<s" quickly. if (!this.tribute.current || this.tribute.current.trigger !== '{{') return; this.templates.cache = values.slice(); // Make the typed text always appear on the last, 10th place. values[9] = text.trim(); this.templates.byText[text] = values; // The text has been updated since the request was made. if (this.templates.snapshot !== text) return; callback(prepareValues(values, this.templates)); } } }, }, tags: { trigger: '<', keepAsEnd: /^>/, searchOpts: { skip: true }, selectTemplate, values: (text, callback) => { const regexp = new RegExp('^' + mw.util.escapeRegExp(text), 'i'); if (!text || !/^[a-z]+$/i.test(text)) { callback([]); return; } const matches = this.tags.default.filter((tag) => regexp.test(tag)); callback(prepareValues(matches, this.tags)); }, }, commentLinks: { trigger: '[[#', keepAsEnd: /^\]\]/, selectTemplate, values: async (text, callback) => { if (!this.commentLinks.default) { this.commentLinks.default = []; this.commentLinks.comments.forEach((comment) => { let { anchor, author, timestamp, getText } = comment; getText = getText.bind(comment); let snippet; const snippetMaxLength = 80; if (getText().length > snippetMaxLength) { snippet = getText().slice(0, snippetMaxLength); const spacePos = snippet.lastIndexOf(cd.mws('word-separator')); if (spacePos !== -1) { snippet = snippet.slice(0, spacePos); } } else { snippet = getText(); } let authortimestamp = author.name; if (timestamp) { authortimestamp += cd.mws('comma-separator') + timestamp; } const key = authortimestamp + cd.mws('colon-separator') + snippet; this.commentLinks.default.push({ key, anchor, author: author.name, timestamp, }); }); } text = removeDoubleSpaces(text); if (/[#<>[\]|{}]/.test(text)) { callback([]); return; } const matches = this.tribute.search .filter(text, this.commentLinks.default, { extract: (el) => el.key }) .map((match) => match.original); callback(prepareValues(matches, this.commentLinks)); }, }, }; const params = { mentions: defaultUserNames, commentLinks: comments, }; const collections = []; types.forEach((type) => { this[type] = Autocomplete.getConfig(type, params[type]); collections.push(collectionsByType[type]); }); return collections; } /** * Get an autocomplete configuration for the specified type. * * @param {string} type * @returns {object} * @private */ static getConfig(type) { let config; switch (type) { case 'mentions': { config = { byText: {}, cache: [], transform: (item) => { const name = item.trim(); const userNamespace = ( cd.config.userNamespacesByGender?.[userRegistry.getUser(name).getGender()] || mw.config.get('wgFormattedNamespaces')[2] ); return { start: `@[[${userNamespace}:${name}|`, end: ']]', content: name, ctrlModify: (data) => { data.end += cd.mws('colon-separator'); return data; }, }; }, removeSelf: (arr) => arr.filter((item) => item !== cd.g.CURRENT_USER_NAME), }; config.default = config.removeSelf(arguments[1] || []); break; } case 'wikilinks': { config = { byText: {}, cache: [], transform: (name) => { name = name.trim(); return { start: '[[' + name, end: ']]', name, shiftModify: (data) => { data.start += '|'; data.content = data.name; return data; }, }; }, }; break; } case 'templates': { config = { byText: {}, cache: [], transform: (name) => { name = name.trim(); return { start: '{{' + name, end: '}}', name, shiftModify: (data) => { data.start += '|'; return data; }, }; }, }; break; } case 'tags': { config = { default: [ // See https://meta.wikimedia.org/wiki/Help:HTML_in_wikitext#Permitted_HTML, // https://en.wikipedia.org/wiki/Help:HTML_in_wikitext#Parser_and_extension_tags. // Deprecated tags are not included. An element can be an array of a string to display // and strings to insert before and after the caret. 'abbr', 'b', 'bdi', 'bdo', 'blockquote', ['br', '<br>'], 'caption', 'cite', 'code', ['codenowiki', '<code><nowiki>', '</'.concat('nowiki></code>')], 'data', 'dd', 'del', 'dfn', 'div', 'dl', 'dt', 'em', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', ['hr', '<hr>'], 'i', 'ins', 'kbd', 'li', 'link', 'mark', 'meta', 'ol', 'p', 'pre', 'q', 'rp', 'rt', 'rtc', 'ruby', 's', 'samp', 'small', 'span', 'strong', 'sub', 'sup', 'table', 'td', 'th', 'time', 'tr', 'u', 'ul', 'var', ['wbr', '<wbr>'], 'gallery', 'includeonly', 'noinclude', 'nowiki', 'onlyinclude', 'categorytree', 'charinsert', 'chem', 'ce', 'graph', 'hiero', 'imagemap', 'indicator', 'inputbox', 'mapframe', 'maplink', 'math', 'poem', 'ref', ['references', '<references />'], 'score', 'section', 'syntaxhighlight', ['syntaxhighlight lang=""', '<syntaxhighlight lang="', '"></syntaxhighlight>'], 'templatedata', ['templatestyles', '<templatestyles src="', '" />'], 'timeline', ], transform: (item) => ({ start: Array.isArray(item) ? item[1] : `<${item}>`, end: Array.isArray(item) ? item[2] : `</${item}>`, typeContent: true, }), }; config.default.sort(); break; } case 'commentLinks': { config = { comments: arguments[1] || [], transform: ({ anchor, author, timestamp }) => ({ start: `[[#${anchor}|`, end: ']]', content: cd.s('cf-autocomplete-commentlinktext', author, timestamp), }), }; break; } } return config; } /** * Search for a string in a list of values. * * @param {string} s * @param {string[]} list * @returns {string[]} Matched results. * @private */ static search(s, list) { const containsRegexp = new RegExp(mw.util.escapeRegExp(s), 'i'); const startsWithRegexp = new RegExp('^' + mw.util.escapeRegExp(s), 'i'); return list .filter((item) => containsRegexp.test(item)) .sort((item1, item2) => { const item1StartsWith = startsWithRegexp.test(item1); const item2StartsWith = startsWithRegexp.test(item2); if (item1StartsWith && !item2StartsWith) { return -1; } else if (item2StartsWith && !item1StartsWith) { return 1; } else { return 0; } }); } } "
"/** * Methods related to comment forms. * * @module CommentFormStatic */ import CommentForm from './CommentForm'; import cd from './cd'; import { areObjectsEqual } from './util'; /** * Callback to be used in Array#sort() for comment forms. * * @param {CommentForm} commentForm1 * @param {CommentForm} commentForm2 * @returns {number} * @private */ function lastFocused(commentForm1, commentForm2) { const lastFocused1 = commentForm1.lastFocused || new Date(0); const lastFocused2 = commentForm2.lastFocused || new Date(0); if (lastFocused2 > lastFocused1) { return 1; } else if (lastFocused2 < lastFocused1) { return -1; } else { return 0; } } export default { /** * Get default preload configuration for the `addSection` mode. * * @returns {object} * @memberof module:CommentForm */ getDefaultPreloadConfig() { return { editIntro: undefined, commentTemplate: undefined, headline: undefined, summary: undefined, noHeadline: false, omitSignature: false, }; }, /** * Get the name of the correlated property of the comment form target based on the comment for * mode. * * @param {string} mode * @returns {string} * @private * @memberof module:CommentForm */ modeToProperty(mode) { return mode === 'replyInSection' ? 'addReply' : mode; }, /** * Get the last active comment form. * * @returns {?CommentForm} * @memberof module:CommentForm */ getLastActive() { return ( cd.commentForms .slice() .sort(lastFocused)[0] || null ); }, /** * Get the last active comment form that has received an input. This includes altering text * fields, not checkboxes. * * @returns {?CommentForm} * @memberof module:CommentForm */ getLastActiveAltered() { return ( cd.commentForms .slice() .sort(lastFocused) .find((commentForm) => commentForm.isAltered()) || null ); }, /** * Create an add section form if not existent. * * @param {object} [preloadConfig] * @param {boolean} [isNewTopicOnTop=false] * @private */ createAddSectionForm( preloadConfig = CommentForm.getDefaultPreloadConfig(), isNewTopicOnTop = false ) { const addSectionForm = cd.g.addSectionForm; if (addSectionForm) { // Sometimes there is more than one "Add section" button on the page, and they lead to opening // forms with different content. if (!areObjectsEqual(preloadConfig, addSectionForm.preloadConfig)) { mw.notify(cd.s('cf-error-formconflict'), { type: 'error' }); return; } addSectionForm.$element.cdScrollIntoView('center'); // Headline input may be missing if the "nosummary" preload parameter is truthy. addSectionForm[addSectionForm.headlineInput ? 'headlineInput' : 'commentInput'].focus(); } else { /** * Add section form. * * @type {CommentForm|undefined} * @memberof module:cd~convenientDiscussions.g */ cd.g.addSectionForm = new CommentForm({ mode: 'addSection', target: cd.g.CURRENT_PAGE, preloadConfig, isNewTopicOnTop, }); } }, }; "
"/** * Comment timestamp and author processing utilities. These are mostly format conversion utilities. * Listing of different formats of dates, digits, and timezones together with regexp and parser * generators go in {@link module:siteData}. Functions related to wikitext parsing go in {@link * module:wikitext}. * * Terminology used here (and in other modules): * - "date" is a `Date` object, * - "timestamp" is a string date as it is present on wiki pages (`23:29, 10 May 2019 (UTC)`). * * @module timestamp */ import cd from './cd'; import { getMessages, removeDirMarks, spacesToUnderlines } from './util'; let parseTimestampRegexp; let parseTimestampRegexpNoTimezone; /** * @typedef {object} ParseTimestampReturn * @property {Date} date * @property {object} match */ /** * Parse a timestamp, and return a date and the match object. * * @param {string} timestamp * @param {number} [timezoneOffset] Timezone offset in minutes. * @returns {?ParseTimestampReturn} */ export function parseTimestamp(timestamp, timezoneOffset) { // Remove left-to-right and right-to-left marks that sometimes are copied from the edit history to // the timestamp (for example, https://meta.wikimedia.org/w/index.php?diff=20418518). timestamp = removeDirMarks(timestamp); // Creating these regexps every time takes too long (say, 10ms for 1000 runs on an average // machine), so we cache them. if (!parseTimestampRegexp) { parseTimestampRegexp = new RegExp(`^([^]*)(${cd.g.TIMESTAMP_REGEXP.source})(?!["'»])`); parseTimestampRegexpNoTimezone = new RegExp( `^([^]*)(${cd.g.TIMESTAMP_REGEXP_NO_TIMEZONE.source})` ); } const regexp = timezoneOffset === undefined ? parseTimestampRegexp : parseTimestampRegexpNoTimezone; const match = timestamp.match(regexp); if (!match) { return null; } const date = cd.g.TIMESTAMP_PARSER(match, cd, timezoneOffset); return { date, match }; } /** * Pad a number with zeros like this: `4` → `04` or `0004`. * * @param {number} number Number to pad. * @param {number} length Length of the resultant string. * @returns {string} * @private */ function zeroPad(number, length) { return ('0000' + number).slice(-length); } /** * Convert a date to a string in the timestamp format. * * @param {Date} date * @returns {string} */ export function formatDate(date) { const format = cd.g.DATE_FORMAT; let s = ''; for (let p = 0; p < format.length; p++) { let code = format[p]; if (code === 'x' && p < format.length - 1) { code += format[++p]; } if (code === 'xk' && p < format.length - 1) { code += format[++p]; } switch (code) { case 'xx': s += 'x'; break; case 'xg': s += getMessages([ 'january-gen', 'february-gen', 'march-gen', 'april-gen', 'may-gen', 'june-gen', 'july-gen', 'august-gen', 'september-gen', 'october-gen', 'november-gen', 'december-gen' ])[date.getUTCMonth()]; break; case 'd': s += zeroPad(date.getUTCDate(), 2); break; case 'D': s += getMessages(['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'])[date.getUTCDay()]; break; case 'j': s += date.getUTCDate(); break; case 'l': s += getMessages([ 'sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday' ])[date.getDay()]; break; case 'F': s += getMessages([ 'january', 'february', 'march', 'april', 'may_long', 'june', 'july', 'august', 'september', 'october', 'november', 'december' ])[date.getUTCMonth()]; break; case 'M': s += getMessages([ 'jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec' ])[date.getUTCMonth()]; break; case 'n': s += date.getUTCMonth() + 1; break; case 'Y': s += date.getUTCFullYear(); break; case 'xkY': s += date.getUTCFullYear() + 543; break; case 'G': s += date.getUTCHours(); break; case 'H': s += zeroPad(date.getUTCHours(), 2); break; case 'i': s += zeroPad(date.getUTCMinutes(), 2); break; case '\\': // Backslash escaping if (p < format.length - 1) { s += format[++p]; } else { s += '\\'; } break; case '"': // Quoted literal if (p < format.length - 1) { const endQuote = format.indexOf('"', p + 1) if (endQuote === -1) { // No terminating quote, assume literal " s += '"'; } else { s += format.substr(p + 1, endQuote - p - 1); p = endQuote; } } else { // Quote at end of string, assume literal " s += '"'; } break; default: s += format[p]; } } return s; } /** * Generate a comment anchor from a date and author. * * @param {Date} date * @param {string} [author] * @param {boolean} [resolveCollisions=false] If set to `true`, anchors that collide with anchors * already registered via {@link module:timestamp.registerCommentAnchor} will get a `_<number>` * postfix. * @returns {string} */ export function generateCommentAnchor(date, author, resolveCollisions = false) { let year = date.getUTCFullYear(); let month = date.getUTCMonth(); let day = date.getUTCDate(); let hours = date.getUTCHours(); let minutes = date.getUTCMinutes(); let anchor = ( zeroPad(year, 4) + zeroPad(month + 1, 2) + zeroPad(day, 2) + zeroPad(hours, 2) + zeroPad(minutes, 2) + (author ? '_' + spacesToUnderlines(author) : '') ); if (resolveCollisions && commentAnchors.includes(anchor)) { let anchorNum = 2; const base = anchor; do { anchor = `${base}_${anchorNum}`; anchorNum++; } while (commentAnchors.includes(anchor)); } return anchor; } let commentAnchors = []; /** * Add a comment anchor to the registry to avoid collisions. * * @param {string} anchor */ export function registerCommentAnchor(anchor) { if (anchor) { commentAnchors.push(anchor); } } /** * Empty the comment anchor registry. * * Meant to be executed any time we start processing a new page. If we forget to run it, the newly * registered anchors can get extra `_2` or similar text at the end due to collisions with the * existing anchors that were not unloaded. */ export function resetCommentAnchors() { commentAnchors = []; } /** * @typedef {object} ParseCommentAnchorReturn * @property {Date} date * @property {string} author */ /** * Extract a date and author from a comment anchor. * * @param {string} commentAnchor * @returns {?ParseCommentAnchorReturn} */ export function parseCommentAnchor(commentAnchor) { const match = commentAnchor.match(/^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})_(.+)$/); if (!match) { return null; } const year = Number(match[1]); const month = Number(match[2]) - 1; const day = Number(match[3]); const hours = Number(match[4]); const minutes = Number(match[5]); const author = match[6]; const date = new Date(Date.UTC(year, month, day, hours, minutes)); return { date, author }; } "
"/** * Wikitext parsing and processing functions. * * @module wikitext */ import html_entity_decode from 'locutus/php/strings/html_entity_decode'; import cd from './cd'; import userRegistry from './userRegistry'; import { generateCommentAnchor, parseTimestamp, registerCommentAnchor, resetCommentAnchors, } from './timestamp'; import { hideText } from './util'; /** * Conceal HTML comments (`<!-- -->`), `&lt;nowiki&gt;`, `&lt;syntaxhighlight&gt;`, * `&lt;source&gt;`, and `&lt;pre&gt;` tags content, left-to-right and right-to-left marks, and also * newlines inside some tags (`<br\n>`) in the code. * * This is used to ignore comment contents (there could be section code examples for novices there * that could confuse search results) but get right positions and code in the result. * * @param {string} code * @param {boolean} [replaceMarks=true] Whether to replace left-to-right and right-to-left marks. * @returns {string} */ export function hideDistractingCode(code, replaceMarks = true) { let newCode = code .replace( /(<(?:nowiki|syntaxhighlight|source|pre)(?: [\w ]+(?:=[^<>]+?)?| ?)>)([^]*?)(<\/(?:nowiki|syntaxhighlight|source|pre)(?: \w+)? ?>)/g, (s, before, content, after) => before + ' '.repeat(content.length) + after ) .replace(/<!--([^]*?)-->/g, (s, content) => '\x01' + ' '.repeat(content.length + 5) + '\x02') .replace( /(<\/?(?:br|p)\b.*)(\n+)(>)/g, (s, before, newline, after) => before + ' '.repeat(newline.length) + after ); if (replaceMarks) { newCode = newCode.replace(/[\u200E\u200F]/g, (s) => ' '.repeat(s.length)); } return newCode; } /** * Find the first timestamp related to a comment in the code. * * @param {string} code * @returns {?string} */ export function findFirstTimestamp(code) { const signatures = extractSignatures(code); return signatures.length ? signatures[0].timestamp : null; } /** * Remove certain kinds of wiki markup from code, such as formatting, links, tags, and comments. * Also replace multiple spaces with one and trim the input. The product of this function is not for * display (for example, it just removes template names making the resulting code look silly), but * for comparing purposes. * * @param {string} code * @returns {string} */ export function removeWikiMarkup(code) { return code // Remove comments .replace(/<!--[^]*?-->/g, '') // Remove text hidden by the script (for example, in wikitext.hideDistractingCode) .replace(/\x01 *\x02/g, '') // Pipe trick .replace(/(\[\[:?(?:[^|[\]<>\n:]+:)?([^|[\]<>\n]+)\|)(\]\])/g, '$1$2$3') // Extract displayed text from file embeddings .replace(cd.g.FILE_LINK_REGEXP, '$1') // Extract displayed text from [[wikilinks]] .replace(/\[\[:?(?:[^|[\]<>\n]+\|)?(.+?)\]\]/g, '$1') // For optimization purposes, remove template names .replace(/\{\{:?(?:[^|{}<>\n]+)(?:\|(.+?))?\}\}/g, '$1') // Extract displayed text from [links] .replace(/\[https?:\/\/[^[\]<>"\n ]+ *([^\]]*)\]/g, '$1') // Remove bold .replace(/'''(.+?)'''/g, '$1') // Remove italics .replace(/''(.+?)''/g, '$1') // Replace <br> with a space .replace(/<br ?\/?>/g, ' ') // Remove opening tags (won't work with <smth param=">">, but the native parser fails too). .replace(/<\w+(?: [\w ]+(?:=[^<>]+?)?| ?\/?)>/g, '') // Remove closing tags .replace(/<\/\w+(?: \w+)? ?>/g, '') // Replace multiple spaces with one space .replace(/ {2,}/g, ' ') .trim(); } /** * Replace HTML entities with corresponding characters. Also replace different kinds of spaces, * including multiple, with one normal space. * * @param {string} text * @returns {string} */ export function normalizeCode(text) { return decodeHtmlEntities(text).replace(/\s+/g, ' ').trim(); } /** * Encode text to put it in a `[[wikilink]]`. This is meant for section links as the characters that * this function encodes are forbidden in page titles anyway, so page titles containing them are not * valid titles. * * @param {string} link * @returns {string} */ export function encodeWikilink(link) { return link // Tags .replace(/<(\w+(?: [\w ]+(?:=[^<>]+?)?| ?\/?)|\/\w+(?: \w+)? ?)>/g, '%3C$1%3E') .replace(/\[/g, '%5B') .replace(/\]/g, '%5D') .replace(/\{/g, '%7B') .replace(/\|/g, '%7C') .replace(/\}/g, '%7D') .replace(/\s+/g, ' '); } /** * Extract signatures that don't come from the unsigned templates from wikitext. * * @param {string} code * @returns {object[]} * @private */ function extractRegularSignatures(code) { const timestampRegexp = new RegExp( `^((.*)(${cd.g.TIMESTAMP_REGEXP.source})(?!["'»])(?:\\}\\}|</small>)?).*(?:\n*|$)`, 'igm' ); // ".*" helps to get the last author link. But after that we make another capture to make sure we // take the first link to the comment author. 251 is not arbitrary: it's 255 (maximum allowed // signature length) minus '[[u:a'.length plus ' '.length (the space before the timestamp). const signatureScanLimitWikitext = 251; const signatureRegexp = new RegExp( /* Captures: 1 - the whole line with the signature 2 - text before the last user link 3 - unprocessed signature 4 - author name (inside cd.g.CAPTURE_USER_NAME_PATTERN) 5 - sometimes, a slash appears here (inside cd.g.CAPTURE_USER_NAME_PATTERN) 6 - timestamp + small template ending characters / ending small tag 7 - timestamp 8 - new line characters or empty string */ `^((.*)(${cd.g.CAPTURE_USER_NAME_PATTERN}.{1,${signatureScanLimitWikitext}}((${cd.g.TIMESTAMP_REGEXP.source})(?:\\}\\}|</small>)?)).*)(\n*|$)`, 'igm' ); const authorLinkRegexp = new RegExp(cd.g.CAPTURE_USER_NAME_PATTERN, 'ig'); let signatures = []; let timestampMatch; while ((timestampMatch = timestampRegexp.exec(code))) { const line = timestampMatch[0]; signatureRegexp.lastIndex = 0; const authorTimestampMatch = signatureRegexp.exec(line); let author; let timestamp; let startIndex; let endIndex; let nextCommentStartIndex; let dirtyCode; if (authorTimestampMatch) { author = userRegistry.getUser(decodeHtmlEntities(authorTimestampMatch[4])); timestamp = authorTimestampMatch[7]; startIndex = timestampMatch.index + authorTimestampMatch[2].length; endIndex = timestampMatch.index + authorTimestampMatch[1].length; nextCommentStartIndex = timestampMatch.index + authorTimestampMatch[0].length; dirtyCode = authorTimestampMatch[3]; // Find the first link to this author in the preceding text. let authorLinkMatch; authorLinkRegexp.lastIndex = 0; const commentEndingStartIndex = Math.max( 0, authorTimestampMatch[0].length - authorTimestampMatch[6].length - authorTimestampMatch[authorTimestampMatch.length - 1].length - signatureScanLimitWikitext ); const commentEnding = authorTimestampMatch[0].slice(commentEndingStartIndex); while ((authorLinkMatch = authorLinkRegexp.exec(commentEnding))) { // Slash can be present in authorLinkMatch[2]. It often indicates a link to a page in the // author's userspace that is not part of the signature (while some such links are, and we // don't want to eliminate those cases). if (authorLinkMatch[2]) continue; const testAuthor = userRegistry.getUser(decodeHtmlEntities(authorLinkMatch[1])); if (testAuthor === author) { startIndex = timestampMatch.index + commentEndingStartIndex + authorLinkMatch.index; dirtyCode = code.slice(startIndex, endIndex); break; } } } else { timestamp = timestampMatch[3]; startIndex = timestampMatch.index + timestampMatch[2].length; endIndex = timestampMatch.index + timestampMatch[1].length; nextCommentStartIndex = timestampMatch.index + timestampMatch[0].length; dirtyCode = timestamp; } signatures.push({ author, timestamp, startIndex, endIndex, dirtyCode, nextCommentStartIndex }); } return signatures; } /** * Extract signatures that come from the unsigned templates from wikitext. * * @param {string} code Page code. * @param {object[]} signatures Existing signatures. * @returns {object[]} * @private */ function extractUnsigneds(code, signatures) { const unsigneds = []; if (cd.g.UNSIGNED_TEMPLATES_REGEXP) { let match; while ((match = cd.g.UNSIGNED_TEMPLATES_REGEXP.exec(code))) { let author; let timestamp; if (cd.g.TIMESTAMP_REGEXP_NO_TIMEZONE.test(match[2])) { timestamp = match[2]; author = match[3]; } else if (cd.g.TIMESTAMP_REGEXP_NO_TIMEZONE.test(match[3])) { timestamp = match[3]; author = match[2]; } else { author = match[2]; } author = author && userRegistry.getUser(decodeHtmlEntities(author)); // Append "(UTC)" to the `timestamp` of templates that allow to omit the timezone. The // timezone could be not UTC, but currently the timezone offset is taken from the wiki // configuration, so doesn't have effect. if (timestamp && !cd.g.TIMESTAMP_REGEXP.test(timestamp)) { timestamp += ' (UTC)'; // Workaround for "undated" templates if (!author) { author = '<undated>'; } } let startIndex = match.index; const endIndex = match.index + match[1].length; let dirtyCode = match[1]; const nextCommentStartIndex = match.index + match[0].length; // "[5 tildes] {{unsigned|}}" cases. In these cases, both the signature and {{unsigned|}} are // considered signatures and added to the array. We could combine them but that would need // corresponding code in Parser.js which could be tricky, so for now we just remove the // duplicate. That still allows to reply to the comment. const relevantSignatureIndex = ( signatures.findIndex((sig) => sig.nextCommentStartIndex === nextCommentStartIndex) ); if (relevantSignatureIndex !== -1) { signatures.splice(relevantSignatureIndex, 1); } unsigneds.push({ author, timestamp, startIndex, endIndex, dirtyCode, nextCommentStartIndex, }); } } return unsigneds; } /** * Extract signatures from wikitext. * * Only basic signature parsing is performed here; more precise signature text identification is * performed in {@link module:Comment#adjustCommentCodeData}. See also {@link * module:Comment#adjustCommentBeginning}, called before that. * * @param {string} code Code to extract signatures from. * @param {boolean} generateCommentAnchors Whether to generate and register comment anchors. * @returns {object[]} */ export function extractSignatures(code, generateCommentAnchors) { // Hide HTML comments, quotes and lines containing antipatterns. const adjustedCode = hideDistractingCode(code, false) .replace( cd.g.QUOTE_REGEXP, (s, beginning, content, ending) => beginning + ' '.repeat(content.length) + ending ) .replace(cd.g.COMMENT_ANTIPATTERNS_REGEXP, (s) => ' '.repeat(s.length)); // Custom user signatures can contain RTL marks, so we remove them only for unsigneds. const adjustedCodeForUnsigneds = adjustedCode .replace(/[\u200E\u200F]/g, (s) => ' '.repeat(s.length)); let signatures = extractRegularSignatures(adjustedCode); const unsigneds = extractUnsigneds(adjustedCodeForUnsigneds, signatures); signatures.push(...unsigneds); if (unsigneds.length) { signatures.sort((sig1, sig2) => sig1.startIndex > sig2.startIndex ? 1 : -1); } signatures = signatures.filter((sig) => sig.author); signatures.forEach((sig, i) => { sig.commentStartIndex = i === 0 ? 0 : signatures[i - 1].nextCommentStartIndex; }); if (generateCommentAnchors) { resetCommentAnchors(); } signatures.forEach((sig, i) => { const { date } = sig.timestamp && parseTimestamp(sig.timestamp) || {}; sig.id = i; sig.date = date; delete sig.nextCommentStartIndex; if (generateCommentAnchors) { const anchor = date && generateCommentAnchor(date, sig.author.name, true); sig.anchor = anchor; registerCommentAnchor(anchor); } }); return signatures; } /** * Decode HTML entities in a string. * * It should work as fast as possible, so we use `String#indexOf`, not `String#includes`. * * @param {string} s * @returns {string} */ export function decodeHtmlEntities(s) { if (s.indexOf('&') === -1) { return s; } else { let result = s; if (result.indexOf('&#38;amp;') !== -1) { result = result.replace(/&#38;amp;/g, '&amp;amp;') } if (result.indexOf('&#') !== -1) { result = result.replace(/&#(\d+);/g, (s, code) => String.fromCharCode(code)); } if (result.indexOf('&') !== -1) { result = html_entity_decode(result); } return result; } } /** * @typedef {object} HideSensitiveCodeReturn * @property {string} code * @property {string[]} hidden */ /** * Hide templates taking into account nested ones. * * @param {string} code * @param {Array} [hidden] Array with texts replaced by markers. Not required if `concealFirstMode` * is `true`. * @param {boolean} [concealFirstMarkerLength] Instead of putting markers in place of templates, * fill the space that the first met template occupies with spaces, and put the specified number * of marker characters at the first positions. * @returns {HideSensitiveCodeReturn} */ export function hideTemplatesRecursively(code, hidden, concealFirstMarkerLength) { let pos = 0; const stack = []; do { let left = code.indexOf('{{', pos); let right = code.indexOf('}}', pos); if (left === -1 && right === -1 && !stack.length) break; if (left !== -1 && (left < right || right === -1)) { stack.push(left); pos = left + 2; } else { left = stack.pop(); if (typeof left === 'undefined') { if (right === -1) { pos += 2; continue; } else { left = 0; } } if (right === -1) { right = code.length; } right += 2; const template = code.substring(left, right); const replacement = concealFirstMarkerLength === undefined ? '\x01' + hidden.push(template) + '\x02' : ( '\x01'.repeat(concealFirstMarkerLength) + ' '.repeat(template.length - concealFirstMarkerLength - 1) + '\x02' ); code = code.substring(0, left) + replacement + code.substr(right); pos = right - template.length; } } while (concealFirstMarkerLength === undefined || stack.length); return { code, hidden }; } /** * Replace code that should not be modified when processing it with placeholders. * * @param {string} code * @returns {HideSensitiveCodeReturn} */ export function hideSensitiveCode(code) { let hidden = []; const hide = (regexp, isTable) => { code = hideText(code, regexp, hidden, isTable); }; const hideTags = (...args) => { args.forEach((arg) => { hide(new RegExp(`<${arg}(?: [^>]+)?>[\\s\\S]+?<\\/${arg}>`, 'gi')); }); }; // Taken from // https://ru.wikipedia.org/w/index.php?title=MediaWiki:Gadget-wikificator.js&oldid=102530721 const hideTemplates = () => { // Simple regexp for hiding templates that have no nested ones. hide(/\{\{(?:[^{]\{?)+?\}\}/g); ({code, hidden} = hideTemplatesRecursively(code, hidden)); }; hideTags('nowiki', 'pre', 'source', 'syntaxhighlight'); hideTemplates(); // Tables hide(/^(:* *)(\{\|[^]*?\n\|\})/gm, true); return { code, hidden }; } /** * Modify or leave unchanged the string to have two newlines in the end of it. * * @param {string} code * @returns {string} */ export function endWithTwoNewlines(code) { return code.replace(/([^\n])\n?$/, '$1\n\n'); } "
"/** * Page class. * * @module Page */ import CdError from './CdError'; import cd from './cd'; import { findFirstTimestamp, hideDistractingCode } from './wikitext'; import { handleApiReject, isProbablyTalkPage } from './util'; import { makeBackgroundRequest, parseCode, unknownApiErrorText } from './apiWrappers'; import { parseTimestamp } from './timestamp'; /** * Class representing a page. It contains a few properties and methods compared to {@link * module:Comment Comment} and {@link module:Section Section}. * * @module Page */ export default class Page { /** * Create a page instance. * * @param {string|mw.Title} nameOrMwTitle * @throws {CdError} */ constructor(nameOrMwTitle) { const title = nameOrMwTitle instanceof mw.Title ? nameOrMwTitle : mw.Title.newFromText(nameOrMwTitle); if (!title) { throw new CdError(); } /** * Page title, with no namespace name. The word separator is a space, not an underline. * * @type {number} */ this.title = title.getMainText(); /** * Page name, with a namespace name. The word separator is a space, not an underline. * * @type {number} */ this.name = title.getPrefixedText(); /** * Namespace number. * * @type {number} */ this.namespace = title.getNamespaceId(); } /** * Get the URL of the page with the specified parameters. * * @param {object} parameters * @returns {string} */ getUrl(parameters) { return mw.util.getUrl(this.name, parameters); } /** * Check if the page is probably a talk page. * * @returns {boolean} */ isProbablyTalkPage() { return isProbablyTalkPage(this.realName || this.name, this.namespace); } /** * Whether the page is an archive page. Relies on {@link module:defaultConfig.archivePaths} * and/or, for the current page, elements with the class `cd-archivingInfo` and attribute * `data-is-archive-page`. * * @returns {boolean} */ isArchivePage() { if (this.cachedIsArchivePage !== undefined) { return this.cachedIsArchivePage; } let result; if (this === cd.g.CURRENT_PAGE) { result = $('.cd-archivingInfo').data('isArchivePage'); } if (result === undefined) { result = false; const name = this.realName || this.name; const iterator = cd.g.SOURCE_PAGES_MAP.keys(); for (const sourceRegexp of iterator) { if (sourceRegexp.test(name)) { result = true; break; } } } this.cachedIsArchivePage = Boolean(result); return result; } /** * Whether this page can have archives. If the page is an archive page, returns `false`. Relies on * {@link module:defaultConfig.pagesWithoutArchives} and {@link module:defaultConfig.archivePaths} * and/or, for the current page, elements with the class `cd-archivingInfo` and attribute * `data-can-have-archives`. * * @returns {?boolean} */ canHaveArchives() { if (this.isArchivePage()) { return false; } let result; if (this === cd.g.CURRENT_PAGE) { result = $('.cd-archivingInfo').data('canHaveArchives'); } if (result === undefined) { const name = this.realName || this.name; result = !cd.g.PAGES_WITHOUT_ARCHIVES_REGEXP?.test(name); } return Boolean(result); } /** * Get the archive prefix for the page. If no prefix is found based on {@link * module:defaultConfig.archivePaths} and/or, for the current page, elements with the class * `cd-archivingInfo` and attribute `data-archive-prefix`, returns the current page's name. If the * page is an archive page or can't have archives, returns `null`. * * @returns {?string} */ getArchivePrefix() { if (!this.canHaveArchives()) { return null; } let result; if (this === cd.g.CURRENT_PAGE) { result = $('.cd-archivingInfo').data('archivePrefix'); } const name = this.realName || this.name; if (!result) { const iterator = cd.g.ARCHIVE_PAGES_MAP.entries(); for (const [sourceRegexp, replacement] of iterator) { if (sourceRegexp.test(name)) { result = name.replace(sourceRegexp, replacement); break; } } } return String(result || name); } /** * Get the source page for the page (i.e., the page from which archiving is happening). Returns * the page itself if it is not an archive page. Relies on {@link * module:defaultConfig.archivePaths} and/or, for the current page, elements with the class * `cd-archivingInfo` and attribute `data-archived-page`. * * @returns {Page} */ getArchivedPage() { let result; if (this === cd.g.CURRENT_PAGE) { result = $('.cd-archivingInfo').data('archivedPage'); } if (!result) { const name = this.realName || this.name; const iterator = cd.g.SOURCE_PAGES_MAP.entries(); for (const [archiveRegexp, replacement] of iterator) { if (archiveRegexp.test(name)) { result = name.replace(archiveRegexp, replacement); break; } } } return result ? new Page(String(result)) : this; } /** * Make a revision request (see {@link https://www.mediawiki.org/wiki/API:Revisions}) to load the * code of the page, together with a few revision properties: the timestamp, redirect target, and * query timestamp (curtimestamp). Enrich the Page instance with those properties. Also set the * `realName` property that indicates either the redirect target if it's present or the page name. * * @param {boolean} [tolerateMissing=true] Assign `''` to the `code` property if the page is * missing instead of throwing an error. * * @throws {CdError} */ async getCode(tolerateMissing = true) { const resp = await cd.g.api.post({ action: 'query', titles: this.name, prop: 'revisions', rvslots: 'main', rvprop: ['ids', 'content'], redirects: true, curtimestamp: true, formatversion: 2, }).catch(handleApiReject); const query = resp.query; const page = query?.pages?.[0]; const revision = page?.revisions?.[0]; const content = revision?.slots?.main?.content; if (!query || !page) { throw new CdError({ type: 'api', code: 'noData', }); } if (page.missing) { if (tolerateMissing) { Object.assign(this, { code: '', realName: this.name, queryTimestamp: resp.curtimestamp, }); return; } else { throw new CdError({ type: 'api', code: 'missing', }); } } if (page.invalid) { throw new CdError({ type: 'api', code: 'invalid', }); } if (!revision || content === undefined) { throw new CdError({ type: 'api', code: 'noData', }); } const redirectTarget = query.redirects?.[0]?.to || null; /** * Page ID on the wiki. Filled upon running {@link module:Page#getCode} or {@link * module:Page#edit}. In the latter case, it is useful for newly created pages. * * @name pageId * @type {number|undefined} * @instance */ /** * Page code. Filled upon running {@link module:Page#getCode}. * * @name code * @type {string|undefined} * @instance */ /** * ID of the revision that has {@link module:Page#code}. Filled upon running {@link * module:Page#getCode}. * * @name revisionId * @type {string|undefined} * @instance */ /** * Page where {@link module:Page#name} redirects. Filled upon running {@link * module:Page#getCode}. * * @name redirectTarget * @type {?(string|undefined)} * @instance */ /** * If {@link module:Page#name} redirects to some other page, the value is that page. If not, the * value is the same as {@link module:Page#name}. Filled upon running {@link * module:Page#getCode}. * * @name realName * @type {string|undefined} * @instance */ /** * Time when {@link module:Page#code} was queried (as the server reports it). Filled upon * running {@link module:Page#getCode}. * * @name queryTimestamp * @type {string|undefined} * @instance */ Object.assign(this, { pageId: page.pageid, // It's more convenient to unify regexps to have \n as the last character of anything, not // (?:\n|$), and it doesn't seem to affect anything substantially. code: content + '\n', revisionId: revision.revid, redirectTarget, realName: redirectTarget || this.name, queryTimestamp: resp.curtimestamp, }); } /** * Make a parse request (see {@link https://www.mediawiki.org/wiki/API:Parsing_wikitext}). * * @param {boolean} [customOptions] * @param {boolean} [requestInBackground=false] Make a request that won't set the process on hold * when the tab is in the background. * @param {boolean} [markAsRead=false] Mark the current page as read in the watchlist. * @returns {object} * @throws {CdError} */ async parse(customOptions, requestInBackground = false, markAsRead = false) { const defaultOptions = { action: 'parse', // If we know that this page is a redirect, use its target. Otherwise, use the regular name. page: this.realName || this.name, prop: ['text', 'revid', 'modules', 'jsconfigvars'], formatversion: 2, }; const options = Object.assign({}, defaultOptions, customOptions); // "page" and "oldid" can not be used together. if (customOptions?.oldid) { delete options.page; } const request = requestInBackground ? makeBackgroundRequest(options).catch(handleApiReject) : cd.g.api.post(options).catch(handleApiReject); const parse = (await request).parse; if (parse?.text === undefined) { throw new CdError({ type: 'api', code: 'noData', }); } if (markAsRead) { this.markAsRead(parse.revid); } return parse; } /** * Get a list of revisions of the page ("redirects" is set to true by default). * * @param {object} [customOptions={}] * @param {boolean} [requestInBackground=false] Make a request that won't set the process on hold * when the tab is in the background. * @returns {Array} */ async getRevisions(customOptions = {}, requestInBackground = false) { const defaultOptions = { action: 'query', titles: this.name, rvslots: 'main', prop: 'revisions', redirects: true, formatversion: 2, }; const options = Object.assign({}, defaultOptions, customOptions); const request = requestInBackground ? makeBackgroundRequest(options).catch(handleApiReject) : cd.g.api.post(options).catch(handleApiReject); const revisions = (await request).query?.pages?.[0]?.revisions; if (!revisions) { throw new CdError({ type: 'api', code: 'noData', }); } return revisions; } /** * Modify a page code string in accordance with an action. The `'addSection'` action is presumed. * * @param {object} options * @param {string} options.pageCode * @param {CommentForm} options.commentForm * @returns {string} */ modifyCode({ pageCode, commentForm }) { const { commentCode } = commentForm.commentTextToCode('submit'); let newPageCode; let codeBeforeInsertion; if (commentForm.isNewTopicOnTop) { const adjustedPageCode = hideDistractingCode(pageCode); const firstSectionStartIndex = adjustedPageCode.search(/^(=+).*\1[ \t\x01\x02]*$/m); if (firstSectionStartIndex === -1) { codeBeforeInsertion = pageCode ? pageCode + '\n' : ''; } else { codeBeforeInsertion = pageCode.slice(0, firstSectionStartIndex); } const codeAfterInsertion = pageCode.slice(firstSectionStartIndex); newPageCode = codeBeforeInsertion + commentCode + '\n' + codeAfterInsertion; } else { codeBeforeInsertion = (pageCode + '\n').trimLeft(); newPageCode = codeBeforeInsertion + commentCode; } return { newPageCode, codeBeforeInsertion, commentCode }; } /** * Make an edit API request ({@link https://www.mediawiki.org/wiki/API:Edit}). * * @param {object} customOptions * @returns {number|string} editTimestamp Unix time of the edit or `'nochange'` if nothing has * changed. */ async edit(customOptions) { const defaultOptions = { // If we know that this page is a redirect, use its target. Otherwise, use the regular name. title: this.realName || this.name, action: 'edit', formatversion: 2, }; const options = cd.g.api.assertCurrentUser(Object.assign({}, defaultOptions, customOptions)); let resp; try { resp = await cd.g.api.postWithEditToken(options).catch(handleApiReject); } catch (e) { if (e instanceof CdError) { const { type, apiData } = e.data; if (type === 'network') { throw e; } else { const error = apiData?.error; let message; let isRawMessage = false; let logMessage; let code; if (error) { code = error.code; switch (code) { case 'spamblacklist': { message = cd.sParse('error-spamblacklist', error.spamblacklist.matches[0]); break; } case 'titleblacklist': { message = cd.sParse('error-titleblacklist'); break; } case 'abusefilter-warning': case 'abusefilter-disallowed': { await cd.g.api.loadMessagesIfMissing([code]); const description = mw.message(code, error.abusefilter.description).plain(); try { message = (await parseCode(description)).html; } catch (e) { console.warn('Couldn\'t parse the error code.'); } if (message) { isRawMessage = true; } else { message = cd.sParse('error-abusefilter', error.abusefilter.description); } break; } case 'editconflict': { message = cd.sParse('error-editconflict'); break; } case 'blocked': { message = cd.sParse('error-blocked'); break; } case 'missingtitle': { message = cd.sParse('error-pagedeleted'); break; } default: { message = ( cd.sParse('error-pagenotedited') + ' ' + (await unknownApiErrorText(code, error.info)) ); } } logMessage = [code, apiData]; } else { logMessage = apiData; } throw new CdError({ type: 'api', code: 'error', apiData: resp, details: { code, message, isRawMessage, logMessage }, }); } } else { throw e; } } this.pageId = resp.edit.pageid; return resp.edit.newtimestamp || 'nochange'; } /** * Enrich the page instance with the properties regarding whether new topics go on top on this * page (based on the various factors) and, if new topics are on top, the start index of the first * section. * * @throws {CdError} */ analyzeNewTopicPlacement() { if (this.code === undefined) { throw new CdError('Can\'t analyze the new topics placement: Page#code is undefined.'); } let areNewTopicsOnTop = cd.config.areNewTopicsOnTop?.(this.name, this.code); const adjustedCode = hideDistractingCode(this.code); const sectionHeadingRegexp = /^==[^=].*?==[ \t\x01\x02]*\n/gm; let firstSectionStartIndex; let sectionHeadingMatch; // Search for the first section's index. If areNewTopicsOnTop is false, we don't need it. if (areNewTopicsOnTop !== false) { sectionHeadingMatch = sectionHeadingRegexp.exec(adjustedCode); firstSectionStartIndex = sectionHeadingMatch?.index; sectionHeadingRegexp.lastIndex = 0; } if (areNewTopicsOnTop === undefined) { // Detect the topic order: newest first or newest last. let previousDate; let difference = 0; while ((sectionHeadingMatch = sectionHeadingRegexp.exec(adjustedCode))) { const timestamp = findFirstTimestamp(this.code.slice(sectionHeadingMatch.index)); const { date } = timestamp && parseTimestamp(timestamp) || {}; if (date) { if (previousDate) { difference += date > previousDate ? -1 : 1; } previousDate = date; } } areNewTopicsOnTop = difference === 0 ? this.namespace % 2 === 0 : difference > 0; } /** * Whether new topics go on top on this page. Filled upon running {@link * module:Page#analyzeNewTopicPlacement}. * * @name areNewTopicsOnTop * @type {boolean|undefined} * @instance */ /** * The start index of the first section, if new topics are on top on this page. Filled upon * running {@link module:Page#analyzeNewTopicPlacement}. * * @name firstSectionStartIndex * @type {number|undefined} * @instance */ Object.assign(this, { areNewTopicsOnTop, firstSectionStartIndex }); } /** * {@link https://www.mediawiki.org/wiki/Manual:Purge Purge cache} of the page. */ async purge() { await cd.g.api.post({ action: 'purge', titles: this.name, }).catch(() => { mw.notify(cd.s('error-purgecache'), { type: 'error' }); }); } /** * Mark the page as read, optionally setting the revision to mark as read. * * @param {number} revisionId Revision to mark as read (setting all newer revisions unread). */ async markAsRead(revisionId) { await cd.g.api.postWithEditToken({ action: 'setnotificationtimestamp', titles: this.name, newerthanrevid: revisionId, formatversion: 2, }); } } "
"/** * Tree walker classes. * * @module treeWalker */ import cd from './cd'; /** * Generalization and simplification of the TreeWalker web API for the normal and worker contexts. */ export class TreeWalker { /** * Create a tree walker. * * @param {Node} root Node that limits where the tree walker can go within this document's tree: * only the root node and its descendants. * @param {Function} [acceptNode] Function that returns `true` if the tree walker should accept * the node, and `false` if it should reject. * @param {boolean} [onlyElementNodes=false] Walk only on element nodes, ignoring nodes of other * types. * @param {Node} [startNode=root] Node to set as a current node. */ constructor(root, acceptNode, onlyElementNodes = false, startNode = root) { this.acceptNode = acceptNode; this.root = root; this.currentNode = startNode; if (onlyElementNodes) { this.firstChildProperty = 'firstElementChild'; this.lastChildProperty = 'lastElementChild'; this.previousSiblingProperty = 'previousElementSibling'; this.nextSiblingProperty = 'nextElementSibling'; } else { this.firstChildProperty = 'firstChild'; this.lastChildProperty = 'lastChild'; this.previousSiblingProperty = 'previousSibling'; this.nextSiblingProperty = 'nextSibling'; } } /** * Try changing the current node to a node specified by the property. * * @param {string} property * @returns {?Node} * @private */ tryMove(property) { let node = this.currentNode; if (node === this.root && !property.includes('Child')) { return null; } do { node = node[property]; } while (node && this.acceptNode && !this.acceptNode(node)); if (node) { this.currentNode = node; } return node || null; } /** * Go to the parent node. * * @returns {?Node} */ parentNode() { return this.tryMove('parentNode'); } /** * Go to the first child node. * * @returns {?Node} */ firstChild() { return this.tryMove(this.firstChildProperty); } /** * Go to the last child node. * * @returns {?Node} */ lastChild() { return this.tryMove(this.lastChildProperty); } /** * Go to the previous sibling node. * * @returns {?Node} */ previousSibling() { return this.tryMove(this.previousSiblingProperty); } /** * Go to the next sibling node. * * @returns {?Node} */ nextSibling() { return this.tryMove(this.nextSiblingProperty); } /** * Go to the next node (don't confuse with the next sibling). * * @returns {?Node} */ nextNode() { let node = this.currentNode; do { if (node[this.firstChildProperty]) { node = node[this.firstChildProperty]; } else { while (node && !node[this.nextSiblingProperty] && node.parentNode !== this.root) { node = node.parentNode; } if (node) { node = node[this.nextSiblingProperty]; } } } while (node && this.acceptNode && !this.acceptNode(node)); if (node) { this.currentNode = node; } return node; } /** * Go to the previous node (don't confuse with the previous sibling). * * @returns {?Node} */ previousNode() { let node = this.currentNode; if (node === this.root) return; do { if (node[this.previousSiblingProperty]) { node = node[this.previousSiblingProperty]; while (node[this.lastChildProperty]) { node = node[this.lastChildProperty]; } } else { node = node.parentNode; } } while (node && this.acceptNode && !this.acceptNode(node)); if (node) { this.currentNode = node; } return node; } } /** * Tree walker that walks only on element nodes of the current document. * * @augments module:treeWalker.TreeWalker */ export class ElementsTreeWalker extends TreeWalker { /** * Create an elements {@link module:treeWalker.TreeWalker tree walker}. * * @param {Node} [startNode] */ constructor(startNode) { super(cd.g.rootElement, null, true); if (startNode) { this.currentNode = startNode; } } } /** * Tree walker that walks on both element and text nodes of the current document and ignores * "style" and "link" elements. * * @augments module:treeWalker.TreeWalker */ export class ElementsAndTextTreeWalker extends TreeWalker { /** * Create an elements and text {@link module:treeWalker.TreeWalker tree walker}. * * @param {Node} [startNode] */ constructor(startNode) { super( cd.g.rootElement, (node) => node.nodeType === Node.TEXT_NODE || node.nodeType === Node.ELEMENT_NODE ); if (startNode) { this.currentNode = startNode; } } } "
"/** * Comment underlay and overlay-related functions and configuration. * * @module commentLayers */ import cd from './cd'; import { getExtendedRect } from './util'; export default { /** * List of the underlays. * * @type {Element[]} */ underlays: [], /** * List of the containers of the underlays. * * @type {Element[]} */ layersContainers: [], /** * Recalculate positions of the highlighted comments' (usually, new or own) layers and redraw if * they've changed. * * @param {boolean} [removeUnhighlighted] Whether to remove the unhighlighted comments' layers. * @param {boolean} [redrawAll] Whether to redraw all underlays and not stop at first three * unmoved. */ redrawIfNecessary(removeUnhighlighted = false, redrawAll = false) { if (!this.underlays.length || (document.hidden && !redrawAll)) return; this.layersContainers.forEach((container) => { container.cdCouldHaveMoved = true; }); const comments = []; const rootBottom = cd.g.$root.get(0).getBoundingClientRect().bottom + window.pageYOffset; let notMovedCount = 0; let floatingRects; // We go from the end and stop at the first _two_ comments that have not been misplaced. A // quirky reason for this is that the mouse could be over some comment making its underlay to be // repositioned immediately and therefore not appearing as misplaced to this procedure. Three // comments threshold should be more reliable. cd.comments.slice().reverse().some((comment) => { const shouldBeHighlighted = ( comment.isNew || (comment.isOwn && cd.settings.highlightOwnComments) || comment.isTarget || comment.isFocused || comment.isDeleted ); // Layers that ended up under the bottom of the page content and could be moving the page // bottom down. const isUnderBottom = comment.positions && comment.positions.bottom > rootBottom; if ((removeUnhighlighted || isUnderBottom) && !shouldBeHighlighted && comment.$underlay) { comment.removeLayers(); } else if (shouldBeHighlighted && !comment.editForm) { floatingRects = floatingRects || cd.g.floatingElements.map(getExtendedRect); const isMoved = comment.configureLayers({ // If a comment was hidden, then became visible, we need to add the layers. add: true, update: false, floatingRects, }); if (isMoved || redrawAll) { notMovedCount = 0; comments.push(comment); } else if ( isMoved === false && // Nested containers shouldn't count, the positions of the layers inside them may be OK, // unlike the layers preceding them. !comment.getLayersContainer().parentNode.parentNode .closest('.cd-commentLayersContainerParent') ) { notMovedCount++; if (notMovedCount === 3) { return true; } } } return false; }); // It's faster to update the positions separately in one sequence. comments.forEach((comment) => { comment.updateLayersPositions(); }); }, /** * Empty the underlay registry and the layers container elements. */ reset() { this.underlays = []; this.layersContainers.forEach((container) => { container.innerHTML = ''; }); }, }; "
"/** * Block displaying the current section and subsections. * * @module currentSection */ import cd from './cd'; import { getExtendedRect } from './util'; let currentSection; export default { mount() { this.$element = $('<ul>') .attr('id', 'cd-currentSection') .appendTo(document.body); }, update() { if ( currentSection && ( document.documentElement.scrollHeight === document.documentElement.clientHeight || window.pageYOffset === 0 || !cd.sections.length || getExtendedRect(cd.sections[0].$heading.get(0)).outerTop >= 0 ) ) { this.reset(); return; } cd.sections .slice() .reverse() .some((section) => { const extendedRect = getExtendedRect(section.$heading.get(0)); // If the element has 0 as the left position and height, it's probably invisible for some // reason. if (extendedRect.left === 0 && extendedRect.height === 0) return; if (extendedRect.outerTop < 0) { if (currentSection === section) { return true; } currentSection = section; this.$element.empty(); const parentTree = [section, ...section.getParentTree()].reverse(); parentTree.forEach((sectionInTree, level) => { $('<li>') .addClass('cd-currentSection-level') .addClass(`cd-currentSection-level-${level}`) .text(sectionInTree.headline) .on('click', (e) => { e.preventDefault(); sectionInTree.$heading.cdScrollTo('top'); }) .appendTo(this.$element); }); return true; } return false; }); }, reset() { currentSection = null; this.$element.empty(); }, }; "
"/** * jQuery extensions. See {@link $.fn}. * * @module jqueryExtensions */ import cd from './cd'; import navPanel from './navPanel'; import { handleScroll } from './eventHandlers'; /** * jQuery. See {@link $.fn} for extensions. * * @namespace $ * @type {object} */ /** * (`$.fn`) jQuery extensions. * * @namespace fn * @memberof $ */ export default { /** * Removes non-element nodes from a jQuery collection. * * @returns {JQuery} * @memberof $.fn */ cdRemoveNonElementNodes: function () { return this.filter(function () { return this.nodeType === Node.ELEMENT_NODE; }); }, /** * Scroll to the element. * * @param {string} [alignment='top'] Where should the element be positioned relative to the * viewport. Possible values: `'top'`, `'center'`, and `'bottom'`. * @param {boolean} [smooth=true] Whether to use a smooth animation. * @param {Function} [callback] Callback to run after the animation has completed. * @returns {JQuery} * @memberof $.fn */ cdScrollTo(alignment = 'top', smooth = true, callback) { cd.g.autoScrollInProgress = true; let $elements = this.cdRemoveNonElementNodes(); const offsetTop = $elements.first().offset().top; const offsetTopLast = $elements.last().offset().top; let offsetBottom = offsetTopLast + $elements.last().outerHeight(); if (offsetTop === 0 || offsetTopLast === 0) { cd.g.autoScrollInProgress = false; mw.notify(cd.s('error-elementhidden'), { type: 'error' }) return this; } let offset; if (alignment === 'center') { offset = Math.min( offsetTop, offsetTop + ((offsetBottom - offsetTop) * 0.5) - $(window).height() * 0.5 ); } else if (alignment === 'bottom') { offset = offsetBottom - $(window).height(); } else { offset = offsetTop; } const onComplete = () => { cd.g.autoScrollInProgress = false; handleScroll(); navPanel.updateCommentFormButton(); }; if (smooth) { $('body, html').animate({ scrollTop: offset }, { complete: function () { if (this !== document.documentElement) return; onComplete(); if (callback) { callback(); } } }); } else { window.scrollTo(0, offset); onComplete(); if (callback) { callback(); } } return this; }, /** * Check if the element is in the viewport. Hidden elements are checked as if they were visible. * * This method is not supposed to be used on element collections that are partially visible, * partially hidden, as it can not remember their state. * * @param {boolean} partially Return true even if only a part of the element is in the viewport. * @returns {JQuery} * @memberof $.fn */ cdIsInViewport(partially = false) { const $elements = this.cdRemoveNonElementNodes(); // Workaround for hidden elements (use cases like checking if the add section form is in the // viewport). const wasHidden = $elements.get().every((el) => el.style.display === 'none'); if (wasHidden) { $elements.show(); } const elementTop = $elements.first().offset().top; const elementBottom = $elements.last().offset().top + $elements.last().height(); if (wasHidden) { $elements.hide(); } const viewportTop = $(window).scrollTop(); const viewportBottom = viewportTop + $(window).height(); return partially ? elementBottom > viewportTop && elementTop < viewportBottom : elementTop >= viewportTop && elementBottom <= viewportBottom; }, /** * Scroll to the element if it is not in the viewport. * * @param {string} [alignment] One of the values that {@link $.fn.cdScrollTo} accepts: `'top'`, * `'center'`, or `'bottom'`. * @param {boolean} [smooth=true] Whether to use a smooth animation. * @param {Function} [callback] Callback to run after the animation has completed. * @returns {JQuery} * @memberof $.fn */ cdScrollIntoView(alignment, smooth = true, callback) { if (this.cdIsInViewport()) { if (callback) { callback(); } } else { if (callback) { // Wrap into setTimeout() for a more smooth animation in case there is .focus() in the // callback. setTimeout(() => { this.cdScrollTo(alignment, smooth, callback); }); } else { this.cdScrollTo(alignment, smooth, callback); } } return this; }, /** * Get the element text as it is rendered in the browser, i.e. line breaks, paragraphs etc. are * taken into account. **This function is expensive.** * * @returns {string} * @memberof $.fn */ cdGetText() { let text; const dummyElement = document.createElement('div'); Array.from(this.get(0).childNodes).forEach((node) => { dummyElement.appendChild(node.cloneNode(true)); }); document.body.appendChild(dummyElement); text = dummyElement.innerText; dummyElement.remove(); return text; }, /** * Add a close button to the element. * * @returns {JQuery} * @memberof $.fn */ cdAddCloseButton() { if (this.find('.cd-closeButton').length) return this; const $closeButton = $('<a>') .attr('title', cd.s('cf-block-close')) .addClass('cd-closeButton') .on('click', () => { this.empty(); }); this.prepend($closeButton); return this; }, }; "
"/** * Web page (not wikitext) parsing class. Parsing here means "extracting meaningful parts from the * page". Functions related to wikitext parsing go in {@link module:wikitext}. * * Here, we use vanilla JavaScript for recurring operations that together take up a lot of time. * * @module Parser */ import cd from './cd'; import { ElementsAndTextTreeWalker, ElementsTreeWalker } from './treeWalker'; import { defined, firstCharToUpperCase, flat, isInline, underlinesToSpaces } from './util'; import { generateCommentAnchor, parseTimestamp, registerCommentAnchor } from './timestamp'; let foreignComponentClasses; let timezoneRegexp; let signatureEndingRegexp; let elementsToExclude; /** * Get the page name from a URL. * * @param {string} url * @returns {?string} * @private */ function getPageNameFromUrl(url) { // Are only WMF wikis guaranteed to have the format we need? if ( typeof mw === 'undefined' || (mw.config.get('wgArticlePath') === '/wiki/$1' && mw.config.get('wgScript') === '/w/index.php') ) { let pageName = url .replace(/^(?:https?:)?\/\/[^/]+/, '') .replace(/^\/wiki\//, '') .replace(/^\/w\/index.php\?title=/, '') .replace(/&action=edit.*/, '') .replace(/#.*/, '') .replace(/_/g, ' '); try { pageName = decodeURIComponent(pageName); } catch (e) { return null; } return pageName; } else { let uri; try { uri = new mw.Uri(url); } catch (e) { return null; } const match = uri.path.match(cd.g.ARTICLE_PATH_REGEXP); if (match) { try { return decodeURIComponent(match[1]); } catch (e) { return null; } } return uri.query.title || null; } } /** * Get the user name from a link. * * @param {Element} element * @returns {string} * @private */ export function getUserNameFromLink(element) { const href = element.getAttribute('href'); let userName; if (href) { const pageName = getPageNameFromUrl(href); if (!pageName) { return null; } const match = pageName.match(cd.g.USER_NAMESPACES_REGEXP); if (match) { userName = match[1]; } else if (pageName.startsWith(cd.g.CONTRIBS_PAGE + '/')) { userName = pageName.replace(cd.g.CONTRIBS_PAGE_LINK_REGEXP, ''); if (cd.g.IS_IPv6_ADDRESS(userName)) { userName = userName.toUpperCase(); } } if (userName) { userName = firstCharToUpperCase(underlinesToSpaces(userName.replace(/\/.*/, ''))).trim(); } } else { if (element.classList.contains('mw-selflink') && cd.g.CURRENT_NAMESPACE_NUMBER === 3) { // Comments of users that have only the user talk page link in their signature on their talk // page. userName = cd.g.CURRENT_PAGE_TITLE; } else { return null; } } return userName; } /** * Determine whether the provided element is a cell of a table containing multiple signatures. * * @param {Element} element * @returns {boolean} */ function isCellOfMultiCommentTable(element) { if (element.tagName !== 'TD') { return false; } let table; for (let n = element; !table && n !== cd.g.rootElement; n = n.parentNode) { if (n.tagName === 'TABLE') { table = n; } } return !table || table.getElementsByClassName('cd-signature', 2).length > 1; } /** * Generalization of a page parser for the window and worker contexts. */ export default class Parser { /** * Create a page parser in the provided context. * * @param {object} context Collection of classes, functions, and other properties that perform the * tasks we need in the current context (window or worker). */ constructor(context) { this.context = context; if (!foreignComponentClasses) { foreignComponentClasses = ['cd-commentPart', ...cd.config.closedDiscussionClasses]; if (cd.g.pageHasOutdents) { foreignComponentClasses.push('outdent-template'); } timezoneRegexp = new RegExp(cd.g.TIMEZONE_REGEXP.source + '\\s*$'); if (cd.config.signatureEndingRegexp) { signatureEndingRegexp = new RegExp(cd.config.signatureEndingRegexp.source + '$'); } } } /** * Create a comment instance. * * @param {Element} signature * @returns {*} */ createComment(signature) { return new this.context.CommentClass(this, signature); } /** * Create a section instance. * * @param {Element} headingElement * @param {Promise} watchedSectionsRequest * @returns {*} */ createSection(headingElement, watchedSectionsRequest) { return new this.context.SectionClass(this, headingElement, watchedSectionsRequest); } /** * @typedef {object} Timestamp * @property {Element} element * @property {Date} date */ /** * @typedef {Timestamp[]} FindTimestampsReturn */ /** * Find timestamps under the root element. * * @returns {FindTimestampsReturn} */ findTimestamps() { elementsToExclude = [ ...Array.from(cd.g.rootElement.getElementsByTagName('blockquote')), ...flat( cd.config.elementsToExcludeClasses .map((className) => Array.from(cd.g.rootElement.getElementsByClassName(className))) ), ]; return this.context.getAllTextNodes() .map((node) => { const text = node.textContent; const { date, match } = parseTimestamp(text) || {}; if (date && !elementsToExclude.some((el) => el.contains(node))) { return { node, date, match }; } }) .filter(defined) .map((finding) => { const { node, match, date } = finding; const element = this.context.document.createElement('span'); element.classList.add('cd-timestamp'); const textNode = this.context.document.createTextNode(match[2]); element.appendChild(textNode); const remainedText = node.textContent.slice(match.index + match[0].length); let afterNode; if (remainedText) { afterNode = this.context.document.createTextNode(remainedText); } node.textContent = node.textContent.slice(0, match.index + match[1].length); node.parentNode.insertBefore(element, node.nextSibling); if (afterNode) { node.parentNode.insertBefore(afterNode, element.nextSibling); } return { element, date }; }); } /** * Find signatures under the root element given timestamps. * * Characters before the author link, like "—", aren't considered a part of the signature. * * @param {object[]} timestamps * @returns {object[]} */ findSignatures(timestamps) { const signatures = timestamps .map((timestamp) => { const date = timestamp.date; const timestampElement = timestamp.element; const timestampText = timestamp.element.textContent; let unsignedElement; // If the closest not inline timestamp element ancestor has more than one signature, we // choose the last signature to consider it the signature of the comment author. There is no // point for us to parse them as distinct comments as a reply posted using our script will // go below all of them anyway. let closestNotInlineAncestor; for (let el = timestamp.element; !closestNotInlineAncestor; el = el.parentNode) { if (isInline(el)) { // Simultaneously check if we are inside an unsigned template. if (el.classList.contains(cd.config.unsignedClass)) { unsignedElement = el; } } else { closestNotInlineAncestor = el; } } const isUnsigned = Boolean(unsignedElement); if (closestNotInlineAncestor) { const cniaChildren = Array.from( closestNotInlineAncestor[this.context.childElementsProperty] ); const treeWalker = new ElementsTreeWalker(timestamp.element); while ( treeWalker.nextNode() && closestNotInlineAncestor.contains(treeWalker.currentNode) && (!cniaChildren.includes(treeWalker.currentNode) || isInline(treeWalker.currentNode)) ) { // Found other timestamp after this timestamp if (treeWalker.currentNode.classList.contains('cd-timestamp')) return; } } const startElement = unsignedElement || timestamp.element; const treeWalker = new ElementsAndTextTreeWalker(startElement); let authorName; let length = 0; let firstSignatureElement; const signatureNodes = []; if (unsignedElement) { firstSignatureElement = startElement; } else { signatureNodes.push(startElement); treeWalker.previousSibling(); } // Unsigned template may be of the "undated" kind - containing a timestamp but no author // name, so we need to walk the tree anyway. do { const node = treeWalker.currentNode; length += node.textContent.length; if (node.nodeType === Node.ELEMENT_NODE) { if (node.classList.contains('cd-timestamp')) break; let hasAuthorLinks = false; if (node.tagName === 'A') { const userName = getUserNameFromLink(node); if (userName) { if (!authorName) { authorName = userName; } if (authorName === userName) { // That's not some other user link that is not a part of the signature. hasAuthorLinks = true; } } } else { Array.from(node.getElementsByTagName('a')) .reverse() .some((link) => { const userName = getUserNameFromLink(link); if (userName) { if (!authorName) { authorName = userName; } if (authorName === userName) { // That's not some other user link that is not a part of the signature. hasAuthorLinks = true; return true; } } }); } if (hasAuthorLinks) { firstSignatureElement = node; } } signatureNodes.push(node); // We may need using `previousNode()` here but currently the only known use case where it // helps is the "undated" templates when those are not marked by the class specificied in // the wiki configuration (which they should be). } while (treeWalker.previousSibling() && length < cd.config.signatureScanLimit); const firstSignatureElementIndex = signatureNodes.indexOf(firstSignatureElement); signatureNodes.splice( firstSignatureElementIndex === -1 ? 1 : firstSignatureElementIndex + 1 ); const anchor = generateCommentAnchor(timestamp.date, authorName, true); registerCommentAnchor(anchor); const signatureContainer = startElement.parentNode; const startElementNextSibling = startElement.nextSibling; const element = this.context.document.createElement('span'); element.classList.add('cd-signature'); signatureNodes.reverse().forEach(element.appendChild.bind(element)); signatureContainer.insertBefore(element, startElementNextSibling); // If there is no author, we add the class to prevent the element from being considered a // part of other comment but don't append to the list of signatures. if (!authorName) return; return { element, timestampElement, timestampText, date, authorName, anchor, isUnsigned }; }) .filter(defined); if (cd.config.unsignedClass) { Array.from(cd.g.rootElement.getElementsByClassName(cd.config.unsignedClass)) .forEach((element) => { // Only templates with no timestamp interest us. if (!this.context.getElementByClassName(element, 'cd-timestamp')) { Array.from(element.getElementsByTagName('a')).some((link) => { const authorName = getUserNameFromLink(link); if (authorName) { element.classList.add('cd-signature'); const isUnsigned = true; signatures.push({ element, authorName, isUnsigned }); return true; } }); } }); } // Sort signatures according to their position in the DOM. sig1 and sig2 are expected not to be // the same elements. signatures.sort((sig1, sig2) => this.context.follows(sig1.element, sig2.element) ? 1 : -1); return signatures; } /** * Collect the parts of the comment given a signature element. * * @param {Element} signatureElement * @returns {object[]} */ collectParts(signatureElement) { const treeWalker = new ElementsAndTextTreeWalker(signatureElement); let parts = []; let firstForeignComponentAfter; // The code: // * Smth. [signature] // ** Smth. // *: Smth. [signature] // or // ** Smth. [signature] // ** Smth. // *: Smth. [signature] // produces a DOM where the second line is not a part of the first comment, but there is only // the first comment's signature in the DOM subtree related to the second line. We need to // acknowledge there is a foreign not inline element here to be able to tell comment boundaries // accurately (inline elements in most cases are continuations of the same comment). while (!firstForeignComponentAfter) { while (!treeWalker.currentNode.nextSibling && treeWalker.parentNode()); if (!treeWalker.nextSibling()) break; if (!isInline(treeWalker.currentNode, true)) { firstForeignComponentAfter = treeWalker.currentNode; } } // As an optimization, avoid adding every text node of the comment to the array of its parts if // possible. Add their common container instead. if ( ( firstForeignComponentAfter && signatureElement.parentNode.contains(firstForeignComponentAfter) ) || // Cases when the comment has no wrapper that contains only that comment (for example, // https://ru.wikipedia.org/wiki/Project:Форум/Архив/Технический/2020/10#202010140847_AndreiK). // The second parameter of getElementsByClassName() is an optimization for the worker context. signatureElement.parentNode.getElementsByClassName('cd-signature', 2).length > 1 || isCellOfMultiCommentTable(signatureElement.parentNode) ) { // Collect inline parts after the signature treeWalker.currentNode = signatureElement; while (treeWalker.nextSibling()) { if (isInline(treeWalker.currentNode, true)) { parts.push({ node: treeWalker.currentNode, isTextNode: treeWalker.currentNode.nodeType === Node.TEXT_NODE, isHeading: false, hasCurrentSignature: false, hasForeignComponents: false, lastStep: 'start', }); } else { break; } } parts.reverse(); treeWalker.currentNode = signatureElement; } else { treeWalker.currentNode = signatureElement.parentNode; } parts.push({ node: treeWalker.currentNode, isTextNode: false, isHeading: false, hasCurrentSignature: true, hasForeignComponents: false, lastStep: 'start', }); // 500 seems to be a safe enough value in case of any weird reasons for an infinite loop. for (let i = 0; i < 500; i++) { // lastStep may be: // * "start" (parts added at the beginning) // * "back" (go to the previous sibling) // * "up" (go to the parent element) // * "dive" (recursively go to the last not inline/text child) // * "replaced" (obtained as a result of manipulations after node traversal) let lastStep; const previousPart = parts[parts.length - 1]; if (!previousPart.isTextNode && !previousPart.hasCurrentSignature) { // A simple check before we go: a timestamp or signature ending at the end of the line means // a foreign signature; nothing more to search for in that case. const text = previousPart.node.textContent; if ( // Filter out additions to the end of a comment like: // https://ru.wikipedia.org/w/index.php?diff=107450915 // https://ru.wikipedia.org/w/index.php?diff=107487558 !isInline(previousPart.node, true) && (timezoneRegexp.test(text) || signatureEndingRegexp?.test(text)) && !elementsToExclude.some((el) => el.contains(previousPart.node)) ) { previousPart.hasForeignComponents = true; break; } } if (!previousPart.hasCurrentSignature && previousPart.hasForeignComponents) { // Here we dive to the bottom of the element subtree to find parts of the _current_ comment // that may be present. This happens with code like this: // :* Smth. [signature] // :* Smth. <!-- The comment part that we need to grab while it's in the same element as the // signature above. --> // :: Smth. [signature] <!-- The comment part we are at. --> // Get the last not inline child of the current node. let previousNode; let haveDived = false; while ((previousNode = treeWalker.currentNode) && treeWalker.lastChild()) { if (isInline(treeWalker.currentNode, true)) { treeWalker.currentNode = previousNode; break; } haveDived = true; } if (haveDived) { lastStep = 'dive'; } else { break; } } else if (treeWalker.previousSibling()) { lastStep = 'back'; } else { if (!treeWalker.parentNode()) break; lastStep = 'up'; } const node = treeWalker.currentNode; const isTextNode = node.nodeType === Node.TEXT_NODE; /* Cases like: === Section title === Section introduction. Not a comment. # Vote. [signature] Without the following code, the section introduction would be a part of the comment. The same may happen inside a discussion thread (often because one of the users didn't sign). */ if ( lastStep === 'back' && ['OL', 'UL'].includes(previousPart.node.tagName) && // Exceptions like https://ru.wikipedia.org/w/index.php?diff=105007602 !( ['DL', 'OL', 'UL'].includes(node.tagName) || ( isTextNode && node.previousSibling && ['DL', 'OL', 'UL'].includes(node.previousSibling.tagName) ) ) && previousPart.node[this.context.childElementsProperty][0]?.contains(signatureElement) ) { break; } let isHeading = null; let hasCurrentSignature = null; let hasForeignComponents = null; if (!isTextNode) { if ( node === treeWalker.root || foreignComponentClasses.some((className) => node.classList.contains(className)) || node.getAttribute('id') === 'toc' || isCellOfMultiCommentTable(node) || // Horizontal lines sometimes separate different section blocks. ( node.tagName === 'HR' && node.previousElementSibling && this.context.getElementByClassName(node.previousElementSibling, 'cd-signature') ) || (cd.g.pageHasOutdents && this.context.getElementByClassName(node, 'outdent-template')) || cd.config.checkForCustomForeignComponents?.(node, this.context) ) { break; } isHeading = /^H[1-6]$/.test(node.tagName); hasCurrentSignature = node.contains(signatureElement); // The second parameter of getElementsByClassName() is an optimization for the worker // context. const signaturesCount = ( node.getElementsByClassName('cd-signature', Number(hasCurrentSignature) + 1).length ); hasForeignComponents = ( signaturesCount - Number(hasCurrentSignature) > 0 || (firstForeignComponentAfter && node.contains(firstForeignComponentAfter)) ); } // We save all data related to the nodes on the path to reuse it. parts.push({ node, isTextNode, isHeading, hasCurrentSignature, hasForeignComponents, lastStep, }); if (isHeading) break; } return parts; } /** * Remove the comment parts that are inside of other parts. * * @param {object[]} parts * @returns {object[]} */ removeNestedParts(parts) { for (let i = parts.length - 1; i >= 0; i--) { const part = parts[i]; if (part.lastStep === 'up' && !part.hasForeignComponents) { let nextDiveElementIndex = 0; for (let j = i - 1; j > 0; j--) { if (parts[j].lastStep === 'dive') { nextDiveElementIndex = j; break; } } parts.splice(nextDiveElementIndex, i - nextDiveElementIndex); i = nextDiveElementIndex; } } return parts; } /** * Wrap the text and inline nodes into block elements. * * @param {object[]} parts * @param {Element} signatureElement * @returns {object[]} */ encloseInlineParts(parts, signatureElement) { const sequencesToBeEnclosed = []; let start = null; let encloseThis = false; for (let i = 0; i <= parts.length; i++) { const part = parts[i]; if ( part && (start === null || (['back', 'start'].includes(part.lastStep))) && !part.hasForeignComponents && !part.isHeading ) { if (start === null) { // Don't enclose nodes whose parent is an inline element. if (isInline(part.node.parentNode)) { for (let j = i + 1; j < parts.length; j++) { if (parts[j].lastStep === 'up') { i = j - 1; continue; } } break; } else { start = i; } } // We should only enclose if there is need: there is at least one inline or non-empty text // node in the sequence. if ( !encloseThis && ((part.isTextNode && part.node.textContent.trim()) || isInline(part.node)) ) { encloseThis = true; } } else { if (start !== null) { if (encloseThis) { const end = i - 1; sequencesToBeEnclosed.push({ start, end }); } start = null; encloseThis = false; } } } for (let i = sequencesToBeEnclosed.length - 1; i >= 0; i--) { const sequence = sequencesToBeEnclosed[i]; const wrapper = this.context.document.createElement('div'); const nextSibling = parts[sequence.start].node.nextSibling; const parent = parts[sequence.start].node.parentNode; for (let j = sequence.end; j >= sequence.start; j--) { wrapper.appendChild(parts[j].node); } parent.insertBefore(wrapper, nextSibling); const newNode = { node: wrapper, isTextNode: false, isHeading: false, hasCurrentSignature: wrapper.contains(signatureElement), hasForeignComponents: false, lastStep: 'replaced', }; parts.splice(sequence.start, sequence.end - sequence.start + 1, newNode); } return parts; } /** * Remove unnecessary and incorrect parts from the collection. * * @param {object[]} parts * @returns {object[]} */ filterParts(parts) { parts = parts.filter((part) => !part.hasForeignComponents && !part.isTextNode); for (let i = parts.length - 1; i > 0; i--) { const part = parts[i]; if (part.node.tagName === 'P' && !part.node.textContent.trim()) { parts.splice(i, 1); } else { break; } } return parts; } /** * Replace the list elements with collections of their items if appropriate. * * @param {object[]} parts * @param {Element} signatureElement * @returns {object[]} */ replaceListsWithItems(parts, signatureElement) { const lastPart = parts[parts.length - 1]; for (let i = parts.length - 1; i >= 0; i--) { const part = parts[i]; if ( // 'LI', 'DD' are in this list too for this kind of structures: // https://ru.wikipedia.org/w/index.php?diff=103584477. ['UL', 'DL', 'OL', 'LI', 'DD'].includes(part.node.tagName) && // The check for 'DD' rescues us here: // https://ru.wikipedia.org/wiki/Википедия:Форум/Общий#201911201924_Vcohen. // The check for 'DL' rescues us here: // https://ru.wikipedia.org/wiki/Википедия:Форум/Общий#202003090945_Serhio_Magpie. The check // for 'P' rescues us here: // https://ru.wikipedia.org/wiki/Википедия:Форум/Правила#201910270736_S.m.46. // The check for "!parts[i + 1]..." rescues us here: // https://ru.wikipedia.org/wiki/Википедия:Технические_запросы#201912081049_Sunpriat. ( (part.lastStep === 'up' && (!parts[i - 1] || parts[i - 1].lastStep !== 'back')) || ( ( lastPart.node.tagName === 'DD' || lastPart.node.parentNode.tagName === 'DD' || lastPart.node.tagName === 'DL' ) && !parts.slice(i + 1).some((part) => part.node.tagName === 'P') ) ) ) { // We ignore all spaces as an easy way to ignore only whitespace text nodes between element // nodes (this is a bad idea if we deal with inline nodes, but here we deal with lists). const partTextNoSpaces = part.node.textContent.replace(/\s+/g, ''); let current = [part.node]; let children; // With code like this: // * Smth. [signature] // :: Smth. [signature] // ...one comment (preceded by :: in this case) creates its own list tree, not a subtree, // even though it's a reply to a reply. So we dive to the bottom of the hierarchy of nested // lists to get the bottom node (and therefore draw the comment layers more neatly). One of // the most complex tree structures is this: // * Smth. [signature] // :* Smth. // :: Smth. [signature] // (seen here: // https://ru.wikipedia.org/w/index.php?title=Википедия:Форум/Общий&oldid=103760740#201912010211_Mikhail_Ryazanov) // It has a branchy structure that requires a tricky algorithm to be parsed correctly. do { children = current.reduce( (arr, element) => arr.concat(Array.from(element[this.context.childElementsProperty])), [] ); } while ( children.length && children.every((child) => ['UL', 'DL', 'OL', 'LI', 'DD'].includes(child.tagName)) && ( children.map((child) => child.textContent).join('').replace(/\s+/g, '') === partTextNoSpaces ) && (current = children) ); if (current.length > 1) { const newParts = current.map((el) => ({ node: el, isTextNode: false, hasCurrentSignature: el.contains(signatureElement), hasForeignComponents: false, lastStep: 'replaced', })); parts.splice(i, 1, ...newParts); } else if (current[0] !== part.node) { Object.assign(part, { node: current[0], lastStep: 'replaced', }); } } } return parts; } /** * Get the ".cd-commentLevel" elements up the DOM tree. * * @param {Element} initialElement * @returns {Element[]} */ getLevelsUpTree(initialElement) { const levelElements = []; const treeWalker = new ElementsTreeWalker(initialElement); while (treeWalker.parentNode()) { const el = treeWalker.currentNode; if (['UL', 'DL', 'OL'].includes(el.tagName)) { if (el.classList.contains('cd-commentLevel')) { const classAttr = el.getAttribute('class'); const match = classAttr.match(/cd-commentLevel-(\d+)/); if (match) { levelElements.unshift(...Array(Number(match[1]))); } return levelElements; } else { levelElements.unshift(el); } } } return levelElements; } /** * Get all headings on the page. * * @returns {Element[]} */ // The worker context doesn't support .querySelector(), so we have to use .getElementsByTagName(). findHeadings() { const headings = [ ...cd.g.rootElement.getElementsByTagName('h1'), ...cd.g.rootElement.getElementsByTagName('h2'), ...cd.g.rootElement.getElementsByTagName('h3'), ...cd.g.rootElement.getElementsByTagName('h4'), ...cd.g.rootElement.getElementsByTagName('h5'), ...cd.g.rootElement.getElementsByTagName('h6'), ]; headings.sort((heading1, heading2) => this.context.follows(heading1, heading2) ? 1 : -1); return headings; } } "
"/** * Web page processing module. Its only export, `processPage()`, is executed after {@link module:app * the main module} on first run and as part of {@link module:boot.reloadPage} on subsequent runs. * * @module processPage */ import CdError from './CdError'; import Comment from './Comment'; import CommentForm from './CommentForm'; import Page from './Page'; import Parser, { getUserNameFromLink } from './Parser'; import Section from './Section'; import cd from './cd'; import commentLayers from './commentLayers'; import currentSection from './currentSection'; import navPanel from './navPanel'; import toc from './toc'; import updateChecker from './updateChecker'; import { ElementsTreeWalker } from './treeWalker'; import { addPreventUnloadCondition, handleGlobalKeyDown, handleScroll, handleWindowResize, } from './eventHandlers'; import { confirmDialog, editWatchedSections, notFound, settingsDialog } from './modal'; import { generateCommentAnchor, parseCommentAnchor, resetCommentAnchors } from './timestamp'; import { getSettings, getVisits, getWatchedSections } from './options'; import { init, removeLoadingOverlay, restoreCommentForms, saveSession } from './boot'; import { isInline } from './util'; import { setSettings, setVisits } from './options'; /** * Prepare (initialize or reset) various properties, mostly global ones. DOM preparations related to * comment layers are also made here. * * @param {object} [data] Data passed from the main module. * @param {Promise} [data.messagesRequest] Promise returned by {@link module:siteData.loadData}. * @private */ async function prepare({ messagesRequest }) { cd.g.$root = cd.g.$content.children('.mw-parser-output'); if (!cd.g.$root.length) { cd.g.$root = cd.g.$content; } cd.g.rootElement = cd.g.$root.get(0); toc.reset(); /** * Collection of all comments on the page ordered the same way as in the DOM. * * @name comments * @type {Comment[]} * @memberof module:cd~convenientDiscussions */ cd.comments = []; /** * Collection of all sections on the page ordered the same way as in the DOM. * * @name sections * @type {Section[]} * @memberof module:cd~convenientDiscussions */ cd.sections = []; if (cd.g.isFirstRun) { await init({ messagesRequest }); } else { resetCommentAnchors(); commentLayers.reset(); } } /** * @typedef {object} GetFirstElementInViewportDataReturn * @property {Element} element * @property {number} top * @private */ /** * Find the first element in the viewport looking from the top of the page and its top offset. * * @returns {?GetFirstElementInViewportDataReturn} * @private */ function getFirstElementInViewportData() { let element; let top; if (window.pageYOffset !== 0 && cd.g.rootElement.getBoundingClientRect().top <= 0) { const treeWalker = new ElementsTreeWalker(cd.g.rootElement.firstElementChild); while (true) { if (!isInline(treeWalker.currentNode.tagName)) { const rect = treeWalker.currentNode.getBoundingClientRect(); if (rect.bottom >= 0 && rect.height !== 0) { element = treeWalker.currentNode; top = rect.top; if (treeWalker.firstChild()) { continue; } else { break; } } } if (!treeWalker.nextSibling()) break; } } return element ? { element, top } : null; } /** * Get all text nodes under the root element in the window (not worker) context. * * @returns {Node[]} */ function getAllTextNodes() { const result = document.evaluate( // './/text()' doesn't work in Edge. './/descendant::text()', cd.g.rootElement, null, XPathResult.ANY_TYPE, null ); const textNodes = []; let node; while ((node = result.iterateNext())) { textNodes.push(node); } return textNodes; } /** * Find some types of special elements on the page (floating elements, closed discussions, outdent * templates). */ function findSpecialElements() { // Describe all floating elements on the page in order to calculate the right border (temporarily // setting "overflow: hidden") for all comments that they intersect with. const floatingElementsSelector = [ ...cd.g.FLOATING_ELEMENT_SELECTORS, ...cd.config.customFloatingElementSelectors, ] .join(', '); cd.g.floatingElements = cd.g.$root .find(floatingElementsSelector) .get() // Remove all known elements that never intersect comments from the collection. .filter((el) => !el.classList.contains('cd-ignoreFloating')); const closedDiscussionsSelector = cd.config.closedDiscussionClasses .map((name) => `.${name}`) .join(', '); cd.g.closedDiscussionElements = cd.g.$root.find(closedDiscussionsSelector).get(); cd.g.pageHasOutdents = Boolean(cd.g.$root.find('.outdent-template').length); } /** * Replace an element with an identical one but with another tag name, i.e. move all child nodes, * attributes, and some bound events to a new node, and also reassign references in some variables * and properties to this element. Unfortunately, we can't just change the element's `tagName` to do * that. * * Not a pure function; it alters `feivData`. * * @param {Element} element * @param {string} newType * @param {object|undefined} feivData * @returns {Element} * @private */ function changeElementType(element, newType, feivData) { const newElement = document.createElement(newType); while (element.firstChild) { newElement.appendChild(element.firstChild); } Array.from(element.attributes).forEach((attribute) => { newElement.setAttribute(attribute.name, attribute.value); }); // If this element is a part of a comment, replace it in the Comment object instance. let commentId = element.getAttribute('data-comment-id'); if (commentId !== null) { commentId = Number(commentId); cd.comments[commentId].replaceElement(element, newElement); } else { element.parentNode.replaceChild(newElement, element); } if (feivData && element === feivData.element) { feivData.element = newElement; } return newElement; } /** * Combine two adjacent ".cd-commentLevel" elements into one, recursively going deeper in terms of * the nesting level. * * @param {object|undefined} feivData * @private */ function mergeAdjacentCommentLevels(feivData) { const levels = ( cd.g.rootElement.querySelectorAll('.cd-commentLevel:not(ol) + .cd-commentLevel:not(ol)') ); if (!levels.length) return; const isOrHasCommentLevel = (el) => ( (el.classList.contains('cd-commentLevel') && el.tagName !== 'OL') || el.querySelector('.cd-commentLevel:not(ol)') ); Array.from(levels).forEach((bottomElement) => { const topElement = bottomElement.previousElementSibling; // If the previous element was removed in this cycle. (Or it could be absent for some other // reason? I can confirm that I witnessed a case where the element was absent, but didn't pay // attention why unfortunately.) if (!topElement) return; let currentTopElement = topElement; let currentBottomElement = bottomElement; do { const topTag = currentTopElement.tagName; const bottomInnerTags = {}; if (topTag === 'UL') { bottomInnerTags.DD = 'LI'; } else if (topTag === 'DL') { bottomInnerTags.LI = 'DD'; } let firstMoved; if (isOrHasCommentLevel(currentTopElement)) { while (currentBottomElement.childNodes.length) { let child = currentBottomElement.firstChild; if (child.nodeType === Node.ELEMENT_NODE) { if (bottomInnerTags[child.tagName]) { child = changeElementType(child, bottomInnerTags[child.tagName], feivData); } if (firstMoved === undefined) { firstMoved = child; } } else { if (firstMoved === undefined && child.textContent.trim()) { // Don't fill the "firstMoved" variable which is used further to merge elements if // there is a non-empty text node between. (An example that is now fixed: // https://ru.wikipedia.org/wiki/Википедия:Форум/Архив/Викиданные/2018/1_полугодие#201805032155_NBS, // but other can be on the loose.) Instead, wrap the text node into an element to // prevent it from being ignored when searching next time for adjacent .commentLevel // elements. This could be seen only as an additional precaution, since it doesn't fix // the source of the problem: the fact that a bare text node is (probably) a part of // the reply. It shouldn't be happening. firstMoved = null; const newChild = document.createElement('span'); newChild.appendChild(child); child = newChild; } } currentTopElement.appendChild(child); } currentBottomElement.remove(); } currentBottomElement = firstMoved; currentTopElement = firstMoved?.previousElementSibling; } while ( currentTopElement && currentBottomElement && isOrHasCommentLevel(currentBottomElement) ); }); } /** * Perform some DOM-related taskes after parsing comments. * * @param {object|undefined} feivData * @private */ function adjustDom(feivData) { mergeAdjacentCommentLevels(feivData); mergeAdjacentCommentLevels(feivData); if (cd.g.rootElement.querySelector('.cd-commentLevel:not(ol) + .cd-commentLevel:not(ol)')) { console.warn('.cd-commentLevel adjacencies have left.'); } $('dl').has('dt').each((i, el) => { Array.from(el.classList) .filter((className) => className.startsWith('cd-commentLevel')) .forEach((className) => el.classList.remove(className)); }); } /** * Parse comments and modify related parts of the DOM. * * @param {Parser} parser * @param {object|undefined} feivData * @throws {CdError} If there are no comments. * @private */ function processComments(parser, feivData) { const timestamps = parser.findTimestamps(); const signatures = parser.findSignatures(timestamps); signatures.forEach((signature) => { try { const comment = parser.createComment(signature); if (comment.highlightables.length) { cd.comments.push(comment); } } catch (e) { if (!(e instanceof CdError)) { console.error(e); } } }); adjustDom(feivData); /** * The script has processed the comments. * * @event commentsReady * @type {module:cd~convenientDiscussions.comments} */ mw.hook('convenientDiscussions.commentsReady').fire(cd.comments); } /** * Parse sections and modify some parts of them. * * @param {Parser} parser * @param {Promise} watchedSectionsRequest * @private */ function processSections(parser, watchedSectionsRequest) { parser.findHeadings().forEach((heading) => { try { const section = parser.createSection(heading, watchedSectionsRequest); if (section.id !== undefined) { cd.sections.push(section); } } catch (e) { if (!(e instanceof CdError)) { console.error(e); } } }); Section.adjust(); if (watchedSectionsRequest) { watchedSectionsRequest.then(() => { Section.cleanUpWatched(); toc.highlightWatchedSections(); }); } /** * The script has processed the sections. * * @event sectionsReady * @type {module:cd~convenientDiscussions.sections} */ mw.hook('convenientDiscussions.sectionsReady').fire(cd.sections); } /** * Add an "Add topic" button to the bottom of the page if there is an "Add topic" tab. * * @private */ function addAddTopicButton() { if ($('#ca-addsection').length) { cd.g.addSectionButton = new OO.ui.ButtonWidget({ label: cd.s('addtopic'), framed: false, classes: ['cd-button', 'cd-sectionButton'], }); cd.g.addSectionButton.on('click', () => { CommentForm.createAddSectionForm(); }); cd.g.$addSectionButtonContainer = $('<div>') .addClass('cd-addTopicButtonContainer') .addClass('cd-sectionButtonContainer') .append(cd.g.addSectionButton.$element) .appendTo(cd.g.rootElement); } } /** * Bind a click handler to every known "Add new topic" button. * * @private */ function connectToAddTopicButtons() { $(cd.g.ADD_TOPIC_SELECTORS) .filter(function () { const $button = $(this); if ($button.is('a')) { const href = $button.attr('href'); const path = new mw.Uri(href).path; const parts = path.split('/') const pageName = parts[2]; const page = new Page(pageName); if (page.name !== cd.g.CURRENT_PAGE.name) { return false; } } else if ($button.is('input')) { const pageName = $button .closest('form') .find('input[name="title"]') .val(); const page = new Page(pageName); if (page.name !== cd.g.CURRENT_PAGE.name) { return false; } } else { return false; } return true; }) .off('click.cd') .on('click.cd', function (e) { if (e.ctrlKey || e.shiftKey || e.metaKey) return; const $button = $(this); let preloadConfig; let isNewTopicOnTop = false; if ($button.is('a')) { const href = $button.attr('href'); const query = new mw.Uri(href).query; preloadConfig = { editIntro: query.editintro, commentTemplate: query.preload, headline: query.preloadtitle, summary: query.summary?.replace(/^.+?\*\/ */, ''), noHeadline: Boolean(query.nosummary), omitSignature: Boolean(query.cdomitsignature), }; isNewTopicOnTop = query.section === '0'; } else { // <input> const $form = $button.closest('form'); preloadConfig = { editIntro: $form.find('input[name="editintro"]').val(), commentTemplate: $form.find('input[name="preload"]').val(), headline: $form.find('input[name="preloadtitle"]').val(), summary: $form.find('input[name="summary"]').val(), noHeadline: Boolean($form.find('input[name="nosummary"]').val()), omitSignature: false, }; } e.preventDefault(); CommentForm.createAddSectionForm(preloadConfig, isNewTopicOnTop); }) .attr('title', cd.s('addtopicbutton-tooltip')); } /** * Bind a click handler to comment links to make them work as in-script comment links. * * @param {JQuery} $content * @private */ function connectToCommentLinks($content) { $content .find(`a[href^="#"]`) .filter(function () { return /^#\d{12}_.+$/.test($(this).attr('href')); }) .on('click', function (e) { e.preventDefault(); const anchor = $(this).attr('href').slice(1); Comment.getByAnchor(anchor)?.scrollToAndHighlightTarget(true, true); }); } /** * Highlight comments of the current user. * * @private */ function highlightOwnComments() { if (!cd.settings.highlightOwnComments) return; Comment.configureAndAddLayers(cd.comments.filter((comment) => comment.isOwn)); } /** * Highlight mentions of the current user. * * @param {JQuery} $content * @private */ function highlightMentions($content) { Array.from( $content.get(0).querySelectorAll(`.cd-commentPart a[title*=":${cd.g.CURRENT_USER_NAME}"]`) ) .filter((el) => ( cd.g.USER_NAMESPACE_ALIASES_REGEXP.test(el.title) && !el.parentNode.closest('.cd-signature') && getUserNameFromLink(el) === cd.g.CURRENT_USER_NAME )) .forEach((link) => { link.classList.add('cd-currentUserLink'); }); } /** * Perform fragment-related tasks, as well as comment anchor-related ones. * * @param {object} keptData * @private */ async function processFragment(keptData) { let fragment; let decodedFragment; let escapedFragment; let escapedDecodedFragment; let commentAnchor; if (cd.g.isFirstRun) { fragment = location.hash.slice(1); try { decodedFragment = decodeURIComponent(fragment); } catch (e) { console.error(e); } escapedFragment = $.escapeSelector(fragment); escapedDecodedFragment = decodedFragment && $.escapeSelector(decodedFragment); if (/^\d{12}_.+$/.test(fragment)) { commentAnchor = decodedFragment; } } else { commentAnchor = keptData.commentAnchor; } let date; let author; let comment; if (commentAnchor) { ({ date, author } = parseCommentAnchor(commentAnchor) || {}); comment = Comment.getByAnchor(commentAnchor); if (!keptData.commentAnchor && !comment) { let commentAnchorToCheck; // There can be a time difference between the time we know (taken from the watchlist) and the // time on the page. We take it to be not higher than 5 minutes for the watchlist. for (let gap = 1; !comment && gap <= 5; gap++) { const dateToFind = new Date(date.getTime() - cd.g.MILLISECONDS_IN_A_MINUTE * gap); commentAnchorToCheck = generateCommentAnchor(dateToFind, author); comment = Comment.getByAnchor(commentAnchorToCheck); } } if (comment) { // setTimeout is for Firefox - for some reason, without it Firefox positions the underlay // incorrectly. setTimeout(() => { comment.scrollToAndHighlightTarget(false, keptData.pushState); }); } } if (keptData.sectionAnchor) { const section = Section.getByAnchor(keptData.sectionAnchor); if (section) { if (keptData.pushState) { history.pushState(history.state, '', '#' + section.anchor); } // setTimeout for Firefox, as above setTimeout(() => { section.$elements.first().cdScrollTo('top', false); }); } } if (cd.g.isFirstRun) { const fragmentHasNoTarget = ( decodedFragment && !comment && !cd.config.idleFragments.includes(decodedFragment) && !decodedFragment.startsWith('/media/') && !$(':target').length && !$(`a[name="${escapedDecodedFragment}"]`).length && !$(`*[id="${escapedDecodedFragment}"]`).length && !$(`a[name="${escapedFragment}"]`).length && !$(`*[id="${escapedFragment}"]`).length ); if (decodedFragment && fragmentHasNoTarget && cd.g.isPageActive) { await notFound(decodedFragment, date); } } } /** * Highlight new comments and update the navigation panel. A promise obtained from {@link * module:options.getVisits} should be provided. * * @param {Promise} visitsRequest * @param {object} keptData * @fires newCommentsHighlighted */ async function processVisits(visitsRequest, keptData) { let visits; let thisPageVisits; try { ({ visits, thisPageVisits } = await visitsRequest); } catch (e) { console.warn('Couldn\'t load the settings from the server.', e); return; } if (cd.g.thisPageVisits.length >= 1) { cd.g.previousVisitUnixTime = Number(cd.g.thisPageVisits[cd.g.thisPageVisits.length - 1]); } const currentUnixTime = Math.floor(Date.now() / 1000); // Cleanup for (let i = thisPageVisits.length - 1; i >= 0; i--) { if (thisPageVisits[i] < currentUnixTime - 60 * cd.g.HIGHLIGHT_NEW_COMMENTS_INTERVAL) { thisPageVisits.splice(0, i); break; } } let haveMatchedTimeWithComment = false; if (thisPageVisits.length) { cd.comments.forEach((comment) => { /** * Is the comment new. Set only on active pages (not archived, not old diffs) excluding pages * that are visited for the first time. * * @type {boolean|undefined} * @memberof module:Comment */ comment.isNew = false; /** * Has the comment been seen. Set only on active pages (not archived, not old diffs) excluding * pages that are visited for the first time. Check using `=== false` if you need to know if * the comment is highlighted as new and unseen. * * @type {boolean|undefined} * @memberof module:Comment */ comment.isSeen = true; if (!comment.date) return; const commentUnixTime = Math.floor(comment.date.getTime() / 1000); if (commentUnixTime <= currentUnixTime && currentUnixTime < commentUnixTime + 60) { haveMatchedTimeWithComment = true; } if (commentUnixTime + 60 > thisPageVisits[0]) { comment.isNew = true; comment.isSeen = ( (commentUnixTime + 60 <= thisPageVisits[thisPageVisits.length - 1] || comment.isOwn) && !keptData.unseenCommentAnchors?.some((anchor) => anchor === comment.anchor) ); } }); Comment.configureAndAddLayers(cd.comments.filter((comment) => comment.isNew)); const unseenComments = cd.comments.filter((comment) => comment.isSeen === false); toc.addNewComments(Comment.groupBySection(unseenComments), keptData); } // Reduce the probability that we will wrongfully mark a seen comment as unseen/new by adding a // minute to the current time if there is a comment with matched time. (Previously, the comment // time needed to be less than the current time which could result in missed comments if a comment // was sent the same minute when the page was loaded but after that moment.) thisPageVisits.push(String(currentUnixTime + haveMatchedTimeWithComment * 60)); setVisits(visits); navPanel.fill(); handleScroll(); /** * New comments have been highlighted. * * @event newCommentsHighlighted * @type {module:cd~convenientDiscussions} */ mw.hook('convenientDiscussions.newCommentsHighlighted').fire(cd); } /** * Ask the user if they want to receive desktop notifications on first run and ask for a permission * if it is default but the user has desktop notifications enabled (for example, if he/she is using * a browser different from where he/she has previously used). * * @private */ async function confirmDesktopNotifications() { if (cd.settings.desktopNotifications === 'unknown' && Notification.permission !== 'denied') { // Avoid using the setting kept in `mw.user.options`, as it may be outdated. getSettings({ reuse: true }).then((settings) => { if (settings.desktopNotifications === 'unknown') { const actions = [ { label: cd.s('dn-confirm-yes'), action: 'accept', flags: 'primary', }, { label: cd.s('dn-confirm-no'), action: 'reject', }, ]; confirmDialog(cd.s('dn-confirm'), { size: 'medium', actions, }).then((action) => { let promise; if (action === 'accept') { if (Notification.permission === 'default') { OO.ui.alert(cd.s('dn-grantpermission')); Notification.requestPermission((permission) => { if (permission === 'granted') { cd.settings.desktopNotifications = settings.desktopNotifications = 'all'; promise = setSettings(settings); } else if (permission === 'denied') { cd.settings.desktopNotifications = settings.desktopNotifications = 'none'; promise = setSettings(settings); } }); } else if (Notification.permission === 'granted') { cd.settings.desktopNotifications = settings.desktopNotifications = 'all'; promise = setSettings(settings); } } else if (action === 'reject') { cd.settings.desktopNotifications = settings.desktopNotifications = 'none'; promise = setSettings(settings); } if (promise) { promise.catch((e) => { mw.notify(cd.s('error-settings-save'), { type: 'error' }) console.warn(e); }); } }); } }); } if ( !['unknown', 'none'].includes(cd.settings.desktopNotifications) && Notification.permission === 'default' ) { await OO.ui.alert(cd.s('dn-grantpermission-again'), { title: cd.s('script-name') }); Notification.requestPermission(); } } /** * Log debug data to the console. * * @private */ function debugLog() { const baseTime = ( cd.debug.timerTotal['main code'] + cd.debug.timerTotal['final code and rendering'] ); const timePerComment = baseTime / cd.comments.length; cd.debug.logAndResetTimer('total time'); console.debug(`number of comments: ${cd.comments.length}`); console.debug(`per comment: ${timePerComment.toFixed(2)}`); cd.debug.logAndResetEverything(); } /** * @typedef {object} KeptData * @property {string} [commentAnchor] Comment anchor to scroll to. * @property {string} [sectionAnchor] Section anchor to scroll to. * @property {string} [pushState] Whether to replace the URL in the address bar adding the comment * anchor to it if it's specified. * @property {boolean} [wasPageCreated] Whether the page was created while it was in the * previous state. Affects navigation panel mounting and certain key press handlers adding. * @property {number} [scrollPosition] Page Y offset. * @property {object[]} [unseenCommentAnchors] Anchors of unseen comments on this page. * @property {string} [justWatchedSection] Section just watched so that there could be not * enough time for it to be saved to the server. * @property {string} [justUnwatchedSection] Section just unwatched so that there could be not * enough time for it to be saved to the server. * @property {boolean} [didSubmitCommentForm] Did the user just submitted a comment form. * @property {Promise} [messagesRequest] Promise returned by {@link module:siteData.loadData}. */ /** * Process the current web page. * * @param {KeptData} [keptData={}] Data passed from the previous page state or the main module. * @fires beforeParse * @fires commentsReady * @fires sectionsReady * @fires pageReady */ export default async function processPage(keptData = {}) { cd.debug.stopTimer(cd.g.isFirstRun ? 'loading data' : 'laying out HTML'); cd.debug.startTimer('preparations'); await prepare(keptData); let feivData; if (cd.g.isFirstRun) { feivData = getFirstElementInViewportData(); } cd.debug.stopTimer('preparations'); cd.debug.startTimer('main code'); // This property isn't static: a 404 page doesn't have an ID and is considered inactive, but if // the user adds a topic to it, it will become active and get an ID. At the same time (on a really // rare occasion), an active page may become inactive if it becomes identified as an archive page. cd.g.isPageActive = ( mw.config.get('wgArticleId') && !cd.g.CURRENT_PAGE.isArchivePage() && mw.config.get('wgRevisionId') === mw.config.get('wgCurRevisionId') ); // For testing cd.g.editWatchedSections = editWatchedSections; cd.g.settingsDialog = settingsDialog; let watchedSectionsRequest; if (mw.config.get('wgArticleId')) { watchedSectionsRequest = getWatchedSections(true, keptData); watchedSectionsRequest.catch((e) => { console.warn('Couldn\'t load the settings from the server.', e); }); } let visitsRequest; if (cd.g.isPageActive) { visitsRequest = getVisits(true); } /** * The script is going to parse the page. * * @event beforeParse * @type {module:cd~convenientDiscussions} */ mw.hook('convenientDiscussions.beforeParse').fire(cd); findSpecialElements(); cd.debug.startTimer('process comments'); const parser = new Parser({ CommentClass: Comment, SectionClass: Section, childElementsProperty: 'children', document, follows: (el1, el2) => el1.compareDocumentPosition(el2) & Node.DOCUMENT_POSITION_PRECEDING, getAllTextNodes, getElementByClassName: (node, className) => node.querySelector(`.${className}`), }); try { processComments(parser, feivData); } catch (e) { console.error(e); } cd.debug.stopTimer('process comments'); // We change the evaluation of cd.g.isPageActive if there is no comments and no "Add section" // button. if ( cd.g.isPageActive && !cd.comments.length && !$('#ca-addsection').length && !cd.g.PAGE_WHITELIST_REGEXP?.test(cd.g.CURRENT_PAGE.name) ) { cd.g.isPageActive = false; } cd.debug.startTimer('process sections'); processSections(parser, watchedSectionsRequest); cd.debug.stopTimer('process sections'); addAddTopicButton(); connectToAddTopicButtons(); cd.debug.stopTimer('main code'); // Operations that need reflow, such as getBoundingClientRect(), go in this section. cd.debug.startTimer('final code and rendering'); // Restore the initial viewport position in terms of visible elements which is how the user sees // it. if (feivData) { const y = window.pageYOffset + feivData.element.getBoundingClientRect().top - feivData.top; window.scrollTo(0, y); } highlightOwnComments(); processFragment(keptData); if (cd.g.isPageActive) { if (cd.g.isFirstRun || keptData.wasPageCreated) { navPanel.mount(); } else { navPanel.reset(); } // New comments highlighting processVisits(visitsRequest, keptData); // This should be below processVisits() because of updateChecker.processRevisionsIfNeeded. updateChecker.init(visitsRequest, keptData); } else { if (navPanel.isMounted()) { navPanel.unmount(); } } if (cd.g.isPageActive || !mw.config.get('wgArticleId')) { // This should be below the viewport position restoration and own comments highlighting as it // may rely on the elements that are made invisible during the comment forms restoration. It // should also be below the navPanel mount/reset methods as it runs // navPanel.updateCommentFormButton() which depends on the navPanel being mounted. restoreCommentForms(); } if (cd.g.isFirstRun) { mw.hook('wikipage.content').add(highlightMentions); currentSection.mount(); // `mouseover` allows to capture the event when the cursor is not moving but ends up above the // element (for example, as a result of scrolling). $(document).on('mousemove mouseover', Comment.highlightFocused); $(window).on('resize orientationchange', handleWindowResize); addPreventUnloadCondition('commentForms', () => { saveSession(); return ( mw.user.options.get('useeditwarning') && (CommentForm.getLastActiveAltered() || (alwaysConfirmLeavingPage && cd.commentForms.length)) ); }); mw.hook('wikipage.content').add(connectToCommentLinks); mw.hook('convenientDiscussions.previewReady').add(connectToCommentLinks); // Mutation observer doesn't follow all possible cases (for example, initiated with adding new // CSS) of comment position changing unfortunately. setInterval(() => { commentLayers.redrawIfNecessary(); }, 1000); const observer = new MutationObserver((records) => { const areLayers = records .every((record) => /^cd-comment(Underlay|Overlay|Layers)/.test(record.target.className)); if (areLayers) return; commentLayers.redrawIfNecessary(); }); observer.observe(cd.g.$content.get(0), { attributes: true, childList: true, subtree: true, }); $(document) .on('keydown', handleGlobalKeyDown) .on('scroll resize orientationchange', handleScroll); } else { currentSection.reset(); } let alwaysConfirmLeavingPage = false; if (mw.user.options.get('editondblclick')) { mw.loader.using('mediawiki.action.view.dblClickEdit').then(() => { $('#ca-edit').off('click'); alwaysConfirmLeavingPage = true; }); } if (mw.user.options.get('editsectiononrightclick')) { mw.loader.using('mediawiki.action.view.rightClickEdit').then(() => { $('.mw-editsection a').off('click'); alwaysConfirmLeavingPage = true; }); } if (cd.g.isFirstRun) { confirmDesktopNotifications(); } /** * The script has processed the page. * * @event pageReady * @type {module:cd~convenientDiscussions} */ mw.hook('convenientDiscussions.pageReady').fire(cd); removeLoadingOverlay(); cd.g.isFirstRun = false; // The next line is needed to calculate the rendering time: it won't run until everything gets // rendered. cd.g.rootElement.getBoundingClientRect(); cd.debug.stopTimer('final code and rendering'); cd.debug.stopTimer('total time'); debugLog(); } "
"/** * Timestamp regexp generator, timestamp parser generator, date formats, digits, timezones, * MediaWiki messages, and other site data. * * The code is based on {@link * https://gerrit.wikimedia.org/r/#/c/mediawiki/core/+/539305/3/signaturedetector.js}. * * @module siteData * @author Bartosz Dziewoński <matma.rex@gmail.com> * @license GPL-2.0-only */ import cd from './cd'; import { getMessages } from './util'; const DATE_FORMATS = { 'ab': 'H:i, j xg Y', 'abs': 'j F Y H.i', 'ace': 'j F Y H.i', 'ady-cyrl': 'H:i, j F Y', 'aeb-arab': 'H:i، j xg Y', 'aeb-latn': 'H:i, j F Y', 'af': 'H:i, j F Y', 'ais': 'H:i, j F Y', 'ak': 'H:i, j F Y', 'aln': 'j F Y H:i', 'ami': 'H:i, j F Y', 'am': 'H:i, j F Y', 'ang': 'H:i, j F Y', 'an': 'H:i j M Y', 'anp': 'H:i, j F Y', 'arc': 'H:i, j F Y', 'ar': 'H:i، j xg Y', 'arn': 'H:i j M Y', 'arq': 'H:i، j xg Y', 'ary': 'H:i, j F Y', 'arz': 'H:i، j xg Y', 'ase': 'H:i, j F Y', 'as': 'H:i, j F Y', 'ast': 'H:i j M Y', 'atj': 'j F Y à H:i', 'av': 'H:i, j xg Y', 'avk': 'H:i, j F Y', 'awa': 'H:i, j F Y', 'ay': 'H:i j M Y', 'azb': 'j xg Y، ساعت H:i', 'az': 'H:i, j F Y', 'ba': 'H:i, j xg Y', 'ban': 'j F Y H.i', 'bar': 'H:i, j. M Y', 'bbc-latn': 'j F Y H.i', 'bcc': 'j xg Y، ساعت H:i', 'bcl': 'H:i, j F Y', 'be': 'H:i, j xg Y', 'be-tarask': 'H:i, j xg Y', 'bg': 'H:i, j F Y', 'bgn': 'j xg Y، ساعت H:i', 'bho': 'H:i, j F Y', 'bi': 'H:i, j F Y', 'bjn': 'j F Y H.i', 'bm': 'j F Y à H:i', 'bn': 'H:i, j F Y', 'bo': 'H:i, j F Y', 'bpy': 'H:i, j F Y', 'bqi': 'j xg Y، ساعت H:i', 'brh': 'H:i, j F Y', 'br': 'j M Y "da" H:i', 'bs': 'H:i, j F Y', 'btm': 'j F Y H.i', 'bto': 'H:i, j F Y', 'bug': 'j F Y H.i', 'bxr': 'H:i, j xg Y', 'ca': 'H:i, j M Y', 'cbk-zam': 'H:i j M Y', 'cdo': 'Y "nièng" n "nguŏk" j "hô̤" (D) H:i', 'ceb': 'H:i, j F Y', 'ce': 'Y, j F, H:i', 'ch': 'H:i, j F Y', 'chr': 'H:i, j F Y', 'chy': 'H:i, j F Y', 'ckb': 'H:i، jی xg Y', 'co': 'H:i, j M Y', 'cps': 'H:i, j F Y', 'crh-cyrl': 'H:i, Y "с." xg j', 'crh-latn': 'H:i, Y "s." xg j', 'cr': 'H:i, j F Y', 'csb': 'H:i, j M Y', 'cs': 'j. n. Y, H:i', 'cu': 'H:i, xg j числа, Y', 'cv': 'H:i, j xg Y', 'cy': 'H:i, j F Y', 'da': 'j. M Y, H:i', 'de-at': 'H:i, j. M Y', 'de-ch': 'H:i, j. M Y', 'de-formal': 'H:i, j. M Y', 'de': 'H:i, j. M Y', 'din': 'H:i, j F Y', 'diq': 'H:i, j F Y', 'dsb': 'j. xg Y, H:i', 'dtp': 'H:i, j F Y', 'dty': 'H:i, j F Y', 'dv': 'H:i, j F Y', 'dz': 'H:i, j F Y', 'ee': 'H:i, j F Y', 'egl': 'H:i, j M Y', 'el': 'H:i, j xg Y', 'eml': 'H:i, j M Y', 'en-ca': 'H:i, j F Y', 'en-gb': 'H:i, j F Y', 'en': 'H:i, j F Y', 'eo': 'H:i, j M. Y', 'es-formal': 'H:i j M Y', 'es': 'H:i j M Y', 'et': 'j. F Y, "kell" H:i', 'eu': 'H:i, j F Y', 'exif': 'H:i, j F Y', 'ext': 'H:i j M Y', 'fa': 'j xg Y، ساعت H:i', 'ff': 'j F Y à H:i', 'fi': 'j. F"ta" Y "kello" H.i', 'fit': 'j. F"ta" Y "kello" H.i', 'fj': 'H:i, j F Y', 'fo': 'j. M Y "kl." H:i', 'frc': 'j F Y à H:i', 'fr': 'j F Y à H:i', 'frp': 'j F Y "a" H:i', 'frr': 'H:i, j. M Y', 'fur': 'j "di" M Y "a lis" H:i', 'fy': 'j M Y, H.i', 'gag': 'H.i, j F Y', 'ga': 'H:i, j F Y', 'gan-hans': 'Y年n月j日 (D) H:i', 'gan-hant': 'Y年n月j日 (D) H:i', 'gan': 'Y年n月j日 (D) H:i', 'gcr': 'j F Y à H:i', 'gd': 'H:i, j F Y', 'gl': 'j \\d\\e F \\d\\e Y "ás" H:i', 'glk': 'j xg Y، ساعت H:i', 'gn': 'H:i j M Y', 'gom': 'H:i, j F Y', 'gom-deva': 'H:i, j F Y', 'gom-latn': 'H:i, j F Y', 'gor': 'j F Y H.i', 'got': 'H:i, j F Y', 'grc': 'H:i, j xg Y', 'gsw': 'H:i, j. M Y', 'gu': 'H:i, j F Y', 'gv': 'H:i, j F Y', 'ha': 'H:i, j F Y', 'hak': 'H:i, j F Y', 'haw': 'H:i, j F Y', 'he': 'H:i, j xg Y', 'hif-latn': 'H:i, j F Y', 'hi': 'H:i, j F Y', 'hil': 'H:i, j F Y', 'hr': 'H:i, j. F Y.', 'hrx': 'H:i, j. M Y', 'hsb': 'j. xg Y, H:i', 'ht': 'j F Y à H:i', 'hu-formal': 'Y. F j., H:i', 'hu': 'Y. F j., H:i', 'hy': 'H:i, j xg Y', 'hyw': 'H:i, j xg Y', 'ia': 'H:i, j F Y', 'id': 'j F Y H.i', 'ie': 'H:i, j F Y', 'ig': 'H:i, j F Y', 'ii': 'Y年n月j日 (D) H:i', 'ike-cans': 'H:i, j F Y', 'ike-latn': 'H:i, j F Y', 'ik': 'H:i, j F Y', 'ilo': 'H:i, j F Y', 'inh': 'H:i, j xg Y', 'io': 'H:i, j M. Y', 'is': 'j. F Y "kl." H:i', 'it': 'H:i, j M Y', 'ja': 'Y年n月j日 (D) H:i', 'jam': 'H:i, j F Y', 'jbo': 'H:i, j F Y', 'jut': 'j. M Y, H:i', 'jv': 'j F Y H.i', 'kaa': 'H:i, Y "j." xg j', 'kab': 'H:i, j F Y', 'ka': 'H:i, j F Y', 'kbd-cyrl': 'H:i, j F Y', 'kbp': 'j F Y à H:i', 'kg': 'H:i, j F Y', 'khw': 'H:i، j xg Yء', 'ki': 'H:i, j F Y', 'kiu': 'H.i, j F Y', 'kjp': ' H:i"၊" j F Y', 'kk-arab': 'H:i، Y "ج." xg j', 'kk-cyrl': 'H:i, Y "ж." xg j', 'kk': 'H:i, Y "ж." xg j', 'kk-latn': 'H:i, Y "j." xg j', 'kl': 'j. M Y, H:i', 'km': 'មោងH:i l ទd F ឆ្នាY', 'kn': 'H:i, j F Y', 'krc': 'H:i, j xg Y', 'kri': 'H:i, j F Y', 'krj': 'H:i, j F Y', 'krl': 'j. F"ta" Y "kello" H.i', 'ks-arab': 'H:i, j F Y', 'ks-deva': 'H:i, j F Y', 'ksh': 'H:i, j. M Y', 'ks': 'H:i, j F Y', 'ku-arab': 'H:i، jی xg Y', 'ku-latn': 'H:i, j F Y', 'kum': 'H:i, j xg Y', 'kv': 'H:i, j xg Y', 'kw': 'H:i, j F Y', 'ky': 'H:i, j F Y', 'lad': 'H:i j M Y', 'la': 'H:i, j xg Y', 'lbe': 'H:i, j xg Y', 'lb': 'H:i, j. M Y', 'lez': 'H:i, j xg Y', 'lfn': 'H:i, j F Y', 'lg': 'H:i, j F Y', 'lij': 'H:i, j M Y', 'li': 'j M Y H:i', 'liv': 'j. F Y, "kell" H:i', 'lki': 'j xg Y، ساعت H:i', 'lmo': 'H:i, j M Y', 'ln': 'j F Y à H:i', 'lo': 'H:i, j F Y', 'loz': 'H:i, j F Y', 'lrc': 'j xg Y، ساعت H:i', 'ltg': 'Y". gada" j. F", plkst." H.i', 'lt': 'H:i, j F Y', 'lus': 'H:i, j F Y', 'luz': 'j xg Y، ساعت H:i', 'lv': 'Y". gada" j. F", plkst." H.i', 'lzh': 'Y年n月j日 (D) H時i分', 'lzz': 'H.i, j F Y', 'mai': 'H:i, j F Y', 'map-bms': 'j F Y H.i', 'mdf': 'H:i, j xg Y', 'mg': 'j F Y à H:i', 'mhr': 'H:i, j xg Y', 'mi': 'H:i, j F Y', 'min': 'j F Y H.i', 'mk': 'H:i, j F Y', 'ml': 'H:i, j F Y', 'mni': 'H:i, j F Y', 'mn': 'H:i, j F Y', 'mnw': ' H:i"၊" j F Y', 'mo': 'j F Y H:i', 'mrj': 'H:i, j xg Y', 'mr': 'H:i, j F Y', 'ms': 'H:i, j F Y', 'mt': 'H:i, j F Y', 'mwl': 'H\\hi\\m\\i\\n \\d\\e j \\d\\e F \\d\\e Y', 'my': ' H:i"၊" j F Y', 'myv': 'H:i, j xg Y', 'mzn': 'j xg Y، ساعت H:i', 'nah': 'H:i j M Y', 'na': 'H:i, j F Y', 'nan': 'Y-"nî" n-"goe̍h" j-"ji̍t" (D) H:i', 'nap': 'H:i, j M Y', 'nb': 'j. M Y "kl." H:i', 'nds': 'H:i, j. M Y', 'nds-nl': 'H:i, j M Y', 'ne': 'H:i, j F Y', 'new': 'H:i, j F Y', 'niu': 'H:i, j F Y', 'nl-informal': 'j M Y H:i', 'nl': 'j M Y H:i', 'nn': 'j. F Y "kl." H:i', 'nov': 'H:i, j F Y', 'nqo': 'H:i, j F Y', 'nrm': 'j F Y à H:i', 'nso': 'H:i, j F Y', 'nv': 'H:i, j F Y', 'ny': 'H:i, j F Y', 'nys': 'H:i, j F Y', 'oc': 'j F "de" Y "a" H.i', 'olo': 'j. F"ta" Y "kello" H.i', 'om': 'H:i, j F Y', 'or': 'H:i, j F Y', 'os': 'H:i, j xg Y', 'pag': 'H:i, j F Y', 'pa': 'H:i, j F Y', 'pam': 'H:i, j F Y', 'pap': 'H:i, j F Y', 'pcd': 'j F Y à H:i', 'pdc': 'H:i, j. M Y', 'pdt': 'H:i, j. M Y', 'pfl': 'H:i, j. M Y', 'pih': 'H:i, j F Y', 'pi': 'H:i, j F Y', 'pl': 'H:i, j M Y', 'pms': 'H:i, j M Y', 'pnb': 'H:i, j F Y', 'pnt': 'H:i, j xg Y', 'prg': 'H:i, j F Y', 'ps': 'H:i, j F Y', 'pt-br': 'H"h"i"min" "de" j "de" F "de" Y', 'pt': 'H\\hi\\m\\i\\n \\d\\e j \\d\\e F \\d\\e Y', 'qqq': 'H:i, j F Y', 'qug': 'H:i j M Y', 'qu': 'H:i j M Y', 'rgn': 'H:i, j M Y', 'rif': 'H:i, j F Y', 'rm': 'H:i, j F Y', 'rmy': 'j F Y H:i', 'roa-tara': 'H:i, j M Y', 'ro': 'j F Y H:i', 'rue': 'H:i, j xg Y', 'ru': 'H:i, j xg Y', 'rup': 'j F Y H:i', 'ruq-cyrl': 'H:i, j F Y', 'ruq-latn': 'j F Y H:i', 'rw': 'H:i, j F Y', 'sah': 'H:i, j xg Y', 'sa': 'H:i, j F Y', 'sat': 'H:i, j F Y', 'sc': 'H:i, j M Y', 'scn': 'H:i, j M Y', 'sco': 'H:i, j F Y', 'sdc': 'H:i, j F Y', 'sdh': 'j xg Y، ساعت H:i', 'sd': 'H:i, j F Y', 'sei': 'H:i, j F Y', 'se': 'xg j "b." Y "dii." G.i', 'ses': 'j F Y à H:i', 'sg': 'j F Y à H:i', 'sgs': 'H:i, j F Y', 'shi': 'H:i, j F Y', 'sh': 'H:i, j F Y', 'shn': 'H:i, j F Y', 'shy-latn': 'H:i, j F Y', 'si': 'H:i, j F Y', 'sk': 'H:i, j. F Y', 'skr-arab': 'H:i، j xg Yء', 'sli': 'H:i, j. M Y', 'sl': 'H:i, j. F Y', 'sma': 'H:i, j F Y', 'sm': 'H:i, j F Y', 'sn': 'H:i, j F Y', 'so': 'H:i, j F Y', 'sq': 'j F Y H:i', 'sr-ec': 'H:i, j. F Y.', 'sr-el': 'H:i, j. F Y.', 'srn': 'j M Y H:i', 'ss': 'H:i, j F Y', 'st': 'H:i, j F Y', 'stq': 'H:i, j. M Y', 'sty': 'H:i, j xg Y', 'su': 'j F Y H.i', 'sv': 'j F Y "kl." H.i', 'sw': 'H:i, j F Y', 'szl': 'H:i, j M Y', 'ta': 'H:i, j F Y', 'tay': 'H:i, j F Y', 'tcy': 'H:i, j F Y', 'te': 'H:i, j F Y', 'tet': 'H\\hi\\m\\i\\n \\d\\e j \\d\\e F \\d\\e Y', 'tg-cyrl': 'H:i, j xg Y', 'tg-latn': 'H:i, j F Y', 'th': 'H:i, j F xkY', 'ti': 'H:i, j F Y', 'tk': 'H:i, j F Y', 'tl': 'H:i, j F Y', 'tly': 'H:i, j F Y', 'tn': 'H:i, j F Y', 'to': 'H:i, j F Y', 'tpi': 'H:i, j F Y', 'tr': 'H.i, j F Y', 'tru': 'H:i, j F Y', 'trv': 'H:i, j F Y', 'ts': 'H:i, j F Y', 'tt-cyrl': 'j M Y, H:i', 'tt-latn': 'j M Y, H:i', 'tw': 'H:i, j F Y', 'ty': 'j F Y à H:i', 'tyv': 'H:i, j xg Y', 'tzm': 'H:i, j F Y', 'udm': 'H:i, j xg Y', 'ug-arab': 'H:i, j F Y', 'ug-latn': 'H:i, j F Y', 'uk': 'H:i, j xg Y', 'ur': 'H:i، j xg Yء', 'uz': 'H:i, j-F Y', 'vec': 'H:i, j M Y', 've': 'H:i, j F Y', 'vep': 'j. F Y, "kell" H:i', 'vi': 'H:i, "ngày" j "tháng" n "năm" Y', 'vls': 'j M Y H:i', 'vmf': 'H:i, j. M Y', 'vo': 'H:i, Y F j"id"', 'vot': 'j. F"ta" Y "kello" H.i', 'vro': 'j. F Y, "kell" H:i', 'wa': 'j F Y à H:i', 'war': 'H:i, j F Y', 'wo': 'j F Y à H:i', 'wuu': 'Y年n月j号 (D) H:i', 'xal': 'H:i, j xg Y', 'xh': 'H:i, j F Y', 'xmf': 'H:i, j F Y', 'xsy': 'H:i, j F Y', 'yi': 'H:i, j xg Y', 'yo': 'H:i, j F Y', 'yue': 'Y年n月j號 (D) H:i', 'za': 'Y年n月j日 (D) H:i', 'zea': 'j M Y H:i', 'zgh': 'H:i, j F Y', 'zh-hans': 'Y年n月j日 (D) H:i', 'zh-hant': 'Y年n月j日 (D) H:i', 'zh-hk': 'Y年n月j日 (D) H:i', 'zh': 'Y年n月j日 (D) H:i', 'zh-sg': 'Y年n月j日 (D) H:i', 'zh-tw': 'Y年n月j日 (D) H:i', 'zu': 'H:i, j F Y', }; const DIGITS = { 'aeb-arab': '٠١٢٣٤٥٦٧٨٩', 'anp': '०१२३४५६७८९', 'ar': '٠١٢٣٤٥٦٧٨٩', 'as': '০১২৩৪৫৬৭৮৯', 'azb': '۰۱۲۳۴۵۶۷۸۹', 'bcc': '۰۱۲۳۴۵۶۷۸۹', 'bgn': '۰۱۲۳۴۵۶۷۸۹', 'bho': '०१२३४५६७८९', 'bn': '০১২৩৪৫৬৭৮৯', 'bo': '༠༡༢༣༤༥༦༧༨༩', 'bpy': '০১২৩৪৫৬৭৮৯', 'bqi': '۰۱۲۳۴۵۶۷۸۹', 'ckb': '٠١٢٣٤٥٦٧٨٩', 'dty': '०१२३४५६७८९', 'dz': '༠༡༢༣༤༥༦༧༨༩', 'fa': '۰۱۲۳۴۵۶۷۸۹', 'glk': '۰۱۲۳۴۵۶۷۸۹', 'gom-deva': '०१२३४५६७८९', 'gu': '૦૧૨૩૪૫૬૭૮૯', 'hi': '०१२३४५६७८९', 'kjp': '၀၁၂၃၄၅၆၇၈၉', 'kk-arab': '۰۱۲۳۴۵۶۷۸۹', 'km': '០១២៣៤៥៦៧៨៩', 'kn': '೦೧೨೩೪೫೬೭೮೯', 'ks-arab': '٠١٢٣٤٥٦٧٨٩', 'ks-deva': '०१२३४५६७८९', 'ks': '٠١٢٣٤٥٦٧٨٩', 'ku-arab': '٠١٢٣٤٥٦٧٨٩', 'lki': '۰۱۲۳۴۵۶۷۸۹', 'lo': '໐໑໒໓໔໕໖໗໘໙', 'lrc': '۰۱۲۳۴۵۶۷۸۹', 'luz': '۰۱۲۳۴۵۶۷۸۹', 'lzh': '〇一二三四五六七八九', 'mai': '०१२३४५६७८९', 'mni': '꯰꯱꯲꯳꯴꯵꯶꯷꯸꯹', 'mnw': '၀၁၂၃၄၅၆၇၈၉', 'mr': '०१२३४५६७८९', 'my': '၀၁၂၃၄၅၆၇၈၉', 'mzn': '۰۱۲۳۴۵۶۷۸۹', 'ne': '०१२३४५६७८९', 'new': '०१२३४५६७८९', 'nqo': '߀߁߂߃߄߅߆߇߈߉', 'or': '୦୧୨୩୪୫୬୭୮୯', 'pi': '०१२३४५६७८९', 'ps': '۰۱۲۳۴۵۶۷۸۹', 'sa': '०१२३४५६७८९', 'sat': '᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙', 'sdh': '۰۱۲۳۴۵۶۷۸۹', 'skr-arab': '٠١٢٣٤٥٦٧٨٩', 'tcy': '೦೧೨೩೪೫೬೭೮೯', }; const TIMEZONES = [ 'acdt', 'acst', 'act', 'acwdt', 'acwst', 'addt', 'adt', 'aedt', 'aest', 'aft', 'ahdt', 'ahst', 'akdt', 'akst', 'amst', 'amt', 'ant', 'apt', 'arst', 'art', 'ast', 'awdt', 'awst', 'awt', 'azomt', 'azost', 'azot', 'bdst', 'bdt', 'beat', 'beaut', 'bmt', 'bnt', 'bortst', 'bort', 'bost', 'bot', 'brst', 'brt', 'bst', 'btt', 'burt', 'cant', 'capt', 'cast', 'cat', 'cawt', 'cct', 'cddt', 'cdt', 'cemt', 'cest', 'cet', 'cgst', 'cgt', 'chadt', 'chast', 'chdt', 'chost', 'chot', 'chut', 'ckhst', 'ckt', 'clst', 'clt', 'cmt', 'cost', 'cot', 'cpt', 'cst', 'cut', 'cvst', 'cvt', 'cwt', 'cxt', 'chst', 'dact', 'dmt', 'easst', 'east', 'eat', 'ect', 'eddt', 'edt', 'eest', 'eet', 'egst', 'egt', 'ehdt', 'emt', 'ept', 'est', 'ewt', 'ffmt', 'fjst', 'fjt', 'fkst', 'fkt', 'fmt', 'fnst', 'fnt', 'galt', 'gamt', 'gbgt', 'gft', 'ghst', 'gilt', 'gmt', 'gst', 'gyt', 'hdt', 'hkst', 'hkt', 'hmt', 'hovst', 'hovt', 'hst', 'ict', 'iddt', 'idt', 'ihst', 'imt', 'iot', 'irdt', 'irst', 'isst', 'ist', 'javt', 'jcst', 'jdt', 'jmt', 'jst', 'jwst', 'kart', 'kdt', 'kmt', 'kost', 'kst', 'kwat', 'lhdt', 'lhst', 'lint', 'lkt', 'lrt', 'lst', 'madmt', 'madst', 'madt', 'malst', 'malt', 'mart', 'mddt', 'mdst', 'mdt', 'mest', 'met', 'mht', 'mist', 'mmt', 'most', 'mot', 'mpt', 'msd', 'msk', 'mst', 'must', 'mut', 'mvt', 'mwt', 'myt', 'ncst', 'nct', 'nddt', 'ndt', 'negt', 'nest', 'net', 'nfst', 'nft', 'nmt', 'npt', 'nrt', 'nst', 'nut', 'nwt', 'nzdt', 'nzmt', 'nzst', 'pddt', 'pdt', 'pest', 'pet', 'pgt', 'phot', 'phst', 'pht', 'pkst', 'pkt', 'plmt', 'pmdt', 'pmmt', 'pmst', 'pmt', 'pnt', 'pont', 'ppmt', 'ppt', 'pst', 'pwt', 'pyst', 'pyt', 'qmt', 'ret', 'rmt', 'sast', 'sbt', 'sct', 'sdmt', 'sdt', 'set', 'sgt', 'sjmt', 'smt', 'srt', 'sst', 'swat', 'taht', 'tbmt', 'tkt', 'tlt', 'tmt', 'tost', 'tot', 'tvt', 'uct', 'ulast', 'ulat', 'utc', 'uyhst', 'uyst', 'uyt', 'vet', 'vust', 'vut', 'wakt', 'warst', 'wart', 'wast', 'wat', 'wemt', 'west', 'wet', 'wft', 'wgst', 'wgt', 'wib', 'wita', 'wit', 'wmt', 'wsdt', 'wsst', 'xjt', 'yddt', 'ydt', 'ypt', 'yst', 'ywt', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' ]; /** * Set the global variables related to date format. * * @private */ function setFormats() { const langCode = mw.config.get('wgContentLanguage'); cd.g.DATE_FORMAT = DATE_FORMATS[langCode]; cd.g.DIGITS = mw.config.get('wgTranslateNumerals') ? DIGITS[langCode] : null; } /** * Load messages needed to parse and generate timestamps, as well as some site data. * * @returns {Promise} */ export function loadData() { const requests = []; mw.messages.set(cd.config.messages); cd.g.CONTRIBS_PAGE = cd.config.contribsPage; cd.g.LOCAL_TIMEZONE_OFFSET = cd.config.localTimezoneOffset; const messageNames = [ 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec', 'january', 'february', 'march', 'april', 'may_long', 'june', 'july', 'august', 'september', 'october', 'november', 'december', 'january-gen', 'february-gen', 'march-gen', 'april-gen', 'may-gen', 'june-gen', 'july-gen', 'august-gen', 'september-gen', 'october-gen', 'november-gen', 'december-gen', 'parentheses', 'parentheses-start', 'parentheses-end', 'word-separator', 'comma-separator', 'colon-separator', 'dot-separator', 'nextdiff', ]; cd.g.api = cd.g.api || new mw.Api(); // I hope we won't be scolded too much for making two message requests in parallel. const messagesRequests = []; for (let i = 0; i < messageNames.length; i += 50) { const nextNames = messageNames.slice(i, i + 50); const request = cd.g.api.loadMessagesIfMissing(nextNames, { amlang: mw.config.get('wgContentLanguage'), }); messagesRequests.push(request); } if (!Object.keys(cd.config.messages).some((name) => name.startsWith('timezone-'))) { const request = cd.g.api.loadMessages(undefined, { amlang: mw.config.get('wgContentLanguage'), amincludelocal: 1, amfilter: 'timezone-', }); messagesRequests.push(request); } Promise.all(messagesRequests).then(() => { cd.g.messages = {}; // We need this object to pass to the web worker. messageNames.push( ...Object.keys(mw.messages.get()).filter((name) => name.startsWith('timezone-')) ); messageNames.forEach((name) => { cd.g.messages[name] = mw.messages.get(name); }); }); requests.push(...messagesRequests); if (!cd.g.CONTRIBS_PAGE || cd.g.LOCAL_TIMEZONE_OFFSET === null) { const request = cd.g.api.get({ action: 'query', meta: 'siteinfo', siprop: ['specialpagealiases', 'general'], }).then((resp) => { resp.query.specialpagealiases.some((alias) => { if (alias.realname === 'Contributions') { cd.g.CONTRIBS_PAGE = mw.config.get('wgFormattedNamespaces')[-1] + ':' + alias.aliases[0]; return true; } }); // TODO: Implement DST offsets cd.g.LOCAL_TIMEZONE_OFFSET = resp.query.general.timeoffset; }); requests.push(request); } return Promise.all(requests); } /** * Get a regexp that matches timestamps (without timezone at the end) generated using the given date * format. * * This only supports format characters that are used by the default date format in any of * MediaWiki's languages, namely: D, d, F, G, H, i, j, l, M, n, Y, xg, xkY (and escape characters), * and only dates when MediaWiki existed, let's say 2000 onwards (Thai dates before 1941 are * complicated). * * @param {string} format Date format, as used by MediaWiki. * @param {string} digits Regular expression matching a single localized digit, e.g. `[0-9]`. * @returns {string} Pattern to be a part of a regular expression. * @private */ function getTimestampMainPartPattern(format, digits) { const regexpGroup = (regexp) => '(' + regexp + ')'; const regexpAlternateGroup = (arr) => '(' + arr.map(mw.util.escapeRegExp).join('|') + ')'; let s = '\\b'; for (let p = 0; p < format.length; p++) { let num = false; let code = format[p]; if (code === 'x' && p < format.length - 1) { code += format[++p]; } if (code === 'xk' && p < format.length - 1) { code += format[++p]; } switch (code) { case 'xx': s += 'x'; break; case 'xg': s += regexpAlternateGroup(getMessages([ 'january-gen', 'february-gen', 'march-gen', 'april-gen', 'may-gen', 'june-gen', 'july-gen', 'august-gen', 'september-gen', 'october-gen', 'november-gen', 'december-gen' ])); break; case 'd': num = '2'; break; case 'D': s += regexpAlternateGroup(getMessages(['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'])); break; case 'j': num = '1,2'; break; case 'l': s += regexpAlternateGroup(getMessages([ 'sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday' ])); break; case 'F': s += regexpAlternateGroup(getMessages([ 'january', 'february', 'march', 'april', 'may_long', 'june', 'july', 'august', 'september', 'october', 'november', 'december' ])); break; case 'M': s += regexpAlternateGroup(getMessages([ 'jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec' ])); break; case 'n': num = '1,2'; break; case 'Y': num = '4'; break; case 'xkY': num = '4'; break; case 'G': num = '1,2'; break; case 'H': num = '2'; break; case 'i': num = '2'; break; case '\\': // Backslash escaping if (p < format.length - 1) { s += format[++p]; } else { s += '\\'; } break; case '"': // Quoted literal if (p < format.length - 1) { const endQuote = format.indexOf('"', p + 1) if (endQuote === -1) { // No terminating quote, assume literal " s += '"'; } else { s += format.substr(p + 1, endQuote - p - 1); p = endQuote; } } else { // Quote at end of string, assume literal " s += '"'; } break; default: s += format[p]; } if (num !== false) { s += regexpGroup(digits + '{' + num + '}'); } } return s; } /** * Create and set the regexp that matches timestamps in the local date format. * * This calls `getTimestampMainPartPattern()` with data for the current wiki. * * @private */ function setLocalTimestampRegexps() { const mainPartPattern = getTimestampMainPartPattern( cd.g.DATE_FORMAT, cd.g.DIGITS ? `[${cd.g.DIGITS}]` : '\\d' ); const timezones = Object.keys(cd.g.messages) .filter((name) => name.startsWith('timezone-')) .map((name) => name.slice(9)) .filter((name) => !['local', 'useoffset-placeholder'].includes(name)); const localizedTimezones = TIMEZONES.concat(timezones).map((abbr) => { const message = mw.message('timezone-' + abbr); return message.exists() ? message.parse() : abbr; }); const timezonePattern = ( '\\((?:' + localizedTimezones.map(mw.util.escapeRegExp).join('|').toUpperCase() + ')\\)' ); const pattern = mainPartPattern + ' ' + timezonePattern; /** * Regular expression for matching timestamps. * * @name TIMESTAMP_REGEXP * @type {RegExp} * @memberof module:cd~convenientDiscussions.g */ cd.g.TIMESTAMP_REGEXP = new RegExp(pattern); /** * Regular expression for matching timestamps with no timezone at the end. * * @name TIMESTAMP_REGEXP_NO_TIMEZONE * @type {RegExp} * @memberof module:cd~convenientDiscussions.g */ cd.g.TIMESTAMP_REGEXP_NO_TIMEZONE = new RegExp(mainPartPattern); /** * Regular expression for matching timezone, with a global flag. * * @name TIMEZONE_REGEXP * @type {RegExp} * @memberof module:cd~convenientDiscussions.g */ cd.g.TIMEZONE_REGEXP = new RegExp(timezonePattern, 'g'); } /** * Create and set the function that parses timestamps in the local date format, based on the result * of matching the regexp set by `setLocalTimestampRegexps()`. * * @private */ function setLocalTimestampParser() { const format = cd.g.DATE_FORMAT; const matchingGroups = []; for (let p = 0; p < format.length; p++) { let code = format[p]; if (code === 'x' && p < format.length - 1) { code += format[++p]; } if (code === 'xk' && p < format.length - 1) { code += format[++p]; } switch (code) { case 'xx': break; case 'xg': case 'd': case 'j': case 'D': case 'l': case 'F': case 'M': case 'n': case 'Y': case 'xkY': case 'G': case 'H': case 'i': matchingGroups.push(code); break; case '\\': // Backslash escaping if (p < format.length - 1) { ++p; } break; case '"': // Quoted literal if (p < format.length - 1) { const endQuote = format.indexOf('"', p + 1) if (endQuote !== -1) { p = endQuote; } } break; default: break; } } // We can't use the variables from the scope of the current function and have to accept the global // object as a parameter because we need to use the function in a web worker which can receive // functions only as strings, forgetting their scope. /** * Timestamp parser. * * @name TIMESTAMP_PARSER * @param {Array} match Regexp match data. * @param {object} cd `convenientDiscussions` (in the window context) / `cd` (in the worker * context) global object. * @param {number} [timezoneOffset] User's timezone, if it should be used instead of the wiki's * timezone. * @returns {Date} * @memberof module:cd~convenientDiscussions.g */ cd.g.TIMESTAMP_PARSER = (match, cd, timezoneOffset) => { const untransformDigits = (text) => { if (!cd.g.DIGITS) { return text; } return text.replace(new RegExp('[' + cd.g.DIGITS + ']', 'g'), (m) => cd.g.DIGITS.indexOf(m)); }; // Override the imported function to be able to use it in the worker context. const getMessages = (messages) => messages.map((name) => cd.g.messages[name]); let year = 0; let monthIdx = 0; let day = 0; let hour = 0; let minute = 0; for (let i = 0; i < cd.g.TIMESTAMP_MATCHING_GROUPS.length; i++) { const code = cd.g.TIMESTAMP_MATCHING_GROUPS[i]; const text = match[i + 3]; switch (code) { case 'xg': monthIdx = getMessages([ 'january-gen', 'february-gen', 'march-gen', 'april-gen', 'may-gen', 'june-gen', 'july-gen', 'august-gen', 'september-gen', 'october-gen', 'november-gen', 'december-gen' ]).indexOf(text); break; case 'd': case 'j': day = Number(untransformDigits(text)); break; case 'D': case 'l': // Day of the week - unused break; case 'F': monthIdx = getMessages([ 'january', 'february', 'march', 'april', 'may_long', 'june', 'july', 'august', 'september', 'october', 'november', 'december' ]).indexOf(text); break; case 'M': monthIdx = getMessages([ 'jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec' ]).indexOf(text); break; case 'n': monthIdx = Number(untransformDigits(text)) - 1; break; case 'Y': year = Number(untransformDigits(text)); break; case 'xkY': // Thai year year = Number(untransformDigits(text)) - 543; break; case 'G': case 'H': hour = Number(untransformDigits(text)); break; case 'i': minute = Number(untransformDigits(text)); break; default: throw 'Not implemented'; } } if (timezoneOffset === undefined) { timezoneOffset = cd.g.LOCAL_TIMEZONE_OFFSET; } return new Date( Date.UTC(year, monthIdx, day, hour, minute) - timezoneOffset * cd.g.MILLISECONDS_IN_A_MINUTE ); }; /** * Codes of date components for the parser function. * * @name TIMESTAMP_MATCHING_GROUPS * @type {string[]} * @memberof module:cd~convenientDiscussions.g */ cd.g.TIMESTAMP_MATCHING_GROUPS = matchingGroups; } /** * Set the global variables related to timestamp parsing. */ export function initTimestampParsingTools() { setFormats(); setLocalTimestampRegexps(); setLocalTimestampParser(); } "
"/** * Initialization, page loading, reloading, and session-related functions. * * @module boot */ import { create as nanoCssCreate } from 'nano-css'; import CdError from './CdError'; import Comment from './Comment'; import CommentForm from './CommentForm'; import Page from './Page'; import Section from './Section'; import Worker from './worker-gate'; import cd from './cd'; import jqueryExtensions from './jqueryExtensions'; import navPanel from './navPanel'; import processPage from './processPage'; import toc from './toc'; import updateChecker from './updateChecker'; import { areObjectsEqual, caseInsensitiveFirstCharPattern, firstCharToUpperCase, getFromLocalStorage, hideText, mergeRegexps, restoreScrollPosition, saveScrollPosition, saveToLocalStorage, transparentize, unhideText, } from './util'; import { createWindowManager, rescueCommentFormsContent } from './modal'; import { getLocalOverridingSettings, getSettings, setSettings } from './options'; import { getUserInfo } from './apiWrappers'; import { initTimestampParsingTools, loadData } from './siteData'; let notificationsData = []; let isPageBeingReloaded = false; let saveSessionTimeout; let saveSessionLastTime; /** * Initiate user settings. */ export async function initSettings() { /** * Script settings of the current user. * * @name settings * @type {object} * @memberof module:cd~convenientDiscussions */ cd.settings = cd.settings || {}; // We fill the settings after the modules are loaded so that the settings set via common.js had // less chance not to load. /** * Default settings. * * @name defaultSetings * @type {object} * @memberof module:cd~convenientDiscussions */ cd.defaultSettings = { allowEditOthersComments: false, alwaysExpandAdvanced: false, // If the user has never changed the insert buttons configuration, it should change with the // default configuration change. haveInsertButtonsBeenAltered: false, // The order should coincide with the order of checkboxes in // `SettingsDialog#autocompleteTypesMultiselect` in modal.js (otherwise the "Save" and "Reset" // buttons in the settings dialog won't work properly. autocompleteTypes: ['mentions', 'commentLinks', 'wikilinks', 'templates', 'tags'], autopreview: true, desktopNotifications: 'unknown', // Not shown in the settings dialog. TODO: delete if proves unnecessary. defaultCommentLinkType: 'diff', defaultSectionLinkType: 'wikilink', highlightOwnComments: true, insertButtons: cd.config.defaultInsertButtons || [], notifications: 'all', notificationsBlacklist: [], // Not shown in the settings dialog showLoadingOverlay: true, showToolbar: true, signaturePrefix: cd.config.defaultSignaturePrefix, modifyToc: true, useTemplateData: true, watchOnReply: true, watchSectionOnReply: true, }; cd.localSettingNames = ['haveInsertButtonsBeenAltered', 'insertButtons', 'signaturePrefix']; const options = { [cd.g.SETTINGS_OPTION_NAME]: mw.user.options.get(cd.g.SETTINGS_OPTION_NAME), [cd.g.LOCAL_SETTINGS_OPTION_NAME]: mw.user.options.get(cd.g.LOCAL_SETTINGS_OPTION_NAME), } // Aliases for seamless transition when changing a setting name. cd.settingAliases = { allowEditOthersComments: ['allowEditOthersMsgs'], alwaysExpandAdvanced: ['alwaysExpandSettings'], haveInsertButtonsBeenAltered: ['areInsertButtonsAltered', 'insertButtonsChanged'], desktopNotifications: ['browserNotifications'], signaturePrefix: ['mySig', 'mySignature'], }; // Settings in variables like "cdAlowEditOthersComments" used before server-stored settings // were implemented. Object.keys(cd.defaultSettings).forEach((name) => { (cd.settingAliases[name] || []).concat(name).forEach((alias) => { const varAlias = 'cd' + firstCharToUpperCase(alias); if (varAlias in window && typeof window[varAlias] === typeof cd.defaultSettings[name]) { cd.settings[name] = window[varAlias]; } }); }); const remoteSettings = await getSettings({ options, omitLocal: true, }); cd.settings = Object.assign(cd.settings, remoteSettings); // Seamless transition from mySignature. if (cd.settings.signaturePrefix !== undefined) { // eslint-disable-next-line no-useless-escape cd.settings.signaturePrefix = cd.settings.signaturePrefix.replace('~~\~~', ''); } if ( !cd.settings.haveInsertButtonsBeenAltered && JSON.stringify(cd.settings.insertButtons) !== JSON.stringify(cd.config.defaultInsertButtons) ) { cd.settings.insertButtons = cd.config.defaultInsertButtons; } cd.settings = Object.assign({}, cd.defaultSettings, cd.settings); if (!areObjectsEqual(cd.settings, remoteSettings)) { setSettings().catch((e) => { console.warn('Couldn\'t save the settings to the server.', e); }); } // Settings in variables like "cdLocal..." override all other and are not saved to the server. Object.assign(cd.settings, getLocalOverridingSettings()); } /** * Set CSS for talk pages. * * @private */ export function initTalkPageCss() { cd.g.nanoCss = nanoCssCreate(); cd.g.nanoCss.put(':root', { '--cd-comment-focused-color': cd.g.COMMENT_FOCUSED_COLOR, '--cd-comment-target-color': cd.g.COMMENT_TARGET_COLOR, '--cd-comment-new-color': cd.g.COMMENT_NEW_COLOR, '--cd-comment-own-color': cd.g.COMMENT_OWN_COLOR, '--cd-comment-deleted-color': cd.g.COMMENT_DELETED_COLOR, }); // Set the transparent color for the "focused" color. The user may override the CSS variable value // in their personal styles, so we get the existing value first. const focusedColor = $(document.documentElement).css('--cd-comment-focused-color'); cd.g.nanoCss.put(':root', { '--cd-comment-focused-transparent-color': transparentize(focusedColor), }); cd.g.nanoCss.put('.ltr .cd-commentOverlay-gradient', { backgroundImage: 'linear-gradient(to left, var(--cd-comment-focused-color), var(--cd-comment-focused-transparent-color))', }); cd.g.nanoCss.put('.rtl .cd-commentOverlay-gradient', { backgroundImage: 'linear-gradient(to right, var(--cd-comment-focused-color), var(--cd-comment-focused-transparent-color))', }); // Vector, Monobook, Minerva const contentBackgroundColor = $('#content').css('background-color') || '#fff'; cd.g.nanoCss.put('.cd-messageArea .cd-closeButton', { backgroundColor: contentBackgroundColor, }); const sidebarColor = $('.skin-timeless').length ? '#eaecf0' : $(document.body) // New Vector .add('.mw-page-container') .last() .css('background-color'); cd.g.nanoCss.put('#cd-currentSection', { backgroundColor: transparentize(sidebarColor).replace('0)', '0.8)'), width: ($('.mw-body').get(0)?.getBoundingClientRect().left - 18) + 'px', }); cd.g.nanoCss.put('#cd-currentSection:hover', { backgroundColor: sidebarColor, }); } /** * Initialize a number of the global object properties. */ function initGlobals() { cd.g.PHP_CHAR_TO_UPPER_JSON = mw.loader.moduleRegistry['mediawiki.Title'].script .files["phpCharToUpper.json"]; cd.g.CURRENT_PAGE = new Page(cd.g.CURRENT_PAGE_NAME); cd.g.CURRENT_USER_GENDER = mw.user.options.get('gender'); // {{gender:}} with at least two pipes in a selection of the affected strings. cd.g.GENDER_AFFECTS_USER_STRING = /\{\{ *gender *:[^}]+?\|[^}]+?\|/i .test(cd.sPlain('es-reply-to') + cd.sPlain('es-edit-comment-by') + cd.sPlain('thank-confirm')); cd.g.QQX_MODE = mw.util.getParamValue('uselang') === 'qqx'; if (cd.config.tagName) { cd.g.SUMMARY_POSTFIX = ''; cd.g.SUMMARY_LENGTH_LIMIT = mw.config.get('wgCommentCodePointLimit'); } else { cd.g.SUMMARY_POSTFIX = ` ([[${cd.config.scriptPageWikilink}|${cd.s('script-name-short')}]])`; cd.g.SUMMARY_LENGTH_LIMIT = ( mw.config.get('wgCommentCodePointLimit') - cd.g.SUMMARY_POSTFIX.length ); } cd.g.IS_IPv6_ADDRESS = mw.util.isIPv6Address; cd.g.NOTIFICATION_AREA = document.querySelector('.mw-notification-area'); cd.g.dontHandleScroll = false; cd.g.autoScrollInProgress = false; cd.g.activeAutocompleteMenu = null; cd.g.hasPageBeenReloaded = false; // Useful for testing cd.g.processPageInBackground = updateChecker.processPage; /* Some static methods for external use */ /** * @see module:Comment.getByAnchor * @function getCommentByAnchor * @memberof module:cd~convenientDiscussions */ cd.getCommentByAnchor = Comment.getByAnchor; /** * @see module:Section.getByAnchor * @function getSectionByAnchor * @memberof module:cd~convenientDiscussions */ cd.getSectionByAnchor = Section.getByAnchor; /** * @see module:Section.getByHeadline * @function getSectionsByHeadline * @memberof module:cd~convenientDiscussions */ cd.getSectionsByHeadline = Section.getByHeadline; /** * @see module:CommentForm.getLastActive * @function getLastActiveCommentForm * @memberof module:cd~convenientDiscussions */ cd.getLastActiveCommentForm = CommentForm.getLastActive; /** * @see module:CommentForm.getLastActiveAltered * @function getLastActiveAlteredCommentForm * @memberof module:cd~convenientDiscussions */ cd.getLastActiveAlteredCommentForm = CommentForm.getLastActiveAltered; } /** * Generate regexps, patterns (strings to be parts of regexps), selectors from config values. * * @private */ function initPatterns() { cd.g.CONTRIBS_PAGE_LINK_REGEXP = new RegExp(`^${cd.g.CONTRIBS_PAGE}/`); const anySpace = (s) => s.replace(/[ _]/g, '[ _]+').replace(/:/g, '[ _]*:[ _]*'); const namespaceIds = mw.config.get('wgNamespaceIds'); const userNamespaces = Object.keys(namespaceIds) .filter((key) => [2, 3].includes(namespaceIds[key])); const userNamespacesPattern = userNamespaces.map(anySpace).join('|'); cd.g.USER_NAMESPACES_REGEXP = new RegExp(`(?:^|:)(?:${userNamespacesPattern}):(.+)`, 'i'); const allNamespaces = Object.keys(namespaceIds); const allNamespacesPattern = allNamespaces.join('|'); cd.g.ALL_NAMESPACES_REGEXP = new RegExp(`(?:^|:)(?:${allNamespacesPattern}):`, 'i'); const contribsPagePattern = anySpace(cd.g.CONTRIBS_PAGE); cd.g.CAPTURE_USER_NAME_PATTERN = ( `\\[\\[[ _]*:?(?:\\w*:){0,2}(?:(?:${userNamespacesPattern})[ _]*:[ _]*|` + `(?:Special[ _]*:[ _]*Contributions|${contribsPagePattern})\\/[ _]*)([^|\\]/]+)(/)?` ); const userNamespaceAliases = Object.keys(namespaceIds).filter((key) => namespaceIds[key] === 2); const userNamespaceAliasesPattern = userNamespaceAliases.map(anySpace).join('|'); cd.g.USER_NAMESPACE_ALIASES_REGEXP = new RegExp( `^:?(?:${userNamespaceAliasesPattern}):([^/]+)$`, 'i' ); if (cd.config.unsignedTemplates.length) { const unsignedTemplatesPattern = cd.config.unsignedTemplates.join('|'); cd.g.UNSIGNED_TEMPLATES_PATTERN = ( `(\\{\\{ *(?:${unsignedTemplatesPattern}) *\\| *([^}|]+?) *(?:\\| *([^}]+?) *)?\\}\\})` ); cd.g.UNSIGNED_TEMPLATES_REGEXP = new RegExp(cd.g.UNSIGNED_TEMPLATES_PATTERN + '.*\\n', 'ig'); } cd.g.CURRENT_USER_SIGNATURE = cd.settings.signaturePrefix + cd.g.SIGN_CODE; const signatureContent = mw.user.options.get('nickname'); const authorInSignatureMatch = signatureContent.match( new RegExp(cd.g.CAPTURE_USER_NAME_PATTERN, 'i') ); if (authorInSignatureMatch) { // Extract signature contents before the user name - in order to cut it out from comment endings // when editing. const signaturePrefixPattern = mw.util.escapeRegExp(cd.settings.signaturePrefix); const signatureBeginning = mw.util.escapeRegExp( signatureContent.slice(0, authorInSignatureMatch.index) ); cd.g.CURRENT_USER_SIGNATURE_PREFIX_REGEXP = new RegExp( signaturePrefixPattern + signatureBeginning + '$' ); } const pieJoined = cd.g.POPULAR_INLINE_ELEMENTS.join('|'); cd.g.PIE_PATTERN = `(?:${pieJoined})`; const pnieJoined = cd.g.POPULAR_NOT_INLINE_ELEMENTS.join('|'); cd.g.PNIE_PATTERN = `(?:${pnieJoined})`; const commentAntipatternsPatternParts = []; if ( cd.config.elementsToExcludeClasses.length || cd.config.templatesToExclude.length || cd.config.commentAntipatterns.length ) { if (cd.config.elementsToExcludeClasses) { const elementsToExcludeClassesPattern = cd.config.elementsToExcludeClasses.join('\\b|\\b'); commentAntipatternsPatternParts.push( `class=(['"])[^'"\\n]*(?:\\b${elementsToExcludeClassesPattern}\\b)[^'"\\n]*\\1` ); } if (cd.config.templatesToExclude.length) { const templatesToExcludePattern = cd.config.templatesToExclude .map(caseInsensitiveFirstCharPattern) .join('|'); commentAntipatternsPatternParts.push( `\\{\\{ *(?:${templatesToExcludePattern}) *(?:\\||\\}\\})` ); } if (cd.config.commentAntipatterns) { commentAntipatternsPatternParts.push( ...cd.config.commentAntipatterns.map((pattern) => pattern.source) ); } const commentAntipatternPattern = commentAntipatternsPatternParts.join('|'); cd.g.COMMENT_ANTIPATTERNS_REGEXP = new RegExp(`^.*(?:${commentAntipatternPattern}).*$`, 'mg'); } cd.g.ARTICLE_PATH_REGEXP = new RegExp( mw.util.escapeRegExp(mw.config.get('wgArticlePath')).replace('\\$1', '(.*)') ); const quoteTemplateToPattern = (tpl) => '\\{\\{ *' + anySpace(mw.util.escapeRegExp(tpl)); const quoteBeginningsPattern = ['<blockquote>', '<q>'] .concat(cd.config.pairQuoteTemplates?.[0].map(quoteTemplateToPattern) || []) .join('|'); const quoteEndingsPattern = ['</blockquote>', '</q>'] .concat(cd.config.pairQuoteTemplates?.[1].map(quoteTemplateToPattern) || []) .join('|'); cd.g.QUOTE_REGEXP = new RegExp( `(${quoteBeginningsPattern})([^]*?)(${quoteEndingsPattern})`, 'ig' ); const closedDiscussionBeginningsPattern = (cd.config.closedDiscussionTemplates?.[0] || []) .map(mw.util.escapeRegExp) .map(anySpace) .join('|'); const closedDiscussionEndingsPattern = (cd.config.closedDiscussionTemplates?.[1] || []) .map(mw.util.escapeRegExp) .map(anySpace) .join('|'); if (closedDiscussionBeginningsPattern) { if (closedDiscussionEndingsPattern) { cd.g.CLOSED_DISCUSSION_PAIR_REGEXP = new RegExp( `\\{\\{ *(?:${closedDiscussionBeginningsPattern})[^]*?\\}\\}\\s*([:*#]*)[^]*?\\{\\{ *(?:${closedDiscussionEndingsPattern})[^}]*\\}\\}`, 'ig' ); } cd.g.CLOSED_DISCUSSION_SINGLE_REGEXP = new RegExp( `\\{\\{ *(?:${closedDiscussionBeginningsPattern}) *\\|[^}]{0,50}?=\\s*([:*#]*)`, 'ig' ); } cd.g.UNHIGHLIGHTABLE_ELEMENT_CLASSES = cd.g.UNHIGHLIGHTABLE_ELEMENT_CLASSES .concat(cd.config.customUnhighlightableElementClasses); const fileNamespaces = Object.keys(namespaceIds).filter((key) => 6 === namespaceIds[key]); const fileNamespacesPattern = fileNamespaces.map(anySpace).join('|'); cd.g.FILE_PREFIX_PATTERN = `(?:${fileNamespacesPattern}):`; // Actually, only text from "mini" format images should be captured, as in the standard format, // the text is not displayed. See "img_thumbnail" in // https://ru.wikipedia.org/w/api.php?action=query&meta=siteinfo&siprop=magicwords&formatversion=2. // Unfortunately, that would add like 100ms to the server's response time. cd.g.FILE_LINK_REGEXP = new RegExp( `\\[\\[${cd.g.FILE_PREFIX_PATTERN}[^]+?(?:\\|[^]+?\\|((?:\\[\\[[^]+?\\]\\]|[^|])+?))?\\]\\]`, 'ig' ); const colonNamespaces = Object.keys(namespaceIds) .filter((key) => [6, 14].includes(namespaceIds[key])); const colonNamespacesPattern = colonNamespaces.map(anySpace).join('|'); cd.g.COLON_NAMESPACES_PREFIX_REGEXP = new RegExp(`^:(?:${colonNamespacesPattern}):`, 'i'); cd.g.BAD_COMMENT_BEGINNINGS = cd.g.BAD_COMMENT_BEGINNINGS .concat(new RegExp(`^\\[\\[${cd.g.FILE_PREFIX_PATTERN}.+\\n*(?=[*:#])`)) .concat(cd.config.customBadCommentBeginnings); cd.g.ADD_TOPIC_SELECTORS = [ '#ca-addsection a', '.commentbox input[type="submit"]', '.createbox input[type="submit"]', ] .concat(cd.config.customAddTopicLinkSelectors) .join(', '); cd.g.PAGES_WITHOUT_ARCHIVES_REGEXP = mergeRegexps(cd.config.pagesWithoutArchives); cd.g.ARCHIVE_PAGES_MAP = new Map(); cd.g.SOURCE_PAGES_MAP = new Map(); const pathToRegexp = (s, replacements, isArchivePath) => { let hidden = []; let pattern = hideText(s, /\\[$\\]/g, hidden); pattern = mw.util.escapeRegExp(pattern); if (replacements) { pattern = pattern .replace(/\\\$/, '$') .replace(/\$(\d+)/, (s, n) => { const replacement = replacements[n - 1]; return replacement ? `(${replacement.source})` : s; }); } pattern = '^' + pattern + (isArchivePath ? '.*' : '') + '$'; pattern = unhideText(pattern, hidden); return new RegExp(pattern); }; cd.config.archivePaths.forEach((entry) => { if (entry instanceof RegExp) { let archiveRegexp = new RegExp(entry.source + '.*'); cd.g.SOURCE_PAGES_MAP.set(archiveRegexp, ''); } else { const sourceRegexp = pathToRegexp(entry.source, entry.replacements); const archiveRegexp = pathToRegexp(entry.archive, entry.replacements, true); cd.g.ARCHIVE_PAGES_MAP.set(sourceRegexp, entry.archive); cd.g.SOURCE_PAGES_MAP.set(archiveRegexp, entry.source); } }); } /** * Initialize OOUI and comment layers-related objects. * * @private */ function initOouiAndElementPrototypes() { createWindowManager(); // OOUI button prototypes. Creating every button using the constructor takes 15 times longer than // cloning which is critical when creating really many of them. cd.g.COMMENT_ELEMENT_PROTOTYPES = {}; cd.g.COMMENT_ELEMENT_PROTOTYPES.goToParentButton = new OO.ui.ButtonWidget({ label: cd.s('cm-gotoparent'), icon: 'upTriangle', title: cd.s('cm-gotoparent-tooltip'), framed: false, invisibleLabel: true, classes: ['cd-button', 'cd-commentButton', 'cd-commentButton-icon'], }).$element.get(0); cd.g.COMMENT_ELEMENT_PROTOTYPES.linkButton = new OO.ui.ButtonWidget({ label: cd.s('cm-copylink'), icon: 'link', title: cd.s('cm-copylink-tooltip'), framed: false, invisibleLabel: true, classes: ['cd-button', 'cd-commentButton', 'cd-commentButton-icon'], }).$element.get(0); cd.g.COMMENT_ELEMENT_PROTOTYPES.pendingLinkButton = new OO.ui.ButtonWidget({ label: cd.s('cm-copylink'), icon: 'link', title: cd.s('cm-copylink-tooltip'), framed: false, disabled: true, invisibleLabel: true, classes: ['cd-button', 'cd-commentButton', 'cd-commentButton-icon', 'cd-button-pending'], }).$element.get(0); cd.g.COMMENT_ELEMENT_PROTOTYPES.thankButton = new OO.ui.ButtonWidget({ label: cd.s('cm-thank'), title: cd.s('cm-thank-tooltip'), framed: false, classes: ['cd-button', 'cd-commentButton'], }).$element.get(0); cd.g.COMMENT_ELEMENT_PROTOTYPES.pendingThankButton = new OO.ui.ButtonWidget({ label: cd.s('cm-thank'), title: cd.s('cm-thank-tooltip'), framed: false, disabled: true, classes: ['cd-button', 'cd-commentButton', 'cd-button-pending'], }).$element.get(0); cd.g.COMMENT_ELEMENT_PROTOTYPES.thankedButton = new OO.ui.ButtonWidget({ label: cd.s('cm-thanked'), title: cd.s('cm-thanked-tooltip'), framed: false, disabled: true, classes: ['cd-button', 'cd-commentButton'], }).$element.get(0); cd.g.COMMENT_ELEMENT_PROTOTYPES.editButton = new OO.ui.ButtonWidget({ label: cd.s('cm-edit'), framed: false, classes: ['cd-button', 'cd-commentButton'], }).$element.get(0); cd.g.COMMENT_ELEMENT_PROTOTYPES.replyButton = new OO.ui.ButtonWidget({ label: cd.s('cm-reply'), framed: false, classes: ['cd-button', 'cd-commentButton'], }).$element.get(0); cd.g.COMMENT_ELEMENT_PROTOTYPES.underlay = document.createElement('div'); cd.g.COMMENT_ELEMENT_PROTOTYPES.underlay.className = 'cd-commentUnderlay'; cd.g.COMMENT_ELEMENT_PROTOTYPES.overlay = document.createElement('div'); cd.g.COMMENT_ELEMENT_PROTOTYPES.overlay.className = 'cd-commentOverlay'; const overlayInnerWrapper = document.createElement('div'); overlayInnerWrapper.className = 'cd-commentOverlay-innerWrapper'; cd.g.COMMENT_ELEMENT_PROTOTYPES.overlay.appendChild(overlayInnerWrapper); const overlayGradient = document.createElement('div'); overlayGradient.textContent = '\u00A0'; overlayGradient.className = 'cd-commentOverlay-gradient'; overlayInnerWrapper.appendChild(overlayGradient); const overlayContent = document.createElement('div'); overlayContent.className = 'cd-commentOverlay-content'; overlayInnerWrapper.appendChild(overlayContent); cd.g.SECTION_ELEMENT_PROTOTYPES = {}; cd.g.SECTION_ELEMENT_PROTOTYPES.replyButton = new OO.ui.ButtonWidget({ label: cd.s('section-reply'), framed: false, classes: ['cd-button', 'cd-sectionButton'], }).$element.get(0); cd.g.SECTION_ELEMENT_PROTOTYPES.addSubsectionButton = new OO.ui.ButtonWidget({ // Will be replaced label: ' ', framed: false, classes: ['cd-button', 'cd-sectionButton'], }).$element.get(0); } /** * Create various global objects' (`convenientDiscussions`, `$`) properties and methods. Executed at * the first run. * * @param {object} [data] Data passed from the main module. * @param {Promise} [data.messagesRequest] Promise returned by {@link module:siteData.loadData}. */ export async function init({ messagesRequest }) { cd.g.api = cd.g.api || new mw.Api(); cd.g.worker = new Worker(); await (messagesRequest || loadData()); initGlobals(); await initSettings(); initTimestampParsingTools(); /** * Collection of all comment forms on the page in the order of their creation. * * @name commentForms * @type {CommentForm[]} * @memberof module:cd~convenientDiscussions */ cd.commentForms = []; initPatterns(); initOouiAndElementPrototypes(); $.fn.extend(jqueryExtensions); } /** * Get anchors of unseen comments. This is used to arrange that they will still be there after * replying on or refreshing the page. * * @returns {string[]} * @private */ function getUnseenCommentAnchors() { return cd.comments .filter((comment) => comment.isSeen === false) .map((comment) => comment.anchor); } /** * Replace the inner HTML of the content element and run the parse routine. * * @param {string} html * @param {object} keptData * @private */ async function updatePageContent(html, keptData) { cd.debug.stopTimer('getting HTML'); cd.debug.startTimer('laying out HTML'); cd.g.$content.children('.mw-parser-output').remove(); if (keptData.wasPageCreated) { cd.g.$content.empty(); } cd.g.$content.append(html); keptData = Object.assign({}, keptData, { unseenCommentAnchors: getUnseenCommentAnchors() }); // We could say "let it crash", but, well, unforeseen errors in processPage() are just too likely // to go without a safeguard. try { await processPage(keptData); } catch (e) { mw.notify(cd.s('error-processpage'), { type: 'error' }); console.error(e); removeLoadingOverlay(); } mw.hook('wikipage.content').fire(cd.g.$content); } let $loadingPopup; /** * Check if the "showLoadingOverlay" setting is off. We create a separate function for this because * this check has to be performed before the settings object is filled. * * @returns {boolean} * @private */ function isShowLoadingOverlaySettingOff() { return ( (cd.settings && cd.settings.showLoadingOverlay === false) || ( !cd.settings && window.cdShowLoadingOverlay !== undefined && window.cdShowLoadingOverlay === false ) ); } /** * Set the loading overlay. */ export function setLoadingOverlay() { if (isShowLoadingOverlaySettingOff()) return; if (!$loadingPopup) { $loadingPopup = $('<div>').addClass('cd-loadingPopup'); const $logoContainer = $('<div>') .addClass('cd-loadingPopup-logo') .appendTo($loadingPopup); $('<div>') .addClass('cd-loadingPopup-logo-partBackground') .css('background-color', $(document.body).css('background-color')) .appendTo($logoContainer); $('<img>') .attr('src', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADcAAAA3CAYAAACo29JGAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAewQAAHsEBw2lUUwAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAK7SURBVGiB3Zq/axRBFMc/60VioQgW1yjEiwa0tdXiCkH9AwLaKCLY+Aek9CxUbGw9/wMbrYQgCIrEpEgUAimNmCAqapWAGL2wFrPr7R374739kZ3ZL7ziuHlv3mdndufN7MJQHaAPbAIDwK/ZBkEufeA4BXQB2LIAKMm2ghzV6lgOFgXsaOEeW5C41PpauE0LkpbahgbMw9y4LY1TjdoFJqSNPcwVcUmetOE+ZeA/wAqwhBnxvPoBvAY+FoghknS+vwNORPymgVWFf2h3gf1BDA+4Buwo/EuH+x3AjGsG+KtI7HlCDvfqhFtK8V9RJHY9IcaZKuCk99xOyn+aDtPiaNVlCJxYqkmn5bGYDk6iq0OfJSR6XxEjDi5qI6WaNOgyMBUJnveB0mN0rbqK7r7NggsBOxq4cAQXgQWK7Ry+Ai+BDzl8JXA+QamWN8G6TAq3oV3EXdLRJsO1pEXoe2C9ykyAi8ChsoNK5vmLsjsd02lMxV/mPecjDOgDZ6tj46kij1BdSVtp0E/AkQrAbipyqAzOB9YYXciL6gZmG2UFnA/8BG4x3Lbk0TS6qbhncKF9Ax4Cl4DDGTAecAozUvMUq27EcGUeM3wHvmBG1g+AJoE2ZiofKKmf8JihC7xKayg+bBGoHZg1cq1C2dU0dg3us6axa3DzmsYuwW0DDyK/J7McXIHbBmYxVVKoGYlj3vWmahtg3g08Iv793BtBDHFnPcmV2iNdQbjguwj2C0HekkX8DkO482VnKtQE5ij/MnBO45hGf1vR1kYTgzUGrhcDBnZ85VAILgkMzKO57oRzw6WBgTnFrTvhXHBZYGAWUxc+6xiBk4CFsv2DnP/WwuxsNXDrwBPMzroNHMSdGtV6zaGYli5KCuisJIBOKwvQeaUBNkJJgI1RHGCjNA7YOEUBG6k5gvKriXoLeP8AAFe0oEsY7eMAAAAASUVORK5CYII=') .appendTo($logoContainer); $(document.body).append($loadingPopup); } else { $loadingPopup.show(); } } /** * Remove the loading overlay. */ export function removeLoadingOverlay() { if (!$loadingPopup || isShowLoadingOverlaySettingOff()) return; $loadingPopup.hide(); } /** * Is the loading overlay on. This runs very frequently, so we use the fastest way. * * @returns {boolean} */ export function isLoadingOverlayOn() { return Boolean($loadingPopup && $loadingPopup[0] && $loadingPopup[0].style.display === 'block'); } /** * Reload the page via Ajax. * * @param {object} [keptData={}] Data passed from the previous page state. * @throws {CdError|Error} */ export async function reloadPage(keptData = {}) { if (isPageBeingReloaded) return; isPageBeingReloaded = true; // In case checkboxes were changed programmatically. saveSession(); saveScrollPosition(); closeNotifications(keptData.closeNotificationsSmoothly ?? true); cd.debug.init(); cd.debug.startTimer('total time'); cd.debug.startTimer('getting HTML'); setLoadingOverlay(); // Save time by requesting the options in advance. getUserInfo().catch((e) => { console.warn(e); }); let parseData; try { parseData = await cd.g.CURRENT_PAGE.parse(null, false, true); } catch (e) { removeLoadingOverlay(); isPageBeingReloaded = false; if (keptData.didSubmitCommentForm) { throw e; } else { mw.notify(cd.s('error-reloadpage'), { type: 'error' }); console.warn(e); return; } } cd.commentForms.forEach((commentForm) => { commentForm.$outermostElement.detach(); }); mw.config.set({ wgRevisionId: parseData.revid, wgCurRevisionId: parseData.revid, }); mw.loader.load(parseData.modules); mw.loader.load(parseData.modulestyles); mw.config.set(parseData.jsconfigvars); // Remove the fragment history.replaceState(history.state, '', location.pathname + location.search); cd.g.hasPageBeenReloaded = true; updateChecker.updatePageTitle(0, false); await updatePageContent(parseData.text, keptData); toc.possiblyHide(); if (!keptData.commentAnchor && !keptData.sectionAnchor) { restoreScrollPosition(false); } isPageBeingReloaded = false; } /** * Remove sessions older than 30 days. * * @param {object[]} data * @returns {object} * @private */ function cleanUpSessions(data) { const newData = Object.assign({}, data); Object.keys(newData).forEach((key) => { // TODO: remove 1 month after release if (newData[key].forms) { newData[key].commentForms = newData[key].forms; delete newData[key].forms; } if ( !newData[key].commentForms?.length || newData[key].saveUnixTime < Date.now() - 60 * cd.g.SECONDS_IN_A_DAY * 1000 ) { delete newData[key]; } }); return newData; } /** * Save comment form data to the local storage. (Session storage doesn't allow to restore when the * browser has crashed.) */ export function saveSession() { const timeSinceLastSave = Date.now() - saveSessionLastTime; clearTimeout(saveSessionTimeout); saveSessionTimeout = setTimeout(() => { const commentForms = cd.commentForms .filter((commentForm) => commentForm.isAltered()) .map((commentForm) => { let targetData; const target = commentForm.target; if (commentForm.target instanceof Comment) { targetData = { anchor: target.anchor }; } else if (target instanceof Section) { targetData = { headline: target.headline, firstCommentAnchor: target.comments[0]?.anchor, id: target.id, }; } return { mode: commentForm.mode, targetData, preloadConfig: commentForm.preloadConfig, isNewTopicOnTop: commentForm.isNewTopicOnTop, headline: commentForm.headlineInput?.getValue(), comment: commentForm.commentInput.getValue(), summary: commentForm.summaryInput.getValue(), minor: commentForm.minorCheckbox?.isSelected(), watch: commentForm.watchCheckbox?.isSelected(), watchSection: commentForm.watchSectionCheckbox?.isSelected(), omitSignature: commentForm.omitSignatureCheckbox?.isSelected(), delete: commentForm.deleteCheckbox?.isSelected(), originalHeadline: commentForm.originalHeadline, originalComment: commentForm.originalComment, isSummaryAltered: commentForm.isSummaryAltered, lastFocused: commentForm.lastFocused, }; }); const saveUnixTime = Date.now(); const commentFormsData = commentForms.length ? { commentForms, saveUnixTime } : {}; const dataAllPages = getFromLocalStorage('commentForms'); dataAllPages[mw.config.get('wgPageName')] = commentFormsData; saveToLocalStorage('commentForms', dataAllPages); saveSessionLastTime = Date.now(); }, Math.max(0, 5000 - timeSinceLastSave)); } /** * Restore comment forms using the data saved in the local storage. * * @param {object} commentFormsData * @private */ function restoreCommentFormsFromData(commentFormsData) { let haveRestored = false; const rescue = []; commentFormsData.commentForms.forEach((data) => { const property = CommentForm.modeToProperty(data.mode); if (data.targetData?.anchor) { const comment = Comment.getByAnchor(data.targetData.anchor); if (comment?.isActionable && !comment[`${property}Form`]) { try { comment[property](data); haveRestored = true; } catch (e) { console.warn(e); rescue.push(data); } } else { rescue.push(data); } } else if (data.targetData?.headline) { const section = Section.search({ headline: data.targetData.headline, firstCommentAnchor: data.targetData.firstCommentAnchor, // TODO: remove "data.targetData.index ||" after February 2021, when old values in users' // local storages will die for good. id: data.targetData.index || data.targetData.id, // Can't provide parentTree as cd.sections has already changed; will need to add a // workaround if parentTree proves needed. }); if (section?.isActionable && !section[`${property}Form`]) { try { section[property](data); haveRestored = true; } catch (e) { console.warn(e); rescue.push(data); } } else { rescue.push(data); } } else if (data.mode === 'addSection') { if (!cd.g.addSectionForm) { cd.g.addSectionForm = new CommentForm({ target: cd.g.CURRENT_PAGE, mode: data.mode, dataToRestore: data, preloadConfig: data.preloadConfig, isNewTopicOnTop: data.isNewTopicOnTop, }); haveRestored = true; } else { rescue.push(data); } } }); if (haveRestored) { saveSession(); const notification = mw.notification.notify(cd.s('restore-restored-text'), { title: cd.s('restore-restored-title'), }); notification.$notification.on('click', () => { navPanel.goToNextCommentForm(true); }); } if (rescue.length) { rescueCommentFormsContent(rescue); } } /** * Return saved comment forms to their places. */ export function restoreCommentForms() { if (cd.g.isFirstRun) { const dataAllPages = cleanUpSessions(getFromLocalStorage('commentForms')); saveToLocalStorage('commentForms', dataAllPages); const data = dataAllPages[mw.config.get('wgPageName')] || {}; if (data.commentForms) { restoreCommentFormsFromData(data); } } else { const rescue = []; const addToRescue = (commentForm) => { rescue.push({ headline: commentForm.headlineInput?.getValue(), comment: commentForm.commentInput.getValue(), summary: commentForm.summaryInput.getValue(), }); cd.commentForms.splice(cd.commentForms.indexOf(commentForm), 1); }; cd.commentForms.forEach((commentForm) => { commentForm.checkCodeRequest = null; const target = commentForm.target; if (target instanceof Comment) { if (target.anchor) { const comment = Comment.getByAnchor(target.anchor); if (comment?.isActionable) { try { commentForm.setTargets(comment); comment[CommentForm.modeToProperty(commentForm.mode)](commentForm); commentForm.addToPage(); } catch (e) { console.warn(e); addToRescue(commentForm); } } else { addToRescue(commentForm); } } else { addToRescue(commentForm); } } else if (target instanceof Section) { const section = Section.search({ headline: target.headline, firstCommentAnchor: target.comments[0]?.anchor, id: target.id, // Can't provide parentTree as cd.sections has already changed; will need to add a // workaround if parentTree proves needed. }); if (section?.isActionable) { try { commentForm.setTargets(section); section[CommentForm.modeToProperty(commentForm.mode)](commentForm); commentForm.addToPage(); } catch (e) { console.warn(e); addToRescue(commentForm); } } else { addToRescue(commentForm); } } else if (commentForm.mode === 'addSection') { commentForm.addToPage(); cd.g.addSectionForm = commentForm; } }); if (rescue.length) { rescueCommentFormsContent(rescue); } } saveSession(); // Navigation panel doesn't appear on non-existent pages, but sessions are saved and restored on // them. navPanel.updateCommentFormButton(); } /** * Show a notificaition and add it to the registry. This is used to be able to keep track of shown * notifications and close them all at once if needed. * * @param {Array} params Parameters to apply to `mw.notification.notify`. * @param {object} [data={}] Additional data related to the notification. * @returns {Notification} */ export function addNotification(params, data = {}) { const notification = mw.notification.notify(...params); notificationsData.push(Object.assign(data, { notification })); return notification; } /** * Get all notifications added to the registry (including already hidden). The {@link * https://doc.wikimedia.org/mediawiki-core/master/js/#!/api/mw.Notification_ Notification} object * will be in the `notification` property. * * @returns {object[]} */ export function getNotifications() { return notificationsData; } /** * Close all notifications added to the registry immediately. * * @param {boolean} [smooth=true] Use a smooth animation. */ export function closeNotifications(smooth = true) { notificationsData.forEach((data) => { if (!smooth) { data.notification.$notification.hide(); } data.notification.close(); }); notificationsData = []; } "
"/** * Table of contents-related functions. * * @module toc */ import Comment from './Comment'; import Section from './Section'; import cd from './cd'; import { reloadPage } from './boot'; import { restoreScrollPosition, saveScrollPosition } from './util'; let tocItems; /** * Class representing a table of contents item. */ class TocItem { /** * Create a table of contents item object. * * @param {object} a */ constructor(a) { // We expect that the number and text are the first two children of a <li> element. const textSpan = a.children[1]; const headline = textSpan.textContent; const anchor = a.getAttribute('href').slice(1); const li = a.parentNode; let [, level] = li.className.match(/\btoclevel-(\d+)/); level = Number(level); const number = a.children[0].textContent; Object.assign(this, { headline, anchor, level, number, $element: $(li), $link: $(a), $text: $(textSpan), }); } /** * Generate HTML to use it in the TOC for the section. Only a limited number of HTML elements is * allowed in TOC. * * @param {JQuery} $headline */ replaceText($headline) { const html = $headline .clone() .find('*') .each((i, el) => { if (['B', 'EM', 'I', 'S', 'STRIKE', 'STRONG', 'SUB', 'SUP'].includes(el.tagName)) { Array.from(el.attributes).forEach((attr) => { el.removeAttribute(attr.name); }); } else { Array.from(el.childNodes).forEach((child) => { el.parentNode.insertBefore(child, el); }); el.remove(); } }) .end() .html(); this.$text.html(html); this.headline = this.$text.text().trim(); } } export default { /** * Hide the TOC if the relevant cookie is set. This method duplicates {@link * https://phabricator.wikimedia.org/source/mediawiki/browse/master/resources/src/mediawiki.toc/toc.js * the native MediaWiki function} and exists because we may need to hide the TOC earlier than the * native method does it. */ possiblyHide() { if (!cd.g.$toc.length) return; if (mw.cookie.get('hidetoc') === '1') { cd.g.$toc.find('.toctogglecheckbox').prop('checked', true); } }, /** * Reset TOC data (executed at each page reload). */ reset() { tocItems = null; cd.g.$toc = cd.g.$root.find('.toc'); const $closestFloating = cd.g.$toc.closest( '[style*="float: right"], [style*="float:right"], [style*="float: left"], [style*="float:left"]' ); cd.g.isTocFloating = Boolean( $closestFloating.length && cd.g.$root.has($closestFloating).length ); }, /** * Get a TOC item by anchor. * * @param {string} anchor * @returns {?object} */ getItem(anchor) { if (!cd.g.$toc.length) { return null; } if (!tocItems) { // It is executed first time before not rendered (gray) sections are added to the TOC, so we // use a simple algorithm to obtain items. tocItems = Array.from(cd.g.$toc.get(0).querySelectorAll('li > a')).map((a) => new TocItem(a)); } return tocItems.find((item) => item.anchor === anchor) || null; }, /** * Highlight (bold) watched sections. */ highlightWatchedSections() { if (!cd.settings.modifyToc || !cd.g.$toc.length) return; cd.sections .filter((section) => section.isWatched) .forEach((section) => { section.updateTocLink(); }); }, /** * Object with the same basic structure as {@link module:SectionSkeleton} has. (It comes from a * web worker so its constuctor is lost.) * * @typedef {object} SectionSkeletonLike */ /** * Add links to new, not yet rendered sections (loaded in the background) to the table of * contents. * * Note that this method may also add the `match` property to the section elements containing a * matched `Section` object. * * @param {SectionSkeletonLike[]} sections All sections present on the new revision of the page. */ addNewSections(sections) { if (!cd.settings.modifyToc || !cd.g.$toc.length) return; cd.g.$toc .find('.cd-toc-notRenderedSectionList, .cd-toc-notRenderedSection') .remove(); /* Note the case when the page starts with sections of lower levels than the base level, like this: === Section 1 === ==== Section 2 ==== == Section 3 == In this case, the TOC will look like this: 1 Section 1 1.1 Section 2 2 Section 3 The other possible case when the level on the page is different from the level in the TOC is when there is a gap between the levels on the page. For example: == Section == ==== Subsection ==== will be displayed like this in the TOC: 1 Section 1.1 Subsection */ sections.forEach((section, i) => { section.parent = sections .slice(0, i) .reverse() .find((otherSection) => otherSection.level < section.level); }); sections.forEach((section) => { section.tocLevel = section.parent ? section.parent.tocLevel + 1 : 1; }); let currentTree = []; const $topUl = cd.g.$toc.children('ul'); sections.forEach((section) => { let item = section.match?.getTocItem(); if (!item) { const headline = section.headline; const level = section.tocLevel; const currentLevelMatch = currentTree[level - 1]; let upperLevelMatch; if (!currentLevelMatch) { upperLevelMatch = currentTree[currentTree.length - 1]; } const li = document.createElement('li'); li.className = `cd-toc-notRenderedSection toclevel-${level}`; const a = document.createElement('a') a.href = '#' + section.anchor; a.onclick = (e) => { e.preventDefault(); reloadPage({ sectionAnchor: section.anchor, pushState: true, }); }; li.appendChild(a); if (cd.g.thisPageWatchedSections?.includes(headline)) { a.className = 'cd-toc-watched'; a.title = cd.s('toc-watched'); } let number; if (currentLevelMatch) { number = currentLevelMatch.number; } else if (upperLevelMatch) { number = upperLevelMatch.number + '.1'; } else { number = '1'; } const numberSpan = document.createElement('span'); numberSpan.className = 'tocnumber cd-toc-hiddenTocNumber'; numberSpan.textContent = number; a.appendChild(numberSpan); const textSpan = document.createElement('span'); textSpan.className = 'toctext'; textSpan.textContent = section.headline; a.appendChild(textSpan); if (currentLevelMatch) { currentLevelMatch.$element.after(li); } else if (upperLevelMatch) { const ul = document.createElement('ul'); ul.className = `cd-toc-notRenderedSectionList toclevel-${level}`; ul.appendChild(li); upperLevelMatch.$element.append(ul); } else { $topUl.prepend(li); } item = { headline, level, number, $element: $(li), }; } currentTree[section.tocLevel - 1] = item; currentTree.splice(section.tocLevel); }); }, /** * Object with the same basic structure as {@link module:CommentSkeleton} has. (It comes from a * web worker so its constuctor is lost.) * * @typedef {object} CommentSkeletonLike */ /** * Add links to new comments (either already displayed or loaded in the background) to the table * of contents. * * @param {CommentSkeletonLike[]|Comment[]} commentsBySection * @param {object} keptData */ addNewComments(commentsBySection, keptData) { if (!cd.settings.modifyToc || !cd.g.$toc.length) return; const firstComment = commentsBySection.values().next().value?.[0]; if (!firstComment) return; const areCommentsRendered = firstComment instanceof Comment; const saveTocHeight = Boolean( !(cd.g.hasPageBeenReloaded && areCommentsRendered) || // When the comment or section is opened by a link from the TOC keptData.commentAnchor || keptData.sectionAnchor ); saveScrollPosition(saveTocHeight); cd.g.$toc .find('.cd-toc-notRenderedCommentList') .remove(); commentsBySection.forEach((comments, sectionOrAnchor) => { if (!sectionOrAnchor) return; // There could be a collision of hrefs between the existing section and not yet rendered // section, so we compose the selector carefully. const $sectionLink = typeof sectionOrAnchor === 'string' ? cd.g.$toc .find(`.cd-toc-notRenderedSection a[href="#${$.escapeSelector(sectionOrAnchor)}"]`) : sectionOrAnchor.getTocItem().$link; // Should never be the case if (!$sectionLink?.length) return; let $target = $sectionLink; const $next = $sectionLink.next('.cd-toc-newCommentList'); if ($next.length) { $target = $next; } const target = $target.get(0); // jQuery is too expensive here given that very many comments may be added. const ul = document.createElement('ul'); ul.className = areCommentsRendered ? 'cd-toc-newCommentList' : 'cd-toc-notRenderedCommentList'; let moreTooltipText = ''; comments.forEach((comment, i) => { const parent = areCommentsRendered ? comment.getParent() : comment.parent; const names = parent?.author && comment.level > 1 ? cd.s('navpanel-newcomments-names', comment.author.name, parent.author.name) : comment.author.name; const date = comment.date ? cd.util.formatDate(comment.date) : cd.s('navpanel-newcomments-unknowndate'); const text = ( names + (cd.g.SITE_DIR === 'rtl' ? '\u200F' : '') + cd.mws('comma-separator') + date ); // If there are 5 comments or less, show all of them. If there are more, show 4 and "N // more". (Because showing 4 and then "1 more" is stupid.) if (i < 4 || comments.length === 5) { const li = document.createElement('li'); ul.appendChild(li); const bulletSpan = document.createElement('span'); bulletSpan.className = 'tocnumber cd-toc-bullet'; bulletSpan.innerHTML = cd.sParse('bullet'); li.appendChild(bulletSpan); const textSpan = document.createElement('span'); textSpan.className = 'toctext'; li.appendChild(textSpan); const a = document.createElement('a'); a.href = `#${comment.anchor}`; a.textContent = text; textSpan.appendChild(a); if (comment instanceof Comment) { a.onclick = (e) => { e.preventDefault(); comment.scrollToAndHighlightTarget(false, true); }; } else { a.onclick = (e) => { e.preventDefault(); reloadPage({ commentAnchor: comment.anchor, pushState: true, }); }; } } else { moreTooltipText += text + '\n'; } }); if (comments.length > 5) { const span = document.createElement('span'); span.className = 'cd-toc-more'; span.title = moreTooltipText.trim(); span.textContent = cd.s('toc-more', comments.length - 4); const li = document.createElement('li'); li.appendChild(span); ul.appendChild(li); } target.parentNode.insertBefore(ul, target.nextSibling); }); restoreScrollPosition(); }, }; "
"/** * Module responsible for checking for updates of the page in background. * * @module updateChecker */ import CdError from './CdError'; import Comment from './Comment'; import Section from './Section'; import cd from './cd'; import commentLayers from './commentLayers'; import navPanel from './navPanel'; import toc from './toc'; import userRegistry from './userRegistry'; import { addNotification, closeNotifications, getNotifications, isLoadingOverlayOn, reloadPage, } from './boot'; import { calculateWordsOverlap, getFromLocalStorage, keepWorkerSafeValues, saveToLocalStorage, unique, } from './util'; import { getUserGenders } from './apiWrappers'; let lastCheckedRevisionId; let commentsNotifiedAbout; let isBackgroundCheckArranged; let previousVisitRevisionId; let submittedCommentAnchor; let resolverCount = 0; const revisionData = {}; const resolvers = {}; /** * Tell the worker to wake the script up after a given interval. * * Chrome and probably other browsers throttle background tabs. To bypass this, we use a web worker * to wake the script up when we say, making it work as an alarm clock. * * @param {number} interval * @private */ function setAlarmViaWorker(interval) { if (Number.isNaN(Number(interval))) return; cd.g.worker.postMessage({ type: 'setAlarm', interval, }); } /** * Remove an alarm set in `setAlarmViaWorker()`. * * @private */ function removeAlarmViaWorker() { cd.g.worker.postMessage({ type: 'removeAlarm' }); } /** * Check for new comments in a web worker, update the navigation panel, and schedule the next check. * * @private */ async function checkForUpdates() { // We need a value that wouldn't change during await's. const documentHidden = document.hidden; if (documentHidden && !isBackgroundCheckArranged) { const onDocumentVisible = () => { $(document).off('visibilitychange', onDocumentVisible); isBackgroundCheckArranged = false; removeAlarmViaWorker(); checkForUpdates(); }; $(document).on('visibilitychange', onDocumentVisible); const interval = Math.abs(cd.g.BACKGROUND_UPDATE_CHECK_INTERVAL - cd.g.UPDATE_CHECK_INTERVAL); setAlarmViaWorker(interval * 1000); isBackgroundCheckArranged = true; return; } try { const revisions = await cd.g.CURRENT_PAGE.getRevisions({ rvprop: ['ids'], rvlimit: 1, }, true); const currentRevisionId = mw.config.get('wgRevisionId'); if (revisions.length && revisions[0].revid !== (lastCheckedRevisionId || currentRevisionId)) { const { revisionId, comments, sections } = await updateChecker.processPage(); lastCheckedRevisionId = revisionId; if (isPageStillAtRevision(currentRevisionId)) { const { comments: currentComments } = await updateChecker.processPage(currentRevisionId); if (isPageStillAtRevision(currentRevisionId)) { mapSections(sections); toc.addNewSections(sections); const mappedCurrentComments = mapComments(currentComments, comments); // We check for new edits before notifying about new comments to notify about changes in a // renamed section if it is watched. checkForNewEdits(mappedCurrentComments); await processComments(comments, mappedCurrentComments, currentRevisionId); } } } } catch (e) { if (!(e instanceof CdError) || (e.data && e.data.type !== 'network')) { console.warn(e); } } if (documentHidden) { setAlarmViaWorker(cd.g.BACKGROUND_UPDATE_CHECK_INTERVAL * 1000); isBackgroundCheckArranged = true; } else { setAlarmViaWorker(cd.g.UPDATE_CHECK_INTERVAL * 1000); } } /** * If the revision of the current visit and previous visit are different, process the said * revisions. (We need to process the current revision too to get the comments' inner HTML without * any elements that may be added by scripts.) The revisions' data will finally processed by {@link * module:updateChecker~checkForEditsSincePreviousVisit checkForEditsSincePreviousVisit()}. * * @private */ async function processRevisionsIfNeeded() { const revisions = await cd.g.CURRENT_PAGE.getRevisions({ rvprop: ['ids'], rvstart: new Date(cd.g.previousVisitUnixTime * 1000).toISOString(), rvlimit: 1, }, true); previousVisitRevisionId = revisions[0]?.revid; const currentRevisionId = mw.config.get('wgRevisionId'); if (previousVisitRevisionId && previousVisitRevisionId < currentRevisionId) { const { comments: oldComments } = await updateChecker.processPage(previousVisitRevisionId); const { comments: currentComments } = await updateChecker.processPage(currentRevisionId); if (isPageStillAtRevision(currentRevisionId)) { checkForEditsSincePreviousVisit(mapComments(currentComments, oldComments)); } } } /** * Remove seen rendered edits data older than 60 days. * * @param {object[]} data * @returns {object} * @private */ function cleanUpSeenRenderedEdits(data) { const newData = Object.assign({}, data); Object.keys(newData).forEach((key) => { const seenUnixTime = Object.keys(newData[key])[0]?.seenUnixTime; if (!seenUnixTime || seenUnixTime < Date.now() - 60 * cd.g.SECONDS_IN_A_DAY * 1000) { delete newData[key]; } }); return newData; } /** * Object with the same basic structure as {@link module:SectionSkeleton} has. (It comes from a web * worker so its constuctor is lost.) * * @typedef {object} SectionSkeletonLike */ /** * Map sections obtained from a revision to the sections present on the page. * * @param {SectionSkeletonLike[]} sections */ function mapSections(sections) { // Reset from the previous run. cd.sections.forEach((section) => { delete section.match; }); sections.forEach((section) => { const { section: matchedSection, score } = Section.search(section, true) || {}; if (matchedSection && (!matchedSection.match || score > matchedSection.matchScore)) { if (matchedSection.match) { delete matchedSection.match.match; } matchedSection.match = section; matchedSection.matchScore = score; section.match = matchedSection; } }); } /** * Object with the same basic structure as {@link module:CommentSkeleton} has. (It comes from a web * worker so its constuctor is lost.) * * @typedef {object} CommentSkeletonLike */ /** * Map comments obtained from the current revision to the comments obtained from another revision * (newer or older) by adding the `match` property to the first ones. The function also adds the * `hasPoorMatch` property to the comments that have possible matches that are not good enough to * confidently state a match. * * @param {CommentSkeletonLike[]} currentComments * @param {CommentSkeletonLike[]} otherComments * @returns {CommentSkeletonLike[]} Mapped current comments. * @private */ function mapComments(currentComments, otherComments) { const mappedCurrentComments = currentComments.map((comment) => Object.assign({}, comment)); otherComments.forEach((otherComment) => { let currentCommentsFiltered = mappedCurrentComments.filter((currentComment) => ( currentComment.authorName === otherComment.authorName && currentComment.date && otherComment.date && currentComment.date.getTime() === otherComment.date.getTime() )); if (currentCommentsFiltered.length === 1) { currentCommentsFiltered[0].match = otherComment; } else if (currentCommentsFiltered.length > 1) { let found; currentCommentsFiltered .map((currentComment) => { const hasParentAnchorMatched = currentComment.parentAnchor === otherComment.parentAnchor; const hasHeadlineMatched = ( currentComment.section?.headline === otherComment.section?.headline ); // Taking matched ID into account makes sense only if the total number of comments // coincides. const hasIdMatched = ( currentComment.id === otherComment.id && mappedCurrentComments.length === otherComments.length ); const partsMatchedCount = currentComment.elementHtmls .filter((html, i) => html === otherComment.elementHtmls[i]) .length; const partsMatchedProportion = partsMatchedCount / currentComment.elementHtmls.length; const overlap = partsMatchedProportion === 1 ? 1 : calculateWordsOverlap(currentComment.text, otherComment.text); const score = ( hasParentAnchorMatched * (currentComment.parentAnchor ? 1 : 0.75) + hasHeadlineMatched * 1 + partsMatchedProportion + overlap + hasIdMatched * 0.25 ); return { comment: currentComment, score, }; }) .filter((match) => match.score > 1.66) .sort((match1, match2) => { if (match2.score > match1.score) { return 1; } else if (match2.score < match1.score) { return -1; } else { return 0; } }) .forEach((match) => { if (!found && (!match.comment.match || match.comment.matchScore < match.score)) { match.comment.match = otherComment; match.comment.matchScore = match.score; delete match.comment.hasPoorMatch; found = true; } else { if (!match.comment.match) { match.comment.hasPoorMatch = true; } } }); } }); return mappedCurrentComments; } /** * Determine if the comment was edited based on the `textInnerHtml` and `headingInnerHtml` * properties (the comment may lose its heading because technical comment is added between it and * the heading). * * @param {CommentSkeletonLike[]} olderComment * @param {CommentSkeletonLike[]} newerComment * @returns {boolean} * @private */ function isCommentEdited(olderComment, newerComment) { return ( newerComment.textInnerHtml !== olderComment.textInnerHtml || ( newerComment.headingInnerHtml && newerComment.headingInnerHtml !== olderComment.headingInnerHtml ) ); } /** * Check if there are changes made to the currently displayed comments since the previous visit. * * @param {CommentSkeletonLike[]} mappedCurrentComments * @private */ function checkForEditsSincePreviousVisit(mappedCurrentComments) { const seenRenderedEdits = cleanUpSeenRenderedEdits(getFromLocalStorage('seenRenderedEdits')); const articleId = mw.config.get('wgArticleId'); mappedCurrentComments.forEach((currentComment) => { if (currentComment.anchor === submittedCommentAnchor) return; const oldComment = currentComment.match; if (oldComment) { const seenInnerHtml = seenRenderedEdits[articleId]?.[currentComment.anchor]?.innerHtml; if ( isCommentEdited(oldComment, currentComment) && seenInnerHtml !== currentComment.innerHtml ) { const comment = Comment.getByAnchor(currentComment.anchor); if (!comment) return; const commentsData = [oldComment, currentComment]; comment.markAsEdited('editedSince', true, previousVisitRevisionId, commentsData); if (comment.isOpeningSection) { const section = comment.getSection(); if ( section && !section.isWatched && /^H[1-6]$/.test(currentComment.elementTagNames[0]) && oldComment.elementTagNames[0] === currentComment.elementTagNames[0] ) { const html = oldComment.elementHtmls[0].replace( /\x01(\d+)_\w+\x02/g, (s, num) => currentComment.hiddenElementData[num - 1].html ); const $dummy = $('<span>').html($(html).html()); const oldSection = { headlineElement: $dummy.get(0) }; Section.prototype.parseHeadline.call(oldSection); const newHeadline = section.headline; if ( newHeadline && oldSection.headline !== newHeadline && cd.g.originalThisPageWatchedSections?.includes(oldSection.headline) ) { section.watch(true, oldSection.headline); } } } } } }); delete seenRenderedEdits[articleId]; saveToLocalStorage('seenRenderedEdits', seenRenderedEdits); } /** * Check if there are changes made to the currently displayed comments since they were rendered. * * @param {CommentSkeletonLike[]} mappedCurrentComments * @private */ function checkForNewEdits(mappedCurrentComments) { let isEditMarkUpdated = false; mappedCurrentComments.forEach((currentComment) => { const newComment = currentComment.match; if (newComment) { const comment = Comment.getByAnchor(currentComment.anchor); if (!comment) return; if (comment.isDeleted) { comment.unmarkAsEdited('deleted'); isEditMarkUpdated = true; } if (isCommentEdited(currentComment, newComment)) { // The comment may have already been updated previously. if (!comment.comparedHtml || comment.comparedHtml !== newComment.innerHtml) { const success = comment.update(currentComment, newComment); const commentsData = [currentComment, newComment]; comment.markAsEdited('edited', success, lastCheckedRevisionId, commentsData); isEditMarkUpdated = true; comment.comparedHtml = newComment.innerHtml; } } else if (comment.isEdited) { comment.update(currentComment, newComment); comment.unmarkAsEdited('edited'); isEditMarkUpdated = true; } } else if (!currentComment.hasPoorMatch) { const comment = Comment.getByAnchor(currentComment.anchor); if (!comment || comment.isDeleted) return; comment.markAsEdited('deleted'); isEditMarkUpdated = true; } }); if (isEditMarkUpdated) { // If we configure the layers of deleted comments in Comment#unmarkAsEdited, they will prevent // layers before them from being updated due to the "stop at the first two unmoved comments" // optimization. So we better just do the whole job here. commentLayers.redrawIfNecessary(false, true); } } /** * Show an ordinary notification (`mediawiki.notification`) to the user. * * @param {CommentSkeletonLike[]} comments * @private */ function showOrdinaryNotification(comments) { let filteredComments = []; if (cd.settings.notifications === 'all') { filteredComments = comments; } else if (cd.settings.notifications === 'toMe') { filteredComments = comments.filter((comment) => comment.toMe); } if (cd.settings.notifications !== 'none' && filteredComments.length) { // Combine with content of notifications that were displayed but are still open (i.e., the user // most likely didn't see them because the tab is in the background). In the past there could be // more than one notification, now there can be only one. const openNotification = getNotifications() .find((data) => data.comments && data.notification.isOpen); if (openNotification) { filteredComments.push(...openNotification.comments); } } if (filteredComments.length) { let html; const formsDataWillNotBeLost = cd.commentForms.some((commentForm) => commentForm.isAltered()) ? ' ' + cd.mws('parentheses', cd.s('notification-formdata')) : ''; const reloadHtml = cd.sParse('notification-reload', formsDataWillNotBeLost); if (filteredComments.length === 1) { const comment = filteredComments[0]; if (comment.toMe) { const where = comment.watchedSectionHeadline ? ( cd.mws('word-separator') + cd.s('notification-part-insection', comment.watchedSectionHeadline) ) : cd.mws('word-separator') + cd.s('notification-part-onthispage'); html = ( cd.sParse('notification-toyou', comment.author.name, comment.author, where) + ' ' + reloadHtml ); } else { html = ( cd.sParse( 'notification-insection', comment.author.name, comment.author, comment.watchedSectionHeadline ) + ' ' + reloadHtml ); } } else { const isCommonSection = filteredComments.every((comment) => ( comment.watchedSectionHeadline === filteredComments[0].watchedSectionHeadline )); let section; if (isCommonSection) { section = filteredComments[0].watchedSectionHeadline; } const where = ( cd.mws('word-separator') + ( section ? cd.s('notification-part-insection', section) : cd.s('notification-part-onthispage') ) ); let mayBeInterestingString = cd.s('notification-newcomments-maybeinteresting'); if (!mayBeInterestingString.startsWith(',')) { mayBeInterestingString = cd.mws('word-separator') + mayBeInterestingString; } // "that may be interesting to you" text is not needed when the section is watched and the // user can clearly understand why they are notified. const mayBeInteresting = section && cd.g.thisPageWatchedSections?.includes(section) ? '' : mayBeInterestingString; html = ( cd.sParse('notification-newcomments', filteredComments.length, where, mayBeInteresting) + ' ' + reloadHtml ); } closeNotifications(false); const $body = cd.util.wrap(html); const notification = addNotification([$body], { comments: filteredComments }); notification.$notification.on('click', () => { reloadPage({ commentAnchor: filteredComments[0].anchor }); }); } } /** * Show a desktop notification to the user. * * @param {CommentSkeletonLike[]} comments * @private */ function showDesktopNotification(comments) { let filteredComments = []; if (cd.settings.desktopNotifications === 'all') { filteredComments = comments; } else if (cd.settings.desktopNotifications === 'toMe') { filteredComments = comments.filter((comment) => comment.toMe); } if (!document.hasFocus() && Notification.permission === 'granted' && filteredComments.length) { let body; const comment = filteredComments[0]; if (filteredComments.length === 1) { if (comment.toMe) { const where = comment.section?.headline ? cd.mws('word-separator') + cd.s('notification-part-insection', comment.section.headline) : ''; body = cd.s( 'notification-toyou-desktop', comment.author.name, comment.author, where, cd.g.CURRENT_PAGE.name ); } else { body = cd.s( 'notification-insection-desktop', comment.author.name, comment.author, comment.section?.headline, cd.g.CURRENT_PAGE.name ); } } else { const isCommonSection = filteredComments.every((comment) => ( comment.watchedSectionHeadline === filteredComments[0].watchedSectionHeadline )); let section; if (isCommonSection) { section = filteredComments[0].watchedSectionHeadline; } const where = section ? cd.mws('word-separator') + cd.s('notification-part-insection', section) : ''; let mayBeInterestingString = cd.s('notification-newcomments-maybeinteresting'); if (!mayBeInterestingString.startsWith(cd.mws('comma-separator'))) { mayBeInterestingString = cd.mws('word-separator') + mayBeInterestingString; } // "that may be interesting to you" text is not needed when the section is watched and the // user can clearly understand why they are notified. const mayBeInteresting = section && cd.g.thisPageWatchedSections?.includes(section) ? '' : mayBeInterestingString; body = cd.s( 'notification-newcomments-desktop', filteredComments.length, where, cd.g.CURRENT_PAGE.name, mayBeInteresting ); } const notification = new Notification(mw.config.get('wgSiteName'), { body, // We use a tag so that there aren't duplicate notifications when the same page is opened in // two tabs. (Seems it doesn't work? :-/) tag: 'convenient-discussions-' + filteredComments[filteredComments.length - 1].anchor, }); notification.onclick = () => { parent.focus(); // Just in case, old browsers. TODO: delete? window.focus(); reloadPage({ commentAnchor: comment.anchor, closeNotificationsSmoothly: false, }); }; } } /** * Whether the page is still at the specified revision and the content is not loading. * * @param {number} revisionId * @returns {boolean} * @private */ function isPageStillAtRevision(revisionId) { return revisionId === mw.config.get('wgRevisionId') && !isLoadingOverlayOn(); } /** * Process the comments retrieved by a web worker. * * @param {CommentSkeletonLike[]} comments * @param {CommentSkeletonLike[]} mappedCurrentComments * @param {number} currentRevisionId * @private */ async function processComments(comments, mappedCurrentComments, currentRevisionId) { comments.forEach((comment) => { comment.author = userRegistry.getUser(comment.authorName); if (comment.parentAuthorName) { comment.parent = { author: userRegistry.getUser(comment.parentAuthorName), }; } }); const newComments = comments.filter((comment) => ( comment.anchor && !mappedCurrentComments.some((currentComment) => currentComment.match === comment) )); // Extract "interesting" comments (that would make the new comments counter purple and might // invoke notifications). Keep in mind that we should account for the case where comments have // been removed. For example, the counter could be "+1" but then go back to displaying the refresh // icon which means 0 new comments. const interestingNewComments = newComments.filter((comment) => { if (comment.isOwn || cd.settings.notificationsBlacklist.includes(comment.author.name)) { return false; } if (comment.toMe) { comment.interesting = true; return true; } if (!cd.g.thisPageWatchedSections) { return false; } if (comment.section) { // Is this section watched by means of an upper level section? const section = comment.section.match; if (section) { const closestWatchedSection = section.getClosestWatchedSection(true); if (closestWatchedSection) { comment.watchedSectionHeadline = closestWatchedSection.headline; comment.interesting = true; return true; } } } }); const authors = newComments .map((comment) => comment.author) .filter(unique); await getUserGenders(authors, true); if (!isPageStillAtRevision(currentRevisionId)) return; if (interestingNewComments[0]) { updateChecker.relevantNewCommentAnchor = interestingNewComments[0].anchor; } else if (newComments[0]) { updateChecker.relevantNewCommentAnchor = newComments[0].anchor; } const newCommentsBySection = Comment.groupBySection(newComments); const areThereInteresting = Boolean(interestingNewComments.length); navPanel.updateRefreshButton(newComments.length, newCommentsBySection, areThereInteresting); updateChecker.updatePageTitle(newComments.length, areThereInteresting); toc.addNewComments(newCommentsBySection); Section.addNewCommentsNotifications(newCommentsBySection); const commentsToNotifyAbout = interestingNewComments.filter((comment) => ( !commentsNotifiedAbout.some((cna) => cna.anchor === comment.anchor) )); showOrdinaryNotification(commentsToNotifyAbout); showDesktopNotification(commentsToNotifyAbout); commentsNotifiedAbout.push(...commentsToNotifyAbout); } /** * Perform a task in a web worker. * * @param {object} payload * @returns {Promise} */ function runWorkerTask(payload) { return new Promise((resolve) => { const resolverId = resolverCount++; Object.assign(payload, { resolverId }); cd.g.worker.postMessage(payload); resolvers[resolverId] = resolve; }); } /** * Callback for messages from the worker. * * @param {Event} e * @private */ async function onMessageFromWorker(e) { const message = e.data; if (message.type === 'wakeUp') { checkForUpdates(); } else { const resolverId = message.resolverId; delete message.resolverId; delete message.type; resolvers[resolverId](message); delete resolvers[resolverId]; } } const updateChecker = { /** * Anchor of the comment that should be jumped to after reloading the page. * * @type {?string} * @memberof module:updateChecker */ relevantNewCommentAnchor: null, /** * Initialize the update checker. * * @param {Promise} visitsRequest * @param {object} keptData * @memberof module:updateChecker */ async init(visitsRequest, keptData) { if (!cd.g.worker) return; commentsNotifiedAbout = []; this.relevantNewCommentAnchor = null; isBackgroundCheckArranged = false; previousVisitRevisionId = null; if (cd.g.worker.onmessage) { removeAlarmViaWorker(); } else { cd.g.worker.onmessage = onMessageFromWorker; } setAlarmViaWorker(cd.g.UPDATE_CHECK_INTERVAL * 1000); // It is processed in processPage~processVisits. await visitsRequest; if (cd.g.previousVisitUnixTime) { processRevisionsIfNeeded(); if (keptData.didSubmitCommentForm && keptData.commentAnchor) { submittedCommentAnchor = keptData.commentAnchor; } } }, /** * Process the current page in a web worker. * * @param {number} [revisionToParseId] * @returns {object} * @memberof module:updateChecker */ async processPage(revisionToParseId) { if (revisionData[revisionToParseId]) { return revisionData[revisionToParseId]; } const { text, revid: revisionId, } = await cd.g.CURRENT_PAGE.parse({ oldid: revisionToParseId }, true) || {}; const disallowedNames = [ '$content', '$root', '$toc', 'rootElement', 'visits', 'watchedSections', ]; const message = await runWorkerTask({ type: 'parse', revisionId, text, g: keepWorkerSafeValues(cd.g, ['IS_IPv6_ADDRESS', 'TIMESTAMP_PARSER'], disallowedNames), config: keepWorkerSafeValues(cd.config, ['checkForCustomForeignComponents'], disallowedNames), }); if (!revisionData[message.revisionId]) { revisionData[message.revisionId] = message; } // Clean up revisionData from values that can't be reused as it may grow really big. (The newest // revision could be reused as the current revision; the current revision could be reused as the // previous visit revision.) Object.keys(revisionData).forEach((key) => { const revisionId = Number(key); if ( revisionId !== message.revisionId && revisionId !== lastCheckedRevisionId && revisionId !== previousVisitRevisionId && revisionId !== mw.config.get('wgRevisionId') ) { delete revisionData[key]; } }); return message; }, /** * Update the page title to show the number of comments added to the page since it was loaded. * * @param {number} newCommentsCount * @param {boolean} areThereInteresting * @memberof module:updateChecker */ updatePageTitle(newCommentsCount, areThereInteresting) { const interestingMark = areThereInteresting ? '*' : ''; const s = newCommentsCount ? `(${newCommentsCount}${interestingMark}) ` : ''; document.title = document.title.replace(/^(?:\(\d+\*?\) )?/, s); }, }; export default updateChecker; "
"/** * Navigation panel and new comments-related functions and configuration. * * @module navPanel */ import Comment from './Comment'; import cd from './cd'; import updateChecker from './updateChecker'; import { reloadPage } from './boot'; import { removeWikiMarkup } from './wikitext'; import { reorderArray } from './util'; let newCount; let lastFirstUnseenCommentId; /** * Generate tooltip text displaying statistics of unseen or not yet displayed comments. * * @param {number} commentsCount * @param {Map} commentsBySection * @returns {?string} * @private */ function generateTooltipText(commentsCount, commentsBySection) { let tooltipText = null; if (commentsCount) { tooltipText = ( cd.s('navpanel-newcomments-count', commentsCount) + ' ' + cd.s('navpanel-newcomments-refresh') + ' ' + cd.mws('parentheses', 'R') ); const bullet = removeWikiMarkup(cd.s('bullet')); commentsBySection.forEach((comments, sectionOrAnchor) => { let headline; if (typeof sectionOrAnchor === 'string') { headline = comments[0].section.headline; } else if (sectionOrAnchor !== null) { headline = sectionOrAnchor.headline; } tooltipText += headline ? `\n\n${headline}` : '\n'; comments.forEach((comment) => { tooltipText += `\n`; const names = comment.parent?.author && comment.level > 1 ? cd.s('navpanel-newcomments-names', comment.author.name, comment.parent.author.name) : comment.author.name; const date = comment.date ? cd.util.formatDate(comment.date) : cd.s('navpanel-newcomments-unknowndate'); tooltipText += ( bullet + ' ' + names + (cd.g.SITE_DIR === 'rtl' ? '\u200F' : '') + cd.mws('comma-separator') + date ); }); }); } else { tooltipText = `${cd.s('navpanel-refresh')} ${cd.mws('parentheses', 'R')}`; } return tooltipText; } const navPanel = { /** * Render the navigation panel. This is done when the page is first loaded or created. * * @memberof module:navPanel */ mount() { /** * Navigation panel element. * * @type {?(JQuery|undefined)} * @memberof module:navPanel */ this.$element = $('<div>') .attr('id', 'cd-navPanel') .appendTo(document.body); /** * Refresh button element. * * @type {JQuery|undefined} * @memberof module:navPanel */ this.$refreshButton = $('<div>') .addClass('cd-navPanel-button') .attr('id', 'cd-navPanel-refreshButton') .attr('title', `${cd.s('navpanel-refresh')} ${cd.mws('parentheses', 'R')}`) .on('click', () => { this.refreshClick(); }) .appendTo(this.$element); /** * "Go to the previous new comment" button element. * * @type {JQuery|undefined} * @memberof module:navPanel */ this.$previousButton = $('<div>') .addClass('cd-navPanel-button') .attr('id', 'cd-navPanel-previousButton') .attr('title', `${cd.s('navpanel-previous')} ${cd.mws('parentheses', 'W')}`) .on('click', () => { this.goToPreviousNewComment(); }) .hide() .appendTo(this.$element); /** * "Go to the next new comment" button element. * * @type {JQuery|undefined} * @memberof module:navPanel */ this.$nextButton = $('<div>') .addClass('cd-navPanel-button') .attr('id', 'cd-navPanel-nextButton') .attr('title', `${cd.s('navpanel-next')} ${cd.mws('parentheses', 'S')}`) .on('click', () => { this.goToNextNewComment(); }) .hide() .appendTo(this.$element); /** * "Go to the first unseen comment" button element. * * @type {JQuery|undefined} * @memberof module:navPanel */ this.$firstUnseenButton = $('<div>') .addClass('cd-navPanel-button') .attr('id', 'cd-navPanel-firstUnseenButton') .attr('title', `${cd.s('navpanel-firstunseen')} ${cd.mws('parentheses', 'F')}`) .on('click', () => { this.goToFirstUnseenComment(); }) .hide() .appendTo(this.$element); /** * "Go to the next comment form out of sight" button element. * * @type {JQuery|undefined} * @memberof module:navPanel */ this.$commentFormButton = $('<div>') .addClass('cd-navPanel-button') .attr('id', 'cd-navPanel-commentFormButton') .attr('title', cd.s('navpanel-commentform')) .on('click', () => { this.goToNextCommentForm(); }) .hide() .appendTo(this.$element); }, /** * Remove the navigation panel. */ unmount() { this.$element.remove(); this.$element = null; }, /** * Check if the navigation panel is mounted. Is equivalent to checking the existence of {@link * module:navPanel.$element}, and for the most of the practical purposes, does the same as the * `convenientDiscussions.g.isPageActive` check. * * @returns {boolean} * @memberof module:navPanel */ isMounted() { return Boolean(this.$element); }, /** * Reset the navigation panel to the initial state. This is done after page refreshes. (Comment * forms are expected to be restored already.) * * @memberof module:navPanel */ reset() { lastFirstUnseenCommentId = null; this.$refreshButton .empty() .attr('title', `${cd.s('navpanel-refresh')} ${cd.mws('parentheses', 'R')}`); this.$previousButton.hide(); this.$nextButton.hide(); this.$firstUnseenButton.hide(); this.$commentFormButton.hide(); }, /** * Count the new and unseen comments on the page, and update the navigation panel to reflect that. * * @memberof module:navPanel */ fill() { newCount = cd.comments.filter((comment) => comment.isNew).length; if (newCount) { this.$nextButton.show(); this.$previousButton.show(); this.updateFirstUnseenButton(); } }, /** * Update the state of the "Go to the first unseen comment" button. * * @memberof module:navPanel */ updateFirstUnseenButton() { if (!navPanel.isMounted()) return; const unseenCount = cd.comments.filter((comment) => comment.isSeen === false).length; if (unseenCount) { this.$firstUnseenButton.show().text(unseenCount); } else { this.$firstUnseenButton.hide(); } }, /** * Perform routines at the refresh button click. * * @memberof module:navPanel */ refreshClick() { // There was reload confirmation here, but after session restore was introduced, the // confirmation seems to be no longer needed. reloadPage({ commentAnchor: updateChecker.relevantNewCommentAnchor }); }, /** * Scroll to the previous new comment. * * @memberof module:navPanel */ goToPreviousNewComment() { if (cd.g.autoScrollInProgress) return; const commentInViewport = Comment.findInViewport('backward'); if (!commentInViewport) return; // This will return invisible comments too in which case an error will be displayed. const comment = reorderArray(cd.comments, commentInViewport.id, true) .find((comment) => comment.isNew && comment.isInViewport() !== true); if (comment) { comment.$elements.cdScrollTo('center', true, () => { comment.registerSeen('backward', true); this.updateFirstUnseenButton(); }); } }, /** * Scroll to the next new comment. * * @memberof module:navPanel */ goToNextNewComment() { if (cd.g.autoScrollInProgress) return; const commentInViewport = Comment.findInViewport('forward'); if (!commentInViewport) return; // This will return invisible comments too in which case an error will be displayed. const comment = reorderArray(cd.comments, commentInViewport.id) .find((comment) => comment.isNew && comment.isInViewport() !== true); if (comment) { comment.$elements.cdScrollTo('center', true, () => { comment.registerSeen('forward', true); this.updateFirstUnseenButton(); }); } }, /** * Scroll to the first unseen comment. * * @memberof module:navPanel */ goToFirstUnseenComment() { if (cd.g.autoScrollInProgress) return; const comment = cd.comments .slice(lastFirstUnseenCommentId || 0) .find((comment) => comment.isSeen === false); if (comment) { comment.$elements.cdScrollTo('center', true, () => { comment.registerSeen('forward', true); this.updateFirstUnseenButton(); }); lastFirstUnseenCommentId = comment.id; } }, /** * Go to the next comment form out of sight, or just the first comment form, if `first` is set to * true. * * @param {boolean} [first=false] * @memberof module:navPanel */ goToNextCommentForm(first = false) { const commentForm = cd.commentForms .filter((commentForm) => first || !commentForm.$element.cdIsInViewport(true)) .sort((commentForm1, commentForm2) => { let top1 = commentForm1.$element.get(0).getBoundingClientRect().top; if (top1 < 0) { top1 += $(document).height() * 2; } let top2 = commentForm2.$element.get(0).getBoundingClientRect().top; if (top2 < 0) { top2 += $(document).height() * 2; } return top1 - top2; })[0]; if (commentForm) { commentForm.$element.cdScrollIntoView('center'); commentForm.commentInput.focus(); } }, /** * Update the refresh button to show the number of comments added to the page since it was loaded. * * @param {number} commentCount * @param {Map} commentsBySection * @param {boolean} areThereInteresting * @private * @memberof module:navPanel */ updateRefreshButton(commentCount, commentsBySection, areThereInteresting) { this.$refreshButton .empty() .attr('title', generateTooltipText(commentCount, commentsBySection)); if (commentCount) { $('<span>') // Can't set the attribute to $refreshButton as its tooltip may have another direction. .attr('dir', 'ltr') .text(`+${commentCount}`) .appendTo(this.$refreshButton); } if (areThereInteresting) { this.$refreshButton.addClass('cd-navPanel-refreshButton-interesting'); } else { this.$refreshButton.removeClass('cd-navPanel-refreshButton-interesting'); } }, /** * Update the "Go to the next comment form out of sight" button visibility. * * @memberof module:navPanel */ updateCommentFormButton() { if (cd.g.autoScrollInProgress || !navPanel.isMounted()) return; if (cd.commentForms.some((commentForm) => !commentForm.$element.cdIsInViewport(true))) { this.$commentFormButton.show(); } else { this.$commentFormButton.hide(); } }, }; export default navPanel; "
"/** * Functions that handle events bound to the "window" and "document" objects. * * @module eventHandlers */ import Comment from './Comment'; import CommentForm from './CommentForm'; import cd from './cd'; import commentLayers from './commentLayers'; import currentSection from './currentSection'; import navPanel from './navPanel'; import { isInputFocused } from './util'; const beforeUnloadHandlers = {}; /** * Handles the window `resize` event as well as "orientationchange". */ export function handleWindowResize() { commentLayers.redrawIfNecessary(true); navPanel.updateCommentFormButton(); cd.commentForms.forEach((commentForm) => { commentForm.adjustLabels(); }); } /** * Add a condition preventing page unload. * * @param {string} name * @param {Function} condition */ export function addPreventUnloadCondition(name, condition) { beforeUnloadHandlers[name] = (e) => { if (condition()) { e.preventDefault(); e.returnValue = ''; return ''; } }; $(window).on('beforeunload', beforeUnloadHandlers[name]); } /** * Remove a condition preventing page unload. * * @param {string} name */ export function removePreventUnloadCondition(name) { if (beforeUnloadHandlers[name]) { $(window).off('beforeunload', beforeUnloadHandlers[name]); } } /** * Handles the document `keydown` event. * * @param {Event} e */ export function handleGlobalKeyDown(e) { if (!cd.g.isPageActive || cd.util.isPageOverlayOn()) return; if ( // Ctrl+Alt+Q (e.keyCode === 81 && e.ctrlKey && !e.shiftKey && e.altKey) || // Q (e.keyCode === 81 && !e.ctrlKey && !e.shiftKey && !e.altKey && !isInputFocused()) ) { e.preventDefault(); CommentForm.getLastActive()?.quote(e.ctrlKey); } if (navPanel.isMounted()) { // R if (e.keyCode === 82 && !e.ctrlKey && !e.shiftKey && !e.altKey && !isInputFocused()) { navPanel.refreshClick(); } // W if (e.keyCode === 87 && !e.ctrlKey && !e.shiftKey && !e.altKey && !isInputFocused()) { navPanel.goToPreviousNewComment(); } // S if (e.keyCode === 83 && !e.ctrlKey && !e.shiftKey && !e.altKey && !isInputFocused()) { navPanel.goToNextNewComment(); } // F if (e.keyCode === 70 && !e.ctrlKey && !e.shiftKey && !e.altKey && !isInputFocused()) { navPanel.goToFirstUnseenComment(); } } } /** * Register seen comments, update the navigation panel's first unseen button, and update the current * section block. */ export function handleScroll() { // Don't run this more than once in some period, otherwise scrolling may be slowed down. Also, // wait before running, otherwise comments may be registered as seen after a press of Page // Down/Page Up. if (cd.g.dontHandleScroll || cd.g.autoScrollInProgress) return; cd.g.dontHandleScroll = true; // One scroll in Chrome, Firefox with Page Up/Page Down takes a little less than 200ms, but // 200ms proved to be not enough, so we try 300ms. setTimeout(() => { cd.g.dontHandleScroll = false; if (cd.g.isPageActive) { Comment.registerSeen(); navPanel.updateFirstUnseenButton(); navPanel.updateCommentFormButton(); } currentSection.update(); }, 300); } "
"/** * Helpers for heavily used OOUI widgets. * * @module ooui */ import cd from './cd'; /** * @typedef {object} OoUiFieldLayout * @see https://doc.wikimedia.org/oojs-ui/master/js/#!/api/OO.ui.FieldLayout */ /** * @typedef {object} OoUiCheckboxInputWidget * @see https://doc.wikimedia.org/oojs-ui/master/js/#!/api/OO.ui.CheckboxInputWidget */ /** * @typedef {Array} CheckboxFieldReturn * @property {OoUiFieldLayout} 0 * @property {OoUiCheckboxInputWidget} 1 */ /** * Create a checkbox field. * * @param {object} options * @param {string} options.value * @param {string} options.label * @param {boolean} [options.selected] * @param {string} [options.help] * @param {string} [options.tabIndex] * @param {string} [options.title] * @returns {CheckboxFieldReturn} */ export function checkboxField({ value, selected, disabled, label, help, tabIndex, title }) { const checkbox = new OO.ui.CheckboxInputWidget({ value, selected, disabled, tabIndex }); const field = new OO.ui.FieldLayout(checkbox, { label, align: 'inline', help, helpInline: true, title, }); return [field, checkbox]; } /** * @typedef {object} OoUiRadioSelectWidget * @see https://doc.wikimedia.org/oojs-ui/master/js/#!/api/OO.ui.RadioSelectWidget */ /** * @typedef {object} OoUiRadioOptionWidget * @see https://doc.wikimedia.org/oojs-ui/master/js/#!/api/OO.ui.RadioOptionWidget */ /** * @typedef {object} RadioFieldReturn * @property {OoUiFieldLayout} 0 * @property {OoUiRadioSelectWidget} 1 * @property {OoUiRadioOptionWidget} 2 */ /** * Create a radio select field. * * @param {object} options * @param {string} options.label * @param {boolean} [options.selected] * @param {string} [options.help] * @param {object[]} options.options * @returns {RadioFieldReturn} */ export function radioField({ label, selected, help, options }) { const items = options.map((config) => new OO.ui.RadioOptionWidget(config)); const select = new OO.ui.RadioSelectWidget({ items }); const field = new OO.ui.FieldLayout(select, { label, align: 'top', help, helpInline: true, }); select.selectItemByData(selected); return [field, select, ...items]; } /** * @typedef {object} OoUiActionFieldLayout * @see https://doc.wikimedia.org/oojs-ui/master/js/#!/api/OO.ui.ActionFieldLayout */ /** * Create an action field for copying text from an input. * * @param {object} options * @param {object} options.label * @param {object} options.value * @param {object} [options.disabled] * @param {object} [options.help] * @param {object} options.copyCallback * @returns {OoUiActionFieldLayout} */ export function copyActionField({ label, value, disabled = false, help, copyCallback }) { const input = new OO.ui.TextInputWidget({ value, disabled }); const button = new OO.ui.ButtonWidget({ label: cd.s('copy'), icon: 'articles', disabled, }); button.on('click', () => { copyCallback(input.getValue()); }); return new OO.ui.ActionFieldLayout(input, button, { align: 'top', label, help, helpInline: Boolean(help), }); } "
"/** * Modal dialogs. Move section dialog goes in {@link module:Section#move}. * * @module modal */ import CdError from './CdError'; import Comment from './Comment'; import cd from './cd'; import { addPreventUnloadCondition, removePreventUnloadCondition } from './eventHandlers'; import { areObjectsEqual, dealWithLoadingBug, defined, spacesToUnderlines, unique } from './util'; import { checkboxField, copyActionField, radioField } from './ooui'; import { encodeWikilink } from './wikitext'; import { getPageIds, getPageTitles, setGlobalOption, setLocalOption } from './apiWrappers'; import { getSettings, getWatchedSections, setSettings, setWatchedSections } from './options'; import { hideText, underlinesToSpaces, unhideText } from './util'; /** * Create an OOUI window manager. It is supposed to be reused across the script. */ export function createWindowManager() { if (cd.g.windowManager) return; cd.g.windowManager = new OO.ui.WindowManager().on('closing', async (win, closed) => { // We don't have windows that can be reused. await closed; cd.g.windowManager.clearWindows(); }); $(document.body).append(cd.g.windowManager.$element); } /** * Display a OOUI message dialog where user is asked to confirm something. Compared to * `OO.ui.confirm`, returns an action string, not a boolean (which helps to differentiate between * more than two types of answer and also a window close by pressing Esc). * * @param {JQuery|string} message * @param {object} [options={}] * @returns {boolean} */ export async function confirmDialog(message, options = {}) { const defaultOptions = { message, // OO.ui.MessageDialog standard actions: [ { action: 'accept', label: OO.ui.deferMsg('ooui-dialog-message-accept'), flags: 'primary', }, { action: 'reject', label: OO.ui.deferMsg('ooui-dialog-message-reject'), flags: 'safe', }, ], }; const dialog = new OO.ui.MessageDialog(); cd.g.windowManager.addWindows([dialog]); const windowInstance = cd.g.windowManager.openWindow( dialog, Object.assign({}, defaultOptions, options) ); return (await windowInstance.closed)?.action; } /** * Show a confirmation message dialog with a destructive action. * * @param {string} messageName * @param {object} [customOptions={}] * @returns {Promise} */ export function confirmDestructive(messageName, customOptions = {}) { const actions = [ { label: cd.s(`${messageName}-yes`), action: 'accept', flags: ['primary', 'destructive'], }, { label: cd.s(`${messageName}-no`), action: 'reject', flags: 'safe', }, ]; const options = Object.assign({}, { actions }, customOptions); return OO.ui.confirm(cd.s(messageName), options); } /** * Check if there are unsaved changes in a process dialog. * * @param {OoUiProcessDialog} dialog * @returns {boolean} * @private */ function isUnsaved(dialog) { const saveButton = dialog.actions.get({ actions: 'save' })[0]; return saveButton && !saveButton.isDisabled(); } /** * @typedef {object} OoUiProcessDialog * @see https://doc.wikimedia.org/oojs-ui/master/js/#!/api/OO.ui.ProcessDialog */ /** * Confirm closing a process dialog. * * @param {OoUiProcessDialog} dialog * @param {string} dialogCode * @private */ async function confirmCloseDialog(dialog, dialogCode) { if (!isUnsaved(dialog) || (await confirmDestructive(`${dialogCode}-close-confirm`))) { dialog.close({ action: 'close' }); removePreventUnloadCondition('dialog'); } } /** * Standard process dialog error handler. * * @param {OoUiProcessDialog} dialog * @param {CdError|Error} e * @param {string} messageName * @param {boolean} recoverable */ function handleError(dialog, e, messageName, recoverable) { if (e instanceof CdError) { const error = new OO.ui.Error(cd.sParse(messageName), { recoverable }); dialog.showErrors(error); } else { const error = new OO.ui.Error(cd.sParse('error-javascript'), { recoverable: false }); dialog.showErrors(error); } console.warn(e); if (!recoverable) { dialog.$errors .find('.oo-ui-buttonElement-button') .on('click', () => { dialog.close(); }); } dialog.actions.setAbilities({ close: true }); cd.g.windowManager.updateWindowSize(dialog); dialog.popPending(); } /** * Show a settings dialog. */ export async function settingsDialog() { if (cd.util.isPageOverlayOn()) return; /** * @class Subclass of {@link * https://doc.wikimedia.org/oojs-ui/master/js/#!/api/OO.ui.ProcessDialog OO.ui.ProcessDialog} * used to create a settings dialog. * @private */ function SettingsDialog() { SettingsDialog.parent.call(this); } OO.inheritClass(SettingsDialog, OO.ui.ProcessDialog); SettingsDialog.static.name = 'settingsDialog'; SettingsDialog.static.title = cd.s('sd-title'); SettingsDialog.static.actions = [ { action: 'close', modes: ['settings', 'reload', 'dataRemoved'], flags: ['safe', 'close'], disabled: true, }, { action: 'save', modes: ['settings'], label: cd.s('sd-save'), flags: ['primary', 'progressive'], disabled: true, }, { action: 'reset', modes: ['settings'], label: cd.s('sd-reset'), flags: ['destructive'], disabled: true, }, { action: 'reload', modes: ['reload'], label: cd.s('sd-reload'), flags: ['primary', 'progressive'], }, ]; SettingsDialog.static.size = 'large'; SettingsDialog.prototype.getBodyHeight = function () { return 600; }; SettingsDialog.prototype.initialize = async function () { SettingsDialog.parent.prototype.initialize.apply(this, arguments); this.pushPending(); const $loading = $('<div>').text(cd.s('loading-ellipsis')); this.loadingPanel = new OO.ui.PanelLayout({ padded: true, expanded: false, }); this.loadingPanel.$element.append($loading); this.settingsPanel = new OO.ui.PanelLayout({ padded: false, expanded: true, }); const $settingsSaved = $('<p>').text(cd.s('sd-saved')); this.reloadPanel = new OO.ui.PanelLayout({ padded: true, expanded: false, }); this.reloadPanel.$element.append($settingsSaved); const $dataRemoved = $('<p>').text(cd.s('sd-dataremoved')); this.dataRemovedPanel = new OO.ui.PanelLayout({ padded: true, expanded: false, }); this.dataRemovedPanel.$element.append($dataRemoved); this.stackLayout = new OO.ui.StackLayout({ items: [this.loadingPanel, this.settingsPanel, this.reloadPanel, this.dataRemovedPanel], }); this.$body.append(this.stackLayout.$element); }; SettingsDialog.prototype.getSetupProcess = function (data) { return SettingsDialog.parent.prototype.getSetupProcess.call(this, data).next(() => { this.stackLayout.setItem(this.loadingPanel); this.actions.setMode('settings'); }); }; SettingsDialog.prototype.getReadyProcess = function (data) { return SettingsDialog.parent.prototype.getReadyProcess.call(this, data).next(async () => { let settings; try { [settings] = await Promise.all(preparationRequests); } catch (e) { handleError(this, e, 'error-settings-load', false); return; } this.settings = Object.assign({}, cd.settings, settings); // For testing purposes cd.g.settingsForm = this; this.renderForm(this.settings); this.stackLayout.setItem(this.settingsPanel); this.bookletLayout.setPage('general'); this.actions.setAbilities({ close: true }); cd.g.windowManager.updateWindowSize(this); this.popPending(); addPreventUnloadCondition('dialog', () => isUnsaved(dialog)); }); }; SettingsDialog.prototype.getActionProcess = function (action) { if (action === 'save') { return new OO.ui.Process(async () => { this.pushPending(); const settings = this.collectSettings(); try { await setSettings(settings); } catch (e) { handleError(this, e, 'error-settings-save', true); return; } this.stackLayout.setItem(this.reloadPanel); this.actions.setMode('reload'); this.popPending(); }); } else if (action === 'reload') { return new OO.ui.Process(() => { this.close({ action }); location.reload(); }); } else if (action === 'close') { return new OO.ui.Process(async () => { await confirmCloseDialog(this, 'sd'); }); } else if (action === 'reset') { return new OO.ui.Process(async () => { if (await OO.ui.confirm(cd.s('sd-reset-confirm'))) { const currentPageName = this.bookletLayout.getCurrentPageName(); this.renderForm(cd.defaultSettings); this.bookletLayout.setPage(currentPageName); } }); } return SettingsDialog.parent.prototype.getActionProcess.call(this, action); }; SettingsDialog.prototype.renderForm = function (settings) { [this.allowEditOthersCommentsField, this.allowEditOthersCommentsCheckbox] = checkboxField({ value: 'allowEditOthersComments', selected: settings.allowEditOthersComments, label: cd.s('sd-alloweditotherscomments'), }); [this.alwaysExpandAdvancedField, this.alwaysExpandAdvancedCheckbox] = checkboxField({ value: 'alwaysExpandAdvanced', selected: settings.alwaysExpandAdvanced, label: cd.s('sd-alwaysexpandadvanced'), }); const autocompleteMentionsOption = new OO.ui.CheckboxMultioptionWidget({ data: 'mentions', selected: settings.autocompleteTypes.includes('mentions'), label: cd.s('sd-autocompletetypes-mentions'), }); const autocompleteCommentLinksOption = new OO.ui.CheckboxMultioptionWidget({ data: 'commentLinks', selected: settings.autocompleteTypes.includes('commentLinks'), label: cd.s('sd-autocompletetypes-commentlinks'), }); const autocompleteWikilinksOption = new OO.ui.CheckboxMultioptionWidget({ data: 'wikilinks', selected: settings.autocompleteTypes.includes('wikilinks'), label: cd.s('sd-autocompletetypes-wikilinks'), }); const autocompleteTemplatesOption = new OO.ui.CheckboxMultioptionWidget({ data: 'templates', selected: settings.autocompleteTypes.includes('templates'), label: cd.s('sd-autocompletetypes-templates'), }); const autocompleteTagsOption = new OO.ui.CheckboxMultioptionWidget({ data: 'tags', selected: settings.autocompleteTypes.includes('tags'), label: cd.s('sd-autocompletetypes-tags'), }); this.autocompleteTypesMultiselect = new OO.ui.CheckboxMultiselectWidget({ items: [ autocompleteMentionsOption, autocompleteCommentLinksOption, autocompleteWikilinksOption, autocompleteTemplatesOption, autocompleteTagsOption, ], classes: ['cd-autocompleteTypesMultiselect'], }); this.autocompleteTypesField = new OO.ui.FieldLayout(this.autocompleteTypesMultiselect, { label: cd.s('sd-autocompletetypes'), align: 'top', }); [this.autopreviewField, this.autopreviewCheckbox] = checkboxField({ value: 'autopreview', selected: settings.autopreview, label: cd.s('sd-autopreview'), }); [ this.desktopNotificationsField, this.desktopNotificationsSelect, this.desktopNotificationsRadioAll, this.desktopNotificationsRadioNone, this.desktopNotificationsRadioToMe, ] = radioField({ options: [ { label: cd.s('sd-desktopnotifications-radio-all'), data: 'all', }, { label: cd.s('sd-desktopnotifications-radio-tome'), data: 'toMe', }, { label: cd.s('sd-desktopnotifications-radio-none'), data: 'none', }, ], selected: settings.desktopNotifications, label: cd.s('sd-desktopnotifications'), help: cd.s('sd-desktopnotifications-help', location.hostname), }); [this.highlightOwnCommentsField, this.highlightOwnCommentsCheckbox] = checkboxField({ value: 'highlightOwnComments', selected: settings.highlightOwnComments, label: cd.s('sd-highlightowncomments'), }); const insertButtonsSelected = settings.insertButtons .map((button) => Array.isArray(button) ? button.join(';') : button); this.insertButtonsMultiselect = new OO.ui.TagMultiselectWidget({ placeholder: cd.s('sd-insertbuttons-multiselect-placeholder'), allowArbitrary: true, inputPosition: 'outline', tagLimit: 100, selected: insertButtonsSelected, }); this.insertButtonsField = new OO.ui.FieldLayout(this.insertButtonsMultiselect, { label: cd.s('sd-insertbuttons'), align: 'top', help: cd.util.wrap(cd.sParse('sd-insertbuttons-help') + ' ' + cd.sParse('sd-localsetting')), helpInline: true, }); [this.modifyTocField, this.modifyTocCheckbox] = checkboxField({ value: 'modifyToc', selected: settings.modifyToc, label: cd.s('sd-modifytoc'), help: cd.s('sd-modifytoc-help'), }); [ this.notificationsField, this.notificationsSelect, this.notificationsRadioAll, this.notificationsRadioNone, this.notificationsRadioToMe, ] = radioField({ options: [ { label: cd.s('sd-notifications-radio-all'), data: 'all', }, { label: cd.s('sd-notifications-radio-tome'), data: 'toMe', }, { label: cd.s('sd-notifications-radio-none'), data: 'none', }, ], selected: settings.notifications, label: cd.s('sd-notifications'), help: cd.s('sd-notifications-help'), }); this.notificationsBlacklistMultiselect = new mw.widgets.UsersMultiselectWidget({ placeholder: cd.s('sd-notificationsblacklist-multiselect-placeholder'), tagLimit: 100, selected: settings.notificationsBlacklist, }); this.notificationsBlacklistField = ( new OO.ui.FieldLayout(this.notificationsBlacklistMultiselect, { label: cd.s('sd-notificationsblacklist'), align: 'top', }) ); [this.showToolbarField, this.showToolbarCheckbox] = checkboxField({ value: 'showToolbar', selected: settings.showToolbar, label: cd.s('sd-showtoolbar'), }); this.signaturePrefixInput = new OO.ui.TextInputWidget({ value: settings.signaturePrefix, maxlength: 100, }); this.signaturePrefixField = new OO.ui.FieldLayout(this.signaturePrefixInput, { label: cd.s('sd-signatureprefix'), align: 'top', help: cd.util.wrap(cd.sParse('sd-signatureprefix-help') + ' ' + cd.sParse('sd-localsetting')), helpInline: true, }); [this.useTemplateDataField, this.useTemplateDataCheckbox] = checkboxField({ value: 'useTemplateData', selected: settings.useTemplateData, disabled: !settings.autocompleteTypes.includes('templates'), label: cd.s('sd-usetemplatedata'), help: cd.s('sd-usetemplatedata-help'), }); [this.watchOnReplyField, this.watchOnReplyCheckbox] = checkboxField({ value: 'watchOnReply', selected: settings.watchOnReply, label: cd.s('sd-watchonreply'), }); [this.watchSectionOnReplyField, this.watchSectionOnReplyCheckbox] = checkboxField({ value: 'watchSectionOnReply', selected: settings.watchSectionOnReply, label: cd.s('sd-watchsectiononreply'), help: cd.s('sd-watchsectiononreply-help'), }); this.insertButtonsMultiselect.connect(this, { change: 'updateStates' }); this.allowEditOthersCommentsCheckbox.connect(this, { change: 'updateStates' }); this.alwaysExpandAdvancedCheckbox.connect(this, { change: 'updateStates' }); this.autocompleteTypesMultiselect.connect(this, { select: 'updateStates' }); this.autopreviewCheckbox.connect(this, { change: 'updateStates' }); this.desktopNotificationsSelect.connect(this, { select: 'updateStates', choose: 'changeDesktopNotifications', }); this.highlightOwnCommentsCheckbox.connect(this, { change: 'updateStates' }); this.modifyTocCheckbox.connect(this, { change: 'updateStates' }); this.notificationsSelect.connect(this, { select: 'updateStates' }); this.notificationsBlacklistMultiselect.connect(this, { change: 'updateStates' }); this.showToolbarCheckbox.connect(this, { change: 'updateStates' }); this.signaturePrefixInput.connect(this, { change: 'updateStates' }); this.useTemplateDataCheckbox.connect(this, { change: 'updateStates' }); this.watchSectionOnReplyCheckbox.connect(this, { change: 'updateStates' }); this.watchOnReplyCheckbox.connect(this, { change: 'updateStates' }); this.removeDataButton = new OO.ui.ButtonWidget({ label: cd.s('sd-removedata'), flags: ['destructive'], }); this.removeDataButton.connect(this, { click: 'removeData' }); this.removeDataField = new OO.ui.FieldLayout(this.removeDataButton, { label: cd.s('sd-removedata-description'), align: 'top', help: cd.util.wrap(cd.sParse('sd-removedata-help'), { targetBlank: true }), helpInline: true, }); /** * @class Subclass of {@link * https://doc.wikimedia.org/oojs-ui/master/js/#!/api/OO.ui.PageLayout OO.ui.PageLayout} used * to create a "General" booklet page. * @param {string} name * @param {object} [config] * @private */ function GeneralPageLayout(name, config) { GeneralPageLayout.super.call(this, name, config); this.$element.append([ dialog.highlightOwnCommentsField.$element, dialog.allowEditOthersCommentsField.$element, dialog.modifyTocField.$element, ]); } OO.inheritClass(GeneralPageLayout, OO.ui.PageLayout); GeneralPageLayout.prototype.setupOutlineItem = function (outlineItem) { GeneralPageLayout.super.prototype.setupOutlineItem.call(this, outlineItem); this.outlineItem.setLabel(cd.s('sd-page-talkpage')); }; /** * @class Subclass of {@link * https://doc.wikimedia.org/oojs-ui/master/js/#!/api/OO.ui.PageLayout OO.ui.PageLayout} used * to create a "Comment form" booklet page. * @private * @param {string} name * @param {object} [config] */ function CommentFormPageLayout(name, config) { CommentFormPageLayout.super.call(this, name, config); this.$element.append([ dialog.autopreviewField.$element, dialog.watchOnReplyField.$element, dialog.watchSectionOnReplyField.$element, dialog.showToolbarField.$element, dialog.alwaysExpandAdvancedField.$element, dialog.autocompleteTypesField.$element, dialog.useTemplateDataField.$element, dialog.insertButtonsField.$element, dialog.signaturePrefixField.$element, ]); } OO.inheritClass(CommentFormPageLayout, OO.ui.PageLayout); CommentFormPageLayout.prototype.setupOutlineItem = function () { this.outlineItem.setLabel(cd.s('sd-page-commentform')); }; /** * @class Subclass of {@link * https://doc.wikimedia.org/oojs-ui/master/js/#!/api/OO.ui.PageLayout OO.ui.PageLayout} used * to create a "Notifications" booklet page. * @param {string} name * @param {object} [config] * @private */ function NotificationsPageLayout(name, config) { NotificationsPageLayout.super.call(this, name, config); this.$element.append([ dialog.notificationsField.$element, dialog.desktopNotificationsField.$element, dialog.notificationsBlacklistField.$element, ]); } OO.inheritClass(NotificationsPageLayout, OO.ui.PageLayout); NotificationsPageLayout.prototype.setupOutlineItem = function () { this.outlineItem.setLabel(cd.s('sd-page-notifications')); }; /** * @class Subclass of {@link * https://doc.wikimedia.org/oojs-ui/master/js/#!/api/OO.ui.PageLayout OO.ui.PageLayout} used * to create a "Remove data" booklet page. * @param {string} name * @param {object} [config] * @private */ function RemoveDataPageLayout(name, config) { RemoveDataPageLayout.super.call(this, name, config); this.$element.append(dialog.removeDataField.$element); } OO.inheritClass(RemoveDataPageLayout, OO.ui.PageLayout); RemoveDataPageLayout.prototype.setupOutlineItem = function () { this.outlineItem.setLabel(cd.s('sd-page-dataremoval')); }; const generalPage = new GeneralPageLayout('general'); const commentFormPage = new CommentFormPageLayout('commentForm'); const notificationsPage = new NotificationsPageLayout('notifications'); const removeDataPage = new RemoveDataPageLayout('removeData'); this.bookletLayout = new OO.ui.BookletLayout({ outlined: true, }); this.bookletLayout.addPages([generalPage, commentFormPage, notificationsPage, removeDataPage]); this.settingsPanel.$element.empty().append(this.bookletLayout.$element); this.updateStates(); }; SettingsDialog.prototype.collectSettings = function () { const settings = { allowEditOthersComments: this.allowEditOthersCommentsCheckbox.isSelected(), alwaysExpandAdvanced: this.alwaysExpandAdvancedCheckbox.isSelected(), autocompleteTypes: this.autocompleteTypesMultiselect.findSelectedItemsData(), autopreview: this.autopreviewCheckbox.isSelected(), desktopNotifications: ( this.desktopNotificationsSelect.findSelectedItem()?.getData() || 'unknown' ), highlightOwnComments: this.highlightOwnCommentsCheckbox.isSelected(), insertButtons: this.processInsertButtons(), modifyToc: this.modifyTocCheckbox.isSelected(), notifications: this.notificationsSelect.findSelectedItem()?.getData(), notificationsBlacklist: this.notificationsBlacklistMultiselect.getValue(), showToolbar: this.showToolbarCheckbox.isSelected(), signaturePrefix: this.signaturePrefixInput.getValue(), useTemplateData: this.useTemplateDataCheckbox.isSelected(), watchOnReply: this.watchOnReplyCheckbox.isSelected(), watchSectionOnReply: this.watchSectionOnReplyCheckbox.isSelected(), }; settings.haveInsertButtonsBeenAltered = ( JSON.stringify(settings.insertButtons) !== JSON.stringify(cd.defaultSettings.insertButtons) ); return settings; }; SettingsDialog.prototype.processInsertButtons = function () { return this.insertButtonsMultiselect .getValue() .map((value) => { const hidden = []; value = hideText(value, /\\[+;\\]/g, hidden); let [, text, displayedText] = value.match(/^(.*?)(?:;(.+))?$/) || []; if (!text?.replace(/^ +$/, '')) return; text = unhideText(text, hidden); displayedText = displayedText && unhideText(displayedText, hidden); return [text, displayedText].filter(defined); }) .filter(defined); }; SettingsDialog.prototype.updateStates = async function () { this.useTemplateDataCheckbox.setDisabled( !this.autocompleteTypesMultiselect.findItemFromData('templates').isSelected() ); const settings = this.collectSettings(); const save = !areObjectsEqual(settings, this.settings, true); const reset = !areObjectsEqual(settings, cd.defaultSettings, true); this.actions.setAbilities({ save, reset }); }; SettingsDialog.prototype.changeDesktopNotifications = function (option) { if (option.data !== 'none' && Notification.permission !== 'granted') { OO.ui.alert(cd.s('dn-grantpermission')); Notification.requestPermission((permission) => { if (permission !== 'granted') { this.desktopNotificationsSelect.selectItemByData('none'); } }); } }; SettingsDialog.prototype.removeData = async function () { if (await confirmDestructive('sd-removedata-confirm', { size: 'medium' })) { this.pushPending(); try { await Promise.all([ setLocalOption(cd.g.LOCAL_SETTINGS_OPTION_NAME, undefined), setLocalOption(cd.g.VISITS_OPTION_NAME, undefined), setLocalOption(cd.g.WATCHED_SECTIONS_OPTION_NAME, undefined), setGlobalOption(cd.g.SETTINGS_OPTION_NAME, undefined), ]); } catch (e) { handleError(this, e, 'sd-error-removedata', false); return; } localStorage.removeItem('convenientDiscussions-commentForms'); localStorage.removeItem('convenientDiscussions-thanks'); this.stackLayout.setItem(this.dataRemovedPanel); this.actions.setMode('dataRemoved'); this.popPending(); } }; if (dealWithLoadingBug('mediawiki.widgets.UsersMultiselectWidget')) return; // Make requests in advance. const preparationRequests = [ getSettings({ omitLocal: true }), mw.loader.using('mediawiki.widgets.UsersMultiselectWidget'), ]; createWindowManager(); const dialog = new SettingsDialog(); cd.g.windowManager.addWindows([dialog]); cd.g.windowManager.openWindow(dialog); } /** * Show an edit watched sections dialog. */ export async function editWatchedSections() { if (cd.util.isPageOverlayOn()) return; /** * @class Subclass of {@link * https://doc.wikimedia.org/oojs-ui/master/js/#!/api/OO.ui.ProcessDialog OO.ui.ProcessDialog} * used to create an edit watched sections dialog. * @private */ function EditWatchedSectionsDialog() { EditWatchedSectionsDialog.parent.call(this); } OO.inheritClass(EditWatchedSectionsDialog, OO.ui.ProcessDialog); EditWatchedSectionsDialog.static.name = 'editWatchedSectionsDialog'; EditWatchedSectionsDialog.static.title = cd.s('ewsd-title'); EditWatchedSectionsDialog.static.actions = [ { action: 'close', modes: ['edit', 'saved'], flags: ['safe', 'close'], disabled: true, }, { action: 'save', modes: ['edit'], label: cd.s('ewsd-save'), flags: ['primary', 'progressive'], disabled: true, }, ]; EditWatchedSectionsDialog.static.size = 'large'; EditWatchedSectionsDialog.prototype.getBodyHeight = function () { return this.$errorItems ? this.$errors.get(0).scrollHeight : this.$body.get(0).scrollHeight; }; EditWatchedSectionsDialog.prototype.initialize = async function () { EditWatchedSectionsDialog.parent.prototype.initialize.apply(this, arguments); this.pushPending(); const $loading = $('<div>').text(cd.s('loading-ellipsis')); this.loadingPanel = new OO.ui.PanelLayout({ padded: true, expanded: false, }); this.loadingPanel.$element.append($loading); this.sectionsPanel = new OO.ui.PanelLayout({ padded: false, expanded: false, }); const $watchedSectionsSaved = $('<p>').text(cd.s('ewsd-saved')); this.savedPanel = new OO.ui.PanelLayout({ padded: true, expanded: false, }); this.savedPanel.$element.append($watchedSectionsSaved); this.stackLayout = new OO.ui.StackLayout({ items: [this.loadingPanel, this.sectionsPanel, this.savedPanel], }); this.$body.append(this.stackLayout.$element); }; EditWatchedSectionsDialog.prototype.getSetupProcess = function (data) { return EditWatchedSectionsDialog.parent.prototype.getSetupProcess.call(this, data).next(() => { this.stackLayout.setItem(this.loadingPanel); this.actions.setMode('edit'); }); }; EditWatchedSectionsDialog.prototype.getReadyProcess = function (data) { return EditWatchedSectionsDialog.parent.prototype.getReadyProcess.call(this, data) .next(async () => { let pages; try { await watchedSectionsRequest; pages = await getPageTitles( Object.keys(cd.g.watchedSections) .filter((pageId) => cd.g.watchedSections[pageId].length) ); } catch (e) { handleError(this, e, 'ewsd-error-processing', false); return; } // Logically, there should be no coinciding titles between pages, so we don't need a separate // "return 0" condition. pages.sort((page1, page2) => page1.title > page2.title ? 1 : -1); const value = pages // Filter out deleted pages .filter((page) => page.title) .map((page) => ( cd.g.watchedSections[page.pageid] .map((section) => `${page.title}#${section}`) .join('\n') )) .join('\n'); this.input = new OO.ui.MultilineTextInputWidget({ value, rows: 30, classes: ['cd-editWatchedSections-input'], }); this.input.on('change', (newValue) => { this.actions.setAbilities({ save: newValue !== value }); }); this.sectionsPanel.$element.append(this.input.$element); this.stackLayout.setItem(this.sectionsPanel); this.input.focus(); this.actions.setAbilities({ close: true }); // A dirty workaround to avoid a scrollbar appearing when the window is loading. Couldn't // figure out a way to do this out of the box. this.$body.css('overflow', 'hidden'); setTimeout(() => { this.$body.css('overflow', ''); }, 500); cd.g.windowManager.updateWindowSize(this); this.popPending(); addPreventUnloadCondition('dialog', () => isUnsaved(this)); }); }; EditWatchedSectionsDialog.prototype.getActionProcess = function (action) { if (action === 'save') { return new OO.ui.Process(async () => { this.pushPending(); const sections = {}; const pageTitles = []; this.input .getValue() .split('\n') .forEach((section) => { const match = section.match(/^(.+?)#(.+)$/); if (match) { const pageTitle = match[1].trim(); const sectionTitle = match[2].trim(); if (!sections[pageTitle]) { sections[pageTitle] = []; pageTitles.push(pageTitle); } sections[pageTitle].push(sectionTitle); } }); let normalized; let redirects; let pages; try { ({ normalized, redirects, pages } = await getPageIds(pageTitles) || {}); } catch (e) { handleError(this, e, 'ewsd-error-processing', true); return; } // Correct to normalized titles && redirect targets, add to the collection. normalized .concat(redirects) .filter((page) => sections[page.from]) .forEach((page) => { if (!sections[page.to]) { sections[page.to] = []; } sections[page.to].push(...sections[page.from]); delete sections[page.from]; }); const titleToId = {}; pages .filter((page) => page.pageid !== undefined) .forEach((page) => { titleToId[page.title] = page.pageid; }); cd.g.watchedSections = {}; Object.keys(sections) .filter((key) => titleToId[key]) .forEach((key) => { cd.g.watchedSections[titleToId[key]] = sections[key].filter(unique); }); try { await setWatchedSections(); } catch (e) { if (e instanceof CdError) { const { type, code, apiData } = e.data; if (type === 'internal' && code === 'sizeLimit') { const error = new OO.ui.Error( cd.sParse('ewsd-error-maxsize'), { recoverable: false } ); this.showErrors(error); } else { const error = new OO.ui.Error( cd.sParse('ewsd-error-processing'), { recoverable: true } ); this.showErrors(error); } console.warn(type, code, apiData); } else { const error = new OO.ui.Error(cd.sParse('error-javascript'), { recoverable: false }); this.showErrors(error); console.warn(e); } this.popPending(); return; } this.stackLayout.setItem(this.savedPanel); this.actions.setMode('saved'); this.popPending(); }); } else if (action === 'close') { return new OO.ui.Process(async () => { await confirmCloseDialog(this, 'ewsd'); }); } return EditWatchedSectionsDialog.parent.prototype.getActionProcess.call(this, action); }; // Make a request in advance. const watchedSectionsRequest = getWatchedSections(); createWindowManager(); const dialog = new EditWatchedSectionsDialog(); cd.g.windowManager.addWindows([dialog]); cd.g.windowManager.openWindow(dialog); } /** * Copy a link and notify whether the operation was successful. * * @param {string} text * @private */ function copyLinkToClipboardAndNotify(text) { const $textarea = $('<textarea>') .val(text) .appendTo(document.body) .select(); const successful = document.execCommand('copy'); $textarea.remove(); if (successful) { mw.notify(cd.s('copylink-copied')); } else { mw.notify(cd.s('copylink-error'), { type: 'error' }); } } /** * Copy a link to the object or show a copy link dialog. * * @param {Comment|Section} object Comment or section to copy a link to. */ export async function copyLink(object) { if (object.isLinkBeingCopied) return; const isComment = object instanceof Comment; const anchor = encodeWikilink(isComment ? object.anchor : underlinesToSpaces(object.anchor)); const wikilink = `[[${cd.g.CURRENT_PAGE.name}#${anchor}]]`; const decodedCurrentPageUrl = decodeURI(cd.g.CURRENT_PAGE.getUrl()); /** * Is a link to the comment being copied right now (a copy link dialog is opened or a request is * being made to get the diff). * * @name isLinkBeingCopied * @type {boolean} * @memberof module:Comment * @instance */ /** * Is a link to the section being copied right now (a copy link dialog is opened). * * @name isLinkBeingCopied * @type {boolean} * @memberof module:Section * @instance */ object.isLinkBeingCopied = true; const anchorWithUnderlines = spacesToUnderlines(anchor); const url = `https:${mw.config.get('wgServer')}${decodedCurrentPageUrl}#${anchorWithUnderlines}`; const copyCallback = (value) => { copyLinkToClipboardAndNotify(value); dialog.close(); }; let diffField; let shortDiffField; let $diff; if (isComment) { let diffLink; let shortDiffLink; let errorText; try { diffLink = await object.getDiffLink(); shortDiffLink = await object.getDiffLink(true); $diff = await object.generateDiffView(); } catch (e) { if (e instanceof CdError) { const { type } = e.data; if (type === 'network') { errorText = cd.s('cld-diff-error-network'); } else { errorText = cd.s('cld-diff-error'); } } else { errorText = cd.s('cld-diff-error-unknown'); console.warn(e); } } diffField = copyActionField({ value: diffLink || errorText, disabled: !diffLink, label: cd.s('cld-diff'), copyCallback, }); shortDiffField = copyActionField({ value: shortDiffLink || errorText, disabled: !shortDiffLink, label: cd.s('cld-shortdiff'), copyCallback, }); if (dealWithLoadingBug('mediawiki.diff.styles')) { object.isLinkBeingCopied = false; return; } await mw.loader.using('mediawiki.diff.styles'); } let onlyCdWarning; if (isComment) { onlyCdWarning = cd.s('cld-help-onlycd'); } const wikilinkField = copyActionField({ value: wikilink, disabled: !wikilink, label: cd.s('cld-wikilink'), copyCallback, help: onlyCdWarning, }); const currentPageWikilinkField = copyActionField({ value: `[[#${anchor}]]`, label: cd.s('cld-currentpagewikilink'), copyCallback, }); const linkField = copyActionField({ value: url, label: cd.s('cld-link'), copyCallback, help: onlyCdWarning, }); // Workaround, because we don't want the first input to be focused on click almost anywhere in // the dialog, which happens because the whole message is wrapped in the <label> element. const $dummyInput = $('<input>').addClass('cd-hidden'); const $message = $('<div>').append([ diffField?.$element, shortDiffField?.$element, $diff, wikilinkField.$element, currentPageWikilinkField.$element, linkField.$element, ]); $message.children().first().prepend($dummyInput); const dialog = new OO.ui.MessageDialog({ classes: ['cd-copyLinkDialog'], }); cd.g.windowManager.addWindows([dialog]); const windowInstance = cd.g.windowManager.openWindow(dialog, { message: $message, actions: [ { label: cd.s('cld-close'), action: 'close', }, ], size: isComment ? 'larger' : 'large', }); windowInstance.closed.then(() => { object.isLinkBeingCopied = false; }); } /** * Show a modal with content of comment forms that we were unable to restore to the page (because * their target comments/sections disappeared, for example). * * @param {object[]} content * @param {string} [content[].headline] * @param {string} content[].comment * @param {string} content[].summary */ export function rescueCommentFormsContent(content) { const text = content .map((data) => { let text = data.headline !== undefined ? `${cd.s('rd-headline')}: ${data.headline}\n\n` : ''; text += `${cd.s('rd-comment')}: ${data.comment}\n\n${cd.s('rd-summary')}: ${data.summary}`; return text; }) .join('\n\n----\n'); const input = new OO.ui.MultilineTextInputWidget({ value: text, rows: 20, }); const field = new OO.ui.FieldLayout(input, { align: 'top', label: cd.s('rd-intro'), }); const dialog = new OO.ui.MessageDialog(); cd.g.windowManager.addWindows([dialog]); cd.g.windowManager.openWindow(dialog, { message: field.$element, actions: [ { label: cd.s('rd-close'), action: 'close' }, ], size: 'large', }); } /** * Show a message dialog that informs the user that the section/comment was not found. * * @param {string} decodedFragment * @param {Date} date */ export async function notFound(decodedFragment, date) { const title = $('<span>') .addClass('cd-destructiveText') .text(date ? cd.s('deadanchor-comment-title') : cd.s('deadanchor-section-title')); let message = date ? cd.s('deadanchor-comment-text') : cd.s('deadanchor-section-text'); if (cd.g.CURRENT_PAGE.canHaveArchives()) { message += ' ' + cd.s('deadanchor-searchinarchive'); if (await OO.ui.confirm(message, { title })) { let text; if (date) { text = cd.util.formatDate(date); } else { text = decodedFragment .replace(/_/g, ' ') .replace(/"/g, '') .trim(); } const archivePrefix = cd.g.CURRENT_PAGE.getArchivePrefix(); const searchQuery = `"${text}" prefix:${archivePrefix}`; const url = mw.util.getUrl('Special:Search', { profile: 'default', fulltext: 'Search', search: searchQuery, cdcomment: date && decodedFragment, }); location.assign(mw.config.get('wgServer') + url); } } else { OO.ui.alert(message, { title }); } } "
"/** * Methods related to sections. * * @module SectionStatic */ import CdError from './CdError'; import cd from './cd'; import { areObjectsEqual, unique } from './util'; import { editWatchedSections } from './modal'; import { getWatchedSections, setWatchedSections } from './options'; import { reloadPage } from './boot'; let watchPromise = Promise.resolve(); export default { /** * Add a section present on the current page to the watched sections list. * * @param {string} headline * @param {string} [unwatchHeadline] Section to unwatch together with watching the specified * section (used when a section is renamed on the fly in {@link module:Comment#update} or {@link * module:CommentForm#submit}). * @returns {Promise} * @throws {CdError} * @memberof module:Section */ watch(headline, unwatchHeadline) { const watch = async () => { try { await getWatchedSections(); } catch (e) { mw.notify(cd.s('section-watch-error-load'), { type: 'error' }); throw e; } // The section could be added to the watchlist in another tab. if (!cd.g.thisPageWatchedSections.includes(headline)) { cd.g.thisPageWatchedSections.push(headline); } if (unwatchHeadline && cd.g.thisPageWatchedSections.includes(unwatchHeadline)) { cd.g.thisPageWatchedSections.splice( cd.g.thisPageWatchedSections.indexOf(unwatchHeadline), 1 ); } try { await setWatchedSections(); } catch (e) { if (e instanceof CdError) { const { type, code } = e.data; if (type === 'internal' && code === 'sizeLimit') { const $body = cd.util.wrap(cd.sParse('section-watch-error-maxsize'), { callbacks: { 'cd-notification-editWatchedSections': () => { editWatchedSections(); }, }, }); mw.notify($body, { type: 'error', autoHideSeconds: 'long', }); } else { mw.notify(cd.s('section-watch-error-save'), { type: 'error' }); } } else { mw.notify(cd.s('section-watch-error-save'), { type: 'error' }); } throw e; } }; watchPromise = watchPromise.then(watch, watch); return watchPromise; }, /** * Add a section present on the current page to the watched sections list. * * @param {string} headline * @returns {Promise} * @throws {CdError} * @memberof module:Section */ unwatch(headline) { const unwatch = async () => { try { await getWatchedSections(); } catch (e) { mw.notify(cd.s('section-watch-error-load'), { type: 'error' }); throw e; } // The section could be removed from the watchlist in another tab. if (cd.g.thisPageWatchedSections.includes(headline)) { cd.g.thisPageWatchedSections.splice(cd.g.thisPageWatchedSections.indexOf(headline), 1); } if (!cd.g.thisPageWatchedSections.length) { delete cd.g.watchedSections[mw.config.get('wgArticleId')]; } try { await setWatchedSections(); } catch (e) { mw.notify(cd.s('section-watch-error-save'), { type: 'error' }); throw e; } }; watchPromise = watchPromise.then(unwatch, unwatch); return watchPromise; }, /** * Get a section by anchor. * * @param {string} anchor * @returns {?Section} * @memberof module:Section */ getByAnchor(anchor) { if (!cd.sections || !anchor) { return null; } return cd.sections.find((section) => section.anchor === anchor) || null; }, /** * Get sections by headline. * * @param {string} headline * @returns {Section[]} * @memberof module:Section */ getByHeadline(headline) { return cd.sections.filter((section) => section.headline === headline); }, /** * Get a section by several parameters: id (index), headline, anchor, parent tree, first comment * data. At least two parameters must match, not counting id and anchor. * * @param {object} options * @param {number} options.id * @param {string} options.headline * @param {string} options.anchor * @param {string} [options.parentTree] * @param {string} [options.firstCommentAnchor] * @param {boolean} [returnScore] * @returns {?Section} * @memberof module:Section */ search({ id, headline, anchor, parentTree, firstCommentAnchor }, returnScore) { const matches = []; cd.sections.some((section) => { const hasIdMatched = section.id === id; const hasHeadlineMatched = section.headline === headline; const hasAnchorMatched = section.anchor === anchor; let hasParentTreeMatched; if (parentTree) { const sectionParentTree = section.getParentTree().map((section) => section.headline); hasParentTreeMatched = areObjectsEqual(sectionParentTree, parentTree); } else { hasParentTreeMatched = 0.25; } const hasFirstCommentMatched = section.comments[0]?.anchor === firstCommentAnchor; const score = ( hasHeadlineMatched * 1 + hasParentTreeMatched * 1 + hasFirstCommentMatched * 1 + hasAnchorMatched * 0.5 + hasIdMatched * 0.001 ); if (score >= 2) { matches.push({ section, score }); } // Score bigger than 3.5 means it's the best match for sure. Two sections can't have // coinciding anchors, so there can't be 2 sections with the score bigger than 3.5. return score >= 3.5; }); let bestMatch; matches.forEach((match) => { if (!bestMatch || match.score > bestMatch.score) { bestMatch = match; } }); if (returnScore) { return bestMatch || null; } else { return bestMatch ? bestMatch.section : null; } }, /** * Perform extra section-related tasks, including adding the {@link module:Section#isLastSection * isLastSection} property, adding buttons, and binding events. * * @memberof module:Section */ adjust() { cd.sections.forEach((section, i) => { /** * Is the section the last section on the page. * * @name isLastSection * @type {boolean} * @memberof module:Section * @instance */ section.isLastSection = i === cd.sections.length - 1; if (section.isActionable) { // If the next section of the same level has another nesting level (e.g., is inside a <div> // with a specific style), don't add the "Add subsection" button - it would appear in the // wrong place. const nextSameLevelSection = cd.sections .slice(i + 1) .find((otherSection) => otherSection.level === section.level); const isClosed = ( section.elements.length === 2 && cd.config.closedDiscussionClasses ?.some((className) => section.elements[1].classList?.contains(className)) ); if ( isClosed || ( nextSameLevelSection && nextSameLevelSection.headingNestingLevel !== section.headingNestingLevel ) ) { section.$heading.find('.cd-sectionLink-addSubsection').parent().remove(); } else { section.addAddSubsectionButton(); } const isFirstChunkClosed = ( section.elements[1] === section.lastElementInFirstChunk && cd.config.closedDiscussionClasses ?.some((className) => section.lastElementInFirstChunk.classList?.contains(className)) ); const firstContentElement = section.$elements.get(1); // The same for the "Reply" button, but as this button is added to the end of the first // chunk, we look at just the next section, not necessarily of the same level. if ( // The first element is a heading of a subsection. (!firstContentElement || !/^H[1-6]$/.test(firstContentElement.tagName)) && !isFirstChunkClosed && ( !cd.sections[i + 1] || cd.sections[i + 1].headingNestingLevel === section.headingNestingLevel ) ) { section.addReplyButton(); } } }); cd.sections .filter((section) => section.isActionable && section.level === 2) .forEach((section) => { // Section with the last reply button const subsections = section.getChildren(true); const targetSection = subsections.length ? subsections[subsections.length - 1] : section; if (targetSection.$replyButtonLink) { targetSection.$replyButtonLink .on('mouseenter', section.replyButtonHoverHandler) .on('mouseleave', section.replyButtonUnhoverHandler); } }); }, /** * Add new comments notifications to the end of each updated section. * * @param {Map} newCommentsBySection * @memberof module:Section */ addNewCommentsNotifications(newCommentsBySection) { $('.cd-refreshButtonContainer').remove(); newCommentsBySection.forEach((comments, section) => { if (!section || typeof section === 'string') return; const authors = comments .map((comment) => comment.author) .filter(unique); const genders = authors.map((author) => author.getGender()); let commonGender; if (genders.every((gender) => gender === 'female')) { commonGender = 'female'; } else if (genders.every((gender) => gender !== 'female')) { commonGender = 'male'; } else { commonGender = 'unknown'; } const userList = authors.map((user) => user.name).join(', '); const button = new OO.ui.ButtonWidget({ label: cd.s('section-newcomments', comments.length, authors.length, userList, commonGender), framed: false, classes: ['cd-button', 'cd-sectionButton'], }); button.on('click', () => { const commentAnchor = comments[0].anchor; reloadPage({ commentAnchor }); }); let $lastElement; if (section.$addSubsectionButtonContainer && !section.getChildren().length) { $lastElement = section.$addSubsectionButtonContainer; } else if (section.$replyButton) { $lastElement = section.$replyButton.closest('ul, ol, dl'); } else { $lastElement = section.$elements[section.$elements.length - 1]; } $('<div>') .addClass('cd-refreshButtonContainer') .addClass('cd-sectionButtonContainer') .append(button.$element) .insertAfter($lastElement); }); }, /** * Remove sections that can't be found on the page anymore from the watched sections list and save * them to the server. * * @memberof module:Section */ cleanUpWatched() { if (!cd.sections) return; const initialSectionCount = cd.g.thisPageWatchedSections.length; cd.g.originalThisPageWatchedSections = cd.g.thisPageWatchedSections.slice(); cd.g.thisPageWatchedSections = cd.g.thisPageWatchedSections .filter((headline) => cd.sections.some((section) => section.headline === headline)); cd.g.watchedSections[mw.config.get('wgArticleId')] = cd.g.thisPageWatchedSections; if (cd.g.thisPageWatchedSections.length !== initialSectionCount) { setWatchedSections(); } }, }; "
"/** * Section class. * * @module Section */ import Autocomplete from './Autocomplete'; import CdError from './CdError'; import CommentForm from './CommentForm'; import Page from './Page'; import SectionSkeleton from './SectionSkeleton'; import SectionStatic from './SectionStatic'; import cd from './cd'; import toc from './toc'; import { checkboxField } from './ooui'; import { copyLink } from './modal.js'; import { dealWithLoadingBug, defined } from './util'; import { encodeWikilink, endWithTwoNewlines, extractSignatures, findFirstTimestamp, hideDistractingCode, normalizeCode, removeWikiMarkup, } from './wikitext'; import { reloadPage } from './boot'; /** * Class representing a section. * * @augments module:SectionSkeleton */ export default class Section extends SectionSkeleton { /** * Create a section object. * * @param {Parser} parser A relevant instance of {@link module:Parser Parser}. * @param {Element} headingElement * @param {Promise} [watchedSectionsRequest] * @throws {CdError} */ constructor(parser, headingElement, watchedSectionsRequest) { super(parser, headingElement); this.elementPrototypes = cd.g.SECTION_ELEMENT_PROTOTYPES; /** * Section headline element as a jQuery object. * * @type {JQuery} */ this.$headline = $(this.headlineElement); /** * Wiki page that has the source code of the section (may be different from the current page if * the section is transcluded from another page). This property may also be wrong on old version * pages where there are no edit section links. * * @type {string} */ this.sourcePage = cd.g.CURRENT_PAGE; this.editSectionElement = headingElement.querySelector('.mw-editsection'); if (this.editSectionElement) { this.closingBracketElement = this.editSectionElement.lastElementChild; if (!this.closingBracketElement?.classList?.contains('mw-editsection-bracket')) { this.closingBracketElement = null; } // &action=edit, ?action=edit (couldn't figure out where this comes from, but at least one // user has such links), &veaction=editsource. We perhaps could catch veaction=edit, but // there's probably no harm in that. const editLink = this.editSectionElement.querySelector('a[href]'); if (editLink) { /** * URL to edit the section. * * @type {URL} */ this.editUrl = new mw.Uri(editLink.getAttribute('href')); if (this.editUrl) { const sectionNumber = this.editUrl.query.section; if (sectionNumber.startsWith('T-')) { this.sourcePage = new Page(this.editUrl.query.title); } } } else { console.error('Edit link not found.', this); } } /** * Section heading as a jQuery element. * * @type {JQuery} */ this.$heading = $(headingElement); /** * Is the section actionable (is in a closed discussion or on an old version page). * * @type {boolean} */ this.isActionable = ( cd.g.isPageActive && !cd.g.closedDiscussionElements.some((el) => el.contains(headingElement)) ); if (this.isActionable) { this.extendSectionMenu(watchedSectionsRequest); } } /** * Add a "Reply" button to the end of the first chunk of the section. */ addReplyButton() { const replyButton = this.elementPrototypes.replyButton.cloneNode(true); replyButton.firstChild.onclick = () => { this.addReply(); }; // Sections may have "#" in the code as a placeholder for a vote. In this case, we must create // the comment form in the <ol> tag. const isVotePlaceholder = ( this.lastElementInFirstChunk.tagName === 'OL' && this.lastElementInFirstChunk.childElementCount === 1 && this.lastElementInFirstChunk.children[0].classList.contains('mw-empty-elt') ); let tag; let createUl = false; if (this.lastElementInFirstChunk.classList.contains('cd-commentLevel')) { const tagName = this.lastElementInFirstChunk.tagName; if ( tagName === 'UL' || ( tagName === 'OL' && // Check if this is indeed a numbered list with replies as list items, not a numbered list // as part of the user's comment that has their signature technically inside the last // item. ( this.lastElementInFirstChunk.querySelectorAll('ol > li').length === 1 || this.lastElementInFirstChunk.querySelectorAll('ol > li > .cd-signature').length > 1 ) ) ) { tag = 'li'; } else if (tagName === 'DL') { tag = 'dd'; } else { tag = 'li'; createUl = true; } } else { tag = 'li'; if (!isVotePlaceholder) { createUl = true; } } const replyWrapper = document.createElement(tag); replyWrapper.className = 'cd-replyWrapper'; replyWrapper.appendChild(replyButton); // Container contains wrapper that contains element ^_^ let replyContainer; if (createUl) { replyContainer = document.createElement('ul'); replyContainer.className = 'cd-commentLevel cd-sectionButtonContainer'; replyContainer.appendChild(replyWrapper); this.lastElementInFirstChunk.parentNode.insertBefore( replyContainer, this.lastElementInFirstChunk.nextElementSibling ); } else { this.lastElementInFirstChunk.appendChild(replyWrapper); } /** * Reply button on the bottom of the first chunk of the section. * * @type {JQuery|undefined} */ this.$replyButton = $(replyButton); /** * Link element contained in the reply button element. * * @type {JQuery|undefined} */ this.$replyButtonLink = $(replyButton.firstChild); /** * Reply button wrapper. * * @type {JQuery|undefined} */ this.$replyWrapper = $(replyWrapper); /** * Reply button container if present. It may be wrapped around the reply button wrapper. * * @type {JQuery|undefined} */ this.$replyContainer = replyContainer && $(replyContainer); } /** * Add an "Add subsection" button that appears when hovering over a "Reply" button. */ addAddSubsectionButton() { if (this.level !== 2) return; const button = this.elementPrototypes.addSubsectionButton.cloneNode(true); const labelContainer = button.querySelector('.oo-ui-labelElement-label'); if (!labelContainer) return; labelContainer.innerHTML = ''; labelContainer.appendChild( document.createTextNode(cd.s('section-addsubsection-to', this.headline)) ); button.firstChild.onclick = () => { this.addSubsection(); }; const buttonContainer = document.createElement('div'); buttonContainer.className = 'cd-sectionButtonContainer cd-addSubsectionButtonContainer'; buttonContainer.style.display = 'none'; buttonContainer.appendChild(button); const lastElement = this.elements[this.elements.length - 1]; lastElement.parentNode.insertBefore(buttonContainer, lastElement.nextElementSibling); let hideAddSubsectionButtonTimeout; const deferButtonHide = () => { if (!hideAddSubsectionButtonTimeout) { hideAddSubsectionButtonTimeout = setTimeout(() => { this.$addSubsectionButtonContainer.hide(); }, 1000); } }; button.firstChild.onmouseenter = () => { clearTimeout(hideAddSubsectionButtonTimeout); hideAddSubsectionButtonTimeout = null; }; button.firstChild.onmouseleave = () => { deferButtonHide(); }; this.replyButtonHoverHandler = () => { if (this.addSubsectionForm) return; clearTimeout(hideAddSubsectionButtonTimeout); hideAddSubsectionButtonTimeout = null; if (!this.showAddSubsectionButtonTimeout) { this.showAddSubsectionButtonTimeout = setTimeout(() => { this.$addSubsectionButtonContainer.show(); }, 1000); } }; this.replyButtonUnhoverHandler = () => { if (this.addSubsectionForm) return; clearTimeout(this.showAddSubsectionButtonTimeout); this.showAddSubsectionButtonTimeout = null; deferButtonHide(); }; /** * Add subsection button in the end of the section. * * @type {JQuery|undefined} */ this.$addSubsectionButton = $(button); /** * Add subsection button container. * * @type {JQuery|undefined} */ this.$addSubsectionButtonContainer = $(buttonContainer); } /** * Add section menu items. * * @param {Promise} [watchedSectionsRequest] * @fires sectionMenuExtended * @private */ extendSectionMenu(watchedSectionsRequest) { if ( this.comments.length && this.comments[0].isOpeningSection && this.comments[0].openingSectionOfLevel === this.level && (this.comments[0].isOwn || cd.settings.allowEditOthersComments) && this.comments[0].isActionable ) { this.addMenuItem({ label: cd.s('sm-editopeningcomment'), tooltip: cd.s('sm-editopeningcomment-tooltip'), func: () => { this.comments[0].edit(); }, class: 'cd-sectionLink-editOpeningComment', }); } if (this.level >= 2 && this.level !== 6) { this.addMenuItem({ label: cd.s('sm-addsubsection'), tooltip: cd.s('sm-addsubsection-tooltip'), func: () => { this.addSubsection(); }, class: 'cd-sectionLink-addSubsection', }); } if (this.level === 2) { this.addMenuItem({ label: cd.s('sm-move'), tooltip: cd.s('sm-move-tooltip'), func: () => { this.move(); }, class: 'cd-sectionLink-moveSection', }); } if (watchedSectionsRequest) { watchedSectionsRequest .then( () => { this.isWatched = cd.g.thisPageWatchedSections.includes(this.headline); this.addMenuItem({ label: cd.s('sm-unwatch'), tooltip: cd.s('sm-unwatch-tooltip'), func: () => { this.unwatch(); }, class: 'cd-sectionLink-unwatch', visible: this.isWatched, }); this.addMenuItem({ label: cd.s('sm-watch'), tooltip: cd.s('sm-watch-tooltip'), func: () => { this.watch(); }, class: 'cd-sectionLink-watch', visible: !this.isWatched, }); }, () => {} ) .finally(() => { if (this.headline) { // We put this instruction here to make it always appear after the "watch" item. this.addMenuItem({ label: cd.s('sm-copylink'), // We need the event object to be passed to the function. func: this.copyLink.bind(this), class: 'cd-sectionLink-copyLink', tooltip: cd.s('sm-copylink-tooltip'), href: `${cd.g.CURRENT_PAGE.getUrl()}#${this.anchor}`, }); } /** * Section menu has been extneded. * * @event sectionMenuExtended * @type {module:cd~convenientDiscussions} */ mw.hook('convenientDiscussions.sectionMenuExtended').fire(this); }); } } /** * Create an {@link module:Section#addReplyForm add reply form}. * * @param {object|CommentForm} dataToRestore */ addReply(dataToRestore) { // Check for existence in case replying is called from a script of some kind (there is no button // to call it from CD). if (!this.addReplyForm) { /** * Add reply form related to the section. * * @type {CommentForm|undefined} */ this.addReplyForm = dataToRestore instanceof CommentForm ? dataToRestore : new CommentForm({ mode: 'replyInSection', target: this, dataToRestore, }); } const baseSection = this.getBase(); if (baseSection.$addSubsectionButtonContainer) { baseSection.$addSubsectionButtonContainer.hide(); clearTimeout(baseSection.showAddSubsectionButtonTimeout); baseSection.showAddSubsectionButtonTimeout = null; } } /** * Create an {@link module:Section#addSubsectionForm add subsection form} form or focus an * existing one. * * @param {object|CommentForm} dataToRestore */ addSubsection(dataToRestore) { if (this.addSubsectionForm) { this.addSubsectionForm.$element.cdScrollIntoView('center'); this.addSubsectionForm.headlineInput.focus(); } else { /** * Add subsection form related to the section. * * @type {CommentForm|undefined} */ this.addSubsectionForm = dataToRestore instanceof CommentForm ? dataToRestore : new CommentForm({ mode: 'addSubsection', target: this, dataToRestore, }); } } /** * Show a move section dialog. */ move() { /** * @class Subclass of {@link * https://doc.wikimedia.org/oojs-ui/master/js/#!/api/OO.ui.ProcessDialog OO.ui.ProcessDialog} * used to create a move section dialog. * @private */ function MoveSectionDialog() { MoveSectionDialog.parent.call(this); } OO.inheritClass(MoveSectionDialog, OO.ui.ProcessDialog); MoveSectionDialog.static.name = 'moveSectionDialog'; MoveSectionDialog.static.title = cd.s('msd-title'); MoveSectionDialog.static.actions = [ { action: 'close', modes: ['move', 'reload'], flags: ['safe', 'close'], disabled: true, }, { action: 'move', modes: ['move'], label: cd.s('msd-move'), flags: ['primary', 'progressive'], disabled: true, }, { action: 'reload', modes: ['reload'], label: cd.s('msd-reload'), flags: ['primary', 'progressive'], }, ]; MoveSectionDialog.prototype.onTitleInputChange = async function () { let move = true; try { await this.titleInput.getValidity(); } catch (e) { move = false; } this.actions.setAbilities({ move }); }; MoveSectionDialog.prototype.loadSourcePage = async function () { try { await section.getSourcePage().getCode(false); } catch (e) { if (e instanceof CdError) { const { type, code } = e.data; if (type === 'api') { if (code === 'missing') { throw [cd.sParse('msd-error-sourcepagedeleted'), true]; } else { throw [cd.sParse('error-api', code), true]; } } else if (type === 'network') { throw [cd.sParse('error-network'), true]; } } else { throw [cd.sParse('error-javascript'), false]; } } try { section.locateInCode(); } catch (e) { if (e instanceof CdError) { const { code } = e.data; let message; if (code === 'locateSection') { message = cd.sParse('error-locatesection'); } else { message = cd.sParse('error-unknown'); } throw [message, true]; } else { throw [cd.sParse('error-javascript'), false]; } } return { page: section.getSourcePage(), sectionInCode: section.inCode, sectionWikilink: `${section.getSourcePage().name}#${encodeWikilink(section.headline)}`, }; }; MoveSectionDialog.prototype.loadTargetPage = async function (targetPage) { try { await targetPage.getCode(); } catch (e) { if (e instanceof CdError) { const { type, code } = e.data; if (type === 'api') { if (code === 'invalid') { // Must be filtered before submit. throw [cd.sParse('msd-error-invalidpagename'), false]; } else { throw [cd.sParse('error-api', code), true]; } } else if (type === 'network') { throw [cd.sParse('error-network'), true]; } } else { throw [cd.sParse('error-javascript'), false]; } } targetPage.analyzeNewTopicPlacement(); const sectionWikilink = `${targetPage.realName}#${encodeWikilink(section.headline)}`; return { page: targetPage, sectionWikilink, }; }; MoveSectionDialog.prototype.editTargetPage = async function (source, target) { let codeBeginning; let codeEnding; if (cd.config.getMoveTargetPageCode && this.keepLinkCheckbox.isSelected()) { const code = ( cd.config.getMoveTargetPageCode(source.sectionWikilink, cd.g.CURRENT_USER_SIGNATURE) ); if (Array.isArray(code)) { codeBeginning = code[0] + '\n'; codeEnding = '\n' + code[1]; } else { codeBeginning = code; codeEnding = ''; } } else { codeBeginning = ''; codeEnding = ''; } const newSectionCode = endWithTwoNewlines( source.sectionInCode.code.slice(0, source.sectionInCode.relativeContentStartIndex) + codeBeginning + source.sectionInCode.code.slice(source.sectionInCode.relativeContentStartIndex) + codeEnding ); let newCode; if (target.page.areNewTopicsOnTop) { // The page has no sections, so we add to the bottom. if (target.page.firstSectionStartIndex === undefined) { target.page.firstSectionStartIndex = target.page.code.length; } newCode = ( endWithTwoNewlines(target.page.code.slice(0, target.page.firstSectionStartIndex)) + newSectionCode + target.page.code.slice(target.page.firstSectionStartIndex) ); } else { newCode = target.page.code + (target.page.code ? '\n\n' : '') + newSectionCode; } const summaryEnding = this.summaryEndingInput.getValue(); const summary = ( cd.s('es-move-from', source.sectionWikilink) + (summaryEnding ? cd.mws('colon-separator') + summaryEnding : '') ); try { await target.page.edit({ text: newCode, summary: cd.util.buildEditSummary({ text: summary, section: section.headline, }), tags: cd.config.tagName, baserevid: target.page.revisionId, starttimestamp: target.page.queryTimestamp, }); } catch (e) { if (e instanceof CdError) { const { type, details } = e.data; if (type === 'network') { throw [ cd.sParse('msd-error-editingtargetpage') + ' ' + cd.sParse('error-network'), true, ]; } else { let { code, message, logMessage } = details; if (code === 'editconflict') { message += ' ' + cd.sParse('msd-error-editconflict-retry'); } console.warn(logMessage); throw [cd.sParse('msd-error-editingtargetpage') + ' ' + message, true]; } } else { console.warn(e); throw [ cd.sParse('msd-error-editingtargetpage') + ' ' + cd.sParse('error-javascript'), true, ]; } } }; MoveSectionDialog.prototype.editSourcePage = async function (source, target) { const timestamp = findFirstTimestamp(source.sectionInCode.code) || cd.g.SIGN_CODE + '~'; let newSectionCode; if (cd.config.getMoveSourcePageCode && this.keepLinkCheckbox.isSelected()) { const code = cd.config.getMoveSourcePageCode( target.sectionWikilink, cd.g.CURRENT_USER_SIGNATURE, timestamp ); newSectionCode = ( source.sectionInCode.code.slice(0, source.sectionInCode.relativeContentStartIndex) + code + '\n\n' ); } else { newSectionCode = ''; } const newCode = ( source.page.code.slice(0, source.sectionInCode.startIndex) + newSectionCode + source.page.code.slice(source.sectionInCode.endIndex) ); const summaryEnding = this.summaryEndingInput.getValue(); const summary = ( cd.s('es-move-to', target.sectionWikilink) + (summaryEnding ? cd.mws('colon-separator') + summaryEnding : '') ); try { await source.page.edit({ text: newCode, summary: cd.util.buildEditSummary({ text: summary, section: section.headline, }), tags: cd.config.tagName, baserevid: source.page.revisionId, starttimestamp: source.page.queryTimestamp, }); } catch (e) { if (e instanceof CdError) { const { type, details } = e.data; if (type === 'network') { throw [ cd.sParse('msd-error-editingsourcepage') + ' ' + cd.sParse('error-network'), false, ]; } else { let { message, logMessage } = details; console.warn(logMessage); throw [cd.sParse('msd-error-editingsourcepage') + ' ' + message, false]; } } else { console.warn(e); throw [ cd.sParse('msd-error-editingsourcepage') + ' ' + cd.sParse('error-javascript'), false, ]; } } }; MoveSectionDialog.prototype.abort = function (html, recoverable) { const $body = cd.util.wrap(html, { callbacks: { 'cd-message-reloadPage': () => { this.close(); reloadPage(); }, }, }); const error = new OO.ui.Error($body, { recoverable }) this.showErrors(error); this.$errors .find('.oo-ui-buttonElement-button') .on('click', () => { if (recoverable) { cd.g.windowManager.updateWindowSize(this); } else { this.close(); } }); this.actions.setAbilities({ close: true, move: recoverable, }); cd.g.windowManager.updateWindowSize(this); this.popPending(); }; MoveSectionDialog.prototype.getBodyHeight = function () { return this.$errorItems ? this.$errors.get(0).scrollHeight : this.$body.get(0).scrollHeight; }; MoveSectionDialog.prototype.initialize = function () { MoveSectionDialog.parent.prototype.initialize.apply(this, arguments); this.pushPending(); const $loading = $('<div>').text(cd.s('loading-ellipsis')); this.loadingPanel = new OO.ui.PanelLayout({ padded: true, expanded: false, }); this.loadingPanel.$element.append($loading); this.movePanel = new OO.ui.PanelLayout({ padded: true, expanded: false, }); this.reloadPanel = new OO.ui.PanelLayout({ padded: true, expanded: false, }); this.stackLayout = new OO.ui.StackLayout({ items: [this.loadingPanel, this.movePanel, this.reloadPanel], }); this.$body.append(this.stackLayout.$element); }; MoveSectionDialog.prototype.getSetupProcess = function (data) { return MoveSectionDialog.parent.prototype.getSetupProcess.call(this, data).next(() => { this.stackLayout.setItem(this.loadingPanel); this.actions.setMode('move'); }); }; MoveSectionDialog.prototype.getReadyProcess = function (data) { return MoveSectionDialog.parent.prototype.getReadyProcess.call(this, data).next(async () => { try { await Promise.all(preparationRequests); } catch (e) { this.abort(cd.sParse('cf-error-getpagecode'), false); return; } try { section.locateInCode(); } catch (e) { if (e instanceof CdError) { const { data } = e.data; const message = data === 'locateSection' ? cd.sParse('error-locatesection') : cd.sParse('error-unknown'); this.abort(message, false); } else { this.abort(cd.sParse('error-javascript'), false); } return; } const sectionCode = section.inCode.code; this.titleInput = new mw.widgets.TitleInputWidget({ $overlay: this.$overlay, excludeCurrentPage: true, showMissing: false, validate: () => { const title = this.titleInput.getMWTitle(); const page = title && new Page(title); return page && page.name !== section.getSourcePage().name && page.isProbablyTalkPage(); }, }); this.titleField = new OO.ui.FieldLayout(this.titleInput, { label: cd.s('msd-targetpage'), align: 'top', }); this.titleInput.connect(this, { 'change': 'onTitleInputChange' }); this.titleInput.connect(this, { 'enter': () => { if (!this.actions.get({ actions: 'move' })[0].isDisabled()) { this.executeAction('move'); } }, }); if (cd.config.getMoveSourcePageCode || cd.config.getMoveTargetPageCode) { [this.keepLinkField, this.keepLinkCheckbox] = checkboxField({ value: 'keepLink', selected: true, label: cd.s('msd-keeplink'), }); } const $sectionCodeNote = $('<div>'); const code = sectionCode.slice(0, 300) + (sectionCode.length >= 300 ? '...' : ''); $('<pre>') .addClass('cd-moveSectionDialog-code') .text(code) .appendTo($sectionCodeNote); $('<p>') .addClass('cd-moveSectionDialog-codeNote') .text(cd.s('msd-bottom')) .appendTo($sectionCodeNote); this.summaryEndingInput = new OO.ui.TextInputWidget({ // TODO: take into account the whole summary length, updating the maximum value // dynamically. maxLength: 250, }); this.summaryEndingAutocomplete = new Autocomplete({ types: ['mentions', 'wikilinks'], inputs: [this.summaryEndingInput], }); this.summaryEndingField = new OO.ui.FieldLayout(this.summaryEndingInput, { label: cd.s('msd-summaryending'), align: 'top', }); this.movePanel.$element.append([ this.titleField.$element, this.keepLinkField?.$element, $sectionCodeNote, this.summaryEndingField.$element, ].filter(defined)); this.stackLayout.setItem(this.movePanel); this.titleInput.focus(); this.actions.setAbilities({ close: true }); // A dirty workaround to avoid a scrollbar appearing when the window is loading. Couldn't // figure out a way to do this out of the box. this.$body.css('overflow', 'hidden'); setTimeout(() => { this.$body.css('overflow', ''); }, 500); cd.g.windowManager.updateWindowSize(this); this.popPending(); }); }; MoveSectionDialog.prototype.getActionProcess = function (action) { if (action === 'move') { return new OO.ui.Process(async () => { this.pushPending(); this.titleInput.$input.blur(); let targetPage = new Page(this.titleInput.getMWTitle()); // Should be ruled out by making the button disabled. if ( targetPage.name === section.getSourcePage().name || !targetPage.isProbablyTalkPage() ) { this.abort(cd.sParse('msd-error-wrongpage'), false); return; } let source; let target; try { [source, target] = await Promise.all([ this.loadSourcePage(), this.loadTargetPage(targetPage), ]); await this.editTargetPage(source, target); await this.editSourcePage(source, target); } catch (e) { this.abort(...e); return; } this.reloadPanel.$element.append( cd.util.wrap(cd.sParse('msd-moved', target.sectionWikilink), { tagName: 'div' }) ); this.stackLayout.setItem(this.reloadPanel); this.actions.setMode('reload'); this.popPending(); }); } else if (action === 'reload') { return new OO.ui.Process(() => { this.close({ action }); reloadPage({ sectionAnchor: section.anchor }); }); } else if (action === 'close') { return new OO.ui.Process(() => { this.close(); }); } return MoveSectionDialog.parent.prototype.getActionProcess.call(this, action); }; if (dealWithLoadingBug('mediawiki.widgets')) return; // Make requests in advance const preparationRequests = [ this.getSourcePage().getCode(), mw.loader.using('mediawiki.widgets'), ]; const section = this; const dialog = new MoveSectionDialog(); cd.g.windowManager.addWindows([dialog]); cd.g.windowManager.openWindow(dialog); } /** * Update the watch/unwatch section links visibility. * * @private */ updateWatchMenuItems() { if (this.isWatched) { this.$heading.find('.cd-sectionLink-unwatch').parent().show(); this.$heading.find('.cd-sectionLink-watch').parent().hide(); } else { this.$heading.find('.cd-sectionLink-watch').parent().show(); this.$heading.find('.cd-sectionLink-unwatch').parent().hide(); } } /** * Add the section to the watched sections list. * * @param {boolean} [silent=false] Don't show a notification or change UI unless there is an * error. * @param {string} [renamedFrom] If the section was renamed, the previous section headline. It is * unwatched together with watching the current headline if there is no other coinciding * headlines on the page. */ watch(silent = false, renamedFrom) { const sections = Section.getByHeadline(this.headline); let $links; if (!silent) { $links = $(sections.map((section) => section.$heading.find('.cd-sectionLink-watch').get(0))); if ($links.hasClass('cd-link-pending')) { return; } else { $links.addClass('cd-link-pending'); } } let unwatchHeadline; if (renamedFrom && !Section.getByHeadline(renamedFrom).length) { unwatchHeadline = renamedFrom; } Section.watch(this.headline, unwatchHeadline) .finally(() => { if ($links) { $links.removeClass('cd-link-pending'); } }) .then( () => { sections.forEach((section) => { section.isWatched = true; section.updateWatchMenuItems(); section.updateTocLink(); }); if (!silent) { let text = cd.sParse('section-watch-success', this.headline); let autoHideSeconds; if ($('#ca-watch').length) { text += ' ' + cd.sParse('section-watch-pagenotwatched'); autoHideSeconds = 'long'; } mw.notify(cd.util.wrap(text), { autoHideSeconds }); } }, () => {} ); } /** * Remove the section from the watched sections list. * * @param {boolean} [silent=false] Don't show a notification or change UI unless there is an * error. */ unwatch(silent = false) { const sections = Section.getByHeadline(this.headline); let $links; if (!silent) { $links = $( sections.map((section) => section.$heading.find('.cd-sectionLink-unwatch').get(0)) ); if ($links.hasClass('cd-link-pending')) { return; } else { $links.addClass('cd-link-pending'); } } Section.unwatch(this.headline) .finally(() => { if ($links) { $links.removeClass('cd-link-pending'); } }) .then( () => { sections.forEach((section) => { section.isWatched = false; section.updateWatchMenuItems(); section.updateTocLink(); }); const watchedAncestorHeadline = this.getClosestWatchedSection()?.headline; if (!silent || watchedAncestorHeadline) { let text = cd.sParse('section-unwatch-success', this.headline); let autoHideSeconds; if (watchedAncestorHeadline) { text += ' ' + cd.sParse('section-unwatch-stillwatched', watchedAncestorHeadline); autoHideSeconds = 'long'; } mw.notify(cd.util.wrap(text), { autoHideSeconds }); } }, () => {} ); } /** * Copy a link to the section or open a copy link dialog. * * @param {Event} e */ copyLink(e) { e.preventDefault(); copyLink(this); } /** * Locate the section in the page source code and set the result to the `inCode` property. * * @throws {CdError} */ locateInCode() { this.inCode = null; // Collect all possible matches const matches = this.searchInCode(this.getSourcePage().code); let bestMatch; matches.forEach((match) => { if (!bestMatch || match.score > bestMatch.score) { bestMatch = match; } }); if (!bestMatch) { throw new CdError({ type: 'parse', code: 'locateSection', }); } this.inCode = bestMatch; } /** * Modify a page code string related to the section in accordance with an action. * * @param {object} options * @param {string} options.pageCode * @param {string} options.action * @param {string} options.commentForm * @returns {string} */ modifyCode({ pageCode, action, commentForm }) { if (action === 'replyInSection') { // Detect the last section comment's indentation characters if needed or a vote / bulleted // reply placeholder. const [, replyPlaceholder] = this.inCode.firstChunkCode.match(/\n([#*]) *\n+$/) || []; if (replyPlaceholder) { this.inCode.lastCommentIndentationChars = replyPlaceholder; } else { const lastComment = this.comments[this.comments.length - 1]; if ( lastComment && (commentForm.containerListType === 'ol' || cd.config.indentationCharMode === 'mimic') ) { try { lastComment.locateInCode(); } finally { if ( lastComment.inCode && ( !lastComment.inCode.indentationChars.startsWith('#') || // For now we use the workaround with commentForm.containerListType to make sure "#" // is a part of comments organized in a numbered list, not of a numbered list _in_ // the target comment. commentForm.containerListType === 'ol' ) ) { this.inCode.lastCommentIndentationChars = lastComment.inCode.indentationChars; } } } } } let commentCode; if (!commentCode && commentForm) { ({ commentCode } = commentForm.commentTextToCode('submit')); } let newPageCode; let codeBeforeInsertion; switch (action) { case 'replyInSection': { codeBeforeInsertion = pageCode.slice(0, this.inCode.firstChunkContentEndIndex); const codeAfterInsertion = pageCode.slice(this.inCode.firstChunkContentEndIndex); newPageCode = codeBeforeInsertion + commentCode + codeAfterInsertion; break; } case 'addSubsection': { codeBeforeInsertion = endWithTwoNewlines(pageCode.slice(0, this.inCode.contentEndIndex)); const codeAfterInsertion = pageCode.slice(this.inCode.contentEndIndex).trim(); newPageCode = codeBeforeInsertion + commentCode + codeAfterInsertion; break; } } return { newPageCode, codeBeforeInsertion, commentCode }; } /** * Get the first upper level section relative to the current section that is watched. * * @param {boolean} [includeCurrent=false] Check the current section too. * @returns {?Section} */ getClosestWatchedSection(includeCurrent = false) { for ( let otherSection = includeCurrent ? this : this.getParent(); otherSection; otherSection = otherSection.getParent() ) { if (otherSection.isWatched) { return otherSection; } } return null; } /** * Load the section code. * * @throws {CdError|Error} */ async getCode() { try { await this.getSourcePage().getCode(); this.locateInCode(); } catch (e) { if (e instanceof CdError) { throw new CdError(Object.assign({}, { message: cd.s('cf-error-getpagecode') }, e.data)); } else { throw e; } } } /** * Add an item to the section menu (to the right from the section headline). * * @param {object} item * @param {string} item.label Item label. * @param {string} [item.href] Value of the item href attribute. * @param {Function} [item.func] Function to execute on click. * @param {string} [item.class] Link class name. * @param {string} [item.tooltip] Tooltip text. * @param {boolean} [item.visible=true] Should the item be visible. */ addMenuItem({ label, href, func, class: className, tooltip, visible = true, }) { if (this.closingBracketElement) { const wrapper = document.createElement('span'); wrapper.className = 'cd-sectionLinkWrapper'; if (!visible) { wrapper.style.display = 'none'; } const a = document.createElement('a'); a.textContent = label; if (href) { a.href = href; } if (func) { a.onclick = func; } a.className = 'cd-sectionLink'; if (className) { a.className += ' ' + className; } if (tooltip) { a.title = tooltip; } wrapper.appendChild(a); this.editSectionElement.insertBefore(wrapper, this.closingBracketElement); } } /** * Section elements as a jQuery object. * * Uses a getter mostly for unification with {@link module:Comment#$elements}. * * @type {JQuery} */ get $elements() { if (this.cached$elements === undefined) { this.cached$elements = $(this.elements); } return this.cached$elements; } set $elements(value) { this.cached$elements = value; this.elements = value.get(); } /** * Search for the section in the source code and return possible matches. * * @param {string} pageCode * @returns {object} * @private */ searchInCode(pageCode) { const firstComment = this.comments[0]; const headline = normalizeCode(this.headline); const adjustedPageCode = hideDistractingCode(pageCode); const sectionHeadingRegexp = /^((=+)(.*)\2[ \t\x01\x02]*)\n/gm; const matches = []; const headlines = []; let sectionIndex = 0; let sectionHeadingMatch; while ((sectionHeadingMatch = sectionHeadingRegexp.exec(adjustedPageCode))) { const thisHeadline = normalizeCode(removeWikiMarkup(sectionHeadingMatch[3])); const hasHeadlineMatched = thisHeadline === headline; let numberOfPreviousHeadlinesToCheck = 3; const previousHeadlinesInCode = headlines .slice(-numberOfPreviousHeadlinesToCheck) .reverse(); const previousHeadlines = cd.sections .slice(Math.max(0, this.id - numberOfPreviousHeadlinesToCheck), this.id) .reverse() .map((section) => section.headline); const havePreviousHeadlinesMatched = previousHeadlines .every((headline, i) => normalizeCode(headline) === previousHeadlinesInCode[i]); headlines.push(thisHeadline); // Matching section index is one of the most unreliable ways to tell matching sections as // sections may be added and removed from the page, so we don't rely on it very much. const hasSectionIndexMatched = this.id === sectionIndex; sectionIndex++; // Get the section content const fullHeadingMatch = sectionHeadingMatch[1]; const equalSigns = sectionHeadingMatch[2]; const equalSignsPattern = `={1,${equalSigns.length}}`; const codeFromSection = pageCode.slice(sectionHeadingMatch.index); const adjustedCodeFromSection = adjustedPageCode.slice(sectionHeadingMatch.index); const sectionMatch = ( adjustedCodeFromSection.match(new RegExp( // Will fail at "===" or the like. '(' + mw.util.escapeRegExp(fullHeadingMatch) + '[^]*?\\n)' + equalSignsPattern + '[^=].*=+[ \\t\\x01\\x02]*\\n' )) || codeFromSection.match(new RegExp( '(' + mw.util.escapeRegExp(fullHeadingMatch) + '[^]*$)' )) ); // To simplify the workings of the "replyInSection" mode we don't consider terminating line // breaks to be a part of the first chunk of the section (i.e., the section subdivision before // the first heading). const firstChunkMatch = ( adjustedCodeFromSection.match(new RegExp( // Will fail at "===" or the like. '(' + mw.util.escapeRegExp(fullHeadingMatch) + '[^]*?\\n)\\n*' + // Any next heading. '={1,6}' + '[^=].*=+[ \\t\\x01\\x02]*\n' )) || codeFromSection.match(new RegExp( '(' + mw.util.escapeRegExp(fullHeadingMatch) + '[^]*$)' )) ); const code = ( sectionMatch && codeFromSection.substr(sectionMatch.index, sectionMatch[1].length) ); const firstChunkCode = ( firstChunkMatch && codeFromSection.substr(firstChunkMatch.index, firstChunkMatch[1].length) ); if (!code || !firstChunkCode) { console.log(`Couldn't read the "${thisHeadline}" section contents.`); continue; } const signatures = extractSignatures(code); let hasFirstCommentMatched; if (signatures.length) { hasFirstCommentMatched = ( Boolean(firstComment) && ( signatures[0].timestamp === firstComment.timestamp || signatures[0].author === firstComment.author ) ); } else { // There's no comments neither in the code nor on the page. hasFirstCommentMatched = !this.comments.length; } const score = ( hasHeadlineMatched * 1 + hasFirstCommentMatched * 1 + hasSectionIndexMatched * 0.5 + // Shouldn't give too high a weight to this factor as it is true for every first section. havePreviousHeadlinesMatched * 0.25 ); if (score <= 1) continue; const startIndex = sectionHeadingMatch.index; const endIndex = startIndex + code.length; const contentStartIndex = sectionHeadingMatch.index + sectionHeadingMatch[0].length; const firstChunkEndIndex = startIndex + firstChunkCode.length; const relativeContentStartIndex = contentStartIndex - startIndex; let firstChunkContentEndIndex = firstChunkEndIndex; let contentEndIndex = endIndex; cd.config.keepInSectionEnding.forEach((regexp) => { const firstChunkMatch = firstChunkCode.match(regexp); if (firstChunkMatch) { // "1" accounts for the first line break. firstChunkContentEndIndex -= firstChunkMatch[0].length - 1; } const codeMatch = code.match(regexp); if (codeMatch) { // "1" accounts for the first line break. contentEndIndex -= codeMatch[0].length - 1; } }); // Sections may have "#" or "*" as a placeholder for a vote or bulleted reply. In this case, // we must use that "#" or "*" in the reply. As for the placeholder, perhaps we should remove // it, but as for now, we keep it because if: // * the placeholder character is "*", // * cd.config.indentationCharMode is 'unify', // * cd.config.defaultIndentationChar is ':', and // * there is more than one reply, // the next reply would go back to ":", not "*" as should be. const match = firstChunkCode.match(/\n([#*] *\n+)$/); if (match) { firstChunkContentEndIndex -= match[1].length; } matches.push({ hasHeadlineMatched, hasFirstCommentMatched, hasSectionIndexMatched, havePreviousHeadlinesMatched, score, startIndex, endIndex, code, contentStartIndex, contentEndIndex, relativeContentStartIndex, firstChunkEndIndex, firstChunkContentEndIndex, firstChunkCode, }); // Maximal possible score if (score === 2.75) break; } return matches; } /** * Get the wiki page that has the source code of the section (may be different from the current * page if the section is transcluded from another page). * * @returns {Page} */ getSourcePage() { return this.sourcePage; } /** * Get the base section, i.e. a section of level 2 that is an ancestor of the section, or the * section itself if it is of level 2 (even if there is a level 1 section) or if there is no * higher level section (the current section may be of level 3 or 1, for example). * * @returns {Section} */ getBase() { if (this.level <= 2) { return this; } return ( cd.sections .slice(0, this.id) .reverse() .find((section) => section.level === 2) || this ); } /** * Get the collection of the section's subsections. * * @param {boolean} [indirect=false] Whether to include subsections of subsections and so on. * @returns {Section[]} */ getChildren(indirect = false) { const children = []; let haveMetDirect = false; cd.sections .slice(this.id + 1) .some((section) => { if (section.level > this.level) { // If, say, a level 4 section directly follows a level 2 section, it should be considered // a child. This is why we need the haveMetDirect variable. if (section.level === this.level + 1) { haveMetDirect = true; } if (indirect || section.level === this.level + 1 || !haveMetDirect) { children.push(section); } } else { return true; } }); return children; } /** * Get the TOC item for the section if present. * * @returns {?object} */ getTocItem() { return toc.getItem(this.anchor) || null; } /** * Bold/unbold the section's TOC link and update the `title` attribute. */ updateTocLink() { if (!cd.settings.modifyToc) return; const tocItem = this.getTocItem(); if (!tocItem) return; if (this.isWatched) { tocItem.$link .addClass('cd-toc-watched') .attr('title', cd.s('toc-watched')); } else { tocItem.$link .removeClass('cd-toc-watched') .removeAttr('title'); } } } Object.assign(Section, SectionStatic); "
"/** * Section skeleton class. * * @module SectionSkeleton */ import CdError from './CdError'; import cd from './cd'; import { TreeWalker } from './treeWalker'; /** * Class containing the main properties of a section. This class is the only one used in the worker * context for sections. */ export default class SectionSkeleton { /** * Create a section skeleton instance. * * @param {Parser} parser * @param {Element} headingElement */ constructor(parser, headingElement) { this.parser = parser; /** * Headline element. * * @type {Element} */ this.headlineElement = this.parser.context.getElementByClassName(headingElement, 'mw-headline'); if (!this.headlineElement) { throw new CdError(); } /** * Section anchor. * * @type {string} */ this.anchor = this.headlineElement.getAttribute('id'); this.parseHeadline(); const levelMatch = headingElement.tagName.match(/^H([1-6])$/); /** * Section level. A level is a number representing the number of `=` characters in the section * heading's code. * * @type {number} */ this.level = levelMatch && Number(levelMatch[1]); const treeWalker = new TreeWalker( cd.g.rootElement, (node) => ( !['STYLE', 'LINK'].includes(node.tagName) && // .cd-sectionButtonContainer elements are added to level 2 sections, which means they won't // have them as elements but their last subsections can if they are included. So we better // don't include them at all. !node.classList.contains('cd-sectionButtonContainer') ), true, headingElement ); this.headingNestingLevel = 0; while (treeWalker.parentNode()) { this.headingNestingLevel++; } treeWalker.currentNode = headingElement; const elements = [headingElement]; const levelRegexp = new RegExp(`^H[1-${this.level}]$`); // The last element before the next heading if we start from the heading of this section. That // heading which may be a part of the next section of the same level, or the subsection of this // section. let hasSubsections = false; while (treeWalker.nextSibling() && !levelRegexp.test(treeWalker.currentNode.tagName)) { if ( this.lastElementInFirstChunk === undefined && /^H[2-6]$/.test(treeWalker.currentNode.tagName) ) { hasSubsections = true; this.lastElementInFirstChunk = elements[elements.length - 1]; } elements.push(treeWalker.currentNode); } /** * Last element in the first chunk of the section, i.e. all elements up to the first subheading * if it is present, or all elements if it is not. * * @type {Element} */ this.lastElementInFirstChunk = this.lastElementInFirstChunk || elements[elements.length - 1]; // We only need the first and the last comment parts to determine comments in the section. let firstCommentPart; let lastCommentPart; if (elements[1]) { treeWalker.currentNode = elements[elements.length - 1]; while (treeWalker.lastChild()); const lastNode = treeWalker.currentNode; treeWalker.currentNode = elements[1]; do { if (treeWalker.currentNode.classList.contains('cd-commentPart')) { firstCommentPart = treeWalker.currentNode; } } while (!firstCommentPart && treeWalker.currentNode !== lastNode && treeWalker.nextNode()); treeWalker.currentNode = lastNode; do { if (treeWalker.currentNode.classList.contains('cd-commentPart')) { lastCommentPart = treeWalker.currentNode; } } while ( !lastCommentPart && treeWalker.currentNode !== elements[1] && treeWalker.previousNode() ); } if (firstCommentPart) { const firstCommentPartId = Number(firstCommentPart.getAttribute('data-comment-id')); const lastCommentPartId = Number(lastCommentPart.getAttribute('data-comment-id')); this.comments = cd.comments.slice(firstCommentPartId, lastCommentPartId + 1); if (hasSubsections) { const endIndex = this.comments.findIndex((comment) => !( this.parser.context.follows(this.lastElementInFirstChunk, comment.elements[0]) || this.lastElementInFirstChunk.contains(comment.elements[0]) )); this.commentsInFirstChunk = this.comments.slice(0, endIndex || 0); } this.comments[0].followsHeading = true; } /** * Section ID. Same as the section index in {@link module:cd~convenientDiscussions.sections * convenientDiscussions.sections}. * * @type {number} */ this.id = cd.sections.length; /** * Comments contained in the section. * * @type {Comment[]} */ this.comments = this.comments || []; /** * Comments contained in the first chunk of the section, i.e. all elements up to the first * subheading if it is present, or all elements if it is not. * * @type {Comment[]} */ this.commentsInFirstChunk = this.commentsInFirstChunk || this.comments; /** * Section elements. * * @type {Element[]} */ this.elements = elements; } /** * Parse the headline of the section and fill the `headline` property, containing no HTML tags. */ parseHeadline() { const classesToFilter = ['mw-headline-number', ...cd.config.foreignElementsInHeadlinesClasses]; const nodes = Array.from(this.headlineElement.childNodes).filter((node) => ( node.nodeType !== Node.ELEMENT_NODE || !classesToFilter.some((className) => node.classList.contains(className)) )); /** * Section headline as it appears on the page. * * Foreign elements can get there, add the classes of these elements to {@link * module:defaultConfig.foreignElementsInHeadlinesClasses} to filter them out. * * @type {string} */ this.headline = nodes.map((node) => node.textContent).join('').trim(); } /** * Get the parent section of the section. * * @param {boolean} [ignoreFirstLevel=true] Don't consider sections of the first level parent * sections; stop at second level sections. * @returns {?SectionSkeleton} */ getParent(ignoreFirstLevel = true) { if (ignoreFirstLevel && this.level <= 2) { return null; } return ( cd.sections .slice(0, this.id) .reverse() .find((section) => section.level < this.level) || null ); } /** * Get the ancestors of the section as an array, starting with the parent section. * * @returns {Array} */ getParentTree() { if (!this.cachedParentTree) { this.cachedParentTree = []; let section = this; while ((section = section.getParent(false))) { this.cachedParentTree.push(section); } } return this.cachedParentTree; } } "
"/** * Comment form class. * * @module CommentForm */ import Autocomplete from './Autocomplete'; import CdError from './CdError'; import Comment from './Comment'; import CommentFormStatic from './CommentFormStatic'; import Page from './Page'; import Section from './Section'; import cd from './cd'; import navPanel from './navPanel'; import { addNotification, reloadPage, removeLoadingOverlay, saveSession } from './boot'; import { checkboxField } from './ooui'; import { confirmDestructive, settingsDialog } from './modal'; import { defined, findLastIndex, handleApiReject, hideText, insertText, isInputFocused, nativePromiseState, removeDoubleSpaces, restoreScrollPosition, saveScrollPosition, unhideText, unique, } from './util'; import { extractSignatures, hideSensitiveCode, removeWikiMarkup } from './wikitext'; import { generateCommentAnchor } from './timestamp'; import { parseCode, unknownApiErrorText } from './apiWrappers'; let commentFormsCounter = 0; /** Class representing a comment form. */ export default class CommentForm { /** * Object specifying configuration to preload data into the comment form. It is extracted from the * "Add section" link/button target. * * @typedef {object} PreloadConfig * @property {string} [editIntro] Edit intro page name. * @property {string} [commentTemplate] Comment template's page name. * @property {string} [headline] Subject/headline. * @property {string} [summary] Edit summary. */ /** * Create a comment form. * * @param {object} config * @param {string} config.mode `'reply'`, `'replyInSection'`, `'edit'`, `'addSubsection'`, or * `'addSection'`. * @param {Comment|Section|Page} config.target Comment, section, or page that the form is related * to. * @param {object} [config.dataToRestore] Data saved in the previous session. * @param {PreloadConfig} [config.preloadConfig] Configuration to preload data into the form. * @param {boolean} [config.isNewTopicOnTop] When adding a topic, whether it should be on top. * @throws {CdError} * @fires commentFormCreated * @fires commentFormModulesReady */ constructor({ mode, target, dataToRestore, preloadConfig, isNewTopicOnTop }) { /** * Form mode. `'reply'`, `'replyInSection'`, `'edit'`, `'addSubsection'`, or `'addSection'`. * * @type {string} */ this.mode = mode; this.setTargets(target); /** * Configuration to preload data into the form. * * @type {object|undefined} */ this.preloadConfig = preloadConfig; /** * When adding a topic, whether it should be on top. * * @type {boolean|undefined} */ this.isNewTopicOnTop = isNewTopicOnTop; if (this.target instanceof Comment) { this.sectionHeadline = this.target.getSection()?.headline; } else if (this.target instanceof Section) { this.sectionHeadline = this.target.headline; } /** * Form ID. * * @type {number} */ this.id = commentFormsCounter++; /** * Was the summary altered manually. * * @type {boolean} */ this.isSummaryAltered = dataToRestore ? dataToRestore.isSummaryAltered : false; if (this.mode === 'addSection') { const title = cd.g.CURRENT_PAGE.title.replace(/\//g, '-'); let code = ( '<div class="cd-editnotice">' + `{{MediaWiki:Editnotice-${cd.g.CURRENT_NAMESPACE_NUMBER}}}` + '</div>\n' + '<div class="cd-editnotice">' + `{{MediaWiki:Editnotice-${cd.g.CURRENT_NAMESPACE_NUMBER}-${title}}}` + '</div>\n' ); if (this.preloadConfig?.editIntro) { code = `<div class="cd-editintro">{{${this.preloadConfig.editIntro}}}</div>\n` + code; } parseCode(code, { title: cd.g.CURRENT_PAGE.name }).then((result) => { const mediaWikiNamespace = mw.config.get('wgFormattedNamespaces')[8]; this.$messageArea .append(result.html) .cdAddCloseButton() .find(`.cd-editnotice > a.new[title^="${mediaWikiNamespace}:Editnotice-"]`) .parent() .remove(); // We mirror the functionality of the "ext.charinsert" module to keep the undo/redo // functionality. this.$messageArea .find('.mw-charinsert-item') .each((i, el) => { const $el = $(el); const pre = $el.data('mw-charinsert-start'); const post = $el.data('mw-charinsert-end'); $el .on('click', () => { this.encapsulateSelection({ pre, post }); }) .data('mw-charinsert-done', true); }); mw.hook('wikipage.content').fire(this.$messageArea); }); } this.createContents(dataToRestore); this.addEvents(); this.initAutocomplete(); // This call and the subsequent `restoreScrollPosition()` call is, first of all, for // compensation of the Chrome 84.0.4147.89 behavior where the viewport jumps down all of a // sudden. saveScrollPosition(); this.addToPage(); /** * @typedef {object} Operation * @property {string} type Operation type. One of `'load'`, `'preview'`, `'viewChanges'`, and * `'submit'`. * @property {boolean} [affectHeadline=false] Should the headline input be shown as pending. * @property {boolean} [isClosed] Is the operation closed (settled). * @property {boolean} [isDelayed] Is the operation delayed. */ /** * A list of current operations. * * @type {Operation[]} */ this.operations = []; cd.commentForms.push(this); restoreScrollPosition(); navPanel.updateCommentFormButton(); if (dataToRestore) { this.originalComment = dataToRestore.originalComment; this.originalHeadline = dataToRestore.originalHeadline; if (dataToRestore.lastFocused) { /** * The date when the comment form was focused last time. * * @type {Date|undefined} */ this.lastFocused = new Date(dataToRestore.lastFocused); } } else { this.$element.cdScrollIntoView('center', true, () => { this[this.headlineInput ? 'headlineInput' : 'commentInput'].focus(); }); if (this.mode === 'edit') { const currentOperation = this.registerOperation({ type: 'load' }); this.target.getCode(true).then( () => { let commentText = this.target.codeToText(); if (this.target.inCode.inSmallFont) { commentText = `<small>${commentText}</small>`; } const headline = this.target.inCode.headlineCode; this.commentInput.setValue(commentText); this.originalComment = commentText; if (this.headlineInput) { this.headlineInput.setValue(headline); this.originalHeadline = headline; } this.closeOperation(currentOperation); this.commentInput.focus(); this.preview(); }, (e) => { if (e instanceof CdError) { const options = Object.assign({}, e.data, { cancel: true, currentOperation, }); this.handleError(options); } else { this.handleError({ type: 'javascript', logMessage: e, cancel: true, currentOperation, }); } } ); } else { if (this.preloadConfig?.commentTemplate) { const currentOperation = this.registerOperation({ type: 'load', affectHeadline: false, }); const preloadPage = new Page(this.preloadConfig.commentTemplate); preloadPage.getCode().then( () => { let code = preloadPage.code; const regexp = /<onlyinclude(?: [\w ]+(?:=[^<>]+?)?| ?\/?)>([^]*?)<\/onlyinclude(?: \w+)? ?>/g; let match; let onlyInclude; while ((match = regexp.exec(code))) { if (onlyInclude === undefined) { onlyInclude = ''; } onlyInclude += match[1]; } if (onlyInclude !== undefined) { code = onlyInclude; } code = code .replace( /<includeonly(?: [\w ]+(?:=[^<>]+?)?| ?\/?)>([^]*?)<\/includeonly(?: \w+)? ?>/g, '$1' ) .replace( /<noinclude(?: [\w ]+(?:=[^<>]+?)?| ?\/?)>([^]*?)<\/noinclude(?: \w+)? ?>/g, '' ); code = code.trim(); if (code.includes(cd.g.SIGN_CODE) || this.preloadConfig.omitSignature) { this.omitSignatureCheckbox.setSelected(true); } this.commentInput.setValue(code); this.originalComment = code; this.closeOperation(currentOperation); this.preview(); }, (e) => { if (e instanceof CdError) { const options = Object.assign({}, e.data, { cancel: true, currentOperation, }); this.handleError(options); } else { this.handleError({ type: 'javascript', logMessage: e, cancel: true, currentOperation, }); } } ); } else { this.originalComment = ''; } if (this.headlineInput) { this.headlineInput.setValue(this.preloadConfig?.headline || ''); this.originalHeadline = this.preloadConfig?.headline || ''; } if (!(this.target instanceof Page)) { this.checkCode(); } } } /** * A comment form has been created. * * @event commentFormCreated * @type {module:CommentForm} */ mw.hook('convenientDiscussions.commentFormCreated').fire(this); } /** * Test if a comment or section exists in the code. * * @returns {JQuery.Promise} */ checkCode() { if (!this.checkCodeRequest) { /** * Request to test if a comment or section exists in the code made by {@link * module:CommentForm#checkCode}. * * @type {JQuery.Promise|undefined} */ this.checkCodeRequest = this.target.getCode(this).catch((e) => { if (e instanceof CdError) { const options = Object.assign({}, e.data); this.handleError(options); } else { this.handleError({ type: 'javascript', logMessage: e, }); } }); } return this.checkCodeRequest; } /** * Set the `target`, `targetSection`, `targetComment`, and `targetPage` properties. * * @param {Comment|Section|Page} target * @throws {CdError} */ setTargets(target) { /** * Target object. * * @type {?(Comment|Section)} */ this.target = target; if (this.target instanceof Comment) { /** * Target section. * * @type {?(Section|undefined)} */ this.targetSection = this.target.getSection(); /** * Target comment. This may be the comment the user replies to or the comment opening the * section. * * @type {?(Comment|Section|undefined)} */ this.targetComment = this.target; } else if (this.target instanceof Section) { this.targetSection = this.target; if (this.mode === 'replyInSection' && !this.target.$replyButton) { throw new CdError(); } if ( this.mode === 'addSubsection' && !this.targetSection.$heading.find('.cd-sectionLink-addSubsection').length ) { throw new CdError(); } if (this.target.comments[0]?.isOpeningSection) { this.targetComment = this.target.comments[0]; } } /** * Wiki page that has the source code of the target object (may be different from the current * page if the section is transcluded from another page). * * @type {string} */ this.targetPage = this.targetSection ? this.targetSection.getSourcePage() : cd.g.CURRENT_PAGE; } /** * Add a WikiEditor toolbar to the comment input. * * @param {string[]} moduleNames List of custom comment form modules to await loading of before * adding the toolbar. * @fires commentFormToolbarReady * @private */ addToolbar(moduleNames) { const $toolbarPlaceholder = $('<div>') .addClass('cd-toolbarPlaceholder') .insertBefore(this.commentInput.$element); mw.loader.using(['ext.wikiEditor'].concat(moduleNames)).then(() => { const $input = this.commentInput.$input; $input.wikiEditor( 'addModule', mw.loader.moduleRegistry['ext.wikiEditor'] .packageExports['jquery.wikiEditor.toolbar.config.js'] ); const dialogsConfig = mw.loader.moduleRegistry['ext.wikiEditor'] .packageExports['jquery.wikiEditor.dialogs.config.js']; dialogsConfig.replaceIcons($input); $input.wikiEditor('addModule', dialogsConfig.getDefaultConfig()); this.commentInput.$element .find('.tool[rel="redirect"], .tool[rel="signature"], .tool[rel="newline"], .tool[rel="gallery"], .tool[rel="reference"], .option[rel="heading-2"]') .remove(); if (!['addSection', 'addSubsection'].includes(this.mode)) { this.commentInput.$element.find('.group-heading').remove(); } // Make the undo/redo functionality work in browsers that support it (Chrome). $input.textSelection('register', { encapsulateSelection: (options) => { this.encapsulateSelection(options); }, setContents: (value) => { this.commentInput.select(); insertText(this.commentInput, value); }, }); const lang = mw.config.get('wgUserLanguage'); $input.wikiEditor('addToToolbar', { section: 'main', group: 'format', tools: { smaller: { label: cd.mws('wikieditor-toolbar-tool-small'), type: 'button', icon: `/w/load.php?modules=oojs-ui.styles.icons-editing-styling&image=smaller&lang=${lang}&skin=vector`, action: { type: 'encapsulate', options: { pre: '<small>', peri: cd.mws('wikieditor-toolbar-tool-small-example'), post: '</small>', }, }, }, quote: { label: `${cd.s('cf-quote-tooltip')} ${cd.mws('parentheses', `Q${cd.mws('comma-separator')}Ctrl+Alt+Q`)}`, type: 'button', icon: `/w/load.php?modules=oojs-ui.styles.icons-editing-advanced&image=quotes&lang=${lang}&skin=vector`, action: { type: 'callback', execute: () => { this.quote(); }, }, }, }, }); $input.wikiEditor('addToToolbar', { section: 'advanced', group: 'format', tools: { code: { label: cd.s('cf-code-tooltip'), type: 'button', icon: `/w/load.php?modules=oojs-ui.styles.icons-editing-advanced&image=code&lang=${lang}&skin=vector`, action: { type: 'encapsulate', options: { pre: '<code><nowiki>', peri: cd.s('cf-code-placeholder'), post: '</'.concat('nowiki></code>'), }, }, }, codeBlock: { label: cd.s('cf-codeblock-tooltip'), type: 'button', icon: `/w/load.php?modules=oojs-ui.styles.icons-editing-advanced&image=markup&lang=${lang}&skin=vector`, action: { type: 'encapsulate', options: { pre: '<syntaxhighlight lang="">\n', peri: cd.s('cf-codeblock-placeholder'), post: '\n</syntaxhighlight>', }, }, }, underline: { label: cd.s('cf-underline-tooltip'), type: 'button', icon: `/w/load.php?modules=oojs-ui.styles.icons-editing-styling&image=underline&lang=${lang}&skin=vector`, action: { type: 'encapsulate', options: { pre: '<u>', peri: cd.s('cf-underline-placeholder'), post: '</u>', }, }, }, strikethrough: { label: cd.s('cf-strikethrough-tooltip'), type: 'button', icon: `/w/load.php?modules=oojs-ui.styles.icons-editing-styling&image=strikethrough&lang=${lang}&skin=vector`, action: { type: 'encapsulate', options: { pre: '<s>', peri: cd.s('cf-strikethrough-placeholder'), post: '</s>', }, }, }, }, }); $input.wikiEditor('addToToolbar', { section: 'main', groups: { 'convenient-discussions': { tools: { mention: { label: cd.s('cf-mention-tooltip'), type: 'button', icon: `/w/load.php?modules=oojs-ui.styles.icons-user&image=userAvatar&lang=${lang}&skin=vector`, action: { type: 'callback', execute: () => {}, }, }, }, }, }, }); this.$element .find('.tool-button[rel="mention"]') .off('click') .on('click', (e) => { this.mention(e.ctrlKey); }); // For some reason, in (starting with?) Chrome 84.0.4147.89, if you put // `$toolbarPlaceholder.hide();` to the top, the viewport will jump down. See also // saveScrollPosition() call above. $toolbarPlaceholder.remove(); // More Chrome scrolling bug fixes this.$element .find('.tool[rel="link"] a, .tool[rel="file"] a') .on('mouseup', () => { saveScrollPosition(); }) .on('click', () => { restoreScrollPosition(); }); /** * The comment form toolbar is ready; all requested custom comment form modules have been * loaded and executed. * * @event commentFormToolbarReady * @type {module:CommentForm} */ mw.hook('convenientDiscussions.commentFormToolbarReady').fire(this); }); } /** * Add an insert button to the block under the comment input. * * @param {string} text * @param {string} [displayedText] * @private */ addInsertButton(text, displayedText) { const hidden = []; text = hideText(text, /\\[+;\\]/g, hidden); let [, pre, post] = text.match(/^(.*?)(?:\+(.*))?$/) || []; if (!pre) return; post = post || ''; const unescape = (text) => text.replace(/\\([+;\\])/g, '$1'); pre = unescape(unhideText(pre, hidden)); post = unescape(unhideText(post, hidden)); displayedText = displayedText ? unescape(displayedText) : pre + post; const $a = $('<a>') .text(displayedText) .addClass('cd-insertButtons-item') .on('click', () => { this.encapsulateSelection({ pre, post }); }); this.$insertButtons.append($a, ' '); } /** * Create the contents of the form. * * @param {object} dataToRestore * @private */ createContents(dataToRestore) { if (['addSection', 'addSubsection'].includes(this.mode)) { this.containerListType = null; } else { /** * Name of the tag used as a list whereof this comment form is an item. `'dl'`, `'ul'`, * `'ol'`, or `null`. * * @type {?string} */ this.containerListType = this.target instanceof Comment ? this.target.$elements .last() .parent() .prop('tagName') .toLowerCase() : this.target.$replyWrapper .parent() .prop('tagName') .toLowerCase(); } this.editingSectionOpeningComment = this.mode === 'edit' && this.target.isOpeningSection; /** * The main form element. * * @type {JQuery} */ this.$element = $('<div>') .addClass('cd-commentForm') .addClass(`cd-commentForm-${this.mode}`) // The form may sometimes get inside <div dir="..."> element, so we need to reset the text // direction. .attr('dir', cd.g.SITE_DIR); if (this.containerListType === 'ol') { this.$element.addClass('cd-commentForm-inNumberedList'); } if (this.editingSectionOpeningComment) { this.$element.addClass('cd-commentForm-sectionOpeningComment'); } if (this.mode === 'addSubsection') { this.$element.addClass(`cd-commentForm-addSubsection-${this.target.level}`); } /** * The area where service messages are displayed. * * @type {JQuery} */ this.$messageArea = $('<div>').addClass('cd-messageArea'); /** * @typedef {object} OoUiTextInputWidget * @see https://doc.wikimedia.org/oojs-ui/master/js/#!/api/OO.ui.TextInputWidget */ if ( (['addSection', 'addSubsection'].includes(this.mode) && !this.preloadConfig?.noHeadline) || this.editingSectionOpeningComment ) { if (this.mode === 'addSubsection') { this.headlineInputPurpose = cd.s('cf-headline-subsection', this.targetSection.headline); } else if (this.mode === 'edit' && this.targetSection.getParent()) { this.headlineInputPurpose = cd.s( 'cf-headline-subsection', this.targetSection.getParent().headline ); } else { this.headlineInputPurpose = cd.s('cf-headline-topic'); } /** * Headline input. * * @type {OoUiTextInputWidget|undefined} */ this.headlineInput = new OO.ui.TextInputWidget({ value: dataToRestore ? dataToRestore.headline : '', placeholder: this.headlineInputPurpose, classes: ['cd-headlineInput'], tabIndex: String(this.id) + '11', }); } let rowNumber = this.headlineInput ? 5 : 3; // Firefox gives a bigger height to a textarea with a specified number of rows than other // browsers. if ($.client.profile().name === 'firefox') { rowNumber -= 1; } let commentInputPlaceholder; if ( this.mode === 'replyInSection' || (this.mode === 'reply' && this.target.isOpeningSection) ) { commentInputPlaceholder = cd.s( 'cf-comment-placeholder-replytosection', this.targetSection.headline ); } else if (this.mode === 'reply') { // If there is a need to make a request to get the user gender, we don't show any // placeholder text at the beginning to avoid drawing the user's attention to the changing // of the text. (But it could be a better idea to set the `showCommentInputPlaceholder` // config variable to `false` to avoid showing any text whatsoever.) this.target.requestAuthorGenderIfNeeded(() => { this.commentInput.$input.attr( 'placeholder', removeDoubleSpaces(cd.s( 'cf-comment-placeholder-replytocomment', this.target.author.name, this.target.author )) ); }, true); } /** * @typedef {object} OoUiMultilineTextInputWidget * @see https://doc.wikimedia.org/oojs-ui/master/js/#!/api/OO.ui.MultilineTextInputWidget */ /** * Comment input. * * @type {OoUiMultilineTextInputWidget} */ this.commentInput = new OO.ui.MultilineTextInputWidget({ value: dataToRestore ? dataToRestore.comment : '', placeholder: commentInputPlaceholder, autosize: true, rows: rowNumber, maxRows: 30, classes: ['cd-commentInput'], tabIndex: String(this.id) + '12', }); /** * Advanced section container. * * @type {JQuery} */ this.$advanced = $('<div>').addClass('cd-commentFormAdvanced'); /** * Edit summary input. * * @type {OoUiTextInputWidget} */ this.summaryInput = new OO.ui.TextInputWidget({ value: dataToRestore ? dataToRestore.summary : '', maxLength: cd.g.SUMMARY_LENGTH_LIMIT, placeholder: cd.s('cf-summary-placeholder'), classes: ['cd-summaryInput'], tabIndex: String(this.id) + '13', }); this.summaryInput.$input.codePointLimit(cd.g.SUMMARY_LENGTH_LIMIT); mw.widgets.visibleCodePointLimit(this.summaryInput, cd.g.SUMMARY_LENGTH_LIMIT); this.updateAutoSummary(!dataToRestore); /** * The area where edit summary preview is displayed. * * @type {JQuery} */ this.$summaryPreview = $('<div>').addClass('cd-summaryPreview'); /** * @typedef {object} OoUiFieldLayout * @see https://doc.wikimedia.org/oojs-ui/master/js/#!/api/OO.ui.FieldLayout */ /** * @typedef {object} OoUiCheckboxInputWidget * @see https://doc.wikimedia.org/oojs-ui/master/js/#!/api/OO.ui.CheckboxInputWidget */ if (this.mode === 'edit') { /** * Minor change checkbox field. * * @name minorField * @type {OoUiFieldLayout|undefined} * @instance */ /** * Minor change checkbox. * * @name minorCheckbox * @type {OoUiCheckboxInputWidget|undefined} * @instance */ [this.minorField, this.minorCheckbox] = checkboxField({ value: 'minor', selected: dataToRestore ? dataToRestore.minor : true, label: cd.s('cf-minor'), tabIndex: String(this.id) + '20', }); } const watchCheckboxSelected = ( (cd.settings.watchOnReply && this.mode !== 'edit') || $('#ca-unwatch').length || mw.user.options.get(mw.config.get('wgArticleId') ? 'watchdefault' : 'watchcreations') ); /** * Watch page checkbox field. * * @name watchField * @type {OoUiFieldLayout} * @instance */ /** * Watch page checkbox. * * @name watchCheckbox * @type {OoUiCheckboxInputWidget} * @instance */ [this.watchField, this.watchCheckbox] = checkboxField({ value: 'watch', selected: dataToRestore ? dataToRestore.watch : watchCheckboxSelected, label: cd.s('cf-watch'), tabIndex: String(this.id) + '21', }); if (this.targetSection || this.mode === 'addSection') { const callItTopic = ( this.mode !== 'addSubsection' && ((this.targetSection && this.targetSection.level <= 2) || this.mode === 'addSection') ); const label = cd.s('cf-watchsection-' + (callItTopic ? 'topic' : 'subsection')); const selected = ( (cd.settings.watchSectionOnReply && this.mode !== 'edit') || this.targetSection?.isWatched ); /** * Watch section checkbox field. * * @name watchSectionField * @type {OoUiFieldLayout|undefined} * @instance */ /** * Watch section checkbox. * * @name watchSectionCheckbox * @type {OoUiCheckboxInputWidget|undefined} * @instance */ [this.watchSectionField, this.watchSectionCheckbox] = checkboxField({ value: 'watchSection', selected: dataToRestore ? dataToRestore.watchSection : selected, label, tabIndex: String(this.id) + '22', title: cd.s('cf-watchsection-tooltip'), }); } if (['addSection', 'addSubsection'].includes(this.mode)) { /** * Omit signature checkbox field. * * @name omitSignatureField * @type {OoUiFieldLayout|undefined} * @instance */ /** * Omit signature checkbox. * * @name omitSignatureCheckbox * @type {OoUiCheckboxInputWidget|undefined} * @instance */ [this.omitSignatureField, this.omitSignatureCheckbox] = checkboxField({ value: 'omitSignature', selected: dataToRestore ? dataToRestore.omitSignature : false, label: cd.s('cf-omitsignature'), tabIndex: String(this.id) + '25', }); } if ( this.mode === 'edit' && ( this.target.isOpeningSection ? this.targetSection.comments.length === 1 : !this.target.getChildren().length ) ) { const selected = dataToRestore ? dataToRestore.delete : false; /** * Delete checkbox field. * * @name deleteField * @type {OoUiFieldLayout|undefined} * @instance */ /** * Delete checkbox. * * @name deleteCheckbox * @type {OoUiCheckboxInputWidget|undefined} * @instance */ [this.deleteField, this.deleteCheckbox] = checkboxField({ value: 'delete', selected, label: cd.s('cf-delete'), tabIndex: String(this.id) + '26', }); } /** * Script settings button. * * @name settingsButton * @type {Promise} * @instance */ this.settingsButton = new OO.ui.ButtonWidget({ framed: false, icon: 'settings', label: cd.s('cf-settings-tooltip'), invisibleLabel: true, title: cd.s('cf-settings-tooltip'), classes: ['cd-button', 'cd-settingsButton'], tabIndex: String(this.id) + '27', }); /** * @typedef {object} OoUiHorizontalLayout * @see https://doc.wikimedia.org/oojs-ui/master/js/#!/api/OO.ui.HorizontalLayout */ /** * Checkboxes area. * * @type {OoUiHorizontalLayout} */ this.checkboxesLayout = new OO.ui.HorizontalLayout({ classes: ['cd-checkboxesContainer'], items: [ this.minorField, this.watchField, this.watchSectionField, this.omitSignatureField, this.deleteField, this.settingsButton, ].filter(defined), }); /** * Form buttons container. * * @type {JQuery} */ this.$buttonsContainer = $('<div>').addClass('cd-buttonsContainer'); /** * Left form buttons container. * * @type {JQuery} */ this.$leftButtonsContainer = $('<div>').addClass('cd-leftButtonsContainer'); /** * Right form buttons container. * * @type {JQuery} */ this.$rightButtonsContainer = $('<div>').addClass('cd-rightButtonsContainer'); let message; switch (this.mode) { case 'edit': message = 'save'; break; case 'addSection': message = 'addtopic'; break; case 'addSubsection': message = 'addsubsection'; break; default: message = 'reply'; } this.submitButtonLabelStandard = cd.s(`cf-${message}`); this.submitButtonLabelShort = cd.s(`cf-${message}-short`); /** * @typedef {object} OoUiButtonWidget * @see https://doc.wikimedia.org/oojs-ui/master/js/#!/api/OO.ui.ButtonWidget */ /** * Toggle advanced section button. * * @type {OoUiButtonWidget} */ this.advancedButton = new OO.ui.ButtonWidget({ label: cd.s('cf-advanced'), framed: false, classes: ['cd-button', 'cd-advancedButton'], tabIndex: String(this.id) + '30', }); if (!cd.g.$popupsOverlay) { cd.g.$popupsOverlay = $('<div>') .addClass('cd-popupsOverlay') .appendTo(document.body); } /** * @typedef {object} OoUiPopupButtonWidget * @see https://doc.wikimedia.org/oojs-ui/master/js/#!/api/OO.ui.PopupButtonWidget */ /** * Help button. * * @type {OoUiPopupButtonWidget} */ this.helpPopupButton = new OO.ui.PopupButtonWidget({ label: cd.s('cf-help'), framed: false, classes: ['cd-button'], popup: { head: false, $content: cd.util.wrap(cd.sParse('cf-help-content', cd.config.mentionCharacter), { tagName: 'div', targetBlank: true, }), padded: true, align: 'center', width: 400, }, $overlay: cd.g.$popupsOverlay, tabIndex: String(this.id) + '31', }); /** * Cancel button. * * @type {OoUiButtonWidget} */ this.cancelButton = new OO.ui.ButtonWidget({ label: cd.s('cf-cancel'), flags: 'destructive', framed: false, classes: ['cd-button', 'cd-cancelButton'], tabIndex: String(this.id) + '32', }); /** * View changes button. * * @type {OoUiButtonWidget} */ this.viewChangesButton = new OO.ui.ButtonWidget({ label: cd.s('cf-viewchanges'), classes: ['cd-viewChangesButton'], tabIndex: String(this.id) + '33', }); /** * Preview button. * * @type {OoUiButtonWidget} */ this.previewButton = new OO.ui.ButtonWidget({ label: cd.s('cf-preview'), classes: ['cd-previewButton'], tabIndex: String(this.id) + '34', }); if (cd.settings.autopreview) { this.previewButton.$element.hide(); } /** * Submit button. * * @type {OoUiButtonWidget} */ this.submitButton = new OO.ui.ButtonWidget({ label: this.submitButtonLabelStandard, flags: ['progressive', 'primary'], classes: ['cd-submitButton'], tabIndex: String(this.id) + '35', }); if (this.deleteCheckbox?.isSelected()) { this.updateFormOnDeleteCheckboxChange(true); } this.$advanced.append([ this.summaryInput.$element, this.$summaryPreview, this.checkboxesLayout.$element, ]); this.$leftButtonsContainer.append([ this.advancedButton.$element, this.helpPopupButton.$element, ]); this.$rightButtonsContainer.append([ this.cancelButton.$element, this.viewChangesButton.$element, this.previewButton.$element, this.submitButton.$element, ]); this.$buttonsContainer.append(this.$leftButtonsContainer, this.$rightButtonsContainer); this.$element.append([ this.$messageArea, this.headlineInput?.$element, this.commentInput.$element, this.$advanced, this.$buttonsContainer, ].filter(defined)); if (this.mode !== 'edit' && !cd.settings.alwaysExpandAdvanced) { this.$advanced.hide(); } /** * The area where comment previews and changes are displayed. * * @type {JQuery} */ this.$previewArea = $('<div>').addClass('cd-previewArea') if (cd.settings.autopreview) { this.$previewArea .addClass('cd-previewArea-below') .appendTo(this.$element); } else { this.$previewArea .addClass('cd-previewArea-above') .prependTo(this.$element); } if (this.containerListType === 'ol' && $.client.profile().layout !== 'webkit') { // Dummy element for forms inside a numbered list so that the number is placed in front of // that area, not in some silly place. Note that in Chrome, the number is placed in front of // the textarea, so we don't need this in that browser. $('<div>') .html('&nbsp;') .addClass('cd-commentForm-dummyElement') .prependTo(this.$element); } const moduleNames = cd.config.customCommentFormModules .filter((module) => !module.checkFunc || module.checkFunc()) .map((module) => module.name); mw.loader.using(moduleNames).then(() => { /** * All requested custom comment form modules have been loaded and executed. (The comment form * may not be ready yet, use {@link module:CommentForm~commentFormToolbarReady} for that.) * * @event commentFormModulesReady * @type {module:CommentForm} */ mw.hook('convenientDiscussions.commentFormModulesReady').fire(this); }); if (cd.settings.showToolbar) { this.addToolbar(moduleNames); } if (cd.settings.insertButtons.length) { /** * Text insert buttons. * * @type {JQuery|undefined} */ this.$insertButtons = $('<div>') .addClass('cd-insertButtons') .insertAfter(this.commentInput.$element); cd.settings.insertButtons.forEach((button) => { let text; let displayedText; if (Array.isArray(button)) { text = button[0]; displayedText = button[1]; } else { text = button; } this.addInsertButton(text, displayedText); }); } } /** * Insert the form into the DOM. */ addToPage() { if (this.mode === 'replyInSection') { this.target.$replyButton.hide(); } else if (this.mode === 'addSubsection' && this.target.$addSubsectionButtonContainer) { this.target.$addSubsectionButtonContainer.hide(); } else if (this.mode === 'addSection' && cd.g.$addSectionButtonContainer) { cd.g.$addSectionButtonContainer.hide(); } // 'addSection' if (!mw.config.get('wgArticleId')) { cd.g.$root.empty(); } let outerWrapperTag; let createList = false; let $lastOfTarget; let $other; if (this.mode === 'reply') { createList = true; $lastOfTarget = this.target.$elements.last(); $other = $lastOfTarget.next(); const $nextToTargetFirstChild = $other.children().first(); if ($other.is('li, dd') && $nextToTargetFirstChild.hasClass('cd-commentLevel')) { $other = $nextToTargetFirstChild; } if ($other.is('ul')) { createList = false; outerWrapperTag = 'li'; } else if ($other.is('dl')) { createList = false; outerWrapperTag = 'dd'; } else if ($lastOfTarget.is('li')) { // We need to avoid a number appearing next to the form in numbered lists, so we have <div> // in those cases. Which is unsemantic, yes :-( if (this.containerListType !== 'ol') { outerWrapperTag = 'li'; } else { outerWrapperTag = 'div'; } } else if ($lastOfTarget.is('dd')) { outerWrapperTag = 'dd'; } } else if (this.mode === 'edit') { const $lastOfTarget = this.target.$elements.last(); if ($lastOfTarget.is('li')) { outerWrapperTag = 'li'; } else if ($lastOfTarget.is('dd')) { outerWrapperTag = 'dd'; } } if (outerWrapperTag) { /** * Element, usually a `li` or `dd`, that wraps either {@link module:CommentForm~$element the * comment form element} directly, or {@link module:CommentForm~$wrappingList the list} that * wraps the item that wraps the comment form element. * * @type {JQuery|undefined} */ this.$outerWrapper = $(`<${outerWrapperTag}>`); } if (this.mode === 'reply') { if (createList) { /** * List that wraps the item that wraps the comment form element. * * @type {JQuery|undefined} */ this.$wrappingList = $('<ul>').addClass('cd-commentLevel'); if (this.$outerWrapper) { this.$wrappingList.appendTo(this.$outerWrapper); } const $wrappingItem = $('<li>').appendTo(this.$wrappingList); this.$element.appendTo($wrappingItem); } else { this.$element.appendTo(this.$outerWrapper); } } else if (this.mode === 'edit') { if (this.$outerWrapper) { this.$element.appendTo(this.$outerWrapper); } } /** * The outermost element of the form (equal to {@link module:CommentForm#$outerWrapper}, {@link * module:CommentForm#$wrappingList} or {@link module:CommentForm#$element}). It is removed to * return the DOM to the original state, before the form was created. * * @type {JQuery} */ this.$outermostElement = this.$outerWrapper || this.$wrappingList || this.$element; switch (this.mode) { case 'reply': { if ($other.is('ul, dl')) { this.$outerWrapper.prependTo($other); } else if ($lastOfTarget.is('li, dd')) { this.$outerWrapper.insertAfter($lastOfTarget); } else { this.$wrappingList.insertAfter($lastOfTarget); } break; } case 'edit': { const $element = this.$outerWrapper || this.$element; // We insert the form before the comment so that if the comment ends on a wrong level, the // form is on a right one. The exception is comments that open a section (otherwise a bug // will be introduced that will manifest when opening an "Add subsection" form of the // previous section). if (this.target.isOpeningSection) { $element.insertAfter(this.target.$elements.last()); } else { $element.insertBefore(this.target.$elements.first()); } break; } case 'replyInSection': { this.$element.appendTo(this.target.$replyWrapper); this.target.$replyWrapper.addClass('cd-replyWrapper-hasCommentForm'); break; } case 'addSection': { if (this.isNewTopicOnTop && cd.sections[0]) { this.$element.insertBefore(cd.sections[0].$heading); } else { this.$element.appendTo(cd.g.$root); } break; } case 'addSubsection': { /* In the following structure: == Level 2 section == === Level 3 section === ==== Level 4 section ==== ..."Add subsection" forms should go in the opposite order. So, if there are "Add subsection" forms for a level 4 and then a level 2 section and the user clicks "Add subsection" for a level 3 section, we need to put our form between them. */ const headingLevelRegexp = new RegExp( `\\bcd-commentForm-addSubsection-[${this.target.level}-6]\\b` ); let $target; let $tested = this.target.$elements.last(); do { $target = $tested; $tested = $tested.next(); } while ( $tested.is('.cd-sectionButtonContainer:not(.cd-addTopicButtonContainer), .cd-commentForm-reply') || ($tested.get(0)?.className.match(headingLevelRegexp)) ); this.$element.insertAfter($target); break; } } this.adjustLabels(); } /** * Add events to form elements. */ addEvents() { const saveSessionEventHandler = () => { saveSession(); }; const preview = () => { this.preview(); }; const textReactions = [ { pattern: new RegExp(cd.g.SIGN_CODE + '\\s*$'), message: cd.sParse('cf-reaction-signature', cd.g.SIGN_CODE), name: 'signatureNotNeeded', type: 'notice', checkFunc: () => !this.omitSignatureCheckbox?.isSelected(), }, { pattern: /<pre/, message: cd.sParse('cf-reaction-pre'), name: 'dontUsePre', type: 'warning', }, ].concat(cd.config.customTextReactions); this.$element // Hotkeys .on('keydown', (e) => { // Ctrl+Enter if (e.ctrlKey && !e.shiftKey && !e.altKey && e.keyCode === 13) { this.submit(); } // Esc if (!e.ctrlKey && !e.shiftKey && !e.altKey && e.keyCode === 27) { this.cancel(); } }) // "focusin" is "focus" that bubbles, i.e. propagates up the node tree. .on('focusin', () => { this.lastFocused = new Date(); }); if (this.headlineInput) { this.headlineInput .on('change', (headline) => { this.updateAutoSummary(true, true); if (headline.includes('{{') && !this.preloadConfig?.headline) { this.showMessage(cd.sParse('cf-reaction-templateinheadline'), { type: 'warning', name: 'templateInHeadline', }); } else { this.hideMessage('templateInHeadline'); } }) .on('change', preview) .on('change', saveSessionEventHandler); this.headlineInput.$input.on('keydown', (e) => { // Enter if (e.keyCode === 13 && !cd.g.activeAutocompleteMenu) { this.submit(); } }); } this.commentInput .on('change', (text) => { this.updateAutoSummary(true, true); textReactions.forEach(({ pattern, checkFunc, message, type, name }) => { if (pattern.test(text) && (typeof checkFunc !== 'function' || checkFunc(this))) { this.showMessage(message, { type, name }); } else { this.hideMessage(name); } }); }) .on('change', preview) .on('change', saveSessionEventHandler); this.commentInput.$input.get(0).addEventListener('tribute-replaced', (e) => { if (e.detail.instance.trigger === cd.config.mentionCharacter) { if (this.mode === 'edit') { const $message = cd.util.wrap(cd.sParse('cf-reaction-mention-edit'), { targetBlank: true, }); this.showMessage($message, { type: 'notice', name: 'mentionEdit', }); } if (this.omitSignatureCheckbox?.isSelected()) { const $message = cd.util.wrap(cd.sParse('cf-reaction-mention-nosignature'), { targetBlank: true, }); this.showMessage($message, { type: 'notice', name: 'mentionNoSignature', }); } } }); this.summaryInput .on('change', () => { if (this.summaryInput.$input.is(':focus')) { this.isSummaryAltered = true; this.dontAutopreviewOnSummaryChange = false; } if (!this.dontAutopreviewOnSummaryChange) { preview(); } }) .on('change', saveSessionEventHandler); this.summaryInput.$input.on('keydown', (e) => { // Enter if (e.keyCode === 13 && !cd.g.activeAutocompleteMenu) { this.submit(); } }); if (this.minorCheckbox) { this.minorCheckbox .on('change', saveSessionEventHandler); } this.watchCheckbox .on('change', saveSessionEventHandler); if (this.watchSectionCheckbox) { this.watchSectionCheckbox .on('change', saveSessionEventHandler); } if (this.omitSignatureCheckbox) { this.omitSignatureCheckbox .on('change', () => { this.preview(false); }) .on('change', saveSessionEventHandler); } if (this.deleteCheckbox) { this.deleteCheckbox .on('change', (selected) => { this.updateAutoSummary(true, true); this.updateFormOnDeleteCheckboxChange(selected); }) .on('change', preview) .on('change', saveSessionEventHandler); } this.settingsButton .on('click', () => { settingsDialog(); }); this.advancedButton .on('click', () => { this.toggleAdvanced(); }); this.cancelButton .on('click', () => { this.cancel(); }); this.viewChangesButton .on('click', () => { this.viewChanges(); }); this.previewButton .on('click', () => { this.preview(true, false); }); this.submitButton .on('click', () => { this.submit(); }); } /** * Initialize autocomplete using {@link https://github.com/zurb/tribute Tribute}. */ initAutocomplete() { let commentsInSection = []; if (this.targetSection) { commentsInSection = this.targetSection.getBase().comments; } else if (this.mode !== 'addSection') { // Comments in the lead section cd.comments.some((comment) => { if (comment.getSection()) { return true; } else { commentsInSection.push(comment); return false; } }); } if (this.mode === 'edit') { commentsInSection = commentsInSection.filter((comment) => comment !== this.target); } let usersInSection = commentsInSection .map((comment) => comment.author.name) .sort(); if (this.targetComment && this.mode !== 'edit') { usersInSection.unshift(this.targetComment.author.name); } usersInSection = usersInSection.filter(unique); /** * Autocomplete object for the comment input. * * @type {Autocomplete} */ this.autocomplete = new Autocomplete({ types: ['mentions', 'wikilinks', 'templates', 'tags', 'commentLinks'], inputs: [this.commentInput], comments: commentsInSection, defaultUserNames: usersInSection, }); if (this.headlineInput) { /** * Autocomplete object for the headline input. * * @type {Autocomplete|undefined} */ this.headlineAutocomplete = new Autocomplete({ types: ['mentions', 'wikilinks', 'tags'], inputs: [this.headlineInput], comments: commentsInSection, defaultUserNames: usersInSection, }); } /** * Autocomplete object for the summary input. * * @type {Autocomplete} */ this.summaryAutocomplete = new Autocomplete({ types: ['mentions', 'wikilinks'], inputs: [this.summaryInput], comments: commentsInSection, defaultUserNames: usersInSection, }); } /** * Show or hide the advanced section. */ toggleAdvanced() { saveScrollPosition(); if (this.$advanced.is(':hidden')) { this.$advanced.show(); const value = this.summaryInput.getValue(); const match = value.match(/^.+?\*\/ */); this.summaryInput.selectRange(match ? match[0].length : 0, value.length); } else { this.$advanced.hide(); this.commentInput.focus(); } restoreScrollPosition(); } /** * Adjust button labels according to the form width: if the form is to narrow, the labels will * shrink. */ adjustLabels() { let formWidth = this.$element.width(); if (this.$element.hasClass('cd-commentForm-short')) { if (formWidth >= this.buttonsTotalWidthStandard + 7) { this.$element.removeClass('cd-commentForm-short'); this.submitButton.setLabel(this.submitButtonLabelStandard); this.previewButton.setLabel(cd.s('cf-preview')); this.viewChangesButton.setLabel(cd.s('cf-viewchanges')); this.cancelButton.setLabel(cd.s('cf-cancel')); } } else { this.buttonsTotalWidthStandard = ( this.submitButton.$element.outerWidth(true) + ( this.previewButton.$element.is(':visible') ? this.previewButton.$element.outerWidth(true) : 0 ) + // Users may hide the view changes button by any kind of a plugin. ( this.viewChangesButton.$element.is(':visible') ? this.viewChangesButton.$element.outerWidth(true) : 0 ) + this.advancedButton.$element.outerWidth(true) + this.helpPopupButton.$element.outerWidth(true) + this.cancelButton.$element.outerWidth(true) ); if (formWidth < this.buttonsTotalWidthStandard + 7) { this.$element.addClass('cd-commentForm-short'); this.submitButton.setLabel(this.submitButtonLabelShort); this.previewButton.setLabel(cd.s('cf-preview-short')); this.viewChangesButton.setLabel(cd.s('cf-viewchanges-short')); this.cancelButton.setLabel(cd.s('cf-cancel-short')); } } } /** * Push the pending status of the form inputs. * * @param {boolean} setDisabled Whether to set buttons and inputs disabled. * @param {boolean} affectHeadline Should the `pushPending` method be applied to the headline * input. * @see * https://doc.wikimedia.org/oojs-ui/master/js/#!/api/OO.ui.mixin.PendingElement-method-pushPending */ pushPending(setDisabled = false, affectHeadline = true) { this.commentInput.pushPending(); this.summaryInput.pushPending(); if (affectHeadline) { this.headlineInput?.pushPending(); } if (setDisabled) { this.commentInput.setDisabled(true); this.summaryInput.setDisabled(true); if (affectHeadline) { this.headlineInput?.setDisabled(true); } this.submitButton.setDisabled(true); this.previewButton.setDisabled(true); this.viewChangesButton.setDisabled(true); this.cancelButton.setDisabled(true); this.minorCheckbox?.setDisabled(true); this.watchCheckbox.setDisabled(true); this.watchSectionCheckbox?.setDisabled(true); this.omitSignatureCheckbox?.setDisabled(true); this.deleteCheckbox?.setDisabled(true); } } /** * Pop the pending status of the form inputs. * * @param {boolean} [setEnabled=false] Whether to set buttons and inputs enabled. * @param {boolean} [affectHeadline=true] Should the `popPending` method be applied to the * headline input. * @see * https://doc.wikimedia.org/oojs-ui/master/js/#!/api/OO.ui.mixin.PendingElement-method-popPending */ popPending(setEnabled = false, affectHeadline = true) { this.commentInput.popPending(); this.summaryInput.popPending(); if (affectHeadline) { this.headlineInput?.popPending(); } if (setEnabled) { this.commentInput.setDisabled(false); this.summaryInput.setDisabled(false); if (affectHeadline) { this.headlineInput?.setDisabled(false); } this.submitButton.setDisabled(false); this.previewButton.setDisabled(false); this.viewChangesButton.setDisabled(false); this.cancelButton.setDisabled(false); this.minorCheckbox?.setDisabled(false); this.watchCheckbox.setDisabled(false); this.watchSectionCheckbox?.setDisabled(false); this.omitSignatureCheckbox?.setDisabled(false); this.deleteCheckbox?.setDisabled(false); // Restore needed "disabled"s. if (this.deleteCheckbox?.isSelected()) { this.updateFormOnDeleteCheckboxChange(true); } } } /** * Show a service message above the form. * * @param {string|JQuery} htmlOrJquery * @param {object} [options] * @param {string} [options.type='notice'] `'notice'`, `'error'`, `'warning'`, or `'success'`. See * {@link * https://doc.wikimedia.org/oojs-ui/master/demos/?page=widgets&theme=wikimediaui&direction=ltr&platform=desktop#MessageWidget-type-notice-inline-true * the OOUI Demos}. * @param {string} [options.name] Name added to the class name of the message element. * @param {boolean} [options.isRaw=false] Message HTML contains the whole message code. It doesn't * need to be wrapped in the widget. */ showMessage(htmlOrJquery, { type = 'notice', name, isRaw = false } = {}) { if (this.isDestroyed || (name && this.$messageArea.children(`.cd-message-${name}`).length)) { return; } let appendable; if (isRaw) { appendable = htmlOrJquery; } else { const $label = htmlOrJquery instanceof $ ? htmlOrJquery : cd.util.wrap(htmlOrJquery); const classes = ['cd-message']; if (name) { classes.push(`cd-message-${name}`); } const message = new OO.ui.MessageWidget({ type, inline: true, label: $label, classes, }); appendable = message.$element; } this.$messageArea .append(appendable) .cdAddCloseButton() .cdScrollIntoView('top'); } /** * Hide the service message above the form with the provided class. * * @param {string} name */ hideMessage(name) { const $info = this.$messageArea.children(`.cd-message-${name}`); if ($info.length) { $info.remove(); } } /** * Abort the operation the form is undergoing and show an error message. * * @param {object} options * @param {string} options.message Message visible to the user. * @param {string} [options.messageType='error'] Message type if not `'error'` (`'notice'` or * `'warning'`). * @param {boolean} [options.isRawMessage=false] Show the message as it is, without icons and * framing. * @param {string} [options.logMessage] Message for the browser console. * @param {boolean} [options.cancel=false] Cancel the form and show the message as a notification. * @param {object} [options.currentOperation] Operation the form is undergoing. * @private */ abort({ message, messageType = 'error', isRawMessage = false, logMessage, cancel = false, currentOperation, }) { if (currentOperation) { this.closeOperation(currentOperation); } if (this.isDestroyed) return; if (logMessage) { console.warn(logMessage); } if (cancel) { addNotification([ message, { type: 'error', autoHideSeconds: 'long', }, ]); this.cancel(false); } else { if (!(currentOperation && currentOperation.type === 'preview' && currentOperation.isAuto)) { this.showMessage(message, { type: messageType, isRaw: isRawMessage, }); } this.$messageArea.cdScrollIntoView('top'); } } /** * Abort the operation the form is undergoing and show an appropriate error message. This is a * wrapper around {@link module:CommentForm#abort}. * * @param {object} options * @param {string} options.type Type of the error: `'parse'` for parse errors defined in the * script, `'api'` for MediaWiki API errors, `'network'` for network errors defined in the * script, `'javascript'` for JavaScript errors, `'ui'` for UI errors. * @param {string} [options.code] Code of the error (either `code`, `apiData`, or `message` * should be specified). * @param {object} [options.details] Additional details about the error. * @param {string} [options.apiData] Data object received from the MediaWiki server (either * `code`, `apiData`, or `message` should be specified). * @param {string} [options.message] Text of the error (either `code`, `apiData`, or `message` * should be specified). * @param {string} [options.messageType] Message type if not `'error'` (`'notice'` or * `'warning'`). * @param {string} [options.logMessage] Data or text to display in the browser console. * @param {boolean} [options.cancel=false] Cancel the form and show the message as a * notification. * @param {boolean} [options.isRawMessage=false] Show the message as it is, without OOUI framing. * @param {Operation} [options.currentOperation] Operation the form is undergoing. */ async handleError({ type, code, details, apiData, message, messageType, logMessage, cancel = false, isRawMessage = false, currentOperation, }) { switch (type) { case 'parse': { let editUrl; switch (code) { case 'locateComment': if (this.targetSection) { editUrl = this.targetSection.editUrl ? this.targetSection.editUrl.toString() : cd.g.CURRENT_PAGE.getUrl({ action: 'edit' }); } else { editUrl = cd.g.CURRENT_PAGE.getUrl({ action: 'edit', section: 0, }); } message = cd.sParse('error-locatecomment', editUrl); break; case 'locateSection': editUrl = cd.g.CURRENT_PAGE.getUrl({ action: 'edit' }); message = cd.sParse('error-locatesection', editUrl); break; case 'numberedList-list': message = ( cd.sParse('cf-error-numberedlist') + ' ' + cd.sParse('cf-error-numberedlist-list') ); break; case 'numberedList-table': message = ( cd.sParse('cf-error-numberedlist') + ' ' + cd.sParse('cf-error-numberedlist-table') ); break; case 'findPlace': message = cd.sParse('cf-error-findplace'); break; case 'findPlace-unexpectedHeading': message = cd.sParse('cf-error-findplace-unexpectedheading'); break; case 'delete-repliesToComment': message = cd.sParse('cf-error-delete-repliestocomment'); break; case 'delete-repliesInSection': message = cd.sParse('cf-error-delete-repliesinsection'); break; case 'commentLinks-commentNotFound': message = cd.sParse('cf-error-commentlinks-commentnotfound', details.anchor); break; } const navigateToEditUrl = async (e) => { if (e.ctrlKey || e.shiftKey || e.metaKey) return; e.preventDefault(); if (await this.confirmClose()) { this.forget(); location.assign(editUrl); } }; message = cd.util.wrap(message, { callbacks: { 'cd-message-reloadPage': async () => { if (await this.confirmClose()) { this.reloadPage(); } }, 'cd-message-editSection': navigateToEditUrl, 'cd-message-editPage': navigateToEditUrl, }, }); break; } case 'api': { // Error messages related to error codes from API should rewrite our generic messages. switch (code) { case 'missing': { message = cd.sParse('cf-error-pagedoesntexist'); break; } case 'error': { const { code: errorCode, info: errorInfo, } = apiData.error; switch (errorCode) { case 'missingtitle': message = cd.sParse('cf-error-pagedoesntexist'); break; default: message = await unknownApiErrorText(errorCode, errorInfo); } break; } } message = cd.util.wrap(message); message.find('.mw-parser-output').css('display', 'inline'); logMessage = logMessage || [code, apiData]; break; } case 'network': case 'javascript': { message = (message ? message + ' ' : '') + cd.sParse(`error-${type}`); break; } } this.abort({ message, messageType, isRawMessage, logMessage, cancel, currentOperation }); } /** * Prepend indentation chars to code. * * @param {string} code * @param {string} indentationChars * @returns {string} * @private */ addIndentationChars(code, indentationChars) { return ( indentationChars + ( indentationChars && !/^[:*#]/.test(code) && cd.config.spaceAfterIndentationChars ? ' ' : '' ) + code ); } /** * Convert the text of the comment in the form to wikitext. * * @param {string} action `'submit'` (view changes maps to this too) or `'preview'`. * @returns {string} * @throws {CdError} */ commentTextToCode(action) { let indentationChars; // This is mostly to tell if inconvertible newlines would cause problems in the comment and // reflect that in the comment preview. let willCommentBeIndented = false; switch (this.mode) { case 'reply': indentationChars = this.target.inCode.replyIndentationChars; willCommentBeIndented = true; break; case 'edit': indentationChars = this.target.inCode.indentationChars; willCommentBeIndented = Boolean(indentationChars); break; case 'replyInSection': indentationChars = cd.config.defaultIndentationChar; if (this.target.inCode.lastCommentIndentationChars) { if (this.target.inCode.lastCommentIndentationChars[0] === '#') { indentationChars = '#'; } else if (cd.config.indentationCharMode === 'mimic') { indentationChars = this.target.inCode.lastCommentIndentationChars[0]; } } willCommentBeIndented = true; break; default: indentationChars = ''; } const isZeroLevel = ( action === 'preview' || ['addSection', 'addSubsection'].includes(this.mode) || (this.mode === 'edit' && !indentationChars) ); const newLineIndentationChars = indentationChars.replace(/\*/g, ':'); // Work with the code let code = this.commentInput.getValue(); if (cd.config.preTransformCode) { code = cd.config.preTransformCode(code, this); } code = code.trim(); let hidden; ({ code, hidden } = hideSensitiveCode(code)); let isWholeCommentInSmall = false; if (!this.headlineInput) { // If the user wrapped the comment in <small></small>, remove the tags to later wrap the // comment together with the signature into the tags and possibly ensure the correct line // spacing. code = code.replace(/^<small>([^]*)<\/small>$/i, (s, content) => { isWholeCommentInSmall = true; return content; }); } // Remove spaces from empty lines except when they are a part of the syntax creating <pre>. code = code .replace(/^(?:[ \t\xA0\uFEFF]*\n)+(?! )/gm, (s) => s.replace(/^[ \t\uFEFF\xA0]+/gm, '')); let signature; if (this.omitSignatureCheckbox?.isSelected()) { signature = ''; } else { signature = this.mode === 'edit' ? this.target.inCode.signatureCode : cd.g.CURRENT_USER_SIGNATURE; } // Make so that the signature doesn't turn out to be at the end of the last item of the list if // the comment contains one. if ( signature && (this.mode !== 'edit' || !/^[ \t]*\n/.test(signature)) && /\n[:*#].*$/.test(code) ) { code += '\n'; } if (!isZeroLevel) { // Add intentation characters to the lines with the list markup. code = code.replace(/\n([:*#]+)/g, (s, chars) => '\n' + newLineIndentationChars + chars); if (willCommentBeIndented && (/^[:*#]/m.test(code) || code.includes('\x03'))) { if (newLineIndentationChars === '#') { throw new CdError({ type: 'parse', code: 'numberedList-list', }); } // Table markup is OK only with colons as indentation characters. if (newLineIndentationChars.includes('#') && code.includes('\x03')) { throw new CdError({ type: 'parse', code: 'numberedList-table', }); } // Add intentation characters to the rest of the lines. code = code.replace(/\n(?!:)/g, () => ( '\n' + newLineIndentationChars + (cd.config.spaceAfterIndentationChars ? ' ' : '') )); } } if (willCommentBeIndented) { // Remove spaces in the beginning of the lines if the comment is indented. code = code.replace(/^ +/gm, ''); const replacement = cd.config.paragraphTemplates.length ? `$1{{${cd.config.paragraphTemplates[0]}}}` : '$1<br><br>'; code = code.replace(/^((?![:*#= ]).*)\n\n(?![:*#=])/gm, replacement); } // Process newlines by adding or not adding <br> and keeping or not keeping the newline. \x01 // and \x02 mean the beginning and ending of sensitive code except for tables. \x03 and \x04 // mean the beginning and ending of a table. Note: This should be kept coordinated with the // reverse transformation code in Comment#codeToText. const entireLineRegexp = new RegExp( `^(?:\\x01.+?\\x02|\\[\\[${cd.g.FILE_PREFIX_PATTERN}.+\\]\\]) *$`, 'i' ); const thisLineEndingRegexp = new RegExp( `(?:<${cd.g.PNIE_PATTERN}(?: [\\w ]+?=[^<>]+?| ?\\/?)>|<\\/${cd.g.PNIE_PATTERN}>|\\x04) *$`, 'i' ); const nextLineBeginningRegexp = new RegExp( `^(?:<\\/${cd.g.PNIE_PATTERN}>|<${cd.g.PNIE_PATTERN}|\\|)`, 'i' ); const headingRegexp = /^(=+).*\1[ \t]*$/; code = code.replace( /^((?![:*# ]).+)\n(?![\n:*# \x03])(?=(.*))/gm, (s, thisLine, nextLine) => { const br = ( // We assume that if a tag/template occupies an entire line or multiple lines, it's a // block tag/template and it doesn't need <br>s before or after it. A false positive is // possible in case of <nowiki> occupying an entire line (as of May 2020, no other inline // tags are hidden, see hideSensitiveCode() in wikitext.js). // https://en.wikipedia.org/w/index.php?diff=946978893 // https://en.wikipedia.org/w/index.php?diff=941991985 entireLineRegexp.test(thisLine) || entireLineRegexp.test(nextLine) || ( !willCommentBeIndented && (headingRegexp.test(thisLine) || headingRegexp.test(nextLine)) ) || // Removing <br>s after block elements is not a perfect solution as there would be no // newlines when editing such a comment, but this way we would avoid empty lines in cases // like "</div><br>". thisLineEndingRegexp.test(thisLine) || nextLineBeginningRegexp.test(nextLine) ) ? '' : '<br>'; const newline = willCommentBeIndented ? '' : '\n'; return thisLine + br + newline; } ); if (!this.omitSignatureCheckbox?.isSelected()) { // Remove signature tildes code = code.replace(/\s*~{3,}$/, ''); } // If the comment starts with a numbered list or table, replace all asterisks in the indentation // chars with colons to have the list or table form correctly. if (!isZeroLevel && /^(#|.*\x03)/.test(code)) { indentationChars = newLineIndentationChars; } // Add the headline if (this.headlineInput) { let level; if (this.mode === 'addSection') { level = 2; } else if (this.mode === 'addSubsection') { level = this.target.level + 1; } else { level = this.target.inCode.headingLevel; } const equalSigns = '='.repeat(level); if (this.editingSectionOpeningComment && /^\n/.test(this.target.inCode.code)) { // To have pretty diffs. code = '\n' + code; } code = `${equalSigns} ${this.headlineInput.getValue().trim()} ${equalSigns}\n${code}`; } // Add the signature if (action === 'preview' && signature) { signature = `<span class="cd-commentForm-signature">${signature}</span>`; } // Space in the beggining of the line, creating <pre>. if (/(?:^|\n) .*$/.test(code)) { code += '\n'; } // Remove starting spaces if the line starts with the signature. if (!code || code.endsWith('\n') || code.endsWith(' ')) { signature = signature.trimLeft(); } // Process the small font wrappers, add the signature. if (isWholeCommentInSmall && !this.headlineInput) { const spaceOrNot = /^[:*#]/.test(code) || !cd.config.spaceAfterIndentationChars ? '' : ' '; const indentation = newLineIndentationChars + spaceOrNot; const before = /^[:*# ]/.test(code) ? `\n${indentation}` : ''; if (cd.config.smallDivTemplates?.[0] && !/^[:*#]/m.test(code)) { const adjustedCode = code.replace(/\|/g, '{{!}}') + signature; code = `{{${cd.config.smallDivTemplates[0]}|1=${adjustedCode}}}`; } else { code = `<small>${before}${code}</small> ${signature}`; } } else { code += signature; } if (this.mode !== 'edit') { code += '\n'; } // Add the indentation characters if (action === 'submit') { code = this.addIndentationChars(code, indentationChars); // When an indented comment had been started with a list but the list has gone after editing. // Really rare but possible (see // https://ru.wikipedia.org/w/index.php?diff=next&oldid=105978713) case. if ( willCommentBeIndented && this.mode === 'edit' && /^[:*]/.test(this.target.inCode.code) && !/^[:*]/.test(code) ) { code = ' ' + code; } if (this.mode === 'addSubsection') { code += '\n'; } } // Imitate a list so that the user will see where it would break on a real page. This // pseudolist's margin is made invisible by CSS. let imitateList; if (action === 'preview' && willCommentBeIndented && this.commentInput.getValue().trim()) { code = code.replace(/^(?=(.?))/gm, (s, after) => ':' + (after === ';' ? ' ' : '')); imitateList = true; } else { imitateList = false; } code = unhideText(code, hidden); if (cd.config.postTransformCode) { code = cd.config.postTransformCode(code, this); } return { commentCode: code, imitateList, }; } /** * Prepare the new page code based on the form input. * * @param {string} pageCode * @param {string} action `'submit'` or `'viewChanges'`. * @returns {string} * @throws {CdError} * @private */ prepareNewPageCode(pageCode, action) { const doDelete = this.deleteCheckbox?.isSelected(); if (!(this.target instanceof Page)) { this.target.locateInCode(); } let { newPageCode, codeBeforeInsertion, commentCode } = this.target.modifyCode({ pageCode, action: this.mode, doDelete, commentForm: this, }); if (action === 'submit' && !doDelete) { // We need this only to generate anchors for the comments above our comment to avoid // collisions. extractSignatures(codeBeforeInsertion, true); } // Add anchor code to comments linked from the comment. const anchorsRegexp = /\[\[#(\d{12}_[^|\]]+)/g; const anchors = []; let match; while ((match = anchorsRegexp.exec(commentCode))) { anchors.push(match[1]); } anchors.forEach((anchor) => { const comment = Comment.getByAnchor(anchor); if (comment) { const commentInCode = comment.locateInCode(newPageCode); const anchorCode = cd.config.getAnchorCode(anchor); if (commentInCode.code.includes(anchorCode)) return; let commentStart = this.addIndentationChars( commentInCode.code, commentInCode.indentationChars ); const commentTextIndex = commentStart.match(/^[:*#]* */)[0].length; commentStart = ( commentStart.slice(0, commentTextIndex) + anchorCode + commentStart.slice(commentTextIndex) ); const commentCode = ( (commentInCode.headingCode || '') + commentStart + commentInCode.signatureDirtyCode ); ({ newPageCode } = comment.modifyCode({ pageCode: newPageCode, thisInCode: commentInCode, action: 'edit', commentCode, })); } else if (!$('#' + anchor).length) { throw new CdError({ type: 'parse', code: 'commentLinks-commentNotFound', details: { anchor }, }); } }); return newPageCode; } /** * Prepare the new page code and handle errors. * * @param {string} action `'submit'` or `'viewChanges'`. * @returns {string} newPageCode * @private */ async tryPrepareNewPageCode(action) { try { await this.targetPage.getCode(mw.config.get('wgArticleId') === 0); } catch (e) { if (e instanceof CdError) { const options = Object.assign({}, { message: cd.sParse('cf-error-getpagecode') }, e.data); this.handleError(options); } else { this.handleError({ type: 'javascript', logMessage: e, }); } return; } let newPageCode; try { newPageCode = this.prepareNewPageCode(this.targetPage.code, action); } catch (e) { if (e instanceof CdError) { this.handleError(e.data); } else { this.handleError({ type: 'javascript', logMessage: e, }); } return; } return newPageCode; } /** * Add an operation to the registry of operations. * * @param {Operation} operation * @returns {Operation} */ registerOperation(operation) { this.operations.push(operation); operation.isClosed = false; if (operation.type !== 'preview' || !operation.isAuto) { this.$messageArea.empty(); this.pushPending(['load', 'submit'].includes(operation.type), operation.affectHeadline); } return operation; } /** * Mark the operation as closed if it is not. Should be done when the operation has finished * (either successfully or not). * * @param {Operation} operation */ closeOperation(operation) { if (operation.isClosed) return; operation.isClosed = true; if (operation.type !== 'preview' || !operation.isAuto) { this.popPending(['load', 'submit'].includes(operation.type), operation.affectHeadline); } } /** * Check for conflicts of the operation with other pending operations, and if there are such, * close the operation and return `true` to abort it. The rules are the following: * - `preview` and `viewChanges` operations may be overriden with other of one of these types * (every new request replaces the old, although a new autopreview request cannot be made while * the old is pending). * - `submit` operations may not be overriden (and are not checked by this function), but also * don't override existing `preview` and `viewChanges` operations (so that the user gets the last * autopreview even after they have sent the comment). * * For convenience, can also check for an arbitrary condition and close the operation if it is * `true`. * * @param {Operation} operation * @returns {boolean} */ closeOperationIfNecessary(operation) { if (operation.isClosed) { return true; } const otherOperationIndex = findLastIndex( this.operations, (op) => operation !== op && ['preview', 'viewChanges'].includes(op.type) && !op.isDelayed ); if (otherOperationIndex !== null && otherOperationIndex > this.operations.indexOf(operation)) { this.closeOperation(operation); return true; } else { return false; } } /** * Remove the operation from the registry of operations. * * @param {Operation} operation */ unregisterOperation(operation) { if (this.operations.includes(operation)) { this.operations.splice(this.operations.indexOf(operation), 1); } // This was excessive at the time when it was written as the only use case is autopreview. if (operation.type !== 'preview' || !operation.isAuto) { this.popPending(operation.type === 'submit', operation.affectHeadline); } } /** * Whether the form is being submitted right now. * * @returns {boolean} */ isBeingSubmitted() { return this.operations.some((op) => op.type === 'submit' && !op.isClosed); } /** * Preview the comment. * * @param {boolean} [previewEmpty=true] If `false`, don't preview if the comment and headline * inputs are empty. * @param {boolean} [isAuto=true] Preview is initiated automatically (if the user has * `cd.settings.autopreview` as `true`). * @param {boolean} [operation] Operation object when the function is called from within itself, * being delayed. * @fires previewReady */ async preview(previewEmpty = true, isAuto = true, operation) { if ( this.operations.some((op) => !op.isClosed && op.type === 'load') || ( !(this.target instanceof Page) && !this.target.inCode && this.checkCodeRequest && (await nativePromiseState(this.checkCodeRequest)) === 'resolved' ) || this.isBeingSubmitted() || (isAuto && !cd.settings.autopreview) ) { if (operation) { this.closeOperation(operation); } return; } const currentOperation = ( operation || this.registerOperation({ type: 'preview', isAuto, }) ); if (isAuto) { const isTooEarly = Date.now() - this.lastPreviewTimestamp < 1000; if ( isTooEarly || this.operations .some((op) => !op.isClosed && op.type === 'preview' && op !== currentOperation) ) { if (this.previewTimeout) { this.unregisterOperation(currentOperation); } else { currentOperation.isDelayed = true; this.previewTimeout = setTimeout(() => { this.previewTimeout = null; this.preview(previewEmpty, true, currentOperation); }, isTooEarly ? 1000 - (Date.now() - this.lastPreviewTimestamp) : 100); } return; } this.lastPreviewTimestamp = Date.now(); } if (this.closeOperationIfNecessary(currentOperation)) return; /* This happens: - when restoring the form from a session, - when the target comment has not been loaded yet, possibly because of an error when tried to (if the mode is 'edit' and the comment has not been loaded, this method would halt after the looking for the unclosed 'load' operation above). */ if (!(this.target instanceof Page) && !this.target.inCode) { await this.checkCode(); if (!this.target.inCode) { this.closeOperation(currentOperation); } if (currentOperation.isClosed) return; } // In case of an empty comment input, we in fact make this request for the sake of parsing the // summary if there is a need. The other possibility is previewing by clicking the relevant // button. const areInputsEmpty = ( !this.commentInput.getValue().trim() && !this.headlineInput?.getValue().trim() ); if (areInputsEmpty && !previewEmpty) { this.closeOperation(currentOperation); return; } const { commentCode, imitateList } = this.commentTextToCode('preview'); let html; let parsedSummary; try { ({ html, parsedSummary } = await parseCode(commentCode, { title: this.targetPage.name, summary: cd.util.buildEditSummary({ text: this.summaryInput.getValue() }), })); } catch (e) { if (e instanceof CdError) { const options = Object.assign({}, e.data, { message: cd.sParse('cf-error-preview'), currentOperation, }); this.handleError(options); } else { this.handleError({ type: 'javascript', logMessage: e, currentOperation, }); } return; } if (this.closeOperationIfNecessary(currentOperation)) return; if (html) { if ((isAuto && areInputsEmpty) || this.deleteCheckbox?.isSelected()) { this.$previewArea.empty(); } else { const $label = $('<div>') .addClass('cd-previewArea-label') .text(cd.s('cf-block-preview')); this.$previewArea .html(html) .prepend($label) .cdAddCloseButton(); if (imitateList) { this.$previewArea.addClass('cd-previewArea-indentedComment'); } else { this.$previewArea.removeClass('cd-previewArea-indentedComment'); } /** * A comment preview has been rendered. * * @event previewReady * @type {JQuery} */ mw.hook('convenientDiscussions.previewReady').fire(this.$previewArea); if (!isAuto) { mw.hook('wikipage.content').fire(this.$previewArea); } } const $comment = $('<span>') .addClass('comment') .append(parsedSummary); this.$summaryPreview.empty(); if (parsedSummary) { const $colon = $('<span>').text(cd.mws('colon-separator')); const $previewLabel = $('<span>').text(cd.s('cf-summary-preview')); this.$summaryPreview.append($previewLabel, $colon, $comment); } } if (cd.settings.autopreview && this.previewButton.$element.is(':visible')) { this.previewButton.$element.hide(); this.viewChangesButton.$element.show(); this.adjustLabels(); } if (!isAuto) { this.commentInput.focus(); this.$previewArea.cdScrollIntoView( this.$previewArea.hasClass('cd-previewArea-above') ? 'top' : 'bottom' ); } this.closeOperation(currentOperation); } /** * View changes in the page code after submitting the form. */ async viewChanges() { if (this.isBeingSubmitted()) return; const currentOperation = this.registerOperation({ type: 'viewChanges' }); const newPageCode = await this.tryPrepareNewPageCode('viewChanges'); if (newPageCode === undefined) { this.closeOperation(currentOperation); } if (currentOperation.isClosed) return; mw.loader.load('mediawiki.diff.styles'); let resp; try { const options = { action: 'compare', toslots: 'main', 'totext-main': newPageCode, prop: 'diff', formatversion: 2, }; if (mw.config.get('wgArticleId')) { options.fromrev = this.targetPage.revisionId; } else { // Unexistent pages options.fromslots = 'main', options['fromtext-main'] = ''; } resp = await cd.g.api.post(options).catch(handleApiReject); } catch (e) { if (e instanceof CdError) { const options = Object.assign({}, e.data, { message: cd.sParse('cf-error-viewchanges'), currentOperation, }); this.handleError(options); } else { this.handleError({ type: 'javascript', logMessage: e, currentOperation, }); } return; } if (this.closeOperationIfNecessary(currentOperation)) return; let html = resp.compare?.body; if (html) { html = cd.util.wrapDiffBody(html); const $label = $('<div>') .addClass('cd-previewArea-label') .text(cd.s('cf-block-viewchanges')); this.$previewArea .html(html) .prepend($label) .cdAddCloseButton(); } else { this.$previewArea.empty(); if (html !== undefined) { this.showMessage(cd.sParse('cf-notice-nochanges')); } } if (cd.settings.autopreview) { this.viewChangesButton.$element.hide(); this.previewButton.$element.show(); this.adjustLabels(); } this.$previewArea.cdScrollIntoView( this.$previewArea.hasClass('cd-previewArea-above') ? 'top' : 'bottom' ); this.commentInput.focus(); this.closeOperation(currentOperation); } /** * Forget the form and reload the page. * * @param {object} [keptData] Data passed from the previous page state. * @param {Operation} [currentOperation] Current operation. */ async reloadPage(keptData, currentOperation) { this.forget(); try { await reloadPage(keptData); } catch (e) { if (e instanceof CdError) { const options = Object.assign({}, e.data, { message: cd.sParse('error-reloadpage-saved'), cancel: true, currentOperation, }); this.handleError(options); } else { this.handleError({ type: 'javascript', logMessage: e, cancel: true, currentOperation, }); } removeLoadingOverlay(); } } /** * Run checks before submitting the form. * * @param {object} options * @param {boolean} options.doDelete * @returns {boolean} * @private */ async runChecks({ doDelete }) { const checks = [ { condition: !doDelete && this.headlineInput?.getValue() === '', confirmation: async () => { const noHeadline = cd.s( 'cf-confirm-noheadline-' + (this.headlineInputPurpose === cd.s('cf-headline-topic') ? 'topic' : 'subsection') ); return await OO.ui.confirm(noHeadline + ' ' + cd.s('cf-confirm-noheadline-question')); }, }, { condition: ( !doDelete && !this.commentInput.getValue().trim() && !cd.config.noConfirmPostEmptyCommentPageRegexp?.test(cd.g.CURRENT_PAGE.name) ), confirmation: async () => await OO.ui.confirm(cd.s('cf-confirm-empty')), }, { condition: ( !doDelete && this.commentInput.getValue().trim().length > cd.config.longCommentThreshold ), confirmation: async () => ( await OO.ui.confirm(cd.s('cf-confirm-long', cd.config.longCommentThreshold)) ), }, { condition: ( !doDelete && /^==[^=]/m.test(this.commentInput.getValue()) && this.mode !== 'edit' ), confirmation: async () => await OO.ui.confirm(cd.s('cf-confirm-secondlevelheading')), }, { condition: doDelete, confirmation: async () => await confirmDestructive('cf-confirm-delete'), } ]; for (const check of checks) { if (check.condition && !(await check.confirmation())) { this.commentInput.focus(); return false; } } return true; } /** * Send a post request to edit the page and handle errors. * * @param {object} page * @param {string} newPageCode * @param {Operation} currentOperation * @returns {?object} * @private */ async tryEditPage(page, newPageCode, currentOperation) { let result; try { result = await this.targetPage.edit({ text: newPageCode, summary: cd.util.buildEditSummary({ text: this.summaryInput.getValue() }), tags: cd.config.tagName, baserevid: page.revisionId, starttimestamp: page.queryTimestamp, minor: this.minorCheckbox?.isSelected(), watchlist: this.watchCheckbox.isSelected() ? 'watch' : 'unwatch', }); } catch (e) { if (e instanceof CdError) { const { type, details } = e.data; if (type === 'network') { this.handleError({ type, message: cd.sParse('cf-error-couldntedit'), currentOperation, }); } else { let messageType; let { code, message, isRawMessage, logMessage } = details; if (code === 'editconflict') { message += ' ' + cd.sParse('cf-notice-editconflict-retrying'); messageType = 'notice'; this.submit(); } // FIXME: We don't pass apiData to prevent the message for "missingtitle" to be overriden, // which is hacky. this.handleError({ type, message, messageType, isRawMessage, logMessage, currentOperation, }); } } else { this.handleError({ type: 'javascript', logMessage: e, currentOperation, }); } return null; } return result; } /** * Submit the form. */ async submit() { if (this.operations.some((op) => !op.isClosed && op.type === 'load')) return; const doDelete = this.deleteCheckbox?.isSelected(); if (!(await this.runChecks({ doDelete }))) return; const currentOperation = this.registerOperation({ type: 'submit' }); const otherFormsSubmitted = cd.commentForms .some((commentForm) => commentForm !== this && commentForm.isBeingSubmitted()); if (otherFormsSubmitted) { this.handleError({ type: 'ui', message: cd.sParse('cf-error-othersubmitted'), currentOperation, }); return; } const newPageCode = await this.tryPrepareNewPageCode('submit'); if (newPageCode === undefined) { this.closeOperation(currentOperation); return; } const editTimestamp = await this.tryEditPage( this.targetPage, newPageCode, currentOperation ); if (!editTimestamp) return; // Here we use a trick where we pass, in keptData, the name of the section that was set to be // watched/unwatched using a checkbox in a form just sent. The server doesn't manage to update // the value quickly enough, so it returns the old value, but we must display the new one. const keptData = { didSubmitCommentForm: true }; // When creating a page if (!mw.config.get('wgArticleId')) { mw.config.set('wgArticleId', this.targetPage.pageId); keptData.wasPageCreated = true; } if (this.watchSectionCheckbox) { if (this.watchSectionCheckbox.isSelected()) { const isHeadlineAltered = ( this.editingSectionOpeningComment && this.headlineInput.getValue() !== this.originalHeadline ); if (this.mode === 'addSection' || this.mode === 'addSubsection' || isHeadlineAltered) { const headline = removeWikiMarkup(this.headlineInput.getValue()); keptData.justWatchedSection = headline; let originalHeadline; if (isHeadlineAltered) { originalHeadline = removeWikiMarkup(this.originalHeadline); keptData.justUnwatchedSection = originalHeadline; } Section.watch(headline, originalHeadline).catch(() => {}); } else { const section = this.targetSection; if (section && !section.isWatched) { section.watch(true); keptData.justWatchedSection = section.headline; } } } else { const section = this.targetSection; if (section?.isWatched) { section.unwatch(true); keptData.justUnwatchedSection = section.headline; } } } if (this.watchCheckbox.isSelected() && $('#ca-watch').length) { $('#ca-watch').attr('id', 'ca-unwatch'); } if (!this.watchCheckbox.isSelected() && $('#ca-unwatch').length) { $('#ca-unwatch').attr('id', 'ca-watch'); } if (!doDelete) { keptData.commentAnchor = this.mode === 'edit' ? this.target.anchor : generateCommentAnchor(new Date(editTimestamp), cd.g.CURRENT_USER_NAME, true); } // When the edit takes place on another page that is transcluded in the current one, we must // purge the current page, otherwise we may get an old version without the submitted comment. if (this.targetPage !== cd.g.CURRENT_PAGE) { await cd.g.CURRENT_PAGE.purge(); } this.reloadPage(keptData, currentOperation); } /** * Ask for a confirmation to close the form if necessary. * * @returns {boolean} */ async confirmClose() { return (!this.isAltered() || (await confirmDestructive('cf-confirm-close'))); } /** * Close the form. * * @param {boolean} [confirmClose=true] Whether to confirm form close. */ async cancel(confirmClose = true) { if (cd.util.isPageOverlayOn() || this.isBeingSubmitted()) return; if (confirmClose && !(await this.confirmClose())) { this.commentInput.focus(); return; } this.destroy(); if (this.mode === 'reply') { this.target.scrollIntoView('top'); } else if (this.mode === 'replyInSection') { this.target.$replyButton.show(); this.target.$replyWrapper.removeClass('cd-replyWrapper-hasCommentForm'); } else if (this.mode === 'edit') { this.target.$elements.removeClass('cd-hidden'); this.target.scrollIntoView('top'); this.target.configureLayers(); } else if (this.mode === 'addSection' && cd.g.$addSectionButtonContainer) { cd.g.$addSectionButtonContainer.show(); } } /** * Remove the elements and other objects' properties related to the form. */ destroy() { this.$outermostElement.remove(); this.operations .filter((op) => !op.isClosed) .forEach(this.closeOperation.bind(this)); this.forget(); /** * Has the comment form been {@link module:CommentForm#destroy destroyed}. * * @type {boolean} */ this.isDestroyed = true; } /** * Remove the references to the form and unload it from the session data thus making it not appear * after a page reload. * * @private */ forget() { if (this.mode === 'addSection') { delete cd.g.addSectionForm; } else { delete this.target[CommentForm.modeToProperty(this.mode) + 'Form']; } if (cd.commentForms.includes(this)) { cd.commentForms.splice(cd.commentForms.indexOf(this), 1); } saveSession(); navPanel.updateCommentFormButton(); } /** * Check if the form was altered. This means the values of the text fields (but not the state of * checkboxes) are different from initial. * * @returns {boolean} */ isAltered() { // In case of the comment being edited some properties would be undefined if its code was not // located in the source. return ( ( this.originalComment !== undefined && this.originalComment !== this.commentInput.getValue() ) || this.autoSummary !== this.summaryInput.getValue() || ( this.headlineInput && this.originalHeadline !== undefined && this.originalHeadline !== this.headlineInput.getValue() ) ); } /** * Update the automatic text for the edit summary. * * @param {boolean} [set=true] Whether to actually set the input value, or just save auto summary * to a property. * @param {boolean} [dontAutopreviewOnSummaryChange=false] Whether to prevent making autopreview * request in order not to make two identical requests (for example, if the update is initiated * by a change in the comment). * @private */ updateAutoSummary(set = true, dontAutopreviewOnSummaryChange = false) { if (this.isSummaryAltered) return; this.dontAutopreviewOnSummaryChange = dontAutopreviewOnSummaryChange; const text = this.autoText(); const section = this.headlineInput && this.mode !== 'addSubsection' ? removeWikiMarkup(this.headlineInput.getValue()) : this.sectionHeadline; let optionalText; if (['reply', 'replyInSection'].includes(this.mode)) { const commentText = this.commentInput.getValue() .trim() .replace(/\s+/g, ' ') // Remove user links to prevent sending a double notification. .replace(/\[\[:?(?:([^|[\]<>\n]+)\|)?(.+?)\]\]/g, (s, wikilink, text) => ( cd.g.USER_NAMESPACE_ALIASES_REGEXP.test(wikilink) ? text : s )); if (commentText && commentText.length <= cd.config.summaryCommentTextLengthLimit) { optionalText = `: ${commentText} (-)`; } } else if (this.mode === 'addSubsection') { const subsection = removeWikiMarkup(this.headlineInput.getValue()); if (subsection) { optionalText = `: /* ${subsection} */`; } } this.autoSummary = cd.util.buildEditSummary({ text, section, optionalText, addPostfix: false, }); if (set) { this.summaryInput.setValue(this.autoSummary); } } /** * Generate the _static_ part of the automatic text for the edit summary, excluding the section * headline. * * @returns {string} * @private */ autoText() { this.updateAutoSummaryBound = this.updateAutoSummaryBound || this.updateAutoSummary.bind(this); switch (this.mode) { case 'reply': { if (this.target.isOpeningSection) { return cd.s('es-reply'); } else { this.target.requestAuthorGenderIfNeeded(this.updateAutoSummaryBound); return this.target.isOwn ? cd.s('es-addition') : removeDoubleSpaces(cd.s('es-reply-to', this.target.author.name, this.target.author)); } } case 'edit': { // The codes for generating "edit" and "delete" descriptions are equivalent, so we provide // an umbrella function. const editOrDeleteText = (action) => { let subject; let target = this.target; if (this.target.isOwn) { const targetParent = this.target.getParent(); if (targetParent) { if (targetParent.level === 0) { subject = 'reply'; } else { targetParent.requestAuthorGenderIfNeeded(this.updateAutoSummaryBound); subject = targetParent.isOwn ? 'addition' : 'reply-to'; target = targetParent; } } else { if (this.target.isOpeningSection) { subject = this.targetSection.getParent() ? 'subsection' : 'topic'; } else { subject = 'comment'; } } } else { if (this.target.isOpeningSection) { subject = this.targetSection.getParent() ? 'subsection' : 'topic'; } else { this.target.requestAuthorGenderIfNeeded(this.updateAutoSummaryBound); subject = 'comment-by'; } } return removeDoubleSpaces( cd.s(`es-${action}-${subject}`, target.author.name, target.author) ); }; return editOrDeleteText(this.deleteCheckbox?.isSelected() ? 'delete' : 'edit'); } case 'replyInSection': { return cd.s('es-reply'); } case 'addSection': { return this.preloadConfig?.summary || cd.s('es-new-topic'); } case 'addSubsection': { return cd.s('es-new-subsection'); } } } /** * Handle the delete checkbox change, setting form elements as disabled or enabled. * * @param {boolean} selected * @private */ updateFormOnDeleteCheckboxChange(selected) { if (selected) { this.initialMinorCheckboxSelected = this.minorCheckbox.isSelected(); this.minorCheckbox.setSelected(false); this.commentInput.setDisabled(true); this.headlineInput?.setDisabled(true); this.minorCheckbox.setDisabled(true); this.omitSignatureCheckbox?.setDisabled(true); this.submitButtonLabelStandard = cd.s('cf-delete-button'); this.submitButtonLabelShort = cd.s('cf-delete-button-short'); this.submitButton .clearFlags() .setFlags(['destructive', 'primary']) .setLabel( this.$element.hasClass('cd-commentForm-short') ? this.submitButtonLabelStandard : this.submitButtonLabelShort ); } else { this.minorCheckbox.setSelected(this.initialMinorCheckboxSelected); this.commentInput.setDisabled(false); this.headlineInput?.setDisabled(false); this.minorCheckbox.setDisabled(false); this.omitSignatureCheckbox?.setDisabled(false); this.submitButtonLabelStandard = cd.s('cf-save'); this.submitButtonLabelShort = cd.s('cf-save-short'); this.submitButton .clearFlags() .setFlags(['progressive', 'primary']) .setLabel( this.$element.hasClass('cd-commentForm-short') ? this.submitButtonLabelStandard : this.submitButtonLabelShort ); } } /** * Insert "@" into the comment input, activating the mention autocomplete menu. * * @param {boolean} mentionAddressee Don't show the autocomplete menu, just insert a mention of * the addressee to the beginning of the comment input. */ mention(mentionAddressee) { if (mentionAddressee && this.targetComment) { let data = Autocomplete.getConfig('mentions').transform(this.targetComment.author.name); data = data.ctrlModify(data); const text = data.start + data.content + data.end; const range = this.commentInput.getRange(); this.commentInput.selectRange(0); insertText(this.commentInput, text); this.commentInput.selectRange(range.from + text.length, range.to + text.length); return; } const caretIndex = this.commentInput.getRange().to; // Prevent removal of text if (this.commentInput.getRange().from !== caretIndex) { this.commentInput.selectRange(caretIndex); } const lastChar = caretIndex && this.commentInput.getValue().slice(caretIndex - 1, caretIndex); if (caretIndex && !/\s/.test(lastChar)) { insertText(this.commentInput, ' '); } this.autocomplete.tribute.showMenuForCollection( this.commentInput.$input.get(0), this.autocomplete.tribute.collection .findIndex((collection) => collection.trigger === cd.config.mentionCharacter) ); } /** * Quote the selected text. * * @param {boolean} [allowEmptySelection=true] Insert markup (with a placeholder text) even if the * selection is empty. */ quote(allowEmptySelection = true) { const selection = isInputFocused() ? document.activeElement.value .substring(document.activeElement.selectionStart, document.activeElement.selectionEnd) : window.getSelection().toString(); // With just "Q" pressed, empty selection doesn't count. if (selection || allowEmptySelection) { const isCommentInputFocused = this.commentInput.$input.is(':focus'); const range = this.commentInput.getRange(); const caretIndex = range.to; let rangeStart = Math.min(range.to, range.from); let rangeEnd = Math.max(range.to, range.from); // Reset the selection if the input is not focused to prevent losing text. if (!isCommentInputFocused && rangeStart !== rangeEnd) { this.commentInput.selectRange(caretIndex); rangeStart = rangeEnd = caretIndex; } this.encapsulateSelection({ pre: cd.config.quoteFormatting[0], peri: cd.s('cf-quote-placeholder'), post: cd.config.quoteFormatting[1], selection, trim: true, leadingNewline: true, }); } } /** * Wrap the selected text in the comment input with other text, optionally falling back to the * provided value if no text is selected. * * @param {object} options * @param {string} [options.pre] Text to insert before the caret/selection. * @param {string} [options.peri=''] Fallback value used instead of the selection. * @param {string} [options.post] Text to insert after the caret/selection. * @param {string} [options.replace=false] If there is a selection, replace it with peri instead * of leaving it alone. * @param {string} [options.selection] The selected text. Use if it is out of the input. * @param {boolean} [options.trim] Trim the selection. * @param {boolean} [options.leadingNewline] Put a newline before the resulting text to insert if * it is not already there. */ encapsulateSelection({ pre = '', peri = '', post = '', selection, replace = false, trim, leadingNewline, }) { const range = this.commentInput.getRange(); const selectionStartPos = Math.min(range.from, range.to); const value = this.commentInput.getValue(); const leadingNewlineChar = ( leadingNewline && !/(^|\n)$/.test(value.slice(0, selectionStartPos)) ? '\n' : '' ); let periStartPos; const getSelection = !selection && !(peri && replace); if (getSelection) { periStartPos = selectionStartPos + leadingNewlineChar.length + pre.length; selection = value.substring(range.from, range.to); } else { selection = selection || ''; } if (trim) { selection = selection.trim(); } // Wrap text moving the leading and trailing spaces to the sides of the resulting text. const [leadingSpace] = selection.match(/^ */); const [trailingSpace] = selection.match(/ *$/); const middleText = selection || peri; const text = ( leadingNewlineChar + leadingSpace + pre + middleText.slice(leadingSpace.length, middleText.length - trailingSpace.length) + post + trailingSpace ); insertText(this.commentInput, text); if (getSelection) { this.commentInput.selectRange(periStartPos, periStartPos + peri.length); } } } Object.assign(CommentForm, CommentFormStatic); "
"/** * Methods related to comments. * * @module CommentStatic */ import Comment from './Comment'; import Section from './Section'; import cd from './cd'; import navPanel from './navPanel'; import { getExtendedRect, reorderArray } from './util'; export default { /** * Configure and add underlayers for a group of comments. * * @param {Comment[]} comments * @memberof module:Comment */ configureAndAddLayers(comments) { let floatingRects; if (comments.length) { floatingRects = cd.g.floatingElements.map(getExtendedRect); } comments.forEach((comment) => { comment.configureLayers({ add: false, update: false, floatingRects, }); }); // Faster to add them in one sequence. comments.forEach((comment) => { comment.addLayers(); }); }, /** * Mark comments that are currently in the viewport as read, and also {@link module:Comment#flash * flash} comments that are prescribed to flash. * * @memberof module:Comment */ registerSeen() { const commentInViewport = Comment.findInViewport(); if (!commentInViewport) return; const registerIfInViewport = (comment) => { const isInViewport = comment.isInViewport(); if (isInViewport) { comment.registerSeen(); return false; } else if (isInViewport === false) { // isInViewport could also be null. return true; } }; // Back cd.comments .slice(0, commentInViewport.id) .reverse() .some(registerIfInViewport); // Forward cd.comments .slice(commentInViewport.id) .some(registerIfInViewport); }, /** * Object with the same basic structure as {@link module:CommentSkeleton} has. (It comes from a * web worker so its constuctor is lost.) * * @typedef {object} CommentSkeletonLike */ /** * Turn comment array into object with section anchors as keys. * * @param {CommentSkeletonLike[]|Comment[]} comments * @returns {Map} * @private * @memberof module:Comment */ groupBySection(comments) { const commentsBySection = new Map(); comments.forEach((comment) => { let sectionOrAnchor; if (comment instanceof Comment) { sectionOrAnchor = comment.getSection(); } else if (comment.section) { sectionOrAnchor = comment.section.match || comment.section.anchor; } else { sectionOrAnchor = null; } if (!commentsBySection.get(sectionOrAnchor)) { commentsBySection.set(sectionOrAnchor, []); } commentsBySection.get(sectionOrAnchor).push(comment); }); return commentsBySection; }, /** * Find any one comment inside the viewport. * * @param {string} [findClosestDirection] If there is no comment in the viewport, find the closest * comment in the specified direction. * @returns {?Comment} * @memberof module:Comment */ findInViewport(findClosestDirection) { const viewportTop = window.pageYOffset; const viewportBottom = viewportTop + window.innerHeight; // Visibility in the sense that an element is visible on the page, not necessarily in the // viewport. const isVisible = (comment) => { comment.getPositions(); return Boolean(comment.positions); }; const findVisible = (direction, startIndex = 0) => { const comments = reorderArray(cd.comments, startIndex, direction === 'backward'); return comments.find(isVisible) || null; }; const firstVisibleComment = findVisible('forward'); const lastVisibleComment = findVisible('backward', cd.comments.length - 1); if (!firstVisibleComment) { return null; } let searchArea = { top: firstVisibleComment, bottom: lastVisibleComment, }; let currentComment = searchArea.top; let foundComment; const findClosest = (direction, searchArea, reverse = false) => { if (direction === 'forward') { return findVisible(direction, reverse ? searchArea.top.id : searchArea.bottom.id); } else if (direction === 'backward') { return findVisible(direction, reverse ? searchArea.bottom.id : searchArea.top.id); } return null; }; // Here, we don't iterate over cd.comments as it may look like. We narrow the search region by // getting a proportion of the distance between far away comments and the viewport and // calculating the ID of the next comment based on it; then, the position of that next comment // is checked, and so on. cd.comments.length value is used as an upper boundary for the number // of cycle steps. It's more of a protection against an infinite loop: the value is with a large // margin and not practically reachable, unless when there is only few comments. Usually the // cycle finishes after a few steps. for (let i = 0; i < cd.comments.length; i++) { if (currentComment.isInViewport()) { foundComment = currentComment; break; } if ( currentComment.positions && // The bottom edge of the viewport is above the first comment. ( currentComment === firstVisibleComment && viewportBottom < currentComment.positions.downplayedBottom ) || // The top edge of the viewport is below the last comment. (currentComment === lastVisibleComment && viewportTop > currentComment.positions.top) ) { foundComment = findClosest(findClosestDirection, searchArea, true); break; } if (searchArea.top === searchArea.bottom) { foundComment = findClosest(findClosestDirection, searchArea); break; } if (!currentComment.positions) { // To avoid contriving a sophisticated algorithm for choosing which comment to pick next // (and avoid picking any previously picked) we just pick the comment next to the beginning // of the search area. currentComment = cd.comments[searchArea.top.id + 1]; searchArea.top = currentComment; continue; } if (currentComment === firstVisibleComment) { currentComment = searchArea.bottom; } else { searchArea[viewportTop > currentComment.positions.top ? 'top' : 'bottom'] = currentComment; // There's not a single comment in the viewport. if (searchArea.bottom.id - searchArea.top.id <= 1) { foundComment = findClosest(findClosestDirection, searchArea); break; } // Determine the ID of the next comment to check. const higherTop = searchArea.top.positions.top; const lowerBottom = searchArea.bottom.positions.downplayedBottom; const proportion = ( (viewportTop - higherTop) / ((lowerBottom - viewportBottom) + (viewportTop - higherTop)) ); if (proportion < 0 || proportion >= 1) { console.warn( 'The proportion shouldn\'t be more than 0 or less or equal to 1.', 'proportion', proportion, 'searchArea', searchArea ); } currentComment = cd.comments[Math.round( (searchArea.bottom.id - searchArea.top.id - 1) * proportion + searchArea.top.id + 0.5 )]; } } return foundComment || null; }, /** * Handles the `mousemove` and `mouseover` events and highlights hovered comments even when the * cursor is between comment parts, not over them. * * @param {Event} e * @memberof module:Comment */ highlightFocused(e) { if (cd.g.dontHandleScroll || cd.g.autoScrollInProgress || cd.util.isPageOverlayOn()) return; const isObstructingElementHovered = ( Array.from(cd.g.NOTIFICATION_AREA?.querySelectorAll('.mw-notification')) .some((notification) => notification.matches(':hover')) || cd.g.activeAutocompleteMenu?.matches(':hover') || // In case the user has moved the navigation panel to the other side. navPanel.$element?.get(0).matches(':hover') || // WikiEditor dialog $(document.body).children('.ui-widget-overlay').length || cd.g.$popupsOverlay ?.get(0) .querySelector('.oo-ui-popupWidget:not(.oo-ui-element-hidden)') ?.matches(':hover') ); cd.comments .filter((comment) => comment.underlay) .forEach((comment) => { const layersContainerOffset = comment.getLayersContainerOffset(); if ( !isObstructingElementHovered && e.pageY >= comment.layersTop + layersContainerOffset.top && e.pageY <= comment.layersTop + comment.layersHeight + layersContainerOffset.top && e.pageX >= comment.layersLeft + layersContainerOffset.left && e.pageX <= comment.layersLeft + comment.layersWidth + layersContainerOffset.left ) { comment.highlightFocused(); } else { comment.unhighlightFocused(); } }); }, /** * Get a comment by anchor. * * @param {string} anchor * @returns {?Comment} * @memberof module:Comment */ getByAnchor(anchor) { if (!cd.comments || !anchor) { return null; } return cd.comments.find((comment) => comment.anchor === anchor) || null; }, }; "
"/** * Comment class. * * @module Comment */ import CdError from './CdError'; import CommentForm from './CommentForm'; import CommentSkeleton from './CommentSkeleton'; import CommentStatic from './CommentStatic'; import cd from './cd'; import commentLayers from './commentLayers'; import userRegistry from './userRegistry'; import { ElementsTreeWalker, TreeWalker } from './treeWalker'; import { areObjectsEqual, calculateWordsOverlap, caseInsensitiveFirstCharPattern, dealWithLoadingBug, defined, getExtendedRect, getFromLocalStorage, handleApiReject, isInline, saveToLocalStorage, unhideText, } from './util'; import { copyLink } from './modal.js'; import { decodeHtmlEntities, extractSignatures, hideDistractingCode, hideSensitiveCode, hideTemplatesRecursively, normalizeCode, removeWikiMarkup, } from './wikitext'; import { getUserGenders, parseCode } from './apiWrappers'; import { reloadPage } from './boot'; let thanks; /** * Remove thanks older than 60 days. * * @param {object[]} data * @returns {object} * @private */ function cleanUpThanks(data) { const newData = Object.assign({}, data); Object.keys(newData).forEach((key) => { if ( !newData[key].thankUnixTime || newData[key].thankUnixTime < Date.now() - 60 * cd.g.SECONDS_IN_A_DAY * 1000 ) { delete newData[key]; } }); return newData; } /** * Class representing a comment (any signed, and in some cases unsigned, text on a wiki talk page). * * @augments module:CommentSkeleton */ export default class Comment extends CommentSkeleton { /** * Create a comment object. * * @param {Parser} parser A relevant instance of {@link module:Parser Parser}. * @param {object} signature Signature object returned by {@link * module:Parser#findSignatures}. */ constructor(parser, signature) { super(parser, signature); this.elementPrototypes = cd.g.COMMENT_ELEMENT_PROTOTYPES; /** * Comment author {@link module:userRegistry~User user object}. * * @type {User} */ this.author = userRegistry.getUser(this.authorName); /** * Comment signature element as a jQuery object. * * @type {JQuery} */ this.$signature = $(signature.element); delete this.signatureElement; /** * Comment timestamp element as a jQuery object. * * @type {JQuery} */ this.$timestamp = $(signature.timestampElement); /** * Is the comment actionable, i.e. you can reply to or edit it. A comment is actionable if it is * not in a closed discussion or an old diff page. (Previously the presence of an author was * also checked, but currently all comments should have an author.) * * @type {boolean} */ this.isActionable = ( cd.g.isPageActive && !cd.g.closedDiscussionElements.some((el) => el.contains(this.elements[0])) ); this.highlightables.forEach((el) => { this.bindEvents(el); }); /** * Is the comment currently highlighted as the target comment. * * @type {boolean} */ this.isTarget = false; /** * Is the comment currently focused. * * @type {boolean} */ this.isFocused = false; /** * Was the comment edited since the previous visit. * * @type {?boolean} */ this.isEditedSincePreviousVisit = null; /** * Was the comment edited while the page was idle. (The new version may be rendered or may be * not, if the layout is too complex.) * * @type {?boolean} */ this.isEdited = null; /** * Was the comment deleted while the page was idle. * * @type {?boolean} */ this.isDeleted = null; /** * Should the comment be flashed as updated when it appears in sight. * * @type {?boolean} */ this.isFlashNewOnSightSet = false; } /** * Bind the standard events to a comment part. Executed on comment object creation and DOM * modifications affecting comment parts. * * @param {Element} el */ bindEvents(el) { el.onmouseenter = this.highlightFocused.bind(this); el.onmouseleave = this.unhighlightFocused.bind(this); el.ontouchstart = this.highlightFocused.bind(this); } /** * Get the comment coordinates and set them as the `positions` comment property. If the comment is * invisible, positions are unset. * * Note that comment coordinates are not static, obviously, but we need to recalculate them only * occasionally. * * @param {object} [options={}] * @private */ getPositions(options = {}) { if (options.considerFloating === undefined) { options.considerFloating = false; } this.positions = null; if (this.editForm) return; let rectTop = options.rectTop || this.highlightables[0].getBoundingClientRect(); let rectBottom = ( options.rectBottom || ( this.elements.length === 1 ? rectTop : this.highlightables[this.highlightables.length - 1].getBoundingClientRect() ) ); // If the element has 0 as the left position and height, it's probably invisible for some // reason. if (rectTop.left === 0 && rectTop.height === 0) return; const top = window.pageYOffset + rectTop.top; const bottom = window.pageYOffset + rectBottom.bottom; if (options.considerFloating) { const floatingRects = options.floatingRects || cd.g.floatingElements.map(getExtendedRect); let intersectsFloatingCount = 0; let bottomIntersectsFloating = false; floatingRects.forEach((rect) => { const floatingTop = window.pageYOffset + rect.outerTop; const floatingBottom = window.pageYOffset + rect.outerBottom; if (bottom > floatingTop && bottom < floatingBottom + cd.g.REGULAR_LINE_HEIGHT) { bottomIntersectsFloating = true; } if (bottom > floatingTop && top < floatingBottom + cd.g.REGULAR_LINE_HEIGHT) { intersectsFloatingCount++; } }); // We calculate the right border separately - in its case, we need to change the `overflow` // property to get the desired value, otherwise floating elements are not taken into account. const initialOverflows = []; if (bottomIntersectsFloating) { this.elements.forEach((el, i) => { initialOverflows[i] = el.style.overflow; el.style.overflow = 'hidden'; }); } rectTop = this.highlightables[0].getBoundingClientRect(); rectBottom = this.elements.length === 1 ? rectTop : this.highlightables[this.highlightables.length - 1].getBoundingClientRect(); // If the comment intersects more than one floating block, we better keep `overflow: hidden` // to avoid bugs like where there are two floating blocks to the right with different leftmost // positions and the layer is more narrow than the comment. if (intersectsFloatingCount === 1) { this.elements.forEach((el, i) => { el.style.overflow = initialOverflows[i]; }); } } const left = window.pageXOffset + Math.min(rectTop.left, rectBottom.left); const right = window.pageXOffset + Math.max(rectTop.right, rectBottom.right); // A solution for comments that have the height bigger than the viewport height. In Chrome, the // scrolling step is 40 pixels. const downplayedBottom = bottom - top > (window.innerHeight - 200) ? top + (window.innerHeight - 200) : bottom; this.positions = { top, bottom, left, right, downplayedBottom }; } /** * Calculate the underlay and overlay positions. * * @param {object} [options={}] * @returns {?object} * @private */ calculateLayersPositions(options = {}) { // getBoundingClientRect() calculation is a little costly, so we take the value that has already // been calculated where possible. this.getPositions(Object.assign({}, options, { considerFloating: true })); if (!this.positions) { return null; } // This is to determine if the element has moved in future checks. this.firstHighlightableWidth = this.highlightables[0].offsetWidth; return { layersTop: this.positions.top - options.layersContainerOffset.top, layersLeft: ( this.positions.left - cd.g.COMMENT_UNDERLAY_SIDE_MARGIN - options.layersContainerOffset.left ), layersWidth: ( this.positions.right - this.positions.left + cd.g.COMMENT_UNDERLAY_SIDE_MARGIN * 2 ), layersHeight: this.positions.bottom - this.positions.top, }; } /** * Hide the comment menu (in fact, the comment overlay). * * @param {Event} [e] */ hideMenu(e) { if (e) { e.preventDefault(); } this.overlay.style.display = 'none'; } /** * Create the comment's underlay and overlay. * * @fires commentLayersCreated * @private */ createLayers() { this.underlay = this.elementPrototypes.underlay.cloneNode(true); commentLayers.underlays.push(this.underlay); this.overlay = this.elementPrototypes.overlay.cloneNode(true); this.overlayInnerWrapper = this.overlay.firstChild; // Hide the overlay on right click. It can block clicking the author page link. this.overlayInnerWrapper.oncontextmenu = this.hideMenu.bind(this); let mouseUpTimeout; const deferHideMenu = (e) => { // Ignore other than left button clicks. if (e.which !== 1) return; mouseUpTimeout = setTimeout(this.hideMenu.bind(this), 1000); }; const dontHideMenu = () => { clearTimeout(mouseUpTimeout); }; // Hide the overlay on long click/tap. this.overlayInnerWrapper.onmousedown = deferHideMenu; this.overlayInnerWrapper.onmouseup = dontHideMenu; this.overlayGradient = this.overlayInnerWrapper.firstChild; this.overlayContent = this.overlayInnerWrapper.lastChild; if (this.getParent()) { /** * "Go to the parent comment" button. * * @type {Element|undefined} */ this.goToParentButton = this.elementPrototypes.goToParentButton.cloneNode(true); this.goToParentButton.firstChild.onclick = () => { this.goToParent(); }; this.overlayContent.appendChild(this.goToParentButton); } if (this.anchor) { /** * "Copy link" button. * * @type {Element|undefined} */ this.linkButton = this.elementPrototypes.linkButton.cloneNode(true); this.linkButton.firstChild.onclick = this.copyLink.bind(this); this.overlayContent.appendChild(this.linkButton); } if (this.author.isRegistered() && this.date && !this.isOwn) { if (!thanks) { thanks = cleanUpThanks(getFromLocalStorage('thanks')); saveToLocalStorage('thanks', thanks); } const isThanked = Object.keys(thanks).some((key) => ( this.anchor === thanks[key].anchor && calculateWordsOverlap(this.getText(), thanks[key].text) > 0.66 )); if (isThanked) { this.thankButton = this.elementPrototypes.thankedButton.cloneNode(true); } else { /** * Thank button. * * @type {Element|undefined} */ this.thankButton = this.elementPrototypes.thankButton.cloneNode(true); this.thankButton.firstChild.onclick = () => { this.thank(); }; } this.overlayContent.appendChild(this.thankButton); } if (this.isActionable) { if (this.isOwn || cd.settings.allowEditOthersComments) { /** * Edit button. * * @type {Element|undefined} */ this.editButton = this.elementPrototypes.editButton.cloneNode(true); this.editButton.firstChild.onclick = () => { if (!this.editButton.classList.contains('oo-ui-widget-disabled')) { this.edit(); } }; this.overlayContent.appendChild(this.editButton); } /** * Reply button. * * @type {Element|undefined} */ this.replyButton = this.elementPrototypes.replyButton.cloneNode(true); this.replyButton.firstChild.onclick = () => { if (this.replyForm) { this.replyForm.cancel(); } else { if (!this.replyButton.classList.contains('oo-ui-widget-disabled')) { this.reply(); } } }; this.overlayContent.appendChild(this.replyButton); } this.updateLayersStyles(); /** * Comment's underlay. * * @type {?(JQuery|undefined)} */ this.$underlay = $(this.underlay); /** * Comment's overlay. * * @type {?(JQuery|undefined)} */ this.$overlay = $(this.overlay); /** * Links container of the comment's overlay. * * @type {?(JQuery|undefined)} */ this.$overlayContent = $(this.overlayContent); /** * Gradient element of the comment's overlay. * * @type {?(JQuery|undefined)} */ this.$overlayGradient = $(this.overlayGradient); /** * Comment layers have been created. * * @event commentLayersReady * @type {module:cd~convenientDiscussions} */ mw.hook('convenientDiscussions.commentLayersCreated').fire(this); } /** * Update the styles of the layers according to the comment's properties. */ updateLayersStyles() { if (!this.underlay) return; if (this.isNew) { this.underlay.classList.add('cd-commentUnderlay-new'); } if (cd.settings.highlightOwnComments && this.isOwn) { this.underlay.classList.add('cd-commentUnderlay-own'); } if (this.isDeleted) { this.underlay.classList.add('cd-commentUnderlay-deleted'); if (this.replyButton) { this.replyButton.classList.add('oo-ui-widget-disabled'); this.replyButton.classList.remove('oo-ui-widget-enabled'); } if (this.editButton) { this.editButton.classList.add('oo-ui-widget-disabled'); this.editButton.classList.remove('oo-ui-widget-enabled'); } } else if (this.underlay.classList.contains('cd-commentUnderlay-deleted')) { this.underlay.classList.remove('cd-commentUnderlay-deleted'); if (this.replyButton) { this.replyButton.classList.remove('oo-ui-widget-disabled'); this.replyButton.classList.add('oo-ui-widget-enabled'); } if (this.editButton) { this.editButton.classList.remove('oo-ui-widget-disabled'); this.editButton.classList.add('oo-ui-widget-enabled'); } } } /** * Add the underlay and overlay if they are missing, update their styles, recalculate their * positions and redraw if the comment has been moved or do nothing if everything is right. * * @param {object} [options={}] * @param {boolean} [options.add=true] Add the layers in case they are created. If set to false, * it is expected that the layers created during this procedure, if any, will be added * afterwards (otherwise there would be layers without a parent element which would lead to * bugs). * @param {boolean} [options.update=true] Update the layers' positions in case the comment is * moved. If set to false, it is expected that the positions will be updated afterwards. * @param {object} [options.floatingRects] `Element#getBoundingClientRect` results. It may be * calculated in advance for many elements in one sequence to save time. * @returns {?boolean} Was the comment moved. */ configureLayers(options = {}) { if (this.editForm) { return null; } if (options.add === undefined) { options.add = true; } if (options.update === undefined) { options.update = true; } options.rectTop = this.highlightables[0].getBoundingClientRect(); options.rectBottom = this.elements.length === 1 ? options.rectTop : this.highlightables[this.highlightables.length - 1].getBoundingClientRect(); options.layersContainerOffset = this.getLayersContainerOffset(); let isMoved = false; if (this.underlay) { // Firefox bug makes it possible for minor (~0.02) differences to manifest. const topDifference = Math.abs( window.pageYOffset + options.rectTop.top - options.layersContainerOffset.top - this.layersTop ); const heightDifference = Math.abs( options.rectBottom.bottom - options.rectTop.top - this.layersHeight ); isMoved = ( topDifference > 0.5 || heightDifference > 0.5 || this.highlightables[0].offsetWidth !== this.firstHighlightableWidth ); } if (!this.underlay || isMoved) { Object.assign(this, this.calculateLayersPositions(options)); } // The comment is invisible. if (this.layersLeft === undefined) { return null; } // Configure the layers only if they were unexistent or the comment position has changed, to // save time. if (this.underlay) { this.updateLayersStyles(); if (isMoved && options.update) { this.updateLayersPositions(); } return isMoved; } else { this.createLayers(); if (options.add) { this.addLayers(); } return false; } } /** * Add the comment's layers to the DOM. */ addLayers() { if (!this.underlay) return; this.updateLayersPositions(); this.getLayersContainer().appendChild(this.underlay); this.getLayersContainer().appendChild(this.overlay); } /** * Transfer the `layers(Top|Left|Width|Height)` values to the style of the layers. */ updateLayersPositions() { this.underlay.style.top = this.overlay.style.top = this.layersTop + 'px'; this.underlay.style.left = this.overlay.style.left = this.layersLeft + 'px'; this.underlay.style.width = this.overlay.style.width = this.layersWidth + 'px'; this.underlay.style.height = this.overlay.style.height = this.layersHeight + 'px'; } /** * Highlight the comment when it is focused. */ highlightFocused() { if (this.isFocused || cd.util.isPageOverlayOn()) return; const isMoved = this.configureLayers(); // Add classes if the comment wasn't moved. If it was moved, the layers are removed and created // again when the next event fires. if (isMoved || !this.underlay) return; this.underlay.classList.add('cd-commentUnderlay-focused'); this.overlay.classList.add('cd-commentOverlay-focused'); this.isFocused = true; } /** * Unhighlight the comment when it has lost focus. */ unhighlightFocused() { if (!this.isFocused) return; this.underlay.classList.remove('cd-commentUnderlay-focused'); this.overlay.classList.remove('cd-commentOverlay-focused'); this.overlay.style.display = ''; this.isFocused = false; } /** * Get the comment's current background color, be it an underlay color or regular background * color. * * @returns {string} */ getCurrentBackgroundColor() { let color = window.getComputedStyle(this.$underlay.get(0)).backgroundColor; if (color === 'rgba(0, 0, 0, 0)' && this.backgroundColor) { color = this.backgroundColor; } return color; } /** * Highlight the comment as a target (it is opened by a link, just posted, is the target of the * up/down comment buttons, or is scrolled to after pressing a navigation panel button). */ highlightTarget() { this.isTarget = true; // We don't take the color from cd.g.COMMENT_TARGET_COLOR as it may be overriden by the user in // their personal CSS. this.flash($(document.documentElement).css('--cd-comment-target-color'), 1500, () => { this.isTarget = false; }); } /** * Change the comment's background color to the provided color for the given number of * milliseconds, then smoothly change it back. * * @param {string} color * @param {number} delay * @param {Function} callback */ flash(color, delay, callback) { this.configureLayers(); if (!this.$underlay) { if (callback) { callback(); } return; } this.$elementsToAnimate = this.$underlay .add(this.$overlayGradient) .add(this.$overlayContent) .stop() .css('background-image', 'none') .css('background-color', ''); let finalColor = this.getCurrentBackgroundColor(); this.$elementsToAnimate.css('background-color', color); clearTimeout(this.unhighlightTimeout); this.unhighlightTimeout = setTimeout(() => { // These comment properties may get assigned after the flash() call. if (this.isFocused) { finalColor = $(document.documentElement).css('--cd-comment-focused-color'); } else if (this.isNew && !this.isOwn) { finalColor = $(document.documentElement).css('--cd-comment-new-color'); } if (finalColor === color) { finalColor = this.backgroundColor || 'rgba(0, 0, 0, 0)'; } const comment = this; this.$elementsToAnimate .stop() .css('background-image', 'none') .css('background-color', color) .animate( { backgroundColor: finalColor }, 400, 'swing', function () { if (this !== comment.$overlayContent.get(0)) return; if (callback) { callback(); } comment.$elementsToAnimate .css('background-image', '') .css('background-color', ''); delete comment.$elementsToAnimate; } ); }, delay); } /** * Flash the comment as updated and add it to the seen rendered edits list kept in the local * storage. */ flashNew() { this.flash($(document.documentElement).css('--cd-comment-new-color'), 500); if (this.isEdited) { const seenRenderedEdits = getFromLocalStorage('seenRenderedEdits'); const articleId = mw.config.get('wgArticleId'); seenRenderedEdits[articleId] = seenRenderedEdits[articleId] || {}; seenRenderedEdits[articleId][this.anchor] = { innerHtml: this.innerHtml, seenUnixTime: Date.now(), }; saveToLocalStorage('seenRenderedEdits', seenRenderedEdits); } } /** * Flash the comment as updated when it appears in sight. */ flashNewOnSight() { if (this.isInViewport()) { this.flashNew(); } else { this.isFlashNewOnSightSet = true; } } /** * Update the comment's properties, add a small text next to the signature saying the comment has * been edited or deleted, and flash the comment as updated if it has been. * * @param {string} type Type of the mark: `'edited'`, `'editedSince'`, or `'deleted'`. * @param {boolean} isNewVersionRendered Has the new version of the comment been rendered. * @param {number} comparedRevisionId ID of the revision to compare with when the user clicks to * see the diff. * @param {string} commentsData Data of the comments as of the current revision and the revision * to compare with. */ markAsEdited(type, isNewVersionRendered, comparedRevisionId, commentsData) { let stringName; switch (type) { case 'edited': default: this.isEdited = true; stringName = 'comment-edited'; break; case 'editedSince': this.isEditedSincePreviousVisit = true; stringName = 'comment-editedsince'; break; case 'deleted': this.isDeleted = true; stringName = 'comment-deleted'; break; } this.$elements .last() .find('.cd-editMark') .remove(); let $refreshLink; if (!isNewVersionRendered) { const keptData = type === 'deleted' ? {} : { commentAnchor: this.anchor }; $refreshLink = $('<a>') .text(cd.s('comment-edited-refresh')) .on('click', () => { reloadPage(keptData); }); } let $diffLink; if (type !== 'deleted' && this.getSourcePage().name === cd.g.CURRENT_PAGE.name) { $diffLink = $('<a>') .text(cd.s('comment-edited-diff')) .on('click', async (e) => { e.preventDefault(); $diffLink.addClass('cd-link-pending'); try { await this.showDiff(comparedRevisionId, commentsData); } catch (e) { let text = cd.s('comment-edited-diff-error'); if (e instanceof CdError) { const { type, message } = e.data; if (message) { text = message; } else if (type === 'network') { text += ' ' + cd.sParse('error-network'); } } mw.notify(text, { type: 'error' }); } $diffLink.removeClass('cd-link-pending'); }); } const $span = $('<span>') .addClass('cd-editMark') .append(cd.sParse(stringName)); if ($refreshLink) { $span.append(' ', $refreshLink); } else { $span.addClass('cd-editMark-newVersionRendered'); } if ($diffLink) { $span.append($refreshLink ? cd.mws('dot-separator') : ' ', $diffLink); } // Add the mark to the last block element, going as many nesting levels down as needed to avoid // it appearing after a block element. let $last; let $tested = this.$elements.last(); do { $last = $tested; $tested = $last.children().last(); } while ($tested.length && !isInline($tested.get(0))); $last.append($span); if (isNewVersionRendered) { this.flashNewOnSight(); } // Layers are supposed to be updated (deleted comments background, repositioning) separately, // see updateChecker~checkForNewEdits, for example. } /** * Update the comment's properties, remove the edit mark added in {@link * module:Comment#markAsEdited} and flash the comment as updated if it has been (reset to the * original version, or unedited, in this case). * * @param {string} type Type of the mark: `'edited'` or `'deleted'`. */ unmarkAsEdited(type) { switch (type) { case 'edited': default: this.isEdited = false; break; case 'deleted': this.isDeleted = false; // commentLayers.redrawIfNecessary(), that is called on DOM updates, could circumvent this // comment if it has no property signalling that it should be highlighted, so we update its // styles manually. this.updateLayersStyles(); break; } this.$elements .last() .find('.cd-editMark') .remove(); if (type === 'edited') { if (this.isFlashNewOnSightSet) { this.isFlashNewOnSightSet = false; } else { const seenRenderedEdits = getFromLocalStorage('seenRenderedEdits'); const articleId = mw.config.get('wgArticleId'); seenRenderedEdits[articleId] = seenRenderedEdits[articleId] || {}; delete seenRenderedEdits[articleId][this.anchor]; saveToLocalStorage('seenRenderedEdits', seenRenderedEdits); this.flashNewOnSight(); } } } /** * Update the comment's content. * * @param {object} currentComment Data about the comment in the current revision as delivered by * the worker. * @param {object} newComment Data about the comment in the new revision as delivered by the * worker. * @returns {boolean} Was the update successful. */ update(currentComment, newComment) { const elementTagNames = Array.from(this.$elements).map((el) => el.tagName); // References themselves may be out of the comment's HTML and might be edited. const areThereReferences = newComment.hiddenElementData .some((data) => data.type === 'reference'); // If a style element is replaced with a link element, we can't replace HTML. const areStyleTagsKept = ( !newComment.hiddenElementData.length || newComment.hiddenElementData.every((data, i) => ( data.type !== 'templateStyles' || data.tagName === 'STYLE' || currentComment.hiddenElementData[i].tagName !== 'STYLE' )) ); if ( !areThereReferences && areStyleTagsKept && areObjectsEqual(elementTagNames, newComment.elementTagNames) ) { const match = this.$elements.find('.autonumber').text().match(/\d+/); let currentAutonumber = match ? match[0] : 1; newComment.elementHtmls.forEach((html, i) => { html = html.replace( /\x01(\d+)_\w+\x02/g, (s, num) => newComment.hiddenElementData[num - 1].html ); if (/^H[1-6]$/.test(elementTagNames[i])) { const $headline = this.$elements.eq(i).find('.mw-headline'); if ($headline.length) { const $headlineNumber = $headline.find('.mw-headline-number'); const $html = $(html); $headline .html($html.html()) .prepend($headlineNumber); const section = this.getSection(); if (section) { const originalHeadline = section.headline; section.parseHeadline(); if (section.isWatched && section.headline !== originalHeadline) { section.watch(true, originalHeadline); } section.getTocItem()?.replaceText($html); } } } else { this.replaceElement(this.$elements.eq(i), html); } }); this.$elements.find('.autonumber').each((i, el) => { $(el).text(`[${currentAutonumber}]`); currentAutonumber++; }); this.$elements .attr('data-comment-id', this.id) .first() .attr('id', this.anchor); mw.hook('wikipage.content').add(this.$elements); delete this.cachedText; return true; } else { return false; } } /** * Scroll to the comment if it is not in the viewport. * * @param {string} alignment One of the values that {@link $.fn.cdScrollTo} accepts: `'top'`, * `'center'`, or `'bottom'`. */ scrollIntoView(alignment) { const $target = this.editForm ? this.editForm.$element : this.$elements; $target.cdScrollIntoView(alignment); } /** * Scroll to the comment and highlight it as a target. * * @param {boolean} [smooth=true] Use a smooth animation. * @param {boolean} [pushState=false] Whether to push a state to the history with the comment * anchor as a fragment. */ scrollToAndHighlightTarget(smooth = true, pushState = false) { if (pushState) { history.pushState(history.state, '', '#' + this.anchor); } const $elements = this.editForm ? this.editForm.$element : this.$elements; $elements.cdScrollIntoView(this.isOpeningSection || this.editForm ? 'top' : 'center', smooth); this.highlightTarget(); } /** * Replace a button in the comment overlay with another. * * @param {Element} button * @param {Element} replacement * @param {string} buttonName * @private */ replaceButton(button, replacement, buttonName) { this.overlayContent.insertBefore(replacement, button); button.remove(); this[buttonName + 'Button'] = replacement; } /** * Scroll to the parent comment of the comment. */ goToParent() { const parent = this.getParent(); if (!parent) { console.error('This comment has no parent.'); return; } parent.scrollToAndHighlightTarget(); const goToChildButton = new OO.ui.ButtonWidget({ label: cd.s('cm-gotochild'), icon: 'downTriangle', title: cd.s('cm-gotochild-tooltip'), framed: false, invisibleLabel: true, classes: ['cd-button', 'cd-commentButton', 'cd-commentButton-icon'], }); goToChildButton.on('click', () => { parent.goToChild(); }); parent.configureLayers(); if (parent.goToChildButton) { parent.goToChildButton.$element.remove(); } parent.$overlayContent.prepend(goToChildButton.$element); parent.goToChildButton = goToChildButton; /** * Child comment that has sent the user to this comment using the "Go to parent" function. * * @name childToScrollBackTo * @type {Comment|undefined} * @instance */ parent.childToScrollBackTo = this; } /** * Scroll to the child comment of the comment. */ goToChild() { if (!this.childToScrollBackTo) { console.error('This comment has no child from which the user had navigated earlier.'); return; } this.childToScrollBackTo.scrollToAndHighlightTarget(); } /** * Copy a link to the comment or open a copy link dialog. */ async copyLink() { if (this.isLinkBeingCopied) return; const linkButton = this.linkButton; const pendingLinkButton = this.elementPrototypes.pendingLinkButton.cloneNode(true); this.replaceButton(this.linkButton, pendingLinkButton, 'link'); await copyLink(this); this.replaceButton(this.linkButton, linkButton, 'link'); } /** * Find the edit that added the comment. * * @returns {object} * @throws {CdError} */ async findAddingEdit() { if (this.addingEdit) { return this.addingEdit; } // Search for the edit in the range of 2 minutes before to 2 minutes later. const rvstart = new Date(this.date.getTime() - cd.g.MILLISECONDS_IN_A_MINUTE * 2).toISOString(); const rvend = new Date(this.date.getTime() + cd.g.MILLISECONDS_IN_A_MINUTE * 2).toISOString(); const revisions = await this.getSourcePage().getArchivedPage().getRevisions({ rvprop: ['ids', 'comment', 'parsedcomment', 'timestamp'], rvdir: 'newer', rvstart, rvend, rvuser: this.author.name, rvlimit: 500, }).catch(handleApiReject); const compareRequests = revisions.map((revision) => cd.g.api.post({ action: 'compare', fromtitle: this.getSourcePage().getArchivedPage().name, fromrev: revision.revid, torelative: 'prev', prop: ['diff'], formatversion: 2, }).catch(handleApiReject)); const compareResps = await Promise.all(compareRequests); const regexp = /<td colspan="2" class="diff-empty">&#160;<\/td>\s*<td class="diff-marker">\+<\/td>\s*<td class="diff-addedline"><div>(?!=)(.+?)<\/div><\/td>\s*<\/tr>/g; const commentFullText = this.getText(false) + ' ' + this.$signature.get(0).innerText; const matches = []; for (let i = 0; i < compareResps.length; i++) { const diffBody = compareResps[i]?.compare?.body; if (!diffBody) continue; const revision = revisions[i]; // Compare diff _parts_ with added text in case multiple comments were added with the edit. let match; let diffOriginalText = ''; let diffText = ''; let bestDiffPartOverlap = 0; while ((match = regexp.exec(diffBody))) { const diffPartText = removeWikiMarkup(decodeHtmlEntities(match[1])); const diffPartOverlap = calculateWordsOverlap(diffPartText, commentFullText); if (diffPartOverlap > bestDiffPartOverlap) { bestDiffPartOverlap = diffPartOverlap; } diffText += diffPartText + '\n'; diffOriginalText += match[1] + '\n'; } if (!diffOriginalText.trim()) continue; revision.diffBody = diffBody; const timestamp = new Date(revision.timestamp).getTime(); // Add 30 seconds to get better date proximity results since we don't see the seconds // number. const thisCommentTimestamp = this.date.getTime() + (30 * 1000); const dateProximity = Math.abs(thisCommentTimestamp - timestamp); let overlap = Math.max(calculateWordsOverlap(diffText, commentFullText), bestDiffPartOverlap); if (overlap < 1 && diffOriginalText.includes('{{')) { try { const html = (await parseCode(diffOriginalText, { title: cd.g.CURRENT_PAGE.name })).html; diffOriginalText = $('<div>').append(html).cdGetText(); } catch (e) { throw new CdError({ type: 'parse', }); } overlap = calculateWordsOverlap(diffOriginalText, commentFullText); } matches.push({ revision, overlap, dateProximity }); } let bestMatch; matches.forEach((match) => { if ( !bestMatch || match.overlap > bestMatch.overlap || ( bestMatch && match.overlap === bestMatch.overlap && match.dateProximity > bestMatch.dateProximity ) ) { bestMatch = match; } }); if (!bestMatch) { throw new CdError({ type: 'parse', }); } // Cache a successful result. this.addingEdit = bestMatch.revision; return this.addingEdit; } /** * Get a diff link for the comment. * * @param {boolean} short Whether to return a short diff link. * @returns {string} */ async getDiffLink(short) { const edit = await this.findAddingEdit(); if (short) { return `https:${mw.config.get('wgServer')}/?diff=${edit.revid}`; } else { const urlEnding = decodeURI(cd.g.CURRENT_PAGE.getArchivedPage().getUrl({ diff: edit.revid })); return `https:${mw.config.get('wgServer')}${urlEnding}`; } } /** * Generate a JQuery object containing an edit summary, diff body, and link to the next diff. * * @returns {JQuery} * @private */ async generateDiffView() { const edit = await this.findAddingEdit(); const diffLink = await this.getDiffLink(); const $nextDiffLink = $('<a>') .addClass('cd-diffView-nextDiffLink') .attr('href', diffLink.replace(/&diff=(\d+)/, '&oldid=$1&diff=next')) .attr('target', '_blank') .text(cd.mws('nextdiff')); const $summaryText = cd.util.wrap(edit.parsedcomment, { targetBlank: true }) .addClass('comment'); const $above = $('<div>').append([ $nextDiffLink, cd.sParse('cld-summary'), cd.mws('colon-separator'), $summaryText, ]); const $diffBody = cd.util.wrapDiffBody(edit.diffBody); return $('<div>') .addClass('cd-diffView-diff') .append($above, $diffBody); } /** * Process thank error. * * @param {CdError|Error} e * @param {Element} thankButton * @private */ thankFail(e, thankButton) { const { type, code } = e.data; let text; switch (type) { case 'parse': { const url = this.getSourcePage().getArchivedPage().getUrl({ action: 'history' }); text = cd.sParse('error-diffnotfound') + ' ' + cd.sParse('error-diffnotfound-history', url); break; } case 'api': default: { if (code === 'noData') { const url = this.getSourcePage().getArchivedPage().getUrl({ action: 'history' }); text = ( cd.sParse('error-diffnotfound') + ' ' + cd.sParse('error-diffnotfound-history', url) ); } else { text = cd.sParse('thank-error'); console.warn(e); } break; } case 'network': { text = cd.sParse('error-diffnotfound') + ' ' + cd.sParse('error-network'); break; } } mw.notify(cd.util.wrap(text, { targetBlank: true }), { type: 'error' }); this.replaceButton(this.thankButton, thankButton, 'thank'); } /** * Find the edit that added the comment, ask for a confirmation, and send a "thank you" * notification. */ async thank() { if (dealWithLoadingBug('mediawiki.diff.styles')) return; const thankButton = this.thankButton; const pendingThankButton = this.elementPrototypes.pendingThankButton.cloneNode(true); this.replaceButton(this.thankButton, pendingThankButton, 'thank'); let genderRequest; if (cd.g.GENDER_AFFECTS_USER_STRING && this.author.isRegistered()) { genderRequest = getUserGenders([this.author]); } let edit; try { ([edit] = await Promise.all([ this.findAddingEdit(), genderRequest, mw.loader.using('mediawiki.diff.styles'), ].filter(defined))); } catch (e) { this.thankFail(e, thankButton); return; } const url = this.getSourcePage().getArchivedPage().getUrl({ diff: edit.revid }); const question = cd.sParse('thank-confirm', this.author.name, this.author, url); const $question = cd.util.wrap(question, { tagName: 'div', targetBlank: true, }); const $diff = await this.generateDiffView(); const $content = $('<div>').append($question, $diff); if (await OO.ui.confirm($content, { size: 'larger' })) { try { await cd.g.api.postWithEditToken(cd.g.api.assertCurrentUser({ action: 'thank', rev: edit.revid, source: cd.config.scriptCodeName, })).catch(handleApiReject); } catch (e) { this.thankFail(e, thankButton); return; } mw.notify(cd.s('thank-success')); const thankedButton = this.elementPrototypes.thankedButton.cloneNode(true); this.replaceButton(this.thankButton, thankedButton, 'thank'); thanks[edit.revid] = { anchor: this.anchor, text: this.getText(), thankUnixTime: Date.now(), }; saveToLocalStorage('thanks', thanks); } else { this.replaceButton(this.thankButton, thankButton, 'thank'); } } /** * Locate the comment in the page source code and, if no `pageCode` is passed, set the results to * the `inCode` property. Otherwise, return the result. * * @param {string} [pageCode] Page code, if different from the `code` property of {@link * Comment#getSourcePage()}. * @param {string} [commentData] Comment data for comparison (can be set together with pageCode). * @returns {string|undefined} * @throws {CdError} */ locateInCode(pageCode, commentData) { if (!pageCode) { this.inCode = null; } // Collect matches const matches = this.searchInCode(pageCode || this.getSourcePage().code, commentData); let bestMatch; matches.forEach((match) => { if (!bestMatch || match.score > bestMatch.score) { bestMatch = match; } }); if (!bestMatch) { throw new CdError({ type: 'parse', code: 'locateComment', }); } const inCode = this.adjustCommentCodeData(bestMatch); if (pageCode) { return inCode; } else { this.inCode = inCode; } } /** * Create a {@link module:Comment#replyForm reply form} for the comment. * * @param {object|CommentForm} dataToRestore */ reply(dataToRestore) { if (!this.replyForm) { /** * Reply form related to the comment. * * @type {CommentForm|undefined} */ this.replyForm = dataToRestore instanceof CommentForm ? dataToRestore : new CommentForm({ mode: 'reply', target: this, dataToRestore, }); } } /** * Create an {@link module:Comment#editForm edit form} for the comment. * * @param {object|CommentForm} dataToRestore */ edit(dataToRestore) { // "!this.editForm" check is in case the editing is called from a script of some kind (there is // no button to call it from CD when the form is displayed). if (!this.editForm) { /** * Edit form related to the comment. * * @type {CommentForm|undefined} */ this.editForm = dataToRestore instanceof CommentForm ? dataToRestore : new CommentForm({ mode: 'edit', target: this, dataToRestore, }); } // We use a class here because there can be elements in the comment that are hidden from the // beginning and should stay so when reshowing the comment. this.$elements.addClass('cd-hidden'); this.removeLayers(); } /** * Convert the comment code as present in the `inCode` property to text to set as a value of the * form's comment input. * * @returns {string} */ codeToText() { if (!this.inCode) { console.error('The Comment#inCode property should contain an object with the comment code data.'); return; } let { code, indentationChars } = this.inCode; let hidden; ({ code, hidden } = hideSensitiveCode(code)); let text = code; if (this.level === 0) { // Collapse random line breaks that do not affect text rendering but will transform into <br> // on posting. \x01 and \x02 mean the beginning and ending of sensitive code except for // tables. \x03 and \x04 mean the beginning and ending of a table. Note: This should be kept // coordinated with the reverse transformation code in CommentForm#commentTextToCode. Some // more comments are there. const entireLineRegexp = new RegExp( `^(?:\\x01.+?\\x02|\\[\\[${cd.g.FILE_PREFIX_PATTERN}.+\\]\\]) *$`, 'i' ); const thisLineEndingRegexp = new RegExp( `(?:<${cd.g.PNIE_PATTERN}(?: [\\w ]+?=[^<>]+?| ?\\/?)>|<\\/${cd.g.PNIE_PATTERN}>|\\x04) *$`, 'i' ); const nextLineBeginningRegexp = new RegExp( `^(?:<\\/${cd.g.PNIE_PATTERN}>|<${cd.g.PNIE_PATTERN}|\\|)`, 'i' ); const headingRegexp = /^(=+).*\1[ \t]*$/; text = text.replace( /^((?![:*# ]).+)\n(?![\n:*# \x03])(?=(.*))/gm, (s, thisLine, nextLine) => { const newlineOrSpace = ( entireLineRegexp.test(thisLine) || entireLineRegexp.test(nextLine) || headingRegexp.test(thisLine) || headingRegexp.test(nextLine) || thisLineEndingRegexp.test(thisLine) || nextLineBeginningRegexp.test(nextLine) ) ? '\n' : ' '; return thisLine + newlineOrSpace; } ); } text = text // <br> → \n, except in list elements and <pre>'s created by a space starting the line. .replace(/^(?![:*# ]).*<br[ \n]*\/?>.*$/gmi, (s) => ( s.replace(/<br[ \n]*\/?>\n? */gi, () => '\n') )) // Remove indentation characters .replace(/\n([:*#]*[:*])([ \t]*)/g, (s, chars, spacing) => { const newChars = chars.slice(indentationChars.length); return ( '\n' + ( chars.length >= indentationChars.length ? newChars + (chars.length > indentationChars.length ? spacing : '') : chars + spacing ) ); }); text = unhideText(text, hidden); if (cd.config.paragraphTemplates.length) { const paragraphTemplatesPattern = cd.config.paragraphTemplates .map(caseInsensitiveFirstCharPattern) .join('|'); const pattern = `\\{\\{(?:${paragraphTemplatesPattern})\\}\\}`; const regexp = new RegExp(pattern, 'g'); const lineRegexp = new RegExp(`^(?![:*#]).*${pattern}`, 'gm'); text = text.replace(lineRegexp, (s) => s.replace(regexp, '\n\n')); } return text.trim(); } /** * Load the comment code. * * @throws {CdError|Error} */ async getCode() { try { await this.getSourcePage().getCode(); this.locateInCode(); } catch (e) { if (e instanceof CdError) { throw new CdError(Object.assign({}, { message: cd.s('cf-error-getpagecode') }, e.data)); } else { throw e; } } } /** * Mark the comment as seen, and also {@link module:Comment#flash flash} comments that are * prescribed to flash. * * @param {string} [registerAllInDirection] Mark all comments in the forward (`'forward'`) or * backward (`'backward'`) direction from this comment as seen. * @param {boolean} [highlight=false] Highlight the comment. */ registerSeen(registerAllInDirection, highlight = false) { if (this.isSeen === false) { this.isSeen = true; if (highlight) { this.highlightTarget(); } } if (this.isFlashNewOnSightSet) { this.isFlashNewOnSightSet = false; this.flashNew(); } const makesSenseToRegister = cd.comments .some((comment) => comment.isSeen || comment.isFlashNewOnSightSet); if (registerAllInDirection && makesSenseToRegister) { const nextComment = cd.comments[this.id + (registerAllInDirection === 'forward' ? 1 : -1)]; if (nextComment?.isInViewport()) { nextComment.registerSeen(registerAllInDirection, highlight); } } } /** * Determine if the comment is in the viewport. Return `null` if we couldn't get the comment's * positions. * * @param {boolean} partially Return true even if only a part of the comment is in the viewport. * @returns {?boolean} */ isInViewport(partially = false) { const viewportTop = window.pageYOffset; const viewportBottom = viewportTop + window.innerHeight; this.getPositions(); if (!this.positions) { return null; } return partially ? this.positions.downplayedBottom > viewportTop && this.positions.top < viewportBottom : this.positions.top >= viewportTop && this.positions.downplayedBottom <= viewportBottom; } /** * Remove the comment's layers. */ removeLayers() { if (!this.underlay) return; this.$elementsToAnimate?.stop(); commentLayers.underlays.splice(commentLayers.underlays.indexOf(this.underlay), 1); this.underlay.remove(); this.underlay = null; this.$underlay = null; this.overlay.remove(); this.overlay = null; this.$overlay = null; } /** * Comment elements as a jQuery object. * * Uses a getter because elements of a comment can be altered after creating an instance, for * example with `mergeAdjacentCommentLevels()` in {@link module:modifyDom}. Using a getter also * allows to save a little time on running `$()`, although that alone is perhaps not enough to * create it. * * @type {JQuery} */ get $elements() { if (this.cached$elements === undefined) { this.cached$elements = $(this.elements); } return this.cached$elements; } set $elements(value) { this.cached$elements = value; this.elements = value.get(); } /** * Replace an element that is one of the comment's elements with another element or HTML string. * * @param {Element|JQuery} element * @param {Element|string} newElementOrHtml */ replaceElement(element, newElementOrHtml) { const nativeElement = element instanceof $ ? element.get(0) : element; let newElement; if (typeof newElementOrHtml === 'string') { const index = Array.from(nativeElement.parentNode.children).indexOf(nativeElement); const parentNode = nativeElement.parentNode; nativeElement.outerHTML = newElementOrHtml; newElement = parentNode.children[index]; } else { newElement = newElementOrHtml; nativeElement.parentNode.replaceChild(newElement, element); } if (element instanceof $) { this.$elements = this.$elements .not(nativeElement) .add(newElement); } else { this.elements.splice(this.elements.indexOf(element), 1, newElementOrHtml); } if (this.highlightables.includes(nativeElement)) { this.highlightables.splice(this.highlightables.indexOf(nativeElement), 1, newElement); this.bindEvents(newElement); } } /** * Get the parent comment of the comment. * * @returns {?Comment} */ getParent() { if (this.cachedParent === undefined && this.id === 0) { this.cachedParent = null; } // Look for {{outdent}} templates if (this.cachedParent === undefined && cd.g.pageHasOutdents) { const treeWalker = new ElementsTreeWalker(this.elements[0]); while ( treeWalker.previousNode() && !treeWalker.currentNode.classList.contains('cd-commentPart') ) { if (treeWalker.currentNode.classList.contains('outdent-template')) { this.cachedParent = cd.comments[this.id - 1]; break; } } } if (this.cachedParent === undefined && this.level === 0) { this.cachedParent = null; } if (this.cachedParent === undefined) { this.cachedParent = ( cd.comments .slice(0, this.id) .reverse() .find((comment) => ( comment.getSection() === this.getSection() && comment.level < this.level )) || null ); } return this.cachedParent; } /** * Get the comment's text. * * @param {boolean} [cleanUp=true] Whether to clean up the signature. * @returns {string} */ getText(cleanUp = true) { if (this.cachedText === undefined) { const $clone = this.$elements .not('h1, h2, h3, h4, h5, h6') .clone() .removeClass('cd-hidden'); const $dummy = $('<div>').append($clone); const selectorParts = ['.cd-signature', '.cd-editMark']; if (cd.config.unsignedClass) { selectorParts.push(`.${cd.config.unsignedClass}`); } const selector = selectorParts.join(', '); $dummy.find(selector).remove(); let text = $dummy.cdGetText(); if (cleanUp) { if (cd.config.signatureEndingRegexp) { text = text.replace(new RegExp(cd.config.signatureEndingRegexp.source + '$'), ''); } // FIXME: We use the same regexp to clean both wikitext and render. With the current default // config value the side effects seem to be negligable, but who knows... if (cd.config.signaturePrefixRegexp) { text = text.replace(cd.config.signaturePrefixRegexp, ''); } } this.cachedText = text; } return this.cachedText; } /** * When searching for the comment in the code, adjust the index of the comment start point and * some related properties. * * @param {object} originalData * @returns {object} * @private */ adjustCommentBeginning({ code, startIndex }) { // Identifying indentation characters let indentationChars = ''; let lineStartIndex = startIndex; const headingMatch = code.match(/(^[^]*(?:^|\n))((=+)(.*?)\3[ \t\x01\x02]*\n)/); let headingCode; let headingStartIndex; let headingLevel; let headlineCode; if (headingMatch) { headingCode = headingMatch[2]; headingStartIndex = startIndex + headingMatch[1].length; headingLevel = headingMatch[3].length; headlineCode = headingMatch[4].trim(); startIndex += headingMatch[0].length; code = code.slice(headingMatch[0].length); // Try to edit the first comment at // https://ru.wikipedia.org/wiki/Википедия:Голосования/Отметки_статусных_статей_в_навигационных_шаблонах#Да // to see a bug happening if we don't check for `this.isOpeningSection`. lineStartIndex = this.isOpeningSection ? headingStartIndex : startIndex; } // Exclude the text of the previous comment that is ended with 3/5 tildes instead of 4. [cd.config.signatureEndingRegexp, cd.g.TIMEZONE_REGEXP] .filter(defined) .filter((regexp) => regexp !== null) .forEach((originalRegexp) => { const regexp = new RegExp(originalRegexp.source + '$', 'm'); const linesRegexp = /^(.+)\n/gm; let line; let indent; while ((line = linesRegexp.exec(code))) { if (regexp.test(removeWikiMarkup(line[1]))) { const testIndent = line.index + line[0].length; if (testIndent === code.length) { break; } else { indent = testIndent; } } } if (indent) { code = code.slice(indent); startIndex += indent; lineStartIndex += indent; } }); // This should be before the "this.level > 0" block to account for cases like // https://ru.wikipedia.org/w/index.php?oldid=110033693&section=6&action=edit (a regexp doesn't // catch the comment because of a new line inside a "syntaxhighlight" element). cd.g.BAD_COMMENT_BEGINNINGS.forEach((pattern) => { if (pattern.source[0] !== '^') { console.debug('Regexps in cd.config.customBadCommentBeginnings should have "^" as the first character.'); } const match = code.match(pattern); if (match) { code = code.slice(match[0].length); lineStartIndex = startIndex + match[0].lastIndexOf('\n') + 1; startIndex += match[0].length; } }); // Exclude the indentation characters and any foreign code before them from the comment code. // Comments at the zero level sometimes start with ":" that is used to indent some side note. It // shouldn't be considered an indentation character. if (this.level > 0) { const replaceIndentationChars = (s, before, chars) => { indentationChars = chars; lineStartIndex = startIndex + before.length; startIndex += s.length; return ''; }; code = code.replace( new RegExp(`^()${cd.config.indentationCharsPattern}`), replaceIndentationChars ); // See the comment "Without the following code, the section introduction..." in Parser.js. // Dangerous case: https://ru.wikipedia.org/w/index.php?oldid=105936825&action=edit&section=1. // This was actually a mistake to put a signature at the first level, but if it was legit, // only the last sentence should have been interpreted as the comment. if (indentationChars === '') { code = code.replace( new RegExp(`(^[^]*?(?:^|\n))${cd.config.indentationCharsPattern}(?![^]*\\n[^:*#])`), replaceIndentationChars ); } } return { code, startIndex, lineStartIndex, headingMatch, headingCode, headingStartIndex, headingLevel, headlineCode, indentationChars, }; } /** * While locating the comment in the source code, adjust the data related to the comment code. * This is mostly related to the signature code and indentation characters. * * @param {object} originalData * @returns {object} * @private */ adjustCommentCodeData(originalData) { const data = Object.assign({}, originalData); const movePartToSignature = (s) => { data.signatureDirtyCode = s + data.signatureDirtyCode; data.endIndex -= s.length; return ''; } if (this.isOwn && cd.g.CURRENT_USER_SIGNATURE_PREFIX_REGEXP) { data.code = data.code.replace(cd.g.CURRENT_USER_SIGNATURE_PREFIX_REGEXP, movePartToSignature); } const movePartsToSignature = (code, regexps) => { regexps.forEach((regexp) => { code = code.replace(regexp, movePartToSignature); }); return code; }; const tagRegexp = new RegExp(`(<${cd.g.PIE_PATTERN}(?: [\\w ]+?=[^<>]+?)?> *)+$`, 'i'); // Why signaturePrefixRegexp three times? Well, the test case here is the MusikAnimal's // signature here: https://en.wikipedia.org/w/index.php?diff=next&oldid=946899148. data.code = movePartsToSignature(data.code, [ cd.config.signaturePrefixRegexp, tagRegexp, cd.config.signaturePrefixRegexp, tagRegexp, new RegExp(`<small class="${cd.config.unsignedClass}">.*$`), /<!-- *Template:Unsigned.*$/, cd.config.signaturePrefixRegexp, ]); // Exclude <small></small> and template wrappers from the strings const smallWrappers = [{ start: /^<small>/, end: /<\/small>[ \u00A0\t]*$/, }]; if (cd.config.smallDivTemplates?.[0]) { smallWrappers.push({ start: new RegExp( `^(?:\\{\\{(${cd.config.smallDivTemplates.join('|')})\\|(?: *1 *= *|(?![^{]*=)))`, 'i' ), end: /\}\}[ \u00A0\t]*$/, }); } data.signatureCode = data.signatureDirtyCode; data.inSmallFont = false; smallWrappers.some((wrapper) => { if (wrapper.start.test(data.code) && wrapper.end.test(data.signatureCode)) { data.inSmallFont = true; data.code = data.code.replace(wrapper.start, ''); data.signatureCode = data.signatureCode.replace(wrapper.end, ''); return true; } }); // If the comment contains different indentation character sets for different lines, then use // different sets depending on the mode (edit/reply). data.replyIndentationChars = data.indentationChars; if (!this.isOpeningSection) { // If the last line ends with "#", it's probably a numbered list _inside_ the comment, not two // comments in one, so we exclude such cases. The signature code is used because it may start // with a newline. const match = (data.code + data.signatureDirtyCode).match(/\n([:*#]*[:*]).*$/); if (match) { data.replyIndentationChars = match[1]; // Cases where indentation characters on the first line don't denote a comment level but // serve some other purposes. Some strange example: // https://ru.wikipedia.org/w/index.php?diff=105978713. if (data.replyIndentationChars.length < data.indentationChars.length) { const prefix = data.indentationChars.slice(data.replyIndentationChars.length) + ' '; data.code = prefix + data.code; data.indentationChars = data.indentationChars.slice(0, data.replyIndentationChars.length); data.startIndex -= prefix.length; } } } data.replyIndentationChars += cd.config.defaultIndentationChar; return data; } /** * Search for the comment in the source code and return possible matches. * * @param {string} pageCode * @param {string} commentData * @returns {object} * @private */ searchInCode(pageCode, commentData) { const signatures = extractSignatures(pageCode); // .startsWith() to account for cases where you can ignore the timezone string in the "unsigned" // templates (it may be present and may be not), but it appears on the page. const signatureMatches = signatures.filter((sig) => ( (sig.author === this.author || sig.author === '<undated>') && ( this.timestamp === sig.timestamp || (this.timestamp && this.timestamp.startsWith(sig.timestamp)) ) )); // Signature object to a comment match object let matches = signatureMatches.map((match) => ({ id: match.id, author: match.author, timestamp: match.timestamp, date: match.date, anchor: match.anchor, signatureDirtyCode: match.dirtyCode, startIndex: match.commentStartIndex, endIndex: match.startIndex, signatureEndIndex: match.startIndex + match.dirtyCode.length, })); // For the reserve method; the main method uses one date. const previousComments = commentData ? commentData.previousComments : cd.comments .slice(Math.max(0, this.id - 2), this.id) .reverse(); const id = commentData ? commentData.id : this.id; let followsHeading; let sectionHeadline; if (commentData) { followsHeading = commentData.followsHeading; sectionHeadline = commentData.section?.headline; } else { followsHeading = this.followsHeading; sectionHeadline = this.getSection()?.headline; } // Collect data for every match matches.forEach((match) => { match.code = pageCode.slice(match.startIndex, match.endIndex); match.hasIdMatched = id === match.id; if (previousComments.length) { match.hasPreviousCommentsDataMatched = false; match.hasPreviousCommentDataMatched = false; for (let i = 0; i < previousComments.length; i++) { const signature = signatures[match.id - 1 - i]; if (!signature) break; // At least one coincided comment is enough if the second is unavailable. match.hasPreviousCommentsDataMatched = ( signature.timestamp === previousComments[i].timestamp && // Previous comment object may come from the worker, where it has only the authorName // property. signature.author.name === previousComments[i].authorName ); // Many consecutive comments with the same author and timestamp. if (match.isPreviousCommentsDataEqual !== false) { match.isPreviousCommentsDataEqual = ( match.timestamp === signature.timestamp && match.author === signature.author ); } if (i === 0) { match.hasPreviousCommentDataMatched = match.hasPreviousCommentsDataMatched; } if (!match.hasPreviousCommentsDataMatched) break; } } else { // If there is no previous comment both on the page and in the code, it's a match. match.hasPreviousCommentsDataMatched = match.id === 0; match.hasPreviousCommentDataMatched = match.id === 0; } match.isPreviousCommentsDataEqual = Boolean(match.isPreviousCommentsDataEqual); Object.assign(match, this.adjustCommentBeginning(match)); match.hasHeadlineMatched = followsHeading ? ( match.headingMatch && sectionHeadline && normalizeCode(removeWikiMarkup(match.headlineCode)) === normalizeCode(sectionHeadline) ) : !match.headingMatch; const commentText = commentData ? commentData.text : this.getText(); match.overlap = calculateWordsOverlap(commentText, removeWikiMarkup(match.code)); match.score = ( ( match.overlap > 0.66 || // The reserve method, if for some reason the text is not overlapping: by this and // previous two dates and authors. If all dates and authors are the same, that shouldn't // count (see [[Википедия:К удалению/22 сентября 2020#202009221158_Facenapalm_17]]). ( id !== 0 && match.hasPreviousCommentsDataMatched && !match.isPreviousCommentsDataEqual ) || // There are always problems with first comments as there are no previous comments to // compare the signatures of and it's harder to tell the match, so we use a bit ugly // solution here, although it should be quite reliable: the comment's firstness, matching // author, date, and headline. A false negative will take place when the comment is no // longer first. Another option is to look for next comments, not for previous. (id === 0 && match.hasPreviousCommentsDataMatched && match.hasHeadlineMatched) ) * 2 + match.overlap + match.hasHeadlineMatched * 1 + match.hasPreviousCommentsDataMatched * 0.5 + match.hasIdMatched * 0.0001 ); }); matches = matches.filter((match) => match.score > 2.5); return matches; } /** * Modify a page code string related to the comment in accordance with an action. * * @param {object} options * @param {string} options.pageCode * @param {string} options.action * @param {string} options.doDelete * @param {string} [options.thisInCode] Should be set if `commentCode` is set. * @param {string} [options.commentForm] `commentCode` or `commentForm` should be set. * @param {string} [options.commentCode] `commentCode` or `commentForm` should be set. * @returns {string} * @throws {CdError} */ modifyCode({ pageCode, action, doDelete, commentForm, thisInCode, commentCode }) { thisInCode = thisInCode || this.inCode; let currentIndex; if (action === 'reply') { currentIndex = thisInCode.endIndex; let adjustedCode = hideDistractingCode(pageCode); if (cd.g.CLOSED_DISCUSSION_PAIR_REGEXP) { adjustedCode = adjustedCode .replace(cd.g.CLOSED_DISCUSSION_PAIR_REGEXP, (s, indentationChars) => ( '\x01'.repeat(indentationChars.length) + ' '.repeat(s.length - indentationChars.length - 1) + '\x02' )); } if (cd.g.CLOSED_DISCUSSION_SINGLE_REGEXP) { let match; while ((match = cd.g.CLOSED_DISCUSSION_SINGLE_REGEXP.exec(adjustedCode))) { adjustedCode = ( adjustedCode.slice(0, match.index) + hideTemplatesRecursively(adjustedCode.slice(match.index), null, match[1].length).code ); } } const adjustedCodeAfter = adjustedCode.slice(currentIndex); const nextSectionHeadingMatch = adjustedCodeAfter.match(/\n+(=+).*?\1[ \t\x01\x02]*\n|$/); let chunkCodeAfterEndIndex = currentIndex + nextSectionHeadingMatch.index + 1; let chunkCodeAfter = pageCode.slice(currentIndex, chunkCodeAfterEndIndex); cd.config.keepInSectionEnding.forEach((regexp) => { const match = chunkCodeAfter.match(regexp); if (match) { // "1" accounts for the first line break. chunkCodeAfterEndIndex -= match[0].length - 1; } }); const adjustedChunkCodeAfter = adjustedCode.slice(currentIndex, chunkCodeAfterEndIndex); const maxIndentationCharsLength = thisInCode.replyIndentationChars.length - 1; const properPlaceRegexp = new RegExp( '^([^]*?(?:' + mw.util.escapeRegExp(thisInCode.signatureCode) + '|' + cd.g.TIMESTAMP_REGEXP.source + '.*' + (cd.g.UNSIGNED_TEMPLATES_PATTERN ? `|${cd.g.UNSIGNED_TEMPLATES_PATTERN}.*` : '') + // "\x01" is from hiding closed discussions and HTML comments. TODO: Line can start with a // HTML comment in a <pre> tag, that doesn't mean we can put a comment after it. We perhaps // need to change `wikitext.hideDistractingCode`. '|(?:^|\\n)\\x01.+)\\n)\\n*(?:' + // "\n" is here to avoid putting the reply on a casual empty line. "\x01" is from hiding // closed discussions. `[:*#\\x01]{0,${maxIndentationCharsLength}}(?![:*#\\n\\x01])` + // This excludes the case where "#" is starting a numbered list inside a comment // (https://ru.wikipedia.org/w/index.php?diff=110482717). ( maxIndentationCharsLength > 0 ? `|[:*#\\x01]{1,${maxIndentationCharsLength}}(?![:*\\n\\x01])` : '' ) + ')' ); let [, adjustedCodeInBetween] = adjustedChunkCodeAfter.match(properPlaceRegexp) || []; if (adjustedCodeInBetween === undefined) { throw new CdError({ type: 'parse', code: 'findPlace', }); } // Hotfix for comments inside a table (barnstars, for example). if (adjustedChunkCodeAfter.slice(adjustedCodeInBetween.length).startsWith('|}\n')) { adjustedCodeInBetween += '|}\n'; } // If the comment is to be put after a comment with different indentation characters, use // these. const [, changedIndentationChars] = ( adjustedCodeInBetween.match(/\n([:*#]{2,}|#[:*#]*).*\n$/) || [] ); if (changedIndentationChars) { // Note the bug https://ru.wikipedia.org/w/index.php?diff=next&oldid=105529545 that was // possible here when we used ".slice(0, thisInCode.indentationChars.length + 1)" (due to // "**" as indentation characters in Bsivko's comment). thisInCode.replyIndentationChars = changedIndentationChars .slice(0, thisInCode.replyIndentationChars.length) .replace(/:$/, cd.config.defaultIndentationChar); } currentIndex += adjustedCodeInBetween.length; } if (!commentCode && commentForm && !doDelete) { ({ commentCode } = commentForm.commentTextToCode('submit')); } let newPageCode; let codeBeforeInsertion; switch (action) { case 'reply': { codeBeforeInsertion = pageCode.slice(0, currentIndex); newPageCode = codeBeforeInsertion + commentCode + pageCode.slice(currentIndex); break; } case 'edit': { if (doDelete) { let startIndex; let endIndex; if (this.isOpeningSection && thisInCode.headingStartIndex !== undefined) { this.getSection().locateInCode(); if (extractSignatures(this.getSection().inCode.code).length > 1) { throw new CdError({ type: 'parse', code: 'delete-repliesInSection', }); } else { // Deleting the whole section is safer as we don't want to leave any content in the // end anyway. ({ startIndex, contentEndIndex: endIndex } = this.getSection().inCode); } } else { endIndex = thisInCode.signatureEndIndex + 1; const succeedingText = pageCode.slice(thisInCode.endIndex); const repliesRegexp = new RegExp( `^.+\\n+[:*#]{${thisInCode.indentationChars.length + 1},}` ); const repliesMatch = repliesRegexp.exec(succeedingText); if (repliesMatch) { throw new CdError({ type: 'parse', code: 'delete-repliesToComment', }); } else { startIndex = thisInCode.lineStartIndex; } } newPageCode = pageCode.slice(0, startIndex) + pageCode.slice(endIndex); } else { const startIndex = thisInCode.lineStartIndex; codeBeforeInsertion = pageCode.slice(0, startIndex); const codeAfterInsertion = pageCode.slice(thisInCode.signatureEndIndex); newPageCode = codeBeforeInsertion + commentCode + codeAfterInsertion; } break; } } return { newPageCode, codeBeforeInsertion, commentCode }; } /** * Get and sometimes create the container for the comment's underlay. * * @returns {Element} */ getLayersContainer() { if (this.cachedLayersContainer === undefined) { let offsetParent; const treeWalker = new TreeWalker(document.body, null, true, this.elements[0]); while (treeWalker.parentNode()) { let style = treeWalker.currentNode.conveneintDiscussionsStyle; if (!style) { // window.getComputedStyle is expensive, so we save the result to the node's property. style = window.getComputedStyle(treeWalker.currentNode); treeWalker.currentNode.conveneintDiscussionsStyle = style; } if (['absolute', 'relative'].includes(style.position)) { offsetParent = treeWalker.currentNode; } const backgroundColor = style.backgroundColor; if (backgroundColor.includes('rgb(') || style.backgroundImage !== 'none') { if (backgroundColor.includes('rgb(')) { /** * Comment's background color if not default. * * @type {string|undefined} */ this.backgroundColor = backgroundColor; } if (!offsetParent) { offsetParent = treeWalker.currentNode; offsetParent.classList.add('cd-commentLayersContainerParent-relative'); } } if (offsetParent) break; } if (!offsetParent) { offsetParent = document.body; } offsetParent.classList.add('cd-commentLayersContainerParent'); let container = offsetParent.firstElementChild; if (!container.classList.contains('cd-commentLayersContainer')) { container = document.createElement('div'); container.classList.add('cd-commentLayersContainer'); offsetParent.insertBefore(container, offsetParent.firstChild); } this.cachedLayersContainer = container; if (!commentLayers.layersContainers.includes(container)) { commentLayers.layersContainers.push(container); } } return this.cachedLayersContainer; } /** * @typedef {object} LayersContainerOffset * @property {number} top Top offset. * @property {number} left Left offset. */ /** * Get the top and left offset of the layers container. * * @returns {LayersContainerOffset} */ getLayersContainerOffset() { const container = this.getLayersContainer(); let top = container.cdCachedLayersContainerTop; let left = container.cdCachedLayersContainerLeft; if (top === undefined || container.cdCouldHaveMoved) { let el = container; let offsetParent; top = 0; left = 0; while ((offsetParent = el.offsetParent)) { top += offsetParent.offsetTop; left += offsetParent.offsetLeft; el = offsetParent; } container.cdCouldHaveMoved = false; container.cdCachedLayersContainerTop = top; container.cdCachedLayersContainerLeft = left; } return { top, left }; } /** * Request the gender of the comment's author if it is absent and affects the user mention string * and do something when it's received. * * @param {Function} callback * @param {boolean} [runAlways=false] Whether to execute the callback even if the gender request * is not needed. */ requestAuthorGenderIfNeeded(callback, runAlways = false) { if (cd.g.GENDER_AFFECTS_USER_STRING && this.author.isRegistered() && !this.author.getGender()) { this.genderRequestCallbacks = this.genderRequestCallbacks || []; let errorCallback; if (!this.genderRequest) { this.genderRequest = getUserGenders([this.author]); errorCallback = (e) => { console.warn(`Couldn't get the gender of user ${this.author.name}.`, e); }; } if (!this.genderRequestCallbacks.includes(callback)) { this.genderRequest.then(callback, errorCallback); this.genderRequestCallbacks.push(callback); } } else { if (runAlways) { setTimeout(callback); } } } /** * Get the wiki page that has the source code of the comment (may be different from the current * page if the comment is transcluded from another page). * * @type {Page} */ getSourcePage() { const section = this.getSection(); return section ? section.getSourcePage() : cd.g.CURRENT_PAGE; } /** * Show a diff of changes in the comment between the current revision ID and the provided one. * * @param {number} comparedRevisionId * @param {object} commentsData * @throws {CdError} */ async showDiff(comparedRevisionId, commentsData) { if (dealWithLoadingBug('mediawiki.diff.styles')) return; let revisionIdLesser = Math.min(mw.config.get('wgRevisionId'), comparedRevisionId); let revisionIdGreater = Math.max(mw.config.get('wgRevisionId'), comparedRevisionId); const revisionsRequest = cd.g.api.post({ action: 'query', revids: [revisionIdLesser, revisionIdGreater], prop: 'revisions', rvslots: 'main', rvprop: ['ids', 'content'], redirects: true, formatversion: 2, }).catch(handleApiReject); const compareRequest = cd.g.api.post({ action: 'compare', fromtitle: this.getSourcePage().name, fromrev: revisionIdLesser, torev: revisionIdGreater, prop: ['diff'], formatversion: 2, }).catch(handleApiReject); let [revisionsResp, compareResp] = await Promise.all([ revisionsRequest, compareRequest, mw.loader.using('mediawiki.diff.styles'), ]); const revisions = revisionsResp.query?.pages?.[0]?.revisions; if (!revisions) { throw new CdError({ type: 'api', code: 'noData', }); } const lineNumbers = [[], []]; revisions.forEach((revision, i) => { const pageCode = revision.slots.main.content; const inCode = this.locateInCode(pageCode, commentsData[i]); const newlinesBeforeComment = pageCode.slice(0, inCode.lineStartIndex).match(/\n/g) || []; const newlinesInComment = ( pageCode.slice(inCode.lineStartIndex, inCode.signatureEndIndex).match(/\n/g) || [] ); const startLineNumber = newlinesBeforeComment.length + 1; const endLineNumber = startLineNumber + newlinesInComment.length; for (let j = startLineNumber; j <= endLineNumber; j++) { lineNumbers[i].push(j); } }); const body = compareResp?.compare?.body; if (!body) { throw new CdError({ type: 'api', code: 'noData', }); } const $diff = $(cd.util.wrapDiffBody(body)); let currentLineNumbers = []; let cleanDiffBody = ''; $diff.find('tr').each((i, tr) => { const $tr = $(tr); const $lineNumbers = $tr.children('.diff-lineno'); for (let j = 0; j < $lineNumbers.length; j++) { const match = $lineNumbers.eq(j).text().match(/\d+/); currentLineNumbers[j] = Number((match || [])[0]); if (!currentLineNumbers[j]) { throw new CdError({ type: 'parse', }); } if (j === 1) return; } if (!$tr.children('.diff-marker').length) return; let addToDiff = false; for (let j = 0; j < 2; j++) { if (!$tr.children().eq(j * 2).hasClass('diff-empty')) { if (lineNumbers[j].includes(currentLineNumbers[j])) { addToDiff = true; } currentLineNumbers[j]++; } } if (addToDiff) { cleanDiffBody += $tr.prop('outerHTML'); } }); const $cleanDiff = $(cd.util.wrapDiffBody(cleanDiffBody)); if (!$cleanDiff.find('.diff-deletedline, .diff-addedline').length) { throw new CdError({ type: 'parse', message: cd.s('comment-edited-diff-empty'), }); } const $historyLink = $('<a>') .attr('href', this.getSourcePage().getUrl({ action: 'history' })) .attr('target', '_blank') .text(cd.s('comment-edited-history')); const $below = $('<div>') .addClass('cd-commentDiffView-below') .append($historyLink); const $message = $('<div>').append($cleanDiff, $below); OO.ui.alert($message, { size: 'larger' }); } } Object.assign(Comment, CommentStatic); "
"/** * Module loaded on pages where we need to add comment links to history entries (at minimum). * * @module commentLinks */ import { create as nanoCssCreate } from 'nano-css'; import Comment from './Comment'; import Page from './Page'; import cd from './cd'; import { caseInsensitiveFirstCharPattern, isCommentEdit, isProbablyTalkPage, isUndo, removeDirMarks, spacesToUnderlines, } from './util'; import { editWatchedSections, settingsDialog } from './modal'; import { generateCommentAnchor, parseTimestamp } from './timestamp'; import { getWatchedSections } from './options'; import { initSettings } from './boot'; import { initTimestampParsingTools, loadData } from './siteData'; let colon; let moveFromBeginning; let moveToBeginning; let goToCommentToYou; let goToCommentWatchedSection; let currentUserRegexp; let $wrapperRegularPrototype; let $wrapperInterestingPrototype; let switchInterestingButton; let processDiffFirstRun = true; /** * Prepare variables. * * @param {object} [data] Data passed from the main module. * @param {Promise} [data.dataRequest] Promise returned by {@link module:siteData.loadData}. * @private */ async function prepare({ dataRequest }) { cd.g.api = cd.g.api || new mw.Api(); // Loading the watched sections is not critical, as opposed to messages, so we catch the possible // error, not letting it be caught by the try/catch block. const watchedSectionsRequest = getWatchedSections(true).catch((e) => { console.warn('Couldn\'t load the settings from the server.', e); }); dataRequest = dataRequest || loadData(); try { await Promise.all([watchedSectionsRequest, dataRequest]); } catch (e) { throw ['Couldn\'t load the messages required for the script.', e]; } cd.g.nanoCss = nanoCssCreate(); cd.g.nanoCss.put('.cd-commentLink-innerWrapper', { '::before': { content: `"${cd.mws('parentheses-start')}"`, }, '::after': { content: `"${cd.mws('parentheses-end')}"`, }, }); cd.g.PHP_CHAR_TO_UPPER_JSON = mw.loader.moduleRegistry['mediawiki.Title'].script .files["phpCharToUpper.json"]; cd.g.CURRENT_PAGE = new Page(cd.g.CURRENT_PAGE_NAME); cd.g.QQX_MODE = mw.util.getParamValue('uselang') === 'qqx'; initTimestampParsingTools(); colon = cd.mws('colon-separator').trim(); [moveFromBeginning] = cd.s('es-move-from').match(/^[^[$]+/) || []; [moveToBeginning] = cd.s('es-move-to').match(/^[^[$]+/) || []; goToCommentToYou = `${cd.s('lp-comment-tooltip')} ${cd.mws('parentheses', cd.s('lp-comment-toyou'))}`; goToCommentWatchedSection = `${cd.s('lp-comment-tooltip')} ${cd.mws('parentheses', cd.s('lp-comment-watchedsection'))}`; const $aRegularPrototype = $('<a>') .text(cd.s('lp-comment')) .attr('title', cd.s('lp-comment-tooltip')); const $spanRegularPrototype = $('<span>') .addClass('cd-commentLink-innerWrapper') .append($aRegularPrototype); $wrapperRegularPrototype = $('<span>') .addClass('cd-commentLink') .append($spanRegularPrototype) .prepend(' '); $wrapperInterestingPrototype = $wrapperRegularPrototype .clone() .addClass('cd-commentLink-interesting'); const currentUserNamePattern = caseInsensitiveFirstCharPattern(cd.g.CURRENT_USER_NAME) .replace(/ /g, '[ _]'); currentUserRegexp = new RegExp( `(?:^|[^${cd.g.LETTER_PATTERN}])${currentUserNamePattern}(?![${cd.g.LETTER_PATTERN}])` ); } /** * Show/hide interesting edits. * * @private */ function switchInteresting() { // Item grouping switched on. This may be done in the settings or in the URL. const isEnhanced = !$('.mw-changeslist').find('ul.special').length; // This is for many watchlist types at once. const $collapsibles = cd.g.$content .find('.mw-changeslist .mw-collapsible:not(.mw-changeslist-legend)'); const $lines = cd.g.$content.find('.mw-changeslist-line:not(.mw-collapsible)'); if (switchInterestingButton.hasFlag('progressive')) { // Show all // FIXME: Old watchlist (no JS) + ?enhanced=1&urlversion=2 if (isEnhanced) { $lines .filter('table') .show(); } else { $lines .not(':has(.cd-commentLink-interesting)') .show(); } $collapsibles .not(':has(.cd-commentLink-interesting)') .find('.mw-rcfilters-ui-highlights-enhanced-toplevel') .show(); $collapsibles .not('.mw-collapsed') .find('.mw-enhancedchanges-arrow') .click(); } else { // Show interesting only $collapsibles .not('.mw-collapsed') .find('.mw-enhancedchanges-arrow') .click(); $collapsibles .has('.cd-commentLink-interesting') .find('.mw-enhancedchanges-arrow') .click() $collapsibles .not(':has(.cd-commentLink-interesting)') .find('.mw-rcfilters-ui-highlights-enhanced-toplevel') .hide(); $lines .not(':has(.cd-commentLink-interesting)') .hide(); } switchInterestingButton .setFlags({ progressive: !switchInterestingButton.hasFlag('progressive') }); } /** * Add watchlist menu (a block with buttons). * * @private */ function addWatchlistMenu() { // For auto-updating watchlists mw.hook('wikipage.content').add(() => { if (switchInterestingButton) { switchInterestingButton.setFlags({ progressive: false }); } }); const $menu = $('<div>').addClass('cd-watchlistMenu'); $('<a>') .attr('href', mw.util.getUrl(cd.config.scriptPageWikilink)) .attr('target', '_blank') .addClass('cd-watchlistMenu-scriptPageLink') .text(cd.s('script-name-short')) .appendTo($menu); switchInterestingButton = new OO.ui.ButtonWidget({ framed: false, icon: 'speechBubble', label: cd.s('wl-button-switchinteresting-tooltip'), invisibleLabel: true, title: cd.s('wl-button-switchinteresting-tooltip'), classes: ['cd-watchlistMenu-button', 'cd-watchlistMenu-button-switchInteresting'], disabled: !cd.g.watchedSections, }); switchInterestingButton.on('click', () => { switchInteresting(); }); switchInterestingButton.$element.appendTo($menu); const editWatchedSectionsButton = new OO.ui.ButtonWidget({ framed: false, icon: 'listBullet', label: cd.s('wl-button-editwatchedsections-tooltip'), invisibleLabel: true, title: cd.s('wl-button-editwatchedsections-tooltip'), classes: ['cd-watchlistMenu-button', 'cd-watchlistMenu-button-editWatchedSections'], }); editWatchedSectionsButton.on('click', editWatchedSections); editWatchedSectionsButton.$element.appendTo($menu); const settingsButton = new OO.ui.ButtonWidget({ framed: false, icon: 'settings', label: cd.s('wl-button-settings-tooltip'), invisibleLabel: true, title: cd.s('wl-button-settings-tooltip'), classes: ['cd-watchlistMenu-button', 'cd-watchlistMenu-button-scriptSettings'], }); settingsButton.on('click', () => { settingsDialog(); }); settingsButton.$element.appendTo($menu); // New watchlist, old watchlist cd.g.$content.find('.mw-rcfilters-ui-changesLimitAndDateButtonWidget').prepend($menu); cd.g.$content.find('#mw-watchlist-options .mw-changeslist-legend').after($menu); } /** * Extract an author given a revision line. * * @param {Element} line * @returns {?string} * @private */ function extractAuthor(line) { const authorElement = line.querySelector('.mw-userlink'); if (!authorElement) { return null; } let author = authorElement.textContent; if (author === 'MediaWiki message delivery') { return null; } if (mw.util.isIPv6Address(author)) { author = author.toUpperCase(); } return author; } /** * Check by an edit summary if an edit is probably a move performed by our script. * * @param {string} summary * @returns {boolean} * @private */ function isMoved(summary) { return ( (moveFromBeginning && summary.includes(': ' + moveFromBeginning)) || (moveToBeginning && summary.includes(': ' + moveToBeginning)) ); } /** * Check by an edit summary if an edit is probably an archiving operation. * * @param {string} summary * @returns {boolean} * @private */ function isArchiving(summary) { return summary.includes('Archiving'); } /** * Check by an edit summary if it is an edit in a section this given name. * * @param {string} summary * @param {string} name * @returns {boolean} */ function isInSection(summary, name) { if (!name) { return false; } // This can run many thousand times, so we use the cheapest way. return cd.g.SITE_DIR === 'ltr' ? summary.includes(`→${name}${colon}`) || summary.endsWith(`→${name}`) : summary.includes(`←${name}${colon}`) || summary.endsWith(`←${name}`); } /** * Add comment links to a watchlist or a recent changes page. Add a watchlist menu to the watchlist. * * @param {JQuery} $content * @private */ function processWatchlist($content) { if ( mw.config.get('wgCanonicalSpecialPageName') === 'Watchlist' && !cd.g.$content.find('.cd-watchlistMenu').length ) { initSettings(); if (mw.user.options.get('wlenhancedfilters-disable')) { addWatchlistMenu(); } else { mw.hook('structuredChangeFilters.ui.initialized').add(() => { addWatchlistMenu(); }); } $('.mw-rcfilters-ui-filterWrapperWidget-showNewChanges a').on('click', async () => { try { await getWatchedSections(); } catch (e) { console.warn('Couldn\'t load the settings from the server.', e); } }); } // There are 2 ^ 3 = 8 (!) different watchlist modes: // * expanded and not // * with item grouping and without // * with enhanced fitlers and without const lines = $content.get(0).querySelectorAll('.mw-changeslist-line:not(.mw-collapsible)'); lines.forEach((line) => { const nsMatch = line.className.match(/mw-changeslist-ns(\d+)/); const nsNumber = nsMatch && Number(nsMatch[1]); if (nsNumber === null) return; const isNested = line.tagName === 'TR'; const linkElement = (isNested ? line.parentNode : line) .querySelector('.mw-changeslist-title'); if (!linkElement) return; const pageName = linkElement.textContent; if (!isProbablyTalkPage(pageName, nsNumber)) return; if (line.querySelector('.minoredit')) return; let summary = line.querySelector('.comment')?.textContent; summary = summary && removeDirMarks(summary); if (summary && (isCommentEdit(summary) || isUndo(summary) || isMoved(summary))) return; const bytesAddedElement = line.querySelector('.mw-plusminus-pos'); if (!bytesAddedElement) { return; } if (bytesAddedElement.tagName !== 'STRONG') { const bytesAddedMatch = bytesAddedElement.textContent.match(/\d+/); const bytesAdded = bytesAddedMatch && Number(bytesAddedMatch[0]); if (!bytesAdded || bytesAdded < cd.config.bytesToDeemComment) return; } const timestamp = line.getAttribute('data-mw-ts')?.slice(0, 12); if (!timestamp) return; const author = extractAuthor(line); if (!author) return; const anchor = timestamp + '_' + spacesToUnderlines(author); const link = linkElement.href; if (!link) return; let wrapper; if (summary && currentUserRegexp.test(` ${summary} `)) { wrapper = $wrapperInterestingPrototype.get(0).cloneNode(true); wrapper.lastChild.lastChild.title = goToCommentToYou; } else { let isWatched = false; if (summary) { const curLink = ( // Expanded watchlist line.querySelector('.mw-changeslist-diff-cur') || // Non-expanded watchlist line.querySelector('.mw-changeslist-history') ); const curIdMatch = curLink?.href?.match(/[&?]curid=(\d+)/); const curId = curIdMatch && Number(curIdMatch[1]); if (curId) { const thisPageWatchedSections = cd.g.watchedSections?.[curId] || []; if (thisPageWatchedSections.length) { for (let j = 0; j < thisPageWatchedSections.length; j++) { if (isInSection(summary, thisPageWatchedSections[j])) { isWatched = true; break; } } if (isWatched) { wrapper = $wrapperInterestingPrototype.get(0).cloneNode(true); wrapper.lastChild.lastChild.title = goToCommentWatchedSection; } } } } if (!isWatched) { wrapper = $wrapperRegularPrototype.get(0).cloneNode(true); } } wrapper.lastChild.lastChild.href = `${link}#${anchor}`; const destination = line.querySelector('.comment') || line.querySelector('.mw-usertoollinks'); if (!destination) return; destination.parentNode.insertBefore(wrapper, destination.nextSibling); }); } /** * Add comment links to a contributions page. * * @param {JQuery} $content * @private */ function processContributions($content) { const timezone = mw.user.options.get('timecorrection'); const timezoneParts = timezone?.split('|'); const timezoneOffset = timezoneParts && Number(timezoneParts[1]); if (timezoneOffset == null || isNaN(timezoneOffset)) return; const list = $content.get(0).querySelector('.mw-contributions-list'); const lines = Array.from(list.children); lines.forEach((line) => { const linkElement = line.querySelector('.mw-contributions-title'); if (!linkElement) return; const pageName = linkElement.textContent; const page = new Page(pageName); if (!page.isProbablyTalkPage()) return; const link = linkElement.href; if (!link) return; if (line.querySelector('.minoredit')) return; const summary = line.querySelector('.comment')?.textContent; if (summary && (isCommentEdit(summary) || isUndo(summary) || isMoved(summary))) return; const bytesAddedElement = line.querySelector('.mw-plusminus-pos'); if (!bytesAddedElement) return; if (bytesAddedElement.tagName !== 'STRONG') { const bytesAddedMatch = bytesAddedElement.textContent.match(/\d+/); const bytesAdded = bytesAddedMatch && Number(bytesAddedMatch[0]); if (!bytesAdded || bytesAdded < cd.config.bytesToDeemComment) return; } const dateElement = line.querySelector('.mw-changeslist-date'); if (!dateElement) return; const { date } = parseTimestamp(dateElement.textContent, timezoneOffset) || {}; if (!date) return; const anchor = generateCommentAnchor(date, mw.config.get('wgRelevantUserName')); let wrapper; if (summary && currentUserRegexp.test(` ${summary} `)) { wrapper = $wrapperInterestingPrototype.get(0).cloneNode(true); wrapper.lastChild.lastChild.title = goToCommentToYou; } else { // We have no place to extract the article ID from :-( wrapper = $wrapperRegularPrototype.get(0).cloneNode(true); } wrapper.lastChild.lastChild.href = `${link}#${anchor}`; let destination = line.querySelector('.comment'); if (!destination) { destination = linkElement; destination.nextSibling.textContent = destination.nextSibling.textContent.replace(/^\s/, ''); } destination.parentNode.insertBefore(wrapper, destination.nextSibling); }); } /** * Add comment links to a history page. * * @param {JQuery} $content * @private */ function processHistory($content) { const timezone = mw.user.options.get('timecorrection'); const timezoneParts = timezone?.split('|'); const timezoneOffset = timezoneParts && Number(timezoneParts[1]); if (timezoneOffset == null || isNaN(timezoneOffset)) return; const list = $content.get(0).querySelector('#pagehistory'); const lines = Array.from(list.children); const link = cd.g.CURRENT_PAGE.getUrl(); lines.forEach((line) => { if (line.querySelector('.minoredit')) return; let summary = line.querySelector('.comment')?.textContent; summary = summary && removeDirMarks(summary); if (summary && (isCommentEdit(summary) || isUndo(summary) || isMoved(summary))) return; const bytesAddedElement = line.querySelector('.mw-plusminus-pos'); if (!bytesAddedElement) return; if (bytesAddedElement.tagName !== 'STRONG') { const bytesAddedMatch = bytesAddedElement.textContent.match(/\d+/); const bytesAdded = bytesAddedMatch && Number(bytesAddedMatch[0]); if (!bytesAdded || bytesAdded < cd.config.bytesToDeemComment) return; } const dateElement = line.querySelector('.mw-changeslist-date'); if (!dateElement) return; const { date } = parseTimestamp(dateElement.textContent, timezoneOffset) || {}; if (!date) return; const author = extractAuthor(line); if (!author) return; const anchor = generateCommentAnchor(date, author); let wrapper; if (summary && currentUserRegexp.test(` ${summary} `)) { wrapper = $wrapperInterestingPrototype.get(0).cloneNode(true); wrapper.lastChild.lastChild.title = goToCommentToYou; } else { let isWatched = false; if (summary) { const thisPageWatchedSections = cd.g.watchedSections?.[mw.config.get('wgArticleId')] || []; if (thisPageWatchedSections.length) { for (let j = 0; j < thisPageWatchedSections.length; j++) { if (isInSection(summary, cd.g.thisPageWatchedSections[j])) { isWatched = true; break; } } if (isWatched) { wrapper = $wrapperInterestingPrototype.get(0).cloneNode(true); wrapper.lastChild.lastChild.title = goToCommentWatchedSection; } } } if (!isWatched) { wrapper = $wrapperRegularPrototype.get(0).cloneNode(true); } } wrapper.lastChild.lastChild.href = `${link}#${anchor}`; let destination = line.querySelector('.comment'); if (!destination) { const separators = line.querySelectorAll('.mw-changeslist-separator'); destination = separators?.[separators.length - 1]; } if (!destination) return; destination.parentNode.insertBefore(wrapper, destination.nextSibling); }); } /** * Add comment link to a diff page. * * @fires commentLinksCreated * @private */ async function processDiff() { if (!processDiffFirstRun) return; const timezone = mw.user.options.get('timecorrection'); const timezoneParts = timezone?.split('|'); const timezoneOffset = timezoneParts && Number(timezoneParts[1]); if (timezoneOffset == null || isNaN(timezoneOffset)) return; [document.querySelector('.diff-otitle'), document.querySelector('.diff-ntitle')] .filter((el) => el !== null) .forEach((area) => { if (area.querySelector('.minoredit')) return; let summary = area.querySelector('.comment')?.textContent; summary = summary && removeDirMarks(summary); if ( summary && // In diffs, archivation can't be captured by looking at bytes added. (isCommentEdit(summary) || isUndo(summary) || isMoved(summary) || isArchiving(summary)) ) { return; } const dateElement = area.querySelector('#mw-diff-otitle1 a, #mw-diff-ntitle1 a'); if (!dateElement) return; const { date } = parseTimestamp(dateElement.textContent, timezoneOffset) || {}; if (!date) return; const author = extractAuthor(area); if (!author) return; const anchor = generateCommentAnchor(date, author); let comment = Comment.getByAnchor(anchor); if (!comment) { let commentAnchorToCheck; // There can be a time difference between the time we know (taken from the watchlist or // generated in the script) and the time on the page. We take it to be not higher than 5 // minutes for the watchlist time and not higher than 1 minute for the script-generated // time. for (let gap = 1; !comment && gap <= 5; gap++) { const dateToFind = new Date(date.getTime() - cd.g.MILLISECONDS_IN_A_MINUTE * gap); commentAnchorToCheck = generateCommentAnchor(dateToFind, author); comment = Comment.getByAnchor(commentAnchorToCheck); } } if (comment) { let wrapper; if (summary && currentUserRegexp.test(` ${summary} `)) { wrapper = $wrapperInterestingPrototype.get(0).cloneNode(true); wrapper.lastChild.lastChild.title = goToCommentToYou; } else { let isWatched = false; if (summary && cd.g.thisPageWatchedSections.length) { for (let j = 0; j < cd.g.thisPageWatchedSections.length; j++) { if (isInSection(summary, cd.g.thisPageWatchedSections[j])) { isWatched = true; break; } } if (isWatched) { wrapper = $wrapperInterestingPrototype.get(0).cloneNode(true); wrapper.lastChild.lastChild.title = goToCommentWatchedSection; } } if (!isWatched) { wrapper = $wrapperRegularPrototype.get(0).cloneNode(true); } } const href = '#' + anchor; wrapper.lastChild.lastChild.href = href; wrapper.onclick = function (e) { e.preventDefault(); comment.scrollToAndHighlightTarget(false, true); }; const destination = area.querySelector('#mw-diff-otitle3, #mw-diff-ntitle3'); if (!destination) return; destination.appendChild(wrapper); } }); /** * Comments links have been created. * * @event commentLinksCreated * @type {module:cd~convenientDiscussions} */ mw.hook('convenientDiscussions.commentLinksCreated').fire(cd); processDiffFirstRun = false; } /** * Add comment links to the page. * * @param {JQuery} $content * @private */ async function addCommentLinks($content) { // Occurs in the watchlist when mediawiki.rcfilters.filters.ui module for some reason fires // wikipage.content for the second time with an element that is not in the DOM, // fieldset#mw-watchlist-options (in the mw.rcfilters.ui.FormWrapperWidget#onChangesModelUpdate // function). if (!$content.parent().length) return; if (['Recentchanges', 'Watchlist'].includes(mw.config.get('wgCanonicalSpecialPageName'))) { processWatchlist($content); } else if (mw.config.get('wgCanonicalSpecialPageName') === 'Contributions') { processContributions($content); } else if (mw.config.get('wgAction') === 'history' && cd.g.CURRENT_PAGE.isProbablyTalkPage()) { processHistory($content); } mw.hook('convenientDiscussions.commentLinksCreated').fire(cd); } /** * The entry function for the comment links adding mechanism. * * @param {object} [data] Data passed from the main module. */ export default async function commentLinks({ dataRequest }) { try { await prepare({ dataRequest }); } catch (e) { console.warn(...e); return; } if (cd.g.IS_DIFF_PAGE) { mw.hook('convenientDiscussions.pageReady').add(processDiff); } else { // Hook on wikipage.content to make the code work with the watchlist auto-update feature. mw.hook('wikipage.content').add(addCommentLinks); } } "
"/** * Comment skeleton class. * * @module CommentSkeleton */ import CdError from './CdError'; import cd from './cd'; import { ElementsTreeWalker } from './treeWalker'; /** * Class containing the main properties of a comment. This class is the only one used in the worker * context for comments. * * @class */ export default class CommentSkeleton { /** * Create a comment skeleton instance. * * @param {Parser} parser * @param {object} signature Signature object returned by {@link module:Parser#findSignatures}. * @throws {CdError} */ constructor(parser, signature) { this.parser = parser; // Identify all comment nodes and save a path to them. let parts = this.parser.collectParts(signature.element); // Remove parts contained by other parts. parts = this.parser.removeNestedParts(parts); // We may need to enclose sibling sequences in a <div> tag in order for them not to be bare (we // can't get bounding client rectangle for text nodes, can't specify margins for them etc.). parts = this.parser.encloseInlineParts(parts, signature.element); // At this point, we can safely remove unnecessary nodes. parts = this.parser.filterParts(parts); parts.reverse(); // dd, li instead of dl, ul, ol where appropriate. parts = this.parser.replaceListsWithItems(parts, signature.element); /** * Comment ID. Same as the comment index in {@link module:cd~convenientDiscussions.comments * convenientDiscussions.comments}. * * @type {number} */ this.id = cd.comments.length; /** * Comment date. * * @type {?Date} */ this.date = signature.date || null; /** * Comment timestamp as present on the page. * * @type {string} */ this.timestamp = signature.timestampText; /** * Comment author name. * * @type {string} */ this.authorName = signature.authorName; // This is for the worker context and quickly gets removed. this.signatureElement = signature.element; /** * Does the comment belong to the current user. * * @type {boolean} */ this.isOwn = this.authorName === cd.g.CURRENT_USER_NAME; /** * Comment anchor. * * @type {?string} */ this.anchor = signature.anchor; /** * Is the comment unsigned or not properly signed (an unsigned template class is present). * * Not used anywhere in the script yet. * * @type {boolean} */ this.isUnsigned = signature.isUnsigned; /** * Comment parts. * * @type {object[]} */ this.parts = parts; /** * Comment elements. * * @type {Element[]} */ this.elements = this.parts.map((part) => part.node); const isHighlightable = (el) => ( !/^(H[1-6]|STYLE|LINK)$/.test(el.tagName) && !cd.g.UNHIGHLIGHTABLE_ELEMENT_CLASSES.some((name) => el.classList.contains(name)) && !/float: *(?:left|right)|display: *none/.test(el.getAttribute('style')) ); /** * Comment elements that are highlightable. * * Keep in mind that the elements may be replaced, and the property values will need to be * updated. See `mergeAdjacentCommentLevels()` in {@link module:modifyDom}. * * @type {Element[]} */ this.highlightables = this.elements.filter(isHighlightable); // That which cannot be highlighted should not be considered existent. if (!this.highlightables.length) { throw new CdError(); } this.setLevels(); /** * Is the comment preceded by a heading. Set to `true` in the {@link SectionSkeleton} * constructor if that's the case. * * @type {boolean} */ this.followsHeading = false; if (this.parts[0].isHeading && this.level !== 0) { this.parts.shift(); this.elements.shift(); } if (this.parts[0].isHeading) { /** * Does the comment open a section (has a heading as the first element and is placed at the * zeroth level). * * @type {boolean} */ this.isOpeningSection = true; const headingLevelMatch = this.parts[0].node.tagName.match(/^H([1-6])$/); this.openingSectionOfLevel = headingLevelMatch && Number(headingLevelMatch[1]); } else { this.isOpeningSection = false; } this.addAttributes(); } /** * Add the necessary attributes to the comment elements. * * @private */ addAttributes() { if (this.anchor && !this.elements[0].getAttribute('id')) { this.elements[0].setAttribute('id', this.anchor); } this.highlightables[0].classList.add('cd-commentPart-first'); this.highlightables[this.highlightables.length - 1].classList.add('cd-commentPart-last'); this.elements.forEach((el) => { el.classList.add('cd-commentPart'); el.setAttribute('data-comment-id', String(this.id)); }); } /** * Set the necessary classes to parent elements of the comment elements to make a visible tree * structure. * * @private */ setLevels() { // We make sure the level on the top and on the bottom of the comment are the same, and add // corresponding classes. const levelElements = {}; levelElements.top = this.parser.getLevelsUpTree(this.highlightables[0]); levelElements.bottom = this.highlightables.length > 1 ? this.parser.getLevelsUpTree(this.highlightables[this.highlightables.length - 1]) : levelElements.top; /** * Comment level. A level is a number representing the number of indentation characters * preceding the comment (no indentation means zeroth level). * * @type {number} */ this.level = Math.min(levelElements.top.length, levelElements.bottom.length); for (let i = 0; i < this.level; i++) { if (levelElements.top[i]) { levelElements.top[i].classList.add('cd-commentLevel', `cd-commentLevel-${i + 1}`); } if (levelElements.bottom[i] && levelElements.bottom[i] !== levelElements.top[i]) { levelElements.bottom[i].classList.add('cd-commentLevel', `cd-commentLevel-${i + 1}`); } } } /** * Get the lowest level (= with the biggest level number) section that the comment is in. * * @returns {?Section} * @private */ getSection() { if (this.cachedSection === undefined) { this.cachedSection = ( cd.sections .slice() .reverse() .find((section) => section.comments.includes(this)) || null ); } return this.cachedSection; } /** * Get all replies to the comment. * * @returns {CommentSkeleton[]} */ getChildren() { if (this.id === cd.comments.length - 1) { return []; } if (cd.g.pageHasOutdents) { const treeWalker = new ElementsTreeWalker(this.elements[this.elements.length - 1]); while ( treeWalker.nextNode() && !treeWalker.currentNode.classList.contains('cd-commentPart') ) { if (treeWalker.currentNode.classList.contains('outdent-template')) { return [cd.comments[this.id + 1]]; } } } const children = []; cd.comments .slice(this.id + 1) .some((otherComment) => { if (otherComment.getSection() === this.getSection() && otherComment.level > this.level) { if ( otherComment.level === this.level + 1 || // Comments mistakenly indented more than one level otherComment.id === this.id + 1 ) { children.push(otherComment); } } else { return true; } }); return children; } } "
"/** * A number of methods to simplify measuring time that it takes to run certain routines as well as * counting the number of times certain instructions run. * * @module debug */ export default { /** * Init/reset all properties of the debug object. */ init() { /** * Total time for every timer. * * @type {object} */ this.timerTotal = {}; /** * Timer start timestamps for every timer. * * @type {object} */ this.timerStartTimestamps = {}; /** * The number of times a timer has run. * * @type {object} */ this.timerRunCount = {}; /** * Total time for all timer runs, ignoring timer resets (but not full resets). * * @type {object} */ this.timerAllRunsTotal = {}; this.initCounters(); /** * An array to keep any values sequentially. * * @type {Array} */ this.array = []; /** * An object to keep any values by key. * * @type {Array} */ this.object = {}; }, /** * Init counters object to have incrementation work with any of its properties without the need to * assign 0 to it first. */ initCounters() { this.counters = typeof Proxy === 'undefined' ? {} : new Proxy({}, { get: (obj, prop) => prop in obj ? obj[prop] : 0 }); }, /** * Start the specified timer. * * @param {string} label */ startTimer(label) { if (this.timerTotal[label] === undefined) { this.timerTotal[label] = 0; } this.timerStartTimestamps[label] = Date.now(); }, /** * Stop the specified timer. * * @param {string} label */ stopTimer(label) { if (this.timerStartTimestamps[label] === undefined) return; const interval = Date.now() - this.timerStartTimestamps[label]; this.timerTotal[label] += interval; delete this.timerStartTimestamps[label]; if (this.timerAllRunsTotal[label] === undefined) { this.timerAllRunsTotal[label] = 0; this.timerRunCount[label] = 0; } this.timerAllRunsTotal[label] += interval; this.timerRunCount[label]++; }, /** * Reset the total time value for the timer. * * @param {string} label */ resetTimer(label) { if (this.timerStartTimestamps[label] !== undefined) { this.stopTimer(label); } delete this.timerTotal[label]; }, /** * Remove all data associated with the timer. * * @param {string} label */ fullResetTimer(label) { this.resetTimer(label); delete this.timerAllRunsTotal[label]; delete this.timerRunCount[label]; }, /** * Log and reset the specified timer. * * @param {string} label */ logAndResetTimer(label) { if (this.timerStartTimestamps[label] !== undefined) { this.stopTimer(label); } if (this.timerTotal[label] !== undefined) { console.debug(`${label}: ${this.timerTotal[label]}`); this.resetTimer(label); } }, /** * Log and reset all timers, as well as counters and other collected values. * * @param {boolean} sort Whether to sort timers and counters alphabetically. */ logAndResetEverything(sort) { const timerLabels = Object.keys(this.timerTotal); if (sort) { timerLabels.sort(); } timerLabels.forEach((label) => { this.logAndResetTimer(label); }); const counterLabels = Object.keys(this.counters); if (sort) { counterLabels.sort(); } counterLabels.forEach((label) => { console.debug(`counter ${label}: ${this.counters[label]}`); }); this.initCounters(); if (this.array.length) { console.debug(`array: `, this.array); this.array = []; } if (Object.keys(this.object).length) { console.debug(`object: `, this.object); this.object = {}; } }, /** * Log the average time one run of the specified timer takes. All runs of the timer are taken into * account unless a [full reset]{@link module:debug.fullResetTimer} has been performed. * * @param {string} label */ averageTimerTime(label) { if (this.timerAllRunsTotal[label] === undefined) { console.error(`No data for timer ${label}`); return; } const average = this.timerAllRunsTotal[label] / this.timerRunCount[label]; console.debug(`${label}: ${average.toFixed(1)} average for ${this.timerRunCount[label]} runs`); }, /** * Increment the specified counter. * * @param {string} label */ incrementCounter(label) { this.counters[label]++; }, }; "
"/** * @module defaultConfig */ export default { /** * Object with the names and texts of the messages required by the script as keys and values. Used * to avoid making additional requests on every script run. Get these messages by running {@link * https://commons.wikimedia.org/wiki/User:Jack_who_built_the_house/convenientDiscussions-generateBasicConfig.js} * in your browser's console while the page of your wiki is open. * * @type {object} * @default {} */ messages: {}, /** * Contributions page wikilink as it appears in IP users' signatures (for example, * `Special:Contributions` for English Wikipedia). * * @type {?string} * @default null */ contribsPage: null, /** * Local timezone offset in minutes. Get by running {@link * https://commons.wikimedia.org/wiki/User:Jack_who_built_the_house/convenientDiscussions-generateBasicConfig.js} * in your browser's console while the page of your wiki is open. Leave `null` if your wiki uses * daylight saving time (summer time). * * @type {?number} * @default null */ localTimezoneOffset: null, /** * Numbers of talk namespaces other than odd namespaces. If not set, the value of * `mw.config.get('wgExtraSignatureNamespaces')` will be used. For example: `[4]` for Project. * * **Warning:** This value is overriden by {@link module:defaultConfig.pageWhitelist}: * `customTalkNamespaces` is used only if `pageWhitelist` is `[]` or `null`. * * Note that this value is used in the script as a "soft" value. I.e., the script can decide * (based on the presence of the "Add section" button, existence of comments on the page and * possibly other factors) that the page is not a talk page after all. Use {@link * module:defaultConfig.pageWhitelist} to indicate pages where the script should work in any * circumstances. (For example, you can specify the entire namespace, e.g., `/^Wikipedia:/`). * * @type {number[]} * @default mw.config.get('wgExtraSignatureNamespaces') */ customTalkNamespaces: mw.config.get('wgExtraSignatureNamespaces'), /** * Pages where the script should run. If `[]`, all pages in the {@link * module:defaultConfig.customTalkNamespaces} namespaces will pass. If you add at least one value, * {@link module:defaultConfig.customTalkNamespaces} will not be used. In this case, you may * specify entire namespaces in this value, e.g., /^Wikipedia:/. The blacklist has priority over * the whitelist. * * @type {RegExp[]} * @default [] */ pageWhitelist: [], /** * Pages where the script shouldn't run. The blacklist has priority over the whitelist. * * @type {RegExp[]} * @default [] */ pageBlacklist: [], /** * @typedef {object} UserNamespacesByGender * @property {string} male * @property {string} female * @property {string} unknown */ /** * If the user namespace uses different aliases based on gender, you may include them here. * Unfortunately, we can't get this using API, see {@link * https://phabricator.wikimedia.org/T204610}. * * Example (if only the female form differs from the standard name): * <pre class="prettyprint source"><code>{ * female: 'Участница', * }</code></pre> * * @type {?UserNamespacesByGender} */ userNamespacesByGender: null, /** * Object that connects active (source) talk page names with their archive pages prefixes and vice * versa: archive page names with their source page names. * * @typedef {object} ArchivePathEntry * @property {string} source Source path. Dynamic parts should be replaced with tokens such as * `$1`, `$2` etc. Regular expressions for these tokens, if any, should be defined in the * `replacements` array. * @property {string} archive Archive prefix. Should use the same tokens as in `source`. * @property {RegExp[]|undefined} replacements Array of replacements for `$1`, `$2` tokens in * `source` and `archive`. Note that the regexp should, if put into the `archive` pattern, * capture only the part that is common for the source page and the archive page<u>s</u>. E.g., * in "Wikipedia:Discussion/Archive/General/2020/07", it should capture "General", but not * "General/2020/07". So, you shouldn't use `/.+/` here and use, for example, `/[^/]+/` instead. */ /** * Collection of archive paths, (sometimes) with correspondent source pages paths. It is used in * multiple purposes: * - to identify pages that will be considered inactive, i.e. no replies can be left on them; * - to suggest to search in the archive if the section/comment by a given fragment is not found * on the page; * - to make diff/thank links work on archive pages. * * Each of the array elements can be an object with the defined structure (see {@link * module:defaultConfig~ArchivePathEntry} for details) or a regexp. In the latter case, if a page * name matches the regexp, it will be considered an archive page, and the name of the source page * for that page will be obtained by removing everything that starts with the pattern in the page * name (i.e., the actually used regexp will end with `.*`). * * The entries are applied in the order of their presence in the array. So, if a page name fits * two patterns, the one closer to the beginning of the array is used. * * Example: * <pre class="prettyprint source"><code>[ * { * source: 'Wikipedia:Discussion/Geography', * archive: 'Wikipedia:Discussion/Geography/Archives/', * }, * { * source: 'Wikipedia:Discussion/$1', * archive: 'Wikipedia:Discussion/Archive/$1/', * replacements: [/[^/]+/], * }, * /\/Archive/, * ]</code></pre> * * * @type {Array.<ArchivePathEntry|RegExp>} * @default [] */ archivePaths: [], /** * Pages that can never have archives on a subpage (a subpage is a page with a subtitle after * "/"). If the section specified in the URL fragment will not be found, an error message will * suggest to search in the archives if the page name doesn't match one of these regexps. * * @type {RegExp[]} * @default [] */ pagesWithoutArchives: [], /** * Fragments that shouldn't trigger the "Section not found" dialog. * * @type {string[]} * @default [] */ idleFragments: [], /** * Character that should directly precede the comment text. Normally, `':'` or `'*'`. In votings, * `'#'` is used automatically. * * @type {string} * @default ':' */ defaultIndentationChar: ':', /** * Whether to put a space between the indentation chars and the comment text. * * @type {boolean} * @default true */ spaceAfterIndentationChars: true, /** * Should a new comment at the first level repeat the previous comment's indentation style * (`'mimic'` mode), or should the script use the default indentation char in {@link * module:defaultConfig.checkForCustomForeignComponents} in all cases (`'unify'` mode). Note that * if the last comment of the section uses `#` as the first indentation character, the script will * use it for the comment independent of this value. * * @type {string} */ indentationCharMode: 'mimic', /** * Signature prefix (the text added before the signature) used by default, including a space at * the beginning if it is needed. * * @type {string} */ defaultSignaturePrefix: ' ', /** * Text that is removed from the end of the comment text and transferred to the beginning of the * signature text when editing a comment. * * `'` is in the end alone so that normal markup in the end of comments doesn't get removed - like * this: * ``` * ''Reply in italics.'' [signature] * ``` * Here, `''` is not a part of the signature. * * End the regexp with `$`. * * @type {RegExp} * @default * /(?:\s+>+)?(?:[·•\-–—―~/→⇒\s]|&amp;mdash;|&amp;ndash;|&amp;rarr;|&amp;middot;|&amp;nbsp;|&amp;#32;|&amp;rlm;)*\(?'*$/ */ signaturePrefixRegexp: /(?:\s+>+)?(?:[·•\-–—―~/→⇒\s]|&mdash;|&ndash;|&rarr;|&middot;|&nbsp;|&#32;|&rlm;)*\(?'*$/, /** * Unchangable text (usually user talk page link) at the end of Mediawiki:Signature (visible text, * not wikitext). Used to detect comments where the user has forgotten the forth tilde. For * example: `/ \(talk\)/`. * * @type {?RegExp} * @default null */ signatureEndingRegexp: null, /** * Convenient Discussions tag according to Special:Tags. Needs to be added manually. Set to `null` * of there is no tag. * * @type {?string} * @default null */ tagName: null, /** * Script code name. Used, for example, for the `source` parameter of the thank request: {@link * https://www.mediawiki.org/wiki/Extension:Thanks#API_documentation}. * * @type {string} * @default 'convenient-discussions' */ scriptCodeName: 'convenient-discussions', /** * Prefix for the script options saved to the MediaWiki server in addition to the standard * `userjs-`. * * @type {string} * @default 'convenientDiscussions' */ optionsPrefix: 'convenientDiscussions', /** * Wikilink to the script's page. Used in the watchlist and, if there is no {@link * module:defaultConfig.tagName tag}, in summary. * * @type {string} * @default 'c:User:JWBTH/CD' */ scriptPageWikilink: 'c:Special:MyLanguage/User:JWBTH/CD', /** * Names of the templates that are analogs of {@link * https://en.wikipedia.org/wiki/Template:Unsigned}, {@link * https://en.wikipedia.org/wiki/Template:Unsigned_IP} **on sites where they are not * substituted**. If they are, don't add them. Please include aliases. * * @type {string[]} * @default <pre class="prettyprint source"><code>[ * 'unsigned', * 'unsignedIP', * 'unsigned2', * 'unsignedIP2', * ]</code></pre> */ unsignedTemplates: [ 'unsigned', 'unsignedIP', 'unsigned2', 'unsignedIP2', ], /** * Name of the class that the unsigned templates set to its container element. * * @type {string} */ unsignedClass: 'autosigned', /** * There are quote template pairs where there is a beginning template and an ending template, like * `{{Quote begin}}{{Quote end}}`. So, this is an array of two arrays of strings: the first one * for beginning templates, the second one for ending templates. * * @type {Array.<Array.<string>>} * @default <pre class="prettyprint source"><code>[ * [], * [], * ]</code></pre> */ pairQuoteTemplates: [ [], [], ], /** * Name of the templates that are analogs of {@link * https://en.wikipedia.org/wiki/Template:Smalldiv}. Used when the whole comment is wrapped in * `<small></small>` (with some exceptions when that could break the layout). * * @type {?string} * @default [] */ smallDivTemplates: [], /** * Names of the templates that are analogs of {@link * https://en.wikipedia.org/wiki/Template:Paragraph_break}. The first string will be used when * posting comments. * * @type {string[]} * @default [] */ paragraphTemplates: [], /** * Character used to trigger user mention (ping) autocomplete. * * @type {string} */ mentionCharacter: '@', /** * There should be a leading space (or other punctuation) before {@link * module:defaultConfig.mentionCharacter the mention character} to trigger autocomplete. * * @type {boolean} */ mentionRequiresLeadingSpace: true, /** * Array of two strings to insert before and after the selection when quote function is activated * (by the toolbar button or Ctrl+Alt+Q / Q). * * @type {string[]} * @default ["> ''", "''\n"] */ quoteFormatting: ["> ''", "''\n"], /** * Blocks with classes listed here wont't be considered legit comment timestamp containers. They * can still be parts of comments; for the way to prevent certain elements from becoming comment * parts, see {@link module:defaultConfig.checkForCustomForeignComponents}. This value can have a * wikitext counterpart (although it may not be necessary), {@link * module:defaultConfig.templatesToExclude}. * * When it comes to the wikitext, all lines containing these classes are ignored. * * @type {string[]} * @default [] */ elementsToExcludeClasses: [], /** * Blocks with templates listed here won't be considered legit comment timestamp containers. All * lines containing these templates are ignored when searching for timestamps in the wikitext. * This value can have a web page counterpart, {@link * module:defaultConfig.elementsToExcludeClasses}. * * @type {string[]} * @default [] */ templatesToExclude: [], /** * All lines containing these patterns will be ignored when searching for comments in the * wikitext. * * @type {RegExp[]} * @default [] */ commentAntipatterns: [], /** * Regexps for strings that should be cut out of comment beginnings (not considered parts of them) * when editing comments. This is in addition to {@link * module:cd~convenientDiscussions.g.BAD_COMMENT_BEGINNINGS}. They begin with `^` and usually end * with ` *\n+` or ` *\n+(?=[*:#])`. They _should_ match a newline character at the end for the * script to work properly. * * Example: 'new RegExp(' ^\\{\\{(?:-|clear)\\}\\} *\\n+')`. * * @type {RegExp[]} * @default [] */ customBadCommentBeginnings: [], /** * Regexps for strings that should be kept in section endings when adding a reply or subsection * (so that this reply or subsection is added _before_ them, not after). Should begin with at * least one `\n`. The default value will keep HTML comments placed after an empty line in section * endings. * * @type {RegExp[]} * @default <pre class="prettyprint source"><code>[ * /\n{2,}(?:&lt;!--[^]*?--&gt;\s*)+$/, * ]</code></pre> */ keepInSectionEnding: [ /\n{2,}(?:<!--[^]*?-->\s*)+$/, ], /** * How many displayed (not wikitext) characters to go back from a timestamp looking for an author * link. * * @type {number} * @default 100 */ signatureScanLimit: 100, /** * Classes of elements that should be ignored when extracting headline text. * * @type {string[]} * @default [] */ foreignElementsInHeadlinesClasses: [], /** * Selectors of floating elements. This is needed to display the comment's underlay and overlay * correctly. You can also add the `cd-floating` class to such elements. You can also add the * `cd-ignoreFloating` class to floating elements that never intersect comments but end up in * `convenientDiscussions.g.specialElements.floating` to help performance. * * @type {string[]} * @default [] */ customFloatingElementSelectors: [], /** * Names of the closed discussion templates. They can be single templates like {@link * https://en.wikipedia.org/wiki/Template:Closed} or pair templates like {@link * https://ru.wikipedia.org/wiki/Template:Закрыто} / {@link * https://ru.wikipedia.org/wiki/Template:Конец_закрытой_секции}. Include the closing part of the * pair templates in the second array, and the rest of the templates in the first array. These * templates are ignored when searching for a place to insert a comment in the wikitext. * * @type {Array.<Array.<string>>} * @default <pre class="prettyprint source"><code>[ * [], * [], * ]</code></pre> */ closedDiscussionTemplates: [ [], [], ], /** * Classes of elements that are wrapped around closed discussions. * * @type {string[]} * @default [] */ closedDiscussionClasses: [], /** * Classes of elements that shouldn't be highlighted. * * @type {string[]} * @default [] */ customUnhighlightableElementClasses: [], /** * Selectors of links (buttons) that are used to add topics on this wiki. * * @type {string[]} * @default [] */ customAddTopicLinkSelectors: [], /** * Default collection of insert buttons displayed under the comment input in comment forms. * * @type {Array.<string|Array>} * @default [] */ defaultInsertButtons: [], /** * How many characters should a comment have to be considered long. Comments having more * characters will need confirmation to be sent. * * @type {number} * @default 10000 */ longCommentThreshold: 10000, /** * Lower limit of the number of bytes to be added to the page to deem an edit a new comment. * * @type {number} * @default 50 */ bytesToDeemComment: 50, /** * Upper limit of the length of a comment to put its whole content in the edit summary. * * @type {number} * @default 50 */ summaryCommentTextLengthLimit: 50, /** * Regular expression matching the names of the pages where an sending empty comment shouldn't be * confirmed (e.g., voting pages). * * @type {?RegExp} * @default null */ noConfirmPostEmptyCommentPageRegexp: null, /** * String to be put into a regular expression for matching indentation characters. * * @type {?string} * @default '\\n*([:*#]*) *' */ indentationCharsPattern: '\\n*([:*#]*) *', /** * Strings present in edit summaries of undo/revert edits. Used to detect edits that shouldn't be * considered comments on log pages (watchlist, contributions, history). Displayed text, not * wikitext. Take from MediaWiki:Undo-summary, MediaWiki:Revertpage. * * @type {string[]} * @default [] */ undoTexts: [], /** * Object specifying messages to be displayed when the user enters text that matches a pattern. * * @typedef {object} Reaction * @property {RegExp} pattern Pattern to match. * @property {string} message Message displayed to the user. * @property {string} name Latin letters, digits, `-`. * @property {string} [type='notice'] For example, `notice`. * @property {Function} [checkFunc] If this function returns false, no message is displayed. */ /** * Custom {@link module:defaultConfig~Reaction reactions}. * * @type {Reaction[]} * @default [] */ customTextReactions: [], /** * @typedef {object} Module * @property {string} name Name of the module. * @property {Function} [checkFunc] Function that must return true for the module to be loaded (if * it is present). */ /** * Load these modules on comment form creation. See {@link module:defaultConfig~Module} for the * object structure. If `checkFunc` is set, the module will be loaded if the condition is met. * * @type {Module[]} * @default [] */ customCommentFormModules: [], /** * Function that transforms the automatically generated summary text. * * @type {?Function} * @kind function * @param {string} summary * @returns {string} * @default null */ transformSummary: null, /** * Function that makes custom alterations to the comment code before it is processed and * submitted. See also {@link module:defaultConfig.postTransformCode}. * * @type {?Function} * @kind function * @param {string} code * @param {CommentForm} commentForm * @returns {string} * @default null */ preTransformCode: null, /** * Function that makes custom alterations to the comment code after it is processed and before it * is submitted. (An example would be adding a closer template to all the closures by a user with * the closer flag which is a requirement in Russian Wikipedia.) See also {@link * module:defaultConfig.preTransformCode}. * * @type {?Function} * @kind function * @param {string} code * @param {CommentForm} commentForm * @returns {string} * @default null */ postTransformCode: null, /** * Function that returns `true` for nodes that are not parts of comments and should terminate the * comment part collecting. These rules often need correspoding rules in {@link * module:defaultConfig.customBadCommentBeginnings}. * * The second parameter is a "context", i.e., a collection of classes, functions, and other * properties that perform the tasks we need in the current context (window or worker). * * @type {?Function} * @kind function * @param {Node} node * @param {object} context * @returns {boolean} * @default null */ checkForCustomForeignComponents: null, /** * Function that returns `true` if new topics are placed on top of the page. * * @type {?Function} * @kind function * @param {string} title * @param {string} code * @returns {boolean} * @default null */ areNewTopicsOnTop: null, /** * Function that returns the code to insert in the place of a section moved to another page. The * string normally ends with `\n`. If `null`, the section is just removed from the page. * * @type {?Function} * @kind function * @param {string} targetPageWikilink * @param {string} signature * @param {string} [timestamp] * @returns {string} * @default <pre class="prettyprint source"> * <code>function (targetPageWikilink, signature, timestamp) { * return ( * convenientDiscussions.s('move-sourcepagecode', targetPageWikilink, signature, timestamp) + * '\n' * ); * } * </code></pre> */ getMoveSourcePageCode: function (targetPageWikilink, signature, timestamp) { return ( convenientDiscussions.s('move-sourcepagecode', targetPageWikilink, signature, timestamp) + '\n' ); }, /** * Function that returns the code to insert in the beginning of the section moved from another * page *or* an array of two strings to insert in the beginning and ending of the section * respectively. The strings normally end with `\n`. If `null`, no code will be added. * * @type {?Function} * @kind function * @param {string} targetPageWikilink * @param {string} signature * @returns {string|Array<string, string>} * @default <pre class="prettyprint source"><code>function (targetPageWikilink, signature) { * return convenientDiscussions.s('move-targetpagecode', targetPageWikilink, signature) + '\n'; * }</code></pre> */ getMoveTargetPageCode: function (targetPageWikilink, signature) { return convenientDiscussions.s('move-targetpagecode', targetPageWikilink, signature) + '\n'; }, /** * Code that creates an anchor on the page. * * @type {Function} * @kind function * @param {string} anchor * @returns {string} * @default <pre class="prettyprint source"><code>function (anchor) { * return '&lt;span id="' + anchor + '>&lt;/span>'; * }</code></pre> */ getAnchorCode: function (anchor) { return '<span id="' + anchor + '></span>'; }, }; "
"/** * To-be-properties of the {@link module:cd~convenientDiscussions.g} object. These are those of them * that are known from the beginning and can be safely imported in a web worker (that doesn't have * access to the window scope). We assume that there is no point to make these properties subject to * change by site administrators although that may be disputable. Some of them are extensible in the * config (such as `UNHIGHLIGHTABLE_ELEMENT_CLASSES`). * * @module staticGlobals */ /** * Properties of the `convenientDiscussions.g` object (incomplete list). Static (i.e., known from * the beginning) ones are declared in {@link module:staticGlobals}. * * @namespace g * @memberof module:cd~convenientDiscussions */ export default { /** * A replacement for {@link * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Unicode_Property_Escapes * unicode property escapes} while they are not supported in major browsers. {@link * https://github.com/slevithan/xregexp} can be used also. * * @type {string} * @memberof module:cd~convenientDiscussions.g */ LETTER_PATTERN: 'A-Za-z\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u037F\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u052F\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0620-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0800-\\u0815\\u081A\\u0824\\u0828\\u0840-\\u0858\\u08A0-\\u08B4\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971-\\u0980\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0AF9\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C39\\u0C3D\\u0C58-\\u0C5A\\u0C60\\u0C61\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0CF1\\u0CF2\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D3A\\u0D3D\\u0D4E\\u0D5F-\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC-\\u0EDF\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8C\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10C7\\u10CD\\u10D0-\\u10FA\\u10FC-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F5\\u13F8-\\u13FD\\u1401-\\u166C\\u166F-\\u167F\\u1681-\\u169A\\u16A0-\\u16EA\\u16F1-\\u16F8\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u18B0-\\u18F5\\u1900-\\u191E\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19AB\\u19B0-\\u19C9\\u1A00-\\u1A16\\u1A20-\\u1A54\\u1AA7\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1BBA-\\u1BE5\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1CE9-\\u1CEC\\u1CEE-\\u1CF1\\u1CF5\\u1CF6\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u209C\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2183\\u2184\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2CE4\\u2CEB-\\u2CEE\\u2CF2\\u2CF3\\u2D00-\\u2D25\\u2D27\\u2D2D\\u2D30-\\u2D67\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005\\u3006\\u3031-\\u3035\\u303B\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31BA\\u31F0-\\u31FF\\u3400-\\u4DB5\\u4E00-\\u9FD5\\uA000-\\uA48C\\uA4D0-\\uA4FD\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA66E\\uA67F-\\uA69D\\uA6A0-\\uA6E5\\uA717-\\uA71F\\uA722-\\uA788\\uA78B-\\uA7AD\\uA7B0-\\uA7B7\\uA7F7-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA8F2-\\uA8F7\\uA8FB\\uA8FD\\uA90A-\\uA925\\uA930-\\uA946\\uA960-\\uA97C\\uA984-\\uA9B2\\uA9CF\\uA9E0-\\uA9E4\\uA9E6-\\uA9EF\\uA9FA-\\uA9FE\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAA60-\\uAA76\\uAA7A\\uAA7E-\\uAAAF\\uAAB1\\uAAB5\\uAAB6\\uAAB9-\\uAABD\\uAAC0\\uAAC2\\uAADB-\\uAADD\\uAAE0-\\uAAEA\\uAAF2-\\uAAF4\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uAB30-\\uAB5A\\uAB5C-\\uAB65\\uAB70-\\uABE2\\uAC00-\\uD7A3\\uD7B0-\\uD7C6\\uD7CB-\\uD7FB\\uF900-\\uFA6D\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC', /** * Underlay color for focused (hovered) comments. * * @type {string} * @memberof module:cd~convenientDiscussions.g */ COMMENT_FOCUSED_COLOR: '#eaf3ff', /** * Underlay color for target comments. * * @type {string} * @memberof module:cd~convenientDiscussions.g */ COMMENT_TARGET_COLOR: '#ffedb8', /** * Underlay color for new comments. * * @type {string} * @memberof module:cd~convenientDiscussions.g */ COMMENT_NEW_COLOR: '#e8ffd1', /** * Underlay color for own comments. * * @type {string} * @memberof module:cd~convenientDiscussions.g */ COMMENT_OWN_COLOR: '#f7ebff', /** * Underlay color for deleted comments. * * @type {string} * @memberof module:cd~convenientDiscussions.g */ COMMENT_DELETED_COLOR: '#fee7e6', /** * Size of the underlay's side margin in pixels. * * @type {string} * @memberof module:cd~convenientDiscussions.g */ COMMENT_UNDERLAY_SIDE_MARGIN: 5, /** * How long a comment should be considered new and have a corresponding background on newly loaded * pages. In minutes. * * @type {number} * @memberof module:cd~convenientDiscussions.g */ HIGHLIGHT_NEW_COMMENTS_INTERVAL: 15, /** * Number of seconds between checks for new comments when the tab is not hidden. * * @type {number} * @memberof module:cd~convenientDiscussions.g */ UPDATE_CHECK_INTERVAL: 15, /** * Number of seconds between new comments checks when the tab is hidden. * * @type {number} * @memberof module:cd~convenientDiscussions.g */ BACKGROUND_UPDATE_CHECK_INTERVAL: 60, /** * Number of seconds in a day. * * @type {number} * @memberof module:cd~convenientDiscussions.g */ SECONDS_IN_A_DAY: 60 * 60 * 24, /** * Number of milliseconds in a minute. * * @type {number} * @memberof module:cd~convenientDiscussions.g */ MILLISECONDS_IN_A_MINUTE: 1000 * 60, /** * Popular elements that don't have the `display: inline` property in the default browser styles. * * @type {string[]} * @memberof module:cd~convenientDiscussions.g */ POPULAR_NOT_INLINE_ELEMENTS: [ 'BLOCKQUOTE', 'DD', 'DIV', 'DL', 'FORM', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'HR', 'INPUT', 'LI', 'LINK', 'OL', 'P', 'PRE', 'STYLE', 'TABLE', 'TBODY', 'TR', 'TH', 'TD', 'UL' ], /** * Popular elements that do have the `display: inline` property in the default browser styles. * * @type {string[]} * @memberof module:cd~convenientDiscussions.g */ POPULAR_INLINE_ELEMENTS: [ 'A', 'ABBR', 'B', 'BIG', 'BR', 'CENTER', 'CITE', 'CODE', 'DEL', 'EM', 'FONT', 'I', 'IMG', 'INS', 'KBD', 'Q', 'S', 'SAMP', 'SMALL', 'SPAN', 'STRIKE', 'STRONG', 'SUB', 'SUP', 'TT', 'U', 'VAR' ], /** * Classes of elements that shouldn't be highlighted. Only MediaWiki-assigned classes go here. * Wiki-specific classes go in the configuration. * * @type {string[]} * @memberof module:cd~convenientDiscussions.g */ UNHIGHLIGHTABLE_ELEMENT_CLASSES: [ 'mw-empty-elt', 'tleft', 'tright', 'floatleft', 'floatright', ], /** * Regexps for strings that should be cut out of comment beginnings (not considered parts of * them). * * @type {RegExp[]} * @memberof module:cd~convenientDiscussions.g */ BAD_COMMENT_BEGINNINGS: [ /^<!--[^]*?--> *\n+/, /^(?:----+|<hr>) *\n+/, /^\{\|.*?\|\} *\n+(?=[*:#])/, ], /** * Selectors of floating elements. This is needed to display the comment's underlay and overlay * correctly. * * @type {string[]} * @memberof module:cd~convenientDiscussions.g */ FLOATING_ELEMENT_SELECTORS: [ '.cd-floating', '.tright', '.floatright', '.tleft', '.floatleft', '*[style*="float:right"]', '*[style*="float: right"]', '*[style*="float:left"]', '*[style*="float: left"]', ], /** * Auxiliary property to keep the sign code: "\~\~\~\~". If written as plain text, it gets * transformed into the edit author's signature when saved. Note that the minifier translates * "~\~\\~" and "'\~\~' + '\~'" into "\~\~\~". * * @type {string} * @memberof module:cd~convenientDiscussions.g */ SIGN_CODE: '~~'.concat('~~'), }; "
"/** * Utilities that go to the {@link module:cd~convenientDiscussions.util convenientDiscussions.util} * object. Some such utilities are defined in other modules (for example, {@link * module:cd~convenientDiscussions.util.parseCommentAnchor cd.util.parseCommentAnchor()}). * * @module globalUtil */ import cd from './cd'; import { isLoadingOverlayOn } from './boot'; /** * Properties of the `convenientDiscussions.util` object. Some of them are declared in {@link * module:globalUtil}. * * @namespace util * @memberof module:cd~convenientDiscussions */ export default { /** * @typedef {object} Callbacks * @property {Function} * */ /** * Generate a `<span>` (or other element) suitable as an argument for various methods for * displaying HTML. Optionally, attach callback functions and `target="_blank"` attribute to links * with the provided class names. * * @param {string|JQuery} htmlOrJquery * @param {object} [options={}] * @param {Callbacks} [options.callbacks] * @param {string} [options.tagName='span'] * @param {boolean} [options.targetBlank] * @returns {JQuery} * @memberof module:cd~convenientDiscussions.util */ wrap(htmlOrJquery, options = {}) { const $wrapper = $(htmlOrJquery instanceof $ ? htmlOrJquery : $.parseHTML(htmlOrJquery)) .wrapAll(`<${options.tagName || 'span'}>`) .parent(); if (options) { if (options.callbacks) { Object.keys(options.callbacks).forEach((className) => { const $linkWrapper = $wrapper.find(`.${className}`); if (!$linkWrapper.find('a').length) { $linkWrapper.wrapInner('<a>'); } $linkWrapper.find('a').on('click', options.callbacks[className]); }); } if (options.targetBlank) { $wrapper.find('a[href]').attr('target', '_blank'); } } return $wrapper; }, /** * Combine the section headline, summary text and, optionally, summary postfix to create an edit * summary. * * @param {object} options * @param {string} options.text Summary text. Can be clipped if there is not enough space. * @param {string} [options.optionalText] Optional text added to the end of the summary if there is * enough space. Ignored if there is not. * @param {string} [options.section] Section name. * @param {boolean} [options.addPostfix=true] If to add cd.g.SUMMARY_POSTFIX to the summary. * @returns {string} * @memberof module:cd~convenientDiscussions.util */ buildEditSummary(options) { if (options.addPostfix === undefined) { options.addPostfix = true; } let text = (options.section ? `/* ${options.section} */ ` : '') + options.text.trim(); let wasOptionalTextAdded; if (options.optionalText) { let projectedText = text + options.optionalText; if (cd.config.transformSummary) { projectedText = cd.config.transformSummary(projectedText); } if (projectedText.length <= cd.g.SUMMARY_LENGTH_LIMIT) { text = projectedText; wasOptionalTextAdded = true; } } if (!wasOptionalTextAdded) { if (cd.config.transformSummary) { text = cd.config.transformSummary(text); } if (text.length > cd.g.SUMMARY_LENGTH_LIMIT) { text = text.slice(0, cd.g.SUMMARY_LENGTH_LIMIT - 1) + '…'; } } if (options.addPostfix) { text += cd.g.SUMMARY_POSTFIX; } return text; }, /** * Is there any kind of a page overlay present, like OOUI modal overlay or CD loading overlay. * This runs very frequently, so we use the fastest way. * * @returns {boolean} * @memberof module:cd~convenientDiscussions.util */ isPageOverlayOn() { return ( document.body.classList.contains('oo-ui-windowManager-modal-active') || isLoadingOverlayOn() ); }, /** * Wrap the response to the "compare" API request in a table. * * @param {string} body * @returns {string} * @memberof module:cd~convenientDiscussions.util */ wrapDiffBody(body) { return ( '<table class="diff">' + '<col class="diff-marker"><col class="diff-content">' + '<col class="diff-marker"><col class="diff-content">' + body + '</table>' ); } }; "
"/** * Main module. * * @module app */ import cd from './cd'; import commentLinks from './commentLinks'; import configUrls from './../../config/urls.json'; import debug from './debug'; import defaultConfig from './defaultConfig'; import g from './staticGlobals'; import processPage from './processPage'; import util from './globalUtil'; import { defined, isProbablyTalkPage, mergeRegexps, underlinesToSpaces, unique } from './util'; import { formatDate, parseCommentAnchor } from './timestamp'; import { getUserInfo } from './apiWrappers'; import { initTalkPageCss, isLoadingOverlayOn, removeLoadingOverlay, setLoadingOverlay, } from './boot'; import { loadData } from './siteData'; import { setVisits } from './options'; let config; let strings; if (IS_SNIPPET) { config = require(`../../config/${CONFIG_FILE_NAME}`).default; cd.i18n = {}; cd.i18n.en = require('../../i18n/en.json'); cd.i18n[LANG_CODE] = require(`../../i18n/${LANG_CODE}.json`); } /** * Get a language string. * * @param {string} name String name. * @param {...*} [params] String parameters (substituted strings, also {@link * module:userRegistry~User User} objects for the use in {{gender:}}). * @param {object} [options] * @param {boolean} [options.plain] Should the message be returned in a plain, not substituted, * form. * @param {boolean} [options.parse] Should the message be returned in a parsed form. Wikilinks * are replaced with HTML tags, the code is sanitized. Use this for strings that have their raw * HTML inserted into the page. * @returns {?string} * @memberof module:cd~convenientDiscussions */ function s(name, ...params) { if (!name) { return null; } const fullName = `convenient-discussions-${name}`; if (!cd.g.QQX_MODE && typeof mw.messages.get(fullName) === 'string') { let options = {}; let lastParam = params[params.length - 1]; if ( typeof lastParam === 'object' && // `mw.user`-like object to provide to {{gender:}} !lastParam.options ) { options = lastParam; params.splice(params.length - 1); } const message = mw.message(fullName, ...params); if (options.plain) { return message.plain(); } else if (options.parse) { return message.parse(); } else { return message.text(); } } else { const paramsString = params.length ? `: ${params.join(', ')}` : ''; return `(${fullName}${paramsString})`; } } /** * Get a language string in the "parse" format. Wikilinks are replaced with HTML tags, the code is * sanitized. Use this for strings that have their raw HTML inserted into the page. * * * @param {string} name String name. * @param {...*} [params] String parameters (substituted strings, also {@link * module:userRegistry~User User} objects for the use in {{gender:}}). * @returns {?string} * @memberof module:cd~convenientDiscussions */ function sParse(...args) { return s(...args, { parse: true }); } /** * Get a language string in the "plain" format, with no substitutions replace. * * @param {string} name String name. * @returns {?string} * @memberof module:cd~convenientDiscussions */ function sPlain(name) { return s(name, { plain: true }); } /** * A foolproof method to access MediaWiki messages intended to be used instead of `mw.msg` to * eliminate any possibility of an XSS injection. By a programmer's mistake some `mw.msg` value * could be inserted into a page in a raw HTML form. To prevent it, this function should be used, so * if the message contains an injection (for example, brought from Translatewiki or inserted by a * user who doesn't have the `editsitejs` right, but does have the `editinterface` right), the * function would sanitize the value. * * @param {string} name String name. * @param {...*} [params] String parameters (substituted strings, also {@link * module:userRegistry~User User} objects for the use in {{gender:}}). * @param {object} [options] */ function mws(...args) { return mw.message(...args).parse(); } /** * When searching for a comment after clicking "OK" in a "Comment not found" dialog, add comment * links to the titles. * * @private */ function addCommentLinksToSpecialSearch() { const [, commentAnchor] = location.search.match(/[?&]cdcomment=([^&]+)(?:&|$)/) || []; if (commentAnchor) { mw.loader.using('mediawiki.api').then( async () => { await loadData(); $('.mw-search-result-heading').each((i, el) => { const $a = $('<a>') .attr( 'href', ( $(el) .find('a') .first() .attr('href') + '#' + commentAnchor ) ) .text(cd.s('deadanchor-search-gotocomment')); const $start = $('<span>').text(cd.mws('parentheses-start')); const $end = $('<span>').text(cd.mws('parentheses-end')); const $span = $('<span>') .addClass("cd-searchCommentLink") .append($start, $a, $end); $(el).append(' ', $span.clone()); }); }, console.error ); } } /** * Add a footer link to enable/disable CD. * * @param {boolean} enable * @private */ function addFooterLink(enable) { if (cd.g.CURRENT_NAMESPACE_NUMBER === -1) return; const uri = new mw.Uri(); uri.query.cdtalkpage = enable ? '1' : '0'; const $li = $('<li>').attr('id', enable ? 'footer-places-enablecd' : 'footer-places-disablecd'); $('<a>') .attr('href', uri.toString()) .addClass('noprint') .text(cd.s(enable ? 'footer-runcd' : 'footer-dontruncd')) .appendTo($li); $('#footer-places').append($li); } /** * Set the `cd.strings` object values. * * @private */ function setStrings() { // Strings that should be displayed in the site language, not the user language. const contentStrings = [ 'es-', 'cf-autocomplete-commentlinktext', 'move-', ]; if (!IS_SNIPPET) { require('../../dist/convenientDiscussions-i18n/en.js'); } cd.strings = {}; Object.keys(cd.i18n.en).forEach((name) => { const relevantLang = contentStrings.some((contentStringName) => ( name === contentStringName || contentStringName.endsWith('-') && name.startsWith(contentStringName) )) ? mw.config.get('wgContentLanguage') : mw.config.get('wgUserLanguage'); cd.strings[name] = cd.i18n[relevantLang]?.[name] || cd.i18n.en[name]; }); Object.keys(cd.strings).forEach((name) => { mw.messages.set(`convenient-discussions-${name}`, cd.strings[name]); }); } /** * Function executed after the config and localization strings are ready. * * @private */ function go() { cd.debug.startTimer('start'); /** * Script configuration. The default configuration is at {@link module:defaultConfig}. * * @name config * @type {object} * @memberof module:cd~convenientDiscussions */ cd.config = Object.assign(defaultConfig, cd.config); setStrings(); cd.g.SETTINGS_OPTION_NAME = `userjs-convenientDiscussions-settings`; cd.g.LOCAL_SETTINGS_OPTION_NAME = `userjs-${cd.config.optionsPrefix}-localSettings`; cd.g.VISITS_OPTION_NAME = `userjs-${cd.config.optionsPrefix}-visits`; // For historical reasons, ru.wikipedia.org has 'watchedTopics'. const wsonEnding = location.hostname === 'ru.wikipedia.org' ? 'watchedTopics' : 'watchedSections'; cd.g.WATCHED_SECTIONS_OPTION_NAME = `userjs-${cd.config.optionsPrefix}-${wsonEnding}`; cd.g.IS_DIFF_PAGE = mw.config.get('wgIsArticle') && /[?&]diff=[^&]/.test(location.search); cd.g.CURRENT_PAGE_NAME = underlinesToSpaces(mw.config.get('wgPageName')); cd.g.CURRENT_PAGE_TITLE = underlinesToSpaces(mw.config.get('wgTitle')); cd.g.CURRENT_NAMESPACE_NUMBER = mw.config.get('wgNamespaceNumber'); cd.g.CURRENT_USER_NAME = mw.config.get('wgUserName'); cd.g.PAGE_WHITELIST_REGEXP = mergeRegexps(cd.config.pageWhitelist); cd.g.PAGE_BLACKLIST_REGEXP = mergeRegexps(cd.config.pageBlacklist); cd.g.SITE_DIR = document.body.classList.contains('sitedir-rtl') ? 'rtl' : 'ltr'; cd.g.$content = $('#mw-content-text'); const enabledInQuery = /[?&]cdtalkpage=(1|true|yes|y)(?=&|$)/.test(location.search); // Process the page as a talk page if (mw.config.get('wgIsArticle') && !mw.config.get('wgIsRedirect')) { if ( !/[?&]cdtalkpage=(0|false|no|n)(?=&|$)/.test(location.search) && (!cd.g.$content.find('.cd-notTalkPage').length || enabledInQuery) && ( isProbablyTalkPage(cd.g.CURRENT_PAGE_NAME, cd.g.CURRENT_NAMESPACE_NUMBER) || $('#ca-addsection').length || // .cd-talkPage is used as a last resort way to make CD parse the page, as opposed to using // the list of supported namespaces and page white/black list in the configuration. With // this method, there won't be "comment" links for edits on pages that list revisions such // as the watchlist. cd.g.$content.find('.cd-talkPage').length || enabledInQuery ) ) { /** * Is the page processed for the first time after it was loaded (i.e., not reloaded using the * script's refresh functionality). * * @type {CommentForm|undefined} * @memberof module:cd~convenientDiscussions.g */ cd.g.isFirstRun = true; setLoadingOverlay(); cd.debug.stopTimer('start'); cd.debug.startTimer('loading data'); // Make some requests in advance if the API module is ready in order not to make 2 requests // sequentially. We don't make a userinfo request, because if there is more than one tab in // the background, this request is made and the execution stops at mw.loader.using, which // results in overriding the renewed visits setting of one tab by another tab (the visits are // loaded by one tab, then another tab, then written by one tab, then by another tab). let dataRequest; if (mw.loader.getState('mediawiki.api') === 'ready') { dataRequest = loadData(); } let modulesRequest = mw.loader.using([ 'jquery.color', 'jquery.client', 'mediawiki.Title', 'mediawiki.api', 'mediawiki.cookie', 'mediawiki.jqueryMsg', 'mediawiki.notification', 'mediawiki.user', 'mediawiki.util', 'mediawiki.widgets.visibleLengthLimit', 'oojs', 'oojs-ui', 'oojs-ui.styles.icons-alerts', 'oojs-ui.styles.icons-content', 'oojs-ui.styles.icons-editing-core', 'oojs-ui.styles.icons-interactions', 'oojs-ui.styles.icons-movement', 'user.options', ]); Promise.all([modulesRequest, dataRequest].filter(defined)).then( () => { try { processPage({ dataRequest }); } catch (e) { mw.notify(cd.s('error-processpage'), { type: 'error' }); removeLoadingOverlay(); console.error(e); } }, (e) => { mw.notify(cd.s('error-loaddata'), { type: 'error' }); removeLoadingOverlay(); console.error(e); } ); // https://phabricator.wikimedia.org/T68598 "mw.loader state of module stuck at "loading" if // request was aborted" setTimeout(() => { if (isLoadingOverlayOn()) { removeLoadingOverlay(); console.warn('The loading overlay stays for more than 10 seconds; removing it.'); } }, 10000); /* Additions of CSS cause a reflow which delays operations dependent on rendering, so we run it now, not after the requests are fulfilled, to save time. The overall order is like this: 1. Make API requests (above). 2. Run operations dependent on rendering, such as window.getComputedStyle(). 3. Run operations that initiate a reflow, such as adding CSS. Thanks to the fact that the API requests are already running, we don't lose time. */ cd.g.REGULAR_LINE_HEIGHT = parseFloat( window.getComputedStyle(cd.g.$content.get(0)).lineHeight ); initTalkPageCss(); require('../less/global.less'); require('../less/Comment.less'); require('../less/CommentForm.less'); require('../less/Section.less'); require('../less/commentLayers.less'); require('../less/navPanel.less'); require('../less/skin.less'); require('../less/talkPage.less'); addFooterLink(false); } else { addFooterLink(true); } } // Process the page as a log page if ( ['Watchlist', 'Contributions', 'Recentchanges'] .includes(mw.config.get('wgCanonicalSpecialPageName')) || ( mw.config.get('wgAction') === 'history' && isProbablyTalkPage(cd.g.CURRENT_PAGE_NAME, cd.g.CURRENT_NAMESPACE_NUMBER) ) || cd.g.IS_DIFF_PAGE ) { // Make some requests in advance if the API module is ready in order not to make 2 requests // sequentially. let dataRequest; if (mw.loader.getState('mediawiki.api') === 'ready') { dataRequest = loadData(); if (!cd.g.IS_DIFF_PAGE) { getUserInfo(true).catch((e) => { console.warn(e); }); } } mw.loader.using([ 'user.options', 'mediawiki.Title', 'mediawiki.api', 'mediawiki.jqueryMsg', 'mediawiki.util', 'mediawiki.user', 'oojs', 'oojs-ui', 'oojs-ui.styles.icons-interactions', 'oojs-ui.styles.icons-editing-list', 'oojs-ui.styles.icons-alerts', ]).then( () => { commentLinks({ dataRequest }); // See the comment above: "Additions of CSS...". require('../less/global.less'); require('../less/logPages.less'); }, (e) => { mw.notify(cd.s('error-loaddata'), { type: 'error' }); console.error(e); } ); } if (mw.config.get('wgCanonicalSpecialPageName') === 'Search') { addCommentLinksToSpecialSearch(); } } /** * Load and execute the configuration script if available. * * @returns {Promise} * @private */ function getConfig() { return new Promise((resolve, reject) => { if (configUrls[location.hostname]) { const rejectWithMsg = (e) => { reject(['Convenient Discussions can\'t run: couldn\'t load the configuration.', e]); }; const getScript = (url, emptyResponseCallback) => { mw.loader.getScript(url).then( (data) => { if (data === '') { emptyResponseCallback(); } else { resolve(); } }, rejectWithMsg ); }; const url = IS_DEV ? configUrls[location.hostname].replace('.js', '-dev.js') : configUrls[location.hostname]; getScript(url, () => { if (IS_DEV) { getScript(configUrls[location.hostname], () => { rejectWithMsg('Empty response.'); }); } else { rejectWithMsg('Empty response.'); } }); } else { resolve(); } }); } /** * Load and add localization strings. * * @returns {Promise} * @private */ function getStrings() { const requests = [mw.config.get('wgUserLanguage'), mw.config.get('wgContentLanguage')] .filter(unique) .filter((lang) => lang !== 'en') .map((lang) => mw.loader.getScript(`https://commons.wikimedia.org/w/index.php?title=User:Jack_who_built_the_house/convenientDiscussions-i18n/${lang}.js&action=raw&ctype=text/javascript`)); // We assume it's OK to fall back to English if the translation is unavailable for any reason. return Promise.all(requests).catch(() => {}); } /** * The main script function. * * @fires launched * @private */ async function app() { // Doesn't work in mobile version, isn't needed on Structured Discussions pages. if (/(^|\.)m\./.test(location.hostname) || $('.flow-board-page').length) return; if (cd.isRunning) { console.warn('One instance of Convenient Discussions is already running.'); return; } /** * Is the script running. * * @name isRunning * @type {boolean} * @memberof module:cd~convenientDiscussions */ cd.isRunning = true; if (IS_SNIPPET) { cd.config = Object.assign(defaultConfig, config); cd.strings = strings; } /** * @see module:debug * @name debug * @type {object} * @memberof module:cd~convenientDiscussions */ cd.debug = debug; cd.g = g; cd.s = s; cd.sParse = sParse; cd.sPlain = sPlain; cd.mws = mws; cd.util = util; /* Some utilities that we believe should be global for external use */ /** * @see module:timestamp.parseCommentAnchor * @function parseCommentAnchor * @memberof module:cd~convenientDiscussions.util */ cd.util.parseCommentAnchor = parseCommentAnchor; /** * @see module:timestamp.formatDate * @function formatDate * @memberof module:cd~convenientDiscussions.util */ cd.util.formatDate = formatDate; /** * @see module:options.setVisits * @function setVisits * @memberof module:cd~convenientDiscussions.util */ cd.util.setVisits = setVisits; cd.debug.init(); cd.debug.startTimer('total time'); cd.debug.startTimer('loading config and strings'); /** * The script has launched. * * @event launched * @type {module:cd~convenientDiscussions} */ mw.hook('convenientDiscussions.launched').fire(cd); try { await Promise.all([ !cd.config && getConfig(), // cd.getStringsPromise may be set in the configuration file. !cd.i18n && (cd.getStringsPromise || getStrings()), ].filter(defined)); } catch (e) { console.error(e); return; } cd.debug.stopTimer('loading config and strings'); go(); } $(app); "
sourceRoot""