<|start_filename|>src/Components/Panels/Menu/spacer.react.js<|end_filename|>
/**
 * A spacer menu item, properties:
 * 
 * - name
 *
 * @jsx React.DOM
 */

define(['react'], function(React) {
    return React.createClass({
        render: function() {
            return (
                <li className="menu-item-spacer auja-color-main auja-border-secondary">{this.props.item.getText()}</li>
                );
        }
    });

});

<|start_filename|>src/Factories/form_factory.js<|end_filename|>
/**
 * Form factory will create form objects based on input
 */
define(['build/Objects/Page/form'], function(Form) {

    return new function() {

        /**
         * Create the form
         */
        this.createForm = function(data) {
            return new Form(data);
        }

    };

});

<|start_filename|>src/Components/Panels/Page/Form/time.react.js<|end_filename|>
/**
 * A time field, properties:
 *
 * - label
 * - name
 * - .. any other allowed by input
 *
 * @jsx React.DOM
 */
define(['react', 'build/Components/Panels/Page/Form/label.react', 'moment', 'clockpicker'], function (React, Label, moment) {
    return React.createClass({
        componentDidMount: function () {
            $(this.refs.time.getDOMNode()).clockpicker({
                autoclose: true
            });
        },
        getInitialState: function () {
            return {value: this.props.item.getValue()};
        },
        handleChange: function (event) {
            time = moment(event.target.value, this.props.item.getFormat()).format(this.props.item.getFormat());

            //If parent element want us to broadcast our changes to it we'll oblige
            if (this.props.onChange) {
                this.props.onChange(time);
            }

            this.setState({value: time});
        },
        render: function () {
            var attributes = this.props.item.getAttributes();
            attributes.value = moment(this.state.value, this.props.item.getFormat()).format(this.props.item.getFormat());

            //onBlur needed to detect time change through clockpicker
            attributes.onBlur = this.handleChange;

            //Fallback if clockpicker somehow doesn't work
            attributes.onChange = this.handleChange;

            attributes.ref = 'time';
            attributes.readOnly = true;

            //Insure label is ommited when the item is part of another component.
            attributes.type == 'time' ? label = <Label item={this.props.item} name={this.props.item.getLabel()} /> : label = '';

            return (
                <div>
            {label}
                {React.DOM.input(attributes)}
                </div>
            );
        }
    });
});

<|start_filename|>src/Objects/Abstract/form_item.js<|end_filename|>
/**
 * Abstract form of a form item
 */
define([], function() {

    return function(data) {
        
        /**
         * Location of menu item
         * @type {integer}
         */
        this._order = data.order || 0;

        /**
         * Type of the menu item
         * @type {string}
         */
        this._type = 'unknown';
        
        /**
         * Name
         * @type {string}
         */
        this._name = data.name || null;
                
        /**
         * Label
         * @type {string}
         */
        this._label = data.label || '';

        /**
         * Value
         * @type {string}
         */
        this._value = data.value || null;

        /**
         * Required
         * @type {boolean}
         */
        this._required = data.required || false;

        /**
         * Setter for the order
         * @param order
         */
        this.setOrder = function(order) {
            this._order = order;
        };

        /**
         * Getter for the order
         * @returns integer
         */
        this.getOrder = function() {
            return this._order;
        };

        /**
         * Setter for the type
         * @param type
         */
        this.setType = function(type) {
            this._type = type;
        };

        /**
         * Getter for the type
         * @returns {type|*}
         */
        this.getType = function() {
            return this._type;
        };

        /**
         * Setter for name
         * @param name
         */
        this.setName = function(name) {
            this._name = name;
        };

        /**
         * Getter for name
         * @returns {string}
         */
        this.getName = function() {
            return this._name;
        };

        /**
         * Setter for label
         * @param label
         */
        this.setLabel = function(label) {
            this._label = label;
        };

        /**
         * Getter for label
         * @returns {string}
         */
        this.getLabel = function() {
            return this._label;
        };

        /**
         * Setter for value
         * @param value
         */
        this.setValue = function(value) {
            this._value = value;
        };

        /**
         * Getter for value
         * @returns {string}
         */
        this.getValue = function() {
            return this._value;
        };

        /**
         * Setter for required
         * @param required
         */
        this.setRequired = function(required) {
            this._required = required;
        };

        /**
         * Getter for required
         * @returns {boolean}
         */
        this.isRequired = function() {
            return this._required;
        };
        
    };    
});

<|start_filename|>src/Requests/request.js<|end_filename|>
/**
 * Currently a helper function to do nice ajax requests however
 * the goal is to add routing, options for factories to generate responses etc.etc.
 * @param string url
 */
define(['build/Requests/route_factory', 'build/Requests/cache'], function (RouteFactory) {


    /**
     * Register as a global initializer for a request
     * @constructor
     */
    window.Request = function(url) {
        
        /**
         * Do a GET request
         * @return jQuery.Deferred
         */
        this.get = function () {
            var ongoing = RequestCache.getOngoing(url);
            if(ongoing) {
                return ongoing;
            }
            
            var request = RouteFactory.handler(url).get(arguments[0] ? arguments[0] : null);
            RequestCache.add(url, request);
            return request;
        };

        /**
         * Do a POST request
         * @return jQuery.Deferred
         */
        this.post = function(data) {
            return RouteFactory.handler(url).post(data);
        };

        /**
         * Do a PUT request
         * @return jQuery.Deferred
         */
        this.put = function(data) {
            return RouteFactory.handler(url).put(data);
        }

    }
    
    return window.Request;
});

<|start_filename|>tests/spec/Components/Panels/Menu/resource.react.spec.js<|end_filename|>
/** @jsx React.DOM */
/** @jsx React.DOM */

define([
    'react',
    'build/Components/Panels/menu.react', //Required since resource renders a menu inside itself
    'build/Components/Panels/Menu/resource.react',
    'build/Objects/Menu/resource',
    'build/Objects/menu',
    'jasmine_matchers'
], function (React, MenuView, Resource, Item, Menu) {
    describe('Resource menu item', function () {

        beforeEach(function () {
            this.addMatchers(require('jasmine_matchers'));
        });

        it('should render a list item', function () {
            var TestUtils = React.addons.TestUtils;

            var item = new Item({
                text: "Text on the resource"
            });

            // Render a checkbox with label in the document
            var text = TestUtils.renderIntoDocument(Resource({
                item: item,
                panel: new Menu()
            }));

            //There just should be one single li rendered
            var elements = TestUtils.scryRenderedDOMComponentsWithTag(text, 'li');
            expect(elements.length).toBe(1);
        });
        
        it('should render a search input field', function () {
            var TestUtils = React.addons.TestUtils;
        
            var item = new Item({
                text: "Text on the resource",
                properties: {
                    "searchable": {
                        "target": "example/club_index.json?q=%s"
                    }
                }
            });
        
            // Render a checkbox with label in the document
            var text = TestUtils.renderIntoDocument(Resource({
                item: item,
                panel: new Menu()
            }));
        
            //There just should be one single input rendered
            var elements = TestUtils.scryRenderedDOMComponentsWithTag(text, 'input');
            expect(elements.length).toBe(1);
        })
    });
});
    

<|start_filename|>src/Objects/Abstract/page_item.js<|end_filename|>
/**
 * Menu item definition
 */
define([], function() {

    return function() {

        /**
         * Location of menu item
         * @type {integer}
         */
        this.order = 0;

        /**
         * Type of the menu item
         * @type {string}
         */
        this.type = 'unknown';

        /**
         * Setter for the order
         * @param order
         */
        this.setOrder = function(order) {
            this.order = order;
        };

        /**
         * Getter for the order
         * @returns integer
         */
        this.getOrder = function() {
            return this.order;
        };

        /**
         * Setter for the type
         * @param type
         */
        this.setType = function(type) {
            this.type = type;
        };

        /**
         * Getter for the type
         * @returns {type|*}
         */
        this.getType = function() {
            return this.type;
        };
    };

});

<|start_filename|>src/auja.react.js<|end_filename|>
/**
 * @jsx React.DOM
 */
//RequireJS config
require.config({

    /**
     * Use document base url
     */
    baseUrl: '',

    /**
     * When debug is true add a bust to prevent caching
     */
    urlArgs: (new Date()).getTime(),

    /**
     * Location of dependencies
     */
    paths: {

        //Bunch of requirements needed for the blueimp file uploader
        'jquery.ui.widget': 'bower_components/blueimp-file-upload/js/vendor/jquery.ui.widget',
        'jquery.fileupload': 'bower_components/blueimp-file-upload/js/jquery.fileupload',
        'jquery.fileupload-ui': 'bower_components/blueimp-file-upload/js/jquery.fileupload-ui',
        'jquery.fileupload-image': 'bower_components/blueimp-file-upload/js/jquery.fileupload-image',
        'jquery.fileupload-validate': 'bower_components/blueimp-file-upload/js/jquery.fileupload-validate',
        'jquery.fileupload-video': 'bower_components/blueimp-file-upload/js/jquery.fileupload-video',
        'jquery.fileupload-audio': 'bower_components/blueimp-file-upload/js/jquery.fileupload-audio',
        'jquery.fileupload-process': 'bower_components/blueimp-file-upload/js/jquery.fileupload-process',
        'jquery.fileupload-jquery-ui': 'bower_components/blueimp-file-upload/js/jquery.fileupload-jquery-ui',
        'jquery.iframe-transport': 'bower_components/blueimp-file-upload/js/jquery.iframe-transport',
        'load-image': 'bower_components/blueimp-load-image/js/load-image',
        'load-image-meta': 'bower_components/blueimp-load-image/js/load-image-meta',
        'load-image-exif': 'bower_components/blueimp-load-image/js/load-image-exif',
        'load-image-ios': 'bower_components/blueimp-load-image/js/load-image-ios',
        'canvas-to-blob': 'bower_components/blueimp-canvas-to-blob/js/canvas-to-blob',
        'tmpl': 'bower_components/blueimp-tmpl/js/tmpl',

        //System dependencies
        react: 'bower_components/react/react',
        jquery: 'bower_components/jquery/dist/jquery.min',
        fluxxor: 'bower_components/fluxxor/build/fluxxor',
        signals: 'bower_components/js-signals/dist/signals',
        crossroads: 'bower_components/crossroads.js/dist/crossroads',
        moment: 'bower_components/moment/moment',
        pikaday: 'bower_components/pikaday/pikaday',
        pikadayjq: 'bower_components/pikaday/plugins/pikaday.jquery',
        trumbowyg: 'bower_components/trumbowyg/dist/trumbowyg',
        tinymce: 'bower_components/tinymce/tinymce',
        tinymcejq: 'bower_components/tinymce/tinymce.jquery',
        jstree: 'bower_components/jstree/dist/jstree',
        minicolors: 'bower_components/jquery-minicolors/jquery.minicolors',
        sugar: 'bower_components/sugar/release/sugar-full.development',
        request: 'build/Requests/request',
        flux: 'build/Stores/flux',
        clockpicker: 'bower_components/clockpicker/dist/jquery-clockpicker.min',
        selectize: 'bower_components/selectize/dist/js/standalone/selectize.min'
    },
    config: {
        moment: {
            noGlobal: true
        }
    },

    /**
     * Shim
     */
    shim: {
        trumbowyg: {
            deps: ['jquery']
        },
        tinymcejq: {
            deps: ['jquery', 'tinymce']
        },
        minicolors: {
            deps: ['jquery']
        },
        clockpicker: {
            deps: ['jquery']
        },
        pikadayjq: {
            deps: ['jquery', 'moment', 'pikaday']
        },
        selectize: {
            deps: ['jquery']
        }
    }
});

require(['react', 'flux', 'build/scaffolding.react'], function (React, flux, Scaffolding) {
    React.renderComponent(<Scaffolding flux={flux} />, document.body);
});
    

<|start_filename|>src/Stores/panel.js<|end_filename|>
define(['fluxxor', 'build/Factories/panel_factory'], function(Fluxxor, PanelFactory) {

    /**
     * The main Auja store
     */
    return Fluxxor.createStore({

        /**
         * All panels currently in view
         */
        panels: [],

        /**
         * Height of the panels, changed on resize
         */
        height: 0,

        /**
         * Index of current panel as a reference
         * Starts at -1 since adding will be done using ++index
         */
        index: -1,

        /**
         * On initialization and on system update we will update the state
         * @param url
         */
        initialize: function(url) {
            this.bindActions(
                'panel-scroll', this.scroll,
                'resize', this.resize,
                'activate-item', this.activateItem,
                
                //Update panels
                'update', this.update,
                
                //Different types of panels
                'menu', this.addPanel,
                'page', this.addPanel,

                //Pop
                'pop', this.pop,
                
                //Menu specific actions
                'extend-resource', this.extendResource,
                'update-resource', this.updateResource
            )
        },

        /**
         * Getter for the state
         * @returns {*}
         */
        getState: function() {
            return {
                'height': this.height,
                'panels': this.panels
            };
        },

        /**
         * On window resize also set the panel height
         */
        resize: function() {
            var oldHeight = this.height;
            this.height = $('#panels').height();
            if(this.height != oldHeight) {
                this.emit('change');
            }
        },
        
        /**
         * When somebody scrolls a panel
         */
        scroll: function(panel) {
            if(panel.isPaginated()) {
                this.emit('change');
            }
        },

        /**
         * Update content of all panels
         * @todo group same origin requests (or do something in request object with ongoing requests)
         */
        update: function() {
            this.panels.map(function(panel) {
                if(panel.isUpdateable()) {
                    var request = new Request(panel.getUrl());
                    request.get().done(function (response) {
                        panel = PanelFactory.updatePanel(panel, response);
                        this.emit('change');
                    }.bind(this));
                }
            }.bind(this));
        },

        /**
         * Add a panel
         * @param p
         */
        addPanel: function(p) {
            var panel = PanelFactory.createPanel(p);
            
            if(!panel) {
                console.error('Requested to dispatch unknown panel');
                return;
            }
            
            //Set the index, since adding will always be on the end
            panel.setIndex(++this.index);
            panel.setId('panel-' + panel.getIndex());
            
            //If the panel from which this panel is added does not originate from the latest
            //we need to remove trailing panels
            var panels = [];
            for(var i in this.panels) {
                if(panel.getOrigin() && this.panels[i].getIndex() <= panel.getOrigin().getIndex()) {
                    panels.push(this.panels[i]);
                }
            }      
            this.panels = panels;
                
            //Put the panel in the view
            this.panels[panel.getIndex()] = panel;
            
            this.emit('change');
        },

        pop: function() {
            if (this.panels.length > 0) {
                if (this.panels.pop() == undefined) {
                    this.pop();
                    return;
                }
                --this.index;
            } else {
                console.error('No panels left to remove.')
            }
            this.emit('change');
        },
        /**
         * Activate an item within a panel
         * @todo add spec test
         * @todo move to panel
         * @param item
         */
        activateItem: function(item) {
            for(var i in this.panels) {
                if(this.panels[i].getId() == item.panel.getId()) {
                    this.panels[i].setActiveItem(item.item);
                    break;
                }
            }
            
            this.emit('change');
        },

        /**
         * Extend a resource
         * @param data
         */
        extendResource: function(data) {
            var panel = data.panel,
                response = data.data,
                item = data.item;
            
            //Find the panel
            for(var i in this.panels) {
                if(this.panels[i].getId() == panel.getId()) {
                    
                    if(this.panels[i].getType() != 'menu') {
                        console.error('Update of menu item requested on a non menu');
                        return;
                    }
                    this.panels[i].extendItem(item, response);
                    this.emit('change');                    
                    return;
                }
            }
        },

        /**
         * Update a resource
         * @param data
         */
        updateResource: function(data) {
            var response = data.data,
                item = data.item;

            //Find the panel
            for(var i in this.panels) {
                if(this.panels[i].hasItem(item)) {
                    this.panels[i].updateItem(item, response);
                    this.emit('change');
                    return;
                }
            }
        }
        
    })

});

<|start_filename|>tests/spec/Objects/Menu/spacer.spec.js<|end_filename|>
define(['build/Objects/Menu/spacer'], function (Item) {
    describe('Spacer menu item', function () {

        beforeEach(function () {
            this.addMatchers(require('jasmine_matchers'));
        });

        it('should implement spacer item specific methods', function () {

            var item = new Item({
                text: 'Howdy'
            });

            expect(item.getText()).toBe('Howdy');

            item.setText('Label305');
            
            expect(item.getText()).toBe('Label305');
        });

        it('should implement an update method which transfers properties', function () {
            var item = new Item({
                text: 'Howdy'
            });
            
            expect(item.getText()).toBe('Howdy');

            var updateItem = new Item({
                text: 'Label305'
            });
            item.update(updateItem);

            expect(item.getText()).toBe('Label305');
        });


        it('should implement a menu item', function () {

            var item = new Item({});
            
            item.setId('some-id');
            item.setOrder(72);
            item.setIsActive(true);
            
            expect(item.getId()).toBe('some-id');
            expect(item.getType()).toBe('spacer');
            expect(item.getOrder()).toBe(72);
            expect(item.isActive()).toBe(true);
        });
    });
});


<|start_filename|>src/Objects/Page/Form/textarea.js<|end_filename|>

define(['build/Objects/Abstract/form_item'], function(FormItem) {

    var Textarea = function(data) {

        //Call the parent constructor
        FormItem.call(this, data);

        //Set type of this object
        this.setType('textarea');

        /**
         * Get attributes for this input
         * @return Object
         */
        this.getAttributes = function() {
            return {
                type: this.getType(),
                value: this.getValue(),
                name: this.getName()
            }
        };


    };

    // Inherit Panel
    Textarea.prototype = FormItem;

    // Fix constructor
    Textarea.prototype.constructor = Textarea;
    return Textarea;
});

<|start_filename|>src/Factories/page_factory.js<|end_filename|>
/**
 * Page factory will create page objects based on input
 */
define(['build/Objects/page'], function(Page) {

    return new function() {

        /**
         * Create the page
         */
        this.createPage = function(data) {
            var page = new Page();
            page.setContent(data.page);
            return page;
        }

    };

});

<|start_filename|>src/Components/Panels/Page/form.react.js<|end_filename|>
/**
 * A form, attributes of the form are passed directly
 *
 * @jsx React.DOM
 */

//Listing of all supported page items
var FormItems = {
    'header': 'build/Components/Panels/Page/header.react',
    'text': 'build/Components/Panels/Page/Form/text.react',
    'password': 'build/Components/Panels/Page/Form/password.react',
    'textarea': 'build/Components/Panels/Page/Form/textarea.react',
    'trumbowyg': 'build/Components/Panels/Page/Form/trumbowyg.react',
    'tinymce': 'build/Components/Panels/Page/Form/tinymce.react',
    'number': 'build/Components/Panels/Page/Form/number.react',
    'file_select': 'build/Components/Panels/Page/Form/file_select.react',
    'integer': 'build/Components/Panels/Page/Form/integer.react',
    'url': 'build/Components/Panels/Page/Form/url.react',
    'tel': 'build/Components/Panels/Page/Form/tel.react',
    'color': 'build/Components/Panels/Page/Form/color.react',
    'time': 'build/Components/Panels/Page/Form/time.react',
    'checkbox': 'build/Components/Panels/Page/Form/checkbox.react',
    'email': 'build/Components/Panels/Page/Form/email.react',
    'selectMultiple': 'build/Components/Panels/Page/Form/select_multiple.react',
    'select': 'build/Components/Panels/Page/Form/select.react',
    'selectMultipleCheckbox': 'build/Components/Panels/Page/Form/select_multiple_checkbox.react',
    'date': 'build/Components/Panels/Page/Form/date.react',
    'datetime': 'build/Components/Panels/Page/Form/datetime.react',
    'range': 'build/Components/Panels/Page/Form/range.react',
    'submit': 'build/Components/Panels/Page/Form/submit.react',
    'hidden': 'build/Components/Panels/Page/Form/hidden.react'
};

define([
    'react',
    'build/Components/Panels/Page/header.react',
    'build/Components/Panels/Page/Form/text.react',
    'build/Components/Panels/Page/Form/password.react',
    'build/Components/Panels/Page/Form/textarea.react',
    'build/Components/Panels/Page/Form/trumbowyg.react',
    'build/Components/Panels/Page/Form/tinymce.react',
    'build/Components/Panels/Page/Form/number.react',
    'build/Components/Panels/Page/Form/file_select.react',
    'build/Components/Panels/Page/Form/integer.react',
    'build/Components/Panels/Page/Form/url.react',
    'build/Components/Panels/Page/Form/tel.react',
    'build/Components/Panels/Page/Form/color.react',
    'build/Components/Panels/Page/Form/time.react',
    'build/Components/Panels/Page/Form/checkbox.react',
    'build/Components/Panels/Page/Form/email.react',
    'build/Components/Panels/Page/Form/select_multiple.react',
    'build/Components/Panels/Page/Form/select.react',
    'build/Components/Panels/Page/Form/select_multiple_checkbox.react',
    'build/Components/Panels/Page/Form/date.react',
    'build/Components/Panels/Page/Form/datetime.react',
    'build/Components/Panels/Page/Form/range.react',
    'build/Components/Panels/Page/Form/submit.react',
    'build/Components/Panels/Page/Form/hidden.react'
], function (React) {
    return React.createClass({

        /**
         * Focus first element after form load
         */
        componentDidMount: function() {
            $(this.refs.form.getDOMNode()).find('input:visible:first').focus();
        },

        /**
         * Handles form submission
         */
        handleSubmit: function (event) {
            event.preventDefault();
            flux.actions.submit(
                this.props.item.getAction(),
                event.target.getAttribute('method'),
                $(event.target).serializeArray(),
                this.props.panel
            );
        },

        /**
         * Generate an ID for an item
         * @param item
         */
        getFormItemId: function (item) {
            if (!this.formItemIds) {
                this.formItemIds = [];
            }

            var i = 1;
            var available = false;
            while (!available) {
                var id = 'input.{panel}.{type}.{index}'.assign({
                    panel: this.props.panel.id,
                    type: item.getType(),
                    index: i
                });

                if (!this.formItemIds[name]) {
                    available = true;
                }
            }

            return id;
        },

        render: function () {

            var items = this.props.item.getItems().map(function (item) {

                if (!FormItems[item.getType()]) {
                    console.error("Unsupported form item type requested: " + item.getType());
                    return;
                }

                //Fetch the item from the corresponding file
                var Item = require(FormItems[item.getType()]);

                //Extract the validation message from the item
                item.validationMessage = null;
                if (item.getName() && this.props.message && this.props.message.validation && this.props.message.validation[item.getName()]) {
                    item.validationMessage = this.props.message.validation[item.getName()];
                }

                var className = 'row form-item form-item-{type}'.assign({type: item.getType()});
                return (
                    <div className={className}>
                        <Item itemId={this.getFormItemId(item)} item={item} />
                    </div>
                );
            }.bind(this));

            return (
                <form ref="form" onSubmit={this.handleSubmit} action={this.props.item.getAction()} method={this.props.item.getMethod()}>{items}</form>
            );
        }
    });

});

