<commit_before>// era-staccato.js
//
// Staccato is (or rather, will be) a small language and intermediate
// representation for writing implementations of untyped,
// garbage-collected, imperative languages that compile to untyped,
// garbage-collected, imperative target platforms.
//
// As a Staccato program runs, it performs simple Staccato operations
// (and maybe some custom native operations) and frequently reaches an
// opportunity for a well-defined state snapshot. For target platforms
// that support saving and loading snapshots, the snapshot formats are
// easy to convert, even if the ideal encodings and usage methods may
// vary between platforms for performance reasons.
//
// Thanks to these well-defined state snapshots, if the user pays
// close attention to what they're doing when they modify their
// Staccato programs, they may upgrade a program while continuing to
// support old snapshots -- maybe even upgrade a program while it's
// running. Staccato has been designed for these use cases! Very small
// changes to a Staccato program will not break compatibility, and
// larger changes that cause missing definition errors can be patched
// by simply providing those definitions alongside the rest of the
// program.
//
// The number of Staccato operations that occur between state
// snapshots is bounded by a function of the Staccato program
// implementation. This bound does not vary dynamically unless the
// implementation itself does! This means Staccato programs are rather
// good citizens when the target platform is a cooperative
// multithreading environment; they won't cause long pauses. (To make
// this bound meaningful, most Staccato operations can be implemented
// in constant time on most target platforms. Unfortunately, an
// exception is the (fn-frame ...) Staccato operation, which performs
// allocation.)
//
// Since the Staccato language and Staccato programs go to the trouble
// to specify an upgrade-friendly snapshot format, and new versions of
// a Staccato program can use old snapshots as they see fit,
// information hiding would be of limited use. Indeed, there would be
// a maintenance problem where function closures embedded in old
// snapshots may represent entities whose interface exposed to newer
// code should be somewhat different, even as their interface exposed
// to older code should remain the same. For this reason, Staccato
// function closures simply do not encapsulate their captured
// variables.
//
// Since Staccato function closures aren't encapsulated, they serve
// double duty as data containers, and indeed they're Staccato's only
// value type. Perhaps a Staccato value can be used like a document
// with content negotiation: If you know exactly how to interpret this
// document type, go ahead and interpret it yourself; otherwise, you
// may choose to negotiate with the document by executing it with
// access to a document describing your intentions.

function localStorageStack() {
    function get( k ) {
        var text = localStorage.get( JSON.stringify( k ) ) || "null";
        try { return JSON.parse( text ); }
        catch ( e ) { return null; }
    }
    function set( k, v ) {
        if ( v === null )
            return void localStorage.clear( JSON.stringify( k ) );
        localStorage.set( JSON.stringify( k ), JSON.stringify( v ) );
    }
    var result = {};
    result.setReturnValue = function ( v ) {
        set( "returnValue", v );
    };
    result.getReturnValue = function () {
        return get( "returnValue" );
    };
    result.push = function ( frame ) {
        var i = ~~get( "frames" );
        set( "frames", i + 1 );
        set( [ "frame", i ], [ frame.frameName, frame.env ] );
    };
    result.pop = function () {
        var i = get( "frames" );
        if ( i !== ~~i )
            return null;
        set( "frames", Math.max( 0, i - 1 ) );
        var result = get( [ "frame", i ] );
        set( [ "frame", i ], null );
        return { frameName: result[ 0 ], env: result[ 1 ] };
    };
    return result;
}

function run( stack, rules ) {
    while ( true ) {
        var frame = stack.pop();
        if ( !frame )
            return stack.getReturnValue();
        var rule = rules[ frame.frameName ];
        var newFrames = rule( frame.env, stack.getReturnValue() );
        while ( newFrames.type === "pendingFrame" ) {
            stack.push( newFrames.frame );
            newFrames = newFrames.next;
        }
        if ( newFrames.type !== "returnValue" )
            throw new Error();
        stack.setReturnValue( newFrames.returnValue );
    }
}

// def ::=
//   // This defines a frame that takes an environment with the
//   // variables needed in the tail-expr minus the given one, and
//   // takes any incoming return value. It proceeds by executing the
//   // tail-expr with that scope augmented by an entry binding the
//   // given variable to the incoming return value. The tail-expr
//   // counts as a new root parent expression and scope boundary for
//   // the purposes of (tail-to-temp ...).
//   (def frame-name opt-var-list var tail-expr)
//
// // When an opt-var-list is not omitted, it overrides the usual
// // behavior for inferring the variables required by a frame
// // definition. This way, frames can be defined that receive more
// // variables than they actually use.
// opt-var-list ::=
//   // Sugar.
//   (var-list-omitted)
//
//   (var-list var-list)
//
// var-list ::=
//   (var-list-nil)
//   (var-list-cons var var-list)
//
// env-expr ::=
//   (env-nil)
//   (env-cons var temp-expr env-expr)
//
// tail-expr ::=
//   // Sugar.
//   (tail-def def tail-expr)
//   (tail-let temp-expr tail-expr)
//
//   (temp-to-tail temp-expr)
//
//   // This calls the given temp-expr's result as a function closure
//   // with the given tail-expr's result as its argument.
//   //
//   // When implementing this operation on a target platform, it may
//   // be a good optimization to special-case
//   // (call (fn-frame frame-name env-expr) tail-expr) so that an
//   // allocation can be avoided.
//   //
//   (call temp-expr tail-expr)
//
//   // If the given temp-expr's result is a function closure that
//   // fits the given frame name and environment pattern, this
//   // proceeds as the first tail-expr with the pattern's variables
//   // in scope. Otherwise, it proceeds as the second tail-expr.
//   // Notice that even though the scope and control flow behave in
//   // special ways here, there's no need to define independent stack
//   // frames for the branches because this is a cheap operation.
//   (if-fn-frame frame-name env-pattern temp-expr
//     tail-expr
//     tail-expr)
//
// temp-expr ::=
//   // Sugar.
//   (temp-def def temp-expr)
//   (temp-let temp-expr temp-expr)
//
//   (local var)
//
//   // This forms a function closure from any frame and any
//   // environment. Whenever the function's argument is supplied, it
//   // will be used as the frame's incoming return value.
//   (fn-frame frame-name env-expr)
//
//   // Sugar.
//   //
//   // This defines and calls a frame that takes an environment with
//   // entries for the variables needed in the remainder of the
//   // parent expression minus the given variable, which (in this
//   // call) is captured from the surrounding lexical scope, and
//   // takes an incoming return value that (in this call) is the
//   // result of the given tail-expr. It proceeds by using that
//   // incoming return value as the starting point for executing the
//   // remainder of the parent expression in that scope, augmented by
//   // a binding of the variable to that incoming return value.
//   //
//   (tail-to-temp frame-name opt-var-list var tail-expr)
//
//   // Sugar.
//   //
//   // This defines and forms a function closure for a frame that
//   // takes an environment with the variables needed in the
//   // tail-expr minus the given variable, which (in this call) is
//   // captured from the surrounding lexical scope. The frame
//   // proceeds by executing the tail-expr with that scope augmented
//   // by an entry binding the given variable to the frame's incoming
//   // return value. The tail-expr counts as a new root parent
//   // expression and scope boundary for the purposes of
//   // (tail-to-temp ...).
//   //
//   (fn frame-name opt-var-list var tail-expr)
//

// TODO: Implement these methods on every corresponding syntax:
// optVarList/varList set()
// optVarList or( varSet )
// optVarList/varList isProvidedProperly()
// optVarList/varList capture()
// tempExpr/tailExpr/envExpr/def getFreeVars( freeVarsAfter )
// tempExpr/tailExpr/envExpr/def desugarVarLists( freeVarsAfter )
// tempExpr/tailExpr/envExpr/def hasProperScope( freeVarsAfter )
// tempExpr/tailExpr/envExpr/def desugarFn()
// tempExpr/tailExpr/envExpr desugarDef()
// def desugarDefIncludingSelf()
// tempExpr/tailExpr/envExpr/def desugarTailToTemp( freeVarsAfter )
// tempExpr/tailExpr/envExpr/def desugarLet()
//
// TODO: Implement list(), desugarDefWriter, idWriter, strMap (should
// be around here somewhere), strMap#subset, args.self, and addSyntax
// (with its special DSL-like injection of an args parameter and an
// expr property).

