Open main menu
Home
Random
Donate
Recent changes
Special pages
Community portal
Preferences
About Stockhub
Disclaimers
Search
User menu
Talk
Contributions
Create account
Log in
Editing
Module:Signpost
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
local INDEX_MODULE = 'Module:Signpost/index' local lang = mw.language.getContentLanguage() local libraryUtil = require('libraryUtil') local checkType = libraryUtil.checkType local checkTypeForNamedArg = libraryUtil.checkTypeForNamedArg -------------------------------------------------------------------------------- -- Article class -------------------------------------------------------------------------------- local Article = {} Article.__index = Article Article.rowMethods = { page = 'getPage', fullpage = 'getFullPage', date = 'getDate', title = 'getTitle', subpage = 'getSubpage', } function Article.new(data) local self = setmetatable({}, Article) self.data = data self.matchedTags = {} return self end function Article:getSortKey() return self.data.sortKey end function Article:getPage() return self.data.page end function Article:getDate() return self.data.date end function Article:getTitle() return self.data.title end function Article:getSubpage() return self.data.subpage end function Article:getAuthors() return self.data.authors end function Article:getFragment() local fragment = self:getMatchedTags()[1] if fragment then return mw.uri.anchorEncode(fragment) end end function Article:getFullPage() local page = self:getPage() local fragment = self:getFragment() if fragment then return page .. '#' .. fragment else return page end end function Article:addMatchedTag(tag) table.insert(self.matchedTags, tag) end function Article:getMatchedTags() table.sort(self.matchedTags) return self.matchedTags end function Article:hasAllTags(t) local tags = self.data.tags for i, testTag in ipairs(t) do local hasTag = false for j, tag in ipairs(tags) do if tag == testTag then hasTag = true end end if not hasTag then return false end end return true end function Article:makeRowArgs() local methods = self.rowMethods local args = setmetatable({}, { __index = function (t, key) local method = methods[key] if method then return self[method](self) else error(string.format( "'%s' is not a valid parameter name", key ), 2) end end }) return args end function Article:renderTemplate(template, frame) frame = frame or mw.getCurrentFrame() local args = {} for key, method in pairs(self.rowMethods) do args[key] = self[method](self) end return frame:expandTemplate{ title = template, args = args } end function Article:renderFormat(format) local args = self:makeRowArgs(articleObj) local ret = format:gsub('(%${(%a+)})', function (match, key) return args[key] or match end) return ret end -------------------------------------------------------------------------------- -- List class -------------------------------------------------------------------------------- local List = {} List.__index = List function List.new(options) checkType('List.new', 1, options, 'table') checkTypeForNamedArg('List.new', 'args', options.args, 'table', true) local self = setmetatable({}, List) self.index = options.index or mw.loadData(INDEX_MODULE) self.frame = options.frame or mw.getCurrentFrame() local args = options.args or {} -- Set output formats if not options.suppressFormatErrors and args.rowtemplate and args.rowformat then error("you cannot use both the 'rowtemplate' and the 'rowformat' arguments", 2) elseif not options.suppressFormatErrors and not args.rowtemplate and not args.rowformat then error("you must use either the 'rowtemplate' or the 'rowformat' argument", 2) else self.rowtemplate = args.rowtemplate self.rowformat = args.rowformat end if args.rowseparator == 'newline' then self.rowseparator = '\n' else self.rowseparator = args.rowseparator end self.noarticles = args.noarticles -- Get article objects, filtered by page, date and tag, and sort them. if args.page then self.articles = { self:getPageArticle(args.page) } elseif args.date then self.articles = self:getDateArticles(args.date) else self.articles = self:getTagArticles(args.tags, args.tagmatch) if not self.articles then self.articles = self:getAllArticles() end self:filterArticlesByDate(args.startdate, args.enddate) self:filterArticlesByAuthor(args.author) end self:sortArticles(args.sortdir, args.sortfield) if (args.limit and tonumber(args.limit)) or (args.start and tonumber(args.start)) then self:limitArticleCount(tonumber(args.start), tonumber(args.limit)) end return self end -- Static methods function List.normalizeDate(date) if not date then return nil end return lang:formatDate('Y-m-d', date) end -- Normal methods function List:parseTagString(s) local ret = {} -- Remove whitespace and punctuation for i, tag in ipairs(mw.text.split(s, ',')) do tag = mw.ustring.gsub(tag, '[%s%p]', '') if tag ~= '' then tag = mw.ustring.lower(tag) table.insert(ret, tag) end end -- Resolve aliases for i, tag in ipairs(ret) do ret[i] = self.index.aliases[tag] or tag end -- Remove duplicates local function removeDuplicates(t) local vals, ret = {}, {} for i, val in ipairs(t) do vals[val] = true end for val in pairs(vals) do table.insert(ret, val) end table.sort(ret) return ret end ret = removeDuplicates(ret) return ret end function List:getPageArticle(page) local data = self.index.pages[page] if data then return Article.new(data) end end function List:getDateArticles(date) date = self.normalizeDate(date) local dates = self.index.dates[date] local ret = {} if dates then for i, data in ipairs(dates) do ret[i] = Article.new(data) end end return ret end function List:getTagArticles(s, tagMatch) if not s then return nil end local tagIndex = self.index.tags local ret, pages = {}, {} local tags = self:parseTagString(s) for i, tag in ipairs(tags) do local dataArray = tagIndex[tag] if dataArray then for i, data in ipairs(dataArray) do local obj = Article.new(data) -- Make sure we only have one object per page. if pages[obj:getPage()] then obj = pages[obj:getPage()] else pages[obj:getPage()] = obj end -- Record which tag we matched. obj:addMatchedTag(tag) end end end for page, obj in pairs(pages) do if not tagMatch or tagMatch == 'any' or tagMatch == 'all' and obj:hasAllTags(tags) then table.insert(ret, obj) end end return ret end function List:getAllArticles() local ret = {} for i, data in ipairs(self.index.list) do ret[i] = Article.new(data) end return ret end function List:getArticleCount() return #self.articles end function List:filterArticlesByDate(startDate, endDate) startDate = self.normalizeDate(startDate) or '2005-01-01' endDate = self.normalizeDate(endDate) or lang:formatDate('Y-m-d') local ret = {} for i, article in ipairs(self.articles) do local date = article:getDate() if startDate <= date and date <= endDate then table.insert(ret, article) end end self.articles = ret end function List:filterArticlesByAuthor(targetAuthor) if not targetAuthor then return end local ret = {} for i, article in ipairs(self.articles) do for j, author in ipairs(article:getAuthors()) do if author == targetAuthor then table.insert(ret, article) end end end self.articles = ret end function List:sortArticles(direction, field) local accessor if not field or field == 'date' then accessor = function (article) return article:getSortKey() end elseif field == 'page' then accessor = function (article) return article:getPage() end elseif field == 'title' then accessor = function (article) return article:getTitle() end else error(string.format("'%s' is not a valid sort field", field), 2) end local sortFunc if not direction or direction == 'ascending' then sortFunc = function (a, b) return accessor(a) < accessor(b) end elseif direction == 'descending' then sortFunc = function (a, b) return accessor(a) > accessor(b) end else error(string.format("'%s' is not a valid sort direction", direction), 2) end table.sort(self.articles, sortFunc) end function List:limitArticleCount(start, limit) local ret = {} for i, article in ipairs(self.articles) do if limit and #ret >= limit then break end if not start or i > start then table.insert(ret, article) end end self.articles = ret end function List:renderRow(articleObj) if self.rowtemplate then return articleObj:renderTemplate(self.rowtemplate, self.frame) elseif self.rowformat then return articleObj:renderFormat(self.rowformat) else error('neither rowtemplate nor rowformat were specified') end end function List:__tostring() local ret = {} for i, obj in ipairs(self.articles) do table.insert(ret, self:renderRow(obj)) end if #ret < 1 then return self.noarticles or '<span style="font-color: red;">' .. 'No articles found for the arguments specified</span>' else return table.concat(ret, self.rowseparator) end end -------------------------------------------------------------------------------- -- Exports -------------------------------------------------------------------------------- local p = {} local function makeInvokeFunc(func) return function (frame, index) local args = require('Module:Arguments').getArgs(frame, { parentOnly = true }) return func(args, index) end end function p._exportClasses() return { Article = Article, List = List } end function p._count(args, index) local list = List.new{ args = args, index = index, suppressFormatErrors = true } return list:getArticleCount() end p.count = makeInvokeFunc(p._count) function p._main(args, index) return tostring(List.new{args = args, index = index}) end p.main = makeInvokeFunc(p._main) return p
Summary:
Please note that all contributions to Stockhub may be edited, altered, or removed by other contributors. If you do not want your writing to be edited mercilessly, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource (see
Stockhub:Copyrights
for details).
Do not submit copyrighted work without permission!
Cancel
Editing help
(opens in new window)
Templates used on this page:
Template:Collapse bottom
(
edit
)
Template:Collapse top
(
edit
)
Template:PrefixIndex
(
edit
)
Module:Signpost/doc
(
edit
)