<|start_filename|>src/Objects/Page/Form/datetime.js<|end_filename|>

define(['build/Objects/Abstract/form_item'], function(FormItem) {

    var DateTime = function(data) {

        //Call the parent constructor
        FormItem.call(this, data);

        //Set type of this object
        this.setType('datetime');

        /**
         * The format the datetime
         * @type {string|null}
         * @private
         */
        this._format = data.format || null;
        
        /**
         * Getter for format
         * @returns {string|null}
         */
        this.getFormat = function() {
            return this._format;
        };


        /**
         * Setter for format
         * @param format
         */
        this.setFormat = function(format) {
            this._format = format;
        };
        

        /**
         * Get attributes for this input
         * @return Object
         */
        this.getAttributes = function() {
            return {
                type: this.getType(),
                value: this.getValue(),
                name: this.getName(),
                format: this.getFormat(),

            }
        };
    };

    // Inherit Panel
    DateTime.prototype = FormItem;

    // Fix constructor
    DateTime.prototype.constructor = DateTime;

    return DateTime;
});

<|start_filename|>tests/spec/Objects/Page/Form/range.spec.js<|end_filename|>
define(['build/Objects/Page/Form/range'], function (Item) {
    describe('Range form item', function () {

        beforeEach(function () {
            this.addMatchers(require('jasmine_matchers'));
        });

        it('should return corresponding attributes', function () {
            var item = new Item({
                order: 10,
                name: 'thename',
                label: 'The name',
                value: 11,
                min: 1,
                max: 100,
                required: true
                
            });

            expect(item.getAttributes()).toHaveKeys([
                'type',
                'value',
                'name',
                'min',
                'max'
            ]);
            
            expect(item.getValue()).toBe(11);

        });

        it('should implement a form item', function () {

            var item = new Item({
                order: 10,
                name: 'thename',
                label: 'The name',
                value: 11,
                min: 1,
                max: 100,
                required: true
            });

            //Test spec of transferring initial data
            expect(item.getType()).toBe('range');
            expect(item.getOrder()).toBe(10);
            expect(item.getName()).toBe('thename');
            expect(item.getLabel()).toBe('The name');
            expect(item.getValue()).toBe(11);
            expect(item.getMin()).toBe(1);
            expect(item.getMax()).toBe(100);
            expect(item.isRequired()).toBe(true);

            //Test spec of setters
            item.setOrder(2);
            item.setName('somename');
            item.setLabel('Your name');
            item.setMin(3);
            item.setMax(56);
            item.setValue(14);
            item.setRequired(false);
            
            expect(item.getOrder()).toBe(2);
            expect(item.getName()).toBe('somename');
            expect(item.getLabel()).toBe('Your name');
            expect(item.getMin()).toBe(3);
            expect(item.getMax()).toBe(56);
            expect(item.getValue()).toBe(14);
            expect(item.isRequired()).toBe(false);
            
        });

    });
});


<|start_filename|>src/Components/Panels/menu.react.js<|end_filename|>
/**
 * A menu panel
 *
 * @jsx React.DOM
 */

//Listing of all supported menu items
var MenuItems = {
    'link': 'build/Components/Panels/Menu/link.react',
    'spacer': 'build/Components/Panels/Menu/spacer.react',
    'resource': 'build/Components/Panels/Menu/resource.react'
};

//Map as an array to load panel dependencies
define([
    'react',
    'build/Components/Panels/Menu/link.react',
    'build/Components/Panels/Menu/spacer.react',
    'build/Components/Panels/Menu/resource.react'
], function(React) {
    return React.createClass({
        render: function() {
            
            //Create the possibility to set a custom "origin panel", to use as reference
            var originPanel = this.props.originPanel || this.props.panel;
            
            //Combine menu items together to form a single list
            var menu = this.props.panel.getItems().map(function(item) {
                if(!MenuItems[item.getType()]) {
                    console.error("Unsupported menu item type requested: " + item.getType());
                    return;
                }
                
                var Item = require(MenuItems[item.getType()]);
                return ( <Item key={item.key} scrollContainer={this.props.scrollContainer} flux={this.props.flux} panel={originPanel} item={item} /> );
            }.bind(this));
            
            return (
                <ul>
                    {menu}
                </ul>
                );
        }
    });

});

<|start_filename|>src/scaffolding.react.js<|end_filename|>
/**
 * @jsx React.DOM
 */
define([
    'react',
    'sugar', 
    'fluxxor',
    'flux',
    'build/Stores/auja',
    'build/Components/Scaffolding/message.react',
    'build/Components/Scaffolding/authentication.react',
    'build/Components/Scaffolding/header.react',
    'build/Components/Scaffolding/body.react'
], function (React, SugarJS, Fluxxor, flux, Store, Message, Authentication, Header, Body) {

    var Style = React.createClass({
        /**
         * Combine items into a neatly formatted string
         * @param name
         * @param property_name the CSS property to be styled
         * @param value the value it should take
         * @returns {string}
         */
        entry: function (name, property_name, value) {
            var result = "";
            result += name + " {\n";
            result += "\t" + property_name + ": " + value + "!important;\n";
            result += "}\n\n";
            return result;
        },
        parse: function (colors) {
            var result = "\n";
            for (var name in colors) {
                result += this.entry('.auja-bg-' + name, 'background-color', colors[name]);
                result += this.entry('.auja-color-' + name, 'color', colors[name]);
                result += this.entry('.auja-border-' + name, 'border-color', colors[name]);
                result += this.entry('.active.auja-active-border-' + name, 'border-color', colors[name]);

                //Dependency specific CSS
                switch(name) {
                    case 'main':
                        result += this.entry('.trumbowyg-modal-submit', 'background-color', colors[name]);
                        result += this.entry('.trumbowyg-fullscreen .trumbowyg-fullscreen-button', 'background-color', colors[name]);
                        result += this.entry('input:focus', 'border-color', colors[name]);
                        result += this.entry('select:focus', 'border-color', colors[name]);
                        result += this.entry('.is-selected .pika-button', 'background-color', colors[name]);
                        break;
                }
            }

            return result;
        },
        render: function () {
            var style = this.parse(this.props.auja.colors);
            
            //Force the main auja color to be put into triangle on top
            style += this.entry('ul#main-menu li:after', 'border-color', 'transparent ' + this.props.auja.colors.main + ' transparent transparent');

            return (
                <style>
                    {style}
                </style>
                );
        }
    });

    return React.createClass({
        mixins: [Fluxxor.FluxMixin(React), Fluxxor.StoreWatchMixin('AujaStore')],
        getStateFromFlux: function () {
            return flux.store('AujaStore').getState();
        },
        componentWillMount: function () {
            flux.actions.initialize();
        },
        componentDidMount: function() {
            flux.actions.resize();
            $(window).bind('resize', flux.actions.resize);
        },
        render: function () {
            document.title = this.state.title;

            return (
                <div id="auja">
                    <Message flux={flux} />
                    <Authentication auja={this.state} />
                    <Header auja={this.state} />
                    <Body flux={flux} auja={this.state} />
                    <Style auja={this.state} />
                </div>
                );
        }
    });

});

<|start_filename|>tests/spec/Components/Panels/Menu/link.react.spec.js<|end_filename|>
/** @jsx React.DOM */

define([
    'react',
    'build/Components/Panels/Menu/link.react',
    'build/Objects/Menu/link',
    'jasmine_matchers'
], function (React, Link, Item) {

    describe('Text menu item', function () {

        beforeEach(function () {
            this.addMatchers(require('jasmine_matchers'));
        });

        it('should display its text', function () {
            var TestUtils = React.addons.TestUtils;

            var item = new Item({
                text: "Text on the link"
            });

            // Render a checkbox with label in the document
            var text = TestUtils.renderIntoDocument(Link({
                item: item
            }));

            var a = TestUtils.findRenderedDOMComponentWithTag(text, 'span');
            expect(a.getDOMNode().textContent).toEqual('Text on the link');
        });
    });
});

<|start_filename|>src/Objects/Page/Form/tinymce.js<|end_filename|>

define(['build/Objects/Page/Form/file_select'], function(FileSelect) {

    var Tinymce = function(data) {

        //Call the parent constructor
        FileSelect.call(this, data);

        /**
         * Uploader
         * @type {boolean}
         */
        this._uploader = data.uploader || false;

        /**
         * target
         * @type {string}
         */
        this._target = data.target || null;

        //Set type of this object
        this.setType('tinymce');

        /**
         * Setter for uploader
         * @param uploader
         */
        this.setUploader = function(uploader) {
            this._uploader = uploader;
        };

        /**
         * Getter for uploader
         * @returns {boolean}
         */
        this.hasUploader = function() {
            return this._uploader;
        };

        /**
         * Get target for uploader
         * @returns string
         */
        this.getTarget = function () {
            return this._target;
        };

        /**
         * Set target for uploader
         * @param target
         */
        this.setTarget = function (target) {
            this._target = target;
        };

        /**
         * Get attributes for this input
         * @return Object
         */
        this.getAttributes = function() {
            return {
                type: this.getType(),
                value: this.getValue(),
                name: this.getName()
            }
        };

    };

    // Inherit Panel
    Tinymce.prototype = FileSelect;

    // Fix constructor
    Tinymce.prototype.constructor = Tinymce;

    return Tinymce;
});

<|start_filename|>tests/spec/Stores/flux.spec.js<|end_filename|>
define([
    'jasmine_matchers', 'react', 'jquery', 'fluxxor', 'sugar',
    'build/Stores/flux'
], function () {
    describe('Flux', function () {

        beforeEach(function () {
            this.addMatchers(require('jasmine_matchers'));
        });

        it('should have all actions', function () {

            var flux = require('build/Stores/flux');
            
            expect(flux.actions).toHaveKeys([
                'initialize',
                'resize',
                'click',
                'submit',
                'handle',
                'onPanelScroll',
                'extendResource',
                'updateResource',
                'processFail'
            ]);
        });

        
    });

});

<|start_filename|>tests/spec/Objects/Menu/sortable_item.spec.js<|end_filename|>
define(['build/Objects/Menu/sortable_item'], function (Item) {
    describe('Sortable menu item', function () {

        beforeEach(function () {
            this.addMatchers(require('jasmine_matchers'));
        });

        it('should implement link item specific methods', function () {

            var item = new Item({
                target: '/users',
                text: 'Howdy',
                left: 7,
                right: 8
            });

            expect(item.getTarget()).toBe('/users');
            expect(item.getText()).toBe('Howdy');
            expect(item.getLeft()).toBe(7);
            expect(item.getRight()).toBe(8);
            
            item.setTarget('/companies');
            item.setText('Label305');
            item.setLeft(5);
            item.setRight(6);

            expect(item.getTarget()).toBe('/companies');
            expect(item.getText()).toBe('Label305');
            expect(item.getLeft()).toBe(5);
            expect(item.getRight()).toBe(6);
        });

        it('should implement an update method which transfers properties', function () {
            var item = new Item({
                target: '/users',
                text: 'Howdy',
                left: 7,
                right: 8
            });

            expect(item.getTarget()).toBe('/users');
            expect(item.getText()).toBe('Howdy');
            expect(item.getLeft()).toBe(7);
            expect(item.getRight()).toBe(8);

            var updateItem = new Item({
                target: '/companies',
                text: 'Label305',
                left: 6,
                right: 7
            });            
            item.update(updateItem);

            expect(item.getTarget()).toBe('/companies');
            expect(item.getText()).toBe('Label305');
            expect(item.getLeft()).toBe(6);
            expect(item.getRight()).toBe(7);
        });

        it('should implement a menu item', function () {

            var item = new Item({});

            item.setOrder(72);
            item.setIsActive(true);

            expect(item.getType()).toBe('sortable_item');
            expect(item.getOrder()).toBe(72);
            expect(item.isActive()).toBe(true);
        });
    });
});


<|start_filename|>src/Components/Panels/Menu/link.react.js<|end_filename|>
/**
 * A link menu item, properties:
 *
 * - name
 * - href
 * - icon
 *
 * @jsx React.DOM
 */

define(['react'], function (React) {
    return React.createClass({
        handleClick: function () {
            if (!this.props.item.isExternal()) {
                flux.actions.click(this.props.item.getTarget(), this.props.panel, this.props.item);
            }
        },
        render: function () {

            var className = 'menu-item-link auja-border-secondary ';

            //Create the icon class
            var icon = "fallback";
            if (this.props.item.getIcon()) {
                icon = this.props.item.getIcon();
            }
            className += "icon " + icon;

            //Check if we match the active item
            if (this.props.item.isActive()) {
                className += " auja-color-main active auja-active-border-main";
            }

            var link = <span>{this.props.item.getText()}</span>;
            if (this.props.item.isExternal()) {
                link = <a target="_blank" href={this.props.item.getTarget()}>{this.props.item.getText()}</a>;
                className += " external";
            }

            if (this.props.item.getTarget() == false) {
                className += " no-target";
                return (
                    <li className={className}>
                        {link}
                    </li>
                );
            } else {
                return (
                    <li className={className} onClick={this.handleClick}>
                        {link}
                    </li>
                );
            }
        }
    });

});

<|start_filename|>tests/spec/Objects/Page/Form/header.spec.js<|end_filename|>
define(['build/Objects/Page/Form/header'], function (Item) {
    describe('Header form item', function () {

        beforeEach(function () {
            this.addMatchers(require('jasmine_matchers'));
        });

        it('should have text', function () {
            var item = new Item({
                order: 10,
                name: 'thename',
                label: 'The name',
                value: 'James',
                required: true,
                text: 'This is a title'
            });
            
            expect(item.getText()).toBe('This is a title');
        });

        it('should implement a form item', function () {

            var item = new Item({
                order: 10,
                name: 'thename',
                label: 'The name',
                value: 'James',
                required: true
            });

            //Text spec of transferring initial data
            expect(item.getType()).toBe('header');
            expect(item.getOrder()).toBe(10);
            expect(item.getName()).toBe('thename');
            expect(item.getLabel()).toBe('The name');
            expect(item.getValue()).toBe('James');
            expect(item.isRequired()).toBe(true);

            //Test spec of setters
            item.setOrder(2);
            item.setName('somename');
            item.setLabel('Your name');
            item.setValue('Charles');
            item.setRequired(false);

            expect(item.getOrder()).toBe(2);
            expect(item.getName()).toBe('somename');
            expect(item.getLabel()).toBe('Your name');
            expect(item.getValue()).toBe('Charles');
            expect(item.isRequired()).toBe(false);

        });

    });
});


<|start_filename|>tests/spec/Components/Panels/Menu/spacer.react.spec.js<|end_filename|>
/** @jsx React.DOM */

define([
    'react',
    'build/Components/Panels/Menu/spacer.react',
    'build/Objects/Menu/spacer',
    'jasmine_matchers'
], function (React, Spacer, Item) {

    describe('Text menu item', function () {

        beforeEach(function () {
            this.addMatchers(require('jasmine_matchers'));
        });

        it('should display its text', function () {
            var TestUtils = React.addons.TestUtils;

            var item = new Item({
                text: "Text on the spacer"
            });

            // Render a checkbox with label in the document
            var text = TestUtils.renderIntoDocument(Spacer({
                item: item
            }));

            var a = TestUtils.findRenderedDOMComponentWithTag(text, 'li');
            expect(a.getDOMNode().textContent).toEqual('Text on the spacer');
        });
    });
});

<|start_filename|>src/Objects/Page/Form/header.js<|end_filename|>

define(['build/Objects/Abstract/form_item'], function(FormItem) {
    
    var Header = function(data) {

        //Call the parent constructor
        FormItem.call(this, data);

        //Set type of this object
        this.setType('header');

        /**
         * Text
         * @type {string}
         */
        this.text = data.text || 'NULL';

        /**
         * Buttons
         * @type {array}
         */
        this.buttons = data.buttons || [];

        /**
         * Setter for text
         * @param text
         */
        this.setText = function(text) {
            this.text = text;
        };

        /**
         * Getter for text
         * @returns {string}
         */
        this.getText = function() {
            return this.text;
        };

        /**
         * Setter for buttons
         * @param buttons
         */
        this.setButtons = function(buttons) {
            this.buttons = buttons;
        };

        /**
         * Getter for buttons
         * @returns {array}
         */
        this.getButtons = function() {
            return this.buttons;
        };

    };
    
    // Inherit item
    Header.prototype = FormItem;

    // Fix constructor
    Header.prototype.constructor = Header;
    
    return Header;
});

<|start_filename|>tests/spec/Objects/Menu/Properties/sortable.spec.js<|end_filename|>
define(['build/Objects/Menu/Properties/sortable'], function (Property) {
    describe('Sortable property', function () {

        beforeEach(function () {
            this.addMatchers(require('jasmine_matchers'));
        });

        it('should implement a Property', function () {
            var property = new Property({});

            expect(property.getName()).toBe('sortable');
        });

        it('should have a target', function () {

            var property = new Property({
                target: 'http://sortme'
            });

            expect(property.getTarget()).toBe('http://sortme');

        })
    });
});


<|start_filename|>src/Requests/route_factory.js<|end_filename|>
/**
 * Routing factory, will put all routes in place and ables request object
 * to pass request to correct handler
 */
var routers = {
    'http': 'build/Requests/Routers/http'
};

define([
    'signals', 
    'crossroads',
    'build/Requests/Routers/http'
], function (signals, crossroads) {

    //Register as a global
    window.crossroads = crossroads;

    /**
     * Setup listening to the AujaStore to update routes in crossroads
     */
    require(['flux'], function(flux) {
        flux.store('AujaStore').on('change', function () {
            crossroads.removeAllRoutes();
    
            this.getState().routes.map(function (route) {
                require(routers[route.type]).addRoute(route);
            }.bind(this));
    
            //Add fallback route to http router 
            require(routers['http']).addRoute({
                target: /(.*)/
            });
        });
    });

    //Add fallback route to http router 
    //TODO use bypassed for this
    require(routers['http']).addRoute({
        target: /(.*)/
    });

    return new function () {
        /**
         * Getter for the handler
         * @param url
         * @return handler
         */
        this.handler = function (url) {
            var handler = false;
            var route = false;

            //Return same handler as last time when same url is requested
            //crossroads will not parse same route twice in a row
            if (this.last && this.last.url == url) {
                handler = this.last.handler;
                route = this.last.route;
            } else {
                //Parse the url to fetch the corresponding handler
                crossroads.parse(url, [url, function (h, r) {
                    handler = h;
                    route = r;
                }.bind(this)]);

                if (handler) {
                    this.last = {
                        url: url,
                        handler: handler,
                        route: route
                    }
                }
            }
            
            //Log an error
            if(!handler) {
                console.error('No corresponding handler found for: ' + url);
            }

            //Instantiate the collected handler otherwise return false
            return handler ? new handler(url, route) : false;
        }
    };
});

<|start_filename|>src/Components/Scaffolding/authentication.react.js<|end_filename|>
/**
 * @jsx React.DOM
 */
define(['react', 'build/Components/Panels/Page/form.react'], function (React, Form) {

    return React.createClass({

        /**
         * Stores if the user was authenticated once
         */
        wasAuthenticated: false,

        /**
         * Definition of the authentication panel
         * @todo use an object definition for this
         */
        panel: {
            id: 'authentication'
        },

        render: function () {

            /**
             * Empty overlay when no authentication available
             */
            if(!this.props.auja.authentication) {
                return (
                    <span className="authentication-missing"></span>
                    );
            }

            var className = "authentication-overlay authentication-overlay-hugeinc";

            //Set weither or not the user has already been authenticated before
            if (this.wasAuthenticated) {
                className += " transparent";
            } else if(this.props.auja.authenticated) {
                this.wasAuthenticated = true;
            }
            
            //Set open/closed
            className += this.props.auja.authenticated ? " closed" : " open";

            //Get a message from this form
            var message = flux.store('MessageStore').getMessage();
            
            return (
                <div className={className}>
                    <Form message={message} panel={this.panel} item={this.props.auja.authentication} />
                </div>
                );
        }
    });

});

<|start_filename|>src/Components/Panels/Page/header.react.js<|end_filename|>
/**
 * A page header
 *
 * - contents
 *
 * @jsx React.DOM
 */

define(['react', 'build/Components/Panels/Page/button.react'], function (React, Button) {
    return React.createClass({
        render: function () {
            var buttons = this.props.item.getButtons().map(function (button) {
                return (
                    <Button panel={this.props.panel} button={button} />
                );
            }.bind(this));

            return (
                <h2>{this.props.item.text}{buttons}</h2>
            );
        }
    });

});