addSyntax( "tempExpr", "tail-to-temp",
    "frameName optVarList va tailExpr", {

    _map: function ( args, writerMaker, recur ) {
        var writer = writerMaker.make();
        return writer.go( list( "tail-to-temp",
            args.frameName.expr,
            args.optVarList.expr,
            args.va.expr,
            writer.consume( recur( args.tailExpr ) ) ) );
    },

    getFreeVars: function ( args, freeVarsAfter ) {
        var innerFreeVarsAfter =
            freeVarsAfter.minusKey( args.va.expr );
        var declaredInnerFreeVarsAfter = args.optVarList.set();
        return args.tailExpr.getFreeVars(
            declaredInnerFreeVarsAfter || innerFreeVarsAfter );
    },

    desugarVarLists: function ( args, freeVarsAfter ) {
        var innerFreeVarsAfter =
            freeVarsAfter.minusKey( args.va.expr );
        var declaredInnerFreeVarsAfter = args.optVarList.set();
        return list( "tail-to-temp",
            args.frameName.expr,
            args.optVarList.or( innerFreeVarsAfter ),
            args.va.expr,
            args.tailExpr.desugarVarLists(
                declaredInnerFreeVarsAfter || innerFreeVarsAfter ) );
    },
    hasProperScope: function ( args, freeVarsAfter ) {
        var innerFreeVarsAfter =
            freeVarsAfter.minusKey( args.va.expr );
        var declaredInnerFreeVarsAfter = args.optVarList.set();
        return args.optVarList.isProvidedProperly() &&
            innerFreeVarsAfter.subset( declaredInnerFreeVarsAfter ) &&
            args.tailExpr.hasProperScope(
                declaredInnerFreeVarsAfter );
    },
    desugarFn: function ( args ) {
        return args.self._map( idWriter, function ( arg ) {
            return arg.desugarFn();
        } );
    },
    desugarDef: function ( args ) {
        return args.self._map( desugarDefWriter, function ( arg ) {
            return arg.desugarDef();
        } );
    },
    desugarTailToTemp: function ( args, freeVarsAfter ) {
        return {
            tailToTemp: { frameName: args.frameName,
                varList: args.optVarList, va: args.va },
            frameBody: args.va
        };
    },
    desugarLet: function ( args ) {
        throw new Error();
    }
} );
addSyntax( "tempExpr", "fn", "frameName optVarList va tailExpr", {
    getFreeVars: function ( args, freeVarsAfter ) {
        var innerFreeVarsAfter = strSet();
        var innerFreeVars = args.tailExpr.
            getFreeVars( innerFreeVarsAfter ).minus( args.va.expr );
        var declaredInnerFreeVars = args.optVarList.set();
        return (declaredInnerFreeVars || innerFreeVars).plus(
            freeVarsAfter );
    },

    desugarVarLists: function ( args, freeVarsAfter ) {
        var innerFreeVarsAfter = strSet();
        var innerFreeVars = args.tailExpr.
            getFreeVars( innerFreeVarsAfter ).minus( args.va.expr );
        return list( "fn",
            args.frameName.expr,
            args.optVarList.or( innerFreeVars ),
            args.va.expr,
            args.tailExpr.desugarVarLists( innerFreeVarsAfter ) );
    },
    hasProperScope: function ( args, freeVarsAfter ) {
        var innerFreeVarsAfter = strSet();
        var innerFreeVars = args.tailExpr.
            getFreeVars( innerFreeVarsAfter ).minus( args.va.expr );
        var declaredInnerFreeVars = args.optVarList.set();
        return args.optVarList.isProvidedProperly() &&
            innerFreeVars.subset( declaredInnerFreeVars ) &&
            args.tailExpr.hasProperScope( innerFreeVarsAfter );
    },
    desugarFn: function ( args ) {
        return list( "temp-def",
            list( "def", args.frameName.expr,
                args.optVarList.expr,
                args.va.expr,
                args.tailExpr.desugarFn() ),
            list( "fn-frame", args.frameName.expr,
                args.optVarList.capture() ) );
    },
    desugarDef: function ( args ) {
        throw new Error();
    },
    desugarTailToTemp: function ( args, freeVarsAfter ) {
        throw new Error();
    },
    desugarLet: function ( args ) {
        throw new Error();
    }
} );
<commit_msg>In Staccato, implemented desugaring for (if-fn-frame ...). Desugaring for the remaining syntaxes should be straightforward, at least once a few of their desugarTailToTemp methods have been implemented.<commit_after>// era-staccato.js
//
// Staccato is (or rather, will be) a small language and intermediate
// representation for writing implementations of untyped,
// garbage-collected, imperative languages that compile to untyped,
// garbage-collected, imperative target platforms.
//
// As a Staccato program runs, it performs simple Staccato operations
// (and maybe some custom native operations) and frequently reaches an
// opportunity for a well-defined state snapshot. For target platforms
// that support saving and loading snapshots, the snapshot formats are
// easy to convert, even if the ideal encodings and usage methods may
// vary between platforms for performance reasons.
//
// Thanks to these well-defined state snapshots, if the user pays
// close attention to what they're doing when they modify their
// Staccato programs, they may upgrade a program while continuing to
// support old snapshots -- maybe even upgrade a program while it's
// running. Staccato has been designed for these use cases! Very small
// changes to a Staccato program will not break compatibility, and
// larger changes that cause missing definition errors can be patched
// by simply providing those definitions alongside the rest of the
// program.
//
// The number of Staccato operations that occur between state
// snapshots is bounded by a function of the Staccato program
// implementation. This bound does not vary dynamically unless the
// implementation itself does! This means Staccato programs are rather
// good citizens when the target platform is a cooperative
// multithreading environment; they won't cause long pauses. (To make
// this bound meaningful, most Staccato operations can be implemented
// in constant time on most target platforms. Unfortunately, an
// exception is the (fn-frame ...) Staccato operation, which performs
// allocation.)
//
// Since the Staccato language and Staccato programs go to the trouble
// to specify an upgrade-friendly snapshot format, and new versions of
// a Staccato program can use old snapshots as they see fit,
// information hiding would be of limited use. Indeed, there would be
// a maintenance problem where function closures embedded in old
// snapshots may represent entities whose interface exposed to newer
// code should be somewhat different, even as their interface exposed
// to older code should remain the same. For this reason, Staccato
// function closures simply do not encapsulate their captured
// variables.
//
// Since Staccato function closures aren't encapsulated, they serve
// double duty as data containers, and indeed they're Staccato's only
// value type. Perhaps a Staccato value can be used like a document
// with content negotiation: If you know exactly how to interpret this
// document type, go ahead and interpret it yourself; otherwise, you
// may choose to negotiate with the document by executing it with
// access to a document describing your intentions.

function localStorageStack() {
    function get( k ) {
        var text = localStorage.get( JSON.stringify( k ) ) || "null";
        try { return JSON.parse( text ); }
        catch ( e ) { return null; }
    }
    function set( k, v ) {
        if ( v === null )
            return void localStorage.clear( JSON.stringify( k ) );
        localStorage.set( JSON.stringify( k ), JSON.stringify( v ) );
    }
    var result = {};
    result.setReturnValue = function ( v ) {
        set( "returnValue", v );
    };
    result.getReturnValue = function () {
        return get( "returnValue" );
    };
    result.push = function ( frame ) {
        var i = ~~get( "frames" );
        set( "frames", i + 1 );
        set( [ "frame", i ], [ frame.frameName, frame.env ] );
    };
    result.pop = function () {
        var i = get( "frames" );
        if ( i !== ~~i )
            return null;
        set( "frames", Math.max( 0, i - 1 ) );
        var result = get( [ "frame", i ] );
        set( [ "frame", i ], null );
        return { frameName: result[ 0 ], env: result[ 1 ] };
    };
    return result;
}

function run( stack, rules ) {
    while ( true ) {
        var frame = stack.pop();
        if ( !frame )
            return stack.getReturnValue();
        var rule = rules[ frame.frameName ];
        var newFrames = rule( frame.env, stack.getReturnValue() );
        while ( newFrames.type === "pendingFrame" ) {
            stack.push( newFrames.frame );
            newFrames = newFrames.next;
        }
        if ( newFrames.type !== "returnValue" )
            throw new Error();
        stack.setReturnValue( newFrames.returnValue );
    }
}

// def ::=
//   // This defines a frame that takes an environment with the
//   // variables needed in the tail-expr minus the given one, and
//   // takes any incoming return value. It proceeds by executing the
//   // tail-expr with that scope augmented by an entry binding the
//   // given variable to the incoming return value.
//   //
//   // The tail-expr counts as a new root parent expression and scope
//   // boundary for the purposes of (tail-to-temp ...).
//   //
//   (def frame-name opt-var-list var tail-expr)
//
// // When an opt-var-list is not omitted, it overrides the usual
// // behavior for inferring the variables required by a frame
// // definition. This way, frames can be defined that receive more
// // variables than they actually use.
// opt-var-list ::=
//   // Sugar.
//   (var-list-omitted)
//
//   (var-list var-list)
//
// var-list ::=
//   (var-list-nil)
//   (var-list-cons var var-list)
//
// env-expr ::=
//   (env-nil)
//   (env-cons var temp-expr env-expr)
//
// env-pattern ::=
//   (env-pattern-nil)
//
//   // NOTE: The first var is the key in the environment, and the
//   // second var is the local variable to bind it to.
//   (env-pattern-cons var var env-expr)
//
// tail-expr ::=
//   // Sugar.
//   (tail-def def tail-expr)
//   (tail-let temp-expr tail-expr)
//
//   (temp-to-tail temp-expr)
//
//   // This calls the given temp-expr's result as a function closure
//   // with the given tail-expr's result as its argument.
//   //
//   // When implementing this operation on a target platform, it may
//   // be a good optimization to special-case
//   // (call (fn-frame frame-name env-expr) tail-expr) so that an
//   // allocation can be avoided.
//   //
//   (call temp-expr tail-expr)
//
//   // If the given temp-expr's result is a function closure that
//   // fits the given frame name and environment pattern, this
//   // proceeds as the first tail-expr with the pattern's variables
//   // in scope. Otherwise, it proceeds as the second tail-expr.
//   //
//   // Each tail-expr counts as a new root parent expression and
//   // scope boundary for the purposes of (tail-to-temp ...).
//   //
//   // Notice that even though the scope and control flow behave in
//   // special ways here, there's no need to define independent stack
//   // frames for the branches because this is a cheap operation.
//   //
//   (if-fn-frame frame-name env-pattern temp-expr
//     tail-expr
//     tail-expr)
//
// temp-expr ::=
//   // Sugar.
//   (temp-def def temp-expr)
//   (temp-let temp-expr temp-expr)
//
//   (local var)
//
//   // This forms a function closure from any frame and any
//   // environment. Whenever the function's argument is supplied, it
//   // will be used as the frame's incoming return value.
//   (fn-frame frame-name env-expr)
//
//   // Sugar.
//   //
//   // This defines and calls a frame that takes an environment with
//   // entries for the variables needed in the remainder of the
//   // parent expression minus the given variable, which (in this
//   // call) is captured from the surrounding lexical scope, and
//   // takes an incoming return value that (in this call) is the
//   // result of the given tail-expr. It proceeds by using that
//   // incoming return value as the starting point for executing the
//   // remainder of the parent expression in that scope, augmented by
//   // a binding of the variable to that incoming return value.
//   //
//   // The tail-expr counts as a new root parent expression and scope
//   // boundary for the purposes of (tail-to-temp ...).
//   //
//   (tail-to-temp frame-name opt-var-list var tail-expr)
//
//   // Sugar.
//   //
//   // This defines and forms a function closure for a frame that
//   // takes an environment with the variables needed in the
//   // tail-expr minus the given variable, which (in this call) is
//   // captured from the surrounding lexical scope. The frame
//   // proceeds by executing the tail-expr with that scope augmented
//   // by an entry binding the given variable to the frame's incoming
//   // return value.
//   //
//   // The tail-expr counts as a new root parent expression and scope
//   // boundary for the purposes of (tail-to-temp ...).
//   //
//   (fn frame-name opt-var-list var tail-expr)

