Mô đun:Protection banner

Tài liệu mô đun

Mô-đun này tạo biểu ngữ bảo vệ và biểu tượng ổ khóa được đặt ở đầu trang được khóa.

Sử dụng

Hầu hết người dùng sẽ không cần sử dụng mô-đun này trực tiếp. Để thêm các bản mẫu khóa vào các trang, bạn có thể sử dụng bản mẫu {{Khóa}} hoặc bạn có thể thấy thuận tiện hơn khi sử dụng một trong các bản mẫu khóa cụ thể hơn trong bảng bên dưới.

Từ wikitext

{{#invoke:Protection banner|main| 1        = lý do| small    = yes/no| action   = hành động| date     = ngày khóa| user     = tên thành viên| section  = tên đề mục trang thảo luận| category = no}}

Cú pháp #invoke có thể được sử dụng để tạo các bản mẫu khóa cụ thể hơn {{ khóa}}. Ví dụ: có thể tạo một bản mẫu khóa luôn hiển thị biểu tượng ổ khóa bằng cách sử dụng mã {{#invoke:Protection banner|main|small=yes}}. Các trang gọi bản mẫu này vẫn có thể sử dụng các đối số khác, như action. Tuy nhiên, điều này chỉ hoạt động sâu một cấp; một trang gọi một bản mẫu gọi một bản mẫu khác chứa mã ở trên sẽ không thể tự động sử dụng các tham số như action.

Note: Bạn không còn có thể chỉ định hết hạn, vì nó được tự động truy xuất trong mọi trường hợp.

Từ Lua

Đầu tiên, gọi mô đun:

<syntaxhightlight lang="lua">local mProtectionBanner = require('Module:Protection banner')</syntaxhightlight>

Sau đó, bạn có thể tạo các biểu ngữ bảo vệ bằng cách sử dụng chức năng _main.

<syntaxhightlight lang="lua">mProtectionBanner._main(args, cfg, titleObj)</syntaxhightlight>

args là một bảng các đối số để truyền cho mô-đun. Để biết các khóa và giá trị có thể cho bảng này, hãy xem phần tham số. Biến cfgtitleObj chỉ dành cho thử nghiệm; cfg chỉ định một bảng cấu hình tùy chỉnh để sử dụng thay vì Module:Protection banner/config, and titleObj chỉ định một đối tượng mw.title để sử dụng thay vì tiêu đề hiện tại. args, cfgtitleObj đều là tùy chọn.

Tham số

Tất cả tham số đều là tùy chọn:

  • 1 – Lý do mà trang được khóa. Nếu được đặt, đây phải là một trong các giá trị được liệt kê trong bảng lý do.
  • small – Nếu đặt là "yes", "y", "1", hoặc "true", một biểu tượng ổ khóa được tạo ra thay vì biểu ngữ khóa đầy đủ.
  • action – Các hành động khóa. Phải là một trong số các dạng sau đây: "edit" (đối với khóa thông thường), "move" (đối với khóa di chuyển). Giá trị mặc định là "edit".
  • date – Ngày khóa. Đây phải là đầu vào hợp lệ cho tham số thứ hai của #time parser function. Đối số này có hiệu lực vì những lý do sử dụng tham số PROTECTIONDATE trong cấu hình của chúng. Đối số này chỉ có hiệu lực cho các lý do "office" và "reset".
  • user – Tên thành viên của thành viên để tạo liên kết cho. Kể từ tháng 7 năm 2014, điều này chỉ có hiệu lực khi lý do "usertalk" được chỉ định.
  • section – Tên phần của trang thảo luận của trang được khóa nơi diễn ra cuộc thảo luận. Tham số này hầu hết đều hoạt động, nhưng không phải tất cả, các giá trị của reason.
  • category – Không thêm thể loại nếu tham số này được đặt thành "no", "n", "0", hoặc "false".

Lý do

Bảng sau đây chứa các lý do có sẵn, cộng với các hành động có sẵn.

Lý doHành độngMiêu tả
blpeditĐối với các trang được khóa để tuân thủ quy định về Tiểu sử người đang sống
disputeeditĐối với các trang được khóa do tranh chấp sửa đổi
dmcaeditĐối với các trang được khóa bởi Wikimedia Foundation do yêu cầu gỡ xuống từ en:Digital Millennium Copyright Act
ecpeditĐối với các bài viết trong lĩnh vực chủ đề được ủy quyền bởi ArbCom hoặc đáp ứng tiêu chí sử dụng của cộng đồng
mainpageeditĐối với các trang được khóa để được hiển thị trên Trang chính
officeeditĐối với các trang được khóa bởi Wikimedia Foundation
reseteditĐối với các trang được khóa bởi Wikimedia Foundation và "đặt lại" đến phiên bản thường
sockeditĐối với các trang được khóa do rối phá hoại
templateeditĐối với các bản mẫu và mô-đun Lua nguy hiểm cao
usertalkeditĐối với các trang được bảo vệ chống lại các sửa đổi gây rối bởi thành viên cụ thể
vandalismeditĐối với các trang được khóa để ngăn chặn phá hoại
disputemoveĐối với các trang được khóa chống lại việc di chuyển trang do tranh chấp về tiêu đề trang
vandalismmoveĐối với các trang được khóa chống lại phá hoại trang di chuyển

Lỗi

Dưới đây là danh sách một số lỗi phổ biến mà mô-đun này có thể tạo ra và cách khắc phục chúng.

Sai ngày khóa trang

Lỗi: sai ngày khóa ("abc")

Lỗi này được tạo ra nếu bạn cung cấp một tham số |date= mà giá trị của nó không được công nhận là ngày hợp lệ bởi chức năng phân tích cú pháp #time. Nếu nghi ngờ, bạn chỉ có thể sử dụng một ngày ở định dạng "dd Month YYYY", ví dụ "4 tháng 5 2024". Để xem đầy đủ các đầu vào hợp lệ, xem #time documentation (chỉ tham số đầu tiên, chuỗi định dạng, có thể được chỉ định).

Sai hành động

Lỗi: sai hành động ("abc")

Lỗi này được tạo ra nếu bạn chỉ định một hành động khóa không hợp lệ. Chỉ có ba hành động hợp lệ: edit (mặc định, cho khóa thường) và move (cho khóa di chuyển). Điều này chỉ có thể nếu bạn đang sử dụng một bản mẫu hỗ trợ chỉ định thủ công hành động khóa, chẳng hạn như {{Khóa}} hoặc nếu bạn đang sử dụng trực tiếp #invoke. Nếu đây không phải là trường hợp, vui lòng để lại tin nhắn trên Thảo luận Mô đun:Protection banner.

Lý do không thể chứa ký tự cây đứng

Lỗi: lý do không thể chứa ký tự cây đứng ("|")

Lỗi này được tạo ra nếu bạn chỉ định một lý do sử dụng tham số |1= bao gồm ký tự cây đứng ("|"). Vui lòng kiểm tra xem bạn có đang nhập sai bản mẫu {{!}} vào tham số này không. Ký tự cây đứng không được phép vì mô-đun sử dụng nó trong nội bộ. Có thể xem danh sách các lý do hợp lệ trong phần lý do.

Một số lỗi khác

Nếu bạn thấy một lỗi khác ngoài các lỗi ở trên, đó có thể là lỗi trong mô-đun hoặc lỗi trong cấu hình. Xin vui lòng gửi một tin nhắn về nó tại Thảo luận Mô đun:Protection banner.

Thông tin kỹ thuật

Mô-đun này sử dụng dữ liệu cấu hình từ Module:Protection banner/config. Hầu hết các hành vi của mô-đun có thể được cấu hình ở đó, làm cho nó dễ dàng di chuyển qua các wiki khác nhau và các ngôn ngữ khác nhau.

Các trường hợp thử nghiệm chung cho mô-đun có thể được tìm thấy tại Module:Protection banner/testcases, và các trường hợp thử nghiệm cụ thể cho cấu hình của enwiki có thể được tìm thấy tại Module:Protection banner/config/testcases.

Báo cáo lỗi và yêu cầu tính năng nên được thực hiện trên the module's talk page.

-- This module implements {{pp-meta}} and its daughter templates such as-- {{pp-dispute}}, {{pp-vandalism}} and {{pp-sock}}.-- Initialise necessary modules.require('strict')local makeFileLink = require('Mô đun:File link')._mainlocal effectiveProtectionLevel = require('Mô đun:Effective protection level')._mainlocal effectiveProtectionExpiry = require('Mô đun:Effective protection expiry')._mainlocal yesno = require('Mô đun:Yesno')-- Lazily initialise modules and objects we don't always need.local getArgs, makeMessageBox, lang-- Set constants.local CONFIG_MODULE = 'Mô đun:Protection banner/config'---------------------------------------------------------------------------------- Helper functions--------------------------------------------------------------------------------local function makeCategoryLink(cat, sort)if cat thenreturn string.format('[[%s:%s|%s]]',mw.site.namespaces[14].name,cat,sort)endend-- Validation function for the expiry and the protection datelocal function validateDate(dateString, dateType)if not lang thenlang = mw.language.getContentLanguage()endlocal success, result = pcall(lang.formatDate, lang, 'U', dateString)if success thenresult = tonumber(result)if result thenreturn resultendenderror(string.format('sai %s: %s',dateType,tostring(dateString)), 4)endlocal function makeFullUrl(page, query, display)return string.format('[%s %s]',tostring(mw.uri.fullUrl(page, query)),display)end-- Given a directed graph formatted as node -> table of direct successors,-- get a table of all nodes reachable from a given node (though always-- including the given node).local function getReachableNodes(graph, start)local toWalk, retval = {[start] = true}, {}while true do-- Can't use pairs() since we're adding and removing things as we're iteratinglocal k = next(toWalk) -- This always gets the "first" keyif k == nil thenreturn retvalendtoWalk[k] = nilretval[k] = truefor _,v in ipairs(graph[k]) doif not retval[v] thentoWalk[v] = trueendendendend---------------------------------------------------------------------------------- Protection class--------------------------------------------------------------------------------local Protection = {}Protection.__index = ProtectionProtection.supportedActions = {edit = true,move = true,autoreview = true,upload = true}Protection.bannerConfigFields = {'text','explanation','tooltip','alt','link','image'}function Protection.new(args, cfg, title)local obj = {}obj._cfg = cfgobj.title = title or mw.title.getCurrentTitle()-- Set actionif not args.action thenobj.action = 'edit'elseif Protection.supportedActions[args.action] thenobj.action = args.actionelseerror(string.format('sai hành động: %s',tostring(args.action)), 3)end-- Set levelobj.level = args.demolevel or effectiveProtectionLevel(obj.action, obj.title)if not obj.level or (obj.action == 'move' and obj.level == 'autoconfirmed') then-- Users need to be autoconfirmed to move pages anyway, so treat-- semi-move-protected pages as unprotected.obj.level = '*'end-- Set expirylocal effectiveExpiry = effectiveProtectionExpiry(obj.action, obj.title)if effectiveExpiry == 'infinity' thenobj.expiry = 'indef'elseif effectiveExpiry ~= 'unknown' thenobj.expiry = validateDate(effectiveExpiry, 'expiry date')end-- Set reasonif args[1] thenobj.reason = mw.ustring.lower(args[1])if obj.reason:find('|') thenerror('lý do không thể chứa ký tự cây đứng ("|")', 3)endend-- Set protection dateif args.date thenobj.protectionDate = validateDate(args.date, 'protection date')end-- Set banner configdoobj.bannerConfig = {}local configTables = {}if cfg.banners[obj.action] thenconfigTables[#configTables + 1] = cfg.banners[obj.action][obj.reason]endif cfg.defaultBanners[obj.action] thenconfigTables[#configTables + 1] = cfg.defaultBanners[obj.action][obj.level]configTables[#configTables + 1] = cfg.defaultBanners[obj.action].defaultendconfigTables[#configTables + 1] = cfg.masterBannerfor i, field in ipairs(Protection.bannerConfigFields) dofor j, t in ipairs(configTables) doif t[field] thenobj.bannerConfig[field] = t[field]breakendendendendreturn setmetatable(obj, Protection)endfunction Protection:isProtected()return self.level ~= '*'endfunction Protection:isTemporary()return type(self.expiry) == 'number'endfunction Protection:makeProtectionCategory()local cfg = self._cfglocal title = self.title-- Exit if the page is not protected.if not self:isProtected() thenreturn ''end-- Get the expiry key fragment.local expiryFragmentif self.expiry == 'indef' thenexpiryFragment = self.expiryelseif type(self.expiry) == 'number' thenexpiryFragment = 'temp'end-- Get the namespace key fragment.local namespaceFragment = cfg.categoryNamespaceKeys[title.namespace]if not namespaceFragment and title.namespace % 2 == 1 thennamespaceFragment = 'talk'end -- Define the order that key fragments are tested in. This is done with an-- array of tables containing the value to be tested, along with its-- position in the cfg.protectionCategories table.local order = {{val = expiryFragment,    keypos = 1},{val = namespaceFragment, keypos = 2},{val = self.reason,       keypos = 3},{val = self.level,        keypos = 4},{val = self.action,       keypos = 5}}--[[-- The old protection templates used an ad-hoc protection category system,-- with some templates prioritising namespaces in their categories, and-- others prioritising the protection reason. To emulate this in this module-- we use the config table cfg.reasonsWithNamespacePriority to set the-- reasons for which namespaces have priority over protection reason.-- If we are dealing with one of those reasons, move the namespace table to-- the end of the order table, i.e. give it highest priority. If not, the-- reason should have highest priority, so move that to the end of the table-- instead.--]]table.insert(order, table.remove(order, self.reason and cfg.reasonsWithNamespacePriority[self.reason] and 2 or 3)) --[[-- Define the attempt order. Inactive subtables (subtables with nil "value"-- fields) are moved to the end, where they will later be given the key-- "all". This is to cut down on the number of table lookups in-- cfg.protectionCategories, which grows exponentially with the number of-- non-nil keys. We keep track of the number of active subtables with the-- noActive parameter.--]]local noActive, attemptOrderdolocal active, inactive = {}, {}for i, t in ipairs(order) doif t.val thenactive[#active + 1] = telseinactive[#inactive + 1] = tendendnoActive = #activeattemptOrder = activefor i, t in ipairs(inactive) doattemptOrder[#attemptOrder + 1] = tendend --[[-- Check increasingly generic key combinations until we find a match. If a-- specific category exists for the combination of key fragments we are-- given, that match will be found first. If not, we keep trying different-- key fragment combinations until we match using the key-- "all-all-all-all-all".---- To generate the keys, we index the key subtables using a binary matrix-- with indexes i and j. j is only calculated up to the number of active-- subtables. For example, if there were three active subtables, the matrix-- would look like this, with 0 corresponding to the key fragment "all", and-- 1 corresponding to other key fragments.-- --   j 1  2  3-- i  -- 1   1  1  1-- 2   0  1  1-- 3   1  0  1-- 4   0  0  1-- 5   1  1  0-- 6   0  1  0-- 7   1  0  0-- 8   0  0  0-- -- Values of j higher than the number of active subtables are set-- to the string "all".---- A key for cfg.protectionCategories is constructed for each value of i.-- The position of the value in the key is determined by the keypos field in-- each subtable.--]]local cats = cfg.protectionCategoriesfor i = 1, 2^noActive dolocal key = {}for j, t in ipairs(attemptOrder) doif j > noActive thenkey[t.keypos] = 'all'elselocal quotient = i / 2 ^ (j - 1)quotient = math.ceil(quotient)if quotient % 2 == 1 thenkey[t.keypos] = t.valelsekey[t.keypos] = 'all'endendendkey = table.concat(key, '|')local attempt = cats[key]if attempt thenreturn makeCategoryLink(attempt, title.text)endendreturn ''endfunction Protection:isIncorrect()local expiry = self.expiryreturn not self:isProtected()or type(expiry) == 'number' and expiry < os.time()endfunction Protection:isTemplateProtectedNonTemplate()local action, namespace = self.action, self.title.namespacereturn self.level == 'templateeditor'and ((action ~= 'edit' and action ~= 'move')or (namespace ~= 10 and namespace ~= 828))endfunction Protection:makeCategoryLinks()local msg = self._cfg.msglocal ret = { self:makeProtectionCategory() }if self:isIncorrect() thenret[#ret + 1] = makeCategoryLink(msg['tracking-category-incorrect'],self.title.text)endif self:isTemplateProtectedNonTemplate() thenret[#ret + 1] = makeCategoryLink(msg['tracking-category-template'],self.title.text)endreturn table.concat(ret)end---------------------------------------------------------------------------------- Blurb class--------------------------------------------------------------------------------local Blurb = {}Blurb.__index = BlurbBlurb.bannerTextFields = {text = true,explanation = true,tooltip = true,alt = true,link = true}function Blurb.new(protectionObj, args, cfg)return setmetatable({_cfg = cfg,_protectionObj = protectionObj,_args = args}, Blurb)end-- Private methods --function Blurb:_formatDate(num)-- Formats a Unix timestamp into dd Month, YYYY format.lang = lang or mw.language.getContentLanguage()local success, date = pcall(lang.formatDate,lang,self._cfg.msg['expiry-date-format'] or 'F j Y','@' .. tostring(num))if success thenreturn dateendendfunction Blurb:_getExpandedMessage(msgKey)return self:_substituteParameters(self._cfg.msg[msgKey])endfunction Blurb:_substituteParameters(msg)if not self._params thenlocal parameterFuncs = {}parameterFuncs.CURRENTVERSION     = self._makeCurrentVersionParameterparameterFuncs.EDITREQUEST        = self._makeEditRequestParameterparameterFuncs.EXPIRY             = self._makeExpiryParameterparameterFuncs.EXPLANATIONBLURB   = self._makeExplanationBlurbParameterparameterFuncs.IMAGELINK          = self._makeImageLinkParameterparameterFuncs.INTROBLURB         = self._makeIntroBlurbParameterparameterFuncs.INTROFRAGMENT      = self._makeIntroFragmentParameterparameterFuncs.PAGETYPE           = self._makePagetypeParameterparameterFuncs.PROTECTIONBLURB    = self._makeProtectionBlurbParameterparameterFuncs.PROTECTIONDATE     = self._makeProtectionDateParameterparameterFuncs.PROTECTIONLEVEL    = self._makeProtectionLevelParameterparameterFuncs.PROTECTIONLOG      = self._makeProtectionLogParameterparameterFuncs.TALKPAGE           = self._makeTalkPageParameterparameterFuncs.TOOLTIPBLURB       = self._makeTooltipBlurbParameterparameterFuncs.TOOLTIPFRAGMENT    = self._makeTooltipFragmentParameterparameterFuncs.VANDAL             = self._makeVandalTemplateParameterself._params = setmetatable({}, {__index = function (t, k)local paramif parameterFuncs[k] thenparam = parameterFuncs[k](self)endparam = param or ''t[k] = paramreturn paramend})endmsg = msg:gsub('${(%u+)}', self._params)return msgendfunction Blurb:_makeCurrentVersionParameter()-- A link to the page history or the move log, depending on the kind of-- protection.local pagename = self._protectionObj.title.prefixedTextif self._protectionObj.action == 'move' then-- We need the move log link.return makeFullUrl('Special:Log',{type = 'move', page = pagename},self:_getExpandedMessage('current-version-move-display'))else-- We need the history link.return makeFullUrl(pagename,{action = 'history'},self:_getExpandedMessage('current-version-edit-display'))endendfunction Blurb:_makeEditRequestParameter()local mEditRequest = require('Module:Submit an edit request')local action = self._protectionObj.actionlocal level = self._protectionObj.level-- Get the edit request type.local requestTypeif action == 'edit' thenif level == 'autoconfirmed' thenrequestType = 'semi'elseif level == 'extendedconfirmed' thenrequestType = 'extended'elseif level == 'templateeditor' thenrequestType = 'template'endendrequestType = requestType or 'full'-- Get the display value.local display = self:_getExpandedMessage('edit-request-display')return mEditRequest._link{type = requestType, display = display}endfunction Blurb:_makeExpiryParameter()local expiry = self._protectionObj.expiryif type(expiry) == 'number' thenreturn self:_formatDate(expiry)elsereturn expiryendendfunction Blurb:_makeExplanationBlurbParameter()-- Cover special cases first.if self._protectionObj.title.namespace == 8 then-- MediaWiki namespacereturn self:_getExpandedMessage('explanation-blurb-nounprotect')end-- Get explanation blurb table keyslocal action = self._protectionObj.actionlocal level = self._protectionObj.levellocal talkKey = self._protectionObj.title.isTalkPage and 'talk' or 'subject'-- Find the message in the explanation blurb table and substitute any-- parameters.local explanations = self._cfg.explanationBlurbslocal msgif explanations[action][level] and explanations[action][level][talkKey] thenmsg = explanations[action][level][talkKey]elseif explanations[action][level] and explanations[action][level].default thenmsg = explanations[action][level].defaultelseif explanations[action].default and explanations[action].default[talkKey] thenmsg = explanations[action].default[talkKey]elseif explanations[action].default and explanations[action].default.default thenmsg = explanations[action].default.defaultelseerror(string.format('không thể tìm thấy lời giải thích cho hành động "%s", cấp độ "%s" và key thảo luận "%s"',action,level,talkKey), 8)endreturn self:_substituteParameters(msg)endfunction Blurb:_makeImageLinkParameter()local imageLinks = self._cfg.imageLinkslocal action = self._protectionObj.actionlocal level = self._protectionObj.levellocal msgif imageLinks[action][level] thenmsg = imageLinks[action][level]elseif imageLinks[action].default thenmsg = imageLinks[action].defaultelsemsg = imageLinks.edit.defaultendreturn self:_substituteParameters(msg)endfunction Blurb:_makeIntroBlurbParameter()if self._protectionObj:isTemporary() thenreturn self:_getExpandedMessage('intro-blurb-expiry')elsereturn self:_getExpandedMessage('intro-blurb-noexpiry')endendfunction Blurb:_makeIntroFragmentParameter()if self._protectionObj:isTemporary() thenreturn self:_getExpandedMessage('intro-fragment-expiry')elsereturn self:_getExpandedMessage('intro-fragment-noexpiry')endendfunction Blurb:_makePagetypeParameter()local pagetypes = self._cfg.pagetypesreturn pagetypes[self._protectionObj.title.namespace]or pagetypes.defaultor error('không có kiểu trang mặc định được định nghĩa', 8)endfunction Blurb:_makeProtectionBlurbParameter()local protectionBlurbs = self._cfg.protectionBlurbslocal action = self._protectionObj.actionlocal level = self._protectionObj.levellocal msgif protectionBlurbs[action][level] thenmsg = protectionBlurbs[action][level]elseif protectionBlurbs[action].default thenmsg = protectionBlurbs[action].defaultelseif protectionBlurbs.edit.default thenmsg = protectionBlurbs.edit.defaultelseerror('không có blurb khóa được định nghĩa cho protectionBlurbs.edit.default', 8)endreturn self:_substituteParameters(msg)endfunction Blurb:_makeProtectionDateParameter()local protectionDate = self._protectionObj.protectionDateif type(protectionDate) == 'number' thenreturn self:_formatDate(protectionDate)elsereturn protectionDateendendfunction Blurb:_makeProtectionLevelParameter()local protectionLevels = self._cfg.protectionLevelslocal action = self._protectionObj.actionlocal level = self._protectionObj.levellocal msgif protectionLevels[action][level] thenmsg = protectionLevels[action][level]elseif protectionLevels[action].default thenmsg = protectionLevels[action].defaultelseif protectionLevels.edit.default thenmsg = protectionLevels.edit.defaultelseerror('không có cấp độ khóa được định nghĩa cho protectionLevels.edit.default', 8)endreturn self:_substituteParameters(msg)endfunction Blurb:_makeProtectionLogParameter()local pagename = self._protectionObj.title.prefixedTextif self._protectionObj.action == 'autoreview' then-- We need the pending changes log.return makeFullUrl('Đặc biệt:Nhật trình',{type = 'stable', page = pagename},self:_getExpandedMessage('pc-log-display'))else-- We need the protection log.return makeFullUrl('Đặc biệt:Nhật trình',{type = 'protect', page = pagename},self:_getExpandedMessage('protection-log-display'))endendfunction Blurb:_makeTalkPageParameter()return string.format('[[%s:%s#%s|%s]]',mw.site.namespaces[self._protectionObj.title.namespace].talk.name,self._protectionObj.title.text,self._args.section or 'top',self:_getExpandedMessage('talk-page-link-display'))endfunction Blurb:_makeTooltipBlurbParameter()if self._protectionObj:isTemporary() thenreturn self:_getExpandedMessage('tooltip-blurb-expiry')elsereturn self:_getExpandedMessage('tooltip-blurb-noexpiry')endendfunction Blurb:_makeTooltipFragmentParameter()if self._protectionObj:isTemporary() thenreturn self:_getExpandedMessage('tooltip-fragment-expiry')elsereturn self:_getExpandedMessage('tooltip-fragment-noexpiry')endendfunction Blurb:_makeVandalTemplateParameter()return require('Mô đun:Vandal-m')._main{self._args.user or self._protectionObj.title.baseText}end-- Public methods --function Blurb:makeBannerText(key)-- Validate input.if not key or not Blurb.bannerTextFields[key] thenerror(string.format('"%s" không phải là trường cấu hình biểu ngữ hợp lệ',tostring(key)), 2)end-- Generate the text.local msg = self._protectionObj.bannerConfig[key]if type(msg) == 'string' thenreturn self:_substituteParameters(msg)elseif type(msg) == 'function' thenmsg = msg(self._protectionObj, self._args)if type(msg) ~= 'string' thenerror(string.format('đầu ra xấu từ chức năng cấu hình banner với key "%s"'.. ' (chuỗi thiếu, có %s)',tostring(key),type(msg)), 4)endreturn self:_substituteParameters(msg)endend---------------------------------------------------------------------------------- BannerTemplate class--------------------------------------------------------------------------------local BannerTemplate = {}BannerTemplate.__index = BannerTemplatefunction BannerTemplate.new(protectionObj, cfg)local obj = {}obj._cfg = cfg-- Set the image filename.local imageFilename = protectionObj.bannerConfig.imageif imageFilename thenobj._imageFilename = imageFilenameelse-- If an image filename isn't specified explicitly in the banner config,-- generate it from the protection status and the namespace.local action = protectionObj.actionlocal level = protectionObj.levellocal namespace = protectionObj.title.namespacelocal reason = protectionObj.reason-- Deal with special cases first.if (namespace == 10or namespace == 828or reason and obj._cfg.indefImageReasons[reason])and action == 'edit'and level == 'sysop'and not protectionObj:isTemporary()then-- Fully protected modules and templates get the special red "indef"-- padlock.obj._imageFilename = obj._cfg.msg['image-filename-indef']else-- Deal with regular protection types.local images = obj._cfg.imagesif images[action] thenif images[action][level] thenobj._imageFilename = images[action][level]elseif images[action].default thenobj._imageFilename = images[action].defaultendendendendreturn setmetatable(obj, BannerTemplate)endfunction BannerTemplate:renderImage()local filename = self._imageFilenameor self._cfg.msg['image-filename-default']or 'Transparent.gif'return makeFileLink{file = filename,size = (self.imageWidth or 20) .. 'px',alt = self._imageAlt,link = self._imageLink,caption = self.imageCaption}end---------------------------------------------------------------------------------- Banner class--------------------------------------------------------------------------------local Banner = setmetatable({}, BannerTemplate)Banner.__index = Bannerfunction Banner.new(protectionObj, blurbObj, cfg)local obj = BannerTemplate.new(protectionObj, cfg) -- This doesn't need the blurb.obj.imageWidth = 40obj.imageCaption = blurbObj:makeBannerText('alt') -- Large banners use the alt text for the tooltip.obj._reasonText = blurbObj:makeBannerText('text')obj._explanationText = blurbObj:makeBannerText('explanation')obj._page = protectionObj.title.prefixedText -- Only makes a difference in testing.return setmetatable(obj, Banner)endfunction Banner:__tostring()-- Renders the banner.makeMessageBox = makeMessageBox or require('Module:Message box').mainlocal reasonText = self._reasonText or error('không có đặt văn bản lý do', 2)local explanationText = self._explanationTextlocal mbargs = {page = self._page,type = 'protection',image = self:renderImage(),text = string.format("'''%s'''%s",reasonText,explanationText and '<br />' .. explanationText or '')}return makeMessageBox('mbox', mbargs)end---------------------------------------------------------------------------------- Padlock class--------------------------------------------------------------------------------local Padlock = setmetatable({}, BannerTemplate)Padlock.__index = Padlockfunction Padlock.new(protectionObj, blurbObj, cfg)local obj = BannerTemplate.new(protectionObj, cfg) -- This doesn't need the blurb.obj.imageWidth = 20obj.imageCaption = blurbObj:makeBannerText('tooltip')obj._imageAlt = blurbObj:makeBannerText('alt')obj._imageLink = blurbObj:makeBannerText('link')obj._indicatorName = cfg.padlockIndicatorNames[protectionObj.action]or cfg.padlockIndicatorNames.defaultor 'pp-default'return setmetatable(obj, Padlock)endfunction Padlock:__tostring()local frame = mw.getCurrentFrame()-- The nowiki tag helps prevent whitespace at the top of articles.return frame:extensionTag{name = 'nowiki'} .. frame:extensionTag{name = 'indicator',args = {name = self._indicatorName},content = self:renderImage()}end---------------------------------------------------------------------------------- Exports--------------------------------------------------------------------------------local p = {}function p._exportClasses()-- This is used for testing purposes.return {Protection = Protection,Blurb = Blurb,BannerTemplate = BannerTemplate,Banner = Banner,Padlock = Padlock,}endfunction p._main(args, cfg, title)args = args or {}cfg = cfg or require(CONFIG_MODULE)local protectionObj = Protection.new(args, cfg, title)local ret = {}-- If a page's edit protection is equally or more restrictive than its-- protection from some other action, then don't bother displaying anything-- for the other action (except categories).if protectionObj.action == 'edit' orargs.demolevel ornot getReachableNodes(cfg.hierarchy,protectionObj.level)[effectiveProtectionLevel('edit', protectionObj.title)]then-- Initialise the blurb objectlocal blurbObj = Blurb.new(protectionObj, args, cfg)-- Render the bannerif protectionObj:isProtected() thenret[#ret + 1] = tostring((yesno(args.small) and Padlock or Banner).new(protectionObj, blurbObj, cfg))endend-- Render the categoriesif yesno(args.category) ~= false thenret[#ret + 1] = protectionObj:makeCategoryLinks()endreturn table.concat(ret)endfunction p.main(frame, cfg)cfg = cfg or require(CONFIG_MODULE)-- Find default args, if any.local parent = frame.getParent and frame:getParent()local defaultArgs = parent and cfg.wrappers[parent:getTitle():gsub('/sandbox$', '')]-- Find user args, and use the parent frame if we are being called from a-- wrapper template.getArgs = getArgs or require('Mô đun:Arguments').getArgslocal userArgs = getArgs(frame, {parentOnly = defaultArgs,frameOnly = not defaultArgs})-- Build the args table. User-specified args overwrite default args.local args = {}for k, v in pairs(defaultArgs or {}) doargs[k] = vendfor k, v in pairs(userArgs) doargs[k] = vendreturn p._main(args, cfg)endreturn p