<|start_filename|>tests/spec/Objects/Page/Form/file_select.spec.js<|end_filename|>
define(['build/Objects/Page/Form/file_select'], function (Item) {
    describe('File form item', function () {

        beforeEach(function () {
            this.addMatchers(require('jasmine_matchers'));
        });

        it('should have a target property', function () {
            var item = new Item({
                order: 10,
                name: 'thename',
                label: 'The name',
                value: 'James',
                required: true,
                target: '/uploads'
            });

            expect(item.getTarget()).toBe('/uploads');

            item.setTarget('/images/uploads');

            expect(item.getTarget()).toBe('/images/uploads');
        });

        it('should have a multiple property', function () {
            var item = new Item({
                order: 10,
                name: 'thename',
                label: 'The name',
                value: 'James',
                required: true,
                target: '/uploads',
                ref: 123,
                multiple: false
            });

            expect(item.isMultiple()).toBe(false);

            item.setIsMultiple(true);

            expect(item.isMultiple()).toBe(true);
        });

        it('should have a files property', function () {
            var item = new Item({
                order: 10,
                name: 'thename',
                label: 'The name',
                value: 'James',
                required: true,
                target: '/uploads',
                ref: 123,
                multiple: true,
                files: [
                    {
                        'name': 'bla'
                    }
                ]
            });

            expect(item.getFiles()[0].name).toBe('bla');

            item.setFiles([{
                'name': 'asdf'
            }]);

            expect(item.getFiles()[0].name).toBe('asdf');
        });

        it('should have a accept single file as property', function () {
            var item = new Item({
                order: 10,
                name: 'thename',
                label: 'The name',
                value: 'James',
                required: true,
                target: '/uploads',
                ref: 123,
                multiple: false,
                file: {
                    'name': 'bla'
                }
            });

            expect(item.getFiles()[0].name).toBe('bla');
        });


        it('should implement a form item', function () {

            var item = new Item({
                order: 10,
                name: 'thename',
                label: 'The name',
                value: 'James',
                required: true
            });

            //Text spec of transferring initial data
            expect(item.getType()).toBe('file_select');
            expect(item.getOrder()).toBe(10);
            expect(item.getName()).toBe('thename');
            expect(item.getLabel()).toBe('The name');
            expect(item.getValue()).toBe('James');
            expect(item.isRequired()).toBe(true);

            //Test spec of setters
            item.setOrder(2);
            item.setName('somename');
            item.setLabel('Your name');
            item.setValue('Charles');
            item.setRequired(false);

            expect(item.getOrder()).toBe(2);
            expect(item.getName()).toBe('somename');
            expect(item.getLabel()).toBe('Your name');
            expect(item.getValue()).toBe('Charles');
            expect(item.isRequired()).toBe(false);

        });

    });
});


<|start_filename|>tests/spec/Components/Panels/menu.react.spec.js<|end_filename|>
/** @jsx React.DOM */

define([
    'react',
    'build/Components/Panels/menu.react',
    'build/Objects/menu',
    'jasmine_matchers'
], function (React, Menu, MenuObject) {

    describe('Menu', function () {

        beforeEach(function () {
            this.addMatchers(require('jasmine_matchers'));
        });

        it('should be able to render a menu item', function () {
            var TestUtils = React.addons.TestUtils;

            var menu = new MenuObject({});
            menu.setId(1);
            menu.setItems([
                {
                    "type": "link",
                    "order": 1,
                    "link": {
                        "text": "Add club",
                        "target": "example/clubs/create",
                        "icon": "ion-compose"
                    }
                },
                {
                    "type": "link",
                    "order": 1,
                    "link": {
                        "text": "Add club",
                        "target": "example/clubs/create",
                        "icon": "ion-compose"
                    }
                }
            ]);

            // Render a checkbox with label in the document
            var menu = TestUtils.renderIntoDocument(Menu({
                message: null,
                panel: menu
            }));

            //There just should be two li's rendered
            var elements = TestUtils.scryRenderedDOMComponentsWithTag(menu, 'li');
            expect(elements.length).toBe(2);
        });

    });
});

<|start_filename|>src/Components/Panels/Page/Form/select_multiple_checkbox.react.js<|end_filename|>
/**
 * A select field, properties:
 *
 * - label
 * - name
 * - .. any other allowed by input
 * @jsx React.DOM
 */
 define(['react', 'build/Components/Panels/Page/Form/label.react', 'build/Components/Panels/Page/Form/checkbox.react'], function(React, Label, Checkbox) {
    return React.createClass({
        render: function () {
            var options = this.props.item.getOptions().map(function(option) {
                option._fallback = false;
                return (<Checkbox item={option} />);
            }.bind(this));            
            
            return (
                <div>
                <Label item={this.props.item} name={this.props.item.getLabel()} />
                {options}
                </div>
                );
        }
    });
});


<|start_filename|>tests/spec/Objects/Page/header.spec.js<|end_filename|>
define(['build/Objects/Page/header'], function (Item) {
    describe('Header page item', function () {

        beforeEach(function () {
            this.addMatchers(require('jasmine_matchers'));
        });
        
        it('should implement a text property', function() {

            var item = new Item({});
            
            expect(item.getText()).toBe('');
            item.setText('A nice title');
            expect(item.getText()).toBe('A nice title');
        });
        
        it('should implement a page item', function () {
            
            var item = new Item({});
            
            expect(item.getType()).toBe('header');
            expect(item.getOrder()).toBe(0);
            
            item.setOrder(7);
            
            expect(item.getOrder()).toBe(7);
        });
    });
});


<|start_filename|>src/Components/Panels/Menu/sortable.react.js<|end_filename|>
/**
 * @jsx React.DOM
 */

define(['react', 'jstree'], function (React) {

    return React.createClass({
        /**
         * Check if a is a parent of b
         * @param a
         * @param b
         * @return boolean
         */
        isParentOf: function (a, b) {
            return a.getLeft() < b.getLeft() && a.getRight() > b.getRight();
        },

        /**
         * Check if child of parent
         * @param child
         * @param parent
         * @return boolean
         */
        isChildOf: function (child, parent) {
            return child.getLeft() > parent.getLeft() && child.getRight() < parent.getRight();
        },

        /**
         * Get all parents of an item
         * @param items
         * @param item
         */
        getParents: function (items, item) {
            return items.filter(function (parent) {
                return this.isParentOf(parent, item);
            }.bind(this));
        },

        /**
         * Check if the parent is a direct parent of the child
         * @param items
         * @param parent
         * @param child
         * @return boolean
         */
        isDirectParentOf: function (items, parent, child) {
            var allParentsOfChild = this.getParents(items, child);

            //Check if one of the parents is a child of the to be checked parent
            for (var i in allParentsOfChild) {
                if (this.isChildOf(allParentsOfChild[i], parent)) {
                    return false;
                }
            }
            return true;
        },

        /**
         * Check if the item has a parent
         * @param items
         * @param check
         */
        hasParent: function (items, check) {
            return 0 != items.count(function (item) {
                    return this.isParentOf(item, check);
                }.bind(this));
        },

        /**
         * Get direct children of an item
         * @param items
         * @param parent
         * @return Array
         */
        getDirectChildren: function (items, parent) {
            return items.filter(function (child) {
                return this.isChildOf(child, parent) && this.isDirectParentOf(items, parent, child);
            }.bind(this)).sortBy(function (n) {
                return n.left;
            });
        },

        /**
         * Add children recursively
         * @param all
         * @param items
         * @return Array
         */
        addChildren: function (all, items) {
            return items.map(function (item) {
                item.children = this.getDirectChildren(all, item);
                item.children = this.addChildren(all, item.children);
                return item;
            }.bind(this));
        },

        /**
         * Simplifies nested SortableItem object to something much flatter
         * @param tree
         * @param root
         */
        simplifyForJsTree: function (tree, root) {
            var result = [];

            for (var i in tree) {
                result.push({
                    type: root ? 'root' : 'child',
                    text: tree[i].getText(),
                    data: {
                        id: tree[i].getId(),
                        left: tree[i].getLeft(),
                        right: tree[i].getRight(),
                        text: tree[i].getText(),
                        target: tree[i].getTarget()
                    },
                    state: {
                        opened: true
                    },
                    children: this.simplifyForJsTree(tree[i].children, false)
                });
            }

            return result;
        },

        /**
         * Get the simplified tree
         */
        simplifiedTree: function (items) {
            //Fetch all items without any parent
            var tree = items.filter(function (item) {
                return !this.hasParent(items, item);
            }.bind(this)).sortBy(function (n) {
                return n.left;
            });

            //Add children
            tree = this.addChildren(items, tree);

            //Simplify so that jsTree will like it
            return this.simplifyForJsTree(tree, true);
        },

        /**
         * Transform to the way JsTree want the tree
         */
        getJsTree: function (obj, cb) {
            var tree = this.simplifiedTree(this.props.item.getItems());

            cb.call(this, tree);
        },

        /**
         * Will parse the actual tree
         * @param tree
         * @param nextLeft
         */
        parseTree: function (tree, nextLeft) {
            var result = [];

            for (var i in tree) {
                //Get children
                var children = this.parseTree(tree[i].children, nextLeft + 1);

                //Next right is current left +1 or the topmost child +1
                var nextRight = nextLeft + 1;
                if (children.length > 0) {
                    nextRight = children.max(function (child) {
                        return child.right;
                    }).right + 1;
                }

                //Add current item to the result
                result.push({
                    id: tree[i].data.id,
                    text: tree[i].data.text,
                    left: nextLeft,
                    right: nextRight
                });

                result = result.union(children);

                nextLeft = nextRight + 1;
            }

            return result;
        },

        /**
         * Will normalize the tree from jsTree and dispatch the change
         * @param tree
         */
        treeChanged: function (tree) {
            var parsed = this.parseTree(tree, 1);
            flux.actions.submit(this.props.item.getProperty('sortable').getTarget(), 'post', {tree: parsed});
        },

        /**
         * Triggered when a node if focused
         * @param id
         */
        onNodeFocus: function (id) {
            var item = this.props.item.getItems().find(function (item) {
                return item.getId() == id;
            });

            flux.actions.click(item.getTarget(), this.props.originPanel);
        },

        /**
         * Listen for the tree to change
         */
        componentDidMount: function () {
            $(document).on('dnd_stop.vakata', function (e, data) {
                if (this.refs.tree) {
                    var tree = $(this.refs.tree.getDOMNode()).jstree(true).get_json('#', {});
                    this.treeChanged(tree);
                }
            }.bind(this));

            //Check if focused, if so dispatch click and try to unfocus
            $(this.refs.tree.getDOMNode())
                .on('select_node.jstree', function (e, data) {
                    this.onNodeFocus(data.node.data.id);
                    $(this.refs.tree.getDOMNode()).jstree('deselect_node', data.node);
                }.bind(this))
        },

        /**
         * Check if the component should update
         * nextProps.item will always equal this.props.item since it is a pointer
         * to an object, so we cannot compare the two
         */
        shouldComponentUpdate: function (nextProps, nextState) {
            if (!this.initialized) {
                return true;
            }

            //Get what the tree looks like in the dom
            var domTree = $(this.refs.tree.getDOMNode()).jstree(true).get_json('#', {});
            domTree = this.parseTree(domTree, 1);

            //Check if the items in the next version correspond to items in the dom
            var count = nextProps.item.getItems().count(function (item) {
                return !domTree.none(function (domItem) {
                    return item.getId() == domItem.id
                        && item.getLeft() == domItem.left
                        && item.getRight() == domItem.right
                        && item.getText() == domItem.text
                });
            });

            return count != nextProps.item.getItems().length;
        },

        componentDidUpdate: function () {
            if (!this.initialized) {
                this.initialized = true;

                $(this.refs.tree.getDOMNode())

                    //Initialize the tree
                    .jstree({
                        core: {
                            //Parse and set data
                            data: this.getJsTree,

                            //Make sure something updates when we drag
                            check_callback: true,

                            //More fancy more better
                            animation: 1,

                            //No selection
                            multiple: false
                        },
                        plugins: [
                            //That is, drag 'n drop
                            "dnd"
                        ],
                        types: {
                            root: {
                                max_depth: 4
                            }
                        }
                    });
            } else {
                $(this.refs.tree.getDOMNode()).jstree('refresh');
            }
        },
        render: function () {
            return (
                <div ref="tree"></div>
            );
        }
    });

});


<|start_filename|>tests/spec/Components/Scaffolding/header.react.spec.js<|end_filename|>
/** @jsx React.DOM */

define([
    'react',
    'build/Components/Scaffolding/header.react',
    'jasmine_matchers'
], function (React, Header) {

    describe('Menu', function () {

        beforeEach(function () {
            this.addMatchers(require('jasmine_matchers'));
        });

        it('should show the title', function () {
            var TestUtils = React.addons.TestUtils;

            // Render a checkbox with label in the document
            var header = TestUtils.renderIntoDocument(Header({
                auja: {
                    title: "This is the title"
                }
            }));

            var header = TestUtils.findRenderedDOMComponentWithTag(header, 'h1');

            //parseInt since the value of an input is always a string 
            expect(header.getDOMNode().textContent).toEqual("This is the title");
        });

        it('should show the user name', function () {
            var TestUtils = React.addons.TestUtils;

            // Render a checkbox with label in the document
            var header = TestUtils.renderIntoDocument(Header({
                auja: {
                    title: "This is the title",
                    user: {
                        name: "<NAME>"
                    }
                }
            }));

            var elements = TestUtils.scryRenderedDOMComponentsWithTag(header, 'div');

            var flag = false;
            for (var i in elements) {
                if (elements[i].getDOMNode().textContent == '<NAME>') {
                    flag = true;
                    break;
                }
            }
            expect(flag).toBe(true);
        });

        it('should show buttons', function () {
            var TestUtils = React.addons.TestUtils;

            // Render a checkbox with label in the document
            var header = TestUtils.renderIntoDocument(Header({
                auja: {
                    title: "This is the title",
                    user: {
                        name: "<NAME>"
                    },
                    buttons: [
                        {
                            text: "Logout",
                            target: "#logout"
                        }
                    ]
                }
            }));

            var elements = TestUtils.scryRenderedDOMComponentsWithTag(header, 'a');

            var flag = false;
            for (var i in elements) {
                if (elements[i].getDOMNode().textContent == 'Logout') {
                    flag = true;
                    break;
                }
            }
            expect(flag).toBe(true);
        })

    });
});

<|start_filename|>src/Components/Scaffolding/menu.react.js<|end_filename|>
/**
 * The main menu on the left
 * 
 * @jsx React.DOM
 * @todo new name!
 */
define(['react'], function(React) {
    
    var Item = React.createClass({
        handleClick: function() {
            flux.actions.click(this.props.item.target);
        },
        render: function() {            
            var className = "auja-bg-main";
            
            if(this.props.item.icon) {
                className += " icon " + this.props.item.icon;
            }
            
            return (
                <li className={className} title={this.props.item.title} onClick={this.handleClick}>
                    <span>{this.props.item.title}</span>
                </li>
                );
        }
    });

    return React.createClass({
        render: function() {
            var menu = this.props.auja.menu.map(function(item) {
                return (
                    <Item key={item.target} auja={this.props.auja} item={item} />
                    );
            }.bind(this));
            
            return (
                <ul id="main-menu">
                    {menu}
                </ul>
                );
        }
    });

});

<|start_filename|>src/Requests/cache.js<|end_filename|>
/**
 * Currently a helper function to do nice ajax requests however
 * the goal is to add routing, options for factories to generate responses etc.etc.
 * @param string url
 */
define([], function () {

    window.RequestCache = new function() {

        /**
         * All ongoing requests
         * @type {Array}
         * @private
         */
        this._ongoing = {};

        /**
         * Add url as
         * @param url       to where the request was
         * @param request   the request itself
         */
        this.add = function(url, request) {
            this._ongoing[url] = request;
            request.always(function() {
                delete this._ongoing[url];
            }.bind(this));
        };

        /**
         * Get ongoing request to an url
         * @param url
         * @return jQuery.Deferred|boolean
         */
        this.getOngoing = function(url) {
            return this._ongoing[url];
        }
        
    };
    
});

<|start_filename|>src/Requests/Handlers/http.js<|end_filename|>
/**
 * Helper to do Http requests
 * 
 * @param url
 */
define([], function() {
    window.HttpRequest = function (url, route) {

        /**
         * The url to do the request to
         * @type String
         */
        this.url = route.action ? route.action : url;

        /**
         * Default request
         * @type Object
         */
        this.settings = {
            'data': {},
            'dataType': 'json',
            'cache': false,
            'isFile': false
        };

        /**
         * Setter for data to requests
         * @param data
         */
        this.setData = function (data) {
            this.settings.data = data;
        };

        /**
         * Get request
         * @return Deferred
         */
        this.get = function () {
            if(arguments[0]) {
                this.setData(arguments[0]);
            }
            this.settings.type = 'GET';
            return this._doAjax();
        };

        /**
         * Post request
         * @param data
         * @return Deferred
         */
        this.post = function (data) {
            this.setData(data);
            this.settings.type = 'POST';
            return this._doAjax();
        };

        /**
         * Put request
         * @param data
         * @return Deferred
         */
        this.put = function (data) {
            this.setData(data);
            this.settings.type = 'PUT';
            return this._doAjax();
        };

        /**
         * Actual executor
         * @return Deferred
         */
        this._doAjax = function () {
            var dfd = $.Deferred();
            $.ajax(this.url, this.settings)
                .done(function(response) {
                    dfd.resolve(response);
                })
                .fail(function(jqXHR) {
                    dfd.reject(jqXHR.status);
                });            
            return dfd.promise();
        }
    };
});

<|start_filename|>src/Components/Panels/Menu/resource.react.js<|end_filename|>
/**
 * A resource menu item, properties:
 *
 * - target
 *
 * @jsx React.DOM
 */

define([
    'react', 
    'build/Components/Panels/Menu/Mixins/paging.mixin', 
    'build/Components/Panels/Menu/Mixins/searchable.mixin', 
    'build/Objects/menu', 
    'build/Components/Panels/Menu/sortable.react'], function (React, Paging, Searchable, Menu, SortableMenu) {

    return React.createClass({
        mixins: [Paging, Searchable],
        render: function () {
            if (this.props.item.hasProperty('sortable')) {
                //"Sortable" menu
                return (
                    <li className="menu-item-resource">
                        <SortableMenu item={this.props.item} originPanel={this.props.panel} />
                    </li>
                );
            } else {
                //"Normal" item
                var MenuPanel = require('build/Components/Panels/menu.react');

                //Transfer different props to mock Menu
                var panel = new Menu();
                panel.setOrigin(this.props.panel.getOrigin());
                panel.setItems(this.props.item.getItems());

                return (
                    <li className="menu-item-resource">
                        {this.getSearchableForm()}
                        <MenuPanel panel={panel} originPanel={this.props.panel} />
                    </li>
                );
            }
        }
    });

});

<|start_filename|>src/Components/Panels/page.react.js<|end_filename|>
/**
 * A page panel
 *
 * @jsx React.DOM
 */

//Listing of all supported page items
var PageItems = {
    'header': 'build/Components/Panels/Page/header.react',
    'form': 'build/Components/Panels/Page/form.react'
}

//Map as an array to load panel dependencies
define([
    'react',
    'build/Components/Panels/Page/header.react',
    'build/Components/Panels/Page/form.react'
], function (React) {

    return React.createClass({
        render: function () {

            //Combine page items together to form a single list
            var page = this.props.panel.getContent().map(function (item) {
                if (!item) {
                    console.error('Undefined item passed, did you create an object for it?');
                    return;
                } else if (!PageItems[item.getType()]) {
                    console.error("Unsupported page item type requested: " + item.getType());
                    return;
                }

                var Item = require(PageItems[item.getType()]);

                return (
                    <div className="row">
                        <Item message={this.props.message} panel={this.props.panel} item={item} />
                    </div>
                );
            }.bind(this));

            return (
                <div>
                    {page}
                </div>
            );
        }
    });

});

<|start_filename|>src/Components/Panels/Menu/Mixins/paging.mixin.js<|end_filename|>
/**
 * A mixin that enables the resource to paginate, expects:
 * 
 * - Property item, with method `getPaging`
 * - Property panel
 *
 * @jsx React.DOM
 */
define([], function() {

    return {
        pagingThreshHold: 300,
        componentDidMount: function() {
            flux.actions.extendResource(this.props.panel, this.props.item, this.props.item.getTarget());
        },
        componentDidUpdate: function () {
            if (this.props.item.getPaging() && this.props.item.getPaging().next && this.needsExtending()) {
                flux.actions.extendResource(this.props.panel, this.props.item, this.props.item.getPaging().next);
            }
        },
        needsExtending: function () {
            var node = $('#' + this.props.panel.getId()).find('div:first');
            var ch = node.height(),
                st = node.scrollTop(),
                sh = node[0].scrollHeight;

            return sh - st - ch < this.pagingThreshHold;
        }
    }

});

<|start_filename|>src/Components/Panels/Page/Form/number.react.js<|end_filename|>
/**
 * A number field, properties:
 *
 * - label
 * - name
 * - .. any other allowed by input
 *
 * @jsx React.DOM
 */