// TODO: Implement these methods on every corresponding syntax:
// optVarList/varList set()
// optVarList or( varSet )
// optVarList/varList isProvidedProperly()
// optVarList/varList capture()
// envPattern vals()
// envPattern isProper()
// tempExpr/tailExpr/envExpr/def getFreeVars( freeVarsAfter )
// tempExpr/tailExpr/envExpr/def desugarVarLists( freeVarsAfter )
// tempExpr/tailExpr/envExpr/def hasProperScope( freeVarsAfter )
// tempExpr/tailExpr/envExpr/def desugarFn()
// tempExpr/tailExpr/envExpr/def desugarTailToTemp( freeVarsAfter )
// tempExpr/tailExpr/envExpr desugarDef()
// def desugarDefIncludingSelf()
// tempExpr/tailExpr/envExpr/def desugarLet()
//
// TODO: Implement list(), desugarDefWriterMaker, idWriterMaker,
// strMap (should be around here somewhere), strMap#subset, args.self,
// parseSyntax, and addSyntax (with its special DSL-like injection of
// an args parameter and an expr property).

function processTailToTempRoot( exprObj ) {
    var desugared = exprObj.desugarTailToTemp( strMap() );
    if ( desugared.type === "expr" ) {
        return desugared.expr;
    } else if ( desugared.type === "tailToTemp" ) {
        return processTailToTempRoot( parseSyntax(
            list( "tail-def",
                list( "def",
                    desugared.frameName.expr,
                    desugared.varList.expr,
                    desugared.va.expr,
                    desugared.frameBodyExpr ),
                list( "call"
                    list( "fn-frame", desugared.frameName.expr,
                        desugared.varList.capture() ),
                    desugared.arg.expr ) ) ) ) );
    } else {
        throw new Error();
    }
}

addSyntax( "if-fn-frame", "tailExpr",
    "frameName envPattern tailExpr tailExpr", {

    _map: function ( args, writerMaker, recur ) {
        var writer = writerMaker.make();
        return writer.go( list( "if-fn-frame",
            args.frameName.expr,
            args.envPattern.expr,
            writer.consume( recur( args[ 2 ].expr ) ),
            writer.consume( recur( args[ 3 ].expr ) ) ) );
    },

    getFreeVars: function ( args, freeVarsAfter ) {
        return args[ 2 ].getFreeVars( strMap() ).
            minus( args.envPattern.vals() ).
            plus( args[ 3 ].getFreeVars( strMap() ) ).
            plus( freeVarsAfter );
    },

    desugarVarLists: function ( args, freeVarsAfter ) {
        return args.self._map( idWriterMaker, function ( arg ) {
            return arg.desugarVarLists( strMap() );
        } );
    },
    hasProperScope: function ( args, freeVarsAfter ) {
        return args.envPattern.isProper() &&
            args[ 2 ].hasProperScope( strMap() ) &&
            args[ 3 ].hasProperScope( strMap() );
    },
    desugarFn: function ( args ) {
        return args.self._map( idWriterMaker, function ( arg ) {
            return arg.desugarFn();
        } );
    },
    desugarTailToTemp: function ( args, freeVarsAfter ) {
        return {
            type: "expr"
            expr: list( "if-fn-frame",
                args.frameName.expr,
                args.envPattern.expr,
                processTailToTempRoot( args[ 2 ] ),
                processTailToTempRoot( args[ 3 ] ) );
        };
    },
    desugarDef: function ( args ) {
        return args.self._map( desugarDefWriterMaker,
            function ( arg ) {

            return arg.desugarDef();
        } );
    },
    desugarLet: function ( args ) {
        return args.self._map( idWriterMaker, function ( arg ) {
            return arg.desugarLet();
        } );
    }
} );
addSyntax( "tail-to-temp", "tempExpr",
    "frameName optVarList va tailExpr", {

    _map: function ( args, writerMaker, recur ) {
        var writer = writerMaker.make();
        return writer.go( list( "tail-to-temp",
            args.frameName.expr,
            args.optVarList.expr,
            args.va.expr,
            writer.consume( recur( args.tailExpr ) ) ) );
    },

    getFreeVars: function ( args, freeVarsAfter ) {
        var innerFreeVarsAfter =
            freeVarsAfter.minusKey( args.va.expr );
        var declaredInnerFreeVarsAfter = args.optVarList.set();
        return args.tailExpr.getFreeVars( strSet() ).
            plus( declaredInnerFreeVarsAfter || innerFreeVarsAfter );
    },

    desugarVarLists: function ( args, freeVarsAfter ) {
        var innerFreeVarsAfter =
            freeVarsAfter.minusKey( args.va.expr );
        return list( "tail-to-temp",
            args.frameName.expr,
            args.optVarList.or( innerFreeVarsAfter ),
            args.va.expr,
            args.tailExpr.desugarVarLists( strSet() ) );
    },
    hasProperScope: function ( args, freeVarsAfter ) {
        var innerFreeVarsAfter =
            freeVarsAfter.minusKey( args.va.expr );
        var declaredInnerFreeVarsAfter = args.optVarList.set();
        return args.optVarList.isProvidedProperly() &&
            innerFreeVarsAfter.subset( declaredInnerFreeVarsAfter ) &&
            args.tailExpr.hasProperScope( strSet() );
    },
    desugarFn: function ( args ) {
        return args.self._map( idWriterMaker, function ( arg ) {
            return arg.desugarFn();
        } );
    },
    desugarTailToTemp: function ( args, freeVarsAfter ) {
        return {
            type: "tailToTemp",
            frameName: args.frameName,
            varList: args.optVarList,
            va: args.va,
            arg: args.tailExpr,
            frameBodyExpr: args.va.expr
        };
    },
    desugarDef: function ( args ) {
        throw new Error();
    },
    desugarLet: function ( args ) {
        throw new Error();
    }
} );
addSyntax( "fn", "tempExpr", "frameName optVarList va tailExpr", {
    getFreeVars: function ( args, freeVarsAfter ) {
        var innerFreeVarsAfter = strSet();
        var innerFreeVars = args.tailExpr.
            getFreeVars( innerFreeVarsAfter ).minus( args.va.expr );
        var declaredInnerFreeVars = args.optVarList.set();
        return (declaredInnerFreeVars || innerFreeVars).plus(
            freeVarsAfter );
    },

    desugarVarLists: function ( args, freeVarsAfter ) {
        var innerFreeVarsAfter = strSet();
        var innerFreeVars = args.tailExpr.
            getFreeVars( innerFreeVarsAfter ).minus( args.va.expr );
        return list( "fn",
            args.frameName.expr,
            args.optVarList.or( innerFreeVars ),
            args.va.expr,
            args.tailExpr.desugarVarLists( innerFreeVarsAfter ) );
    },
    hasProperScope: function ( args, freeVarsAfter ) {
        var innerFreeVarsAfter = strSet();
        var innerFreeVars = args.tailExpr.
            getFreeVars( innerFreeVarsAfter ).minus( args.va.expr );
        var declaredInnerFreeVars = args.optVarList.set();
        return args.optVarList.isProvidedProperly() &&
            innerFreeVars.subset( declaredInnerFreeVars ) &&
            args.tailExpr.hasProperScope( innerFreeVarsAfter );
    },
    desugarFn: function ( args ) {
        return list( "temp-def",
            list( "def", args.frameName.expr,
                args.optVarList.expr,
                args.va.expr,
                args.tailExpr.desugarFn() ),
            list( "fn-frame", args.frameName.expr,
                args.optVarList.capture() ) );
    },
    desugarTailToTemp: function ( args, freeVarsAfter ) {
        throw new Error();
    },
    desugarDef: function ( args ) {
        throw new Error();
    },
    desugarLet: function ( args ) {
        throw new Error();
    }
} );
<|endoftext|>


<commit_before>/*global define*/
/*jslint white:true,browser:true*/
define([
    'kb/common/html'
], function (html) {
    'use strict';
    function factory(config) {
        var root = config.root, places = {},
            div = html.tag('div');

        // IMPLEMENTATION

        function addPlace(name) {
            if (places[name]) {
                throw new Error('Place already defined: ' + name);
            }
            var id = html.genId();
            places[name] = {
                id: id
            };
            return id;
        }
        function addPlaceHolder(name) {
            return div({id: addPlace(name)});
        }
        function getPlace(name) {
            var place =  places[name];
            if (place === undefined) {
                throw new Error('Place not defined: ' + name);
            }
            return place;
        }
        function getPlaceNode(name) {
            var place = getPlace(name);
            if (!place.node) {
                place.node = document.getElementById(place.id);
            }
            if (!place.node) {
                throw new Error('Place does not exist in the DOM: ' + place + ' : ' + place.id);
            }
            return place.node;
        }
        function setPlaceContent(name, content) {
            var place = getPlaceNode(name);
            place.innerHTML = content;
        }

        return {
            add: addPlace,
            get: getPlace,
            getNode: getPlaceNode,
            setContent: setPlaceContent,
            addPlaceHolder: addPlaceHolder
        };
    }

    return {
        make: function (config) {
            return factory(config);
        }
    };
});<commit_msg>add appendPlaceContent method to append content to a place<commit_after>/*global define*/
/*jslint white:true,browser:true*/
define([
    'kb/common/html'
], function (html) {
    'use strict';
    function factory(config) {
        var root = config.root, places = {},
            div = html.tag('div');

        // IMPLEMENTATION

        function addPlace(name) {
            if (places[name]) {
                throw new Error('Place already defined: ' + name);
            }
            var id = html.genId();
            places[name] = {
                id: id
            };
            return id;
        }
        function addPlaceHolder(name) {
            return div({id: addPlace(name)});
        }
        function getPlace(name) {
            var place =  places[name];
            if (place === undefined) {
                throw new Error('Place not defined: ' + name);
            }
            return place;
        }
        function getPlaceNode(name) {
            var place = getPlace(name);
            if (!place.node) {
                place.node = document.getElementById(place.id);
            }
            if (!place.node) {
                throw new Error('Place does not exist in the DOM: ' + place + ' : ' + place.id);
            }
            return place.node;
        }
        function setPlaceContent(name, content) {
            var place = getPlaceNode(name);
            place.innerHTML = content;
        }
        function appendPlaceContent(name, content) {
            var place = getPlaceNode(name),
                temp = document.createElement('div');

            temp.innerHTML = content;
            place.appendChild(temp.firstChild)
        }

        return {
            add: addPlace,
            get: getPlace,
            getNode: getPlaceNode,
            setContent: setPlaceContent,
            addPlaceHolder: addPlaceHolder,
            appendContent: appendPlaceContent
        };
    }

    return {
        make: function (config) {
            return factory(config);
        }
    };
});<|endoftext|>


