<commit_before>
import R from 'ramda';
import { Reader } from 'ramda-fantasy';
import $ from 'sanctuary-def';

/* We need a recursion, so: */
/* eslint-disable no-use-before-define */

/* Types are by convention starts with a capital leter, so: */
/* eslint-disable new-cap */

/*
From https://www.npmjs.com/package/hindley-milner-parser-js:

HMP.parse('hello :: Foo a => a -> String');
{
  name: 'hello',
  constraints: [
    {typeclass: 'Foo', typevar: 'a'}],
  type:
    {type: 'function', text: '', children: [
      {type: 'typevar', text: 'a', children: []},
      {type: 'typeConstructor', text: 'String', children: []}]};
*/

// type TypeMap = StrMap Type

// TODO: implement, so
// eslint-disable-next-line no-unused-vars
export const constraints = sig => ({});

const lift = R.map;
const lift2 = R.liftN(2);

// :: Object -> String -> Boolean
const typeEq = R.propEq('type');

// :: SignatureEntry -> Boolean
const hasChildren = R.compose(R.not, R.isEmpty, R.prop('children'));

// :: SignatureEntry -> Reader TypeMap Type
const lookupType = entry => Reader((typeMap) => {
  const name = entry.text;
  const t = typeMap[name];
  if (!t) {
    const allTypes = R.keys(typeMap).join(', ');
    throw new TypeError(`Type ${name} not found in env. Available types are: ${allTypes}`);
  }
  return t;
});

// Helper Type to wipe out thunks
const Thunk = $.NullaryType('hm-def/Thunk', '', R.F);

// :: SignatureEntry -> Reader TypeMap Type
const convertTypeConstructor = entry => R.ifElse(
  hasChildren,
  R.compose(
    lift2(R.apply)(lookupType(entry)),
    convertTypes,
    R.prop('children'),
  ),
  lookupType,
)(entry);

// :: SignatureEntry -> Reader TypeMap Type
const convertList = R.compose(
  lift($.Array),
  convertType,
  R.path(['children', 0]),
);

// :: SignatureEntry -> Reader TypeMap Type
const convertFunction = R.compose(
  lift($.Function),
  convertTypes,
  R.prop('children'),
);

// :: SignatureEntry -> Reader TypeMap (Pair String Type)
const convertRecordField = entry => R.compose(
  lift(valueType => [entry.text, valueType]),
  convertType,
  R.path(['children', 0]),
)(entry);

// :: SignatureEntry -> Reader TypeMap Type
const convertRecord = R.compose(
  lift($.RecordType),
  lift(R.fromPairs),
  R.sequence(Reader.of),
  R.map(convertRecordField),
  R.prop('children'),
);

// :: SignatureEntry -> Type
const convertTypevar = R.memoize(R.compose($.TypeVariable, R.prop('text')));

// :: SignatureEntry -> (Type -> Type)
const unaryTypevar = R.memoize(R.compose($.UnaryTypeVariable, R.prop('text')));

// :: SignatureEntry -> Reader TypeMap Type
const convertConstrainedType = entry => R.compose(
  lift(unaryTypevar(entry)),
  convertType,
  R.path(['children', 0]),
)(entry);

// :: SignatureEntry -> Reader TypeMap Type
function convertType(entry) {
  return R.cond([
    [typeEq('typeConstructor'), convertTypeConstructor],
    [typeEq('function'), convertFunction],
    [typeEq('list'), convertList],
    [typeEq('record'), convertRecord],
    [typeEq('constrainedType'), convertConstrainedType],
    [typeEq('typevar'), R.compose(Reader.of, convertTypevar)],
    [typeEq('thunk'), R.always(Reader.of(Thunk))],
    [R.T, (e) => {
      throw new Error(`Don't know what to do with signature entry ${e.type}`);
    }],
  ])(entry);
}

// :: [SignatureEntry] -> Reader TypeMap [Type]
function convertTypes(entries) {
  return R.compose(
    lift(R.reject(R.equals(Thunk))),
    R.sequence(Reader.of),
    R.map(convertType),
  )(entries);
}

// :: TypeMap -> [SignatureEntry] -> [Type]
export const types = R.curry((typeMap, entries) =>
  convertTypes(entries).run(typeMap),
);

// :: String -> String
const stripNamespace = R.compose(R.last, R.split('/'));

// Type -> Type
const ensureParametrized = R.when(
  R.is(Function),
  fn => R.apply(fn, R.repeat($.Unknown, fn.length)),
);

// :: Type -> String
const shortName = R.compose(
  stripNamespace,
  R.prop('name'),
  ensureParametrized,
);

// :: [Type] -> TypeMap
export const typemap = R.indexBy(shortName);
<commit_msg>refactor: extract children and firstChild function to be more DRY<commit_after>
import R from 'ramda';
import { Reader } from 'ramda-fantasy';
import $ from 'sanctuary-def';

/* We need a recursion, so: */
/* eslint-disable no-use-before-define */

/* Types are by convention starts with a capital leter, so: */
/* eslint-disable new-cap */

/*
From https://www.npmjs.com/package/hindley-milner-parser-js:

HMP.parse('hello :: Foo a => a -> String');
{
  name: 'hello',
  constraints: [
    {typeclass: 'Foo', typevar: 'a'}],
  type:
    {type: 'function', text: '', children: [
      {type: 'typevar', text: 'a', children: []},
      {type: 'typeConstructor', text: 'String', children: []}]};
*/

// type TypeMap = StrMap Type

// TODO: implement, so
// eslint-disable-next-line no-unused-vars
export const constraints = sig => ({});

const lift = R.map;
const lift2 = R.liftN(2);

// :: { children :: [a] } -> [a]
const children = R.prop('children');

// :: { children :: [a] } -> a
const firstChild = R.compose(R.prop(0), children);

// :: Object -> String -> Boolean
const typeEq = R.propEq('type');

// :: SignatureEntry -> Boolean
const hasChildren = R.compose(R.not, R.isEmpty, R.prop('children'));

// :: SignatureEntry -> Reader TypeMap Type
const lookupType = entry => Reader((typeMap) => {
  const name = entry.text;
  const t = typeMap[name];
  if (!t) {
    const allTypes = R.keys(typeMap).join(', ');
    throw new TypeError(`Type ${name} not found in env. Available types are: ${allTypes}`);
  }
  return t;
});

// Helper Type to wipe out thunks
const Thunk = $.NullaryType('hm-def/Thunk', '', R.F);

// :: SignatureEntry -> Reader TypeMap Type
const convertTypeConstructor = entry => R.ifElse(
  hasChildren,
  R.compose(
    lift2(R.apply)(lookupType(entry)),
    convertTypes,
    children,
  ),
  lookupType,
)(entry);

// :: SignatureEntry -> Reader TypeMap Type
const convertList = R.compose(
  lift($.Array),
  convertType,
  firstChild,
);

// :: SignatureEntry -> Reader TypeMap Type
const convertFunction = R.compose(
  lift($.Function),
  convertTypes,
  children,
);

// :: SignatureEntry -> Reader TypeMap (Pair String Type)
const convertRecordField = entry => R.compose(
  lift(valueType => [entry.text, valueType]),
  convertType,
  firstChild,
)(entry);

// :: SignatureEntry -> Reader TypeMap Type
const convertRecord = R.compose(
  lift($.RecordType),
  lift(R.fromPairs),
  R.sequence(Reader.of),
  R.map(convertRecordField),
  children,
);

// :: SignatureEntry -> Type
const convertTypevar = R.memoize(R.compose($.TypeVariable, R.prop('text')));

// :: SignatureEntry -> (Type -> Type)
const unaryTypevar = R.memoize(R.compose($.UnaryTypeVariable, R.prop('text')));

// :: SignatureEntry -> Reader TypeMap Type
const convertConstrainedType = entry => R.compose(
  lift(unaryTypevar(entry)),
  convertType,
  firstChild,
)(entry);

// :: SignatureEntry -> Reader TypeMap Type
function convertType(entry) {
  return R.cond([
    [typeEq('typeConstructor'), convertTypeConstructor],
    [typeEq('function'), convertFunction],
    [typeEq('list'), convertList],
    [typeEq('record'), convertRecord],
    [typeEq('constrainedType'), convertConstrainedType],
    [typeEq('typevar'), R.compose(Reader.of, convertTypevar)],
    [typeEq('thunk'), R.always(Reader.of(Thunk))],
    [R.T, (e) => {
      throw new Error(`Don't know what to do with signature entry ${e.type}`);
    }],
  ])(entry);
}

// :: [SignatureEntry] -> Reader TypeMap [Type]
function convertTypes(entries) {
  return R.compose(
    lift(R.reject(R.equals(Thunk))),
    R.sequence(Reader.of),
    R.map(convertType),
  )(entries);
}

// :: TypeMap -> [SignatureEntry] -> [Type]
export const types = R.curry((typeMap, entries) =>
  convertTypes(entries).run(typeMap),
);

// :: String -> String
const stripNamespace = R.compose(R.last, R.split('/'));

// Type -> Type
const ensureParametrized = R.when(
  R.is(Function),
  fn => R.apply(fn, R.repeat($.Unknown, fn.length)),
);

// :: Type -> String
const shortName = R.compose(
  stripNamespace,
  R.prop('name'),
  ensureParametrized,
);

// :: [Type] -> TypeMap
export const typemap = R.indexBy(shortName);
<|endoftext|>