define(['react', 'build/Components/Panels/Page/Form/label.react'], function (React, Label) {
    return React.createClass({
        getInitialState: function () {
            return {value: this.props.item.getValue()};
        },
        handleChange: function (event) {
            this.setState({value: event.target.value});
        },
        render: function () {
            var attributes = this.props.item.getAttributes();
            attributes.value = this.state.value;
            attributes.onChange = this.handleChange;
            /* Tell the stepping prop any increment is allowed, for browser validation of the number input type */
            attributes.step = "any";

            return (
                <div>
                    <Label item={this.props.item} name={this.props.item.getLabel()} />
                {React.DOM.input(attributes)}
                </div>
            );
        }
    });
});

<|start_filename|>tests/spec/Components/Panels/Page/form.react.spec.js<|end_filename|>
/** @jsx React.DOM */

define([
    'react',
    'build/Components/Panels/Page/form.react',
    'build/Objects/Page/form',
    'jasmine_matchers'
], function (React, Form, FormObject) {

    describe('Form', function () {

        beforeEach(function () {
            this.addMatchers(require('jasmine_matchers'));
        });

        it('should render a form', function () {
            var TestUtils = React.addons.TestUtils;

            var form = new FormObject({
                "action": "example/clubs/store",
                "method": "post"
            });

            // Render a checkbox with label in the document
            var form = TestUtils.renderIntoDocument(Form({
                message: null,
                panel: {},
                item: form
            }));

            var tag = TestUtils.findRenderedDOMComponentWithTag(form, 'form');

            //Url will be absolute
            expect(tag.getDOMNode().action).toContain('example/clubs/store');
            expect(tag.getDOMNode().method).toContain('post');
        });

        it('should display form items', function () {
            var TestUtils = React.addons.TestUtils;

            var form = new FormObject({
                "action": "example/clubs/store",
                "method": "put",
                "items": [
                    {
                        "type": "text",
                        "text": {
                            "name": "name",
                            "label": "Name of club",
                            "value": "Some club"
                        }
                    }
                ]
            });

            // Render a checkbox with label in the document
            var form = TestUtils.renderIntoDocument(Form({
                message: null,
                panel: {},
                item: form
            }));

            var input = TestUtils.findRenderedDOMComponentWithTag(form, 'input');
            expect(input.getDOMNode().value).toEqual('Some club');
        });
    });
});

<|start_filename|>src/Objects/Menu/Properties/searchable.js<|end_filename|>
define(['build/Objects/Abstract/property'], function(Property) {
    
    var SearchableProperty = function(data) {
        
        //Call the parent constructor
        Property.call(this, arguments);
        
        //Set name of this property
        this.setName('searchable');

        /**
         * Target of the searchable, should contain a %s to replace with the search query
         * @type string
         */
        this.target = data.target;

        /**
         * Setter for the target
         * @param target
         */
        this.setTarget = function(target) {
            this.target = target;
        };

        /**
         * Getter for the target
         * @returns {target|*}
         */
        this.getTarget = function() {
            return this.target;
        }
        
    };
    
    // Inherit Property
    SearchableProperty.prototype = Property;

    // Fix constructor
    SearchableProperty.prototype.constructor = SearchableProperty;

    return SearchableProperty;
});

<|start_filename|>src/Objects/Menu/resource.js<|end_filename|>
define(['build/Objects/Abstract/menu_item', 'build/Factories/resource_property_factory'], function (MenuItem, ResourceItemPropertyFactory) {

    var Resource = function (data) {

        //Call the parent constructor
        MenuItem.call(this, arguments);

        /**
         * Resource items
         * @type {Array}
         */
        this.items = [];

        /**
         * Our custom type
         * @type {string}
         */
        this.type = 'resource';

        /**
         * Target where to fetch the data from
         */
        this.target = data.target;

        /**
         * Paging options
         * @type {{}}
         */
        this.paging = {};

        /**
         * Special properties of a resource
         * @type {*|{}}
         */
        this.properties = data.properties ? ResourceItemPropertyFactory.createProperties(data.properties) : [];

        /**
         * Getter for the id
         * @returns string
         * @override
         */
        this.getId = function () {
            return this.target;
        };

        /**
         * Getter for the target
         * @returns String
         */
        this.getTarget = function () {
            return this.target;
        };

        /**
         * Get items in this resource
         * @returns {Array}
         */
        this.getItems = function () {
            return this.items;
        };

        /**
         * Get the current paging
         * @returns Object
         */
        this.getPaging = function () {
            return this.paging;
        };

        /**
         * Get the properties active on this resource
         * @returns {*|{}}
         */
        this.getProperties = function() {
            return this.properties;  
        };

        /**
         * Check if certain named property is present
         * @param name
         * @return boolean
         */
        this.hasProperty = function(name) {
            return this.getProperty(name) !== false;
        };

        /**
         * Get the property
         * @param name
         * @return Property
         */
        this.getProperty = function(name) {
            for(var i in this.properties) {
                if(this.properties[i].getName() == name) {
                    return this.properties[i];
                }
            }
            return false;
        };

        /**
         * Update with new data
         * @param data
         */
        this.extend = function (data) {

            //Initialize like this otherwise we have circular dependencies
            var MenuItemFactory = require('build/Factories/menu_item_factory');
            
            //Create actual items
            data.items = data.items.map(function (item) {
                return MenuItemFactory.createItem(item);
            }.bind(this));

            this.items = this.items.concat(data.items);
            this.paging = data.paging;
        };

        /**
         * Set the active item in our childs
         * @param item
         */
        this.setActiveItem = function (item) {
            for (var i in this.items) {
                this.items[i].setIsActive(this.items[i].getId() == item.getId());
            }
        };

        /**
         * Update with new data
         * @param data
         */
        this.update = function (data) {
            if (data.items && (data.items.length > 0 || this.items.length == 0)) {

                //Initialize like this otherwise we have circular dependencies
                var MenuItemFactory = require('build/Factories/menu_item_factory');
                
                //When items are passed as data directly write them as the content
                //Since we receive a Resource object here it will always have items, so we check if it already
                //contains items, or if originally there were no items (this.items.length == 0)
                this.items = data.items.map(function (item) {
                    return MenuItemFactory.createItem(item);
                }.bind(this));
            } else if (!this.paging || !this.paging.total) {
                this.items = [];
                
                //Just load the original resource again
                setTimeout(function () {
                    flux.actions.updateResource(this, this.getTarget());
                }.bind(this), 1);
            } else if(this.paging.total) {
                //When we have a clue what to call to update this resource do that
                //setTimeout is to handle the "async" behavior of dispatching
                setTimeout(function () {
                    flux.actions.updateResource(this, this.paging.total);
                }.bind(this), 1);
            }
        };
    };

    // Inherit Panel
    Resource.prototype = MenuItem;

    // Fix constructor
    Resource.prototype.constructor = Resource;

    return Resource;
});

<|start_filename|>src/Objects/Abstract/panel.js<|end_filename|>
/**
 * Abstract representation of a panel
 */
define([], function() {
    
    return function() {

        /**
         * The object that called this panel in existence
         * @private
         */
        this._origin;

        /**
         * Type of panel we're looking at
         * @private
         */
        this._type;

        /**
         * ID of the panel
         * @type string
         * @private
         */
        this._id;

        /**
         * Index of the panel
         * @type string
         * @private
         */
        this._index;

        /**
         * Is updateable
         * @type {boolean}
         * @private
         */
        this._isUpdateable = false;

        /**
         * Url which the panel represents
         * @typ string
         * @private
         */
        this._url;

        /**
         * Check if paginated
         * @type {boolean}
         * @private
         */
        this._isPaginaged = false;

        /**
         * Setter for the ID
         * @param id
         */
        this.setId = function(id) {
            this._id = id;
        };
        
        /**
         * Getter for the ID
         * @returns {string|*}
         */
        this.getId = function() {
            return this._id;
        };

        /**
         * Setter for the index
         * @param index
         */
        this.setIndex = function(index) {
            this._index = index;
        };

        /**
         * Getter for the index
         * @returns {integer|*}
         */
        this.getIndex = function() {
            return this._index;
        };

        /**
         * Set the origin of the request
         * @param origin
         */
        this.setOrigin = function(origin) {
            this._origin = origin;
        };

        /**
         * Getter for the origin
         * @returns {origin|*}
         */
        this.getOrigin = function() {
            return this._origin;  
        };

        /**
         * Set type of the panel
         * @param type
         */
        this.setType = function(type) {
            this._type = type;
        };
        
        /**
         * Type of panel we're looking at 
         */
        this.getType = function() {
            return this._type;
        };

        /**
         * Setter for the url
         * @param id
         */
        this.setUrl = function(url) {
            this._url = url;
        };

        /**
         * Getter for the url
         * @returns {string|*}
         */
        this.getUrl = function() {
            return this._url;
        };


        /**
         * Getter for is updateable
         * @returns {*}
         */
        this.isUpdateable = function() {
            return this._isUpdateable;
        };

        /**
         * Setter for is updateable
         * @param isUpdateable
         */
        this.setIsUpdateable = function(isUpdateable) {
            this._isUpdateable = isUpdateable;
        };

        /**
         * Check if the panel is paginated
         * @return boolean
         */
        this.isPaginated = function() {
            return this._isPaginated;
        };
        
    }
    
});

<|start_filename|>tests/spec/Objects/Menu/resource.spec.js<|end_filename|>
define(['build/Objects/Menu/resource'], function (Item) {
    describe('Resource menu item', function () {

        beforeEach(function () {
            this.addMatchers(require('jasmine_matchers'));
        });

        it('should implement a menu item', function () {

            var item = new Item({});
            
            item.setOrder(72);
            item.setIsActive(true);
            
            expect(item.getType()).toBe('resource');
            expect(item.getOrder()).toBe(72);
            expect(item.getProperties()).toBeAnObject();
            expect(item.isActive()).toBe(true);
        });


        it('should have properties', function () {

            var item = new Item({
                properties: {
                    searchable: {
                        target: 'http://searchme'
                    }
                }
            });
            
            expect(item.hasProperty('searchable')).toBe(true);
            expect(item.getProperties().length).toBe(1);
            expect(item.getProperty('searchable').getTarget()).toBe('http://searchme');

            var item = new Item({});
            expect(item.hasProperty('searchable')).toBe(false);
            expect(item.getProperties()).toBeAnArray();

        });
    });
});


<|start_filename|>src/Objects/Page/Form/checkbox.js<|end_filename|>

define(['build/Objects/Abstract/form_item'], function(FormItem) {

    var Checkbox = function(data) {

        //Call the parent constructor
        FormItem.call(this, data);

        //Set type of this object
        this.setType('checkbox');

        /**
         * The checked state of checkbox
         * @type {boolean|null}
         * @private
         */
        this._checked = data.checked || null;

        /**
         * The fallback state of checkbox
         * @type {boolean|null}
         * @private
         */
        this._fallback = data.fallback != false;

        /**
         * Getter for checked
         * @returns {boolean|null}
         */
        this.isChecked = function() {
            return this._checked;
        };

        /**
         * Getter for fallback
         * @returns {boolean|null}
         */
        this.hasFallback = function() {
            return this._fallback;
        };

        /**
         * Setter for checked
         * @param checked
         */
        this.setIsChecked = function(checked) {
            this._checked = checked;
        };

        /**
         * Setter for fallback
         * @param fallback
         */
        this.setHasFallback = function(fallback) {
            this._fallback = fallback;
        };

        /**
         * Get attributes for this input
         * @return Object
         */
        this.getAttributes = function() {
            return {
                type: this.getType(),
                value: this.getValue(),
                name: this.getName(),
                checked: this.isChecked(),
                fallback: this.hasFallback()
            }
        };
    };

    // Inherit FormItem
    Checkbox.prototype = FormItem;

    // Fix constructor
    Checkbox.prototype.constructor = Checkbox;
    
    return Checkbox;
});

<|start_filename|>src/Components/Panels/Page/Form/select_multiple.react.js<|end_filename|>
/**
 * A select field, properties:
 *
 * - label
 * - name
 * - .. any other allowed by input
 * @jsx React.DOM
 */
 define(['react', 'build/Components/Panels/Page/Form/label.react', 'selectize'], function(React, Label) {
    return React.createClass({
        componentDidMount: function() {            
         var selectize = $(this.refs.multiselect.getDOMNode()).selectize({
            plugins: ['remove_button'],
            delimiter: ',',
            persist: false,
            });
        },
        getInitialState: function() {
            return {options: this.props.item.getOptions(),
                value: this.props.item.getValue()};
        },
        handleClick: function(event) {
            var selected = this.state.value.indexOf(event.target.value);
            selected != -1 ? this.state.value.splice(selected ,1) : this.state.value.push(event.target.value);
            
            return this.setState({value: this.state.value});
        },
        render: function () {
            var attributes = this.props.item.getAttributes();

            var options = this.props.item.getOptions().map(function(option) {
            return (React.DOM.option(option, option.label)
                );
            });
            //We want to be able to deselect all options, onChange does not allow this
            attributes.onClick = this.handleClick;
            attributes.value = this.state.value;
            attributes.ref = 'multiselect';
            attributes.multiple = true;
                       
            return (
                <div>
                <Label item={this.props.item} name={this.props.item.getLabel()} />
                {React.DOM.select(attributes,
                    options
                    )}

                </div>
            );
        }
    });
});


<|start_filename|>tests/spec/Components/Panels/Page/Form/submit.react.spec.js<|end_filename|>
/** @jsx React.DOM */

define([
    'react',
    'build/Components/Panels/Page/Form/submit.react',
    'build/Objects/Page/Form/submit',
    'jasmine_matchers'
], function (React, Submit, Item) {

    describe('Submit form input', function () {

        beforeEach(function () {
            this.addMatchers(require('jasmine_matchers'));
        });

        it('should display its value', function () {
            var TestUtils = React.addons.TestUtils;

            var item = new Item({
                value: 10
            });

            // Render a checkbox with label in the document
            var text = TestUtils.renderIntoDocument(Submit({
                item: item
            }));

            var input = TestUtils.findRenderedDOMComponentWithTag(text, 'input');

            //parseInt since the value of an input is always a string 
            expect(parseInt(input.getDOMNode().value)).toEqual(10);
        });

    });
});

<|start_filename|>src/Stores/flux.js<|end_filename|>
var FluxStores = {
    'AujaStore': 'build/Stores/auja',
    'PanelStore': 'build/Stores/panel',
    'MessageStore': 'build/Stores/message'
};

//Map as an array to load store dependencies
define([
    'fluxxor',
    'build/Stores/auja',
    'build/Stores/panel',
    'build/Stores/message'
], function(Fluxxor) {

    //Make sure we only render one instance
    if(window.flux) {
        return window.flux;
    }

    //Fill object with stores
    var stores = {};
    for(var name in FluxStores) {
        var store = require(FluxStores[name]);
        stores[name] = new store;
    }

    /**
     * All actions that can be dispatched
     * @type {{}}
     */
    var actions = {
        /**
         * Dispatch all initializing events
         */
        initialize: function() {
            this.dispatch('initialize');
        },

        /**
         * Dispatched on window resize
         */
        resize: function() {
            this.dispatch('resize');
        },

        /**
         * Process a click on a panel
         *
         * @todo Fix async version of passing the panel to the response handler
         * @param url
         * @param panel (optional)
         * @param item (optional) if isset will dispatch an activate-item event
         */
        click: function(url) {
            var panel = null;
            if(arguments[1]) {
                panel = arguments[1];
            }

            var item = null;
            if(panel != null && arguments[2]) {
                this.dispatch('activate-item', {panel: panel, item: arguments[2]});
            }

            var request = new Request(url);
            request.get().done(function(response) {
                response.url = url;
                flux.actions.handle(response.type, response, panel);
            }).fail(function(code) {
                flux.actions.processFail(code);
            });
        },

        /**
         * Submitting a form
         * @param url
         * @param method
         * @param data
         */
        submit: function(url, method, data) {
            var panel = null;
            if(arguments[3]) {
                panel = arguments[3];
            }

            var request = new Request(url);

            switch(method.toLowerCase()) {
                case 'put':
                    request.put(data).done(function(response) {
                        response.url = url;
                        flux.actions.handle(response.type, response, panel);
                    }).fail(function(code) {
                        flux.actions.processFail(code);
                    });
                    break;
                case 'get':
                    request.get(data).done(function(response) {
                        response.url = url;
                        flux.actions.handle(response.type, response, panel);
                    }).fail(function(code) {
                        flux.actions.processFail(code);
                    });
                    break;
                default:
                    request.post(data).done(function(response) {
                        response.url = url;
                        flux.actions.handle(response.type, response, panel);
                    }).fail(function(code) {
                        flux.actions.processFail(code);
                    });
            }
        },

        /**
         * Will dispatch according to type, so if you listen on handling of type "menu"
         * you'll get your data
         * @param type
         * @param data
         * @param origin the location the event originated from
         */
        handle: function(type, data, origin) {
            data.origin = origin;
            this.dispatch(type, data);

            switch(type) {
                case 'message':
                    //You can set weither or not to update the system
                    if(data.message.update == undefined || data.message.update) {
                        if (data.message.state == "success" || data.message.closeDepth != undefined) {
                            if (data.message.close_depth != undefined) {
                                for (var i = 0; i < data.message.close_depth; i++) {
                                    this.dispatch('pop');
                                }
                            } else {
                                this.dispatch('pop'); //always pop once on success
                            }
                        }
                        this.dispatch('update');
                    }
                    break;
            }
        },

        /**
         * Somewhere something failed with a http status code
         * @param code
         */
        processFail: function(code) {
            var message = {
                state: 'error',
                contents: 'Recieved unexpected response from the server'
            };

            switch(code) {
                case 404:
                    //Not found
                    message.contents = 'Resource not found';
                    break;
                case 401:
                    //Unauthorized
                    message.authenticated = false;
                    message.contents = 'Unauthorized';
                    break;
                case 200:
                    //Unexpected format
                    message.contents = 'Response from server not properly formatted';
            }

            //Append status code
            message.contents += ' [' + code + ']';

            this.dispatch('message', {message: message});

            return message;
        },

        /**
         * Trigger scrolling of a panel
         * @param panel
         */
        onPanelScroll: function(panel) {
            this.dispatch('panel-scroll', panel);
        },

        /**
         * Extend the items in a panel
         * @todo fix async
         * @param panel
         * @param item
         * @param url
         */
        extendResource: function(panel, item, url) {
            var request = new Request(url);
            request.get().done(function(data) {
                this.dispatch('extend-resource', {
                    panel: panel,
                    item: item,
                    data: data
                });
            }.bind(this)).fail(function(code) {
                flux.actions.processFail(code);
            });
        },

        /**
         * Update a single item with the response of an url
         * @param item
         * @param url
         */
        updateResource: function(item, url) {
            var request = new Request(url);
            request.get().done(function(data) {
                this.dispatch('update-resource', {
                    item: item,
                    data: data
                });
            }.bind(this)).fail(function(code) {
                flux.actions.processFail(code);
            });
        }
    };

    window.flux = new Fluxxor.Flux(stores, actions);
    return window.flux;
});

<|start_filename|>src/Components/Panels/Page/Form/password.react.js<|end_filename|>
/**
 * A password field, properties:
 *
 * - label
 * - name
 * - .. any other allowed by input
 *
 * @jsx React.DOM
 */
define(['react', 'build/Components/Panels/Page/Form/label.react'], function (React, Label) {
    return React.createClass({
        getInitialState: function () {
            return {value: this.props.item.getValue()};
        },
        handleChange: function (event) {
            this.setState({value: event.target.value});
        },
        render: function () {
            var attributes = this.props.item.getAttributes();
            attributes.value = this.state.value;
            attributes.onChange = this.handleChange;

            return (
                <div>
                    <Label item={this.props.item} name={this.props.item.getLabel()} />
                {React.DOM.input(attributes)}
                </div>
            );
        }
    });

});

<|start_filename|>src/Components/Panels/Page/Form/select.react.js<|end_filename|>
/**
 * A select field, properties:
 *
 * - label
 * - name
 * - .. any other allowed by input
 * @jsx React.DOM
 */
 define(['react', 'build/Components/Panels/Page/Form/label.react'], function(React, Label) {
    return React.createClass({

        getInitialState: function() {
            return {options: this.props.item.getOptions(),
                value: this.props.item.getValue()}   
        },
        handleChange: function(event) {
            this.setState({value: event.target.value});
        },
        render: function () {
            var attributes = this.props.item.getAttributes();

            var options = this.props.item.getOptions().map(function(option) {
            return (React.DOM.option(option, option.label)
                );
            }.bind(this));

            attributes.value = this.state.value;
            attributes.onChange = this.handleChange;
            
            return (
                <div>
                <Label item={this.props.item} name={this.props.item.getLabel()} />
                {React.DOM.select(attributes,
                    options
                    )}
                </div>
            );
        }
    });
});

<|start_filename|>tests/spec/Stores/auja.spec.js<|end_filename|>
define([
    'jasmine_matchers', 'react', 'jquery', 'fluxxor', 'sugar',
    'build/Stores/auja'
], function () {
    describe('Auja store', function () {

        beforeEach(function () {
            this.addMatchers(require('jasmine_matchers'));
        });

        it('its state should have all keys', function () {

            var Store = require('build/Stores/auja');
            var store = new Store();

            expect(store.getState()).toHaveKeys([
                'title',
                'authenticated',
                'debug',
                'colors',
                'user',
                'buttons',
                'menu',
                'routes',
                'authentication'
            ]);

        });
        
        it('its state should have all colors', function() {

            var Store = require('build/Stores/auja');
            var store = new Store();

            expect(store.getState().colors).toHaveKeys([
                'main',
                'secondary',
                'alert'
            ]);

        });
        
        it('its state should have user', function() {

            var Store = require('build/Stores/auja');
            var store = new Store();

            expect(store.getState().user).toHaveKeys([
                'name'
            ]);
            
        });

        it('to pass the authenticated parameter from a message to the auja state', function () {

            var Store = require('build/Stores/auja');
            var store = new Store();

            expect(store.getState().authenticated).toEqual(false);

            store.message({
                authenticated: true
            });
            expect(store.getState().authenticated).toEqual(true);

        });
    });

});