<commit_before>/**
 * @file TableRow component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */
import React, {Component} from 'react';
import PropTypes from 'prop-types';

export default class TableRow extends Component {

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.contentRenderer = ::this.contentRenderer;
        this.rowTouchTapHandler = ::this.rowTouchTapHandler;
        this.cellTouchTapHandler = ::this.cellTouchTapHandler;

    }

    stringContentRenderer(data, template) {

        if (!data) {
            return template;
        }

        if (/\$\{.+\}/.test(template)) { // 配置的 renderer 中包含 ${...}，用数据替换
            let result = template;
            for (let key in data) {
                result = result.replace(new RegExp('\\$\\{' + key + '\\}', 'g'), data[key]);
            }
            return result;
        } else { // 直接显示字段
            return data[template];
        }

    }

    contentRenderer(renderer, colIndex) {

        const {rowIndex, data} = this.props;

        switch (typeof renderer) {
            case 'string':
                return this.stringContentRenderer(data, renderer);
            case 'function':
                return renderer(data, rowIndex, colIndex);
            default:
                return renderer;
        }

    }

    rowTouchTapHandler(e) {
        const {data, rowIndex, disabled, onRowTouchTap} = this.props;
        !disabled && onRowTouchTap && onRowTouchTap(data, rowIndex, e);
    }

    cellTouchTapHandler(e, colIndex) {
        const {data, rowIndex, disabled, onCellTouchTap} = this.props;
        !disabled && onCellTouchTap && onCellTouchTap(data, rowIndex, colIndex, e);
    }

    render() {

        const {data, columns, isChecked, disabled} = this.props,

            trClassName = (isChecked ? ' activated' : '') + (data.rowClassName ? ' ' + data.rowClassName : '');

        return (

                {
                    columns.map((col, colIndex) =>
                         {
                                this.cellTouchTapHandler(e, colIndex);
                            }}>
                            {this.contentRenderer(col.renderer, colIndex)}

                    )
                }

        );

    }
};

TableRow.propTypes = {

    rowIndex: PropTypes.number,
    columns: PropTypes.array,
    data: PropTypes.object,
    isChecked: PropTypes.bool,
    disabled: PropTypes.bool,

    onRowTouchTap: PropTypes.func,
    onCellTouchTap: PropTypes.func

};

TableRow.defaultProps = {
    rowIndex: 0,
    columns: [],
    data: {},
    isChecked: false,
    disabled: false
};<commit_msg>update TableRow<commit_after>/**
 * @file TableRow component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */
import React, {Component} from 'react';
import PropTypes from 'prop-types';

export default class TableRow extends Component {

    static propTypes = {

        rowIndex: PropTypes.number,
        columns: PropTypes.array,
        data: PropTypes.object,
        isChecked: PropTypes.bool,
        disabled: PropTypes.bool,

        onRowTouchTap: PropTypes.func,
        onCellTouchTap: PropTypes.func

    };
    static defaultProps = {
        rowIndex: 0,
        columns: [],
        data: {},
        isChecked: false,
        disabled: false
    };

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.contentRenderer = ::this.contentRenderer;
        this.rowTouchTapHandler = ::this.rowTouchTapHandler;
        this.cellTouchTapHandler = ::this.cellTouchTapHandler;

    }

    stringContentRenderer(data, template) {

        if (!data) {
            return template;
        }

        if (/\$\{.+\}/.test(template)) { // 配置的 renderer 中包含 ${...}，用数据替换
            let result = template;
            for (let key in data) {
                result = result.replace(new RegExp('\\$\\{' + key + '\\}', 'g'), data[key]);
            }
            return result;
        } else { // 直接显示字段
            return data[template];
        }

    }

    contentRenderer(renderer, colIndex) {

        const {rowIndex, data} = this.props;

        switch (typeof renderer) {
            case 'string':
                return this.stringContentRenderer(data, renderer);
            case 'function':
                return renderer(data, rowIndex, colIndex);
            default:
                return renderer;
        }

    }

    rowTouchTapHandler(e) {
        const {data, rowIndex, disabled, onRowTouchTap} = this.props;
        !disabled && onRowTouchTap && onRowTouchTap(data, rowIndex, e);
    }

    cellTouchTapHandler(e, colIndex) {
        const {data, rowIndex, disabled, onCellTouchTap} = this.props;
        !disabled && onCellTouchTap && onCellTouchTap(data, rowIndex, colIndex, e);
    }

    render() {

        const {data, columns, isChecked, disabled} = this.props,

            trClassName = (isChecked ? ' activated' : '') + (data.rowClassName ? ' ' + data.rowClassName : '');

        return (

                {
                    columns.map((col, colIndex) =>
                         {
                                this.cellTouchTapHandler(e, colIndex);
                            }}>
                            {this.contentRenderer(col.renderer, colIndex)}

                    )
                }

        );

    }
};<|endoftext|>


<commit_before>import React from 'react';

function HomeView (props) {
    return (

Hello {props.user.user || 'empty'}

    );
}

export default HomeView;<commit_msg>Add Link Route component in the Home for example purpose.<commit_after>import React from 'react';
import { Link } from 'react-router'

function HomeView (props) {
    return (

Hello <Link to="Login">{props.user.user || 'empty'}</Link>

    );
}

export default HomeView;<|endoftext|>


<commit_before>"use strict";

class gsuiPianoroll {
	constructor() {
		const root = gsuiPianoroll.template.cloneNode( true ),
			elRows = root.querySelector( ".gsuiPianoroll-rows" ),
			elPanKeys = root.querySelector( ".gsuiPianoroll-pan-keys" ),
			elPanGrid = root.querySelector( ".gsuiPianoroll-pan-grid" ),
			elKeys = root.querySelector( ".gsuiPianoroll-keys" ),
			uiPanels = new gsuiPanels( root ),
			uiKeys = new gsuiKeys(),
			uiKeysRoot = uiKeys.rootElement,
			uiTimeline = new gsuiTimeline(),
			uiBeatlines = new gsuiBeatlines();

		this.rootElement = root;
		this.data = this._proxyCreate();
		this._ = Object.seal( {
			uiKeys,
			elKeys,
			elRows,
			uiPanels,
			elPanKeys,
			elPanGrid,
			uiTimeline,
			uiKeysRoot,
			uiBeatlines,
			idMax: 1,
			offset: 0,
			nlRows: elRows.getElementsByClassName( "gsui-row" ),
			fontSize: 16,
			pxPerBeat: 64,
			mouseDeleting: false,
			elPanGridWidth: 0,
			currKeyDuration: 1,
			elRowsScrollTop: -1,
			elRowsScrollLeft: -1,
			mouseBlcDeleting: [],
			keyBlocks: {},
			rowsByMidi: {},
		} );
		this.onchange =
		this.onchangeLoop =
		this.onchangeCurrentTime = () => {};
		uiTimeline.oninputLoop = ( isLoop, a, b ) => uiBeatlines.loop( isLoop && a, b );
		uiTimeline.onchangeLoop = ( isLoop, a, b ) => this.onchangeLoop( isLoop, a, b );
		uiTimeline.onchangeCurrentTime = t => {
			uiBeatlines.currentTime( t );
			this.onchangeCurrentTime( t );
		};
		root.onwheel = e => {
			e.ctrlKey && e.preventDefault();
		};
		elKeys.onscroll = e => {
			if ( this._.elRowsScrollTop !== elKeys.scrollTop ) {
				this._.elRowsScrollTop =
				elRows.scrollTop = elKeys.scrollTop;
			}
		};
		uiKeysRoot.onwheel = this._uiKeysWheel.bind( this );
		elRows.onwheel = this._elRowsWheel.bind( this );
		elRows.onscroll = this._elRowsScroll.bind( this );
		elRows.oncontextmenu = () => false;
		elPanGrid.onresizing = this._panelGridResizing.bind( this );
		elKeys.append( uiKeysRoot );
		root.querySelector( ".gsuiPianoroll-timeline" ).append( uiTimeline.rootElement );
		root.querySelector( ".gsuiPianoroll-beatlines" ).append( uiBeatlines.rootElement );
	}

	empty() {
		Object.keys( this.data ).forEach( k => delete this.data[ k ] );
	}
	resized() {
		this._panelGridResized();
	}
	attached() {
		const {
				elKeys,
				elRows,
				elPanGrid,
				uiPanels,
			} = this._,
			scrollbarW = elRows.offsetWidth - elRows.clientWidth;

		elKeys.style.right =
		elRows.style.right =
		elKeys.style.bottom =
		elRows.style.bottom = -scrollbarW + "px";
		uiPanels.attached();
		this._panelGridResized();
	}
	octaves( from, nb ) {
		const {
				uiKeys,
				elRows,
				pxPerBeat,
				uiKeysRoot,
				rowsByMidi,
			} = this._,
			rows = uiKeysRoot.getElementsByClassName( "gsui-row" );

		this.empty();
		Object.keys( rowsByMidi ).forEach( k => delete rowsByMidi[ k ] );
		uiKeys.octaves( from, nb );
		Object.values( rows ).forEach( el => {
			el.onmousedown = this._rowMousedown.bind( this, +el.dataset.midi );
			el.firstChild.style.fontSize = pxPerBeat + "px";
			rowsByMidi[ el.dataset.midi ] = el;
		} );
		Element.prototype.append.apply( elRows, rows );
	}
	setFontSize( px ) {
		const {
				elRows,
				fontSize,
				uiKeysRoot,
			} = this._;

		if ( px !== fontSize ) {
			this._.fontSize = px = Math.round( Math.min( Math.max( 8, px ), 64 ) );
			uiKeysRoot.style.fontSize =
			elRows.style.fontSize = px + "px";
		}
		return px;
	}

	// Panel functions
	// ........................................................................
	_panelGridResizing( pan ) {
		const {
				elRows,
				offset,
				pxPerBeat,
				elPanGridWidth,
			} = this._,
			width = pan.clientWidth;

		if ( offset > 0 ) {
			this._.offset -= ( width - elPanGridWidth ) / pxPerBeat;
			elRows.scrollLeft -= width - elPanGridWidth;
		}
		this._panelGridResized();
	}
	_panelGridResized() {
		const {
				offset,
				pxPerBeat,
				elPanGrid,
				uiTimeline,
				uiBeatlines,
			} = this._;

		this._.elPanGridWidth = elPanGrid.clientWidth;
		uiTimeline.resized();
		uiBeatlines.resized();
		uiTimeline.offset( offset, pxPerBeat );
		uiBeatlines.offset( offset, pxPerBeat );
	}

