Matrix Wiki
Advertisement
Matrix Wiki

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:

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

― Name

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 isSrcPrinted = false
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', --float style
        'lstyle', --text style
        'pstyle'  --source style
    }
    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')
            :cssText(options.contextstyle or '')
            :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:wikitext([[
        
{| style= "border-spacing: 0; "]] .. (options.isTableCentered and ' align="center"' or '') .. [[

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

|-
| style= "line-height: 1; " |]] ..
            tostring(quoteSource)) or '') .. [[
            
|}]])
    else
        quoteContainer:wikitext([[
        
{| style= "border-spacing: 0; "]] .. (options.isTableCentered and ' align="center"' or '') .. [[

|-
| 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.contextstyle = args.pstyle
    options.align = ''
    options.styles['min-width'] = args.width or
                                  args.quotewidth or
                                  '300px'
    local float = args.float
    if float then
        options.align = 'pull-quote--' .. float
        options.styles['min-width'] = args.width or
                                  args.quotewidth or
                                  '300px'
        options.styles['width'] = args.width or
                                  args.quotewidth or
                                  '37.5%'
        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'
        if not float then
            options.isTableCentered = true
        end
    else
        if string.lower(trim(args.align or '')) == 'right' then
            options.textAlign = 'right'
        else
            if string.lower(trim(args.align or '')) == 'left' then
                options.textAlign = left
            else
                options.textAlign = nil
            end
        end
    end
    return options
end

function Quote.quotebox(frame)
    addQuoteMarks = false
    return Quote.quote(frame)
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 == '' and origText == '' then
        person = 'Name'
    end
    
    local source = trim(args[3] or
                   args.source or
                   args.Source or
                   args.quotesource or '')

    local block = mw.html.create('div')
            :addClass('pull-quote__box')
    local quoteContents
    
    if addQuoteMarks then
        if options.textAlign == 'center' then
            quoteContents = mw.html.create('p')
                    :addClass('pull-quote__text')
                    :css('display', 'inline')
                    :css('white-space', 'pre-wrap')
                    :css('margin', '0')
                    :css('padding', '0')
                    :cssText(args.lstyle or '')
                    :done()
                :tag('span')
                    :addClass('pull-quote__qmarks')
                    :css('font-family', "'Times New Roman', serif")
                    :css('padding-right', '2px')
                    :css('vertical-align', 'top')
                    :wikitext('“')
                    :done()
                :wikitext(quoteText)
                :tag('span')
                    :css('font-family', "'Times New Roman', serif")
                    :css('white-space', 'nowrap')
                    :css('padding-left', '2px')
                    :css('vertical-align', 'top')
                    :wikitext('”')
                    :done()
            block:wikitext(tostring(quoteContents))
            addQuoteMarks = false
        else
            quoteContents = mw.html.create('p')
                :addClass('pull-quote__text')
                :css('display', 'inline')
                :css('white-space', 'pre-wrap')
                :css('margin', '0')
                :css('padding', '0')
                :cssText(args.lstyle or '')
                :wikitext(quoteText)
                :allDone()
            block:wikitext(tostring(quoteContents))
                :tag('span')
                :css('font-family', "'Times New Roman', serif")
                :css('white-space', 'nowrap')
                :css('padding-left', '2px')
                :css('vertical-align', 'top')
                :wikitext('”')
        end
    else
        quoteContents = mw.html.create('div')
            :addClass('pull-quote__box')
                :tag('p')
                :addClass('pull-quote__text')
                :css('white-space', 'pre-wrap')
                :css('margin', '0')
                :css('padding', '0')
                :cssText(args.lstyle or '')
                :wikitext(quoteText)
        block:wikitext(tostring(quoteContents))
    end
    
    local buildStr = build(block, 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 .. (isSrcPrinted and ('<br />Source:' .. tostring(mw.html.create('pre'):wikitext(mw.text.nowiki(buildStr)))) or '')
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__box')
        :tag('div')
            :addClass('pull-quote__text')
            :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 = trim(args.description or args.context or '')
    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 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

function Quote.debugQuote(frame)
    isSrcPrinted = true
    return Quote.quote(frame)
end

function Quote.debugQuotebox(frame)
    isSrcPrinted = true
    return Quote.quotebox(frame)
end

function Quote.debugDialog(frame)
    isSrcPrinted = true
    return Quote.dialog(frame)
end

return Quote
Advertisement