<|start_filename|>src/Factories/form_item_factory.js<|end_filename|>
/**
 * Menu item factory will create menu item objects based on input
 */
var FormItemObjects = {
    'header': 'build/Objects/Page/Form/header',
    'number': 'build/Objects/Page/Form/number',
    'integer': 'build/Objects/Page/Form/integer',
    'password': 'build/Objects/Page/Form/password',
    'submit': 'build/Objects/Page/Form/submit',
    'text': 'build/Objects/Page/Form/text',
    'textarea': 'build/Objects/Page/Form/textarea',
    'url': 'build/Objects/Page/Form/url',
    'tel': 'build/Objects/Page/Form/tel',
    'color': 'build/Objects/Page/Form/color',
    'time': 'build/Objects/Page/Form/time',
    'checkbox': 'build/Objects/Page/Form/checkbox',
    'email': 'build/Objects/Page/Form/email',
    'selectMultiple': 'build/Objects/Page/Form/select_multiple',
    'select': 'build/Objects/Page/Form/select',
    'selectMultipleCheckbox': 'build/Objects/Page/Form/select_multiple_checkbox',
    'date': 'build/Objects/Page/Form/date',
    'datetime': 'build/Objects/Page/Form/datetime',
    'range': 'build/Objects/Page/Form/range',
    'trumbowyg': 'build/Objects/Page/Form/trumbowyg',
    'tinymce': 'build/Objects/Page/Form/tinymce',
    'file_select': 'build/Objects/Page/Form/file_select',
    'hidden': 'build/Objects/Page/Form/hidden'
};

define([
    'build/Objects/Page/Form/header',
    'build/Objects/Page/Form/number',
    'build/Objects/Page/Form/integer',
    'build/Objects/Page/Form/password',
    'build/Objects/Page/Form/submit',
    'build/Objects/Page/Form/text',
    'build/Objects/Page/Form/textarea',
    'build/Objects/Page/Form/url',
    'build/Objects/Page/Form/tel',
    'build/Objects/Page/Form/color',
    'build/Objects/Page/Form/time',
    'build/Objects/Page/Form/checkbox',
    'build/Objects/Page/Form/email',
    'build/Objects/Page/Form/select_multiple',
    'build/Objects/Page/Form/select',
    'build/Objects/Page/Form/select_multiple_checkbox',
    'build/Objects/Page/Form/date',
    'build/Objects/Page/Form/datetime',
    'build/Objects/Page/Form/range',
    'build/Objects/Page/Form/trumbowyg',
    'build/Objects/Page/Form/tinymce',
    'build/Objects/Page/Form/file_select',
    'build/Objects/Page/Form/hidden'
], function() {

    return new function() {

        /**
         * Create the panel, will do this based on the type passed in the data
         */
        this.createItem = function(data) {
            if(FormItemObjects[data.type]) {
                var Item = require(FormItemObjects[data.type]);
                return new Item(data[data.type]);
            }

            console.error('Unknown item type passed to factory: ' + data.type);

            return false;
        }

    };

});

<|start_filename|>tests/spec/Objects/Page/Form/password.spec.js<|end_filename|>
define(['build/Objects/Page/Form/password'], function (Item) {
    describe('Password form item', function () {

        beforeEach(function () {
            this.addMatchers(require('jasmine_matchers'));
        });

        it('should return corresponding attributes', function () {
            var item = new Item({
                order: 10,
                name: 'thename',
                label: 'The name',
                value: 'James',
                required: true
            });

            expect(item.getAttributes()).toHaveKeys([
                'type',
                'value',
                'name'
            ]);

        });

        it('should implement a form item', function () {

            var item = new Item({
                order: 10,
                name: 'thename',
                label: 'The name',
                value: 'James',
                required: true
            });

            //Text spec of transferring initial data
            expect(item.getType()).toBe('password');
            expect(item.getOrder()).toBe(10);
            expect(item.getName()).toBe('thename');
            expect(item.getLabel()).toBe('The name');
            expect(item.getValue()).toBe('James');
            expect(item.isRequired()).toBe(true);

            //Test spec of setters
            item.setOrder(2);
            item.setName('somename');
            item.setLabel('Your name');
            item.setValue('Charles');
            item.setRequired(false);
            
            expect(item.getOrder()).toBe(2);
            expect(item.getName()).toBe('somename');
            expect(item.getLabel()).toBe('Your name');
            expect(item.getValue()).toBe('Charles');
            expect(item.isRequired()).toBe(false);
            
        });

    });
});


<|start_filename|>src/Factories/menu_item_factory.js<|end_filename|>
/**
 * Menu item factory will create menu item objects based on input
 */
var MenuItemObjects = {
    'link': 'build/Objects/Menu/link',
    'spacer': 'build/Objects/Menu/spacer',
    'resource': 'build/Objects/Menu/resource',
    'sortable_item': 'build/Objects/Menu/sortable_item'
};

define([
    'build/Objects/Menu/link',
    'build/Objects/Menu/spacer',
    'build/Objects/Menu/resource',
    'build/Objects/Menu/sortable_item'
], function() {

    return new function() {

        /**
         * Create the panel, will do this based on the type passed in the data
         */
        this.createItem = function(data) {
            if(MenuItemObjects[data.type]) {
                var Item = require(MenuItemObjects[data.type]);
                return new Item(data[data.type]);
            } else {
                console.error('Unknown menu item type requested: ' + data.type);
            }
            return false;
        }

    };

});

<|start_filename|>tests/spec/Objects/Page/form.spec.js<|end_filename|>
define(['build/Objects/Page/form'], function (Item) {
    describe('Form page item', function () {

        beforeEach(function () {
            this.addMatchers(require('jasmine_matchers'));
        });
        
        it('should implement form methods', function() {


            var item = new Item({});

            //Setting of items
            expect(item.getItems().length).toBe(0);
            item.setItems([
                {
                    type: 'text',
                    text: {
                        //Not needed
                    }
                }    
            ]);
            expect(item.getItems().length).toBe(1);
            
            //Form method
            expect(item.getMethod()).toBe('post');
            item.setMethod('get');
            expect(item.getMethod()).toBe('get');
            
            //Form action
            expect(item.getAction()).toBe(null);
            item.setAction('/users');
            expect(item.getAction()).toBe('/users');
        });
        
        it('should implement a page item', function () {
            
            var item = new Item({});
            
            expect(item.getType()).toBe('form');
            expect(item.getOrder()).toBe(0);
            
            item.setOrder(7);
            
            expect(item.getOrder()).toBe(7);
        });
    });
});


<|start_filename|>src/Components/Panels/Page/Form/file_select.react.js<|end_filename|>
/**
 * A text field, properties:
 *
 * - label
 * - name
 * - .. any other allowed by input
 *
 * @jsx React.DOM
 */
define([
    'react',
    'build/Components/Panels/Page/Form/label.react',
    'jquery.fileupload'
], function (React, Label) {

    var File = React.createClass({
        handleDeleteFile: function () {
            this.props.deleteFileWithRef(this.props.file.ref);
        },
        render: function () {
            var failed = '';
            if (this.props.file != null && this.props.file.failed) {
                failed = <span className="auja-color-alert">failed </span>;
            }
            return <li>
                {this.props.file.name + " "}
                {failed}
                <a onClick={this.handleDeleteFile}>delete</a>
            </li>;
        }
    });

    return React.createClass({
        failedRefId: 0,
        getInitialState: function () {
            return {
                files: this.props.item.getFiles()
            }
        },
        addFailedFile: function (data) {
            this.state.files.push({
                "ref": "failed_" + ++this.failedRefId,
                "failed": true,
                "name": data.files[0].name
            });
            this.setState(this.state);
        },
        componentDidUpdate: function() {
            if(this.props.handleUploaderChange) {
                this.props.handleUploaderChange(this.state.files);
            }
        },
        componentDidMount: function () {
            //Dynamically add the element since we don't want to have React to bind its events to it

            var uploadElem = $('<input type="file" name="file" data-name="file" />');

            if (this.props.item.isMultiple()) {
                uploadElem = $('<input multiple="multiple" type="file" name="file" data-name="file" />');
            }
            var node = $(this.refs.file.getDOMNode()).append(uploadElem);

            node.fileupload({
                url: this.props.item.getTarget(),

                /**
                 * Starting an upload
                 * @param e
                 * @param data
                 */
                send: function (e, data) {
                    if (!this.props.item.isMultiple()) {
                        this.state.files = [];
                        this.setState(this.state);
                    }
                }.bind(this),

                /**
                 * Success
                 * @param e
                 * @param data
                 */
                done: function (e, data) {
                    if (data.result.type == 'file') {
                        this.state.files.push(data.result.file);
                        this.setState(this.state);
                    } else if (data.files[0].name) {
                        this.addFailedFile(data);
                    }
                }.bind(this),

                /**
                 * Failed
                 * @param e
                 * @param data
                 */
                fail: function (e, data) {
                    if (data.files[0].name) {
                        this.addFailedFile(data);
                    }
                }.bind(this)
            });
        },
        /**
         * Hidden input that is submitted
         * @returns {Array}
         */
        getHiddenInput: function () {
            var hidden = [];
            for (var i in this.state.files) {
                if (this.state.files[i] != null && !this.state.files[i].failed) {
                    if (this.props.item.isMultiple) {
                        hidden.push(<input key={this.state.files[i].ref} type="hidden" name={this.props.item.getName()} value={this.state.files[i].ref} />);
                    } else {
                        hidden = [
                            <input key={this.state.files[i].ref} type="hidden" name={this.props.item.getName()} value={this.state.files[i].ref} />
                        ];
                    }
                }
            }
            return hidden;
        },
        deleteFileWithRef: function (ref) {
            this.state.files = this.state.files.remove(function (file) {
                return file.ref == ref;
            });
            this.setState(this.state);
        },
        getFiles: function () {
            return this.state.files.map(function (file) {
                return <File deleteFileWithRef={this.deleteFileWithRef} file={file} />;
            }.bind(this));
        }, render: function () {
            var hidden = this.getHiddenInput();
            var files = this.getFiles();

            return (
                <div>
                    <Label item={this.props.item} name={this.props.item.getLabel()} />
                    <span ref="file"></span>
                    <ul>{files}</ul>
                    {hidden}
                </div>
            );
        }
    });

});

<|start_filename|>src/Objects/page.js<|end_filename|>
/**
 * Page panel type
 * 
 * @todo implement sorting
 */
define(['build/Objects/Abstract/panel', 'build/Factories/page_item_factory'], function(Panel, PageItemFactory) {

    var Page = function() {
        
        //Call the parent constructor
        Panel.call(this);
        
        //Set the type
        this.setType('page');
        
        /**
         * Content of a page
         * @type {Array}
         */
        this.content = [];

        /**
         * Set the content of a page
         */
        this.setContent = function(content) {
            this.content = content.map(function(item) {
                return PageItemFactory.createItem(item);
            });
        };

        /**
         * Getter for the content
         * @returns {Array}
         */
        this.getContent = function() {
            return this.content;
        };
        
    };

    // Inherit Panel
    Page.prototype = Panel;

    // Fix constructor
    Page.prototype.constructor = Page;

    return Page;
});

<|start_filename|>src/Objects/Menu/sortable_item.js<|end_filename|>
define(['build/Objects/Abstract/menu_item'], function (MenuItem) {

    var SortableItem = function (data) {

        //Call the parent constructor
        MenuItem.call(this, arguments);

        /**
         * Our custom type
         * @type {string}
         */
        this.type = 'sortable_item';

        /**
         * Target of this link
         * @type {string|boolean}
         */
        this.target = data.target || false;

        /**
         * Id, this also will be posted back to the server
         *
         * @type integer
         */
        this.id = data.id;

        /**
         * Text
         * @type {string}
         */
        this.text = data.text || 'NULL';

        /**
         * Left
         *
         * @type {integer|boolean}
         */
        this.left = data.left || false;

        /**
         * Right
         * 
         * @type {integer|boolean}
         */
        this.right = data.right || false;

        /**
         * Getter for the id
         * @returns string
         * @override
         */
        this.getId = function () {
            return this.id;
        };

        /**
         * Setter for target
         * @param target
         */
        this.setTarget = function (target) {
            this.target = target;
        };

        /**
         * Getter for target
         * @returns {string|boolean}
         */
        this.getTarget = function () {
            return this.target;
        };

        /**
         * Setter for text
         * @param text
         */
        this.setText = function (text) {
            this.text = text;
        };

        /**
         * Getter for text
         * @returns {string}
         */
        this.getText = function () {
            return this.text;
        };

        /**
         * Setter for left
         * @param left
         */
        this.setLeft = function(left) {
            this.left = left;
        };

        /**
         * Getter for left
         * @return {integer|boolean}
         */
        this.getLeft = function() {
            return this.left;
        };

        /**
         * Setter for right
         * @param right
         */
        this.setRight = function(right) {
            this.right = right;
        };

        /**
         * Getter for right
         * @return {integer|boolean}
         */
        this.getRight = function() {
            return this.right;
        };

        /**
         * Update this Link with another Link
         * @param item
         */
        this.update = function (item) {
            this.setText(item.getText());
            this.setTarget(item.getTarget());
            this.setLeft(item.getLeft());
            this.setRight(item.getRight());
        };
    };

    // Inherit Panel
    SortableItem.prototype = MenuItem;

    // Fix constructor
    SortableItem.prototype.constructor = SortableItem;
    
    return SortableItem;
});

<|start_filename|>src/Factories/page_item_factory.js<|end_filename|>
/**
 * Menu item factory will create menu item objects based on input
 */
var PageItemObjects = {
    'header': 'build/Objects/Page/header',
    'form': 'build/Objects/Page/form'
};

define([
    'build/Objects/Page/header',
    'build/Objects/Page/form'
], function() {

    return new function() {

        /**
         * Create the panel, will do this based on the type passed in the data
         */
        this.createItem = function(data) {
            if(PageItemObjects[data.type]) {
                var Item = require(PageItemObjects[data.type]);
                return new Item(data[data.type]);
            } else {
                console.error('Invalid page type requested: ' + data.type);
            }
            return false;
        }

    };

});

<|start_filename|>src/Components/Panels/Page/Form/checkbox.react.js<|end_filename|>
/**
 * A checkbox field, properties:
 *
 * - label
 * - name
 * - .. any other allowed by input
 * @jsx React.DOM
 */
 define(['react', 'build/Components/Panels/Page/Form/label.react'], function(React, Label) {
    return React.createClass({
        getInitialState: function() {
            return {checked: this.props.item.isChecked()}   
        },
        handleChange: function(event) {
            this.setState({checked: event.target.checked});
        },
        render: function () {
            var attributes = this.props.item.getAttributes();
            attributes.checked = this.state.checked;
            attributes.onChange = this.handleChange;
            
            //Add a fallback to make sure something (although empty) is sent to the server
            var fallback = '';
            if(this.props.item.hasFallback()) {
                fallback = <input type="hidden" name={this.props.item.getName()} value="0"/>;
            }
            
            return (
                <div>
                    <Label item={this.props.item} name={this.props.item.getLabel()} />
                    {fallback}
                    {React.DOM.input(attributes)}
                </div>
            );
        }
    });
});

<|start_filename|>src/Objects/Page/Form/select_multiple_checkbox.js<|end_filename|>

define(['build/Objects/Abstract/form_item', 'build/Objects/Page/Form/checkbox'], function(FormItem, Checkbox) {

    var SelectMultipleCheckbox = function(data) {

        //Call the parent constructor
        FormItem.call(this, data);

        //Set type of this object
        this.setType('selectMultipleCheckbox');

        /**
         * The Options of SelectMultipleCheckbox
         * @type {array|null}
         * @private
         */
        this._options = data.options || [];

        
        /**
         * Getter for Options
         * @returns {array|null}
         */
        this.getOptions = function() {
            return this._options;
        };

               
        /**
         * Setter for Options
         * @param SelectMultipleCheckbox
         */
         this.setOptions = function(options) {
            if(options) {
                //Initialize the options as an array of Checkbox-es
                this._options = options.map(function(checkbox) {
                    checkbox.name = this.getName();
                    checkbox.value = this.getValue();
                    checkbox.fallback = false;
                    return new Checkbox(checkbox);
                }.bind(this));                
            } 
            return this._options;         
        };

          
        /**
         * Get attributes for this input
         * @return Object
         */
        this.getAttributes = function() {
            return {
                type: this.getType(),
                value: this.getValue(),
                name: this.getName(),
                options: this.getOptions(),
                }
        };

        this.setOptions(data.options);

    };

    // Inherit FormItem
    SelectMultipleCheckbox.prototype = FormItem;

    // Fix constructor
    SelectMultipleCheckbox.prototype.constructor = SelectMultipleCheckbox;
    
    return SelectMultipleCheckbox;
});

<|start_filename|>src/Objects/Menu/spacer.js<|end_filename|>

define(['build/Objects/Abstract/menu_item'], function(MenuItem) {

    var Spacer = function(data) {

        //Call the parent constructor
        MenuItem.call(this, arguments);

        /**
         * Our custom type
         * @type {string}
         */
        this.type = 'spacer';

        /**
         * Text
         * @type {string}
         */
        this.text = data.text || 'NULL';
        
        /**
         * Setter for text
         * @param text
         */
        this.setText = function(text) {
            this.text = text;
        };

        /**
         * Getter for text
         * @returns {string}
         */
        this.getText = function() {
            return this.text;
        };

        /**
         * Update this item
         * @param item
         */
        this.update = function(item) {
            this.setText(item.getText());
        }
    };

    // Inherit Panel
    Spacer.prototype = MenuItem;

    // Fix constructor
    Spacer.prototype.constructor = Spacer;
    
    return Spacer;
});

<|start_filename|>src/Components/Panels/Page/Form/label.react.js<|end_filename|>
/**
 * A label as in <label>, properties:
 *
 * - name
 * - item
 *
 * @todo Add validation
 *
 * @jsx React.DOM
 */

define(['react'], function (React) {
    return React.createClass({
        render: function () {
            
            //Extract the validation message
            var validation = '';
            if(this.props.item.validationMessage != null) {
                validation = (
                    <span className="validation-message auja-color-alert">{this.props.item.validationMessage}</span>
                    );
            }
            
            return (
                <label>
                <span>{this.props.name}</span>
                {validation}
                </label>
                );
        }
    });

});

<|start_filename|>src/Objects/Page/Form/trumbowyg.js<|end_filename|>

define(['build/Objects/Abstract/form_item'], function(FormItem) {

    var Trumbowyg = function(data) {

        //Call the parent constructor
        FormItem.call(this, data);

        //Set type of this object
        this.setType('trumbowyg');

        /**
         * Buttons for the editor
         * @type {string[]}
         */
        this.buttons = data.buttons || ['formatting', 'bold', 'italic', '|', 'unorderedList', 'orderedList', '|', 'insertImage', 'link', '|', 'viewHTML', 'fullscreen'];

        /**
         * Get attributes for this input
         * @return Object
         */
        this.getAttributes = function() {
            return {
                type: this.getType(),
                value: this.getValue(),
                name: this.getName()
            }
        };

        /**
         * Setter of buttons
         * @param buttons
         */
        this.setButtons = function(buttons) {
            this.buttons = buttons;
        };

        /**
         * Getter for buttons
         */
        this.getButtons = function() {
            return this.buttons;
        };

    };

    // Inherit Panel
    Trumbowyg.prototype = FormItem;

    // Fix constructor
    Trumbowyg.prototype.constructor = Trumbowyg;

    return Trumbowyg;
});

<|start_filename|>tests/spec/Components/Panels/Page/Form/checkbox.react.spec.js<|end_filename|>
/** @jsx React.DOM */

define([
    'react',
    'build/Components/Panels/Page/Form/checkbox.react',
    'build/Objects/Page/Form/checkbox',
    'jasmine_matchers'
], function (React, Checkbox, Item) {

    describe('Checkbox form input', function () {

        beforeEach(function () {
            this.addMatchers(require('jasmine_matchers'));
        });

        it('should display its value', function () {
            var TestUtils = React.addons.TestUtils;

            var item = new Item({
                checked: true
            });

            // Render a checkbox with label in the document
            var text = TestUtils.renderIntoDocument(Checkbox({
                item: item
            }));

            var input = TestUtils.scryRenderedDOMComponentsWithTag(text, 'input');

                //Check the the fallback field
                expect(input[0].getDOMNode().type).toBe('hidden');
                expect(input[0].getDOMNode().value).toBe('0');

                //Check the checked state of the visible checkbox
                expect(input[1].getDOMNode().checked).toBe(true);
        });

        it('should have a label', function () {
            var TestUtils = React.addons.TestUtils;

            var item = new Item({
                checked: true,
                label: "This is the label"
            });

            // Render a checkbox with label in the document
            var text = TestUtils.renderIntoDocument(Checkbox({
                item: item
            }));

            var label = TestUtils.findRenderedDOMComponentWithTag(text, 'label');
            expect(label.getDOMNode().textContent).toEqual('This is the label');
        });
    });
});

<|start_filename|>src/Components/Panels/Page/Form/trumbowyg.react.js<|end_filename|>
/**
 * A trumbowyg RTE, properties:
 *
 * - label
 * - name
 * - value will be entered as value
 * - .. any other allowed by input
 *
 * @jsx React.DOM
 */