	// Shortcuts
	// ........................................................................
	_getWhenFromPageX( pageX ) {
		return ( pageX - this._.nlRows[ 0 ].getBoundingClientRect().left )
			/ this._.pxPerBeat;
	}

	// Mouse events
	// ........................................................................
	_elRowsScroll( e ) {
		const {
				elKeys,
				elRows,
				pxPerBeat,
				uiTimeline,
				uiBeatlines,
				elRowsScrollTop,
				elRowsScrollLeft,
			} = this._;

		if ( elRows.scrollTop !== elRowsScrollTop ) {
			this._.elRowsScrollTop =
			elKeys.scrollTop = elRows.scrollTop;
		}
		if ( elRows.scrollLeft !== elRowsScrollLeft ) {
			const off = elRows.scrollLeft / pxPerBeat;

			this._.offset = off;
			this._.elRowsScrollLeft = elRows.scrollLeft;
			uiTimeline.offset( off, pxPerBeat );
			uiBeatlines.offset( off, pxPerBeat );
		}
	}
	_uiKeysWheel( e ) {
		if ( e.ctrlKey ) {
			const {
					elKeys,
					elRows,
					fontSize,
					uiKeysRoot,
				} = this._,
				layerY = e.pageY - uiKeysRoot.getBoundingClientRect().top,
				fs = this.setFontSize( fontSize * ( e.deltaY > 0 ? .9 : 1.1 ) );

			this._.elRowsScrollTop =
			elKeys.scrollTop =
			elRows.scrollTop += layerY / fontSize * ( fs - fontSize );
		}
	}
	_elRowsWheel( e ) {
		if ( e.ctrlKey ) {
			const {
					elRows,
					nlRows,
					pxPerBeat,
					uiTimeline,
					uiBeatlines,
				} = this._,
				layerX = e.pageX - elRows.getBoundingClientRect().left + elRows.scrollLeft,
				ppb = Math.round( Math.min( Math.max( 8, pxPerBeat * ( e.deltaY > 0 ? .9 : 1.1 ) ), 512 ) );

			this._.pxPerBeat = ppb;
			this._.elRowsScrollLeft =
			elRows.scrollLeft += layerX / pxPerBeat * ( ppb - pxPerBeat );
			this._.offset = elRows.scrollLeft / ppb;
			uiTimeline.offset( this._.offset, ppb );
			uiBeatlines.offset( this._.offset, ppb );
			Array.from( nlRows ).forEach( el => el.firstChild.style.fontSize = ppb + "px" );
		}
	}
	_rowMousedown( key, e ) {
		const _ = this._,
			tar = e.target;

		if ( e.button === 2 ) {
			_.mouseDeleting = true;
			if ( tar.classList.contains( "gsui-keyBlock" ) ) {
				tar.classList.add( "gsui-keyBlock-hide" );
				_.mouseBlcDeleting.push( tar );
			}
		} else if ( e.button === 0 ) {
			const id = _.idMax + 1,
				obj = {
					key,
					when: _.uiTimeline.beatFloor( this._getWhenFromPageX( e.pageX ) ),
					duration: _.currKeyDuration
				};

			this.data[ id ] = obj;
			this.onchange( { [ id ]: obj } );
		}
		gsuiPianoroll._focused = this;
	}
	_mousemove( e ) {
		const _ = this._,
			tar = e.target;

		if ( _.mouseDeleting
			&& tar.classList.contains( "gsui-keyBlock" )
			&& !tar.classList.contains( "gsui-keyBlock-hide" )
		) {
			tar.classList.add( "gsui-keyBlock-hide" );
			_.mouseBlcDeleting.push( tar );
		}
	}
	_mouseup( e ) {
		const _ = this._;

		if ( _.mouseDeleting ) {
			_.mouseDeleting = false;
			if ( _.mouseBlcDeleting.length > 0 ) {
				const obj = _.mouseBlcDeleting.reduce( ( obj, blc ) => {
						blc.remove();
						obj[ blc.dataset.id ] = null;
						return obj;
					}, {} );

				_.mouseBlcDeleting.length = 0;
				this.onchange( obj );
			}
		}
		delete gsuiPianoroll._focused;
	}

	// Key's functions
	// ........................................................................
	_deleteKey( id ) {
		const { keyBlocks } = this._;

		keyBlocks[ id ].remove();
		delete keyBlocks[ id ];
	}
	_setKey( id, obj ) {
		const {
				keyBlocks,
				rowsByMidi,
			} = this._,
			el = document.createElement( "div" );

		el.dataset.id = id;
		el.className = "gsui-keyBlock";
		el.classList.toggle( "gsui-keyBlock-selected", obj.selected );
		el.style.left = obj.when + "em";
		el.style.width = obj.duration + "em";
		keyBlocks[ id ] = el;
		rowsByMidi[ obj.key ].firstChild.append( el );
	}
	_setKeyProp( id, prop, val ) {
		const el = this._.keyBlocks[ id ];

		switch ( prop ) {
			case "when": el.style.left = val + "em"; break;
			case "duration": el.style.width = val + "em"; break;
			case "selected": el.classList.toggle( "gsui-keyBlock-selected", !!val ); break;
		}
	}

	// Data proxy
	// ........................................................................
	_proxyCreate() {
		return new Proxy( {}, {
			set: this._proxySetKey.bind( this ),
			deleteProperty: this._proxyDeleteKey.bind( this )
		} );
	}
	_proxyDeleteKey( tar, id ) {
		this._deleteKey( id );
		delete tar[ id ];
		return true;
	}
	_proxySetKey( tar, id, obj ) {
		if ( id in tar || !obj ) {
			this._proxyDeleteKey( tar, id );
		}
		if ( obj ) {
			this._.idMax = Math.max( this._.idMax, id );
			this._setKey(
				id,
				tar[ id ] = new Proxy( Object.seal( Object.assign( {
					key: 60,
					when: 0,
					duration: 1,
					selected: false
				}, obj ) ), {
					set: this._proxySetKeyProp.bind( this, id )
				} )
			);
		}
		return true;
	}
	_proxySetKeyProp( id, tar, prop, val ) {
		tar[ prop ] = val;
		this._setKeyProp( id, prop, val );
		return true;
	}
};

gsuiPianoroll.template = document.querySelector( "#gsuiPianoroll-template" );
gsuiPianoroll.template.remove();
gsuiPianoroll.template.removeAttribute( "id" );

document.addEventListener( "mousemove", e => {
	gsuiPianoroll._focused && gsuiPianoroll._focused._mousemove( e );
} );
document.addEventListener( "mouseup", e => {
	gsuiPianoroll._focused && gsuiPianoroll._focused._mouseup( e );
} );
<commit_msg>gsuiPianoroll: selection keys with shiftkey + click<commit_after>"use strict";

class gsuiPianoroll {
	constructor() {
		const root = gsuiPianoroll.template.cloneNode( true ),
			elRows = root.querySelector( ".gsuiPianoroll-rows" ),
			elPanKeys = root.querySelector( ".gsuiPianoroll-pan-keys" ),
			elPanGrid = root.querySelector( ".gsuiPianoroll-pan-grid" ),
			elKeys = root.querySelector( ".gsuiPianoroll-keys" ),
			uiPanels = new gsuiPanels( root ),
			uiKeys = new gsuiKeys(),
			uiKeysRoot = uiKeys.rootElement,
			uiTimeline = new gsuiTimeline(),
			uiBeatlines = new gsuiBeatlines();

		this.rootElement = root;
		this.data = this._proxyCreate();
		this._ = Object.seal( {
			uiKeys,
			elKeys,
			elRows,
			uiPanels,
			elPanKeys,
			elPanGrid,
			uiTimeline,
			uiKeysRoot,
			uiBeatlines,
			elSelection: root.querySelector( ".gsuiPianoroll-selection" ),
			idMax: 1,
			offset: 0,
			nlRows: elRows.getElementsByClassName( "gsui-row" ),
			fontSize: 16,
			pxPerBeat: 64,
			elPanGridWidth: 0,
			currKeyDuration: 1,
			elRowsScrollTop: -1,
			elRowsScrollLeft: -1,
			blcSelected: {},
			mouseDeleting: false,
			mouseBlcDeleting: [],
			keyBlocks: {},
			rowsByMidi: {},
		} );
		this.onchange =
		this.onchangeLoop =
		this.onchangeCurrentTime = () => {};
		uiTimeline.oninputLoop = ( isLoop, a, b ) => uiBeatlines.loop( isLoop && a, b );
		uiTimeline.onchangeLoop = ( isLoop, a, b ) => this.onchangeLoop( isLoop, a, b );
		uiTimeline.onchangeCurrentTime = t => {
			uiBeatlines.currentTime( t );
			this.onchangeCurrentTime( t );
		};
		root.onwheel = e => {
			e.ctrlKey && e.preventDefault();
		};
		elKeys.onscroll = e => {
			if ( this._.elRowsScrollTop !== elKeys.scrollTop ) {
				this._.elRowsScrollTop =
				elRows.scrollTop = elKeys.scrollTop;
			}
		};
		uiKeysRoot.onwheel = this._uiKeysWheel.bind( this );
		elRows.onwheel = this._elRowsWheel.bind( this );
		elRows.onscroll = this._elRowsScroll.bind( this );
		elRows.oncontextmenu = () => false;
		elPanGrid.onresizing = this._panelGridResizing.bind( this );
		elKeys.append( uiKeysRoot );
		root.querySelector( ".gsuiPianoroll-timeline" ).append( uiTimeline.rootElement );
		root.querySelector( ".gsuiPianoroll-beatlines" ).append( uiBeatlines.rootElement );
	}

