<commit_before>"use strict";

window.bmatFn = function() {
    var bmat = {};

    var disabledForms = [];

    var undoCallback = null;

    var searchCount = 0;

    // Error handling
    var _error = function(message) {
        $("#error .errorText").html(message);
        $("#error").slideDown();
    }

    $(document).ajaxError(function(e, xhr, settings, error) {
        if("responseJSON" in xhr && "error" in xhr.responseJSON) {
            _error(xhr.responseJSON.error);
        }else{
            _error("ERROR: "+error);
        }

        _enableAllForms();
    });

    window.addEventListener("error", function(e) {
        _error(e.message);
    });

    // Function that finds the form this element is in, and submits it
    var _submitParent = function() {
        $(this).parents("form").submit();
        _disableForm(this);
    };

    // And a function that disables a form
    var _disableForm = function(e) {
        $(e).parents(".block").addClass("disabled");
        $(e).parents(".block").find("input, select").attr("disabled", "disabled");
        $(e).find("input, select").attr("disabled", "disabled");
        disabledForms.push(e);
    };

    // And to enable all of them again
    var _enableAllForms = function() {
        for(var i = 0; i < disabledForms.length; i ++) {
            var f = disabledForms[i];

            $(f).parents(".block").removeClass("disabled");
            $(f).parents(".block").find("input, select").removeAttr("disabled");
        }
        disabledForms = [];
    };

    // And the undo thing
    var _displayUndo = function(message, url, payload, callback) {
        $("#undo .undoText").html(message);
        $("#undo").slideDown();

        $("#undoForm [name=obj]").val(JSON.stringify(payload));
        $("#undoForm").attr("action", url);
        undoCallback = callback;

        $("#undoForm").find("input, select").removeAttr("disabled");
    };

    // Resets all the listeners, used when a document has been changed or initially loaded
    var _update = function() {
        // Remove all the old listeners
        _clean();

        // Delete button
        $(".block .delete.button").on("click", _submitParent);
        $(".deleteForm").on("submit", function(e) {
            e.preventDefault();

            var elem = $(this);
            var id = elem.parents(".block").attr("data-id");

            //if(!confirm("Are you sure you want to delete this?")) return;

            $.post(elem.attr("action"), elem.serialize(), function(data) {
                if(data.deleted !== null) {
                    elem.parents(".block").slideUp();

                    _displayUndo("Object deleted", elem.attr("data-undo-url"), data.obj, function(dat) {
                        _replace(id, dat.type, false, true, dat.id);
                    });
                }
            });
        });

        // Inline untag button
        $(".inlineUntag.button").on("click", _submitParent);
        $(".inlineUntagForm").on("submit", function(e) {
            e.preventDefault();
            var elem = this;

            var bookmark = $(this).parents(".block").data("id");

            $.post(this.getAttribute("action"), $(this).serialize(), function(data) {
                _replace(bookmark, $(elem).parents(".block").data("taggable-type"), true);
            }, "json");

            _disableForm(this);
        });

        // Open/close button
        $(".expand.button").on("click", function() {
            if($(this).hasClass("open")) {
                $(this).parents(".block").children(".body").slideUp("fast");
                $(this).parents(".block").find(".inlineUntag").animate({"width":"0px"}, "fast");
                $(this).removeClass("open");
                _hideEditing($(this).parents(".block"));
            }else{
                $(this).parents(".block").children(".body").slideDown("fast");
                $(this).parents(".block").find(".inlineUntag").animate({"width":"16px"}, "fast");
                $(this).addClass("open");
            }
        });

        // "Add tag" entry, for generating suggestions
        $(".tagEntry").on("input", function(e) {
            var input = this;

            // Don't bother with text less than 3 characters
            if(e.target.value.length < 3) return;

            // Get the suggestion list, and set the option elemnt to contain it
            $.get("/tags/suggest/"+e.target.value, "", function(data) {
                var html = "";

                for(var i = 0; i < data.tags.length; i ++) {
                    html += "<option value='"+data.tags[i]+"'/>";
                }

                $(input).siblings("datalist").html(html);
            }, "json");
        });

        // Title editing; hides the "real title" and replaces it with the text box, or the opposite
        var _showEditing = function(e) {
            $(e).find(".noedit").hide();
            $(e).find(".edit").show();
            $(e).addClass("editing");
        };

        var _hideEditing = function(e) {
            $(e).find(".noedit").show();
            $(e).find(".edit").hide();
            $(e).removeClass("editing");
        };

        $(".editTitle").on("click", function(e) {
            var block = $(this).parents(".block");

            if(!block.hasClass("editing")) {
                _showEditing(block);
            }else{
                _hideEditing(block);
            }
        });

        // Rename and tag forms, both do the same thing and both result in updating the block
        $(".rename.button").on("click", function() {
            var form = $(this).parents(".block").find(".renameForm");
            form.submit();
            _disableForm(form);
        });
        $("form.tagForm, form.renameForm").on("submit", function(e) {
            e.preventDefault();
            var elem = this;
            $(this).find("input[name=url]").val(
                $(elem).parents(".block").find(".body input[name=url]").val()
            );

            $.post(this.getAttribute("action"), $(this).serialize(), function(data) {
                _replace($(elem).parents(".block").data("id"), $(elem).parents(".block").data("taggable-type"), true);
            }, "json");
        });

        // And the submit button for the add tag button
        $(".addTag.button").on("click", function(e) {
            $(this).parents(".block").find(".tagForm").submit();
        });
    };

    // Removes all listeners
    var _clean = function() {
        $(".delete.button").off();
        $(".untag.button").off();
        $(".inlineUntag.button").off();
        $(".inlineUntagForm").off();
        $(".expand.button").off();
        $(".tagEntry").off();

        $(".addTag.button").off();
        $("form.tagForm").off();

        $(".rename.button").off();
        $("form.renameForm").off();

        $(".editTitle").off();
    };

    // Downloads a bookmark by an id and adds it to the list; used when adding a new one
    var _prependBookmark = function(id) {
        $.get("/bookmarks/"+id+"/html", function(e) {
            $("#bookmark-list").prepend(e);
            _update();
        }, "text");
    };

    // Given an id and a type, downloads a new version of the specific block and replaces them
    // If expand is true, then they are expanded as if the user had clicked the expand button
    var _replace = function(id, type, expand, slide, newid) {
        if(newid == undefined) newid = id;
        var url = "";
        if(type == "tag") url = "/tags/htmlBlock/" + newid;
        if(type == "bookmark") url = "/bookmarks/" + newid + "/html";

        $.get(url, function(e) {
            $(".block[data-id="+id+"]").replaceWith(e);
            if(expand) {
                $(".block[data-id="+id+"][data-taggable-type="+type+"] > .body").show();
                $(".block[data-id="+id+"][data-taggable-type="+type+"] .expand.button").addClass("open");
                $(".block[data-id="+id+"][data-taggable-type="+type+"] .inlineUntag")
                    .css("width", "16px").css("display", "inline-block");
                $(".block[data-id="+id+"][data-taggable-type="+type+"] input")[0].focus();
            }
            if(slide) {
                $(".block[data-id="+newid+"][data-taggable-type="+type+"]").css("display", "none");
                $(".block[data-id="+newid+"][data-taggable-type="+type+"]").slideDown();
            }
            _update();
        }, "text");
    };

    // Add the listeners on initial load
    var _ready = function() {
        // Bookmark adding
        $("#add-bookmark").on("submit", function(e) {
            e.preventDefault();
            $.post("/bookmarks/add", $(this).serialize(), function(e) {
                _prependBookmark(e.id);
                $("#add-bookmark > input[name=url]")[0].value = "";
            }, "json");
        });

        // Error closing
        $("#error .close.button").on("click", function(e) {
            $(this).parents("#error").slideUp();
        });

        // Multitag expand
        $(".multiTag.button").on("click", function(e) {
            if($(this).hasClass("open")) {
                $(this).removeClass("open");
                $(".multiTagCheck").animate({width:"0px", marginRight:"0px", marginLeft:"0px"}, 350);
                $(".multiTagForm").fadeOut();
            }else{
                $(this).addClass("open");
                $(".multiTagCheck").animate({width:"16px", marginRight:"5px", marginLeft:"5px"}, 350);
                $(".multiTagForm").fadeIn();
            }
        });

        // And handle undo
        $("#undo").on("submit", function(e) {
            e.preventDefault();

            var elem = $(this).find("form");

            $.post(elem.attr("action"), elem.serialize(), function(data) {
                undoCallback(data);
            }, "json");

            _disableForm(elem);

            $("#undo").slideUp();
        });

        $("#undo .close.button").on("click", function(e) {
            $(this).parents("#undo").slideUp();
        });

        // And handle the pinning form
        $("#pinForm").on("submit", function(e) {
            e.preventDefault();

            var elem = $(this);

            $.post(elem.attr("action"), elem.serialize(), function(data) {
                document.location.reload();
            }, "json");

            _disableForm(elem);
        });

        // Search page
        $("#search-form input[name=q]").on("input", function(e) {
            var query = e.originalEvent.target.value;

            searchCount ++;
            var localSearchCount = searchCount;

            if("replaceState" in history) {
                history.replaceState({}, "", "?q="+encodeURIComponent(query).replace(/%20/gi, "+"));
            }

            $.get($("#search-form").attr("data-results"), $("#search-form").serialize(), function(results) {
                if(searchCount == localSearchCount) {
                    $("#search-results").html(results);
                    _update();
                }
            }, "html");
        });
    };

    // These two are ran on page load
    $(_ready);
    $(_update);

    return bmat;
};

window.bmatCheckReady = function() {
    if("$" in window) {
        window.bmat = window.bmatFn();
    }else{
        setTimeout(window.bmatCheckReady, 100);
    }
}

bmatCheckReady();
<commit_msg>MultiTag now tags correctly.<commit_after>"use strict";