define(['react', 'build/Components/Panels/Page/Form/label.react', 'trumbowyg'], function(React, Label) {
    return React.createClass({
        componentDidMount: function() {
            var btnsGrps = {
                design: this.props.item.getButtons()
            };            
            
            $(this.refs.textarea.getDOMNode()).trumbowyg({
                btns: this.props.item.getButtons(),
                btnsGrps: btnsGrps
            });
        },
        render: function() {
            var attributes = this.props.item.getAttributes();
            
            Object.merge(attributes, {
                id: this.props.itemId,
                type: 'textarea',
                ref: 'textarea'
            });
            
            return (
                <div>
                    <Label item={this.props.item} name={this.props.item.getLabel()} />
                    {React.DOM.textarea(attributes, this.props.item.getValue())}
                </div>
                );
        }
    });

});

<|start_filename|>tests/spec/Objects/Menu/link.spec.js<|end_filename|>
define(['build/Objects/Menu/link'], function (Item) {
    describe('Link menu item', function () {

        beforeEach(function () {
            this.addMatchers(require('jasmine_matchers'));
        });

        it('should use its target as an ID', function () {

            var item = new Item({
                target: '/users'
            });

            expect(item.getTarget()).toBe('/users');
            expect(item.getId()).toBe(item.getTarget());
        });

        it('should implement link item specific methods', function () {

            var item = new Item({
                icon: 'face',
                target: '/users',
                text: 'Howdy'
            });

            expect(item.getIcon()).toBe('face');
            expect(item.getTarget()).toBe('/users');
            expect(item.getText()).toBe('Howdy');
            
            item.setIcon('factory');
            item.setTarget('/companies');
            item.setText('Label305');

            expect(item.getIcon()).toBe('factory');
            expect(item.getTarget()).toBe('/companies');
            expect(item.getText()).toBe('Label305');
        });

        it('should implement an update method which transfers properties', function () {
            var item = new Item({
                icon: 'face',
                target: '/users',
                text: 'Howdy'
            });

            expect(item.getIcon()).toBe('face');
            expect(item.getTarget()).toBe('/users');
            expect(item.getText()).toBe('Howdy');

            var updateItem = new Item({
                icon: 'factory',
                target: '/companies',
                text: 'Label305'
            });            
            item.update(updateItem);

            expect(item.getIcon()).toBe('factory');
            expect(item.getTarget()).toBe('/companies');
            expect(item.getText()).toBe('Label305');
        });

        it('should implement a menu item', function () {

            var item = new Item({});

            item.setOrder(72);
            item.setIsActive(true);

            expect(item.getType()).toBe('link');
            expect(item.getOrder()).toBe(72);
            expect(item.isActive()).toBe(true);
        });
    });
});


<|start_filename|>src/Components/Scaffolding/panels.react.js<|end_filename|>
/**
 * Panels
 *
 * @jsx React.DOM
 */

//Listing of all supported panels
var PanelTypes = {
    'menu': 'build/Components/Panels/menu.react',
    'page': 'build/Components/Panels/page.react'
};

//Map as an array to load panel dependencies
define([
    'react',
    'fluxxor',
    'flux',
    'build/Components/Panels/menu.react',
    'build/Components/Panels/page.react'
], function (React, Fluxxor, flux) {
    
    var PanelSection = React.createClass({
        handleScroll: function () {
            flux.actions.onPanelScroll(this.props.panel);
        },
        render: function () {
            var Panel = require(PanelTypes[this.props.panel.getType()]);
            
            return (
                <section id={this.props.panel.getId()} key={this.props.panel.getId()} ref="panel" className={"animated fadeInLeft panel panel-" + this.props.panel.getType()}>
                    <div onScroll={this.handleScroll} style={this.props.style}>
                        <Panel flux={this.props.flux} message={this.props.message} panel={this.props.panel} />
                    </div>
                </section>
            );
        }
    });

    /**
     * Main content with all panels
     */
    return React.createClass({
        mixins: [Fluxxor.FluxMixin(React), Fluxxor.StoreWatchMixin('PanelStore', 'MessageStore')],
        getStateFromFlux: function () {
            return flux.store('PanelStore').getState();
        },

        /**
         * After addition/removal will animate scrollLeft, this is done by listening to DOMNode events
         * instead of componentDidUpdate since it triggers too late
         */        
        componentDidMount: function() {
            $(this.refs.panels.getDOMNode()).bind('DOMNodeInserted DOMNodeRemoved', function() {
                var b = $('body');
                if(b[0].scrollLeft != (b[0].scrollWidth - window.innerWidth)) {
                    b.animate({
                        scrollLeft: b[0].scrollWidth - window.innerWidth
                    }, 300);
                }
            });
        },

        /**
         * Render the div with all panels
         * @returns {XML}
         */
        render: function () {

            var message = flux.store('MessageStore').getMessage();
            
            //Fetch and wrap all panels in a section having the class "panel panel-{type}"
            var panels = this.state.panels.map(function (panel) {
                var style = {
                    height: this.state.height
                };

                //When the current message is destined for this panel pass it, otherwise just an empty panel
                var m = {};
                if (message.origin && message.origin.id == panel.id) {
                    m = message.message;
                }
                
                return (<PanelSection key={panel.getIndex()} flux={this.props.flux} panel={panel} message={m} style={style} />);
            }.bind(this));
            
            return (
                <div id="panels" ref="panels">
                    <div>
                        {panels}
                    </div>
                </div>
            );
        }
    });

});

<|start_filename|>src/Components/Panels/Page/button.react.js<|end_filename|>
/**
 * A button
 *
 * - text
 * - target
 * - confirm
 *
 * @jsx React.DOM
 */

define(['react'], function(React) {
    return React.createClass({
        getInitialState: function() {
            return {
                confirming: false  
            };  
        },
        handleClick: function() {
            if(this.props.button.confirm && !this.state.confirming) {
                this.state.confirming = true;
                this.setState(this.state);
                setTimeout(function() {
                    this.state.confirming = false;
                    this.setState(this.state);
                }.bind(this), 1000);
            } else {
                flux.actions.click(this.props.button.target, this.props.panel);   
            }            
        },
        render: function() {
            var className = "button ";
            className += this.props.button.confirm ? "auja-bg-alert" : "auja-bg-main";
            
            if(this.state.confirming) {
                return (
                    <a className={className} onClick={this.handleClick}>{this.props.button.confirm}</a>
                    );
            }
            
            return (
                <a className={className} onClick={this.handleClick}>{this.props.button.text}</a>
                );
        }
    });

});

<|start_filename|>src/Components/Scaffolding/header.react.js<|end_filename|>
/**
 * @jsx React.DOM
 */
define(['react'], function (React) {

    return React.createClass({
        render: function () {
            //Name of the user
            var user = '';
            if (this.props.auja.user) {
                user = (
                    <div className="auja-color-main"  id="user">{this.props.auja.user.name}</div>
                    );
            }

            //Buttons, e.g. logout
            var buttons = '';
            if (this.props.auja.buttons) {
                buttons = this.props.auja.buttons.map(function (button) {
                    return (
                        <a className="auja-bg-main button" key={button.target} href={button.target}>{button.text}</a>
                        );
                });
            }
            return (
                <header>
                    <h1>{this.props.auja.title}</h1>
                    <div id="buttons">{buttons}</div>
                    {user}
                </header>
                );

        }
    });

});
                        

<|start_filename|>tests/spec/Components/Panels/Page/Form/email.react.spec.js<|end_filename|>
/** @jsx React.DOM */

define([
    'react',
    'build/Components/Panels/Page/Form/email.react',
    'build/Objects/Page/Form/email',
    'jasmine_matchers'
], function (React, Email, Item) {

    describe('Email form input', function () {

        beforeEach(function () {
            this.addMatchers(require('jasmine_matchers'));
        });

        it('should display its value', function () {
            var TestUtils = React.addons.TestUtils;

            var item = new Item({
                value: "<EMAIL>"
            });

            // Render a checkbox with label in the document
            var text = TestUtils.renderIntoDocument(Email({
                item: item
            }));

            var input = TestUtils.findRenderedDOMComponentWithTag(text, 'input');
            expect(input.getDOMNode().value).toEqual('<EMAIL>');
        });

        it('should have a label', function () {
            var TestUtils = React.addons.TestUtils;

            var item = new Item({
                value: "<EMAIL>",
                label: "This is the label"
            });

            // Render a checkbox with label in the document
            var text = TestUtils.renderIntoDocument(Email({
                item: item
            }));

            var label = TestUtils.findRenderedDOMComponentWithTag(text, 'label');
            expect(label.getDOMNode().textContent).toEqual('This is the label');
        });
    });
});

<|start_filename|>src/Objects/Page/Form/text.js<|end_filename|>

define(['build/Objects/Abstract/form_item'], function(FormItem) {

    var Text = function(data) {

        //Call the parent constructor
        FormItem.call(this, data);

        //Set type of this object
        this.setType('text');

        /**
         * Max length of the text 
         * @type {Number|null}
         * @private
         */
        this._maxLength = data.maxLength || null;

        /**
         * Getter for maxLength
         * @returns {Number|null}
         */
        this.getMaxLength = function() {
            return this._maxLength;
        };

        /**
         * Setter for maxLength
         * @param maxLength
         */
        this.setMaxLength = function(maxLength) {
            this._maxLength = maxLength;
        };
        
        /**
         * Get attributes for this input
         * @return Object
         */
        this.getAttributes = function() {
            return {
                type: this.getType(),
                value: this.getValue(),
                name: this.getName(),
                maxLength: this.getMaxLength()
            }
        };
    };

    // Inherit FormItem
    Text.prototype = FormItem;

    // Fix constructor
    Text.prototype.constructor = Text;
    
    return Text;
});

<|start_filename|>src/Stores/message.js<|end_filename|>
define(['fluxxor'], function(Fluxxor) {

    /**
     * The pages store
     */
    return Fluxxor.createStore({

        /**
         * All pages currently in view
         */
        message: {},

        /**
         * On initialization and on system update we will update the state
         * @param url
         */
        initialize: function(url) {
            this.bindActions(
                'message', this.dispatch
            )
        },

        /**
         * Getter for the latest message
         * @returns {*}
         */
        getMessage: function() {
            return this.message;
        },

        /**
         * Reset
         */
        reset: function() {
            this.message = {
                message: null
            };
            this.emit('change');
        },

        /**
         * Dispatching of a message
         * @param message
         */
        dispatch: function(message) {
            this.message = message;
            this.emit('change');
        }

    })

});

<|start_filename|>src/Factories/resource_property_factory.js<|end_filename|>
/**
 * Resource property factory will create objects from resource item properties
 */
var ResourceItemProperties = {
    'searchable': 'build/Objects/Menu/Properties/searchable',
    'sortable':  'build/Objects/Menu/Properties/sortable'
};
define([
    'build/Objects/Menu/Properties/searchable',
    'build/Objects/Menu/Properties/sortable'
], function () {

    return new function () {

        /**
         * Create the resource item properties
         */
        this.createProperties = function (data) {
            var result = [];
            for(var name in data) {
                if(ResourceItemProperties[name]) {
                    var propertyObject = require(ResourceItemProperties[name]);
                    result.push(new propertyObject(data[name]));
                } else {
                    console.error('Unknown resource item property requested: ' + name);
                }
            }
            return result;
        };

    };

});

<|start_filename|>src/Objects/Page/header.js<|end_filename|>

define(['build/Objects/Abstract/page_item'], function(PageItem) {

    var Header = function(data) {

        //Call the parent constructor
        PageItem.call(this, arguments);

        /**
         * Our custom type
         * @type {string}
         */
        this.type = 'header';

        /**
         * Text
         * @type {string}
         */
        this.text = data.text || '';

        /**
         * Buttons
         * @type {array}
         */
        this.buttons = data.buttons || [];

        /**
         * Setter for text
         * @param text
         */
        this.setText = function(text) {
            this.text = text;
        };

        /**
         * Getter for text
         * @returns {string}
         */
        this.getText = function() {
            return this.text;
        };

        /**
         * Setter for buttons
         * @param buttons
         */
        this.setButtons = function(buttons) {
            this.buttons = buttons;
        };

        /**
         * Getter for buttons
         * @returns {array}
         */
        this.getButtons = function() {
            return this.buttons;
        };

    };

    // Inherit Panel
    Header.prototype = PageItem;

    // Fix constructor
    Header.prototype.constructor = Header;
    
    return Header;
});

<|start_filename|>src/Requests/Routers/http.js<|end_filename|>
/**
 * REST router, will add rest routes to crossroads
 */
define(['build/Requests/Handlers/http'], function() {

    return {

        /**
         * Add a route
         * @param route
         */
        addRoute: function(route) {
            crossroads.addRoute(route.target).matched.add(function (url, setHandler) {
                setHandler(HttpRequest, route);
            });
        }
    };
});

<|start_filename|>src/Factories/menu_factory.js<|end_filename|>
/**
 * Menu factory will create menu objects based on input
 *
 * @todo implement sorting
 */
define(['build/Objects/menu'], function (Menu) {

    return new function () {

        /**
         * Create the menu
         */
        this.createMenu = function (data) {
            var menu = new Menu();
            menu.setItems(data.menu);
            return menu;
        };

        /**
         * Update contents of a menu
         * @param menu
         * @param data
         */
        this.updateMenu = function (menu, data) {
            //Use a mock menu to be able to match id's and see which have disappeared
            var oldItems = menu.getItems();
            var items = this.createMenu(data).getItems().map(function(item) {
                for(var i in oldItems) {
                    //If item implements update method call it otherwise create the newly created item
                    if(oldItems[i].getId() == item.getId()) {
                        if(!oldItems[i].update) {
                            console.error('Menu item does not implement update method');
                            return item;
                        } else {
                            oldItems[i].update(item);
                            return oldItems[i];
                        }
                    }
                }
                return item;
            });
            
            menu.setItems(items);
            return menu;
        }

    };

});

<|start_filename|>tests/spec/Components/Panels/Page/Form/header.react.spec.js<|end_filename|>
/** @jsx React.DOM */

define([
    'react',
    'build/Components/Panels/Page/header.react',
    'build/Objects/Page/Form/header',
    'jasmine_matchers'
], function (React, Header, Item) {

    describe('Header form input', function () {

        beforeEach(function () {
            this.addMatchers(require('jasmine_matchers'));
        });

        it('should display the title', function () {
            var TestUtils = React.addons.TestUtils;

            var item = new Item({
                text: "Moi title"
            });

            // Render a checkbox with label in the document
            var header = TestUtils.renderIntoDocument(Header({
                item: item
            }));

            var h2 = TestUtils.findRenderedDOMComponentWithTag(header, 'h2');
            expect(h2.getDOMNode().textContent).toEqual('Moi title');
        });
    });
});

<|start_filename|>src/Components/Scaffolding/body.react.js<|end_filename|>
/**
 * @jsx React.DOM
 */
define([
    'react',
    'build/Components/Scaffolding/menu.react',
    'build/Components/Scaffolding/panels.react'
], function(React, Menu, Panels) {

    return React.createClass({
        render: function() {
            return (
                <section id="content">
                    <Menu auja={this.props.auja} />
                    <Panels flux={this.props.flux} />
                </section>
                );
        }
    });

});

<|start_filename|>tests/spec/Components/Panels/page.react.spec.js<|end_filename|>
/** @jsx React.DOM */

define([
    'react',
    'build/Components/Panels/page.react',
    'build/Objects/page',
    'jasmine_matchers'
], function (React, Page, PageObject) {

    describe('Page', function () {

        beforeEach(function () {
            this.addMatchers(require('jasmine_matchers'));
        });

        it('should be able to render a form', function () {
            var TestUtils = React.addons.TestUtils;

            var page = new PageObject({});
            page.setId(1);
            page.setContent([
                {
                    "type": "form",
                    "form": {
                        "action": "example/clubs/store",
                        "method": "post",
                        "items": [
                            {
                                "type": "text",
                                "text": {
                                    "name": "name",
                                    "label": "Name of club",
                                    "value": "Some club"
                                }
                            }
                        ]
                    }
                }
            ]);

            // Render a checkbox with label in the document
            var page = TestUtils.renderIntoDocument(Page({
                message: null,
                panel: page
            }));

            var tag = TestUtils.findRenderedDOMComponentWithTag(page, 'form');

            //Url will be absolute
            expect(tag.getDOMNode().action).toContain('example/clubs/store');
            expect(tag.getDOMNode().method).toContain('post');

            var input = TestUtils.findRenderedDOMComponentWithTag(tag, 'input');
            expect(input.getDOMNode().value).toEqual('Some club');
        });

    });
});

<|start_filename|>Gruntfile.js<|end_filename|>
module.exports = function(grunt) {
    grunt.initConfig({
        sass: {
            dist: {
                files: {
                    'assets/css/auja.css': 'assets/sass/auja.sass'
                }
            }  
        },
        react: {
            dynamic_mappings: {
                files: [
                    {
                        expand: true,
                        cwd: './src',
                        src: ['**/*.js'],
                        dest: './build'
                    }
                ]
            }
        },
        requirejs: {
            compileclosure: {
                options: {    //Base from which the project is looked at
                    baseUrl: '.',
                    //Config file also used by production
                    mainConfigFile: 'build/auja.react.js',

                    //Licence references can be found in READMEs
                    preserveLicenseComments: false,

                    //Let r.js search through all files
                    findNestedDependencies: true,

                    //Include
                    include: [
                        'bower_components/requirejs/require.js',
                        'build/auja.react.js'
                    ],
                    
                    //Output file
                    out: "dist/auja.min.js"
                }
            },
            compile: {
                options: {    //Base from which the project is looked at
                    baseUrl: '.',
                    
                    optimize: 'none',
                    
                    //Config file also used by production
                    mainConfigFile: 'build/auja.react.js',

                    //Licence references can be found in READMEs
                    preserveLicenseComments: false,

                    //Let r.js search through all files
                    findNestedDependencies: true,

                    //Include
                    include: [
                        'bower_components/requirejs/require.js',
                        'build/auja.react.js'
                    ],

                    "paths": {
                        "react": "empty:",
                        "jquery": "empty:",
                        "fluxxor": "empty:",
                        "crossroads.js": "empty:",
                        "js-signals": "empty:",
                        "sugar": "empty:",
                        "Ionicons": "empty:",
                        "trumbowyg": "empty:",
                        "animate.css": "empty:"
                    },

                    //Output file
                    out: "dist/auja.js"
                }
            }
        }
    });
    grunt.loadNpmTasks('grunt-react');
    grunt.loadNpmTasks('grunt-contrib-requirejs');
    grunt.loadNpmTasks('grunt-contrib-sass');
    
    grunt.registerTask('test', ['react', 'sass']);
    grunt.registerTask('default', ['react', 'sass']);
    grunt.registerTask('release', ['react', 'requirejs', 'sass']);
};

<|start_filename|>src/Objects/Abstract/menu_item.js<|end_filename|>
/**
 * Menu item definition
 */
define([], function () {

    return function () {

        /**
         * Location of menu item
         * @type {integer}
         */
        this.order = 0;

        /**
         * Type of the menu item
         * @type {string}
         */
        this.type = 'unknown';

        /**
         * ID
         * @type {mixed}
         */
        this.id = 0;

        /**
         * Weither or not the item is active
         * @type {boolean}
         */
        this.active = false;

        /**
         * Setter for the id
         * @param id
         */
        this.setId = function (id) {
            this.id = id;
        };

        /**
         * Getter for the id
         * @returns {id|*}
         */
        this.getId = function () {
            return this.id;
        };

        /**
         * Setter for the order
         * @param order
         */
        this.setOrder = function (order) {
            this.order = order;
        };

        /**
         * Getter for the order
         * @returns integer
         */
        this.getOrder = function () {
            return this.order;
        };

        /**
         * Setter for the type
         * @param type
         */
        this.setType = function (type) {
            this.type = type;
        };

        /**
         * Getter for the type
         * @returns {type|*}
         */
        this.getType = function () {
            return this.type;
        };

        /**
         * Getter for active
         * @return {boolean}
         */
        this.isActive = function () {
            return this.active;
        };

        /**
         * Setter for active
         * @param active
         */
        this.setIsActive = function(active) {
            this.active = active;
        }
    };

});

<|start_filename|>src/Objects/Page/Form/time.js<|end_filename|>

define(['build/Objects/Abstract/form_item'], function(FormItem) {

    var Time = function(data) {

        //Call the parent constructor
        FormItem.call(this, data);

        //Set type of this object
        this.setType('time');
        /**
         * The format the date
         * @type {string|null}
         * @private
         */
        this._format = data.format || 'HH:mm:ss';

        /**
         * Getter for format
         * @returns {string|null}
         */
        this.getFormat = function() {
            return this._format;
        };

        /**
         * Setter for format
         * @param format
         */
        this.setFormat = function(format) {
            this._format = format;
        };

        /**
         * Get attributes for this input
         * @return Object
         */
        this.getAttributes = function() {
            return {
                type: this.getType(),
                value: this.getValue(),
                name: this.getName(),
                format: this.getFormat()
            }
        };
    };

    // Inherit Panel
    Time.prototype = FormItem;

    // Fix constructor
    Time.prototype.constructor = Time;

    return Time;
});