	empty() {
		Object.keys( this.data ).forEach( k => delete this.data[ k ] );
	}
	resized() {
		this._panelGridResized();
	}
	attached() {
		const {
				elKeys,
				elRows,
				elPanGrid,
				uiPanels,
			} = this._,
			scrollbarW = elRows.offsetWidth - elRows.clientWidth;

		elKeys.style.right =
		elRows.style.right =
		elKeys.style.bottom =
		elRows.style.bottom = -scrollbarW + "px";
		uiPanels.attached();
		this._panelGridResized();
	}
	octaves( from, nb ) {
		const {
				uiKeys,
				elRows,
				pxPerBeat,
				uiKeysRoot,
				rowsByMidi,
			} = this._,
			rows = uiKeysRoot.getElementsByClassName( "gsui-row" );

		this.empty();
		Object.keys( rowsByMidi ).forEach( k => delete rowsByMidi[ k ] );
		uiKeys.octaves( from, nb );
		Object.values( rows ).forEach( el => {
			el.onmousedown = this._rowMousedown.bind( this, +el.dataset.midi );
			el.firstChild.style.fontSize = pxPerBeat + "px";
			rowsByMidi[ el.dataset.midi ] = el;
		} );
		Element.prototype.append.apply( elRows, rows );
	}
	setFontSize( px ) {
		const {
				elRows,
				fontSize,
				uiKeysRoot,
			} = this._;

		if ( px !== fontSize ) {
			this._.fontSize = px = Math.round( Math.min( Math.max( 8, px ), 64 ) );
			uiKeysRoot.style.fontSize =
			elRows.style.fontSize = px + "px";
		}
		return px;
	}

	// Panel functions
	// ........................................................................
	_panelGridResizing( pan ) {
		const {
				elRows,
				offset,
				pxPerBeat,
				elPanGridWidth,
			} = this._,
			width = pan.clientWidth;

		if ( offset > 0 ) {
			this._.offset -= ( width - elPanGridWidth ) / pxPerBeat;
			elRows.scrollLeft -= width - elPanGridWidth;
		}
		this._panelGridResized();
	}
	_panelGridResized() {
		const {
				offset,
				pxPerBeat,
				elPanGrid,
				uiTimeline,
				uiBeatlines,
			} = this._;

		this._.elPanGridWidth = elPanGrid.clientWidth;
		uiTimeline.resized();
		uiBeatlines.resized();
		uiTimeline.offset( offset, pxPerBeat );
		uiBeatlines.offset( offset, pxPerBeat );
	}

	// Shortcuts
	// ........................................................................
	_getWhenFromPageX( pageX ) {
		return ( pageX - this._.nlRows[ 0 ].getBoundingClientRect().left )
			/ this._.pxPerBeat;
	}

	// Mouse events
	// ........................................................................
	_elRowsScroll( e ) {
		const {
				elKeys,
				elRows,
				pxPerBeat,
				uiTimeline,
				uiBeatlines,
				elRowsScrollTop,
				elRowsScrollLeft,
			} = this._;

		if ( elRows.scrollTop !== elRowsScrollTop ) {
			this._.elRowsScrollTop =
			elKeys.scrollTop = elRows.scrollTop;
		}
		if ( elRows.scrollLeft !== elRowsScrollLeft ) {
			const off = elRows.scrollLeft / pxPerBeat;

			this._.offset = off;
			this._.elRowsScrollLeft = elRows.scrollLeft;
			uiTimeline.offset( off, pxPerBeat );
			uiBeatlines.offset( off, pxPerBeat );
		}
	}
	_uiKeysWheel( e ) {
		if ( e.ctrlKey ) {
			const {
					elKeys,
					elRows,
					fontSize,
					uiKeysRoot,
				} = this._,
				layerY = e.pageY - uiKeysRoot.getBoundingClientRect().top,
				fs = this.setFontSize( fontSize * ( e.deltaY > 0 ? .9 : 1.1 ) );

			this._.elRowsScrollTop =
			elKeys.scrollTop =
			elRows.scrollTop += layerY / fontSize * ( fs - fontSize );
		}
	}
	_elRowsWheel( e ) {
		if ( e.ctrlKey ) {
			const {
					elRows,
					nlRows,
					pxPerBeat,
					uiTimeline,
					uiBeatlines,
				} = this._,
				layerX = e.pageX - elRows.getBoundingClientRect().left + elRows.scrollLeft,
				ppb = Math.round( Math.min( Math.max( 8, pxPerBeat * ( e.deltaY > 0 ? .9 : 1.1 ) ), 512 ) );

			this._.pxPerBeat = ppb;
			this._.elRowsScrollLeft =
			elRows.scrollLeft += layerX / pxPerBeat * ( ppb - pxPerBeat );
			this._.offset = elRows.scrollLeft / ppb;
			uiTimeline.offset( this._.offset, ppb );
			uiBeatlines.offset( this._.offset, ppb );
			Array.from( nlRows ).forEach( el => el.firstChild.style.fontSize = ppb + "px" );
		}
	}
	_rowMousedown( key, e ) {
		const _ = this._,
			tar = e.target;

		if ( e.button === 2 ) {
			_.mouseDeleting = true;
		} else if ( e.button === 0 && !e.shiftKey ) {
			const id = _.idMax + 1,
				obj = {
					key,
					when: _.uiTimeline.beatFloor( this._getWhenFromPageX( e.pageX ) ),
					duration: _.currKeyDuration
				};

			this.data[ id ] = obj;
			this.onchange( { [ id ]: obj } );
		}
		gsuiPianoroll._focused = this;
	}
	_mousemove( e ) {
		const _ = this._,
			tar = e.target;

		if ( _.mouseDeleting
			&& tar.classList.contains( "gsui-keyBlock" )
			&& !tar.classList.contains( "gsui-keyBlock-hide" )
		) {
			tar.classList.add( "gsui-keyBlock-hide" );
			_.mouseBlcDeleting.push( tar );
		}
	}
	_mouseup( e ) {
		const _ = this._;

		if ( _.mouseDeleting ) {
			_.mouseDeleting = false;
			if ( _.mouseBlcDeleting.length > 0 ) {
				const obj = _.mouseBlcDeleting.reduce( ( obj, blc ) => {
						blc.remove();
						obj[ blc.dataset.id ] = null;
						return obj;
					}, {} );

				_.mouseBlcDeleting.length = 0;
				this.onchange( obj );
			}
		}
		delete gsuiPianoroll._focused;
	}

	// Key's functions
	// ........................................................................
	_deleteKey( id ) {
		const { keyBlocks } = this._;

		keyBlocks[ id ].remove();
		delete keyBlocks[ id ];
	}
	_setKey( id, obj ) {
		const {
				keyBlocks,
				rowsByMidi,
			} = this._,
			el = document.createElement( "div" );

		el.dataset.id = id;
		el.className = "gsui-keyBlock";
		el.classList.toggle( "gsui-keyBlock-selected", obj.selected );
		el.style.left = obj.when + "em";
		el.style.width = obj.duration + "em";
		el.onmousedown = this._keyMousedown.bind( this, id );
		keyBlocks[ id ] = el;
		rowsByMidi[ obj.key ].firstChild.append( el );
	}
	_setKeyProp( id, prop, val ) {
		const el = this._.keyBlocks[ id ];

		switch ( prop ) {
			case "when": el.style.left = val + "em"; break;
			case "duration": el.style.width = val + "em"; break;
			case "selected": el.classList.toggle( "gsui-keyBlock-selected", !!val ); break;
		}
	}
	_keyMousedown( id, e ) {
		const _ = this._,
			blc = e.target;

		e.stopPropagation();
		if ( e.button === 2 ) {
			blc.classList.add( "gsui-keyBlock-hide" );
			_.mouseBlcDeleting.push( blc );
			_.mouseDeleting = true;
		} else if ( e.button === 0 ) {
			if ( e.shiftKey ) {
				const selected = blc.classList.toggle( "gsui-keyBlock-selected" );

				if ( selected ) {
					_.blcSelected[ id ] = blc;
				} else {
					delete _.blcSelected[ id ];
				}
				this.onchange( { [ id ]: { selected } } );
			}
		}
		gsuiPianoroll._focused = this;
	}

	// Data proxy
	// ........................................................................
	_proxyCreate() {
		return new Proxy( {}, {
			set: this._proxySetKey.bind( this ),
			deleteProperty: this._proxyDeleteKey.bind( this )
		} );
	}
	_proxyDeleteKey( tar, id ) {
		this._deleteKey( id );
		delete tar[ id ];
		return true;
	}
	_proxySetKey( tar, id, obj ) {
		if ( id in tar || !obj ) {
			this._proxyDeleteKey( tar, id );
		}
		if ( obj ) {
			this._.idMax = Math.max( this._.idMax, id );
			this._setKey(
				id,
				tar[ id ] = new Proxy( Object.seal( Object.assign( {
					key: 60,
					when: 0,
					duration: 1,
					selected: false
				}, obj ) ), {
					set: this._proxySetKeyProp.bind( this, id )
				} )
			);
		}
		return true;
	}
	_proxySetKeyProp( id, tar, prop, val ) {
		tar[ prop ] = val;
		this._setKeyProp( id, prop, val );
		return true;
	}
};

gsuiPianoroll.template = document.querySelector( "#gsuiPianoroll-template" );
gsuiPianoroll.template.remove();
gsuiPianoroll.template.removeAttribute( "id" );

document.addEventListener( "mousemove", e => {
	gsuiPianoroll._focused && gsuiPianoroll._focused._mousemove( e );
} );
document.addEventListener( "mouseup", e => {
	gsuiPianoroll._focused && gsuiPianoroll._focused._mouseup( e );
} );
<|endoftext|>


<commit_before>import { BodyComponent } from 'mjml-core'
import crypto from 'crypto'

import conditionalTag, {
  msoConditionalTag,
} from 'mjml-core/lib/helpers/conditionalTag'

export default class MjNavbar extends BodyComponent {
  static allowedAttributes = {
    align: 'enum(left,center,right)',
    'base-url': 'string',
    hamburger: 'string',
    'ico-align': 'enum(left,center,right)',
    'ico-open': 'string',
    'ico-close': 'string',
    'ico-color': 'color',
    'ico-font-size': 'unit(px,%)',
    'ico-font-family': 'string',
    'ico-text-transform': 'string',
    'ico-padding': 'unit(px,%){1,4}',
    'ico-padding-left': 'unit(px,%)',
    'ico-padding-top': 'unit(px,%)',
    'ico-padding-right': 'unit(px,%)',
    'ico-padding-bottom': 'unit(px,%)',
    'ico-text-decoration': 'string',
    'ico-line-height': 'unit(px,%)',
  }