window.bmatFn = function() {
    var bmat = {};

    var disabledForms = [];

    var undoCallback = null;

    var searchCount = 0;

    // Error handling
    var _error = function(message) {
        $("#error .errorText").html(message);
        $("#error").slideDown();
    }

    $(document).ajaxError(function(e, xhr, settings, error) {
        if("responseJSON" in xhr && "error" in xhr.responseJSON) {
            _error(xhr.responseJSON.error);
        }else{
            _error("ERROR: "+error);
        }

        _enableAllForms();
    });

    window.addEventListener("error", function(e) {
        _error(e.message);
    });

    // Function that finds the form this element is in, and submits it
    var _submitParent = function() {
        $(this).parents("form").submit();
        _disableForm(this);
    };

    // And a function that disables a form
    var _disableForm = function(e) {
        $(e).parents(".block").addClass("disabled");
        $(e).parents(".block").find("input, select").attr("disabled", "disabled");
        $(e).find("input, select").attr("disabled", "disabled");
        disabledForms.push(e);
    };

    // And to enable all of them again
    var _enableAllForms = function() {
        for(var i = 0; i < disabledForms.length; i ++) {
            var f = disabledForms[i];

            $(f).parents(".block").removeClass("disabled");
            $(f).parents(".block").find("input, select").removeAttr("disabled");
        }
        disabledForms = [];
    };

    // And the undo thing
    var _displayUndo = function(message, url, payload, callback) {
        $("#undo .undoText").html(message);
        $("#undo").slideDown();

        $("#undoForm [name=obj]").val(JSON.stringify(payload));
        $("#undoForm").attr("action", url);
        undoCallback = callback;

        $("#undoForm").find("input, select").removeAttr("disabled");
    };

    // Resets all the listeners, used when a document has been changed or initially loaded
    var _update = function() {
        // Remove all the old listeners
        _clean();

        // Delete button
        $(".block .delete.button").on("click", _submitParent);
        $(".deleteForm").on("submit", function(e) {
            e.preventDefault();

            var elem = $(this);
            var id = elem.parents(".block").attr("data-id");

            //if(!confirm("Are you sure you want to delete this?")) return;

            $.post(elem.attr("action"), elem.serialize(), function(data) {
                if(data.deleted !== null) {
                    elem.parents(".block").slideUp();

                    _displayUndo("Object deleted", elem.attr("data-undo-url"), data.obj, function(dat) {
                        _replace(id, dat.type, false, true, dat.id);
                    });
                }
            });
        });

        // Inline untag button
        $(".inlineUntag.button").on("click", _submitParent);
        $(".inlineUntagForm").on("submit", function(e) {
            e.preventDefault();
            var elem = this;

            var bookmark = $(this).parents(".block").data("id");

            $.post(this.getAttribute("action"), $(this).serialize(), function(data) {
                _replace(bookmark, $(elem).parents(".block").data("taggable-type"), true);
            }, "json");

            _disableForm(this);
        });

        // Open/close button
        $(".expand.button").on("click", function() {
            if($(this).hasClass("open")) {
                $(this).parents(".block").children(".body").slideUp("fast");
                $(this).parents(".block").find(".inlineUntag").animate({"width":"0px"}, "fast");
                $(this).removeClass("open");
                _hideEditing($(this).parents(".block"));
            }else{
                $(this).parents(".block").children(".body").slideDown("fast");
                $(this).parents(".block").find(".inlineUntag").animate({"width":"16px"}, "fast");
                $(this).addClass("open");
            }
        });

        // "Add tag" entry, for generating suggestions
        $(".tagEntry").on("input", function(e) {
            var input = this;

            // Don't bother with text less than 3 characters
            if(e.target.value.length < 3) return;

            // Get the suggestion list, and set the option elemnt to contain it
            $.get("/tags/suggest/"+e.target.value, "", function(data) {
                var html = "";

                for(var i = 0; i < data.tags.length; i ++) {
                    html += "<option value='"+data.tags[i]+"'/>";
                }

                $(input).siblings("datalist").html(html);
            }, "json");
        });

        // Title editing; hides the "real title" and replaces it with the text box, or the opposite
        var _showEditing = function(e) {
            $(e).find(".noedit").hide();
            $(e).find(".edit").show();
            $(e).addClass("editing");
        };

        var _hideEditing = function(e) {
            $(e).find(".noedit").show();
            $(e).find(".edit").hide();
            $(e).removeClass("editing");
        };

        $(".editTitle").on("click", function(e) {
            var block = $(this).parents(".block");

            if(!block.hasClass("editing")) {
                _showEditing(block);
            }else{
                _hideEditing(block);
            }
        });

        // Rename and tag forms, both do the same thing and both result in updating the block
        $(".rename.button").on("click", function() {
            var form = $(this).parents(".block").find(".renameForm");
            form.submit();
            _disableForm(form);
        });
        $("form.tagForm, form.renameForm").on("submit", function(e) {
            e.preventDefault();
            var elem = this;
            $(this).find("input[name=url]").val(
                $(elem).parents(".block").find(".body input[name=url]").val()
            );

            $.post(this.getAttribute("action"), $(this).serialize(), function(data) {
                _replace($(elem).parents(".block").data("id"), $(elem).parents(".block").data("taggable-type"), true);
            }, "json");
        });

        // And the submit button for the add tag button
        $(".addTag.button").on("click", function(e) {
            $(this).parents(".block").find(".tagForm").submit();
        });
    };

    // Removes all listeners
    var _clean = function() {
        $(".delete.button").off();
        $(".untag.button").off();
        $(".inlineUntag.button").off();
        $(".inlineUntagForm").off();
        $(".expand.button").off();
        $(".tagEntry").off();

        $(".addTag.button").off();
        $("form.tagForm").off();

        $(".rename.button").off();
        $("form.renameForm").off();

        $(".editTitle").off();
    };

    // Downloads a bookmark by an id and adds it to the list; used when adding a new one
    var _prependBookmark = function(id) {
        $.get("/bookmarks/"+id+"/html", function(e) {
            $("#bookmark-list").prepend(e);
            _update();
        }, "text");
    };

    // Given an id and a type, downloads a new version of the specific block and replaces them
    // If expand is true, then they are expanded as if the user had clicked the expand button
    var _replace = function(id, type, expand, slide, newid) {
        if(newid == undefined) newid = id;
        var url = "";
        if(type == "tag") url = "/tags/htmlBlock/" + newid;
        if(type == "bookmark") url = "/bookmarks/" + newid + "/html";

        $.get(url, function(e) {
            $(".block[data-id="+id+"]").replaceWith(e);
            if(expand) {
                $(".block[data-id="+id+"][data-taggable-type="+type+"] > .body").show();
                $(".block[data-id="+id+"][data-taggable-type="+type+"] .expand.button").addClass("open");
                $(".block[data-id="+id+"][data-taggable-type="+type+"] .inlineUntag")
                    .css("width", "16px").css("display", "inline-block");
                $(".block[data-id="+id+"][data-taggable-type="+type+"] input")[0].focus();
            }
            if(slide) {
                $(".block[data-id="+newid+"][data-taggable-type="+type+"]").css("display", "none");
                $(".block[data-id="+newid+"][data-taggable-type="+type+"]").slideDown();
            }
            _update();
        }, "text");
    };

    // Add the listeners on initial load
    var _ready = function() {
        // Bookmark adding
        $("#add-bookmark").on("submit", function(e) {
            e.preventDefault();
            $.post("/bookmarks/add", $(this).serialize(), function(e) {
                _prependBookmark(e.id);
                $("#add-bookmark > input[name=url]")[0].value = "";
            }, "json");
        });

        // Error closing
        $("#error .close.button").on("click", function(e) {
            $(this).parents("#error").slideUp();
        });

        // Multitag expand
        $(".multiTag.button").on("click", function(e) {
            if($(this).hasClass("open")) {
                $(this).removeClass("open");
                $(".multiTagCheck").animate({width:"0px", marginRight:"0px", marginLeft:"0px"}, 350);
                $(".multiTagForm").fadeOut();
            }else{
                $(this).addClass("open");
                $(".multiTagCheck").animate({width:"16px", marginRight:"5px", marginLeft:"5px"}, 350);
                $(".multiTagForm").fadeIn();
            }
        });

        $(".multiTagForm").on("submit", function(e) {
            e.preventDefault();
            var tag = $(this).find("[name=name]").val();
            var colour = $(this).find("[name=colour]").val();

            $(".multiTagCheck:checked").parents(".block").find(".tagForm").each(function(i, node) {
                $(node).find("[name=name]").val(tag);
                $(node).find("[name=colour]").val(colour);
                $(node).submit();
            });
        });

        // And handle undo
        $("#undo").on("submit", function(e) {
            e.preventDefault();

            var elem = $(this).find("form");

            $.post(elem.attr("action"), elem.serialize(), function(data) {
                undoCallback(data);
            }, "json");

            _disableForm(elem);

            $("#undo").slideUp();
        });

        $("#undo .close.button").on("click", function(e) {
            $(this).parents("#undo").slideUp();
        });

        // And handle the pinning form
        $("#pinForm").on("submit", function(e) {
            e.preventDefault();

            var elem = $(this);

            $.post(elem.attr("action"), elem.serialize(), function(data) {
                document.location.reload();
            }, "json");

            _disableForm(elem);
        });

        // Search page
        $("#search-form input[name=q]").on("input", function(e) {
            var query = e.originalEvent.target.value;

            searchCount ++;
            var localSearchCount = searchCount;

            if("replaceState" in history) {
                history.replaceState({}, "", "?q="+encodeURIComponent(query).replace(/%20/gi, "+"));
            }

            $.get($("#search-form").attr("data-results"), $("#search-form").serialize(), function(results) {
                if(searchCount == localSearchCount) {
                    $("#search-results").html(results);
                    _update();
                }
            }, "html");
        });
    };

    // These two are ran on page load
    $(_ready);
    $(_update);

    return bmat;
};

window.bmatCheckReady = function() {
    if("$" in window) {
        window.bmat = window.bmatFn();
    }else{
        setTimeout(window.bmatCheckReady, 100);
    }
}

bmatCheckReady();
<|endoftext|>


<commit_before>// @flow

import Link from 'next/link'

import TimeUtil from '../../utils/Time'

const convertToTimeRemaing = (settingTime: number, pastTime: number) => {
  return settingTime - pastTime
}

const onChange = (setTime: Function) => {
  return (e) => {
    const time = parseInt(e.target.value)
    setTime(time)
  }
}

const onChangeTitle = (changeTaskTitle: Function) => {
  return (e) => {
    changeTaskTitle(e.target.value)
  }
}

const onClickStart = (startTimer: Function) => {
  return () => {
    startTimer(new Date().getTime())
  }
}

const onClickStop = (stopTimer: Function) => {
  return () => {
    stopTimer(new Date().getTime())
  }
}

type Props = {
  startTimer: Function,
  stopTimer: Function,
  pauseTimer: Function,
  setTime: Function,
  elapsedTime: number,
  settingTime: number,
  isStart: boolean,
  isPause: boolean,
  taskTitle: String,
  changeTaskTitle: Function,
}

export default ({ startTimer, stopTimer, pauseTimer, elapsedTime, settingTime, setTime, isStart, isPause, taskTitle, changeTaskTitle }: Props) => {
  return (

HANTEN TIMER

              Task Title

                <input id='task-title' className='input' type='text' value={taskTitle} onChange={onChangeTitle(changeTaskTitle)} />

Time Reaming

{TimeUtil.unix2mmss(convertToTimeRemaing(settingTime, elapsedTime))} sec

              <progress className='progress' value={elapsedTime} max={settingTime} >15%</progress>

                <button className='button is-info' onClick={onClickStart(startTimer)}>startTimer</button>

                <button className='button' onClick={pauseTimer} disabled={isPause || !isStart}>Pause</button>

                <button className='button is-danger' onClick={onClickStop(stopTimer)}>stopTimer</button>

settings

                  <input className='input' value={settingTime} onChange={onChange(setTime)} readOnly={isStart === true} />

                    minutes

        <Link href='/task'>> tasks</Link>

  )
}
<commit_msg>styling page title<commit_after>// @flow

import Link from 'next/link'

import TimeUtil from '../../utils/Time'

const convertToTimeRemaing = (settingTime: number, pastTime: number) => {
  return settingTime - pastTime
}

const onChange = (setTime: Function) => {
  return (e) => {
    const time = parseInt(e.target.value)
    setTime(time)
  }
}

const onChangeTitle = (changeTaskTitle: Function) => {
  return (e) => {
    changeTaskTitle(e.target.value)
  }
}

const onClickStart = (startTimer: Function) => {
  return () => {
    startTimer(new Date().getTime())
  }
}

const onClickStop = (stopTimer: Function) => {
  return () => {
    stopTimer(new Date().getTime())
  }
}

type Props = {
  startTimer: Function,
  stopTimer: Function,
  pauseTimer: Function,
  setTime: Function,
  elapsedTime: number,
  settingTime: number,
  isStart: boolean,
  isPause: boolean,
  taskTitle: String,
  changeTaskTitle: Function,
}

