Jump to content

Module:Aside

From Wikipedia, the free encyclopedia

-- This module is an experiment in an altered discussion dynamic for Wikipedia forums.
-- It presents a brief digest of the referenced discussion on a user's talk subpage.
-- The full conversation remains available via V-D-E buttons (V = view the talk subpage, 
-- D = file a comment to the user's MAIN talk page like if there's something you want him to 'admin' or to request an invite as applicable
-- E = edit the talk subpage
-- The digest should present usernames and the first words of each comment, for the past N comments
-- One intention is to allow off-topic conversations to be less obtrusive on the parent thread.
-- Another is that, potentially, some of these may be invite-only conversations in some forum where that is deemed appropriate.
-- Discussions of this type might be indexed in multiple specialized forums.
-- Part of the experiment is that if users feel *invited* to a discussion, it gives editors a chance to express mutual esteem,
-- as a counterbalance against the usual where they only really talk personally when in conflict.  Not sure this will really happen...

-- To try to keep things more accessible, I think the Lua module should only do the text processing to create the talk page extract
-- This then should get wrapped up in V-D-E boxes and cute formatting by an enveloping template.
-- There are some things I can't be perfect about - if you reply in the middle of someone's comment you'll get their beginning attributed to you.

local p = {}

function p.main(frame,header)
    local parent=frame.getParent(frame) or {}
    local currentpage,top
    ---- args in the #invoke itself trump args in the parent frame - not sure if I should even access these but leaving them for now.
    user = frame.args.user or parent.args.user -- the location for discussion with whoever admins the aside, usually user talk:(x).  "D" defaults to (user)
    page = frame.args.page or parent.args.page -- the location of the page for the aside.
    -- In the template, "V/E" links to (page), usually user talk:(x)/subpage
    -- Here page is the talk page on which these operations are done
    -- page can contain a section using the # character.  Per https://wiki.riteme.site/wiki/Wikipedia:Naming_conventions_(technical_restrictions)#Forbidden_characters
    -- there can be no # in a page name, so this imposes no restrictions.  If a section is indicated then ONLY that section should be processed.
    local basepage, section = mw.ustring.match(page, "(.-)#(.*)")
    if section then page = basepage end
    comments = frame.args.comments or parent.args.comments -- the last N comments are returned
    length = frame.args.length or parent.args.length -- return at most N characters of text per comment
    order = frame.args.order or parent.args.order or "new" -- provides an option to sort the comments various ways
    -- order = "new" (default) : latest comments shown; order = "page" (or whatever) : just show the lowest ones on the page
    if (order == "") then order = "new" end -- I don't think I need this but I'm suspicious
    -- "position" (left, right, plain) is a template parameter that can be handled in the template, so will not be used here.
    ---- args in the parent frame come next
    ---- default values if parameters aren't provided
    comments = comments or 6
    comments = tonumber(comments)
    if (comments == 0 or not(comments)) then comments = 6 end
    length = length or 80 -- In homage to TRS, but probably this will get longer
    length = tonumber(length)
    -- get a pointer to the aside
    local pagepointer=mw.title.new(page)
    if not(pagepointer) then return "''[[Module:Aside]]: The page " .. '"' .. page .. '"' .. " could not be accessed.''" end
    ---- get the text of the aside
    local text=pagepointer.getContent(pagepointer)
    assert (text,"error: failed to get text from ".. page)

    if section then
    	local textbits = mw.text.split(text, section, true) -- this is one of the few functions that takes a plain text...
    	if #textbits > 1 then
    		local i = 2
    		repeat
    		    if (mw.ustring.match(textbits[i-1], "==*%s*$")) and (mw.ustring.match(textbits[i], "^%s*==*")) then
    			    text = mw.ustring.gsub(table.concat(textbits, "", i), "%s*==*", "", 1)
    			    text = mw.ustring.gsub(text, "\n%s*==*.*", "", 1) -- this kills everything after ANY section header, even a subsection
    			    break -- use the first section that matches this section heading, I suppose - omitting this would use the last
    		    end
    		    i = i + 1
	        until (i > #textbits)
	    else
	    	return "''[[Module:Aside]]: The section " .. '"' .. section .. '"' .. " could not be found in " .. '"' .. page .. '"'
	    end
    end
    		
    -- the first set of <banner> and <banner> puts arbitrary text at the beginning.
    local output=mw.ustring.match(text, "<!%-%-+banner%-%-+>(.-)<!%-%-+/banner%-%-+>") or ""
    output = output .. "<br />"
    -- now get rid of the banner so it isn't tacked on to the first comment
    text = mw.ustring.gsub(text, "<!%-%-+banner%-%-+>(.-)<!%-%-+/banner%-%-+>%s*", "", 1)
    -- while we're at it, get rid of all the headers.  Yegods, this looks dicey.
    text = mw.ustring.gsub(text, "==+([^\n=]*)=+=%s*", "")
    -- and all the other comments... this may indicate trouble...
    text = mw.ustring.gsub(text, "<!%-%-+.-%-%-+>", "")
    
    local signaturematch = "%[%[(.-)%]%]%s*%(%[%[(.-)%]%]%)%s*(%d+):(%d+)%s*,%s*(%d+)%s*(.-)%s*(%d+)%s*%(%a%a%a%)%s*"
    local monthlookup = {["January"] = "01", ["February"] = "02", ["March"] = "03", ["April"] = "04", ["May"] = "05", ["June"] = "06", ["July"] = "07", ["August"] = "08", ["September"] = "09", ["October"] = "10", ["November"] = "11", ["December"] = "12"}
    local prowl = mw.ustring.gmatch(text,":*%s*(.-)"..signaturematch)
    local archive = {} -- dictionary that pulls comment from the time
    local keys = {} -- shove all the times in here, then sort it later, use to pull out most recent comments wherever they are on the page
    repeat
        local comment, commentuser, commenttalk, commenthour, commentminute, commentday, commentmonth, commentyear = prowl()
        if not (comment) then break end
        -- could put some verification in here - weird days, months, years etc. could disqualify comments from display.
        -- doubt it's worth bothering at the moment.
        comment = mw.ustring.gsub(comment, "$[:%s\n]*", "", 1) -- remove initial whitespace and colons from comment
        comment = mw.ustring.gsub(comment, "\n:*", "  ") -- remove all newlines from comment and :'s afterward, replace with spaces
        comment = mw.ustring.gsub(comment, "<br ?\\?>", "  ") -- remove br's also
        local commentmonthno = monthlookup[commentmonth] or "00"
        if mw.ustring.len(commentday) == 1 then commentday = "0" .. commentday end -- pad days with leading zeroes for sort
        local key = commentyear .. commentmonthno .. commentday .. commenthour .. commentminute
        commentuser = mw.ustring.match(commentuser, "(.-)|") or commentuser -- get rid of the piped summaries of the links
        commentuser = mw.ustring.match(commentuser, "User:(.*)") or commentuser -- get rid of the User: before user
        commenttalk = mw.ustring.match(commenttalk, "(.-)|") or commenttalk
        commenttalk = mw.ustring.match(commenttalk, "(.-)#") or commenttalk -- get rid of the #crap after the link
        commentdate = commentmonthno .. "/" .. commentday -- just tracking the day of comments for now, seems enough
        archive[key] = {comment, commentuser, commenttalk, commentdate} -- should check user = talk, only store one
        table.insert(keys, key)
    until false

    -- sort keys from earliest to latest; maybe the opposite would be better but I'm not feeling creative.
    if (order == "new") then table.sort(keys) end
    
    -- pick the last N keys
    local lastkey = table.maxn(keys)
    local firstkey = math.max(1, lastkey - comments + 1)
    for i = firstkey, lastkey do
    	local key = keys[i]
    	local comment, commentuser, commenttalk, commentdate = archive[key][1], archive[key][2], archive[key][3], archive[key][4]
    	local longuser = mw.ustring.len(commentuser)
    	if (longuser>12) then commentuser = mw.ustring.sub(commentuser, 1, 5) .. ".." .. mw.ustring.sub(commentuser, longuser - 4, longuser) end
        output=output.. commentdate .." [["..commenttalk.."|"..commentuser.."]]: "..(mw.ustring.sub(comment, 1, length) or "").."<br />" -- this isn't really the output I want yet
    end
    return frame.preprocess(frame,output)
end

return p