  static defaultAttributes = {
    align: 'center',
    'base-url': null,
    hamburger: null,
    'ico-align': 'center',
    'ico-open': '9776',
    'ico-close': '8855',
    'ico-color': '#000000',
    'ico-font-size': '30px',
    'ico-font-family': 'Ubuntu, Helvetica, Arial, sans-serif',
    'ico-text-transform': 'uppercase',
    'ico-padding': '10px',
    'ico-text-decoration': 'none',
    'ico-line-height': '30px',
  }

  headStyle = breakpoint =>
    `
      noinput.mj-menu-checkbox { display:block!important; max-height:none!important; visibility:visible!important; }

      @media only screen and (max-width:${breakpoint}) {
        .mj-menu-checkbox[type="checkbox"] ~ .mj-inline-links { display:none!important; }
        .mj-menu-checkbox[type="checkbox"]:checked ~ .mj-inline-links,
        .mj-menu-checkbox[type="checkbox"] ~ .mj-menu-trigger { display:block!important; max-width:none!important; max-height:none!important; font-size:inherit!important; }
        .mj-menu-checkbox[type="checkbox"] ~ .mj-inline-links > a { display:block!important; }
        .mj-menu-checkbox[type="checkbox"]:checked ~ .mj-menu-trigger .mj-menu-icon-close { display:block!important; }
        .mj-menu-checkbox[type="checkbox"]:checked ~ .mj-menu-trigger .mj-menu-icon-open { display:none!important; }
      }
    `

  getStyles() {
    return {
      div: {
        align: this.getAttribute('align'),
        width: '100%',
      },
      label: {
        display: 'block',
        cursor: 'pointer',
        'mso-hide': 'all',
        '-moz-user-select': 'none',
        'user-select': 'none',
        align: this.getAttribute('ico-align'),
        color: this.getAttribute('ico-color'),
        'font-size': this.getAttribute('ico-font-size'),
        'font-family': this.getAttribute('ico-font-family'),
        'text-transform': this.getAttribute('ico-text-transform'),
        'text-decoration': this.getAttribute('ico-text-decoration'),
        'line-height': this.getAttribute('ico-line-height'),
        'padding-top': this.getAttribute('ico-padding-top'),
        'padding-right': this.getAttribute('ico-padding-right'),
        'padding-bottom': this.getAttribute('ico-padding-bottom'),
        'padding-left': this.getAttribute('ico-padding-left'),
        padding: this.getAttribute('ico-padding'),
      },
      trigger: {
        display: 'none',
        'max-height': '0px',
        'max-width': '0px',
        'font-size': '0px',
        overflow: 'hidden',
      },
      icoOpen: {
        'mso-hide': 'all',
      },
      icoClose: {
        display: 'none',
        'mso-hide': 'all',
      },
    }
  }

  renderHamburger() {
    const key = crypto.randomBytes(8).toString('hex')

    return `
      ${msoConditionalTag(
        `
        <input type="checkbox" id="${key}" class="mj-menu-checkbox" style="display:none !important; max-height:0; visibility:hidden;" />
      `,
        true,
      )}

            ${String.fromCharCode(this.getAttribute('ico-open'))}

            ${String.fromCharCode(this.getAttribute('ico-close'))}

    `
  }

  render() {
    return `
        ${this.getAttribute('hamburger') === 'hamburger'
          ? this.renderHamburger()
          : ''}

        ${conditionalTag(`

        `)}
          ${this.renderChildren(this.props.children, {
            attributes: {
              navbarBaseUrl: this.getAttribute('base-url'),
            },
          })}
          ${conditionalTag(`

          `)}

    `
  }
}
<commit_msg>fix #1187 html char codes for navbar icon<commit_after>import { BodyComponent } from 'mjml-core'
import crypto from 'crypto'

import conditionalTag, {
  msoConditionalTag,
} from 'mjml-core/lib/helpers/conditionalTag'

export default class MjNavbar extends BodyComponent {
  static allowedAttributes = {
    align: 'enum(left,center,right)',
    'base-url': 'string',
    hamburger: 'string',
    'ico-align': 'enum(left,center,right)',
    'ico-open': 'string',
    'ico-close': 'string',
    'ico-color': 'color',
    'ico-font-size': 'unit(px,%)',
    'ico-font-family': 'string',
    'ico-text-transform': 'string',
    'ico-padding': 'unit(px,%){1,4}',
    'ico-padding-left': 'unit(px,%)',
    'ico-padding-top': 'unit(px,%)',
    'ico-padding-right': 'unit(px,%)',
    'ico-padding-bottom': 'unit(px,%)',
    'ico-text-decoration': 'string',
    'ico-line-height': 'unit(px,%)',
  }

  static defaultAttributes = {
    align: 'center',
    'base-url': null,
    hamburger: null,
    'ico-align': 'center',
    'ico-open': '&#9776',
    'ico-close': '&#8855',
    'ico-color': '#000000',
    'ico-font-size': '30px',
    'ico-font-family': 'Ubuntu, Helvetica, Arial, sans-serif',
    'ico-text-transform': 'uppercase',
    'ico-padding': '10px',
    'ico-text-decoration': 'none',
    'ico-line-height': '30px',
  }

  headStyle = breakpoint =>
    `
      noinput.mj-menu-checkbox { display:block!important; max-height:none!important; visibility:visible!important; }

      @media only screen and (max-width:${breakpoint}) {
        .mj-menu-checkbox[type="checkbox"] ~ .mj-inline-links { display:none!important; }
        .mj-menu-checkbox[type="checkbox"]:checked ~ .mj-inline-links,
        .mj-menu-checkbox[type="checkbox"] ~ .mj-menu-trigger { display:block!important; max-width:none!important; max-height:none!important; font-size:inherit!important; }
        .mj-menu-checkbox[type="checkbox"] ~ .mj-inline-links > a { display:block!important; }
        .mj-menu-checkbox[type="checkbox"]:checked ~ .mj-menu-trigger .mj-menu-icon-close { display:block!important; }
        .mj-menu-checkbox[type="checkbox"]:checked ~ .mj-menu-trigger .mj-menu-icon-open { display:none!important; }
      }
    `

  getStyles() {
    return {
      div: {
        align: this.getAttribute('align'),
        width: '100%',
      },
      label: {
        display: 'block',
        cursor: 'pointer',
        'mso-hide': 'all',
        '-moz-user-select': 'none',
        'user-select': 'none',
        align: this.getAttribute('ico-align'),
        color: this.getAttribute('ico-color'),
        'font-size': this.getAttribute('ico-font-size'),
        'font-family': this.getAttribute('ico-font-family'),
        'text-transform': this.getAttribute('ico-text-transform'),
        'text-decoration': this.getAttribute('ico-text-decoration'),
        'line-height': this.getAttribute('ico-line-height'),
        'padding-top': this.getAttribute('ico-padding-top'),
        'padding-right': this.getAttribute('ico-padding-right'),
        'padding-bottom': this.getAttribute('ico-padding-bottom'),
        'padding-left': this.getAttribute('ico-padding-left'),
        padding: this.getAttribute('ico-padding'),
      },
      trigger: {
        display: 'none',
        'max-height': '0px',
        'max-width': '0px',
        'font-size': '0px',
        overflow: 'hidden',
      },
      icoOpen: {
        'mso-hide': 'all',
      },
      icoClose: {
        display: 'none',
        'mso-hide': 'all',
      },
    }
  }

  renderHamburger() {
    const key = crypto.randomBytes(8).toString('hex')

    return `
      ${msoConditionalTag(
        `
        <input type="checkbox" id="${key}" class="mj-menu-checkbox" style="display:none !important; max-height:0; visibility:hidden;" />
      `,
        true,
      )}

            ${this.getAttribute('ico-open')}

            ${this.getAttribute('ico-close')}

    `
  }

  render() {
    return `
        ${this.getAttribute('hamburger') === 'hamburger'
          ? this.renderHamburger()
          : ''}

        ${conditionalTag(`

        `)}
          ${this.renderChildren(this.props.children, {
            attributes: {
              navbarBaseUrl: this.getAttribute('base-url'),
            },
          })}
          ${conditionalTag(`

          `)}

    `
  }
}
<|endoftext|>


<commit_before>/* @flow */
const React = require('react')
const { connect } = require('react-redux')
const { reduxForm } = require('redux-form')

const MemberFields = require('../../shared/components/member_fields.js')
const { validate, sign_up_required, read_only_sign_up } = require('../../shared/form_fields/member.js')

const { identity } = require('ramda')

const { next_page, previous_page } = require('../redux/modules/page.js')
const { sign_up } = require('../redux/modules/signup.js')

const buttons = (props) =>

    <button>Next</button>
    <button onClick={props.previous_page} type='button'>Back</button>

const AddMember = reduxForm(
  { form: 'sign_up'
  , validate: validate(sign_up_required)
  , fields: []
  }
)(MemberFields)

const NewMember = (props) => {
  return (

Please fill in your details

        <AddMember
          fields={page_fields[props.page]}
          Buttons={buttons}
          button_props={ { previous_page: props.previous_page } }
          onSubmit={props.page.page === 5 ? props.sign_up : props.next_page}
          required={sign_up_required}
          mode='edit'
          memberSignup
          read_only={props.page === 5 ? read_only_sign_up : []}
        />

  )
}

const page_fields = [
  [ 'title', 'first_name', 'last_name', 'initials' ],
  [ 'address1', 'address2', 'address3', 'address4', 'postcode' ],
  [ 'home_phone', 'mobile_phone' ],
  [ 'primary_email', 'password' ],
  [ 'membership_type' ],
  [ 'title', 'first_name', 'last_name', 'initials', 'address1', 'address2', 'address3', 'address4', 'postcode', 'home_phone', 'mobile_phone', 'primary_email', 'membership_type' ]
]
export default connect(identity, { sign_up, next_page, previous_page })(NewMember)
<commit_msg>Refactor sign_up component.<commit_after>/* @flow */
const React = require('react')
const { connect } = require('react-redux')
const { reduxForm } = require('redux-form')
const { identity } = require('ramda')

const MemberFields = require('../../shared/components/member_fields.js')
const { validate, sign_up_required, read_only_sign_up } = require('../../shared/form_fields/member.js')

const { next_page, previous_page } = require('../redux/modules/page.js')
const { sign_up } = require('../redux/modules/signup.js')