export default ({ startTimer, stopTimer, pauseTimer, elapsedTime, settingTime, setTime, isStart, isPause, taskTitle, changeTaskTitle }: Props) => {
  return (

HANTEN TIMER

              Task Title

                <input id='task-title' className='input' type='text' value={taskTitle} onChange={onChangeTitle(changeTaskTitle)} />

Time Reaming

{TimeUtil.unix2mmss(convertToTimeRemaing(settingTime, elapsedTime))} sec

              <progress className='progress' value={elapsedTime} max={settingTime} >15%</progress>

                <button className='button is-info' onClick={onClickStart(startTimer)}>startTimer</button>

                <button className='button' onClick={pauseTimer} disabled={isPause || !isStart}>Pause</button>

                <button className='button is-danger' onClick={onClickStop(stopTimer)}>stopTimer</button>

settings

                  <input className='input' value={settingTime} onChange={onChange(setTime)} readOnly={isStart === true} />

                    minutes

        <Link href='/task'>> tasks</Link>

  )
}
<|endoftext|>


<commit_before>/*
Input Mask plugin extensions
http://github.com/RobinHerbots/jquery.inputmask
Copyright (c) 2010 - 2012 Robin Herbots
Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php)
Version: 1.3.3b

Optional extensions on the jquery.inputmask base
*/
(function ($) {
    //number aliases
    $.extend($.inputmask.defaults.aliases, {
        'decimal': {
            mask: "~",
            placeholder: "",
            repeat: 10,
            greedy: false,
            numericInput: true,
            digits: "*", //numer of digits
            groupSeparator: ",", // | "."
            groupSize: 3,
            autoGroup: false,
            postFormat: function (buffer, pos, reformatOnly, opts) {
                var cbuf = buffer.slice();
                if (!reformatOnly) cbuf.splice(pos, 0, "?"); //set position indicator
                var bufVal = cbuf.join('');
                if (opts.autoGroup || bufVal.indexOf(opts.groupSeparator) != -1) {
                    bufVal = bufVal.replace(new RegExp("\\" + opts.groupSeparator, "g"), '');
                    var reg = new RegExp('(-?[\\d?]+)([\\d?]{' + opts.groupSize + '})');
                    while (reg.test(bufVal)) {
                        bufVal = bufVal.replace(reg, '$1' + opts.groupSeparator + '$2');
                    }
                }
                buffer.length = bufVal.length; //align the length
                for (var i = 0, l = bufVal.length; i < l; i++) {
                    buffer[i] = bufVal.charAt(i);
                }
                var newPos = reformatOnly ? pos : buffer.indexOf("?");
                if (!reformatOnly) buffer.splice(newPos, 1);

                return newPos;
            },
            regex: {
                number: function (groupSeparator, groupSize, radixPoint, digits) {
                    var escapedGroupSeparator = $.inputmask.escapeRegex.call(this, groupSeparator);
                    var escapedRadixPoint = $.inputmask.escapeRegex.call(this, radixPoint);
                    var digitExpression = isNaN(digits) ? digits : '{0,' + digits + '}';
                    return new RegExp("^[\+-]?(\\d+|\\d{1," + groupSize + "}((" + escapedGroupSeparator + "\\d{" + groupSize + "})?)+)(" + escapedRadixPoint + "\\d" + digitExpression + ")?$");
                }
            },
            onKeyDown: function (e, opts) {
                var $input = $(this), input = this;
                if (e.keyCode == opts.keyCode.TAB) {
                    var nptStr = input._valueGet();
                    var radixPosition = nptStr.indexOf(opts.radixPoint);
                    if (radixPosition != -1) {
                        for (var i = 1; i < opts.digits; i++) {
                            if (nptStr[radixPosition + i]) nptStr = nptStr + "0";
                        }
                        if (nptStr !== $input.val()) {
                            $input.val(nptStr);
                        }
                    }
                } else if (e.keyCode == opts.keyCode.DELETE || e.keyCode == opts.keyCode.BACKSPACE) {
                    var nptStr = input._valueGet(),
                    buffer = nptStr.split('');
                    var newPos = opts.postFormat(buffer, 0, true, opts);
                    nptStr = buffer.join('');
                    input._valueSet(nptStr);
                }
            },
            definitions: {
                '~': { //real number
                    validator: function (chrs, buffer, pos, strict, opts) {
                        if (chrs == "") return false;
                        var cbuf = strict ? buffer.slice(0, pos) : buffer.slice();
                        cbuf.splice(pos, 0, chrs);
                        var bufferStr = cbuf.join('');
                        if (opts.autoGroup) //strip groupseparator
                            bufferStr = bufferStr.replace(new RegExp("\\" + opts.groupSeparator, "g"), '');
                        var isValid = opts.regex.number(opts.groupSeparator, opts.groupSize, opts.radixPoint, opts.digits).test(bufferStr);
                        if (!isValid) {
                            //let's help the regex a bit
                            bufferStr += "0";
                            isValid = opts.regex.number(opts.groupSeparator, opts.groupSize, opts.radixPoint, opts.digits).test(bufferStr);
                            if (!isValid) {
                                //make a valid group
                                var lastGroupSeparator = bufferStr.lastIndexOf(opts.groupSeparator);
                                for (i = bufferStr.length - lastGroupSeparator; i <= 3; i++) {
                                    bufferStr += "0";
                                }

                                isValid = opts.regex.number(opts.groupSeparator, opts.groupSize, opts.radixPoint, opts.digits).test(bufferStr);
                                if (!isValid && !strict) {
                                    if (chrs == opts.radixPoint) {
                                        isValid = opts.regex.number(opts.groupSeparator, opts.groupSize, opts.radixPoint, opts.digits).test("0" + bufferStr + "0");
                                        if (isValid) {
                                            buffer[pos] = "0";
                                            pos++;
                                            return { "pos": pos };
                                        }
                                    }
                                }
                            }
                        }

                        if (isValid != false && !strict) {
                            var newPos = opts.postFormat(buffer, pos, false, opts);
                            return { "pos": newPos };
                        }
                        return isValid;
                    },
                    cardinality: 1,
                    prevalidator: null
                }
            },
            insertMode: true,
            autoUnmask: false
        },
        'non-negative-decimal': {
            regex: {
                number: function (groupSeparator, groupSize, radixPoint, digits) {
                    var escapedGroupSeparator = $.inputmask.escapeRegex.call(this, groupSeparator);
                    var escapedRadixPoint = $.inputmask.escapeRegex.call(this, radixPoint);
                    var digitExpression = isNaN(digits) ? digits : '{0,' + digits + '}'
                    return new RegExp("^[\+]?(\\d+|\\d{1," + groupSize + "}((" + escapedGroupSeparator + "\\d{" + groupSize + "})?)+)(" + escapedRadixPoint + "\\d" + digitExpression + ")?$");
                }
            },
            alias: "decimal"
        },
        'integer': {
            regex: {
                number: function (groupSeparator, groupSize) { return new RegExp("^([\+\-]?\\d*)$"); }
            },
            alias: "decimal"
        }
    });
})(jQuery);
<commit_msg>some fixes for numeric (still some issue when deleting)<commit_after>/*
Input Mask plugin extensions
http://github.com/RobinHerbots/jquery.inputmask
Copyright (c) 2010 - 2012 Robin Herbots
Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php)
Version: 1.3.3d

Optional extensions on the jquery.inputmask base
*/
(function ($) {
    //number aliases
    $.extend($.inputmask.defaults.aliases, {
        'decimal': {
            mask: "~",
            placeholder: "",
            repeat: 10,
            greedy: false,
            numericInput: true,
            digits: "*", //numer of digits
            groupSeparator: ",", // | "."
            groupSize: 3,
            autoGroup: false,
            postFormat: function (buffer, pos, reformatOnly, opts) {
                var cbuf = buffer.slice();
                if (!reformatOnly) cbuf.splice(pos, 0, "?"); //set position indicator
                var bufVal = cbuf.join('');
                if (opts.autoGroup || (reformatOnly && bufVal.indexOf(opts.groupSeparator) != -1)) {
                    bufVal = bufVal.replace(new RegExp("\\" + opts.groupSeparator, "g"), '');
                    var reg = new RegExp('(-?[\\d?]+)([\\d?]{' + opts.groupSize + '})');
                    while (reg.test(bufVal)) {
                        bufVal = bufVal.replace(reg, '$1' + opts.groupSeparator + '$2');
                    }
                }
                buffer.length = bufVal.length; //align the length
                for (var i = 0, l = bufVal.length; i < l; i++) {
                    buffer[i] = bufVal.charAt(i);
                }
                var newPos = reformatOnly ? pos : buffer.indexOf("?");
                if (!reformatOnly) buffer.splice(newPos, 1);

                return newPos;
            },
            regex: {
                number: function (groupSeparator, groupSize, radixPoint, digits) {
                    var escapedGroupSeparator = $.inputmask.escapeRegex.call(this, groupSeparator);
                    var escapedRadixPoint = $.inputmask.escapeRegex.call(this, radixPoint);
                    var digitExpression = isNaN(digits) ? digits : '{0,' + digits + '}';
                    return new RegExp("^[\+-]?(\\d+|\\d{1," + groupSize + "}((" + escapedGroupSeparator + "\\d{" + groupSize + "})?)+)(" + escapedRadixPoint + "\\d" + digitExpression + ")?$");
                }
            },
            onKeyDown: function (e, opts) {
                var $input = $(this), input = this;
                if (e.keyCode == opts.keyCode.TAB) {
                    var nptStr = input._valueGet();
                    var radixPosition = nptStr.indexOf(opts.radixPoint);
                    if (radixPosition != -1) {
                        for (var i = 1; i < opts.digits; i++) {
                            if (nptStr[radixPosition + i]) nptStr = nptStr + "0";
                        }
                        if (nptStr !== $input.val()) {
                            $input.val(nptStr);
                        }
                    }
                } else if (e.keyCode == opts.keyCode.DELETE || e.keyCode == opts.keyCode.BACKSPACE) {
                    var nptStr = input._valueGet(),
                    buffer = nptStr.split('');
                    var newPos = opts.postFormat(buffer, 0, true, opts);
                    nptStr = buffer.join('');
                    input._valueSet(nptStr);
                }
            },
            definitions: {
                '~': { //real number
                    validator: function (chrs, buffer, pos, strict, opts) {
                        if (chrs == "") return false;
                        if (pos == 1 && buffer[0] === '0' && new RegExp("[\\d|-]").test(chrs)) { //handle first char
                            buffer[0] = "";
                            return { "pos": 0 };
                        }

                        var cbuf = strict ? buffer.slice(0, pos) : buffer.slice();
                        cbuf.splice(pos, 0, chrs);
                        var bufferStr = cbuf.join('');

                        if (opts.autoGroup) //strip groupseparator
                            bufferStr = bufferStr.replace(new RegExp("\\" + opts.groupSeparator, "g"), '');
                        var isValid = opts.regex.number(opts.groupSeparator, opts.groupSize, opts.radixPoint, opts.digits).test(bufferStr);
                        if (!isValid) {
                            //let's help the regex a bit
                            bufferStr += "0";
                            isValid = opts.regex.number(opts.groupSeparator, opts.groupSize, opts.radixPoint, opts.digits).test(bufferStr);
                            if (!isValid) {
                                //make a valid group
                                var lastGroupSeparator = bufferStr.lastIndexOf(opts.groupSeparator);
                                for (i = bufferStr.length - lastGroupSeparator; i <= 3; i++) {
                                    bufferStr += "0";
                                }

                                isValid = opts.regex.number(opts.groupSeparator, opts.groupSize, opts.radixPoint, opts.digits).test(bufferStr);
                                if (!isValid && !strict) {
                                    if (chrs == opts.radixPoint) {
                                        isValid = opts.regex.number(opts.groupSeparator, opts.groupSize, opts.radixPoint, opts.digits).test("0" + bufferStr + "0");
                                        if (isValid) {
                                            buffer[pos] = "0";
                                            pos++;
                                            return { "pos": pos };
                                        }
                                    }
                                }
                            }
                        }

                        if (isValid != false && !strict) {
                            var newPos = opts.postFormat(buffer, pos, false, opts);
                            return { "pos": newPos };
                        }
                        return isValid;
                    },
                    cardinality: 1,
                    prevalidator: null
                }
            },
            insertMode: true,
            autoUnmask: false
        },
        'non-negative-decimal': {
            regex: {
                number: function (groupSeparator, groupSize, radixPoint, digits) {
                    var escapedGroupSeparator = $.inputmask.escapeRegex.call(this, groupSeparator);
                    var escapedRadixPoint = $.inputmask.escapeRegex.call(this, radixPoint);
                    var digitExpression = isNaN(digits) ? digits : '{0,' + digits + '}'
                    return new RegExp("^[\+]?(\\d+|\\d{1," + groupSize + "}((" + escapedGroupSeparator + "\\d{" + groupSize + "})?)+)(" + escapedRadixPoint + "\\d" + digitExpression + ")?$");
                }
            },
            alias: "decimal"
        },
        'integer': {
            regex: {
                number: function (groupSeparator, groupSize) { return new RegExp("^([\+\-]?\\d*)$"); }
            },
            alias: "decimal"
        }
    });
})(jQuery);
<|endoftext|>