<|start_filename|>tests/spec/Objects/Page/Form/select_multiple_checkbox.spec.js<|end_filename|>
define(['build/Objects/Page/Form/select_multiple_checkbox'], function (Item) {
    describe('SelectMultipleCheckbox form item', function () {

        beforeEach(function () {
            this.addMatchers(require('jasmine_matchers'));
        });

        it('should return corresponding attributes', function () {
            var item = new Item({
                order: 10,
                name: 'thename',
                label: '<NAME>',
                options: [
                    {
                     label: 'Jupiler',
                     checked: false
                    },
                    {
                    label: 'Grolsch',
                    checked: true
                    },
                ],
                required: true
            });

            expect(item.getAttributes()).toHaveKeys([
                'type',
                'value',
                'name',
                'options'
            ]);

        });

        it('should implement a form item', function () {

            var item = new Item({
                order: 10,
                name: 'thename',
                label: '<NAME>',
                options: [
                    {
                     label: 'Jupiler',
                     checked: false
                    },
                    {
                    label: 'Grolsch',
                    checked: true
                    },
                ],
                required: true
            });

            //Text spec of transferring initial data
            expect(item.getType()).toBe('selectMultipleCheckbox');
            expect(item.getOrder()).toBe(10);
            expect(item.getName()).toBe('thename');
            expect(item.getLabel()).toBe('The name');
            expect(item.getOptions().length).toBe(2);
            expect(item.isRequired()).toBe(true);

            //Test spec of setters
            item.setOrder(2);
            item.setName('somename');
            item.setLabel('Your name');
            item.setOptions([
                    {
                     label: 'Jupiler',
                     checked: false
                    }                    
                ]);
            item.setRequired(false);
            
            expect(item.getOrder()).toBe(2);
            expect(item.getName()).toBe('somename');
            expect(item.getLabel()).toBe('Your name');
            expect(item.getOptions().length).toBe(1);
            expect(item.isRequired()).toBe(false);
            
        });

    });
});


<|start_filename|>tests/spec/matchers.js<|end_filename|>
define([], function () {
    return {
        /**
         * Check if required keys are present
         * @param keys
         * @returns {boolean}
         */
        toHaveKeys: function (keys) {
            
            //Check missing keys
            for (var i in keys) {
                var flag = false;

                for (var key in this.actual) {
                    if (key == keys[i]) {
                        flag = true;
                    }
                }

                if (!flag) {
                    this.message = function() {
                        return 'Key missing: ' + key;  
                    };
                    return false;
                }
            }
            
            //Check not specified keys
            for (var key in this.actual) {
                var flag = false;

                for (var i in keys) {
                    if (key == keys[i]) {
                        flag = true;
                    }
                }

                if (!flag) {
                    this.message = function () {
                        return 'Key not defined in spec: ' + key;
                    };
                    return false;
                }
            }
            

            return true;
        },

        /**
         * Match if type is object
         */
        toBeAnObject: function() {
            return typeof this.actual == 'object';
        },

        /**
         * Match if type is an array
         */
        toBeAnArray: function() {
            return this.actual instanceof Array;
        },

        /**
         * Match if type is an integer
         */
        toBeAnInteger: function() {
            return parseInt(this.actual) == this.actual;
        }
    }
});


<|start_filename|>src/Components/Panels/Menu/Mixins/searchable.mixin.js<|end_filename|>
/**
 * @jsx React.DOM
 */

define(['react'], function(React) {
   
    return {
        /**
         * Current query
         */
        query: '',

        /**
         * Original source of the menu
         */
        originalSource: null,

        /**
         * Reference to the searchable property
         */
        searchableProperty: null,

        /**
         * Store the original source just before mounting
         */
        componentWillMount: function() {
            this.originalSource = this.props.item.getTarget();  
            this.searchableProperty = this.props.item.getProperty('searchable');
        },

        /**
         * Handle searching
         * @param e
         */
        handleSearch: function(e) {
            this.query = e.target.value;
            
            var target = this.originalSource;
            if(this.query != '') {
                //Get target, replace %s with query and escape it so we have a nice url
                target = this.searchableProperty.getTarget().replace('%s', this.query.escapeURL(true));
            }

            flux.actions.updateResource(this.props.item, target);
        },
        
        /**
         * Fetch the form used for searching, when the property was not attached it will return an empty string
         * @return {*}
         */
        getSearchableForm: function() {
            if(!this.props.item.hasProperty('searchable')) {
                return '';
            }
            return (
                <input type="text" onChange={this.handleSearch} placeholder="Search.." />  
            );
        }
    }
    
});

<|start_filename|>src/Objects/Page/form.js<|end_filename|>

define(['build/Objects/Abstract/page_item', 'build/Factories/form_item_factory'], function(PageItem, FormItemFactory) {

    var Form = function(data) {

        //Call the parent constructor
        PageItem.call(this, arguments);

        /**
         * Our custom type
         * @type {string}
         */
        this.type = 'form';

        /**
         * Form items, is set during construct to make sure we use
         * the FormItemsFactory
         * @type {Array}
         */
        this.items = [];

        /**
         * Method
         * @type {string}
         */
        this.method = data.method || 'post';

        /**
         * Action
         * @type {string}
         */
        this.action = data.action || null;

        /**
         * Setter for Items
         * @param items
         */
        this.setItems = function(items) {
            this.items = items.map(function(item) {
                return FormItemFactory.createItem(item);
            }).filter(function(item) {
                return item !== false;
            });
        };

        /**
         * Getter for items
         * @returns {Array}
         */
        this.getItems = function() {
            return this.items;
        };

        /**
         * Setter for method
         * @param method
         */
        this.setMethod = function(method) {
            this.method = method;
        };

        /**
         * Getter for method
         * @returns {string}
         */
        this.getMethod = function() {
            return this.method;
        };

        /**
         * Setter for action
         * @param action
         */
        this.setAction = function(action) {
            this.action = action;
        };

        /**
         * Getter for action
         * @returns {string}
         */
        this.getAction = function() {
            return this.action;
        };

        if(data.items) {
            this.setItems(data.items);
        }
        
    };

    // Inherit Panel
    Form.prototype = PageItem;

    // Fix constructor
    Form.prototype.constructor = Form;

    return Form;
});

<|start_filename|>src/Components/Panels/Page/Form/submit.react.js<|end_filename|>
/**
 * A submit button, properties:
 *
 * - name
 * - .. any other allowed by input
 *
 * @jsx React.DOM
 */
define(['react'], function (React) {

    return React.createClass({
        render: function () {
            var attributes = this.props.item.getAttributes();
            attributes.className = 'button auja-bg-main';
            
            return (
                <div>
                {React.DOM.input(attributes)}
                </div>
            );
        }
    });
});

<|start_filename|>src/Components/Panels/Page/Form/hidden.react.js<|end_filename|>
/**
 * A text field, properties:
 *
 * - label
 * - name
 * - .. any other allowed by input
 *
 * @jsx React.DOM
 */
define(['react'], function (React) {
    return React.createClass({
        getInitialState: function () {
            return {value: this.props.item.getValue()};
        },
        render: function () {
            var attributes = this.props.item.getAttributes();
            attributes.value = this.state.value;

            return React.DOM.input(attributes);
        }
    });
});


<|start_filename|>src/Objects/Menu/link.js<|end_filename|>
define(['build/Objects/Abstract/menu_item'], function (MenuItem) {

    var Link = function (data) {

        //Call the parent constructor
        MenuItem.call(this, arguments);

        /**
         * Our custom type
         * @type {string}
         */
        this.type = 'link';

        /**
         * Target of this link
         * @type {string|boolean}
         */
        this.target = data.target || false;

        /**
         * If false the dispatching of this link will happen internally within Auja
         * Otherwise will be dispatched to the browser directly
         * @type {boolean}
         */
        this.external = data.external || false;
        
        /**
         * Icon
         * @type {string}
         */
        this.icon = data.icon || 'planet';

        /**
         * Text
         * @type {string}
         */
        this.text = data.text || 'NULL';

        /**
         * Getter for the id
         * @returns string
         * @override
         */
        this.getId = function () {
            return this.target;
        };
        
        /**
         * Setter for icon
         * @param icon
         */
        this.setIcon = function (icon) {
            this.icon = icon;
        };

        /**
         * Getter for icon
         * @returns {string}
         */
        this.getIcon = function () {
            return this.icon;
        };

        /**
         * Getter for external
         * @returns {boolean}
         */
        this.isExternal = function() {
            return this.external;
        };

        /**
         * Setter for external
         * @param external
         */
        this.setIsExternal = function(external) {
            this.external = external;
        };

        /**
         * Setter for target
         * @param target
         */
        this.setTarget = function (target) {
            this.target = target;
        };

        /**
         * Getter for target
         * @returns {string|boolean}
         */
        this.getTarget = function () {
            return this.target;
        };

        /**
         * Setter for text
         * @param text
         */
        this.setText = function (text) {
            this.text = text;
        };

        /**
         * Getter for text
         * @returns {string}
         */
        this.getText = function () {
            return this.text;
        };

        /**
         * Update this Link with another Link
         * @param item
         */
        this.update = function (item) {
            this.setText(item.getText());
            this.setIcon(item.getIcon());
            this.setTarget(item.getTarget());
        };
    };

    // Inherit Panel
    Link.prototype = MenuItem;

    // Fix constructor
    Link.prototype.constructor = Link;
    
    return Link;
});

<|start_filename|>tests/spec/Stores/message.spec.js<|end_filename|>
define([
    'jasmine_matchers', 'react', 'jquery', 'fluxxor', 'sugar',
    'build/Stores/message'
], function () {
    describe('Message store', function () {

        beforeEach(function () {
            this.addMatchers(require('jasmine_matchers'));
        });

        it('should have a message object', function () {

            var Store = require('build/Stores/message');
            var store = new Store();
            
            expect(store.getMessage()).toBeAnObject();
        });

        it('should store a message object', function() {

            var Store = require('build/Stores/message');
            var store = new Store();

            store.dispatch({
                authenticated: true
            });
            
            expect(store.getMessage().authenticated).toBe(true);
            
        });
        
        it('should reset its state', function() {
            
            var Store = require('build/Stores/message');
            var store = new Store();

            store.dispatch({
                authenticated: true
            });

            expect(store.getMessage().authenticated).toBe(true);
            
            store.reset();

            expect(store.getMessage().authenticated).toBeUndefined();
             
        });
        
    });

});

<|start_filename|>src/Factories/panel_factory.js<|end_filename|>
/**
 * Panel factory will create panel objects based on input
 */
define(['build/Factories/menu_factory', 'build/Factories/page_factory'], function (MenuFactory, PageFactory) {  
    
    return new function () {

        /**
         * Create the panel, will do this based on the type passed in the data
         * @param data
         */
        this.createPanel = function (data) {
            var panel = null;
            switch (data.type) {
                case 'menu':
                    panel = MenuFactory.createMenu(data);
                    break;
                case 'page':
                    panel = PageFactory.createPage(data);
                    break;
            }

            //Pass the origin
            panel.setOrigin(data.origin);
            panel.setUrl(data.url);

            return panel;
        };
        
        /**
         * Update contents of a panel
         * @param panel
         * @param data
         */
        this.updatePanel = function (panel, data) {
            if(panel.getType() != data.type) {
                console.err('Panel type does not correspond to data type during update');
                return;
            }
            
            switch (panel.getType()) {
                case 'menu':
                    panel = MenuFactory.updateMenu(panel, data);
                    break;
            }
            
            return panel;
        }

    };

});

<|start_filename|>tests/spec/Stores/panel.spec.js<|end_filename|>
define([
    'jasmine_matchers', 'react', 'jquery', 'fluxxor', 'sugar',
    'build/Stores/panel'
], function () {
    describe('Panel store', function () {

        beforeEach(function () {
            this.addMatchers(require('jasmine_matchers'));
        });

        it('should have an array of panels in its state', function () {

            var Store = require('build/Stores/panel');
            var store = new Store();

            expect(store.getState().panels).toBeAnObject();
            expect(store.getState().height).toBeAnInteger();

        });
        
        it('should be able to add panels', function() {
            
            var Store = require('build/Stores/panel');
            var store = new Store();
            
            expect(store.getState().panels.length).toBe(0);
            
            store.addPanel({
                type: 'menu',
                menu: []
            });
            
            expect(store.getState().panels.length).toBe(1);
            
        });
        
        it('should add _index after adding', function() {
            
            var Store = require('build/Stores/panel');
            var store = new Store();

            expect(store.getState().panels.length).toBe(0);

            var panel = {
                type: 'menu',
                menu: []
            };
            
            store.addPanel(panel);

            expect(store.getState().panels[0]._index).toBe(0);
            
        });
        
        //TODO implement updating
        //it('should be able to update a panel', function() {
        //
        //    var Store = require('build/Stores/panel');
        //    var store = new Store();
        //
        //    expect(store.getState().panels.length).toBe(0);
        //
        //    var panel = {
        //        foo: 123,
        //        origin: {
        //            id: -1
        //        }
        //    };
        //
        //    panel = store.addPanel(panel);
        //    expect(store.getState().panels.length).toBe(1);
        //
        //    expect(panel.foo).toBe(123);
        //    
        //    panel.foo = 321;
        //    
        //    panel = store.updatePanel(panel._index, panel);
        //    
        //    expect(panel.foo).toBe(321);
        //
        //    expect(store.getState().panels.length).toBe(1);
        //    
        //}); 

    });

});

<|start_filename|>tests/spec/Objects/Menu/Properties/searchable.spec.js<|end_filename|>
define(['build/Objects/Menu/Properties/searchable'], function (Property) {
    describe('Searchable property', function () {

        beforeEach(function () {
            this.addMatchers(require('jasmine_matchers'));
        });

        it('should implement a Property', function () {
            var property = new Property({});

            expect(property.getName()).toBe('searchable');
        });

        it('should have a target', function () {

            var property = new Property({
                target: 'http://searchme'
            });

            expect(property.getTarget()).toBe('http://searchme');

        })
    });
});


<|start_filename|>src/Objects/Abstract/property.js<|end_filename|>
/**
 * Abstract representation of a property
 */
define([], function() {

    return function(data) {

        /**
         * Name of the property
         * 
         * @type string
         * @private
         */
        this._name;

        /**
         * Getter for the name
         * @returns string
         */
        this.getName = function() {
            return this._name;
        };

        /**
         * Setter for the name
         * @param name
         */
        this.setName = function(name) {
            this._name = name;
        }
        
    }

});

<|start_filename|>src/Objects/Page/Form/select.js<|end_filename|>

define(['build/Objects/Abstract/form_item'], function(FormItem) {

    var Select = function(data) {

        //Call the parent constructor
        FormItem.call(this, data);

        //Set type of this object
        this.setType('select');

        /**
         * The Options of Select
         * @type {array|null}
         * @private
         */
        this._options = data.options || [];

        

        /**
         * Getter for Options
         * @returns {array|null}
         */
        this.getOptions = function() {
            return this._options;
        };

        

        /**
         * Setter for Options
         * @param Selected
         */
        this.setOptions = function(options) {
            this._options = options;
        };

        
        /**
         * Get attributes for this input
         * @return Object
         */
        this.getAttributes = function() {
            return {
                type: this.getType(),
                value: this.getValue(),
                name: this.getName(),
                options: this.getOptions()
            }
        };
    };

    // Inherit FormItem
    Select.prototype = FormItem;

    // Fix constructor
    Select.prototype.constructor = Select;
    
    return Select;
});

<|start_filename|>tests/spec/Components/Panels/Page/Form/datetime.react.spec.js<|end_filename|>
/** @jsx React.DOM */

define([
    'react',
    'build/Components/Panels/Page/Form/datetime.react',
    'build/Objects/Page/Form/datetime',
    'jasmine_matchers'
    ], function (React, DateTime, Item) {

        describe('DateTime form input', function () {

            beforeEach(function () {
                this.addMatchers(require('jasmine_matchers'));
            });

            it('should display its value', function () {
                var TestUtils = React.addons.TestUtils;

                var item = new Item({
                    value: '1982-08-17 23:15:10',
                    format: 'YYYY-MM-DD HH:mm:ss'
                });

            // Render a datetime input with label in the document
            var text = TestUtils.renderIntoDocument(DateTime({
                item: item
            }));

            var input = TestUtils.scryRenderedDOMComponentsWithTag(text, 'input');

                expect(input[0].getDOMNode().value).toEqual('1982-08-17');
                expect(input[1].getDOMNode().value).toEqual('23:15');

                expect(input[2].getDOMNode().value).toEqual('1982-08-17 23:15:10');
        });

            it('should have a label', function () {
                var TestUtils = React.addons.TestUtils;

                var item = new Item({
                    value: '1982-08-17 23:15:10',
                    format: 'YYYY-MM-DD HH:mm:ss',
                    label: "This is the label"
                });

            // Render a datetime input with label in the document
            var text = TestUtils.renderIntoDocument(DateTime({
                item: item
            }));

            var label = TestUtils.findRenderedDOMComponentWithTag(text, 'label');
            expect(label.getDOMNode().textContent).toEqual('This is the label');
        });
        });
});

<|start_filename|>src/Components/Panels/Page/Form/tinymce.react.js<|end_filename|>
/**
 * A Wysihtml RTE, properties:
 *
 * - label
 * - name
 * - value will be entered as value
 * - .. any other allowed by input
 *
 * @jsx React.DOM
 */
define(['react', 'build/Components/Panels/Page/Form/label.react', 'build/Components/Panels/Page/Form/file_select.react', 'tinymcejq'], function (React, Label, FileSelect) {
    return React.createClass({
        getInstanceId: function () {
            if (!this.instanceId) {
                this.instanceId = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
                    var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
                    return v.toString(16);
                });
            }
            return this.instanceId;
        },
        getIdentifier: function () {
            return 'tinymce-editor-' + this.getInstanceId();
        },
        handleUploaderChange: function(files) {
            //files array.
            if(files[0] != undefined) {
                $('.mce-floatpanel input:first').val(files[0].name);
            }
        },
        componentDidMount: function () {

            // Tell tinyMCE that the dom has already loaded since it wasn't there when
            // the event triggered
            tinymce.dom.Event.domLoaded = true;

            // Tell tinyMCE it has an uploader
            var uploadCallback = null;

            if(this.props.item.hasUploader()) {

                uploadCallback = function (field_name, url, type, win) {
                    var uploaderClass = '.tinymce-uploader-' + this.getInstanceId() + ' input[type="file"]';
                    if(type=='image') $(uploaderClass).click();
                }.bind(this);
            }

            //Actually initialize the editor
            tinymce.init({
                selector: '#' + this.getIdentifier(),
                theme: "modern",
                schema: "html5",
                height: 300,
                content_style: "img{max-width: 100%; display: block;}",
                plugins: [
                    "advlist autolink link image lists charmap preview",
                    "code fullscreen insertdatetime media",
                    "save table contextmenu directionality textcolor"
                ],
                cleanup : false,
                convert_fonts_to_spans: false,
                entity_encoding : "raw",
                toolbar: "styleselect | bold italic underline | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image | preview",
                extended_valid_elements : "div[class], img",
                file_browser_callback: uploadCallback

            });

            //Bind beforeSubmit event to do stuff with tinymce
            $(this.refs.textarea).closest('form').bind('beforeSubmit', function () {
                for (var i in tinymce.editors) {
                    try {
                        tinymce.editors[i].save();
                    } catch (e) {
                    }
                }
            });

        },
        componentWillUnmount: function () {
            tinymce.remove('#' + this.getIdentifier());
        },
        render: function () {
            var attributes = this.props.item.getAttributes();

            var uploader = "";
            if(this.props.item.hasUploader()) {
                uploader = (
                    <span className={"tinymce-uploader-" + this.getInstanceId()} style={{display: 'none'}}>
                        <FileSelect
                            item={this.props.item}
                            name={"tinymce-uploader"}
                            target={ this.props.item.getTarget()}
                            handleUploaderChange={this.handleUploaderChange.bind(this)}
                        />
                    </span>
                );
            }

            Object.merge(attributes, {
                id: this.getIdentifier(),
                type: 'textarea',
                ref: 'textarea',
                className: 'tinymce-editor'
            });

            return (
                <div>
                    {Label({item: this.props.item, name: this.props.item.getLabel()})}
                    {uploader}
                    {React.DOM.textarea(attributes, this.props.item.getValue())}
                </div>
            );
        }
    });

});

<|start_filename|>tests/spec/Components/Panels/Page/Form/number.react.spec.js<|end_filename|>
/** @jsx React.DOM */

define([
    'react',
    'build/Components/Panels/Page/Form/number.react',
    'build/Objects/Page/Form/number',
    'jasmine_matchers'
], function (React, Number, Item) {

    describe('Number form input', function () {

        beforeEach(function () {
            this.addMatchers(require('jasmine_matchers'));
        });

        it('should display its value', function () {
            var TestUtils = React.addons.TestUtils;

            var item = new Item({
                value: 10.25
            });

            // Render a checkbox with label in the document
            var text = TestUtils.renderIntoDocument(Number({
                item: item
            }));

            var input = TestUtils.findRenderedDOMComponentWithTag(text, 'input');

            //parseFloat since the value of an input is always a string
            expect(parseFloat(input.getDOMNode().value)).toEqual(10.25);
        });

        it('should have a label', function () {
            var TestUtils = React.addons.TestUtils;

            var item = new Item({
                value: 10.25,
                label: "This is the label"
            });

            // Render a checkbox with label in the document
            var text = TestUtils.renderIntoDocument(Number({
                item: item
            }));

            var label = TestUtils.findRenderedDOMComponentWithTag(text, 'label');
            expect(label.getDOMNode().textContent).toEqual('This is the label');
        });
    });
});