const SignUp = (props) => {
  return (

{props.page === 5 ? 'If your details are correct click \'Submit\' otherwise go back to change them' : 'Please fill in your details'}

        <SignUpForm
          fields={page_fields[props.page]}
          Buttons={buttons}
          button_props={ { previous_page: props.previous_page, page: props.page } }
          onSubmit={props.page === 5 ? props.sign_up : props.next_page}
          required={sign_up_required}
          mode='edit'
          memberSignup
          read_only={props.page === 5 ? read_only_sign_up : []}
        />

  )
}

const SignUpForm = reduxForm(
  { form: 'sign_up'
  , validate: validate(sign_up_required)
  , fields: []
  }
)(MemberFields)

const buttons = (props) =>

    {props.page !== 0 && back_button(props.previous_page)}
    <button>{props.page === 5 ? 'Submit' : '>'}</button>

const back_button = (previous_page) =>
  <button onClick={previous_page} type='button'>{'<'}</button>

const page_fields =
  [ [ 'title', 'first_name', 'last_name', 'initials' ]
  , [ 'address1', 'address2', 'address3', 'address4', 'postcode' ]
  , [ 'home_phone', 'mobile_phone' ]
  , [ 'primary_email', 'verify_email', 'password', 'verify_password' ]
  , [ 'membership_type' ]
  , read_only_sign_up
  ]

export default connect(identity, { sign_up, next_page, previous_page })(SignUp)
<|endoftext|>


<commit_before>// Documents list and user data

'use strict';

var camelToHyphen    = require('es5-ext/string/#/camel-to-hyphen')
  , _                = require('mano').i18n.bind('User Submitted')
  , generateSections = require('./components/generate-sections');

module.exports = function (businessProcess/*, options*/) {
	var options = Object(arguments[1])
	  , urlPrefix = options.urlPrefix || '/';

	return [section({ class: 'section-primary' },
		h2(_("Documents")),
		hr(),
		_if(businessProcess.requirementUploads.applicable._size,
			[h3(_("Documents required")),
				div(
					{ class: 'table-responsive-container' },
					table(
						{ class: 'submitted-user-data-table ' +
							'submitted-current-user-data-table user-request-table' },
						thead(
							tr(
								th({ class: 'submitted-user-data-table-status' }),
								th(_("Name")),
								th(_("Issuer")),
								th({ class: 'submitted-user-data-table-date' }, _("Issue date")),
								th({ class: 'submitted-user-data-table-link' })
							)
						),
						tbody(
							businessProcess.requirementUploads.applicable,
							function (requirementUpload) {
								td({ class: 'submitted-user-data-table-status' },
									_if(requirementUpload._isApproved, span({ class: 'fa fa-check' })),
										_if(requirementUpload._isRejected, span({ class: 'fa fa-exclamation' })));
								td(requirementUpload.document._label);
								td(requirementUpload.document._issuedBy);
								td({ class: 'submitted-user-data-table-date' },
										requirementUpload.document._issueDate);
								td({ class: 'submitted-user-data-table-link' },
									a({ href: urlPrefix + 'document/' +
										camelToHyphen.call(requirementUpload.document.uniqueKey) + "/" },
										span({ class: 'fa fa-search' }, _("Go to"))));
							}
						)
					)
				)]),
		_if(businessProcess.paymentReceiptUploads.applicable._size,
			[h3(_("Payment receipts")),
				div(
					{ class: 'table-responsive-container' },
					table(
						{ class: 'submitted-user-data-table ' +
							'submitted-current-user-data-table user-request-table' },
						thead(
							tr(
								th({ class: 'submitted-user-data-table-status' }),
								th(_("Name")),
								th({ class: 'submitted-user-data-table-date' }, _("Issue date")),
								th({ class: 'submitted-user-data-table-link' })
							)
						),
						tbody(
							businessProcess.paymentReceiptUploads.applicable,
							function (receipt) {
								td({ class: 'submitted-user-data-table-status' },
									_if(receipt._isApproved, span({ class: 'fa fa-check' })),
										_if(receipt._isRejected, span({ class: 'fa fa-exclamation' })));
								td(receipt.document.label);
								td({ class: 'submitted-user-data-table-date' }, receipt.document._issueDate);
								td({ class: 'submitted-user-data-table-link' },
									a({ href: urlPrefix + 'receipt/' + camelToHyphen.call(receipt.key) + "/" },
										span({ class: 'fa fa-search' }, _("Go to"))));
							}
						)
					)
				)]),
		_if(businessProcess.certificates.uploaded._size,
			[h3(_("Certificates")),
				div(
					{ class: 'table-responsive-container' },
					table(
						{ class: 'submitted-user-data-table ' +
							'submitted-current-user-data-table user-request-table' },
						thead(
							tr(
								th({ class: 'submitted-user-data-table-status' }),
								th(_("Name")),
								th(_("Issuer")),
								th({ class: 'submitted-user-data-table-date' }, _("Issue date")),
								th({ class: 'submitted-user-data-table-link' })
							)
						),
						tbody(
							businessProcess.certificates.uploaded,
							function (certificate) {
								td({ class: 'submitted-user-data-table-status' },
									span({ class: 'fa fa-certificate' }));
								td(certificate.label);
								td(certificate._issuedBy);
								td({ class: 'submitted-user-data-table-date' }, certificate._issueDate);
								td({ class: 'submitted-user-data-table-link' },
									a({ href: urlPrefix + 'certificate/' +
										camelToHyphen.call(certificate.key) + '/' },
										span({ class: 'fa fa-search' }, _("Go to"))));
							}
						)
					)
				)])),
		section({ class: 'section-primary entity-data-section-side' },
			h2({ class: 'container-with-nav' }, _("Form data"),
				a(
					{ class: 'hint-optional hint-optional-left',
						'data-hint': _("Print your application form"), href: urlPrefix + 'data-print/',
						target: '_blank' },
					span({ class: 'fa fa-print' }, _("Print"))
				)),

			generateSections(businessProcess.dataForms.applicable))];
};
<commit_msg>#835 generalized label display to include instert<commit_after>// Documents list and user data

'use strict';

var camelToHyphen    = require('es5-ext/string/#/camel-to-hyphen')
  , _                = require('mano').i18n.bind('User Submitted')
  , generateSections = require('./components/generate-sections')
  , _d = _;

module.exports = function (businessProcess/*, options*/) {
	var options = Object(arguments[1])
	  , urlPrefix = options.urlPrefix || '/';

	return [section({ class: 'section-primary' },
		h2(_("Documents")),
		hr(),
		_if(businessProcess.requirementUploads.applicable._size,
			[h3(_("Documents required")),
				div(
					{ class: 'table-responsive-container' },
					table(
						{ class: 'submitted-user-data-table ' +
							'submitted-current-user-data-table user-request-table' },
						thead(
							tr(
								th({ class: 'submitted-user-data-table-status' }),
								th(_("Name")),
								th(_("Issuer")),
								th({ class: 'submitted-user-data-table-date' }, _("Issue date")),
								th({ class: 'submitted-user-data-table-link' })
							)
						),
						tbody(
							businessProcess.requirementUploads.applicable,
							function (requirementUpload) {
								td({ class: 'submitted-user-data-table-status' },
									_if(requirementUpload._isApproved, span({ class: 'fa fa-check' })),
										_if(requirementUpload._isRejected, span({ class: 'fa fa-exclamation' })));
								td(_d(requirementUpload.document._label, { user: requirementUpload.master }));
								td(requirementUpload.document._issuedBy);
								td({ class: 'submitted-user-data-table-date' },
										requirementUpload.document._issueDate);
								td({ class: 'submitted-user-data-table-link' },
									a({ href: urlPrefix + 'document/' +
										camelToHyphen.call(requirementUpload.document.uniqueKey) + "/" },
										span({ class: 'fa fa-search' }, _("Go to"))));
							}
						)
					)
				)]),
		_if(businessProcess.paymentReceiptUploads.applicable._size,
			[h3(_("Payment receipts")),
				div(
					{ class: 'table-responsive-container' },
					table(
						{ class: 'submitted-user-data-table ' +
							'submitted-current-user-data-table user-request-table' },
						thead(
							tr(
								th({ class: 'submitted-user-data-table-status' }),
								th(_("Name")),
								th({ class: 'submitted-user-data-table-date' }, _("Issue date")),
								th({ class: 'submitted-user-data-table-link' })
							)
						),
						tbody(
							businessProcess.paymentReceiptUploads.applicable,
							function (receipt) {
								td({ class: 'submitted-user-data-table-status' },
									_if(receipt._isApproved, span({ class: 'fa fa-check' })),
										_if(receipt._isRejected, span({ class: 'fa fa-exclamation' })));
								td(receipt.document.label);
								td({ class: 'submitted-user-data-table-date' }, receipt.document._issueDate);
								td({ class: 'submitted-user-data-table-link' },
									a({ href: urlPrefix + 'receipt/' + camelToHyphen.call(receipt.key) + "/" },
										span({ class: 'fa fa-search' }, _("Go to"))));
							}
						)
					)
				)]),
		_if(businessProcess.certificates.uploaded._size,
			[h3(_("Certificates")),
				div(
					{ class: 'table-responsive-container' },
					table(
						{ class: 'submitted-user-data-table ' +
							'submitted-current-user-data-table user-request-table' },
						thead(
							tr(
								th({ class: 'submitted-user-data-table-status' }),
								th(_("Name")),
								th(_("Issuer")),
								th({ class: 'submitted-user-data-table-date' }, _("Issue date")),
								th({ class: 'submitted-user-data-table-link' })
							)
						),
						tbody(
							businessProcess.certificates.uploaded,
							function (certificate) {
								td({ class: 'submitted-user-data-table-status' },
									span({ class: 'fa fa-certificate' }));
								td(certificate.label);
								td(certificate._issuedBy);
								td({ class: 'submitted-user-data-table-date' }, certificate._issueDate);
								td({ class: 'submitted-user-data-table-link' },
									a({ href: urlPrefix + 'certificate/' +
										camelToHyphen.call(certificate.key) + '/' },
										span({ class: 'fa fa-search' }, _("Go to"))));
							}
						)
					)
				)])),
		section({ class: 'section-primary entity-data-section-side' },
			h2({ class: 'container-with-nav' }, _("Form data"),
				a(
					{ class: 'hint-optional hint-optional-left',
						'data-hint': _("Print your application form"), href: urlPrefix + 'data-print/',
						target: '_blank' },
					span({ class: 'fa fa-print' }, _("Print"))
				)),

			generateSections(businessProcess.dataForms.applicable))];
};
<|endoftext|>