<commit_before>'use strict';

// MODULES //

var tape = require( 'tape' );
var proxyquire = require( 'proxyquire' );
var hasSymbols = require( '@stdlib/utils/detect-symbol-support' )();
var hasToStringTag = require( '@stdlib/utils/detect-tostringtag-support' )();
var isNumber = require( './../lib/object.js' );

// VARIABLES //

var opts = {
	'skip': !hasSymbols
};

// TESTS //

tape( 'main export is a function', function test( t ) {
	t.ok( true, __filename );
	t.equal( typeof isNumber, 'function', 'main export is a function' );
	t.end();
});

tape( 'the function returns `true` if provided a number object', function test( t ) {
	t.equal( isNumber( new Number( 5 ) ), true, 'returns true' );
	t.equal( isNumber( new Number( NaN ) ), true, 'returns true' );
	t.end();
});

tape( 'the function returns `false` if provided a primitive number', function test( t ) {
	t.equal( isNumber( 3.14 ), false, 'returns false' );
	t.equal( isNumber( NaN ), false, 'returns false' );
	t.end();
});

tape( 'if `Symbol.toStringTag` is supported, the function guards against objects masquerading as `Number` objects', opts, function test( t ) {
	var isNumber;
	var mock;

	isNumber = proxyquire( './../lib/object.js', {
		'@stdlib/utils/detect-tostringtag-support': detect
	});

	mock = {
		'toString': toString,
		'valueOf': valueOf
	};
	if ( hasToStringTag ) {
		mock[ Symbol.toStringTag ] = 'Number';
	}
	t.equal( isNumber( mock ), false, 'returns false' );
	t.end();

	function detect() {
		return true;
	}
	function toString() {
		return '999';
	}
	function valueOf() {
		return 999;
	}
});

tape( 'if `Symbol.toStringTag` is not supported, the function attempts to determine the native class', function test( t ) {
	var isNumber = proxyquire( './../lib/object.js', {
		'@stdlib/utils/detect-tostringtag-support': detect
	});

	t.equal( isNumber( new Number( 5 ) ), true, 'returns true' );
	t.equal( isNumber( {} ), false, 'returns false' );

	t.end();

	function detect() {
		return false;
	}
});

tape( 'function returns `false` if not provided a number', function test( t ) {
	var values;
	var i;

	values = [
		'5',
		null,
		true,
		undefined,
		[],
		{},
		function(){}
	];

	for ( i = 0; i < values.length; i++ ) {
		t.equal( isNumber( values[i] ), false, 'returns false when provided '+values[i] );
	}
	t.end();
});
<commit_msg>Update test cases<commit_after>'use strict';

// MODULES //

var tape = require( 'tape' );
var proxyquire = require( 'proxyquire' );
var hasSymbols = require( '@stdlib/utils/detect-symbol-support' )();
var hasToStringTag = require( '@stdlib/utils/detect-tostringtag-support' )();
var isNumber = require( './../lib/object.js' );

// VARIABLES //

var opts = {
	'skip': !hasSymbols
};

// TESTS //

tape( 'main export is a function', function test( t ) {
	t.ok( true, __filename );
	t.equal( typeof isNumber, 'function', 'main export is a function' );
	t.end();
});

tape( 'the function returns `true` if provided a number object', function test( t ) {
	t.equal( isNumber( new Number( 5 ) ), true, 'returns true' );
	t.equal( isNumber( new Number( NaN ) ), true, 'returns true' );
	t.end();
});

tape( 'the function returns `false` if provided a primitive number', function test( t ) {
	t.equal( isNumber( 3.14 ), false, 'returns false' );
	t.equal( isNumber( NaN ), false, 'returns false' );
	t.end();
});

tape( 'if `Symbol.toStringTag` is supported, the function guards against objects masquerading as `Number` objects', opts, function test( t ) {
	var isNumber;
	var mock;

	isNumber = proxyquire( './../lib/object.js', {
		'@stdlib/utils/detect-tostringtag-support': detect
	});

	mock = {
		'toString': toString,
		'valueOf': valueOf
	};
	if ( hasToStringTag ) {
		mock[ Symbol.toStringTag ] = 'Number';
	}
	t.equal( isNumber( mock ), false, 'returns false' );
	t.end();

	function detect() {
		return true;
	}
	function toString() {
		return '999';
	}
	function valueOf() {
		return 999;
	}
});

tape( 'if `Symbol.toStringTag` is not supported, the function attempts to determine the native class', function test( t ) {
	var isNumber = proxyquire( './../lib/object.js', {
		'@stdlib/utils/detect-tostringtag-support': detect
	});

	t.equal( isNumber( new Number( 5 ) ), true, 'returns true' );
	t.equal( isNumber( {} ), false, 'returns false' );

	t.end();

	function detect() {
		return false;
	}
});

tape( 'function returns `false` if not provided a number', function test( t ) {
	var values;
	var i;

	values = [
		'5',
		null,
		true,
		undefined,
		[],
		{},
		new Date(),
		/./,
		new RegExp( '.' ),
		function(){}
	];

	for ( i = 0; i < values.length; i++ ) {
		t.equal( isNumber( values[i] ), false, 'returns false when provided '+values[i] );
	}
	t.end();
});
<|endoftext|>


<commit_before>// View model for the courses page
function pageViewModel(gvm) {
    // Page specific i18n bindings
    gvm.app  = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectRapportName")}, gvm);
    gvm.title = ko.computed(function(){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("CourseTitle2");}, gvm);
    gvm.pageHeader = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("CourseTitle2");}, gvm);
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectRapportName");}, gvm);

    gvm.availableLocations = ko.observableArray([]);
    gvm.availableTrainings = ko.observableArray([]);
    gvm.availableCourses = ko.observableArray([]);

    /*Teacher*/
    gvm.availableTeacher = ko.observableArray([]);
    gvm.currentteacherid = null;
    /*teacher*/

    // Pagination i18n bindings
    gvm.addBtn = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("AddBtn")}, gvm);

    gvm.codeTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("CodeTableTitle");}, gvm);
    gvm.nameTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("NameTableTitle");}, gvm);
    gvm.descTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("DescTableTitle");}, gvm);
    gvm.actionTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ActionTableTitle");}, gvm);

    // The table data observable array
    gvm.tabledata = ko.observableArray([]);

    // Add data to the table
    gvm.addTableData = function(id, code, name, desc, teach) {
        // Push data
        var tblOject = {tid: id, tcode: code, tname: name, tdesc: desc, tteach: teach};
        gvm.tabledata.push(tblOject);

        // Attach delete handler to delete button
        $('#removebtn-' + id).bind('click', function(event, data){
            // Delete the table item
            deleteTableItem(id, tblOject);
            event.stopPropagation();
        });

        // Attach edit handler to edit button
        $('#editbtn-' + id).bind('click', function(event, data){
            // Edit the table item
            showEditProjectTypeModal(code, name, desc, id);
            event.stopPropagation();
        });

        // Attach copy handler to copy button
        $('#copybtn-' + id).bind('click', function(event, data){
            // Delete the table item
            copyTableItem(id, tblOject);
            event.stopPropagation();
        });

        //Attach manage handler to manage modules, doelstellingen and criterias to manage button
        $('#managebtn-' + id).bind('click', function(event, data) {
            //TODO
        });

        /*$('#studentbtn-' + id).bind('click', function(event, data) {
            showCoupleStudentListModal(id);
            gvm.currentprojectid = id;
            gvm.currentselectedlist = -1;
            event.stopPropagation();
            loadCoupleDropdown();
        });*/
    }

    gvm.clearTable = function() {
        gvm.tabledata.removeAll();
    }
    /*
    gvm.updateDropdowns = function() {
        $.getJSON('api/teacherrapport/' + gvm.userId, function(data) {
            if(!$.isEmptyObject(data)) {
                $.each(data, function(i, item) {
                    $(".btn-teacher span:first").text(item.teacher);
                    gvm.currentteacherid = item.id;
                    gvm.updateTeacher(item.id);
                    LoadTablePage(item.currentteacherid, 1);
                });
            } else {
                gvm.updateTeacher();
            }
        });
    }*/

    gvm.updateTeacher = function(id) {
        $.getJSON('/api/getteacherrapport/' + id, function(data) {
            gvm.availableTeacher.removeAll();
            $.each(data, function(i, item) {
                console.log(item);
                gvm.availableTeacher.push(item);
                $("#teacherbtn-" + item.id).click(function(){
                    $(".btn-teacher span:first").text($(this).text());
                    gvm.currentteacherid = item.id;
                    gvm.saveLastSelectedDropdowns();
                    loadTablePage(item.id, 1);
                });
            });
        });
    }

    }

/*
 * Delete item from table given the id.
 */
function deleteTableItem(id, tblOject) {
    showYesNoModal("Bent u zeker dat u dit item wil verwijderen? \r\n Let op: verwijderde items blijven in het systeem en kunnen weer actief gezet worden door een administrator. \r\n Gelieve de administrator te contacteren om een vak definitief te verwijderen.", function(val){
        if(val){
            $.ajax({
                url: "/api/coursedelete/" + id,
                type: "DELETE",
                success: function() {
                    viewModel.tabledata.remove(tblOject);
                }
            });
        }
    });
}
/*
 * Delete item from table given the id.
 */
function copyTableItem(id) {
    showYesNoModal("Bent u zeker dat u dit item wil kopiëren? ", function(val){
        if(val){
            $.ajax({
                url: "/api/coursecopy/" + id,
                type: "post",
                success: function() {
                    //tabel refreshen met nieuwe toegevoegde waarde of pagina openen om deze waarde te wijzigen.
                }
            });
        }
    });
}

/*
 * Add a new projecttype
 */
function addNewProjecttypeForm(serialData, callback) {
    $.ajax({
            url: "/api/courserapport",
            type: "POST",
            data: serialData,
            success: function(data) {
                viewModel.addTableData(data['id'], data['code'], data['name'], data['description']);
                callback(true);
            },
            error: function(data) {
                callback(false);
            }
        });
}

