Skip to main content

Ivan Teoh

Something personal yet public

171-exercise65b.js

(Source)

function splitParagraph(paragraph) {
    var paragraphs = [];
    var start, end, content;

    function spliting(first, last, typeString) {
        while (true)  {
            start = paragraph.indexOf(first, 0);
            if (start === -1) {
                break;
            }
            end = paragraph.indexOf(last, start + 1);
            if (end === -1) {
                break;
            }
            // content does not have "*"
            content = paragraph.slice(start, end + 1).slice(1, -1);
            paragraph = paragraph.slice(0,
                            paragraph.charAt(start) === " "? start - 1 :start)
                            .concat(paragraph.slice(end + 1));
            paragraphs.push({'content': content, 'type': typeString});
        }
    }

    // emphasised part
    spliting("*", "*", "emphasised");

    // footnote
    spliting("{", "}", "footnote");

    // normal text
    paragraphs.push({'content': paragraph, 'type': 'normal'});
    return paragraphs;
}

function forEach(array, action) {
    var i;
    for (i = 0; i < array.length; i++) {
        action(array[i]);
    }
}

function map(func, array) {
    var result = [];
    forEach(array, function (element) {
        result.push(func(element));
    });
    return result;
}

function tag(name, content, attributes) {
    return {name: name, attributes: attributes, content: content};
}

function link(target, text) {
    return tag("a", [text], {href: target});
}

function footnote(number) {
    return tag("sup", [link("#footnote" + number,
                          String(number))]);
}

function renderFragment(fragment) {
    var content;
    switch (fragment.type) {
        case "emphasised":
            content = tag("em", [fragment.content]);
            break;
        case "footnote":
            content = footnote(fragment.content);
            break;
        default: // case 'normal'
            content = fragment.content;
            break;
    }
    return content;
}

// {'content': 'A hermit spent ten years writing a program.', 'type': 'p'}
// {'content': 'two and then *square* it again, the {result} is already
// inaccurate!', 'type': 'p'}
function renderParagraph(paragraph) {
    // [{'content': 'square', 'type': 'emphasised'},
    //  {'content': 'result', 'type': 'footnote'},
    //  {'content': 'two and then it again, the is already inaccurate!',
    //   'type': 'normal'}]
    var fragments = splitParagraph(paragraph.content);
    return tag(paragraph.type, map(renderFragment, fragments));
}

//console.log(renderParagraph({'content': 'two and then *square* it again, the
//{result} is already inaccurate!', 'type': 'p'}));