<commit_before>/** @format */
const Sidebar = {
    _init() {},

    updateContent(sentenceData, wordData, corpus, tokens) {
        this.element.html('

')
        const corpusObj = settings.corpora[corpus]

        const corpusInfo = $("
").html(
            `<h4 rel='localize[corpus]'></h4> <p>${corpusObj.title}</p>`
        )
        corpusInfo.prependTo("#selected_sentence")

        if (corpusObj["inStrix"]) {
            const sentenceID = sentenceData["sentence_id"]
            if (sentenceID) {
                // TODO fix this so that strix uses correct corpus ids
                const strixCorpus = corpus === "wikipedia-sv" ? "wikipedia" : corpus
                const strixLinkText = `${
                    settings.strixUrl
                }?sentenceID=${sentenceID}&documentCorpus=${strixCorpus}`
                $("
")
                    .html(
                        `<a target='_blank' href='${strixLinkText}' rel='localize[read_in_strix]'></a>`
                    )
                    .prependTo(corpusInfo)
            }
        }

        const customData = { pos: [], struct: [] }
        if (!$.isEmptyObject(corpusObj.customAttributes)) {
            const [word, sentence] = this.renderCustomContent(
                wordData,
                sentenceData,
                corpusObj.customAttributes,
                tokens
            )
            customData.pos = word
            customData.struct = sentence
        }

        let posData = []
        if (!$.isEmptyObject(corpusObj.attributes)) {
            posData = this.renderCorpusContent(
                "pos",
                wordData,
                sentenceData,
                corpusObj.attributes,
                tokens,
                corpusObj.customAttributes || {},
                customData.pos
            )
        }
        let structData = []
        if (!$.isEmptyObject(corpusObj.structAttributes)) {
            structData = this.renderCorpusContent(
                "struct",
                wordData,
                sentenceData,
                corpusObj.structAttributes,
                tokens,
                corpusObj.customAttributes || {},
                customData.struct
            )
        }

        $("#selected_word").append($("
").localeKey("word_attr"))
        $("#selected_sentence").append($("
").localeKey("sentence_attr"))
        $("#selected_word").append(posData)
        $("#selected_sentence").append(structData)

        this.element.localize()
        this.applyEllipse()
        if (corpusObj.attributes.deprel) {
            this.renderGraph(tokens)
        }
    },

    renderGraph(tokens) {
        $("</button>")
            .localeKey("show_deptree")
            .click(function() {
                const outerW = $(window).width() - 80
                const info = $("")
                const iframe = $('')
                    .css("width", outerW - 40)
                    .on("load", function() {
                        const wnd = this.contentWindow
                        wnd.draw_deptree(wnd, tokens, function(msg) {
                            const [type, val] = _.head(_.toPairs(msg))
                            info.empty().append(
                                $("").localeKey(type),
                                $(": "),
                                $("").localeKey(`${type}_${val}`)
                            )
                        })
                    })

                $("#deptree_popup")
                    .empty()
                    .append(info, iframe)
                    .dialog({
                        height: 300,
                        width: outerW
                    })
                    .parent()
                    .find(".ui-dialog-title")
                    .localeKey("dep_tree")
            })
            .appendTo(this.element)
    },

    renderCorpusContent(
        type,
        wordData,
        sentenceData,
        corpus_attrs,
        tokens,
        customAttrs,
        customData
    ) {
        let pairs
        if (type === "struct") {
            pairs = _.toPairs(sentenceData)
        } else if (type === "pos") {
            pairs = _.toPairs(wordData)
        }

        pairs = _.filter(pairs, function(...args) {
            let [key, val] = args[0]
            return corpus_attrs[key]
        })
        pairs = _.filter(pairs, function(...args) {
            let [key, val] = args[0]
            return !(corpus_attrs[key].displayType === "hidden" || corpus_attrs[key].hideSidebar)
        })

        for (let custom of customData) {
            pairs.push(custom)
        }

        pairs.sort(function(...args) {
            let ord1, ord2
            const [a] = args[0]
            const [b] = args[1]
            if (a in corpus_attrs) {
                ord1 = corpus_attrs[a].order
            } else {
                ord1 = customAttrs[a].order
            }

            if (b in corpus_attrs) {
                ord2 = corpus_attrs[b].order
            } else {
                ord2 = customAttrs[b].order
            }

            if (_.isUndefined(ord1)) {
                ord1 = 10000
            }
            if (_.isUndefined(ord2)) {
                ord2 = 10000
            }
            return ord1 - ord2
        })

        let items = []
        for (let [key, value] of pairs) {
            if (key in customAttrs) {
                items.push(value)
            } else {
                items = items.concat(
                    (
                        this.renderItem(
                            key,
                            value,
                            corpus_attrs[key],
                            wordData,
                            sentenceData,
                            tokens
                        ) || $()
                    ).get(0) || []
                )
            }
        }

        items = _.compact(items)
        return $(items)
    },

    renderCustomContent(wordData, sentenceData, corpus_attrs, tokens) {
        const structItems = []
        const posItems = []
        for (let key in corpus_attrs) {
            const attrs = corpus_attrs[key]
            const output = (
                this.renderItem(key, "not_used", attrs, wordData, sentenceData, tokens) || $()
            ).get(0)
            if (attrs.customType === "struct") {
                structItems.push([key, output])
            } else if (attrs.customType === "pos") {
                posItems.push([key, output])
            }
        }
        return [posItems, structItems]
    },

    renderItem(key, value, attrs, wordData, sentenceData, tokens) {
        let lis, output, pattern, ul, valueArray
        let val, inner, cqpVal, li, address
        if (attrs.label) {
            output = $(`<p><span rel='localize[${attrs.label}]'></span>: </p>`)
        } else {
            output = $("

")
        }
        if (attrs.renderItem) {
            return output.append(
                attrs.renderItem(key, value, attrs, wordData, sentenceData, tokens)
            )
        }

        output.data("attrs", attrs)
        if (value === "|" || value === "" || value === null) {
            output.append(
                `<i rel='localize[empty]' style='color : grey'>${util.getLocaleString("empty")}</i>`
            )
            return output
        }

        if (attrs.type === "set" && attrs.display && attrs.display.expandList) {
            valueArray = _.filter((value && value.split("|")) || [], Boolean)
            const attrSettings = attrs.display.expandList
            if (attrs.ranked) {
                valueArray = _.map(valueArray, function(value) {
                    val = value.split(":")
                    return [val[0], val[val.length - 1]]
                })

                lis = []

                for (let outerIdx = 0; outerIdx < valueArray.length; outerIdx++) {
                    var externalLink
                    let [value, prob] = valueArray[outerIdx]
                    li = $("

")
                    const subValues = attrSettings.splitValue
                        ? attrSettings.splitValue(value)
                        : [value]
                    for (let idx = 0; idx < subValues.length; idx++) {
                        const subValue = subValues[idx]
                        val = (attrs.stringify || attrSettings.stringify || _.identity)(subValue)
                        inner = $(`<span>${val}</span>`)
                        inner.attr("title", prob)

                        if (
                            attrs.internalSearch &&
                            (attrSettings.linkAllValues || outerIdx === 0)
                        ) {
                            inner.data("key", subValue)
                            inner.addClass("link").click(function() {
                                const searchKey = attrSettings.searchKey || key
                                cqpVal = $(this).data("key")
                                const cqpExpr = attrSettings.internalSearch
                                    ? attrSettings.internalSearch(searchKey, cqpVal)
                                    : `[${searchKey} contains '${regescape(cqpVal)}']`
                                return locationSearch({ search: "cqp", cqp: cqpExpr, page: null })
                            })
                        }
                        if (attrs.externalSearch) {
                            address = _.template(attrs.externalSearch)({ val: subValue })
                            externalLink = $(
                                `<a href='${address}' class='external_link' target='_blank' style='margin-top: -6px'></a>`
                            )
                        }

                        li.append(inner)
                        if (attrSettings.joinValues && idx !== subValues.length - 1) {
                            li.append(attrSettings.joinValues)
                        }
                    }
                    if (externalLink) {
                        li.append(externalLink)
                    }
                    lis.push(li)
                }
            } else {
                lis = []
                for (value of valueArray) {
                    li = $("

")
                    li.append(value)
                    lis.push(li)
                }
            }

            if (lis.length === 0) {
                ul = $('')
            } else {
                ul = $("
")
                ul.append(lis)

                if (lis.length !== 1 && !attrSettings.showAll) {
                    _.map(lis, function(li, idx) {
                        if (idx !== 0) {
                            return li.css("display", "none")
                        }
                    })

                    const showAll = $(
                        ` (${lis.length -
                            1})`
                    )
                    ul.append(showAll)

                    const showOne = $(
                        ""
                    )
                    showOne.css("display", "none")
                    ul.append(showOne)

                    showAll.click(function() {
                        showAll.css("display", "none")
                        showOne.css("display", "inline")
                        return _.map(lis, li => li.css("display", "list-item"))
                    })

                    showOne.click(function() {
                        showAll.css("display", "inline")
                        showOne.css("display", "none")
                        _.map(lis, function(li, i) {
                            if (i !== 0) {
                                return li.css("display", "none")
                            }
                        })
                    })
                }
            }

            output.append(ul)
            return output
        } else if (attrs.type === "set") {
            pattern = attrs.pattern || '<span data-key="<%= key %>"><%= val %>'
            ul = $("
")
            const getStringVal = str =>
                _.reduce(
                    _.invokeMap(_.invokeMap(str, "charCodeAt", 0), "toString"),
                    (a, b) => a + b
                )
            valueArray = _.filter((value && value.split("|")) || [], Boolean)
            if (key === "variants") {
                // TODO: this doesn't sort quite as expected
                valueArray.sort(function(a, b) {
                    const splita = util.splitLemgram(a)
                    const splitb = util.splitLemgram(b)
                    const strvala =
                        getStringVal(splita.form) + splita.index + getStringVal(splita.pos)
                    const strvalb =
                        getStringVal(splitb.form) + splitb.index + getStringVal(splitb.pos)

                    return parseInt(strvala) - parseInt(strvalb)
                })
            }

            const itr = _.isArray(valueArray) ? valueArray : _.values(valueArray)
            const lis = []
            for (let x of itr) {
                if (x.length) {
                    val = (attrs.stringify || _.identity)(x)

                    inner = $(_.template(pattern)({ key: x, val }))
                    if (attrs.translationKey != null) {
                        const prefix = attrs.translationKey || ""
                        inner.localeKey(prefix + val)
                    }

                    if (attrs.internalSearch) {
                        inner.addClass("link").click(function() {
                            cqpVal = $(this).data("key")
                            return locationSearch({
                                page: null,
                                search: "cqp",
                                cqp: `[${key} contains \"${regescape(cqpVal)}\"]`
                            })
                        })
                    }

                    li = $("

")
                        .data("key", x)
                        .append(inner)
                    if (attrs.externalSearch) {
                        address = _.template(attrs.externalSearch)({ val: x })
                        li.append(
                            $(`<a href='${address}' class='external_link' target='_blank'></a>`)
                        )
                    }

                    lis.push(li)
                }
            }
            ul.append(lis)
            output.append(ul)

            return output
        }

        const str_value = (attrs.stringify || _.identity)(value)

        if (attrs.type === "url") {
            return output.append(
                `${decodeURI(
                    str_value
                )}`
            )
        } else if (key === "msd") {
            // msdTags = require '../markup/msdtags.html'
            const msdTags = "markup/msdtags.html"
            return output.append(`${str_value}

                \
            `)
        } else if (attrs.pattern) {
            return output.append(
                _.template(attrs.pattern)({
                    key,
                    val: str_value,
                    pos_attrs: wordData,
                    struct_attrs: sentenceData
                })
            )
        } else {
            if (attrs.translationKey) {
                if (window.loc_data["en"][attrs.translationKey + value]) {
                    return output.append(
                        `<span rel='localize[${attrs.translationKey}${value}]'></span>`
                    )
                } else {
                    return output.append(`<span>${value}</span>`)
                }
            } else {
                return output.append(`<span>${str_value || ""}</span>`)
            }
        }
    },

    applyEllipse() {
        // oldDisplay = @element.css("display")
        // @element.css "display", "block"
        const totalWidth = this.element.width()

        // ellipse for too long links of type=url
        this.element
            .find(".sidebar_url")
            .css("white-space", "nowrap")
            .each(function() {
                while ($(this).width() > totalWidth) {
                    const oldtext = $(this).text()
                    const a = _.trim(oldtext, "/")
                        .replace("...", "")
                        .split("/")
                    const domain = a.slice(2, 3)
                    let midsection = a.slice(3).join("/")
                    midsection = `...${midsection.slice(2)}`
                    $(this).text(["http:/"].concat(domain, midsection).join("/"))
                    if (midsection === "...") {
                        break
                    }
                }
            })
    },

    updatePlacement() {
        const max = Math.round($("#columns").position().top)
        if ($(window).scrollTop() < max) {
            return this.element.removeClass("fixed")
        } else if ($("#left-column").height() > $("#sidebar").height()) {
            return this.element.addClass("fixed")
        }
    }
}

$.widget("korp.sidebar", Sidebar)

$.widget("korp.radioList", {
    options: {
        change: $.noop,
        separator: "|",
        selected: "default"
    },

    _create() {
        this._super()
        const self = this
        $.each(this.element, function() {
            // $.proxy(self.options.change, self.element)();
            return $(this)
                .children()
                .wrap("
")
                .click(function() {
                    if (!$(this).is(".radioList_selected")) {
                        self.select($(this).data("mode"))
                        return self._trigger("change", $(this).data("mode"))
                    }
                })
                .parent()
                .prepend($("").text(self.options.separator))
                .wrapAll("
")
        })

        this.element.find(".inline_list span:first").remove()
        return this.select(this.options.selected)
    },

    select(mode) {
        this.options.selected = mode
        const target = this.element.find("a").filter(function() {
            return $(this).data("mode") === mode
        })
        this.element.find(".radioList_selected").removeClass("radioList_selected")
        this.element.find(target).addClass("radioList_selected")
        return this.element
    },

    getSelected() {
        return this.element.find(".radioList_selected")
    }
})
<commit_msg>fix dependency tree<commit_after>/** @format */
const Sidebar = {
    _init() {},

    updateContent(sentenceData, wordData, corpus, tokens) {
        this.element.html('

')
        const corpusObj = settings.corpora[corpus]

        const corpusInfo = $("
").html(
            `<h4 rel='localize[corpus]'></h4> <p>${corpusObj.title}</p>`
        )
        corpusInfo.prependTo("#selected_sentence")

        if (corpusObj["inStrix"]) {
            const sentenceID = sentenceData["sentence_id"]
            if (sentenceID) {
                // TODO fix this so that strix uses correct corpus ids
                const strixCorpus = corpus === "wikipedia-sv" ? "wikipedia" : corpus
                const strixLinkText = `${
                    settings.strixUrl
                }?sentenceID=${sentenceID}&documentCorpus=${strixCorpus}`
                $("
")
                    .html(
                        `<a target='_blank' href='${strixLinkText}' rel='localize[read_in_strix]'></a>`
                    )
                    .prependTo(corpusInfo)
            }
        }

        const customData = { pos: [], struct: [] }
        if (!$.isEmptyObject(corpusObj.customAttributes)) {
            const [word, sentence] = this.renderCustomContent(
                wordData,
                sentenceData,
                corpusObj.customAttributes,
                tokens
            )
            customData.pos = word
            customData.struct = sentence
        }

        let posData = []
        if (!$.isEmptyObject(corpusObj.attributes)) {
            posData = this.renderCorpusContent(
                "pos",
                wordData,
                sentenceData,
                corpusObj.attributes,
                tokens,
                corpusObj.customAttributes || {},
                customData.pos
            )
        }
        let structData = []
        if (!$.isEmptyObject(corpusObj.structAttributes)) {
            structData = this.renderCorpusContent(
                "struct",
                wordData,
                sentenceData,
                corpusObj.structAttributes,
                tokens,
                corpusObj.customAttributes || {},
                customData.struct
            )
        }

        $("#selected_word").append($("
").localeKey("word_attr"))
        $("#selected_sentence").append($("
").localeKey("sentence_attr"))
        $("#selected_word").append(posData)
        $("#selected_sentence").append(structData)

        this.element.localize()
        this.applyEllipse()
        if (corpusObj.attributes.deprel) {
            this.renderGraph(tokens)
        }
    },

    renderGraph(tokens) {
        $("</button>")
            .localeKey("show_deptree")
            .click(function() {
                const outerW = $(window).width() - 80
                const info = $("")
                const iframe = $('')
                    .css("width", outerW - 40)
                    .on("load", function() {
                        const wnd = this.contentWindow
                        wnd.draw_deptree.call(wnd, tokens, function(msg) {
                            const [type, val] = _.head(_.toPairs(msg))
                            info.empty().append(
                                $("").localeKey(type),
                                $(": "),
                                $("").localeKey(`${type}_${val}`)
                            )
                        })
                    })

                $("#deptree_popup")
                    .empty()
                    .append(info, iframe)
                    .dialog({
                        height: 300,
                        width: outerW
                    })
                    .parent()
                    .find(".ui-dialog-title")
                    .localeKey("dep_tree")
            })
            .appendTo(this.element)
    },

    renderCorpusContent(
        type,
        wordData,
        sentenceData,
        corpus_attrs,
        tokens,
        customAttrs,
        customData
    ) {
        let pairs
        if (type === "struct") {
            pairs = _.toPairs(sentenceData)
        } else if (type === "pos") {
            pairs = _.toPairs(wordData)
        }

        pairs = _.filter(pairs, function(...args) {
            let [key, val] = args[0]
            return corpus_attrs[key]
        })
        pairs = _.filter(pairs, function(...args) {
            let [key, val] = args[0]
            return !(corpus_attrs[key].displayType === "hidden" || corpus_attrs[key].hideSidebar)
        })

        for (let custom of customData) {
            pairs.push(custom)
        }

        pairs.sort(function(...args) {
            let ord1, ord2
            const [a] = args[0]
            const [b] = args[1]
            if (a in corpus_attrs) {
                ord1 = corpus_attrs[a].order
            } else {
                ord1 = customAttrs[a].order
            }

            if (b in corpus_attrs) {
                ord2 = corpus_attrs[b].order
            } else {
                ord2 = customAttrs[b].order
            }

            if (_.isUndefined(ord1)) {
                ord1 = 10000
            }
            if (_.isUndefined(ord2)) {
                ord2 = 10000
            }
            return ord1 - ord2
        })

        let items = []
        for (let [key, value] of pairs) {
            if (key in customAttrs) {
                items.push(value)
            } else {
                items = items.concat(
                    (
                        this.renderItem(
                            key,
                            value,
                            corpus_attrs[key],
                            wordData,
                            sentenceData,
                            tokens
                        ) || $()
                    ).get(0) || []
                )
            }
        }

        items = _.compact(items)
        return $(items)
    },

    renderCustomContent(wordData, sentenceData, corpus_attrs, tokens) {
        const structItems = []
        const posItems = []
        for (let key in corpus_attrs) {
            const attrs = corpus_attrs[key]
            const output = (
                this.renderItem(key, "not_used", attrs, wordData, sentenceData, tokens) || $()
            ).get(0)
            if (attrs.customType === "struct") {
                structItems.push([key, output])
            } else if (attrs.customType === "pos") {
                posItems.push([key, output])
            }
        }
        return [posItems, structItems]
    },

    renderItem(key, value, attrs, wordData, sentenceData, tokens) {
        let lis, output, pattern, ul, valueArray
        let val, inner, cqpVal, li, address
        if (attrs.label) {
            output = $(`<p><span rel='localize[${attrs.label}]'></span>: </p>`)
        } else {
            output = $("

")
        }
        if (attrs.renderItem) {
            return output.append(
                attrs.renderItem(key, value, attrs, wordData, sentenceData, tokens)
            )
        }

        output.data("attrs", attrs)
        if (value === "|" || value === "" || value === null) {
            output.append(
                `<i rel='localize[empty]' style='color : grey'>${util.getLocaleString("empty")}</i>`
            )
            return output
        }

        if (attrs.type === "set" && attrs.display && attrs.display.expandList) {
            valueArray = _.filter((value && value.split("|")) || [], Boolean)
            const attrSettings = attrs.display.expandList
            if (attrs.ranked) {
                valueArray = _.map(valueArray, function(value) {
                    val = value.split(":")
                    return [val[0], val[val.length - 1]]
                })

                lis = []

                for (let outerIdx = 0; outerIdx < valueArray.length; outerIdx++) {
                    var externalLink
                    let [value, prob] = valueArray[outerIdx]
                    li = $("

")
                    const subValues = attrSettings.splitValue
                        ? attrSettings.splitValue(value)
                        : [value]
                    for (let idx = 0; idx < subValues.length; idx++) {
                        const subValue = subValues[idx]
                        val = (attrs.stringify || attrSettings.stringify || _.identity)(subValue)
                        inner = $(`<span>${val}</span>`)
                        inner.attr("title", prob)

                        if (
                            attrs.internalSearch &&
                            (attrSettings.linkAllValues || outerIdx === 0)
                        ) {
                            inner.data("key", subValue)
                            inner.addClass("link").click(function() {
                                const searchKey = attrSettings.searchKey || key
                                cqpVal = $(this).data("key")
                                const cqpExpr = attrSettings.internalSearch
                                    ? attrSettings.internalSearch(searchKey, cqpVal)
                                    : `[${searchKey} contains '${regescape(cqpVal)}']`
                                return locationSearch({ search: "cqp", cqp: cqpExpr, page: null })
                            })
                        }
                        if (attrs.externalSearch) {
                            address = _.template(attrs.externalSearch)({ val: subValue })
                            externalLink = $(
                                `<a href='${address}' class='external_link' target='_blank' style='margin-top: -6px'></a>`
                            )
                        }

                        li.append(inner)
                        if (attrSettings.joinValues && idx !== subValues.length - 1) {
                            li.append(attrSettings.joinValues)
                        }
                    }
                    if (externalLink) {
                        li.append(externalLink)
                    }
                    lis.push(li)
                }
            } else {
                lis = []
                for (value of valueArray) {
                    li = $("

")
                    li.append(value)
                    lis.push(li)
                }
            }

            if (lis.length === 0) {
                ul = $('')
            } else {
                ul = $("
")
                ul.append(lis)

                if (lis.length !== 1 && !attrSettings.showAll) {
                    _.map(lis, function(li, idx) {
                        if (idx !== 0) {
                            return li.css("display", "none")
                        }
                    })

                    const showAll = $(
                        ` (${lis.length -
                            1})`
                    )
                    ul.append(showAll)

                    const showOne = $(
                        ""
                    )
                    showOne.css("display", "none")
                    ul.append(showOne)

                    showAll.click(function() {
                        showAll.css("display", "none")
                        showOne.css("display", "inline")
                        return _.map(lis, li => li.css("display", "list-item"))
                    })

                    showOne.click(function() {
                        showAll.css("display", "inline")
                        showOne.css("display", "none")
                        _.map(lis, function(li, i) {
                            if (i !== 0) {
                                return li.css("display", "none")
                            }
                        })
                    })
                }
            }

            output.append(ul)
            return output
        } else if (attrs.type === "set") {
            pattern = attrs.pattern || '<span data-key="<%= key %>"><%= val %>'
            ul = $("
")
            const getStringVal = str =>
                _.reduce(
                    _.invokeMap(_.invokeMap(str, "charCodeAt", 0), "toString"),
                    (a, b) => a + b
                )
            valueArray = _.filter((value && value.split("|")) || [], Boolean)
            if (key === "variants") {
                // TODO: this doesn't sort quite as expected
                valueArray.sort(function(a, b) {
                    const splita = util.splitLemgram(a)
                    const splitb = util.splitLemgram(b)
                    const strvala =
                        getStringVal(splita.form) + splita.index + getStringVal(splita.pos)
                    const strvalb =
                        getStringVal(splitb.form) + splitb.index + getStringVal(splitb.pos)

                    return parseInt(strvala) - parseInt(strvalb)
                })
            }

            const itr = _.isArray(valueArray) ? valueArray : _.values(valueArray)
            const lis = []
            for (let x of itr) {
                if (x.length) {
                    val = (attrs.stringify || _.identity)(x)

                    inner = $(_.template(pattern)({ key: x, val }))
                    if (attrs.translationKey != null) {
                        const prefix = attrs.translationKey || ""
                        inner.localeKey(prefix + val)
                    }

                    if (attrs.internalSearch) {
                        inner.addClass("link").click(function() {
                            cqpVal = $(this).data("key")
                            return locationSearch({
                                page: null,
                                search: "cqp",
                                cqp: `[${key} contains \"${regescape(cqpVal)}\"]`
                            })
                        })
                    }

                    li = $("

")
                        .data("key", x)
                        .append(inner)
                    if (attrs.externalSearch) {
                        address = _.template(attrs.externalSearch)({ val: x })
                        li.append(
                            $(`<a href='${address}' class='external_link' target='_blank'></a>`)
                        )
                    }

                    lis.push(li)
                }
            }
            ul.append(lis)
            output.append(ul)

            return output
        }

        const str_value = (attrs.stringify || _.identity)(value)

        if (attrs.type === "url") {
            return output.append(
                `${decodeURI(
                    str_value
                )}`
            )
        } else if (key === "msd") {
            // msdTags = require '../markup/msdtags.html'
            const msdTags = "markup/msdtags.html"
            return output.append(`${str_value}

                \
            `)
        } else if (attrs.pattern) {
            return output.append(
                _.template(attrs.pattern)({
                    key,
                    val: str_value,
                    pos_attrs: wordData,
                    struct_attrs: sentenceData
                })
            )
        } else {
            if (attrs.translationKey) {
                if (window.loc_data["en"][attrs.translationKey + value]) {
                    return output.append(
                        `<span rel='localize[${attrs.translationKey}${value}]'></span>`
                    )
                } else {
                    return output.append(`<span>${value}</span>`)
                }
            } else {
                return output.append(`<span>${str_value || ""}</span>`)
            }
        }
    },

    applyEllipse() {
        // oldDisplay = @element.css("display")
        // @element.css "display", "block"
        const totalWidth = this.element.width()

        // ellipse for too long links of type=url
        this.element
            .find(".sidebar_url")
            .css("white-space", "nowrap")
            .each(function() {
                while ($(this).width() > totalWidth) {
                    const oldtext = $(this).text()
                    const a = _.trim(oldtext, "/")
                        .replace("...", "")
                        .split("/")
                    const domain = a.slice(2, 3)
                    let midsection = a.slice(3).join("/")
                    midsection = `...${midsection.slice(2)}`
                    $(this).text(["http:/"].concat(domain, midsection).join("/"))
                    if (midsection === "...") {
                        break
                    }
                }
            })
    },

    updatePlacement() {
        const max = Math.round($("#columns").position().top)
        if ($(window).scrollTop() < max) {
            return this.element.removeClass("fixed")
        } else if ($("#left-column").height() > $("#sidebar").height()) {
            return this.element.addClass("fixed")
        }
    }
}

$.widget("korp.sidebar", Sidebar)

$.widget("korp.radioList", {
    options: {
        change: $.noop,
        separator: "|",
        selected: "default"
    },

    _create() {
        this._super()
        const self = this
        $.each(this.element, function() {
            // $.proxy(self.options.change, self.element)();
            return $(this)
                .children()
                .wrap("
")
                .click(function() {
                    if (!$(this).is(".radioList_selected")) {
                        self.select($(this).data("mode"))
                        return self._trigger("change", $(this).data("mode"))
                    }
                })
                .parent()
                .prepend($("").text(self.options.separator))
                .wrapAll("
")
        })

        this.element.find(".inline_list span:first").remove()
        return this.select(this.options.selected)
    },

    select(mode) {
        this.options.selected = mode
        const target = this.element.find("a").filter(function() {
            return $(this).data("mode") === mode
        })
        this.element.find(".radioList_selected").removeClass("radioList_selected")
        this.element.find(target).addClass("radioList_selected")
        return this.element
    },

    getSelected() {
        return this.element.find(".radioList_selected")
    }
})
<|endoftext|>


<commit_before>;(function (factory) {
    if (typeof module === "object" && typeof module.exports === "object") {
        factory(require('jquery'), window, document);
    } else {
        factory(window.jQuery, window, document);
    }
}(function ( $, window, document, undefined ) {

    /**
     * Calculate scrollbar width
     *
     * Called only once as a constant variable: we assume that scrollbar width never change
     *
     * Original function by Jonathan Sharp:
     * http://jdsharp.us/jQuery/minute/calculate-scrollbar-width.php
     */
    var SCROLLBAR_WIDTH;

    function scrollbarWidth () {
        // Append a temporary scrolling element to the DOM, then measure
        // the difference between its outer and inner elements.
        var tempEl  = $('

'),
            width   = 0,
            widthMinusScrollbars = 0;

        $('body').append(tempEl);

        width = $(tempEl).innerWidth(),
        widthMinusScrollbars = $('div', tempEl).innerWidth();

        tempEl.remove();

        return (width - widthMinusScrollbars);
    }

    var IS_WEBKIT = 'WebkitAppearance' in document.documentElement.style;

    // SimpleBar Constructor
    function SimpleBar (element, options) {
        this.el = element,
        this.$el = $(element),
        this.$track,
        this.$scrollbar,
        this.dragOffset,
        this.flashTimeout,
        this.$contentEl         = this.$el,
        this.$scrollContentEl   = this.$el,
        this.scrollDirection    = 'vert',
        this.scrollOffsetAttr   = 'scrollTop',
        this.sizeAttr           = 'height',
        this.scrollSizeAttr     = 'scrollHeight',
        this.offsetAttr         = 'top';

        this.options = $.extend({}, SimpleBar.DEFAULTS, options);

        this.init();
    }

    SimpleBar.DEFAULTS = {
        wrapContent: true,
        autoHide: true
    };

    SimpleBar.prototype.init = function () {
        // Measure scrollbar width
        if(typeof SCROLLBAR_WIDTH === 'undefined') {
            SCROLLBAR_WIDTH = scrollbarWidth();
        }

        // If scrollbar is a floating scrollbar, disable the plugin
        if(SCROLLBAR_WIDTH === 0) {
          this.$el.css('overflow', 'auto');

          return;
        }

        if (this.$el.data('simplebar-direction') === 'horizontal' || this.$el.hasClass('simplebar horizontal')) {
            this.scrollDirection    = 'horiz';
            this.scrollOffsetAttr   = 'scrollLeft';
            this.sizeAttr           = 'width';
            this.scrollSizeAttr     = 'scrollWidth';
            this.offsetAttr         = 'left';
        }

        if (this.options.wrapContent) {
            this.$el.wrapInner('

');
        }

        this.$contentEl = this.$el.find('.simplebar-content');

        this.$el.prepend('

');
        this.$track = this.$el.find('.simplebar-track');
        this.$scrollbar = this.$el.find('.simplebar-scrollbar');

        this.$scrollContentEl = this.$el.find('.simplebar-scroll-content');

        this.resizeScrollContent();

        if (this.options.autoHide) {
            this.$el.on('mouseenter', $.proxy(this.flashScrollbar, this));
        }

        this.$scrollbar.on('mousedown', $.proxy(this.startDrag, this));
        this.$scrollContentEl.on('scroll', $.proxy(this.startScroll, this));

        this.resizeScrollbar();

        if (!this.options.autoHide) {
            this.showScrollbar();
        }
    };

    /**
     * Start scrollbar handle drag
     */
    SimpleBar.prototype.startDrag = function (e) {
        // Preventing the event's default action stops text being
        // selectable during the drag.
        e.preventDefault();

        // Measure how far the user's mouse is from the top of the scrollbar drag handle.
        var eventOffset = e.pageY;
        if (this.scrollDirection === 'horiz') {
            eventOffset = e.pageX;
        }
        this.dragOffset = eventOffset - this.$scrollbar.offset()[this.offsetAttr];

        $(document).on('mousemove', $.proxy(this.drag, this));
        $(document).on('mouseup', $.proxy(this.endDrag, this));
    };

    /**
     * Drag scrollbar handle
     */
    SimpleBar.prototype.drag = function (e) {
        e.preventDefault();

        // Calculate how far the user's mouse is from the top/left of the scrollbar (minus the dragOffset).
        var eventOffset = e.pageY,
            dragPos     = null,
            dragPerc    = null,
            scrollPos   = null;

        if (this.scrollDirection === 'horiz') {
          eventOffset = e.pageX;
        }

        dragPos = eventOffset - this.$track.offset()[this.offsetAttr] - this.dragOffset;
        // Convert the mouse position into a percentage of the scrollbar height/width.
        dragPerc = dragPos / this.$track[this.sizeAttr]();
        // Scroll the content by the same percentage.
        scrollPos = dragPerc * this.$contentEl[0][this.scrollSizeAttr];

        this.$scrollContentEl[this.scrollOffsetAttr](scrollPos);
    };

    /**
     * End scroll handle drag
     */
    SimpleBar.prototype.endDrag = function () {
        $(document).off('mousemove', this.drag);
        $(document).off('mouseup', this.endDrag);
    };

    /**
     * Resize scrollbar
     */
    SimpleBar.prototype.resizeScrollbar = function () {
        if(SCROLLBAR_WIDTH === 0) {
            return;
        }

        var contentSize     = this.$contentEl[0][this.scrollSizeAttr],
            scrollOffset    = this.$scrollContentEl[this.scrollOffsetAttr](), // Either scrollTop() or scrollLeft().
            scrollbarSize   = this.$track[this.sizeAttr](),
            scrollbarRatio  = scrollbarSize / contentSize,
            // Calculate new height/position of drag handle.
            // Offset of 2px allows for a small top/bottom or left/right margin around handle.
            handleOffset    = Math.round(scrollbarRatio * scrollOffset) + 2,
            handleSize      = Math.floor(scrollbarRatio * (scrollbarSize - 2)) - 2;

        if (scrollbarSize < contentSize) {
            if (this.scrollDirection === 'vert'){
                this.$scrollbar.css({'top': handleOffset, 'height': handleSize});
            } else {
                this.$scrollbar.css({'left': handleOffset, 'width': handleSize});
            }
            this.$track.show();
        } else {
            this.$track.hide();
        }
    };

    /**
     * On scroll event handling
     */
    SimpleBar.prototype.startScroll = function(e) {
        // Simulate event bubbling to root element
        this.$el.trigger(e);

        this.flashScrollbar();
    };

    /**
     * Flash scrollbar visibility
     */
    SimpleBar.prototype.flashScrollbar = function () {
        this.resizeScrollbar();
        this.showScrollbar();
    };

    /**
     * Show scrollbar
     */
    SimpleBar.prototype.showScrollbar = function () {
        this.$scrollbar.addClass('visible');

        if (!this.options.autoHide) {
            return;
        }
        if(typeof this.flashTimeout === 'number') {
            window.clearTimeout(this.flashTimeout);
        }

        this.flashTimeout = window.setTimeout($.proxy(this.hideScrollbar, this), 1000);
    };

    /**
     * Hide Scrollbar
     */
    SimpleBar.prototype.hideScrollbar = function () {
        this.$scrollbar.removeClass('visible');
        if(typeof this.flashTimeout === 'number') {
            window.clearTimeout(this.flashTimeout);
        }
    };

    /**
     * Resize content element
     */
    SimpleBar.prototype.resizeScrollContent = function () {
        if (IS_WEBKIT) {
            return;
        }

        if (this.scrollDirection === 'vert'){
            this.$scrollContentEl.width(this.$el.width()+SCROLLBAR_WIDTH);
            this.$scrollContentEl.height(this.$el.height());
        } else {
            this.$scrollContentEl.width(this.$el.width());
            this.$scrollContentEl.height(this.$el.height()+SCROLLBAR_WIDTH);
        }
    };

    /**
     * Recalculate scrollbar
     */
    SimpleBar.prototype.recalculate = function () {
        this.resizeScrollContent();
        this.resizeScrollbar();
    };

    /**
     * Getter for original scrolling element
     */
    SimpleBar.prototype.getScrollElement = function () {
        return this.$scrollContentEl;
    };

    /**
     * Getter for content element
     */
    SimpleBar.prototype.getContentElement = function () {
        return this.$contentEl;
    };

    /**
     * Data API
     */
    $(window).on('load', function () {
        $('[data-simplebar-direction]').each(function () {
            $(this).simplebar();
        });
    });

    /**
     * Plugin definition
     */
    var old = $.fn.simplebar;

    $.fn.simplebar = function (options) {
        var args = arguments,
            returns;

        // If the first parameter is an object (options), or was omitted,
        // instantiate a new instance of the plugin.
        if (typeof options === 'undefined' || typeof options === 'object') {
            return this.each(function () {

                // Only allow the plugin to be instantiated once,
                // so we check that the element has no plugin instantiation yet
                if (!$.data(this, 'simplebar')) { $.data(this, 'simplebar', new SimpleBar(this, options)); }
            });

        // If the first parameter is a string
        // treat this as a call to a public method.
        } else if (typeof options === 'string') {
            this.each(function () {
                var instance = $.data(this, 'simplebar');

                // Tests that there's already a plugin-instance
                // and checks that the requested public method exists
                if (instance instanceof SimpleBar && typeof instance[options] === 'function') {

                    // Call the method of our plugin instance,
                    // and pass it the supplied arguments.
                    returns = instance[options].apply( instance, Array.prototype.slice.call( args, 1 ) );
                }

                // Allow instances to be destroyed via the 'destroy' method
                if (options === 'destroy') {
                  $.data(this, 'simplebar', null);
                }
            });

            // If the earlier cached method
            // gives a value back return the value,
            // otherwise return this to preserve chainability.
            return returns !== undefined ? returns : this;
        }
    };

    $.fn.simplebar.Constructor = SimpleBar;

    /**
     * No conflict
     */
    $.fn.simplebar.noConflict = function () {
        $.fn.simplebar = old;
        return this;
    };

}));
<commit_msg>fix jshint issue<commit_after>;(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        factory(require('jquery'), window, document);
    } else {
        factory(window.jQuery, window, document);
    }
}(function ( $, window, document, undefined ) {

    /**
     * Calculate scrollbar width
     *
     * Called only once as a constant variable: we assume that scrollbar width never change
     *
     * Original function by Jonathan Sharp:
     * http://jdsharp.us/jQuery/minute/calculate-scrollbar-width.php
     */
    var SCROLLBAR_WIDTH;

    function scrollbarWidth () {
        // Append a temporary scrolling element to the DOM, then measure
        // the difference between its outer and inner elements.
        var tempEl  = $('

'),
            width   = 0,
            widthMinusScrollbars = 0;

        $('body').append(tempEl);

        width = $(tempEl).innerWidth(),
        widthMinusScrollbars = $('div', tempEl).innerWidth();

        tempEl.remove();

        return (width - widthMinusScrollbars);
    }

    var IS_WEBKIT = 'WebkitAppearance' in document.documentElement.style;

    // SimpleBar Constructor
    function SimpleBar (element, options) {
        this.el = element,
        this.$el = $(element),
        this.$track,
        this.$scrollbar,
        this.dragOffset,
        this.flashTimeout,
        this.$contentEl         = this.$el,
        this.$scrollContentEl   = this.$el,
        this.scrollDirection    = 'vert',
        this.scrollOffsetAttr   = 'scrollTop',
        this.sizeAttr           = 'height',
        this.scrollSizeAttr     = 'scrollHeight',
        this.offsetAttr         = 'top';

        this.options = $.extend({}, SimpleBar.DEFAULTS, options);

        this.init();
    }

    SimpleBar.DEFAULTS = {
        wrapContent: true,
        autoHide: true
    };

    SimpleBar.prototype.init = function () {
        // Measure scrollbar width
        if(typeof SCROLLBAR_WIDTH === 'undefined') {
            SCROLLBAR_WIDTH = scrollbarWidth();
        }

        // If scrollbar is a floating scrollbar, disable the plugin
        if(SCROLLBAR_WIDTH === 0) {
          this.$el.css('overflow', 'auto');

          return;
        }

        if (this.$el.data('simplebar-direction') === 'horizontal' || this.$el.hasClass('simplebar horizontal')) {
            this.scrollDirection    = 'horiz';
            this.scrollOffsetAttr   = 'scrollLeft';
            this.sizeAttr           = 'width';
            this.scrollSizeAttr     = 'scrollWidth';
            this.offsetAttr         = 'left';
        }

        if (this.options.wrapContent) {
            this.$el.wrapInner('

');
        }

        this.$contentEl = this.$el.find('.simplebar-content');

        this.$el.prepend('

');
        this.$track = this.$el.find('.simplebar-track');
        this.$scrollbar = this.$el.find('.simplebar-scrollbar');

        this.$scrollContentEl = this.$el.find('.simplebar-scroll-content');

        this.resizeScrollContent();

        if (this.options.autoHide) {
            this.$el.on('mouseenter', $.proxy(this.flashScrollbar, this));
        }

        this.$scrollbar.on('mousedown', $.proxy(this.startDrag, this));
        this.$scrollContentEl.on('scroll', $.proxy(this.startScroll, this));

        this.resizeScrollbar();

        if (!this.options.autoHide) {
            this.showScrollbar();
        }
    };

    /**
     * Start scrollbar handle drag
     */
    SimpleBar.prototype.startDrag = function (e) {
        // Preventing the event's default action stops text being
        // selectable during the drag.
        e.preventDefault();

        // Measure how far the user's mouse is from the top of the scrollbar drag handle.
        var eventOffset = e.pageY;
        if (this.scrollDirection === 'horiz') {
            eventOffset = e.pageX;
        }
        this.dragOffset = eventOffset - this.$scrollbar.offset()[this.offsetAttr];

        $(document).on('mousemove', $.proxy(this.drag, this));
        $(document).on('mouseup', $.proxy(this.endDrag, this));
    };

    /**
     * Drag scrollbar handle
     */
    SimpleBar.prototype.drag = function (e) {
        e.preventDefault();

        // Calculate how far the user's mouse is from the top/left of the scrollbar (minus the dragOffset).
        var eventOffset = e.pageY,
            dragPos     = null,
            dragPerc    = null,
            scrollPos   = null;

        if (this.scrollDirection === 'horiz') {
          eventOffset = e.pageX;
        }

        dragPos = eventOffset - this.$track.offset()[this.offsetAttr] - this.dragOffset;
        // Convert the mouse position into a percentage of the scrollbar height/width.
        dragPerc = dragPos / this.$track[this.sizeAttr]();
        // Scroll the content by the same percentage.
        scrollPos = dragPerc * this.$contentEl[0][this.scrollSizeAttr];

        this.$scrollContentEl[this.scrollOffsetAttr](scrollPos);
    };

    /**
     * End scroll handle drag
     */
    SimpleBar.prototype.endDrag = function () {
        $(document).off('mousemove', this.drag);
        $(document).off('mouseup', this.endDrag);
    };

    /**
     * Resize scrollbar
     */
    SimpleBar.prototype.resizeScrollbar = function () {
        if(SCROLLBAR_WIDTH === 0) {
            return;
        }

        var contentSize     = this.$contentEl[0][this.scrollSizeAttr],
            scrollOffset    = this.$scrollContentEl[this.scrollOffsetAttr](), // Either scrollTop() or scrollLeft().
            scrollbarSize   = this.$track[this.sizeAttr](),
            scrollbarRatio  = scrollbarSize / contentSize,
            // Calculate new height/position of drag handle.
            // Offset of 2px allows for a small top/bottom or left/right margin around handle.
            handleOffset    = Math.round(scrollbarRatio * scrollOffset) + 2,
            handleSize      = Math.floor(scrollbarRatio * (scrollbarSize - 2)) - 2;

        if (scrollbarSize < contentSize) {
            if (this.scrollDirection === 'vert'){
                this.$scrollbar.css({'top': handleOffset, 'height': handleSize});
            } else {
                this.$scrollbar.css({'left': handleOffset, 'width': handleSize});
            }
            this.$track.show();
        } else {
            this.$track.hide();
        }
    };

    /**
     * On scroll event handling
     */
    SimpleBar.prototype.startScroll = function(e) {
        // Simulate event bubbling to root element
        this.$el.trigger(e);

        this.flashScrollbar();
    };

    /**
     * Flash scrollbar visibility
     */
    SimpleBar.prototype.flashScrollbar = function () {
        this.resizeScrollbar();
        this.showScrollbar();
    };

    /**
     * Show scrollbar
     */
    SimpleBar.prototype.showScrollbar = function () {
        this.$scrollbar.addClass('visible');

        if (!this.options.autoHide) {
            return;
        }
        if(typeof this.flashTimeout === 'number') {
            window.clearTimeout(this.flashTimeout);
        }

        this.flashTimeout = window.setTimeout($.proxy(this.hideScrollbar, this), 1000);
    };

    /**
     * Hide Scrollbar
     */
    SimpleBar.prototype.hideScrollbar = function () {
        this.$scrollbar.removeClass('visible');
        if(typeof this.flashTimeout === 'number') {
            window.clearTimeout(this.flashTimeout);
        }
    };

    /**
     * Resize content element
     */
    SimpleBar.prototype.resizeScrollContent = function () {
        if (IS_WEBKIT) {
            return;
        }

        if (this.scrollDirection === 'vert'){
            this.$scrollContentEl.width(this.$el.width()+SCROLLBAR_WIDTH);
            this.$scrollContentEl.height(this.$el.height());
        } else {
            this.$scrollContentEl.width(this.$el.width());
            this.$scrollContentEl.height(this.$el.height()+SCROLLBAR_WIDTH);
        }
    };

    /**
     * Recalculate scrollbar
     */
    SimpleBar.prototype.recalculate = function () {
        this.resizeScrollContent();
        this.resizeScrollbar();
    };

    /**
     * Getter for original scrolling element
     */
    SimpleBar.prototype.getScrollElement = function () {
        return this.$scrollContentEl;
    };

    /**
     * Getter for content element
     */
    SimpleBar.prototype.getContentElement = function () {
        return this.$contentEl;
    };

    /**
     * Data API
     */
    $(window).on('load', function () {
        $('[data-simplebar-direction]').each(function () {
            $(this).simplebar();
        });
    });

    /**
     * Plugin definition
     */
    var old = $.fn.simplebar;

    $.fn.simplebar = function (options) {
        var args = arguments,
            returns;

        // If the first parameter is an object (options), or was omitted,
        // instantiate a new instance of the plugin.
        if (typeof options === 'undefined' || typeof options === 'object') {
            return this.each(function () {

                // Only allow the plugin to be instantiated once,
                // so we check that the element has no plugin instantiation yet
                if (!$.data(this, 'simplebar')) { $.data(this, 'simplebar', new SimpleBar(this, options)); }
            });

        // If the first parameter is a string
        // treat this as a call to a public method.
        } else if (typeof options === 'string') {
            this.each(function () {
                var instance = $.data(this, 'simplebar');

                // Tests that there's already a plugin-instance
                // and checks that the requested public method exists
                if (instance instanceof SimpleBar && typeof instance[options] === 'function') {

                    // Call the method of our plugin instance,
                    // and pass it the supplied arguments.
                    returns = instance[options].apply( instance, Array.prototype.slice.call( args, 1 ) );
                }

                // Allow instances to be destroyed via the 'destroy' method
                if (options === 'destroy') {
                  $.data(this, 'simplebar', null);
                }
            });

            // If the earlier cached method
            // gives a value back return the value,
            // otherwise return this to preserve chainability.
            return returns !== undefined ? returns : this;
        }
    };

    $.fn.simplebar.Constructor = SimpleBar;

    /**
     * No conflict
     */
    $.fn.simplebar.noConflict = function () {
        $.fn.simplebar = old;
        return this;
    };

}));
<|endoftext|>


<commit_before>var request = require('request'),
    async = require('async'),
    _ = require('underscore'),
    striptags = require('striptags');

module.exports = function () {
    var self = this,
    queryBuilds = function (callback) {
        requestBuilds(function (error, body) {
            if (error) {
                callback(error);
                return;
            }

            async.map(body, requestBuild, function (error, results) {
                callback(error, results);
            });
        });
    },
    requestBuilds = function (callback) {
        var planUri = self.configuration.url + "/rest/api/latest/result/" + self.configuration.planKey + ".json";
        var urlParams = {
            "os_authType": "basic"
        };

        request({ uri: planUri, qs: urlParams }, function(error, response, body) {
            try {
                var bodyJson = JSON.parse(body);
                callback(error, bodyJson.results.result);
            } catch (parseError) {
                callback(parseError, null);
            }
        });
    },
    requestBuild = function (build, callback) {
        var planUri = self.configuration.url + "/rest/api/latest/result/" + self.configuration.planKey + "/" + build.number + ".json";
        var urlParams = {
            "os_authType": "basic"
        };
        request({ uri: planUri, qs: urlParams }, function(error, response, body) {
            if (error) {
                callback(error);
                return;
            }
            try {
                var bodyJson = JSON.parse(body);
                callback(error, simplifyBuild(bodyJson));
            } catch (parseError) {
                callback(parseError, null);
            }
        });
    },
    simplifyBuild = function (res) {
        return {
            id: self.configuration.slug + '|' + res.number,
            project: res.plan.shortName,
            number: res.number,
            isRunning: res.state === 'started',
            startedAt: res.buildStartedTime,
            finishedAt: res.buildCompletedTime,
            requestedFor: getAuthors(res.buildReason),
            status: getStatus(res.state),
            statusText: res.state,
            reason: striptags(res.buildReason),
            hasErrors: !res.successful,
            hasWarnings: !res.successful,
            url: self.configuration.url + '/browse/' + res.buildResultKey
        };
    },
    getAuthors = function(reason) {
        var urlRegex = /<a[^>]*>([\s\S]*?)<\/a>/g;
        var links = reason.match(urlRegex);
        if (links !== null) {
            return links.map(
                function(url) {
                    return striptags(url);
                }
            ).join(', ');
        }
        return 'System';
    },
    getStatus = function(state) {
        if (state === 'started') return "Blue";
        if (state === 'created') return "Blue";
        if (state === 'canceled') return "Gray";
        if (state === 'Failed') return "Red";
        return "Green";
    };

    self.cache = {
        expires: 0,
        projects: {}
    };

    self.configure = function (config) {
        self.configuration = config;

        if (config.username && config.password) {
            var protocol = config.url.match(/(^|\s)(https?:\/\/)/i);
            if (_.isArray(protocol)) {
                protocol = _.first(protocol);
                var url = config.url.substr(protocol.length);
                host = protocol + config.username + ":" + config.password + "@" + url;
            }
        }
        self.configuration.url = host || config.url;
    };

    self.check = function (callback) {
        queryBuilds(callback);
    };
};
<commit_msg>remove unnecessary dependency on underscore<commit_after>var request = require('request'),
    async = require('async'),
    striptags = require('striptags');

module.exports = function () {
    var self = this,
    queryBuilds = function (callback) {
        requestBuilds(function (error, body) {
            if (error) {
                callback(error);
                return;
            }

            async.map(body, requestBuild, function (error, results) {
                callback(error, results);
            });
        });
    },
    requestBuilds = function (callback) {
        var planUri = self.configuration.url + "/rest/api/latest/result/" + self.configuration.planKey + ".json";
        var urlParams = {
            "os_authType": "basic"
        };

        request({ uri: planUri, qs: urlParams }, function(error, response, body) {
            try {
                var bodyJson = JSON.parse(body);
                callback(error, bodyJson.results.result);
            } catch (parseError) {
                callback(parseError, null);
            }
        });
    },
    requestBuild = function (build, callback) {
        var planUri = self.configuration.url + "/rest/api/latest/result/" + self.configuration.planKey + "/" + build.number + ".json";
        var urlParams = {
            "os_authType": "basic"
        };
        request({ uri: planUri, qs: urlParams }, function(error, response, body) {
            if (error) {
                callback(error);
                return;
            }
            try {
                var bodyJson = JSON.parse(body);
                callback(error, simplifyBuild(bodyJson));
            } catch (parseError) {
                callback(parseError, null);
            }
        });
    },
    simplifyBuild = function (res) {
        return {
            id: self.configuration.slug + '|' + res.number,
            project: res.plan.shortName,
            number: res.number,
            isRunning: res.state === 'started',
            startedAt: res.buildStartedTime,
            finishedAt: res.buildCompletedTime,
            requestedFor: getAuthors(res.buildReason),
            status: getStatus(res.state),
            statusText: res.state,
            reason: striptags(res.buildReason),
            hasErrors: !res.successful,
            hasWarnings: !res.successful,
            url: self.configuration.url + '/browse/' + res.buildResultKey
        };
    },
    getAuthors = function(reason) {
        var urlRegex = /<a[^>]*>([\s\S]*?)<\/a>/g;
        var links = reason.match(urlRegex);
        if (links !== null) {
            return links.map(
                function(url) {
                    return striptags(url);
                }
            ).join(', ');
        }
        return 'System';
    },
    getStatus = function(state) {
        if (state === 'started') return "Blue";
        if (state === 'created') return "Blue";
        if (state === 'canceled') return "Gray";
        if (state === 'Failed') return "Red";
        return "Green";
    };

    self.cache = {
        expires: 0,
        projects: {}
    };

    self.configure = function (config) {
        self.configuration = config;

        if (config.username && config.password) {
            var protocol = config.url.match(/(^|\s)(https?:\/\/)/i);
            if (Array.isArray(protocol)) {
                protocol = protocol[0];
                var url = config.url.substr(protocol.length);
                host = protocol + config.username + ":" + config.password + "@" + url;
            }
        }
        self.configuration.url = host || config.url;
    };

    self.check = function (callback) {
        queryBuilds(callback);
    };
};
<|endoftext|>


<commit_before>/*
 * moment_business (v1.0.1)
 * https://github.com/DaveTian/moment_business
 * The MIT License (MIT)
 * (c) 2014-2015 Zenefits
 */

var US_FEDERAL_HOLIDAYS = [
  "2013-1-1", "2013-1-21", "2013-2-18", "2013-5-27", "2013-7-4", "2013-9-2", "2013-10-14", "2013-11-11", "2013-11-28", "2013-12-25",
  "2014-1-1", "2014-1-20", "2014-2-17", "2014-5-26", "2014-7-4", "2014-9-1", "2014-10-13", "2014-11-11", "2014-11-27", "2014-12-25",
  "2015-1-1", "2015-1-19", "2015-2-16", "2015-5-25", "2015-7-3", "2015-9-7", "2015-10-12", "2015-11-11", "2015-11-26", "2015-12-25",
  "2016-1-1", "2016-1-18", "2016-2-15", "2016-5-30", "2016-7-4", "2016-9-5", "2016-10-10", "2016-11-11", "2016-11-24", "2016-12-26",
  "2017-1-2", "2017-1-16", "2017-2-20", "2017-5-29", "2017-7-4", "2017-9-4", "2017-10-9",  "2017-11-10", "2017-11-23", "2017-12-25",
  "2018-1-1", "2018-1-15", "2018-2-19", "2018-5-28", "2018-7-4", "2018-9-3", "2018-10-8",  "2018-11-12", "2018-11-22", "2018-12-25",
  "2019-1-1", "2019-1-21", "2019-2-18", "2019-5-27", "2019-7-4", "2019-9-2", "2019-10-14", "2019-11-11", "2019-11-28", "2019-12-25",
  "2020-1-1", "2020-1-20", "2020-2-17", "2020-5-25", "2020-7-3", "2020-9-7", "2020-10-12", "2020-11-11", "2020-11-26", "2020-12-25",
  // More Years? Need to check moment timezone version
];

(function () {
	var moment;
	moment = this.moment;

	/**
	 * Find holidays between two moment date
	 *
	 * @param {moment} moment_date The end date
	 * @returns {Array}
	 */
	moment.fn.holidaysBetween = function(moment_date) {
		var start_day = moment.min(moment_date, this);
		var end_day = moment.max(moment_date, this);
		var holidays = [];

		if (start_day.isSame(end_day, 'day') === true) {
			return holidays;
		}

		for (var i = 0; i < US_FEDERAL_HOLIDAYS.length; i++) {
			var current_holiday = moment(US_FEDERAL_HOLIDAYS[i], 'YYYY-MM-DD');
			if (current_holiday.isAfter(end_day)) {
				return holidays;
			}
			else if (current_holiday.isAfter(start_day)) {
				holidays.push(current_holiday);
			}
		}

		return holidays;
	};

	/**
	 * Calculate number(s) of holidays between two moment date
	 *
	 * @param {moment} moment_date
	 * @returns {number} number of holidays between the two moment date
	 *                   0 - if moment() is the same day as @param moment_date
	 *                   positive number - if moment() earlier than @param moment_date
	 *                   negative number - if @param moment_date earlier than moment()
	 */
	moment.fn.holidayDiff = function(moment_date) {
		var start_day = moment.min(this, moment_date);
		var end_day = moment.max(this, moment_date);

		if (start_day.isSame(end_day, 'day') === true) {
			return 0;
		}

		var signal = start_day.isAfter(end_day, 'day') ? -1 : 1;

		return (start_day.holidaysBetween(end_day).length) * signal;
	};

	/**
	 * Calculate number(s) of business days between two moment date
	 *
	 * @param {moment} moment_date
	 * @returns {number} number of holidays between the two moment date
	 *                   0 - if {moment} *this* is the same day as @param moment_date
	 *                   positive number - if {moment} *this* is earlier than @param moment_date
	 *                   negative number - if @param moment_date is earlier than {moment} *this*
	 */
	moment.fn.businessDiff = function (moment_date) {
		var start_day = moment.min(this, moment_date);
		var end_day = moment.max(this, moment_date);

		if (start_day.isSame(end_day, 'day') === true) {
			return 0;
		}

		var signal = start_day.isAfter(end_day, 'day') ? -1 : 1;
		var diff_days = end_day.diff(start_day, 'day');
		var head = start_day.isoWeekday();
		var tail = end_day.isoWeekday();
		var total = diff_days + head + (7 - tail);
		var weeks = total / 7;
		var workdays = weeks * 5;
		workdays -= Math.min(5, head);
		workdays -= Math.max(0, 5 - tail);
		workdays -= start_day.holidayDiff(end_day);

		return workdays >= 0 ? workdays * signal : 0;
	};

	/**
	 * Determine if {moment} *this* is week day
	 *
	 * @returns {boolean} - true if if {moment} *this* is week day
	 */
	moment.fn.isWeekday = function() {
		return this.isoWeekday() < 6;
	};

	/**
	 * Determine if {moment} *this* is Saturday or Sunday
	 *
	 * @returns {boolean} - true if {moment} *this* is Saturday or Sunday or Holiday
	 */
	moment.fn.isWeekend = function() {
		return this.isoWeekday() > 5;
	};

	/**
	 * Determine if {moment} *this* is business day
	 *
	 * @returns {boolean} - true if {moment} *this* is a business day
	 */
	moment.fn.isBusinessDay = function() {
		return (this.isoWeekday() < 6 && US_FEDERAL_HOLIDAYS.indexOf(this.format('YYYY-M-D')) === -1);
	};

	/**
	 * Find the business day which is n days from {moment} *this*
	 *
	 * @param {int} days: number of days
	 * @param {string} sign [optional]: '+' or '-'
	 * @returns {moment} - the nth business day from {moment} *this*
	 */
	moment.fn.addBusinessDay = function (days, sign) {
		if (typeof sign === 'undefined') {
			sign = '+';
		}
		else if (!(sign === '-' || sign === '+')) {
			window.console && console.error('Unknown sign (' + sign + ').');
			return;
		}
		var date = this.clone();
		var signal = sign === '+' ? 1 : -1;
		signal = days < 0 ? signal * -1 : signal;
		var offset = Math.abs(days);

		if (offset === 0){
			// If give day is holiday or weekend.
			while(!date.isBusinessDay()) {
				date = date.add(signal, 'days');
			}
		}
		else {
			while (offset !== 0) {
				date = date.add(signal, 'days');
				if(date.isBusinessDay()) {
					offset-- ;
				}
			}
		}
		return date;
	};

	/**
	 * Find the business day which is n days from {moment} *this*
	 *
	 * @param {int} days: number of days
	 * @returns {moment} - the nth business day from {moment} *this*
	 */
	moment.fn.subtractBusinessDay = function(days){
		return this.addBusinessDay(days, '-');
	};

	/**
	 * Find the next business day from {moment} *this*
	 *
	 * @returns {moment} - next business day from {moment} *this*
	 */
	moment.fn.nextBusinessDay = function() {
		var date = this.clone();
		return date.addBusinessDay(1);
	};

	/**
	 * Find the previous day from {moment} *this*
	 *
	 * @returns {moment} - previous business day from {moment} *this*
	 */
	moment.fn.previousBusinessDay = function() {
		var date = this.clone();
		return date.subtractBusinessDay(1);
	};

}).call(this);
<commit_msg>Change us holiday to constant<commit_after>/*
 * moment_business (v1.0.1)
 * https://github.com/DaveTian/moment_business
 * The MIT License (MIT)
 * (c) 2014-2015 Zenefits
 */

const US_FEDERAL_HOLIDAYS = [
  "2013-1-1", "2013-1-21", "2013-2-18", "2013-5-27", "2013-7-4", "2013-9-2", "2013-10-14", "2013-11-11", "2013-11-28", "2013-12-25",
  "2014-1-1", "2014-1-20", "2014-2-17", "2014-5-26", "2014-7-4", "2014-9-1", "2014-10-13", "2014-11-11", "2014-11-27", "2014-12-25",
  "2015-1-1", "2015-1-19", "2015-2-16", "2015-5-25", "2015-7-3", "2015-9-7", "2015-10-12", "2015-11-11", "2015-11-26", "2015-12-25",
  "2016-1-1", "2016-1-18", "2016-2-15", "2016-5-30", "2016-7-4", "2016-9-5", "2016-10-10", "2016-11-11", "2016-11-24", "2016-12-26",
  "2017-1-2", "2017-1-16", "2017-2-20", "2017-5-29", "2017-7-4", "2017-9-4", "2017-10-9",  "2017-11-10", "2017-11-23", "2017-12-25",
  "2018-1-1", "2018-1-15", "2018-2-19", "2018-5-28", "2018-7-4", "2018-9-3", "2018-10-8",  "2018-11-12", "2018-11-22", "2018-12-25",
  "2019-1-1", "2019-1-21", "2019-2-18", "2019-5-27", "2019-7-4", "2019-9-2", "2019-10-14", "2019-11-11", "2019-11-28", "2019-12-25",
  "2020-1-1", "2020-1-20", "2020-2-17", "2020-5-25", "2020-7-3", "2020-9-7", "2020-10-12", "2020-11-11", "2020-11-26", "2020-12-25",
  // More Years? Need to check moment timezone version
];

(function () {
	var moment;
	moment = this.moment;

	/**
	 * Find holidays between two moment date
	 *
	 * @param {moment} moment_date The end date
	 * @returns {Array}
	 */
	moment.fn.holidaysBetween = function(moment_date) {
		var start_day = moment.min(moment_date, this);
		var end_day = moment.max(moment_date, this);
		var holidays = [];

		if (start_day.isSame(end_day, 'day') === true) {
			return holidays;
		}

		for (var i = 0; i < US_FEDERAL_HOLIDAYS.length; i++) {
			var current_holiday = moment(US_FEDERAL_HOLIDAYS[i], 'YYYY-MM-DD');
			if (current_holiday.isAfter(end_day)) {
				return holidays;
			}
			else if (current_holiday.isAfter(start_day)) {
				holidays.push(current_holiday);
			}
		}

		return holidays;
	};

	/**
	 * Calculate number(s) of holidays between two moment date
	 *
	 * @param {moment} moment_date
	 * @returns {number} number of holidays between the two moment date
	 *                   0 - if moment() is the same day as @param moment_date
	 *                   positive number - if moment() earlier than @param moment_date
	 *                   negative number - if @param moment_date earlier than moment()
	 */
	moment.fn.holidayDiff = function(moment_date) {
		var start_day = moment.min(this, moment_date);
		var end_day = moment.max(this, moment_date);

		if (start_day.isSame(end_day, 'day') === true) {
			return 0;
		}

		var signal = start_day.isAfter(end_day, 'day') ? -1 : 1;

		return (start_day.holidaysBetween(end_day).length) * signal;
	};

	/**
	 * Calculate number(s) of business days between two moment date
	 *
	 * @param {moment} moment_date
	 * @returns {number} number of holidays between the two moment date
	 *                   0 - if {moment} *this* is the same day as @param moment_date
	 *                   positive number - if {moment} *this* is earlier than @param moment_date
	 *                   negative number - if @param moment_date is earlier than {moment} *this*
	 */
	moment.fn.businessDiff = function (moment_date) {
		var start_day = moment.min(this, moment_date);
		var end_day = moment.max(this, moment_date);

		if (start_day.isSame(end_day, 'day') === true) {
			return 0;
		}

		var signal = start_day.isAfter(end_day, 'day') ? -1 : 1;
		var diff_days = end_day.diff(start_day, 'day');
		var head = start_day.isoWeekday();
		var tail = end_day.isoWeekday();
		var total = diff_days + head + (7 - tail);
		var weeks = total / 7;
		var workdays = weeks * 5;
		workdays -= Math.min(5, head);
		workdays -= Math.max(0, 5 - tail);
		workdays -= start_day.holidayDiff(end_day);

		return workdays >= 0 ? workdays * signal : 0;
	};

	/**
	 * Determine if {moment} *this* is week day
	 *
	 * @returns {boolean} - true if if {moment} *this* is week day
	 */
	moment.fn.isWeekday = function() {
		return this.isoWeekday() < 6;
	};

	/**
	 * Determine if {moment} *this* is Saturday or Sunday
	 *
	 * @returns {boolean} - true if {moment} *this* is Saturday or Sunday or Holiday
	 */
	moment.fn.isWeekend = function() {
		return this.isoWeekday() > 5;
	};

	/**
	 * Determine if {moment} *this* is business day
	 *
	 * @returns {boolean} - true if {moment} *this* is a business day
	 */
	moment.fn.isBusinessDay = function() {
		return (this.isoWeekday() < 6 && US_FEDERAL_HOLIDAYS.indexOf(this.format('YYYY-M-D')) === -1);
	};

	/**
	 * Find the business day which is n days from {moment} *this*
	 *
	 * @param {int} days: number of days
	 * @param {string} sign [optional]: '+' or '-'
	 * @returns {moment} - the nth business day from {moment} *this*
	 */
	moment.fn.addBusinessDay = function (days, sign) {
		if (typeof sign === 'undefined') {
			sign = '+';
		}
		else if (!(sign === '-' || sign === '+')) {
			window.console && console.error('Unknown sign (' + sign + ').');
			return;
		}
		var date = this.clone();
		var signal = sign === '+' ? 1 : -1;
		signal = days < 0 ? signal * -1 : signal;
		var offset = Math.abs(days);

		if (offset === 0){
			// If give day is holiday or weekend.
			while(!date.isBusinessDay()) {
				date = date.add(signal, 'days');
			}
		}
		else {
			while (offset !== 0) {
				date = date.add(signal, 'days');
				if(date.isBusinessDay()) {
					offset-- ;
				}
			}
		}
		return date;
	};

	/**
	 * Find the business day which is n days from {moment} *this*
	 *
	 * @param {int} days: number of days
	 * @returns {moment} - the nth business day from {moment} *this*
	 */
	moment.fn.subtractBusinessDay = function(days){
		return this.addBusinessDay(days, '-');
	};

	/**
	 * Find the next business day from {moment} *this*
	 *
	 * @returns {moment} - next business day from {moment} *this*
	 */
	moment.fn.nextBusinessDay = function() {
		var date = this.clone();
		return date.addBusinessDay(1);
	};

	/**
	 * Find the previous day from {moment} *this*
	 *
	 * @returns {moment} - previous business day from {moment} *this*
	 */
	moment.fn.previousBusinessDay = function() {
		var date = this.clone();
		return date.subtractBusinessDay(1);
	};

}).call(this);
<|endoftext|>


<commit_before>var jsonHandler = require('./handler/regexp/jsonHandler');
var log = require('rsimulatorjs-log');
var simulatorResponse = require('./simulatorResponse');

module.exports = (function () {

    var logger = log.getLogger('rsimulatorjs-core.simulator');

    var defaultOptions = {
        handlers: {
            json: jsonHandler
        }
    };

     // The simulator encapsulates the simulation logic.
    var create = function (options) {
        var that = {};
        var theOptions = options || defaultOptions;

        // Returns a SimulatorResponse that matches the specified request.
        //
        // rootPath the root path on which to search recursively for matches to the specified request
        // rootRelativePath the path on which to search recursively for matches to the specified request
        // request the request
        // contentType the content type of the request, e.g. txt or xml
        that.service = function (simulatorRequest) {
            var handler;
            var responseBody;
            var theSimulatorResponse;

            logger.debug('simulatorRequest: %j', simulatorRequest);

            handler = theOptions.handlers[simulatorRequest.contentType];

            theSimulatorResponse = handler.findMatch(simulatorRequest.rootPath, simulatorRequest.rootRelativePath, simulatorRequest.request);

            if (theSimulatorResponse) {
                logger.info('simulatorResponse: %j', simulatorResponse);
            } else {
                responseBody = 'No simulatorResponse found!';
                logger.error('%j, simulatorRequest: %j', responseBody, simulatorRequest);
                theSimulatorResponse = simulatorResponse.create(responseBody);
            };

            return theSimulatorResponse;
        };

        return that;
    };

    return {
        create: create
    };

}());
<commit_msg>added config option<commit_after>var jsonHandler = require('./handler/regexp/jsonHandler');
var log = require('rsimulatorjs-log');
var simulatorResponse = require('./simulatorResponse');

module.exports = (function () {

    var logger = log.getLogger('rsimulatorjs-core.simulator');

    var defaultOptions = {
        handlers: {
            json: jsonHandler
        }
    };

     // The simulator encapsulates the simulation logic.
    var create = function (options) {
        var that = {};
        var theOptions = options || defaultOptions;

        // Returns a SimulatorResponse that matches the specified request.
        //
        // rootPath the root path on which to search recursively for matches to the specified request
        // rootRelativePath the path on which to search recursively for matches to the specified request
        // request the request
        // contentType the content type of the request, e.g. txt or xml
        that.service = function (simulatorRequest) {
            var handler;
            var responseBody;
            var theSimulatorResponse;

            logger.debug('simulatorRequest: %j', simulatorRequest);

            handler = theOptions.handlers[simulatorRequest.contentType];

            theSimulatorResponse = handler.findMatch(simulatorRequest.rootPath, simulatorRequest.rootRelativePath, simulatorRequest.request);

            if (theSimulatorResponse) {
                logger.info('simulatorResponse: %j', simulatorResponse);
            } else {
                responseBody = 'No simulatorResponse found!';
                logger.error('%j, simulatorRequest: %j', responseBody, simulatorRequest);
                theSimulatorResponse = simulatorResponse.create(responseBody);
            }

            return theSimulatorResponse;
        };

        that.setGlobalLogLevel = function (logLevel) {
            log.setGlobalLogLevel(logLevel);
        };

        return that;
    };

    return {
        create: create
    };

}());
<|endoftext|>


<commit_before>define('Mobile/SalesLogix/Views/NameEdit', [
    'dojo/_base/declare',
    'dojo/_base/lang',
    'Mobile/SalesLogix/Validator',
    'Sage/Platform/Mobile/Edit'
], function(
    declare,
    lang,
    validator,
    Edit
) {

    return declare('Mobile.SalesLogix.Views.NameEdit', [Edit], {
        //Localization
        firstNameText: 'first',
        middleNameText: 'middle',
        lastNameText: 'last',
        prefixText: 'prefix',
        prefixTitleText: 'Name Prefix',
        suffixText: 'suffix',
        suffixTitleText: 'Name Suffix',

        //View Properties
        id: 'name_edit',

        constructor: function(o) {
            lang.mixin(this, o, {
                expose: false
            });

            this.layout = [
                {
                    emptyText: '',
                    label: this.prefixText,
                    name: 'Prefix',
                    property: 'Prefix',
                    picklist: 'Name Prefix',
                    requireSelection: true,
                    title: this.prefixTitleText,
                    type: 'picklist'
                },
                {
                    name: 'FirstName',
                    property: 'FirstName',
                    label: this.firstNameText,
                    type: 'text',
                    maxTextLength: 32,
                    validator: validator.exceedsMaxTextLength
                },
                {
                    name: 'MiddleName',
                    property: 'MiddleName',
                    label: this.middleNameText,
                    type: 'text',
                    maxTextLength: 32,
                    validator: validator.exceedsMaxTextLength
                },
                {
                    name: 'LastName',
                    property: 'LastName',
                    label: this.lastNameText,
                    type: 'text',
                    maxTextLength: 32,
                    validator: validator.exceedsMaxTextLength
                },
                {
                    emptyText: '',
                    label: this.suffixText,
                    name: 'Suffix',
                    property: 'Suffix',
                    picklist: 'Name Suffix',
                    requireSelection: true,
                    title: this.suffixTitleText,
                    type: 'picklist'
                }
            ];
        }
    });
});<commit_msg>refactored to proper Edit view<commit_after>define('Mobile/SalesLogix/Views/NameEdit', [
    'dojo/_base/declare',
    'dojo/_base/lang',
    'Mobile/SalesLogix/Validator',
    'Sage/Platform/Mobile/Edit'
], function(
    declare,
    lang,
    validator,
    Edit
) {

    return declare('Mobile.SalesLogix.Views.NameEdit', [Edit], {
        //Localization
        titleText: 'Edit Name',
        firstNameText: 'first',
        middleNameText: 'middle',
        lastNameText: 'last',
        prefixText: 'prefix',
        prefixTitleText: 'Name Prefix',
        suffixText: 'suffix',
        suffixTitleText: 'Name Suffix',

        //View Properties
        id: 'name_edit',

        createLayout: function() {
            return this.layout || (this.layout = [
                {
                    emptyText: '',
                    label: this.prefixText,
                    name: 'Prefix',
                    property: 'Prefix',
                    picklist: 'Name Prefix',
                    requireSelection: true,
                    title: this.prefixTitleText,
                    type: 'picklist'
                },
                {
                    name: 'FirstName',
                    property: 'FirstName',
                    label: this.firstNameText,
                    type: 'text',
                    maxTextLength: 32,
                    validator: validator.exceedsMaxTextLength
                },
                {
                    name: 'MiddleName',
                    property: 'MiddleName',
                    label: this.middleNameText,
                    type: 'text',
                    maxTextLength: 32,
                    validator: validator.exceedsMaxTextLength
                },
                {
                    name: 'LastName',
                    property: 'LastName',
                    label: this.lastNameText,
                    type: 'text',
                    maxTextLength: 32,
                    validator: validator.exceedsMaxTextLength
                },
                {
                    emptyText: '',
                    label: this.suffixText,
                    name: 'Suffix',
                    property: 'Suffix',
                    picklist: 'Name Suffix',
                    requireSelection: true,
                    title: this.suffixTitleText,
                    type: 'picklist'
                }
            ]);
        }
    });
});<|endoftext|>