/*
 * Add a new projecttype
 */
function addNewProjecttypeRaw(code, name, description, callback) {
    addNewProjecttypeForm("code=" + encodeURIComponent(code) + "&name=" + encodeURIComponent(name) + "&description=" + encodeURIComponent(description), callback);
}

/*
 * Update the projecttype
 * @param {type} id
 * @param {type} code
 * @param {type} name
 * @param {type} description
 * @param {type} callback
 * @returns {undefined}
 */
function updateProjecttypeForm(id, serialData, callback) {
    $.ajax({
        url: "/api/courseupdate/" + id,
        type: "PUT",
        data: serialData,
        success: function(data) {
            //viewModel.addTableData(data['id'], data['code'], data['name'], data['description']);
            loadTablePage(1); //TODO now it is refreshing table after updating but it redirects to pagenr 1     WERKT NIET
            callback(true);
        },
        error: function(data) {
            callback(false);
        }
    });
}

/**
 * update project type
 * @param {type} id
 * @param {type} code
 * @param {type} name
 * @param {type} description
 * @param {type} callback
 * @returns {undefined}
 */
function updateProjecttypeRaw(id, code, name, description, callback) {
    updateProjecttypeForm(id, "code=" + encodeURIComponent(code) + "&name=" + encodeURIComponent(name) + "&description=" + encodeURIComponent(description), callback);
}

/*
 * Load page of the table
 */
function loadTablePage(pagenr)
{
    $.getJSON('/api/coursesrapport/page/' + pagenr, function(data){

        /* Clear current table page */
        viewModel.clearTable();

        // Load table data
        $.each(data.data, function(i, item) {
            viewModel.addTableData(item.id, item.code, item.name, item.description, item.leerkracht);
        });

        /* Let previous en next buttons work */
        if(data.prev == "none"){
            $('#pager-prev-btn').addClass('disabled');
        } else {
            $('#pager-prev-btn').removeClass('disabled');
            $('#pager-prev-btn a').click(function(){
                loadTablePage(data.prev);
            });
        }

        if(data.next == "none"){
            $('#pager-next-btn').addClass('disabled');
        } else {
            $('#pager-next-btn').removeClass('disabled');
            $('#pager-next-btn a').click(function(){
                loadTablePage(data.next);
            });
        }

        // Number of pager buttons
        var numItems = $('.pager-nr-btn').length;

        /* Calculate for the pager buttons */
        var lowPage = Math.floor(pagenr/numItems) + 1;

        $('.pager-nr-btn').each(function() {
            /* calculate current page number */
            var thispagenr = lowPage++;

            /* Add the page number */
            $(this).html('' + thispagenr + '');

            /* Add active class to current page */
            if(thispagenr == pagenr) {
                $(this).addClass('active');
            } else {
                $(this).removeClass('active');
            }

            /* Disable inactive classes and bind handlers to active classes */
            if(thispagenr > data.pagecount) {
                $(this).addClass('disabled');
            } else {
                /* Add click listener for button */
                $(this).click(function() {
                    loadTablePage(thispagenr);
                });
            }
        });
    });
}

/**
 * Show a new projecttype modal.
 * @returns {undefined}
 */
function showNewProjectTypeModal()
{
    resetGeneralModal();
    setGeneralModalTitle(i18n.__("AddNewCourse"));
    setGeneralModalBody('<form id="newprojectform"> \

 \
                <input type="text" class="form-control input-lg" placeholder="' + i18n.__('CodeTableTitle') + '" " name="code"> \

 \

 \
                <input type="text" class="form-control input-lg" placeholder="' + i18n.__('NameTableTitle') + '" name="name"> \

 \

 \
                <input type="text" class="form-control input-lg" placeholder="' + i18n.__('DescTableTitle') + '" name="description"> \

 \
            </form>' );

    addGeneralModalButton(i18n.__("AddBtn"), function(){
        console.log($('#newprojectform').serialize());
       addNewProjecttypeForm($('#newprojectform').serialize(), function(result){
            hideModal();
        });
    });

    showGeneralModal();
}

/**
 * Show the edit projecttype modal.
 * @param {type} code
 * @param {type} name
 * @param {type} description
 * @param {type} tid
 * @returns {undefined}
 */
function showEditProjectTypeModal(code, name, description, tid)
{
  resetGeneralModal();
    setGeneralModalTitle(i18n.__("EditProjectTitle2"));
    setGeneralModalBody('<form id="updateprojectform"> \

 \
                <input type="text" class="form-control input-lg" placeholder="' + i18n.__('CodeTableTitle') + '" " name="code" value="' + code + '"> \

 \

 \
                <input type="text" class="form-control input-lg" placeholder="' + i18n.__('NameTableTitle') + '" name="name" value="' + name + '"> \

 \

 \
                <input type="text" class="form-control input-lg" placeholder="' + i18n.__('DescTableTitle') + '" name="description" value="' + description + '"> \

 \
        </form>');
    $.getJSON()

    addGeneralModalButton(i18n.__("SaveBtn"), function(){
        updateProjecttypeForm(tid, $('#updateprojectform').serialize(), function(result){
            hideModal();
        });
    });

    addGeneralModalButton(i18n.__("CancelBtn"), function(){
        hideModal();
    })

    showGeneralModal();
}

function showCoupleStudentListModal(projectid) {
    viewModel.currentselectedlist = -1;
    resetGeneralModal();
    setGeneralModalTitle(i18n.__("CoupleStudentList"));
    setGeneralModalBody(
        '
' +
            '<button class="btn btn-default dropdown-toggle" type="button" id="dropdownStudLists" data-toggle="dropdown" aria-expanded="true">' +
                'Dropdown' +
                '' +
            '</button>' +
            '
' +
            '
' +
        '
');

    addGeneralModalButton(i18n.__("SaveBtn"), function() {
        updateListForm(viewModel.currentselectedlist, $('#coupleform').serialize(), function(result){
            hideModal();
        });
    });

    addGeneralModalButton(i18n.__("CancelBtn"), function(){
        hideModal();
    })
    showGeneralModal();
}
function loadCoupleDropdown() {
    $.getJSON('/api/studentlists/' + viewModel.userId, function(data) {
        $.each(data, function(i, item) {
            $("#ddlLists").append('
' + item.name + '
')
            $("#dropdownitem-" + item.id).click(function(){
                $(this).parent().parent().parent().removeClass("open");
                $(this).parent().parent().parent().find(".btn").html($(this).text() + '');
                viewModel.currentselectedlist = item.id;
            });
        });
    });
    $("#dropdownStudLists").click(function() {
        $(this).parent().toggleClass("open");
    });
}

function updateListForm(id, serialData, callback) {
    $.ajax({
        url: "/api/project/" + viewModel.currentprojectid + "/studentlist/" + id,
        type: "POST",
        data: serialData,
        success: function(data) {
            callback(true);
        },
        error: function(data) {
            callback(false);
        }
    });
}

function initPage() {
    // Add button handlers
    $('#addProjectTypeBtn').click(function(){
        showNewProjectTypeModal();
    });

    $.getJSON('/api/currentuser', function(data) {
        viewModel.userId = data.id;
        /*viewModel.updateDropdowns();*/
    });

    loadTablePage(1);
}

<commit_msg>copy functie course<commit_after>// View model for the courses page
function pageViewModel(gvm) {
    // Page specific i18n bindings
    gvm.app  = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectRapportName")}, gvm);
    gvm.title = ko.computed(function(){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("CourseTitle2");}, gvm);
    gvm.pageHeader = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("CourseTitle2");}, gvm);
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectRapportName");}, gvm);

    gvm.availableLocations = ko.observableArray([]);
    gvm.availableTrainings = ko.observableArray([]);
    gvm.availableCourses = ko.observableArray([]);

    /*Teacher*/
    gvm.availableTeacher = ko.observableArray([]);
    gvm.currentteacherid = null;
    /*teacher*/

    // Pagination i18n bindings
    gvm.addBtn = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("AddBtn")}, gvm);

    gvm.codeTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("CodeTableTitle");}, gvm);
    gvm.nameTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("NameTableTitle");}, gvm);
    gvm.descTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("DescTableTitle");}, gvm);
    gvm.actionTableTitle = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ActionTableTitle");}, gvm);

    // The table data observable array
    gvm.tabledata = ko.observableArray([]);

    // Add data to the table
    gvm.addTableData = function(id, code, name, desc, teach) {
        // Push data
        var tblOject = {tid: id, tcode: code, tname: name, tdesc: desc, tteach: teach};
        gvm.tabledata.push(tblOject);

        // Attach delete handler to delete button
        $('#removebtn-' + id).bind('click', function(event, data){
            // Delete the table item
            deleteTableItem(id, tblOject);
            event.stopPropagation();
        });

        // Attach edit handler to edit button
        $('#editbtn-' + id).bind('click', function(event, data){
            // Edit the table item
            showEditProjectTypeModal(code, name, desc, id);
            event.stopPropagation();
        });

        // Attach copy handler to copy button
        $('#copybtn-' + id).bind('click', function(event, data){
            // Delete the table item
            copyTableItem(id, tblOject);
            event.stopPropagation();
        });

        //Attach manage handler to manage modules, doelstellingen and criterias to manage button
        $('#managebtn-' + id).bind('click', function(event, data) {
            //TODO
        });

        /*$('#studentbtn-' + id).bind('click', function(event, data) {
            showCoupleStudentListModal(id);
            gvm.currentprojectid = id;
            gvm.currentselectedlist = -1;
            event.stopPropagation();
            loadCoupleDropdown();
        });*/
    }

    gvm.clearTable = function() {
        gvm.tabledata.removeAll();
    }
    /*
    gvm.updateDropdowns = function() {
        $.getJSON('api/teacherrapport/' + gvm.userId, function(data) {
            if(!$.isEmptyObject(data)) {
                $.each(data, function(i, item) {
                    $(".btn-teacher span:first").text(item.teacher);
                    gvm.currentteacherid = item.id;
                    gvm.updateTeacher(item.id);
                    LoadTablePage(item.currentteacherid, 1);
                });
            } else {
                gvm.updateTeacher();
            }
        });
    }*/

    gvm.updateTeacher = function(id) {
        $.getJSON('/api/getteacherrapport/' + id, function(data) {
            gvm.availableTeacher.removeAll();
            $.each(data, function(i, item) {
                console.log(item);
                gvm.availableTeacher.push(item);
                $("#teacherbtn-" + item.id).click(function(){
                    $(".btn-teacher span:first").text($(this).text());
                    gvm.currentteacherid = item.id;
                    gvm.saveLastSelectedDropdowns();
                    loadTablePage(item.id, 1);
                });
            });
        });
    }

    }

/*
 * Delete item from table given the id.
 */
function deleteTableItem(id, tblOject) {
    showYesNoModal("Bent u zeker dat u dit item wil verwijderen? \r\n " +
    "Let op: verwijderde items blijven in het systeem en kunnen weer actief gezet worden door een administrator. " +
    "\r\n Gelieve de administrator te contacteren om een vak definitief te verwijderen.", function(val){
                if(val){
            $.ajax({
                url: "/api/coursedelete/" + id,
                type: "DELETE",
                success: function() {
                    viewModel.tabledata.remove(tblOject);
                }
            });
        }
    });
}
/*
 * Copy item from table given the id.
 */
