Matrix Wiki
Matrix Wiki
(Matching how quotebox looks with quote)
(Adds debug string for quotebox)
Line 144: Line 144:
 
addQuoteMarks = false
 
addQuoteMarks = false
 
return Quote.quote(frame)
 
return Quote.quote(frame)
  +
.. '<br />Source:' .. tostring(mw.html.create('pre'):wikitext(mw.text.nowiki(buildStr)))
 
end
 
end
   

Revision as of 06:28, 8 April 2021

This module attempts to abide by the dev:Quotes customization guidelines seen here: https://dev.fandom.com/wiki/Global_Lua_Modules/Quote but with some major changes.

  1. The "align" parameter instead refers to text-alignment while "float" replaces the old "align" parameter.
  2. This module currently works with no custom stylesheets. Instead, quote marks are programmatically added by the module. The quotemarks class is:
    pull-quote__qmarks

To disable the module itself from adding the quotes, use the following invocation:

{{#invoke:Quote|quotebox}}

Sample output: Lua error in mw.text.lua at line 129: bad argument #1 to 'gsub' (string expected, got nil).

The default invocation below auto-adds the quote marks at the beginning and end of the quote:

{{#invoke:Quote|quote}}

Sample output:

Type in text without quote marks here. (Second line of text will appear as such with all spaces preserved.)

― Name

Note: The dialog module is dependent on this module.

CSS

Check the Dev:Quote module documentation for the latest stylesheet sample. A version of the stylesheet captured upon development of this module is shown below for reference:

:root {

    --pull-quote-max-width: 80%;
    --pull-quote-text-color: rgba(0, 0, 0, .8);
    --pull-quote-mark-color: rgba(0, 0, 0, .15);
    --pull-quote-mark-font: "Times New Roman", serif;
    --pull-quote-hyphens: auto;
    --pull-quote-frame-color: #bbb;
}

/* .WikiaPage added as a parent selector to the following in order to override default blockquote styles. */

.WikiaPage .pull-quote {
    display: flex;
    flex-wrap: wrap;
    max-width: var(--pull-quote-max-width);
    margin: 1em auto;
    font-size: 1em;
    line-height: 1.8;
}

.WikiaPage .pull-quote__text {
    flex-basis: 100%;
    position: relative;
    padding: 0 2em;
    hyphens: var(--pull-quote-hyphens);
    color: var(--pull-quote-text-color);
}

.WikiaPage .pull-quote__text::before, .WikiaPage .pull-quote__text::after {
    position: absolute;
    font-size: 3em;
    font-family: var(--pull-quote-mark-font);
    font-weight: 700;
    color: var(--pull-quote-mark-color);
}

.WikiaPage .pull-quote__text::before {
    content: "“";
    top: 0;
    left: 0;
    line-height: 1;
}

.WikiaPage .pull-quote__text::after {
    content: "”";
    bottom: 0;
    right: 0;
    line-height: 0.2;
}

.WikiaPage .pull-quote__source {
    margin-left: auto;
}

.WikiaPage .pull-quote__source::before {
    content: "—"; 
}

.WikiaPage .pull-quote--right, .WikiaPage .pull-quote--left {
    border: 1px solid var(--pull-quote-frame-color);
    border-left: 0;
    border-right: 0;
    padding: 1em 0;
    text-align: justify;
}

.WikiaPage .pull-quote--right {
    float: right;
    margin: 1em 0 1em 2em;
}

.WikiaPage .pull-quote--left {
    float: left;
    margin: 1em 2em 1em 0;
}

-- this module implements {{quote}}
-- follows customization guidelines of Dev:Quote

local Quote = {}

-- this module can add actual quote marks instead of relying on CSS styling
local addQuoteMarks = true

local isDialog = false
local tracking, preview

local function trim(s)
    return mw.ustring.gsub(mw.ustring.gsub(s, '%s+', ' '), '^%s*(.-)%s*$', '%1')
end

local function convertNewLines(s)
    return mw.ustring.gsub(mw.ustring.gsub(s, '^\n*(.-)\n*$', '%1'), '\n', '<br />')
end

local function checkArg(k,v)
    local validArgs = {
        'Quote', 'quotetext', 'quote', 'text',
        'Name', 'name', 'person', 'speaker', 'personquoted', 'context',
        'Source', 'source', 'quotesource',
        'class', 'style', 'align', 'width', 'quotewidth', 'float', 'fstyle'
    }
    if isDialog == true then
        validArgs = {
            'description', 'context',
            'source',
            'class', 'style', 'align', 'width', 'float', 'pstyle', 'lstyle', 'fstyle'
        }
    end
    if k and type(k) == 'string' then
        if k:match('^speaker%d+$') then
            hasSpeaker = true
            return true
        end
        local lookup = {}
        for k, v in ipairs(validArgs) do
            lookup[v] = true
        end
        if lookup[k] or k:match('^%d+$') then
            return true
        else
            local vlen = mw.ustring.len(k)
            k = mw.ustring.sub(k, 1, (vlen < 25) and vlen or 25) 
            k = mw.ustring.gsub(k, '[^%w\-_ ]', '?')
            table.insert(tracking, '[[Category:Pages using ' .. (isDialog and 'dialog' or 'quote') .. ' with unknown parameters|' .. k .. ']]')
            table.insert(preview, '"' .. k .. '"')
        end
    else
        if k and type(k) == 'number' then
            return true
        end
    end
    return false
end

local function build(quoteContents, context, source, options)
    local quoteSource
    if context ~= '' then
        local quoteStr
        if source ~= '' then
            quoteStr = '&#8213;&nbsp;' .. context .. tostring(mw.html.create('sup')
                :css('white-space', 'nowrap')
                :css('margin-left', '2px')
                :wikitext('[[' .. source .. '|[src]]]'))
        else
            quoteStr = '&#8213;&nbsp;' .. context
        end
        quoteSource = mw.html.create('cite')
            :addClass('pull-quote__source')
            :css('line-height', '1')
            :wikitext(quoteStr)
    end
    
    local quoteContainer = mw.html.create('blockquote')
        :addClass('pull-quote')
        :addClass(options.align)
        :addClass(options.extraclasses)
        :css(options.styles)
        :css('text-align', options.textAlign)
        :cssText(options.extrastyles)
    if not addQuoteMarks then
        quoteContainer:node(quoteContents)
        if quoteSource then
            quoteContainer:node(quoteSource)
        end
    else
        quoteContainer:wikitext([[

{| style= "border-spacing: 0; "
|-
| style= "vertical-align: top; margin: 0; padding: 0; " |]] ..
            tostring(mw.html.create('span')
                :addClass('pull-quote__qmarks')
                :css('font-family', "'Times New Roman', serif")
                :css('padding-right', '2px')
                :wikitext('“')) .. [[

| style= "width: 100%; " |]] .. tostring(quoteContents) .. (quoteSource and ([[

|-
| colspan= "2" style= "line-height: 1; " |]] ..
            tostring(quoteSource)) or '') .. [[

|}]])
    end
    
    return tostring(quoteContainer)
end

local function options(args)
    local options = {}
    options.styles = {}
    options.extraclasses = args.class
    options.extrastyles = args.style
    options.align = ''
    local float = args.float
    if float then
        options.align = 'pull-quote--' .. float
        options.styles['width'] = args.width or
                                  args.quotewidth or
                                  '300px'
        options.styles['float'] = float
        if args.fstyle then
            options.extrastyles = (options.extrastyles or '') .. ';' .. args.fstyle
        end
    end    
    if string.lower(trim(args.align or '')) == 'center' then
        options.textAlign = 'center'
    else
        if string.lower(trim(args.align or '')) == 'right' then
            options.textAlign = 'right'
        else
            options.textAlign = nil
        end
    end
    return options
end

function Quote.quotebox(frame)
    addQuoteMarks = false
    return Quote.quote(frame)
          .. '<br />Source:' .. tostring(mw.html.create('pre'):wikitext(mw.text.nowiki(buildStr)))
end

function Quote.quote(frame)
    -- If called via #invoke, use the args passed into the invoking template.
    -- Otherwise, for testing purposes, assume args are being passed directly in.
    local origArgs = (type(frame.getParent) == 'function') and frame:getParent().args or frame
    
    local args = {}

    tracking, preview = {}, {}
    for k, v in pairs(origArgs) do
        if checkArg(k,v) == true then
            args[k] = v
        end
    end
    
    local options = options(args)
    
    local origText = convertNewLines(args[1] or
                     args.quotetext or
                     args.quote or
                     args.Quote or
                     args.text or '')
    local quoteText = (origText ~= '' and origText or [[Type in text without quote marks here.
(Second line of text will appear as such with all   spaces   preserved.)]])
    
    local person = trim(args[2] or
                   args.name or
                   args.Name or
                   args.person or
                   args.speaker or
                   args.personquoted or '')
    if person == '' then
        if origText == '' then
            person = 'Name'
        end
    end
    
    local source = trim(args[3] or
                   args.source or
                   args.Source or
                   args.quotesource or '')

    local quoteContents = mw.html.create('p')
        :addClass('pull-quote__text')
        :css('white-space', 'pre-wrap')
        :css('margin', '0')
        :css('padding', '0')
    
    if addQuoteMarks then
        if options.textAlign == 'center' then
            quoteContents:tag('span')
                :addClass('pull-quote__qmarks')
                :css('font-family', "'Times New Roman', serif")
                :css('padding-right', '2px')
                :wikitext('“')
                :done()
            addQuoteMarks = false
        end
        quoteContents:wikitext(quoteText):tag('span')
            :css('font-family', "'Times New Roman', serif")
            :css('white-space', 'nowrap')
            :css('padding-left', '2px')
            :wikitext('”')
    else
        quoteContents:wikitext(quoteText)
    end
    
    local buildStr = build(quoteContents, person, source, options)
    local trackStr = (#tracking > 0) and table.concat(tracking, '') or ''
    if #preview > 0 and frame:preprocess( "{{REVISIONID}}" ) == "" then
        local hatnote = require('Dev:Hatnote')
        trackStr = hatnote.makeWikitextError('Unknown parameters: ' .. table.concat(preview, '; '))
    end
    
    return buildStr .. trackStr
--        .. '<br />Source:' .. tostring(mw.html.create('pre'):wikitext(mw.text.nowiki(buildStr)))
end

function Quote.dialog(frame)
    isDialog = true
    addQuoteMarks = false
    
    -- If called via #invoke, use the args passed into the invoking template.
    -- Otherwise, for testing purposes, assume args are being passed directly in.
    local origArgs = (type(frame.getParent) == 'function') and frame:getParent().args or frame
    
    local args, dialog, speakers = {}, {}, {}

    tracking, preview = {}, {}
    for k, v in pairs(origArgs) do
        if checkArg(k,v) == true then
            args[k] = v
        end
    end
    
    local options = options(args)
    
    local block = mw.html.create('div')
        :addClass('pull-quote__text')
        :tag('div')
            :cssText('display: block; white-space: pre-wrap; margin: 0; padding: 0; ')

    local lineCount = #args

    if hasSpeaker == true then
        for i = 1, lineCount do
            local speaker = trim(args['speaker' .. i] or '')
            if speaker ~= '' then
                speaker = tostring(mw.html.create('strong')
                    :addClass('pull-quote__speaker')
                    :cssText('text-align: left; ' .. (args.pstyle or ''))
                    :wikitext(speaker .. ':'))
                table.insert(speakers, speaker)
            end
        end
        local speakerCount, j = #speakers, 1
        for i = 1, lineCount do
            local line = convertNewLines(args[i] or '')
            if line ~= '' then
                local speaker = speakers[j] or ''
                line = mw.html.create('span')
                    :addClass('pull-quote__line')
                    :cssText('text-align: left; ' .. (args.lstyle or ''))
                    :wikitext(speaker .. '&nbsp;' .. (line ~= '' and string.format("''%s''", line) or ''))
                table.insert(dialog, tostring(line))
                j = (j % speakerCount) + 1
            end
        end
    else
        lineCount = math.ceil(lineCount / 2)
        for i = 1, lineCount do
            local speaker = trim(args[i * 2 - 1] or '')
            local line = convertNewLines(args[i * 2] or '')
            line = (line ~= '' and string.format("''%s''", line) or '')
            if speaker ~= '' then
                speaker = tostring(mw.html.create('strong')
                    :addClass('pull-quote__speaker')
                    :cssText('text-align: left; ' .. (args.pstyle or ''))
                    :wikitext(speaker .. ':'))
                line = speaker .. '&nbsp;' .. line
            end
            table.insert(dialog, tostring(mw.html.create('span')
                :addClass('pull-quote__line')
                :cssText('text-align: left; ' .. (args.lstyle or ''))
                :wikitext(line)))
        end
    end

    local context = args.description or args.context
    if #dialog == 0 then
        table.insert(dialog, tostring(mw.html.create('span')
                :addClass('pull-quote__line')
                :cssText('text-align: left; ' .. (args.lstyle or ''))
                :tag('strong')
                    :addClass('pull-quote__speaker')
                    :cssText('text-align: left; ' .. (args.pstyle or ''))
                    :wikitext('{{{speaker1}}}:')
                    :done()
                :wikitext(" ''{{{1}}}''")))
        table.insert(dialog, tostring(mw.html.create('span')
                :addClass('pull-quote__line')
                :cssText('text-align: left; ' .. (args.lstyle or ''))
                :tag('strong')
                    :addClass('pull-quote__speaker')
                    :cssText('text-align: left; ' .. (args.pstyle or ''))
                    :wikitext('{{{speaker2}}}:')
                    :done()
                :wikitext(" ''{{{2}}}''")))
        if not context then
             context = 'describe the context of the dialog'
        end
    end
    
    local source = trim(args.source or '')
    local dialogContents = block:wikitext(table.concat(dialog, '<br />'))
    local buildStr = build(dialogContents, context, source, options)

    local trackStr = (#tracking > 0) and table.concat(tracking, '') or ''
    if #preview > 0 and frame:preprocess( "{{REVISIONID}}" ) == "" then
        local hatnote = require('Dev:Hatnote')
        trackStr = hatnote.makeWikitextError('Unknown parameters: ' .. table.concat(preview, '; '))
    end

    return  buildStr .. trackStr
    --    .. '<br />Source:' .. tostring(mw.html.create('pre'):wikitext(mw.text.nowiki(buildStr)))
end

return Quote