<|start_filename|>src/Components/Panels/Page/Form/date.react.js<|end_filename|>
/**
 * A date field, properties:
 *
 * - label
 * - name
 * - .. any other allowed by input
 *
 * @jsx React.DOM
 */
 define(['react', 'build/Components/Panels/Page/Form/label.react', 'moment', 'pikadayjq'], function (React, Label, moment) {
    return React.createClass({
        componentDidMount: function() {         
         $(this.refs.date.getDOMNode()).pikaday({
            firstDay: 1,
            bound: true,
            format: this.props.format ? this.props.format : this.props.item.getFormat(),//Allow override from parent
            defaultDate: new Date(this.props.item.getValue()),
            container: this.refs.calender.getDOMNode(),
            showWeekNumber: true,
            onSelect: function(date) {
                this.handleChange(date);
            }.bind(this)
            });
     },
    getInitialState: function () {
        return {value: this.props.item.getValue()};
    },
    handleChange: function (date) {
        date = moment(date).format(this.props.item.getFormat());

        //If parent element want us to broadcast our changes to it we'll oblige
        if(this.props.onChange) {
            this.props.onChange(date);
        }

        this.setState({value: date});
    },
    render: function () {
        var attributes = this.props.item.getAttributes();
        attributes.value = moment(this.state.value).format(this.props.item.getFormat());
        attributes.onChange = this.handleChange;
        attributes.ref = 'date';
        attributes.readOnly = true;
        //Insure label is ommited when the item is part of another component.
        attributes.type == 'date' ? label = <Label item={this.props.item} name={this.props.item.getLabel()} /> : label='';

        return (
            <div>
            {label}
            {React.DOM.input(attributes)}
            <div className="pika-container" ref='calender'></div>
            </div>
            );
    }
});
});

<|start_filename|>src/Objects/Page/Form/file_select.js<|end_filename|>
define(['build/Objects/Abstract/form_item'], function (FormItem) {

    var FileSelect = function (data) {

        //Call the parent constructor
        FormItem.call(this, data);

        //Set type of this object
        this.setType('file_select');
        /**
         * Place to upload data to
         * @var string
         */
        this.target = data.target;

        /**
         * Is multiuploaded
         * @type boolean
         */
        this.multiple = data.multiple || false;

        /**
         * FileSelects
         * @type array
         */
        this.files = this.multiple ? (data.files ? data.files : []) : (data.file ? [data.file] : []);

        /**
         * onchange
         * @type {string}
         */
        this._onChange = data.onChange || null;

        /**
         * Get target for uploader
         * @returns string
         */
        this.getTarget = function () {
            return this.target;
        };

        /**
         * Set target for uploader
         * @param target
         */
        this.setTarget = function (target) {
            this.target = target;
        };

        /**
         * Get file_selects
         * @returns {array}
         */
        this.getFiles = function () {
            return this.files;
        };

        /**
         * Set file_selects
         * @param files
         */
        this.setFiles = function (files) {
            this.files = files;
        };

        /**
         * Check if multiuploader
         * @returns {boolean}
         */
        this.isMultiple = function () {
            return this.multiple;
        };

        /**
         * Set is multiuploader
         * @param multiple
         */
        this.setIsMultiple = function (multiple) {
            this.multiple = multiple;
        };

        /**
         * Setter for onChange
         * @param onChange
         */
        this.setOnChange = function(onChange) {
            this._onChange = onChange;
        };

        /**
         * Getter for onchange
         * @returns {string}
         */
        this.getOnChange = function() {
            return this._onChange;
        };

    };

    // Inherit Panel
    FileSelect.prototype = FormItem;

    // Fix constructor
    FileSelect.prototype.constructor = FileSelect;

    return FileSelect;
});

<|start_filename|>tests/spec/Objects/Page/Form/trumbowyg.spec.js<|end_filename|>
define(['build/Objects/Page/Form/trumbowyg'], function (Item) {
    describe('Trumbowyg RTE form item', function () {

        beforeEach(function () {
            this.addMatchers(require('jasmine_matchers'));
        });
        
        it('should return corresponding attributes', function () {
            var item = new Item({
                order: 10,
                name: 'thename',
                label: 'The name',
                value: 'James',
                required: true
            });

            expect(item.getAttributes()).toHaveKeys([
                'type',
                'value',
                'name'
            ]);

        });
        
        it('should implement a form item', function () {

            var item = new Item({
                order: 10,
                name: 'thename',
                label: 'The name',
                value: 'James',
                required: true
            });

            //Text spec of transferring initial data
            expect(item.getType()).toBe('trumbowyg');
            expect(item.getOrder()).toBe(10);
            expect(item.getName()).toBe('thename');
            expect(item.getLabel()).toBe('The name');
            expect(item.getValue()).toBe('James');
            expect(item.isRequired()).toBe(true);

            //Test spec of setters
            item.setOrder(2);
            item.setName('somename');
            item.setLabel('Your name');
            item.setValue('Charles');
            item.setRequired(false);
            
            expect(item.getOrder()).toBe(2);
            expect(item.getName()).toBe('somename');
            expect(item.getLabel()).toBe('Your name');
            expect(item.getValue()).toBe('Charles');
            expect(item.isRequired()).toBe(false);
            
        });

        it('should allow for overriding the default buttons', function() {

            var buttons = ['bold'];
            var item = new Item({
                order: 10,
                name: 'thename',
                label: 'The name',
                value: 'James',
                required: true,
                buttons: buttons
            });
            
            expect(item.getButtons()).toBe(buttons);
        });
        
        it('should have default buttons', function() {

            var item = new Item({
                order: 10,
                name: 'thename',
                label: 'The name',
                value: 'James',
                required: true
            });

            expect(item.getButtons().length).toBe(['header', 'bold', 'italic', '|', 'unorderedList', 'orderedList', '|', 'insertImage', 'link', '|', 'viewHTML', 'fullscreen'].length);
            
        });
    });
});


<|start_filename|>src/Objects/Page/Form/range.js<|end_filename|>

define(['build/Objects/Abstract/form_item'], function(FormItem) {

    var Range = function(data) {

        //Call the parent constructor
        FormItem.call(this, data);

        //Set type of this object
        this.setType('range');

        /**
         * Min and max of the range 
         * @type {Number|null}
         * @private
         */
        this._min = data.min || null;
        this._max = data.max || null;

        /**
         * Getters for min and max
         * @returns {Number|null}
         */
        this.getMin = function() {
            return this._min;
        };

        this.getMax = function() {
            return this._max;
        };

        /**
         * Setters for min and max
         * @param maxLength
         */
        this.setMin = function(min) {
            this._min = min;
        };
        
        this.setMax = function(max) {
            this._max = max;
        };
        /**
         * Get attributes for this input
         * @return Object
         */
        this.getAttributes = function() {
            return {
                type: this.getType(),
                value: this.getValue(),
                name: this.getName(),
                min: this.getMin(),
                max: this.getMax()
            }
        };
    };

    // Inherit Panel
    Range.prototype = FormItem;

    // Fix constructor
    Range.prototype.constructor = Range;

    return Range;
});

<|start_filename|>src/Objects/Page/Form/email.js<|end_filename|>

define(['build/Objects/Abstract/form_item'], function(FormItem) {

    var Email = function(data) {

        //Call the parent constructor
        FormItem.call(this, data);

        //Set type of this object
        this.setType('email');
        
        /**
         * Get attributes for this input
         * @return Object
         */
        this.getAttributes = function() {
            return {
                type: this.getType(),
                value: this.getValue(),
                name: this.getName()
            }
        };
    };

    // Inherit FormItem
    Email.prototype = FormItem;

    // Fix constructor
    Email.prototype.constructor = Email;
    
    return Email;
});

<|start_filename|>src/Components/Panels/Page/Form/datetime.react.js<|end_filename|>
/**
 * A datetime field, properties:
 *
 * - label
 * - name
 * - .. any other allowed by input
 *
 * @jsx React.DOM
 */
define(['react', 'build/Components/Panels/Page/Form/label.react', 'moment', 'build/Components/Panels/Page/Form/date.react', 'build/Components/Panels/Page/Form/time.react'], function (React, Label, moment, Date, Time) {
    return React.createClass({
        getInitialState: function () {
            return {
                value: this.props.item.getValue(),
                date: moment(this.props.item.getValue(), this.props.item.getFormat()).format('YYYY-MM-DD'),
                time: moment(this.props.item.getValue(), this.props.item.getFormat()).format('HH:mm')
            };
        },
        dateDidChange: function (date) {
            this.state.date = date;
            this.state.value = moment(date + ' ' + this.state.time).format(this.props.item.getFormat());
            this.setState(this.state);
        },
        timeDidChange: function (time) {
            this.state.time = time;
            this.state.value = moment(this.state.date + ' ' + time).format(this.props.item.getFormat());
            this.setState(this.state);
        },
        render: function () {
            var dateItem = $.extend(true, {}, this.props.item);
            dateItem.setFormat('YYYY-MM-DD');
            dateItem.setValue(this.state.date);//Pass formatted date since the dateItem will reference it to YYYY-MM-DD        

            var timeItem = $.extend(true, {}, this.props.item);
            timeItem.setFormat('HH:mm');
            timeItem.setValue(this.state.time);//Same as the dateItem but with HH:mm

            return (
                <div>
                    <Label item={this.props.item} name={this.props.item.getLabel()} />
                    <Date item={dateItem} onChange={this.dateDidChange} />
                    <Time item={timeItem} onChange={this.timeDidChange} />
                    <input type="hidden" value={this.state.value} />
                </div>
            );
        }
    });
});

<|start_filename|>src/Components/Scaffolding/message.react.js<|end_filename|>
/**
 * Message
 *
 * @jsx React.DOM
 */
define(['react', 'fluxxor', 'flux'], function(React, Fluxxor, flux) {
    
    var Info = React.createClass({
        render: function() {
            return (
                <div className="animated zoomIn message message-info auja-bg-main" onClick={this.props.handleOnClick}>
                    {this.props.message.contents}
                </div>
                );
        }
    });

    var Success = React.createClass({
        componentDidMount: function() {
            
            //Wait for a little bit to hide the message
            setTimeout(function() {
                var n = this.refs.message.getDOMNode();
                n.className = n.className + " fadeOut";
                
                //Force reset after automatic 
                setTimeout(function() {
                    this.props.handleOnClick();
                }.bind(this), 250);
            }.bind(this), 750);  
        },
        render: function() {
            return (
                <div ref="message" className="message animated message-success" onClick={this.props.handleOnClick}>
                    {this.props.message.contents}
                    <div className="check-left auja-bg-main animated rotate-left-scale"></div>
                    <div className="check-right auja-bg-main animated rotate-right-scale"></div>
                </div>
            );
        }
    });

    /**
     * Main content with all panels
     */
    return React.createClass({
        mixins: [Fluxxor.FluxMixin(React), Fluxxor.StoreWatchMixin('MessageStore')],
        getStateFromFlux: function() {
            return { 
                message: flux.store('MessageStore').getMessage()
            };
        },

        /**
         * Handle click on message
         */
        handleOnClick: function() {
            flux.store('MessageStore').reset();  
        },

        /**
         * Bind click on escape to reset the message
         */
        componentDidMount: function() {
            $(document).bind('keyup', function(e) {
                if(e.keyCode == 27) {
                    flux.store('MessageStore').reset();
                }  
            });
        },
        
        /**
         * Render the div with all panels
         * @returns {XML}
         */
        render: function() {
            
            //No state nothing to show
            if(this.state.message.message && this.state.message.message.state) {
                switch(this.state.message.message.state) {
                    case 'error':
                    case 'info':
                        return (<Info handleOnClick={this.handleOnClick} message={this.state.message.message} />);
                        break;
                    case 'success':
                        return (<Success handleOnClick={this.handleOnClick} message={this.state.message.message} />);
                        break;
                    default:
                        console.error(this.state.message.message.state.upperCaseChars + ' message not implemented');
                }
            }
            return (<span></span>);
        }
    });

});

<|start_filename|>test-main.js<|end_filename|>
var allTestFiles = [];
var TEST_REGEXP = /spec\.js$/i;

var pathToModule = function (path) {
    return path.replace(/^\/base\//, '').replace(/\.js$/, '');
};

Object.keys(window.__karma__.files).forEach(function (file) {
    if (TEST_REGEXP.test(file)) {
        // Normalize paths to RequireJS module names.
        allTestFiles.push(pathToModule(file));
    }
});

require.config({
    // Karma serves files under /base, which is the basePath from your config file
    baseUrl: '/base',

    // dynamically load all test files
    deps: allTestFiles,

    // we have to kickoff jasmine, as it is asynchronous
    callback: window.__karma__.start,

    /**
     * Location of dependencies
     */
    paths: {
        //Bunch of requirements needed for the blueimp file uploader
        'jquery.ui.widget': 'bower_components/blueimp-file-upload/js/vendor/jquery.ui.widget',
        'jquery.fileupload': 'bower_components/blueimp-file-upload/js/jquery.fileupload',
        'jquery.fileupload-ui': 'bower_components/blueimp-file-upload/js/jquery.fileupload-ui',
        'jquery.fileupload-image': 'bower_components/blueimp-file-upload/js/jquery.fileupload-image',
        'jquery.fileupload-validate': 'bower_components/blueimp-file-upload/js/jquery.fileupload-validate',
        'jquery.fileupload-video': 'bower_components/blueimp-file-upload/js/jquery.fileupload-video',
        'jquery.fileupload-audio': 'bower_components/blueimp-file-upload/js/jquery.fileupload-audio',
        'jquery.fileupload-process': 'bower_components/blueimp-file-upload/js/jquery.fileupload-process',
        'jquery.fileupload-jquery-ui': 'bower_components/blueimp-file-upload/js/jquery.fileupload-jquery-ui',
        'jquery.iframe-transport': 'bower_components/blueimp-file-upload/js/jquery.iframe-transport',
        'load-image': 'bower_components/blueimp-load-image/js/load-image',
        'load-image-meta': 'bower_components/blueimp-load-image/js/load-image-meta',
        'load-image-exif': 'bower_components/blueimp-load-image/js/load-image-exif',
        'load-image-ios': 'bower_components/blueimp-load-image/js/load-image-ios',
        'canvas-to-blob': 'bower_components/blueimp-canvas-to-blob/js/canvas-to-blob',
        'tmpl': 'bower_components/blueimp-tmpl/js/tmpl',
        
        jasmine_matchers: 'tests/spec/matchers',
        react: 'bower_components/react/react-with-addons',
        jquery: 'bower_components/jquery/dist/jquery.min',
        fluxxor: 'bower_components/fluxxor/build/fluxxor',
        signals: 'bower_components/js-signals/dist/signals',
        moment: 'bower_components/moment/min/moment.min',
        pikaday: 'bower_components/pikaday/pikaday',
        pikadayjq: 'bower_components/pikaday/plugins/pikaday.jquery',
        crossroads: 'bower_components/crossroads.js/dist/crossroads',
        trumbowyg: 'bower_components/trumbowyg/dist/trumbowyg.min',
        tinymce: 'bower_components/tinymce/tinymce',
        tinymcejq: 'bower_components/tinymce/tinymce.jquery',
        minicolors: 'bower_components/jquery-minicolors/jquery.minicolors.min',
        jstree: 'bower_components/jstree/dist/jstree.min',
        sugar: 'bower_components/sugar/release/sugar.min',
        request: 'build/Requests/request',
        flux: 'build/Stores/flux',
        clockpicker: 'bower_components/clockpicker/dist/jquery-clockpicker.min',
        selectize: 'bower_components/selectize/dist/js/standalone/selectize.min'
    },

    /**
     * Shim
     */
shim: {
        trumbowyg: {
            deps: ['jquery']
        },
        tinymcejq: {
            deps: ['jquery', 'tinymce']
        },
        minicolors: {
            deps: ['jquery']
        },
        clockpicker: {
            deps: ['jquery']
        },
        pikadayjq: {
            deps: ['jquery', 'moment', 'pikaday']
        },
        selectize: {
            deps: ['jquery']
        }
}
});

<|start_filename|>tests/spec/Components/Panels/Page/Form/date.react.spec.js<|end_filename|>
/** @jsx React.DOM */

define([
    'react',
    'build/Components/Panels/Page/Form/date.react',
    'build/Objects/Page/Form/date',
    'jasmine_matchers'
    ], function (React, Date, Item) {

        describe('Date form input', function () {

            beforeEach(function () {
                this.addMatchers(require('jasmine_matchers'));
            });

            it('should display its value', function () {
                var TestUtils = React.addons.TestUtils;

                var item = new Item({
                    value: '1982-08-17',
                    format: 'YYYY-MM-DD'
                });

            // Render a checkbox with label in the document
            var text = TestUtils.renderIntoDocument(Date({
                item: item
            }));

            var input = TestUtils.findRenderedDOMComponentWithTag(text, 'input');


                expect(input.getDOMNode().value).toEqual('1982-08-17');
        });

            it('should have a label', function () {
                var TestUtils = React.addons.TestUtils;

                var item = new Item({
                    value: "1982-08-17",
                    format: 'YYYY-MM-DD',
                    label: "This is the label"
                });

            // Render a checkbox with label in the document
            var text = TestUtils.renderIntoDocument(Date({
                item: item
            }));

            var label = TestUtils.findRenderedDOMComponentWithTag(text, 'label');
            expect(label.getDOMNode().textContent).toEqual('This is the label');
        });
        });
});

<|start_filename|>src/Stores/auja.js<|end_filename|>
define(['fluxxor', 'request', 'build/Factories/form_factory'], function(Fluxxor, Request, FormFactory) {

    /**
     * The main Auja store
     */
    return Fluxxor.createStore({

        /**
         * State of the Auja scaffolding
         */
        state: {
            "title": "",
            "authenticated": false,
            "debug": true,
            "colors": {
                "main": "#1ebab8",
                "secondary": "#EDEDED",
                "alert": "#e85840"
            },
            "user": {
                "name": ""
            },
            "buttons": [],
            "menu": [],
            "routes": [],
            "authentication": false
        },

        /**
         * On initialization and on system update we will update the state
         * @param url
         */
        initialize: function(url) {
            this.bindActions(
                'initialize', this.update,
                'update', this.update,
                'message', this.message
            )  
        },

        /**
         * Getter for the state
         * @returns {*}
         */
        getState: function() {
            return this.state;
        },

        /**
         * Update, will fetch the 'data-src' tag from the body
         * @todo add error handling
         */
        update: function() {
            var request = new Request(document.body.getAttribute('data-src'));
            request.get()
                .done(function (response) {
                    
                    //Pass through the factory
                    if(response.main.authentication && response.main.authentication.form) {
                        response.main.authentication = FormFactory.createForm(response.main.authentication.form); 
                    }
                    
                    Object.merge(this.state, response.main, true, true);
                    this.emit('change');
                }.bind(this))
                .fail(function (code) {
                    flux.actions.processFail(code);
                }.bind(this));
        },

        /**
         * Messages can contain snippets that are relevant for auja
         * @param message
         */
        message: function(message) {
            var changed = false;
            
            if(message.authenticated && this.state.authenticated != message.authenticated) {
                this.state.authenticated = message.authenticated;
                changed = true;
            }
            
            if(changed) {
                this.emit('change');
            }
        }
        
    })
    
});

<|start_filename|>src/Objects/menu.js<|end_filename|>
/**
 * Menu panel type
 */
define(['build/Objects/Abstract/panel', 'build/Factories/menu_item_factory'], function (Panel, MenuItemFactory) {

    var Menu = function () {

        //Call the parent constructor
        Panel.call(this);

        //Set the type
        this.setType('menu');

        //Show that we're updateable
        this.setIsUpdateable(true);

        /**
         * Menu items
         * @type {Array}
         */
        this.items = [];

        /**
         * Index used to generate ids for items
         * @type {number}
         * @private
         */
        this._lastIndex = 0;

        /**
         * Active item
         * @type MenuItem
         * @private
         */
        this._activeItem = false;

        /**
         * Generate a unique Id
         * @returns {*|string}
         */
        this.getNextId = function (item) {
            return '_' + String(++this._lastIndex);
        };

        /**
         * Setter for items
         * @param items
         */
        this.setItems = function (items) {
            this.items = items.map(function (item) {

                //Check if item already instantiated
                //TODO make checking of this more elegant
                if (item.getId) {
                    item.setId(this.getNextId(item));
                    return item;
                }

                var result = MenuItemFactory.createItem(item);

                //When unable to create menu item just return the invalid version
                if(!result) return result;
                
                //Arrange a panel id or transfer the passed id
                result.setId(this.getNextId(item));

                return result;
            }.bind(this)).filter(function(item) {
                return item !== false;
            });
        };

        /**
         * Getter for items
         * @returns {Array}
         */
        this.getItems = function () {
            return this.items;
        };

        /**
         * Check if this menu contains an item
         * @param item
         * @returns {boolean}
         */
        this.hasItem = function (item) {
            for (var i in this.items) {
                if (this.items[i] == item) {
                    return true;
                }
            }
            return false;
        };

        /**
         * Extend an item
         * @param item
         * @param data
         */
        this.extendItem = function (item, data) {
            for (var i in this.items) {
                if (this.items[i].getId() == item.getId()) {
                    if (this.items[i].extend) {
                        this.items[i].extend(data);
                    } else {
                        console.error('Extend requested on menu item without update method implemented');
                    }
                    break;
                }
            }
        };

        /**
         * Update an item
         * @param item
         * @param data
         */
        this.updateItem = function (item, data) {
            for (var i in this.items) {
                if (this.items[i] == item) {
                    this.items[i].update(data);
                    return;
                }
            }
        };

        /**
         * Setter for the active item
         * @param item
         */
        this.setActiveItem = function(item) {
            for(var i in this.items) {
                this.items[i].setIsActive(this.items[i].getId() == item.getId());
                
                //When the item has childs that might be active pass the item that is active
                if(this.items[i].setActiveItem) {
                    this.items[i].setActiveItem(item);
                }
            }
        };

        /**
         * All menu's are paginateable except for one with a sortable inside it
         * @returns {boolean}
         */
        this.isPaginated = function() {
            return this.items.none(function(item) {
                return item.getType() == 'resource' && item.hasProperty('sortable');
            });
        }

    };

    // Inherit Panel
    Menu.prototype = Panel;

    // Fix constructor
    Menu.prototype.constructor = Menu;
    
    return Menu;
});