function copyTableItem(id) {
    showYesNoModal("Bent u zeker ? \r\n " +
    "Let op: verwijderde items blijven in het systeem en kunnen weer actief gezet worden door een administrator. " +
    "\r\n Gelieve de administrator te contacteren om een vak definitief te verwijderen.", function(val){
        if(val){
            $.ajax({
                url: "/api/coursecopy/" + id,
                type: "post",
                success: function() {
                    //tabel refreshen met nieuwe toegevoegde waarde of pagina openen om deze waarde te wijzigen.
                }
            });
        }
    });
}

/*
 * Add a new projecttype
 */
function addNewProjecttypeForm(serialData, callback) {
    $.ajax({
            url: "/api/courserapport",
            type: "POST",
            data: serialData,
            success: function(data) {
                viewModel.addTableData(data['id'], data['code'], data['name'], data['description']);
                callback(true);
            },
            error: function(data) {
                callback(false);
            }
        });
}

/*
 * Add a new projecttype
 */
function addNewProjecttypeRaw(code, name, description, callback) {
    addNewProjecttypeForm("code=" + encodeURIComponent(code) + "&name=" + encodeURIComponent(name) + "&description=" + encodeURIComponent(description), callback);
}

/*
 * Update the projecttype
 * @param {type} id
 * @param {type} code
 * @param {type} name
 * @param {type} description
 * @param {type} callback
 * @returns {undefined}
 */
function updateProjecttypeForm(id, serialData, callback) {
    $.ajax({
        url: "/api/courseupdate/" + id,
        type: "PUT",
        data: serialData,
        success: function(data) {
            //viewModel.addTableData(data['id'], data['code'], data['name'], data['description']);
            loadTablePage(1); //TODO now it is refreshing table after updating but it redirects to pagenr 1     WERKT NIET
            callback(true);
        },
        error: function(data) {
            callback(false);
        }
    });
}

/**
 * update project type
 * @param {type} id
 * @param {type} code
 * @param {type} name
 * @param {type} description
 * @param {type} callback
 * @returns {undefined}
 */
function updateProjecttypeRaw(id, code, name, description, callback) {
    updateProjecttypeForm(id, "code=" + encodeURIComponent(code) + "&name=" + encodeURIComponent(name) + "&description=" + encodeURIComponent(description), callback);
}

/*
 * Load page of the table
 */
function loadTablePage(pagenr)
{
    $.getJSON('/api/coursesrapport/page/' + pagenr, function(data){

        /* Clear current table page */
        viewModel.clearTable();

        // Load table data
        $.each(data.data, function(i, item) {
            viewModel.addTableData(item.id, item.code, item.name, item.description, item.leerkracht);
        });

        /* Let previous en next buttons work */
        if(data.prev == "none"){
            $('#pager-prev-btn').addClass('disabled');
        } else {
            $('#pager-prev-btn').removeClass('disabled');
            $('#pager-prev-btn a').click(function(){
                loadTablePage(data.prev);
            });
        }

        if(data.next == "none"){
            $('#pager-next-btn').addClass('disabled');
        } else {
            $('#pager-next-btn').removeClass('disabled');
            $('#pager-next-btn a').click(function(){
                loadTablePage(data.next);
            });
        }

        // Number of pager buttons
        var numItems = $('.pager-nr-btn').length;

        /* Calculate for the pager buttons */
        var lowPage = Math.floor(pagenr/numItems) + 1;

        $('.pager-nr-btn').each(function() {
            /* calculate current page number */
            var thispagenr = lowPage++;

            /* Add the page number */
            $(this).html('' + thispagenr + '');

            /* Add active class to current page */
            if(thispagenr == pagenr) {
                $(this).addClass('active');
            } else {
                $(this).removeClass('active');
            }

            /* Disable inactive classes and bind handlers to active classes */
            if(thispagenr > data.pagecount) {
                $(this).addClass('disabled');
            } else {
                /* Add click listener for button */
                $(this).click(function() {
                    loadTablePage(thispagenr);
                });
            }
        });
    });
}

/**
 * Show a new projecttype modal.
 * @returns {undefined}
 */
function showNewProjectTypeModal()
{
    resetGeneralModal();
    setGeneralModalTitle(i18n.__("AddNewCourse"));
    setGeneralModalBody('<form id="newprojectform"> \

 \
                <input type="text" class="form-control input-lg" placeholder="' + i18n.__('CodeTableTitle') + '" " name="code"> \

 \

 \
                <input type="text" class="form-control input-lg" placeholder="' + i18n.__('NameTableTitle') + '" name="name"> \

 \

 \
                <input type="text" class="form-control input-lg" placeholder="' + i18n.__('DescTableTitle') + '" name="description"> \

 \
            </form>' );

    addGeneralModalButton(i18n.__("AddBtn"), function(){
        console.log($('#newprojectform').serialize());
       addNewProjecttypeForm($('#newprojectform').serialize(), function(result){
            hideModal();
        });
    });

    showGeneralModal();
}

/**
 * Show the edit projecttype modal.
 * @param {type} code
 * @param {type} name
 * @param {type} description
 * @param {type} tid
 * @returns {undefined}
 */
function showEditProjectTypeModal(code, name, description, tid)
{
  resetGeneralModal();
    setGeneralModalTitle(i18n.__("EditProjectTitle2"));
    setGeneralModalBody('<form id="updateprojectform"> \

 \
                <input type="text" class="form-control input-lg" placeholder="' + i18n.__('CodeTableTitle') + '" " name="code" value="' + code + '"> \

 \

 \
                <input type="text" class="form-control input-lg" placeholder="' + i18n.__('NameTableTitle') + '" name="name" value="' + name + '"> \

 \

 \
                <input type="text" class="form-control input-lg" placeholder="' + i18n.__('DescTableTitle') + '" name="description" value="' + description + '"> \

 \
        </form>');
    $.getJSON()

    addGeneralModalButton(i18n.__("SaveBtn"), function(){
        updateProjecttypeForm(tid, $('#updateprojectform').serialize(), function(result){
            hideModal();
        });
    });

    addGeneralModalButton(i18n.__("CancelBtn"), function(){
        hideModal();
    })

    showGeneralModal();
}

function showCoupleStudentListModal(projectid) {
    viewModel.currentselectedlist = -1;
    resetGeneralModal();
    setGeneralModalTitle(i18n.__("CoupleStudentList"));
    setGeneralModalBody(
        '
' +
            '<button class="btn btn-default dropdown-toggle" type="button" id="dropdownStudLists" data-toggle="dropdown" aria-expanded="true">' +
                'Dropdown' +
                '' +
            '</button>' +
            '
' +
            '
' +
        '
');

    addGeneralModalButton(i18n.__("SaveBtn"), function() {
        updateListForm(viewModel.currentselectedlist, $('#coupleform').serialize(), function(result){
            hideModal();
        });
    });

    addGeneralModalButton(i18n.__("CancelBtn"), function(){
        hideModal();
    })
    showGeneralModal();
}
function loadCoupleDropdown() {
    $.getJSON('/api/studentlists/' + viewModel.userId, function(data) {
        $.each(data, function(i, item) {
            $("#ddlLists").append('
' + item.name + '
')
            $("#dropdownitem-" + item.id).click(function(){
                $(this).parent().parent().parent().removeClass("open");
                $(this).parent().parent().parent().find(".btn").html($(this).text() + '');
                viewModel.currentselectedlist = item.id;
            });
        });
    });
    $("#dropdownStudLists").click(function() {
        $(this).parent().toggleClass("open");
    });
}

function updateListForm(id, serialData, callback) {
    $.ajax({
        url: "/api/project/" + viewModel.currentprojectid + "/studentlist/" + id,
        type: "POST",
        data: serialData,
        success: function(data) {
            callback(true);
        },
        error: function(data) {
            callback(false);
        }
    });
}

function initPage() {
    // Add button handlers
    $('#addProjectTypeBtn').click(function(){
        showNewProjectTypeModal();
    });

    $.getJSON('/api/currentuser', function(data) {
        viewModel.userId = data.id;
        /*viewModel.updateDropdowns();*/
    });

    loadTablePage(1);
}

<|endoftext|>


<commit_before>/**
* @license Apache-2.0
*
* Copyright (c) 2018 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* eslint-disable max-len */

'use strict';

// MODULES //

var isStringArray = require( '@stdlib/assert/is-string-array' ).primitives;
var isString = require( '@stdlib/assert/is-string' ).isPrimitive;
var isArrayBuffer = require( '@stdlib/assert/is-arraybuffer' );
var propertiesIn = require( '@stdlib/utils/properties-in' );
var typedarray = require( '@stdlib/array/typed' );
var Int8Array = require( '@stdlib/array/int8' );
var getDtype = require( '@stdlib/array/dtype' );
var setReadWriteAccessor = require( '@stdlib/utils/define-read-write-accessor' );
var floor = require( '@stdlib/math/base/special/floor' );
var contains = require( './contains.js' );
var validate = require( './validate.js' );

// VARIABLES //

var RESERVED_PROPS = propertiesIn( new Int8Array( 0 ) );

// MAIN //

/**
* Returns a named typed tuple factory.
*
* @param {StringArray} names - field (property) names
* @param {Options} [options] - options
* @param {string} [options.dtype="float64"] - default data type
* @throws {TypeError} must provide an array of strings
* @throws {Error} cannot provide a reserved field (property) name
* @throws {TypeError} must provide valid options
* @throws {Error} must provide a recognized data type
* @returns {Function} factory function
*
* @example
* var point = factory( [ 'x', 'y' ] );
*
* var p = point( [ 1.0, -1.0 ] );
*
* var x = p[ 0 ];
* // returns 1.0
*
* x = p.x;
* // returns 1.0
*
* var y = p[ 1 ];
* // returns -1.0
*
* y = p.y;
* // returns -1.0
*/
function factory( names, options ) {
	var nfields;
	var fields;
	var opts;
	var err;
	var i;
	if ( !isStringArray( names ) ) {
		throw new TypeError( 'invalid argument. Must provide an array of strings. Value: `' + names + '`.' );
	}
	fields = names.slice();
	nfields = fields.length;
	for ( i = 0; i < nfields; i++ ) {
		if ( contains( RESERVED_PROPS, fields[ i ] ) ) {
			throw new Error( 'invalid argument. Provided field name is reserved. Name: `' + fields[ i ] + '`.' );
		}
	}
	opts = {
		'dtype': 'float64'
	};
	if ( arguments.length > 1 ) {
		err = validate( opts, options );
		if ( err ) {
			throw err;
		}
	}
	return namedtypedtuple;

	/**
	* Returns a named typed tuple.
	*
	* @private
	* @param {(TypedArray|ArrayLikeObject|ArrayBuffer)} [arg] - a typed array, array-like object, or buffer
	* @param {NonNegativeInteger} [byteOffset=0] - byte offset
	* @param {string} [dtype] - data type
	* @throws {TypeError} must provide a recognized data type
	* @throws {RangeError} arguments must be compatible with tuple length
	* @returns {TypedArray} named typed tuple
	*/
	function namedtypedtuple() {
		var indices;
		var dtype;
		var nargs;
		var tuple;
		var i;

		nargs = arguments.length;
		if ( nargs <= 0 ) {
			tuple = typedarray( nfields );
		} else if ( nargs === 1 ) {
			if ( isString( arguments[ 0 ] ) ) {
				// Arguments: [ dtype ]
				tuple = typedarray( nfields, arguments[ 0 ] );
			} else if ( isArrayBuffer( arguments[ 0 ] ) ) {
				// Arguments: [ ArrayBuffer ]
				tuple = typedarray( arguments[ 0 ], 0, nfields, opts.dtype );
			} else {
				// Arguments: [ TypedArray|ArrayLikeObject ]
				tuple = typedarray( arguments[ 0 ], opts.dtype );
			}
		} else if ( nargs === 2 ) {
			if ( isArrayBuffer( arguments[ 0 ] ) ) {
				if ( isString( arguments[ 1 ] ) ) {
					// Arguments: [ ArrayBuffer, dtype ]
					tuple = typedarray( arguments[ 0 ], 0, nfields, arguments[ 1 ] );
				} else {
					// Arguments: [ ArrayBuffer, byteOffset ]
					tuple = typedarray( arguments[ 0 ], arguments[ 1 ], nfields, opts.dtype );
				}
			} else {
				// Arguments: [ TypedArray|ArrayLikeObject, dtype ]
				tuple = typedarray( arguments[ 0 ], arguments[ 1 ] );
			}
		} else {
			// Arguments: [ ArrayBuffer, byteOffset, dtype ]
			tuple = typedarray( arguments[ 0 ], arguments[ 1 ], nfields, arguments[ 2 ] );
		}
		if ( tuple.length !== nfields ) {
			throw new RangeError( 'invalid arguments. Arguments are incompatible with number of tuple fields. Tuple length: `' + tuple.length + '`.' );
		}
		dtype = getDtype( tuple );

		indices = []; // indirect index look-up table
		for ( i = 0; i < nfields; i++ ) {
			indices.push( i );
			setReadWriteAccessor( tuple, fields[ i ], getter( i ), setter( i ) );
		}
		// TODO: entries => [ index, key, value ]

		tuple.every = every;
		tuple.filter = filter;
		tuple.find = find;
		tuple.findIndex = findIndex;
		tuple.forEach = forEach;

		// TODO: keys => [ index, key ]

		tuple.map = map;

		// TODO: reduce => clbk( prev, curr, index, name, array )

		// TODO: reduceRight => clbk( prev, curr, index, name, array )

		tuple.reverse = reverse;
		tuple.some = some;

		// TODO: sort => update mapping of keys to indices (this may require a custom sort algorithm to allow tracking indices)

		// TODO: subtuple => similar to subarray but a new tuple atop the same arraybuffer

		// TODO: toString (?) => custom string representation based on tuple name and fields

		return tuple;

		/**
		* Returns an accessor to retrieve a tuple value.
		*
		* @private
		* @param {NonNegativeInteger} i - tuple index
		* @returns {Function} accessor
		*/
		function getter( i ) {
			return get;

			/**
			* Returns a tuple value.
			*
			* @private
			* @returns {number} tuple value
			*/
			function get() {
				return tuple[ indices[ i ] ];
			}
		}

		/**
		* Returns an accessor to set a tuple value.
		*
		* @private
		* @param {NonNegativeInteger} i - tuple index
		* @returns {Function} accessor
		*/
		function setter( i ) {
			return set;

			/**
			* Sets a tuple value.
			*
			* @private
			* @param {number} v - value to set
			*/
			function set( v ) {
				tuple[ indices[ i ] ] = v;
			}
		}

		/**
		* Tests whether all tuple elements pass a test implemented by a predicate function.
		*
		* @private
		* @param {Function} predicate - predicate function
		* @param {*} [thisArg] - execution context
		* @throws {TypeError} `this` must be the host tuple
		* @returns {boolean} boolean indicating if all elements pass
		*/
		function every( predicate, thisArg ) {
			var bool;
			var i;
			if ( this !== tuple ) { // eslint-disable-line no-invalid-this
				throw new TypeError( 'invalid invocation. `this` is not host tuple.' );
			}
			for ( i = 0; i < nfields; i++ ) {
				bool = predicate.call( thisArg, tuple[ i ], i, fields[ indices[i] ], tuple );
				if ( !bool ) {
					return false;
				}
			}
			return true;
		}

		/**
		* Creates a new tuple which includes those elements for which a predicate function returns a truthy value.
		*
		* ## Notes
		*
		* -   The returned tuple has the same data type as the host tuple.
		*
		* @private
		* @param {Function} fcn - filter function
		* @param {*} [thisArg] - execution context
		* @throws {TypeError} `this` must be the host tuple
		* @returns {TypedArray} new tuple
		*/
		function filter( fcn, thisArg ) {
			var fields;
			var bool;
			var out;
			var tmp;
			var i;
			if ( this !== tuple ) { // eslint-disable-line no-invalid-this
				throw new TypeError( 'invalid invocation. `this` is not host tuple.' );
			}
			fields = [];
			tmp = [];
			for ( i = 0; i < nfields; i++ ) {
				bool = fcn.call( thisArg, tuple[ i ], i, fields[ indices[i] ], tuple );
				if ( bool ) {
					fields.push( fields[ indices[i] ] );
					tmp.push( tuple[ i ] );
				}
			}
			if ( fields.length === nfields ) {
				out = namedtypedtuple( tmp, dtype );
			} else if ( fields.length ) {
				out = factory( fields, opts )( tmp );
			}
			return out;
		}

		/**
		* Returns the first tuple element for which a provided predicate function returns a truthy value.
		*
		* @private
		* @param {Function} predicate - predicate function
		* @param {*} [thisArg] - execution context
		* @throws {TypeError} `this` must be the host tuple
		* @returns {(number|void)} tuple element
		*/
		function find( predicate, thisArg ) {
			var bool;
			var i;
			if ( this !== tuple ) { // eslint-disable-line no-invalid-this
				throw new TypeError( 'invalid invocation. `this` is not host tuple.' );
			}
			for ( i = 0; i < nfields; i++ ) {
				bool = predicate.call( thisArg, tuple[ i ], i, fields[ indices[i] ], tuple );
				if ( bool ) {
					return tuple[ i ];
				}
			}
		}

		/**
		* Returns the index of the first tuple element for which a provided predicate function returns a truthy value.
		*
		* ## Notes
		*
		* -   If the predicate function never returns a truthy value, the function returns `-1`.
		*
		* @private
		* @param {Function} predicate - predicate function
		* @param {*} [thisArg] - execution context
		* @throws {TypeError} `this` must be the host tuple
		* @returns {integer} tuple index or `-1`
		*/
		function findIndex( predicate, thisArg ) {
			var bool;
			var i;
			if ( this !== tuple ) { // eslint-disable-line no-invalid-this
				throw new TypeError( 'invalid invocation. `this` is not host tuple.' );
			}
			for ( i = 0; i < nfields; i++ ) {
				bool = predicate.call( thisArg, tuple[ i ], i, fields[ indices[i] ], tuple );
				if ( bool ) {
					return i;
				}
			}
			return -1;
		}

		/**
		* Invokes a callback for each tuple element.
		*
		* @private
		* @param {Function} fcn - function to invoke
		* @param {*} [thisArg] - execution context
		* @throws {TypeError} `this` must be the host tuple
		*/
		function forEach( fcn, thisArg ) {
			var i;
			if ( this !== tuple ) { // eslint-disable-line no-invalid-this
				throw new TypeError( 'invalid invocation. `this` is not host tuple.' );
			}
			for ( i = 0; i < nfields; i++ ) {
				fcn.call( thisArg, tuple[ i ], i, fields[ indices[i] ], tuple );
			}
		}

		/**
		* Maps each tuple element to an element in a new tuple.
		*
		* ## Notes
		*
		* -   The returned tuple has the same data type as the host tuple.
		*
		* @private
		* @param {Function} fcn - map function
		* @param {*} [thisArg] - execution context
		* @throws {TypeError} `this` must be the host tuple
		* @returns {TypedArray} new tuple
		*/
		function map( fcn, thisArg ) {
			var out;
			var i;
			if ( this !== tuple ) { // eslint-disable-line no-invalid-this
				throw new TypeError( 'invalid invocation. `this` is not host tuple.' );
			}
			out = namedtypedtuple( dtype );
			for ( i = 0; i < nfields; i++ ) {
				out[ i ] = fcn.call( thisArg, tuple[ i ], i, fields[ indices[i] ], tuple );
			}
			return out;
		}

		/**
		* Reverses a tuple **in-place**.
		*
		* @private
		* @throws {TypeError} `this` must be the host tuple
		* @returns {TypedArray} reversed tuple
		*/
		function reverse() {
			var tmp;
			var i;
			var j;
			if ( this !== tuple ) { // eslint-disable-line no-invalid-this
				throw new TypeError( 'invalid invocation. `this` is not host tuple.' );
			}
			for ( i = 0; i < floor( nfields/2 ); i++ ) {
				j = nfields - i - 1;
				tmp = tuple[ i ];
				tuple[ i ] = tuple[ j ];
				tuple[ j ] = tmp;
			}
			for ( i = 0; i < nfields; i++ ) {
				indices[ i ] = nfields - indices[ i ] - 1;
			}
			return tuple;
		}

		/**
		* Tests whether at least one tuple element passes a test implemented by a predicate function.
		*
		* @private
		* @param {Function} predicate - predicate function
		* @param {*} [thisArg] - execution context
		* @throws {TypeError} `this` must be the host tuple
		* @returns {boolean} boolean indicating if at least one element passes
		*/
		function some( predicate, thisArg ) {
			var bool;
			var i;
			if ( this !== tuple ) { // eslint-disable-line no-invalid-this
				throw new TypeError( 'invalid invocation. `this` is not host tuple.' );
			}
			for ( i = 0; i < nfields; i++ ) {
				bool = predicate.call( thisArg, tuple[ i ], i, fields[ indices[i] ], tuple );
				if ( bool ) {
					return true;
				}
			}
			return false;
		}
	}

	// TODO: (read-only) static methods => of, from
}

// EXPORTS //

module.exports = factory;
<commit_msg>Add method to return tuple fields<commit_after>/**
* @license Apache-2.0
*
* Copyright (c) 2018 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* eslint-disable max-len */

'use strict';

// MODULES //

var isStringArray = require( '@stdlib/assert/is-string-array' ).primitives;
var isString = require( '@stdlib/assert/is-string' ).isPrimitive;
var isArrayBuffer = require( '@stdlib/assert/is-arraybuffer' );
var propertiesIn = require( '@stdlib/utils/properties-in' );
var typedarray = require( '@stdlib/array/typed' );
var Int8Array = require( '@stdlib/array/int8' );
var getDtype = require( '@stdlib/array/dtype' );
var setReadWriteAccessor = require( '@stdlib/utils/define-read-write-accessor' );
var floor = require( '@stdlib/math/base/special/floor' );
var contains = require( './contains.js' );
var validate = require( './validate.js' );

// VARIABLES //

var RESERVED_PROPS = propertiesIn( new Int8Array( 0 ) );

// MAIN //

/**
* Returns a named typed tuple factory.
*
* @param {StringArray} names - field (property) names
* @param {Options} [options] - options
* @param {string} [options.dtype="float64"] - default data type
* @throws {TypeError} must provide an array of strings
* @throws {Error} cannot provide a reserved field (property) name
* @throws {TypeError} must provide valid options
* @throws {Error} must provide a recognized data type
* @returns {Function} factory function
*
* @example
* var point = factory( [ 'x', 'y' ] );
*
* var p = point( [ 1.0, -1.0 ] );
*
* var x = p[ 0 ];
* // returns 1.0
*
* x = p.x;
* // returns 1.0
*
* var y = p[ 1 ];
* // returns -1.0
*
* y = p.y;
* // returns -1.0
*/
function factory( names, options ) {
	var nfields;
	var fields;
	var opts;
	var err;
	var i;
	if ( !isStringArray( names ) ) {
		throw new TypeError( 'invalid argument. Must provide an array of strings. Value: `' + names + '`.' );
	}
	fields = names.slice();
	nfields = fields.length;
	for ( i = 0; i < nfields; i++ ) {
		if ( contains( RESERVED_PROPS, fields[ i ] ) ) {
			throw new Error( 'invalid argument. Provided field name is reserved. Name: `' + fields[ i ] + '`.' );
		}
	}
	opts = {
		'dtype': 'float64'
	};
	if ( arguments.length > 1 ) {
		err = validate( opts, options );
		if ( err ) {
			throw err;
		}
	}
	return namedtypedtuple;

	/**
	* Returns a named typed tuple.
	*
	* @private
	* @param {(TypedArray|ArrayLikeObject|ArrayBuffer)} [arg] - a typed array, array-like object, or buffer
	* @param {NonNegativeInteger} [byteOffset=0] - byte offset
	* @param {string} [dtype] - data type
	* @throws {TypeError} must provide a recognized data type
	* @throws {RangeError} arguments must be compatible with tuple length
	* @returns {TypedArray} named typed tuple
	*/
	function namedtypedtuple() {
		var indices;
		var dtype;
		var nargs;
		var tuple;
		var i;

		nargs = arguments.length;
		if ( nargs <= 0 ) {
			tuple = typedarray( nfields );
		} else if ( nargs === 1 ) {
			if ( isString( arguments[ 0 ] ) ) {
				// Arguments: [ dtype ]
				tuple = typedarray( nfields, arguments[ 0 ] );
			} else if ( isArrayBuffer( arguments[ 0 ] ) ) {
				// Arguments: [ ArrayBuffer ]
				tuple = typedarray( arguments[ 0 ], 0, nfields, opts.dtype );
			} else {
				// Arguments: [ TypedArray|ArrayLikeObject ]
				tuple = typedarray( arguments[ 0 ], opts.dtype );
			}
		} else if ( nargs === 2 ) {
			if ( isArrayBuffer( arguments[ 0 ] ) ) {
				if ( isString( arguments[ 1 ] ) ) {
					// Arguments: [ ArrayBuffer, dtype ]
					tuple = typedarray( arguments[ 0 ], 0, nfields, arguments[ 1 ] );
				} else {
					// Arguments: [ ArrayBuffer, byteOffset ]
					tuple = typedarray( arguments[ 0 ], arguments[ 1 ], nfields, opts.dtype );
				}
			} else {
				// Arguments: [ TypedArray|ArrayLikeObject, dtype ]
				tuple = typedarray( arguments[ 0 ], arguments[ 1 ] );
			}
		} else {
			// Arguments: [ ArrayBuffer, byteOffset, dtype ]
			tuple = typedarray( arguments[ 0 ], arguments[ 1 ], nfields, arguments[ 2 ] );
		}
		if ( tuple.length !== nfields ) {
			throw new RangeError( 'invalid arguments. Arguments are incompatible with number of tuple fields. Tuple length: `' + tuple.length + '`.' );
		}
		dtype = getDtype( tuple );

		indices = []; // indirect index look-up table
		for ( i = 0; i < nfields; i++ ) {
			indices.push( i );
			setReadWriteAccessor( tuple, fields[ i ], getter( i ), setter( i ) );
		}
		// TODO: entries => [ index, key, value ]

		tuple.every = every;

		// TODO: field2ind

		tuple.fields = getFields;
		tuple.filter = filter;
		tuple.find = find;
		tuple.findIndex = findIndex;
		tuple.forEach = forEach;

		// TODO: ind2field

		// TODO: keys => [ index, key ]

		tuple.map = map;

		// TODO: reduce => clbk( prev, curr, index, name, array )

		// TODO: reduceRight => clbk( prev, curr, index, name, array )

		tuple.reverse = reverse;
		tuple.some = some;

		// TODO: sort => update mapping of keys to indices (this may require a custom sort algorithm to allow tracking indices)

		// TODO: subtuple => similar to subarray but a new tuple atop the same arraybuffer

		// TODO: toString (?) => custom string representation based on tuple name and fields

		return tuple;

		/**
		* Returns an accessor to retrieve a tuple value.
		*
		* @private
		* @param {NonNegativeInteger} i - tuple index
		* @returns {Function} accessor
		*/
		function getter( i ) {
			return get;

			/**
			* Returns a tuple value.
			*
			* @private
			* @returns {number} tuple value
			*/
			function get() {
				return tuple[ indices[ i ] ];
			}
		}

		/**
		* Returns an accessor to set a tuple value.
		*
		* @private
		* @param {NonNegativeInteger} i - tuple index
		* @returns {Function} accessor
		*/
		function setter( i ) {
			return set;

			/**
			* Sets a tuple value.
			*
			* @private
			* @param {number} v - value to set
			*/
			function set( v ) {
				tuple[ indices[ i ] ] = v;
			}
		}

		/**
		* Tests whether all tuple elements pass a test implemented by a predicate function.
		*
		* @private
		* @param {Function} predicate - predicate function
		* @param {*} [thisArg] - execution context
		* @throws {TypeError} `this` must be the host tuple
		* @returns {boolean} boolean indicating if all elements pass
		*/
		function every( predicate, thisArg ) {
			var bool;
			var i;
			if ( this !== tuple ) { // eslint-disable-line no-invalid-this
				throw new TypeError( 'invalid invocation. `this` is not host tuple.' );
			}
			for ( i = 0; i < nfields; i++ ) {
				bool = predicate.call( thisArg, tuple[ i ], i, fields[ indices[i] ], tuple );
				if ( !bool ) {
					return false;
				}
			}
			return true;
		}

		/**
		* Returns the list of tuple fields.
		*
		* @private
		* @returns {StringArray} tuple fields
		*/
		function getFields() {
			return fields.slice();
		}

		/**
		* Creates a new tuple which includes those elements for which a predicate function returns a truthy value.
		*
		* ## Notes
		*
		* -   The returned tuple has the same data type as the host tuple.
		*
		* @private
		* @param {Function} fcn - filter function
		* @param {*} [thisArg] - execution context
		* @throws {TypeError} `this` must be the host tuple
		* @returns {TypedArray} new tuple
		*/
		function filter( fcn, thisArg ) {
			var fields;
			var bool;
			var out;
			var tmp;
			var i;
			if ( this !== tuple ) { // eslint-disable-line no-invalid-this
				throw new TypeError( 'invalid invocation. `this` is not host tuple.' );
			}
			fields = [];
			tmp = [];
			for ( i = 0; i < nfields; i++ ) {
				bool = fcn.call( thisArg, tuple[ i ], i, fields[ indices[i] ], tuple );
				if ( bool ) {
					fields.push( fields[ indices[i] ] );
					tmp.push( tuple[ i ] );
				}
			}
			if ( fields.length === nfields ) {
				out = namedtypedtuple( tmp, dtype );
			} else if ( fields.length ) {
				out = factory( fields, opts )( tmp );
			}
			return out;
		}

		/**
		* Returns the first tuple element for which a provided predicate function returns a truthy value.
		*
		* @private
		* @param {Function} predicate - predicate function
		* @param {*} [thisArg] - execution context
		* @throws {TypeError} `this` must be the host tuple
		* @returns {(number|void)} tuple element
		*/
		function find( predicate, thisArg ) {
			var bool;
			var i;
			if ( this !== tuple ) { // eslint-disable-line no-invalid-this
				throw new TypeError( 'invalid invocation. `this` is not host tuple.' );
			}
			for ( i = 0; i < nfields; i++ ) {
				bool = predicate.call( thisArg, tuple[ i ], i, fields[ indices[i] ], tuple );
				if ( bool ) {
					return tuple[ i ];
				}
			}
		}

		/**
		* Returns the index of the first tuple element for which a provided predicate function returns a truthy value.
		*
		* ## Notes
		*
		* -   If the predicate function never returns a truthy value, the function returns `-1`.
		*
		* @private
		* @param {Function} predicate - predicate function
		* @param {*} [thisArg] - execution context
		* @throws {TypeError} `this` must be the host tuple
		* @returns {integer} tuple index or `-1`
		*/
		function findIndex( predicate, thisArg ) {
			var bool;
			var i;
			if ( this !== tuple ) { // eslint-disable-line no-invalid-this
				throw new TypeError( 'invalid invocation. `this` is not host tuple.' );
			}
			for ( i = 0; i < nfields; i++ ) {
				bool = predicate.call( thisArg, tuple[ i ], i, fields[ indices[i] ], tuple );
				if ( bool ) {
					return i;
				}
			}
			return -1;
		}

		/**
		* Invokes a callback for each tuple element.
		*
		* @private
		* @param {Function} fcn - function to invoke
		* @param {*} [thisArg] - execution context
		* @throws {TypeError} `this` must be the host tuple
		*/
		function forEach( fcn, thisArg ) {
			var i;
			if ( this !== tuple ) { // eslint-disable-line no-invalid-this
				throw new TypeError( 'invalid invocation. `this` is not host tuple.' );
			}
			for ( i = 0; i < nfields; i++ ) {
				fcn.call( thisArg, tuple[ i ], i, fields[ indices[i] ], tuple );
			}
		}

		/**
		* Maps each tuple element to an element in a new tuple.
		*
		* ## Notes
		*
		* -   The returned tuple has the same data type as the host tuple.
		*
		* @private
		* @param {Function} fcn - map function
		* @param {*} [thisArg] - execution context
		* @throws {TypeError} `this` must be the host tuple
		* @returns {TypedArray} new tuple
		*/
		function map( fcn, thisArg ) {
			var out;
			var i;
			if ( this !== tuple ) { // eslint-disable-line no-invalid-this
				throw new TypeError( 'invalid invocation. `this` is not host tuple.' );
			}
			out = namedtypedtuple( dtype );
			for ( i = 0; i < nfields; i++ ) {
				out[ i ] = fcn.call( thisArg, tuple[ i ], i, fields[ indices[i] ], tuple );
			}
			return out;
		}

		/**
		* Reverses a tuple **in-place**.
		*
		* @private
		* @throws {TypeError} `this` must be the host tuple
		* @returns {TypedArray} reversed tuple
		*/
		function reverse() {
			var tmp;
			var i;
			var j;
			if ( this !== tuple ) { // eslint-disable-line no-invalid-this
				throw new TypeError( 'invalid invocation. `this` is not host tuple.' );
			}
			for ( i = 0; i < floor( nfields/2 ); i++ ) {
				j = nfields - i - 1;
				tmp = tuple[ i ];
				tuple[ i ] = tuple[ j ];
				tuple[ j ] = tmp;
			}
			for ( i = 0; i < nfields; i++ ) {
				indices[ i ] = nfields - indices[ i ] - 1;
			}
			return tuple;
		}

		/**
		* Tests whether at least one tuple element passes a test implemented by a predicate function.
		*
		* @private
		* @param {Function} predicate - predicate function
		* @param {*} [thisArg] - execution context
		* @throws {TypeError} `this` must be the host tuple
		* @returns {boolean} boolean indicating if at least one element passes
		*/
		function some( predicate, thisArg ) {
			var bool;
			var i;
			if ( this !== tuple ) { // eslint-disable-line no-invalid-this
				throw new TypeError( 'invalid invocation. `this` is not host tuple.' );
			}
			for ( i = 0; i < nfields; i++ ) {
				bool = predicate.call( thisArg, tuple[ i ], i, fields[ indices[i] ], tuple );
				if ( bool ) {
					return true;
				}
			}
			return false;
		}
	}

	// TODO: (read-only) static methods => of, from
}

// EXPORTS //

module.exports = factory;
<|endoftext|>